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