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