draw_pipe_wide_point.c revision a407636efb6c32cee81b9a1525dbc804aacd957b
1/**************************************************************************
2 *
3 * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 **************************************************************************/
27
28/* Authors:  Keith Whitwell <keith@tungstengraphics.com>
29 */
30
31/**
32 * Notes on wide points and sprite mode:
33 *
34 * In wide point/sprite mode we effectively need to convert each incoming
35 * vertex into four outgoing vertices specifying the corners of a quad.
36 * Since we don't (yet) have geometry shaders, we have to handle this here
37 * in the draw module.
38 *
39 * For sprites, it also means that this is where we have to handle texcoords
40 * for the vertices of the quad.  OpenGL's GL_COORD_REPLACE state specifies
41 * if/how enabled texcoords are automatically generated for sprites.  We pass
42 * that info through gallium in the pipe_rasterizer_state::sprite_coord_mode
43 * array.
44 *
45 * Additionally, GLSL's gl_PointCoord fragment attribute has to be handled
46 * here as well.  This is basically an additional texture/generic attribute
47 * that varies .x from 0 to 1 horizontally across the point and varies .y
48 * vertically from 0 to 1 down the sprite.
49 *
50 * With geometry shaders, the state tracker could create a GS to do
51 * most/all of this.
52 */
53
54
55#include "util/u_math.h"
56#include "util/u_memory.h"
57#include "pipe/p_defines.h"
58#include "pipe/p_shader_tokens.h"
59#include "draw_vs.h"
60#include "draw_pipe.h"
61
62
63struct widepoint_stage {
64   struct draw_stage stage;
65
66   float half_point_size;
67
68   float xbias;
69   float ybias;
70
71   uint texcoord_slot[PIPE_MAX_SHADER_OUTPUTS];
72   uint texcoord_mode[PIPE_MAX_SHADER_OUTPUTS];
73   uint num_texcoords;
74
75   int psize_slot;
76
77   int point_coord_fs_input;  /**< input for pointcoord */
78};
79
80
81
82static INLINE struct widepoint_stage *
83widepoint_stage( struct draw_stage *stage )
84{
85   return (struct widepoint_stage *)stage;
86}
87
88
89/**
90 * Set the vertex texcoords for sprite mode.
91 * Coords may be left untouched or set to a right-side-up or upside-down
92 * orientation.
93 */
94static void set_texcoords(const struct widepoint_stage *wide,
95                          struct vertex_header *v, const float tc[4])
96{
97   uint i;
98   for (i = 0; i < wide->num_texcoords; i++) {
99      if (wide->texcoord_mode[i] != PIPE_SPRITE_COORD_NONE) {
100         uint j = wide->texcoord_slot[i];
101         v->data[j][0] = tc[0];
102         if (wide->texcoord_mode[i] == PIPE_SPRITE_COORD_LOWER_LEFT)
103            v->data[j][1] = 1.0f - tc[1];
104         else
105            v->data[j][1] = tc[1];
106         v->data[j][2] = tc[2];
107         v->data[j][3] = tc[3];
108      }
109   }
110
111   if (wide->point_coord_fs_input >= 0) {
112      /* put gl_PointCoord into the extra vertex slot */
113      uint slot = wide->stage.draw->extra_shader_outputs.slot;
114      v->data[slot][0] = tc[0];
115      v->data[slot][1] = tc[1];
116      v->data[slot][2] = 0.0F;
117      v->data[slot][3] = 1.0F;
118   }
119}
120
121
122/* If there are lots of sprite points (and why wouldn't there be?) it
123 * would probably be more sensible to change hardware setup to
124 * optimize this rather than doing the whole thing in software like
125 * this.
126 */
127static void widepoint_point( struct draw_stage *stage,
128                             struct prim_header *header )
129{
130   const struct widepoint_stage *wide = widepoint_stage(stage);
131   const unsigned pos = draw_current_shader_position_output(stage->draw);
132   const boolean sprite = (boolean) stage->draw->rasterizer->point_sprite;
133   float half_size;
134   float left_adj, right_adj, bot_adj, top_adj;
135
136   struct prim_header tri;
137
138   /* four dups of original vertex */
139   struct vertex_header *v0 = dup_vert(stage, header->v[0], 0);
140   struct vertex_header *v1 = dup_vert(stage, header->v[0], 1);
141   struct vertex_header *v2 = dup_vert(stage, header->v[0], 2);
142   struct vertex_header *v3 = dup_vert(stage, header->v[0], 3);
143
144   float *pos0 = v0->data[pos];
145   float *pos1 = v1->data[pos];
146   float *pos2 = v2->data[pos];
147   float *pos3 = v3->data[pos];
148
149   /* point size is either per-vertex or fixed size */
150   if (wide->psize_slot >= 0) {
151      half_size = header->v[0]->data[wide->psize_slot][0];
152      half_size *= 0.5f;
153   }
154   else {
155      half_size = wide->half_point_size;
156   }
157
158   left_adj = -half_size + wide->xbias;
159   right_adj = half_size + wide->xbias;
160   bot_adj = half_size + wide->ybias;
161   top_adj = -half_size + wide->ybias;
162
163   pos0[0] += left_adj;
164   pos0[1] += top_adj;
165
166   pos1[0] += left_adj;
167   pos1[1] += bot_adj;
168
169   pos2[0] += right_adj;
170   pos2[1] += top_adj;
171
172   pos3[0] += right_adj;
173   pos3[1] += bot_adj;
174
175   if (sprite) {
176      static const float tex00[4] = { 0, 0, 0, 1 };
177      static const float tex01[4] = { 0, 1, 0, 1 };
178      static const float tex11[4] = { 1, 1, 0, 1 };
179      static const float tex10[4] = { 1, 0, 0, 1 };
180      set_texcoords( wide, v0, tex00 );
181      set_texcoords( wide, v1, tex01 );
182      set_texcoords( wide, v2, tex10 );
183      set_texcoords( wide, v3, tex11 );
184   }
185
186   tri.det = header->det;  /* only the sign matters */
187   tri.v[0] = v0;
188   tri.v[1] = v2;
189   tri.v[2] = v3;
190   stage->next->tri( stage->next, &tri );
191
192   tri.v[0] = v0;
193   tri.v[1] = v3;
194   tri.v[2] = v1;
195   stage->next->tri( stage->next, &tri );
196}
197
198
199static int
200find_pntc_input_attrib(struct draw_context *draw)
201{
202   /* Scan the fragment program's input decls to find the pointcoord
203    * attribute.  The xy components will store the point coord.
204    */
205   return 0; /* XXX fix this */
206}
207
208
209static void widepoint_first_point( struct draw_stage *stage,
210			      struct prim_header *header )
211{
212   struct widepoint_stage *wide = widepoint_stage(stage);
213   struct draw_context *draw = stage->draw;
214
215   wide->half_point_size = 0.5f * draw->rasterizer->point_size;
216   wide->xbias = 0.0;
217   wide->ybias = 0.0;
218
219   if (draw->rasterizer->gl_rasterization_rules) {
220      wide->xbias = 0.125;
221   }
222
223   /* XXX we won't know the real size if it's computed by the vertex shader! */
224   if ((draw->rasterizer->point_size > draw->pipeline.wide_point_threshold) ||
225       (draw->rasterizer->point_sprite && draw->pipeline.point_sprite)) {
226      stage->point = widepoint_point;
227   }
228   else {
229      stage->point = draw_pipe_passthrough_point;
230   }
231
232   if (draw->rasterizer->point_sprite) {
233      /* find vertex shader texcoord outputs */
234      const struct draw_vertex_shader *vs = draw->vs.vertex_shader;
235      uint i, j = 0;
236      for (i = 0; i < vs->info.num_outputs; i++) {
237         if (vs->info.output_semantic_name[i] == TGSI_SEMANTIC_GENERIC) {
238            wide->texcoord_slot[j] = i;
239            wide->texcoord_mode[j] = draw->rasterizer->sprite_coord_mode[j];
240            j++;
241         }
242      }
243      wide->num_texcoords = j;
244
245      /* find fragment shader PointCoord input */
246      wide->point_coord_fs_input = find_pntc_input_attrib(draw);
247
248      /* setup extra vp output (point coord implemented as a texcoord) */
249      draw->extra_shader_outputs.semantic_name = TGSI_SEMANTIC_GENERIC;
250      draw->extra_shader_outputs.semantic_index = 0;
251      draw->extra_shader_outputs.slot = draw_current_shader_outputs(draw);
252   }
253   else {
254      wide->point_coord_fs_input = -1;
255      draw->extra_shader_outputs.slot = 0;
256   }
257
258   wide->psize_slot = -1;
259   if (draw->rasterizer->point_size_per_vertex) {
260      /* find PSIZ vertex output */
261      const struct draw_vertex_shader *vs = draw->vs.vertex_shader;
262      uint i;
263      for (i = 0; i < vs->info.num_outputs; i++) {
264         if (vs->info.output_semantic_name[i] == TGSI_SEMANTIC_PSIZE) {
265            wide->psize_slot = i;
266            break;
267         }
268      }
269   }
270
271   stage->point( stage, header );
272}
273
274
275static void widepoint_flush( struct draw_stage *stage, unsigned flags )
276{
277   stage->point = widepoint_first_point;
278   stage->next->flush( stage->next, flags );
279   stage->draw->extra_shader_outputs.slot = 0;
280}
281
282
283static void widepoint_reset_stipple_counter( struct draw_stage *stage )
284{
285   stage->next->reset_stipple_counter( stage->next );
286}
287
288
289static void widepoint_destroy( struct draw_stage *stage )
290{
291   draw_free_temp_verts( stage );
292   FREE( stage );
293}
294
295
296struct draw_stage *draw_wide_point_stage( struct draw_context *draw )
297{
298   struct widepoint_stage *wide = CALLOC_STRUCT(widepoint_stage);
299   if (wide == NULL)
300      goto fail;
301
302   if (!draw_alloc_temp_verts( &wide->stage, 4 ))
303      goto fail;
304
305   wide->stage.draw = draw;
306   wide->stage.name = "wide-point";
307   wide->stage.next = NULL;
308   wide->stage.point = widepoint_first_point;
309   wide->stage.line = draw_pipe_passthrough_line;
310   wide->stage.tri = draw_pipe_passthrough_tri;
311   wide->stage.flush = widepoint_flush;
312   wide->stage.reset_stipple_counter = widepoint_reset_stipple_counter;
313   wide->stage.destroy = widepoint_destroy;
314
315   return &wide->stage;
316
317 fail:
318   if (wide)
319      wide->stage.destroy( &wide->stage );
320
321   return NULL;
322}
323