1 /************************************************************************** 2 * 3 * Copyright 2010, 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 /* 29 * Binning code for points 30 */ 31 32 #include "lp_setup_context.h" 33 #include "util/u_math.h" 34 #include "util/u_memory.h" 35 #include "lp_perf.h" 36 #include "lp_rast.h" 37 #include "lp_state_fs.h" 38 #include "lp_state_setup.h" 39 #include "tgsi/tgsi_scan.h" 40 41 #define NUM_CHANNELS 4 42 43 struct point_info { 44 /* x,y deltas */ 45 int dy01, dy12; 46 int dx01, dx12; 47 48 const float (*v0)[4]; 49 50 float (*a0)[4]; 51 float (*dadx)[4]; 52 float (*dady)[4]; 53 }; 54 55 56 /** 57 * Compute a0 for a constant-valued coefficient (GL_FLAT shading). 58 */ 59 static void 60 constant_coef(struct lp_setup_context *setup, 61 struct point_info *info, 62 unsigned slot, 63 const float value, 64 unsigned i) 65 { 66 info->a0[slot][i] = value; 67 info->dadx[slot][i] = 0.0f; 68 info->dady[slot][i] = 0.0f; 69 } 70 71 72 static void 73 point_persp_coeff(struct lp_setup_context *setup, 74 const struct point_info *info, 75 unsigned slot, 76 unsigned i) 77 { 78 /* 79 * Fragment shader expects pre-multiplied w for LP_INTERP_PERSPECTIVE. A 80 * better stratergy would be to take the primitive in consideration when 81 * generating the fragment shader key, and therefore avoid the per-fragment 82 * perspective divide. 83 */ 84 85 float w0 = info->v0[0][3]; 86 87 assert(i < 4); 88 89 info->a0[slot][i] = info->v0[slot][i]*w0; 90 info->dadx[slot][i] = 0.0f; 91 info->dady[slot][i] = 0.0f; 92 } 93 94 95 /** 96 * Setup automatic texcoord coefficients (for sprite rendering). 97 * \param slot the vertex attribute slot to setup 98 * \param i the attribute channel in [0,3] 99 * \param sprite_coord_origin one of PIPE_SPRITE_COORD_x 100 * \param perspective does the shader expects pre-multiplied w, i.e., 101 * LP_INTERP_PERSPECTIVE is specified in the shader key 102 */ 103 static void 104 texcoord_coef(struct lp_setup_context *setup, 105 const struct point_info *info, 106 unsigned slot, 107 unsigned i, 108 unsigned sprite_coord_origin, 109 boolean perspective) 110 { 111 float w0 = info->v0[0][3]; 112 113 assert(i < 4); 114 115 if (i == 0) { 116 float dadx = FIXED_ONE / (float)info->dx12; 117 float dady = 0.0f; 118 float x0 = info->v0[0][0] - setup->pixel_offset; 119 float y0 = info->v0[0][1] - setup->pixel_offset; 120 121 info->dadx[slot][0] = dadx; 122 info->dady[slot][0] = dady; 123 info->a0[slot][0] = 0.5 - (dadx * x0 + dady * y0); 124 125 if (perspective) { 126 info->dadx[slot][0] *= w0; 127 info->dady[slot][0] *= w0; 128 info->a0[slot][0] *= w0; 129 } 130 } 131 else if (i == 1) { 132 float dadx = 0.0f; 133 float dady = FIXED_ONE / (float)info->dx12; 134 float x0 = info->v0[0][0] - setup->pixel_offset; 135 float y0 = info->v0[0][1] - setup->pixel_offset; 136 137 if (sprite_coord_origin == PIPE_SPRITE_COORD_LOWER_LEFT) { 138 dady = -dady; 139 } 140 141 info->dadx[slot][1] = dadx; 142 info->dady[slot][1] = dady; 143 info->a0[slot][1] = 0.5 - (dadx * x0 + dady * y0); 144 145 if (perspective) { 146 info->dadx[slot][1] *= w0; 147 info->dady[slot][1] *= w0; 148 info->a0[slot][1] *= w0; 149 } 150 } 151 else if (i == 2) { 152 info->a0[slot][2] = 0.0f; 153 info->dadx[slot][2] = 0.0f; 154 info->dady[slot][2] = 0.0f; 155 } 156 else { 157 info->a0[slot][3] = perspective ? w0 : 1.0f; 158 info->dadx[slot][3] = 0.0f; 159 info->dady[slot][3] = 0.0f; 160 } 161 } 162 163 164 /** 165 * Special coefficient setup for gl_FragCoord. 166 * X and Y are trivial 167 * Z and W are copied from position_coef which should have already been computed. 168 * We could do a bit less work if we'd examine gl_FragCoord's swizzle mask. 169 */ 170 static void 171 setup_point_fragcoord_coef(struct lp_setup_context *setup, 172 struct point_info *info, 173 unsigned slot, 174 unsigned usage_mask) 175 { 176 /*X*/ 177 if (usage_mask & TGSI_WRITEMASK_X) { 178 info->a0[slot][0] = 0.0; 179 info->dadx[slot][0] = 1.0; 180 info->dady[slot][0] = 0.0; 181 } 182 183 /*Y*/ 184 if (usage_mask & TGSI_WRITEMASK_Y) { 185 info->a0[slot][1] = 0.0; 186 info->dadx[slot][1] = 0.0; 187 info->dady[slot][1] = 1.0; 188 } 189 190 /*Z*/ 191 if (usage_mask & TGSI_WRITEMASK_Z) { 192 constant_coef(setup, info, slot, info->v0[0][2], 2); 193 } 194 195 /*W*/ 196 if (usage_mask & TGSI_WRITEMASK_W) { 197 constant_coef(setup, info, slot, info->v0[0][3], 3); 198 } 199 } 200 201 202 /** 203 * Compute the point->coef[] array dadx, dady, a0 values. 204 */ 205 static void 206 setup_point_coefficients( struct lp_setup_context *setup, 207 struct point_info *info) 208 { 209 const struct lp_setup_variant_key *key = &setup->setup.variant->key; 210 const struct lp_fragment_shader *shader = setup->fs.current.variant->shader; 211 unsigned fragcoord_usage_mask = TGSI_WRITEMASK_XYZ; 212 unsigned slot; 213 214 /* setup interpolation for all the remaining attributes: 215 */ 216 for (slot = 0; slot < key->num_inputs; slot++) { 217 unsigned vert_attr = key->inputs[slot].src_index; 218 unsigned usage_mask = key->inputs[slot].usage_mask; 219 enum lp_interp interp = key->inputs[slot].interp; 220 boolean perspective = !!(interp == LP_INTERP_PERSPECTIVE); 221 unsigned i; 222 223 if (perspective & usage_mask) { 224 fragcoord_usage_mask |= TGSI_WRITEMASK_W; 225 } 226 227 switch (interp) { 228 case LP_INTERP_POSITION: 229 /* 230 * The generated pixel interpolators will pick up the coeffs from 231 * slot 0, so all need to ensure that the usage mask is covers all 232 * usages. 233 */ 234 fragcoord_usage_mask |= usage_mask; 235 break; 236 237 case LP_INTERP_LINEAR: 238 /* Sprite tex coords may use linear interpolation someday */ 239 /* fall-through */ 240 case LP_INTERP_PERSPECTIVE: 241 /* check if the sprite coord flag is set for this attribute. 242 * If so, set it up so it up so x and y vary from 0 to 1. 243 */ 244 if (shader->info.base.input_semantic_name[slot] == TGSI_SEMANTIC_GENERIC) { 245 unsigned semantic_index = shader->info.base.input_semantic_index[slot]; 246 /* Note that sprite_coord enable is a bitfield of 247 * PIPE_MAX_SHADER_OUTPUTS bits. 248 */ 249 if (semantic_index < PIPE_MAX_SHADER_OUTPUTS && 250 (setup->sprite_coord_enable & (1 << semantic_index))) { 251 for (i = 0; i < NUM_CHANNELS; i++) { 252 if (usage_mask & (1 << i)) { 253 texcoord_coef(setup, info, slot + 1, i, 254 setup->sprite_coord_origin, 255 perspective); 256 } 257 } 258 break; 259 } 260 } 261 /* fall-through */ 262 case LP_INTERP_CONSTANT: 263 for (i = 0; i < NUM_CHANNELS; i++) { 264 if (usage_mask & (1 << i)) { 265 if (perspective) { 266 point_persp_coeff(setup, info, slot+1, i); 267 } 268 else { 269 constant_coef(setup, info, slot+1, info->v0[vert_attr][i], i); 270 } 271 } 272 } 273 break; 274 275 case LP_INTERP_FACING: 276 for (i = 0; i < NUM_CHANNELS; i++) 277 if (usage_mask & (1 << i)) 278 constant_coef(setup, info, slot+1, 1.0, i); 279 break; 280 281 default: 282 assert(0); 283 break; 284 } 285 } 286 287 /* The internal position input is in slot zero: 288 */ 289 setup_point_fragcoord_coef(setup, info, 0, 290 fragcoord_usage_mask); 291 } 292 293 294 static INLINE int 295 subpixel_snap(float a) 296 { 297 return util_iround(FIXED_ONE * a); 298 } 299 300 301 static boolean 302 try_setup_point( struct lp_setup_context *setup, 303 const float (*v0)[4] ) 304 { 305 /* x/y positions in fixed point */ 306 const struct lp_setup_variant_key *key = &setup->setup.variant->key; 307 const int sizeAttr = setup->psize; 308 const float size 309 = (setup->point_size_per_vertex && sizeAttr > 0) ? v0[sizeAttr][0] 310 : setup->point_size; 311 312 /* Point size as fixed point integer, remove rounding errors 313 * and gives minimum width for very small points 314 */ 315 int fixed_width = MAX2(FIXED_ONE, 316 (subpixel_snap(size) + FIXED_ONE/2 - 1) & ~(FIXED_ONE-1)); 317 318 const int x0 = subpixel_snap(v0[0][0] - setup->pixel_offset) - fixed_width/2; 319 const int y0 = subpixel_snap(v0[0][1] - setup->pixel_offset) - fixed_width/2; 320 321 struct lp_scene *scene = setup->scene; 322 struct lp_rast_triangle *point; 323 unsigned bytes; 324 struct u_rect bbox; 325 unsigned nr_planes = 4; 326 struct point_info info; 327 328 329 /* Bounding rectangle (in pixels) */ 330 { 331 /* Yes this is necessary to accurately calculate bounding boxes 332 * with the two fill-conventions we support. GL (normally) ends 333 * up needing a bottom-left fill convention, which requires 334 * slightly different rounding. 335 */ 336 int adj = (setup->pixel_offset != 0) ? 1 : 0; 337 338 bbox.x0 = (x0 + (FIXED_ONE-1) + adj) >> FIXED_ORDER; 339 bbox.x1 = (x0 + fixed_width + (FIXED_ONE-1) + adj) >> FIXED_ORDER; 340 bbox.y0 = (y0 + (FIXED_ONE-1)) >> FIXED_ORDER; 341 bbox.y1 = (y0 + fixed_width + (FIXED_ONE-1)) >> FIXED_ORDER; 342 343 /* Inclusive coordinates: 344 */ 345 bbox.x1--; 346 bbox.y1--; 347 } 348 349 if (!u_rect_test_intersection(&setup->draw_region, &bbox)) { 350 if (0) debug_printf("offscreen\n"); 351 LP_COUNT(nr_culled_tris); 352 return TRUE; 353 } 354 355 u_rect_find_intersection(&setup->draw_region, &bbox); 356 357 point = lp_setup_alloc_triangle(scene, 358 key->num_inputs, 359 nr_planes, 360 &bytes); 361 if (!point) 362 return FALSE; 363 364 #ifdef DEBUG 365 point->v[0][0] = v0[0][0]; 366 point->v[0][1] = v0[0][1]; 367 #endif 368 369 info.v0 = v0; 370 info.dx01 = 0; 371 info.dx12 = fixed_width; 372 info.dy01 = fixed_width; 373 info.dy12 = 0; 374 info.a0 = GET_A0(&point->inputs); 375 info.dadx = GET_DADX(&point->inputs); 376 info.dady = GET_DADY(&point->inputs); 377 378 /* Setup parameter interpolants: 379 */ 380 setup_point_coefficients(setup, &info); 381 382 point->inputs.frontfacing = TRUE; 383 point->inputs.disable = FALSE; 384 point->inputs.opaque = FALSE; 385 386 { 387 struct lp_rast_plane *plane = GET_PLANES(point); 388 389 plane[0].dcdx = -1; 390 plane[0].dcdy = 0; 391 plane[0].c = 1-bbox.x0; 392 plane[0].eo = 1; 393 394 plane[1].dcdx = 1; 395 plane[1].dcdy = 0; 396 plane[1].c = bbox.x1+1; 397 plane[1].eo = 0; 398 399 plane[2].dcdx = 0; 400 plane[2].dcdy = 1; 401 plane[2].c = 1-bbox.y0; 402 plane[2].eo = 1; 403 404 plane[3].dcdx = 0; 405 plane[3].dcdy = -1; 406 plane[3].c = bbox.y1+1; 407 plane[3].eo = 0; 408 } 409 410 return lp_setup_bin_triangle(setup, point, &bbox, nr_planes); 411 } 412 413 414 static void 415 lp_setup_point(struct lp_setup_context *setup, 416 const float (*v0)[4]) 417 { 418 if (!try_setup_point( setup, v0 )) 419 { 420 if (!lp_setup_flush_and_restart(setup)) 421 return; 422 423 if (!try_setup_point( setup, v0 )) 424 return; 425 } 426 } 427 428 429 void 430 lp_setup_choose_point( struct lp_setup_context *setup ) 431 { 432 setup->point = lp_setup_point; 433 } 434 435 436