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 (at) 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 "pipe/p_context.h" 56 #include "util/u_math.h" 57 #include "util/u_memory.h" 58 #include "pipe/p_defines.h" 59 #include "pipe/p_shader_tokens.h" 60 #include "draw_fs.h" 61 #include "draw_vs.h" 62 #include "draw_pipe.h" 63 64 65 struct widepoint_stage { 66 struct draw_stage stage; /**< base class */ 67 68 float half_point_size; 69 70 float xbias; 71 float ybias; 72 73 /** for automatic texcoord generation/replacement */ 74 uint num_texcoord_gen; 75 uint texcoord_gen_slot[PIPE_MAX_SHADER_OUTPUTS]; 76 77 int psize_slot; 78 }; 79 80 81 82 static INLINE struct widepoint_stage * 83 widepoint_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 */ 94 static void set_texcoords(const struct widepoint_stage *wide, 95 struct vertex_header *v, const float tc[4]) 96 { 97 const struct draw_context *draw = wide->stage.draw; 98 const struct pipe_rasterizer_state *rast = draw->rasterizer; 99 const uint texcoord_mode = rast->sprite_coord_mode; 100 uint i; 101 102 for (i = 0; i < wide->num_texcoord_gen; i++) { 103 const uint slot = wide->texcoord_gen_slot[i]; 104 v->data[slot][0] = tc[0]; 105 if (texcoord_mode == PIPE_SPRITE_COORD_LOWER_LEFT) 106 v->data[slot][1] = 1.0f - tc[1]; 107 else 108 v->data[slot][1] = tc[1]; 109 v->data[slot][2] = tc[2]; 110 v->data[slot][3] = tc[3]; 111 } 112 } 113 114 115 /* If there are lots of sprite points (and why wouldn't there be?) it 116 * would probably be more sensible to change hardware setup to 117 * optimize this rather than doing the whole thing in software like 118 * this. 119 */ 120 static void widepoint_point( struct draw_stage *stage, 121 struct prim_header *header ) 122 { 123 const struct widepoint_stage *wide = widepoint_stage(stage); 124 const unsigned pos = draw_current_shader_position_output(stage->draw); 125 const boolean sprite = (boolean) stage->draw->rasterizer->point_quad_rasterization; 126 float half_size; 127 float left_adj, right_adj, bot_adj, top_adj; 128 129 struct prim_header tri; 130 131 /* four dups of original vertex */ 132 struct vertex_header *v0 = dup_vert(stage, header->v[0], 0); 133 struct vertex_header *v1 = dup_vert(stage, header->v[0], 1); 134 struct vertex_header *v2 = dup_vert(stage, header->v[0], 2); 135 struct vertex_header *v3 = dup_vert(stage, header->v[0], 3); 136 137 float *pos0 = v0->data[pos]; 138 float *pos1 = v1->data[pos]; 139 float *pos2 = v2->data[pos]; 140 float *pos3 = v3->data[pos]; 141 142 /* point size is either per-vertex or fixed size */ 143 if (wide->psize_slot >= 0) { 144 half_size = header->v[0]->data[wide->psize_slot][0]; 145 half_size *= 0.5f; 146 } 147 else { 148 half_size = wide->half_point_size; 149 } 150 151 left_adj = -half_size + wide->xbias; 152 right_adj = half_size + wide->xbias; 153 bot_adj = half_size + wide->ybias; 154 top_adj = -half_size + wide->ybias; 155 156 pos0[0] += left_adj; 157 pos0[1] += top_adj; 158 159 pos1[0] += left_adj; 160 pos1[1] += bot_adj; 161 162 pos2[0] += right_adj; 163 pos2[1] += top_adj; 164 165 pos3[0] += right_adj; 166 pos3[1] += bot_adj; 167 168 if (sprite) { 169 static const float tex00[4] = { 0, 0, 0, 1 }; 170 static const float tex01[4] = { 0, 1, 0, 1 }; 171 static const float tex11[4] = { 1, 1, 0, 1 }; 172 static const float tex10[4] = { 1, 0, 0, 1 }; 173 set_texcoords( wide, v0, tex00 ); 174 set_texcoords( wide, v1, tex01 ); 175 set_texcoords( wide, v2, tex10 ); 176 set_texcoords( wide, v3, tex11 ); 177 } 178 179 tri.det = header->det; /* only the sign matters */ 180 tri.v[0] = v0; 181 tri.v[1] = v2; 182 tri.v[2] = v3; 183 stage->next->tri( stage->next, &tri ); 184 185 tri.v[0] = v0; 186 tri.v[1] = v3; 187 tri.v[2] = v1; 188 stage->next->tri( stage->next, &tri ); 189 } 190 191 192 static void 193 widepoint_first_point(struct draw_stage *stage, 194 struct prim_header *header) 195 { 196 struct widepoint_stage *wide = widepoint_stage(stage); 197 struct draw_context *draw = stage->draw; 198 struct pipe_context *pipe = draw->pipe; 199 const struct pipe_rasterizer_state *rast = draw->rasterizer; 200 void *r; 201 202 wide->half_point_size = 0.5f * rast->point_size; 203 wide->xbias = 0.0; 204 wide->ybias = 0.0; 205 206 if (rast->gl_rasterization_rules) { 207 wide->xbias = 0.125; 208 wide->ybias = -0.125; 209 } 210 211 /* Disable triangle culling, stippling, unfilled mode etc. */ 212 r = draw_get_rasterizer_no_cull(draw, rast->scissor, rast->flatshade); 213 draw->suspend_flushing = TRUE; 214 pipe->bind_rasterizer_state(pipe, r); 215 draw->suspend_flushing = FALSE; 216 217 /* XXX we won't know the real size if it's computed by the vertex shader! */ 218 if ((rast->point_size > draw->pipeline.wide_point_threshold) || 219 (rast->point_quad_rasterization && draw->pipeline.point_sprite)) { 220 stage->point = widepoint_point; 221 } 222 else { 223 stage->point = draw_pipe_passthrough_point; 224 } 225 226 draw_remove_extra_vertex_attribs(draw); 227 228 if (rast->point_quad_rasterization) { 229 const struct draw_fragment_shader *fs = draw->fs.fragment_shader; 230 uint i; 231 232 assert(fs); 233 234 wide->num_texcoord_gen = 0; 235 236 /* Loop over fragment shader inputs looking for generic inputs 237 * for which bit 'k' in sprite_coord_enable is set. 238 */ 239 for (i = 0; i < fs->info.num_inputs; i++) { 240 if (fs->info.input_semantic_name[i] == TGSI_SEMANTIC_GENERIC) { 241 const int generic_index = fs->info.input_semantic_index[i]; 242 /* Note that sprite_coord enable is a bitfield of 243 * PIPE_MAX_SHADER_OUTPUTS bits. 244 */ 245 if (generic_index < PIPE_MAX_SHADER_OUTPUTS && 246 (rast->sprite_coord_enable & (1 << generic_index))) { 247 /* OK, this generic attribute needs to be replaced with a 248 * texcoord (see above). 249 */ 250 int slot = draw_alloc_extra_vertex_attrib(draw, 251 TGSI_SEMANTIC_GENERIC, 252 generic_index); 253 254 /* add this slot to the texcoord-gen list */ 255 wide->texcoord_gen_slot[wide->num_texcoord_gen++] = slot; 256 } 257 } 258 } 259 } 260 261 wide->psize_slot = -1; 262 if (rast->point_size_per_vertex) { 263 /* find PSIZ vertex output */ 264 const struct draw_vertex_shader *vs = draw->vs.vertex_shader; 265 uint i; 266 for (i = 0; i < vs->info.num_outputs; i++) { 267 if (vs->info.output_semantic_name[i] == TGSI_SEMANTIC_PSIZE) { 268 wide->psize_slot = i; 269 break; 270 } 271 } 272 } 273 274 stage->point( stage, header ); 275 } 276 277 278 static void widepoint_flush( struct draw_stage *stage, unsigned flags ) 279 { 280 struct draw_context *draw = stage->draw; 281 struct pipe_context *pipe = draw->pipe; 282 283 stage->point = widepoint_first_point; 284 stage->next->flush( stage->next, flags ); 285 286 draw_remove_extra_vertex_attribs(draw); 287 288 /* restore original rasterizer state */ 289 if (draw->rast_handle) { 290 draw->suspend_flushing = TRUE; 291 pipe->bind_rasterizer_state(pipe, draw->rast_handle); 292 draw->suspend_flushing = FALSE; 293 } 294 } 295 296 297 static void widepoint_reset_stipple_counter( struct draw_stage *stage ) 298 { 299 stage->next->reset_stipple_counter( stage->next ); 300 } 301 302 303 static void widepoint_destroy( struct draw_stage *stage ) 304 { 305 draw_free_temp_verts( stage ); 306 FREE( stage ); 307 } 308 309 310 struct draw_stage *draw_wide_point_stage( struct draw_context *draw ) 311 { 312 struct widepoint_stage *wide = CALLOC_STRUCT(widepoint_stage); 313 if (wide == NULL) 314 goto fail; 315 316 wide->stage.draw = draw; 317 wide->stage.name = "wide-point"; 318 wide->stage.next = NULL; 319 wide->stage.point = widepoint_first_point; 320 wide->stage.line = draw_pipe_passthrough_line; 321 wide->stage.tri = draw_pipe_passthrough_tri; 322 wide->stage.flush = widepoint_flush; 323 wide->stage.reset_stipple_counter = widepoint_reset_stipple_counter; 324 wide->stage.destroy = widepoint_destroy; 325 326 if (!draw_alloc_temp_verts( &wide->stage, 4 )) 327 goto fail; 328 329 return &wide->stage; 330 331 fail: 332 if (wide) 333 wide->stage.destroy( &wide->stage ); 334 335 return NULL; 336 } 337