lp_setup_line.c revision b91553355f848f2174d53429699b116734781ad7
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/* 29 * Binning code for lines 30 */ 31 32#include "util/u_math.h" 33#include "util/u_memory.h" 34#include "lp_perf.h" 35#include "lp_setup_context.h" 36#include "lp_rast.h" 37#include "lp_state_fs.h" 38 39#define NUM_CHANNELS 4 40 41 42static const int step_scissor_minx[16] = { 43 0, 1, 0, 1, 44 2, 3, 2, 3, 45 0, 1, 0, 1, 46 2, 3, 2, 3 47}; 48 49static const int step_scissor_maxx[16] = { 50 0, -1, 0, -1, 51 -2, -3, -2, -3, 52 0, -1, 0, -1, 53 -2, -3, -2, -3 54}; 55 56static const int step_scissor_miny[16] = { 57 0, 0, 1, 1, 58 0, 0, 1, 1, 59 2, 2, 3, 3, 60 2, 2, 3, 3 61}; 62 63static const int step_scissor_maxy[16] = { 64 0, 0, -1, -1, 65 0, 0, -1, -1, 66 -2, -2, -3, -3, 67 -2, -2, -3, -3 68}; 69 70 71 72/** 73 * Compute a0 for a constant-valued coefficient (GL_FLAT shading). 74 */ 75static void constant_coef( struct lp_setup_context *setup, 76 struct lp_rast_triangle *tri, 77 unsigned slot, 78 const float value, 79 unsigned i ) 80{ 81 tri->inputs.a0[slot][i] = value; 82 tri->inputs.dadx[slot][i] = 0.0f; 83 tri->inputs.dady[slot][i] = 0.0f; 84} 85 86 87/** 88 * Compute a0, dadx and dady for a linearly interpolated coefficient, 89 * for a triangle. 90 */ 91static void linear_coef( struct lp_setup_context *setup, 92 struct lp_rast_triangle *tri, 93 float oneoverarea, 94 unsigned slot, 95 const float (*v1)[4], 96 const float (*v2)[4], 97 unsigned vert_attr, 98 unsigned i) 99{ 100 float a1 = v1[vert_attr][i]; 101 float a2 = v2[vert_attr][i]; 102 103 float da21 = a1 - a2; 104 float dadx = da21 * tri->dx * oneoverarea; 105 float dady = da21 * tri->dy * oneoverarea; 106 107 tri->inputs.dadx[slot][i] = dadx; 108 tri->inputs.dady[slot][i] = dady; 109 110 tri->inputs.a0[slot][i] = (a1 - 111 (dadx * (v1[0][0] - setup->pixel_offset) + 112 dady * (v1[0][1] - setup->pixel_offset))); 113} 114 115 116/** 117 * Compute a0, dadx and dady for a perspective-corrected interpolant, 118 * for a triangle. 119 * We basically multiply the vertex value by 1/w before computing 120 * the plane coefficients (a0, dadx, dady). 121 * Later, when we compute the value at a particular fragment position we'll 122 * divide the interpolated value by the interpolated W at that fragment. 123 */ 124static void perspective_coef( struct lp_setup_context *setup, 125 struct lp_rast_triangle *tri, 126 float oneoverarea, 127 unsigned slot, 128 const float (*v1)[4], 129 const float (*v2)[4], 130 unsigned vert_attr, 131 unsigned i) 132{ 133 /* premultiply by 1/w (v[0][3] is always 1/w): 134 */ 135 float a1 = v1[vert_attr][i] * v1[0][3]; 136 float a2 = v2[vert_attr][i] * v2[0][3]; 137 138 float da21 = a1 - a2; 139 float dadx = da21 * tri->dx * oneoverarea; 140 float dady = da21 * tri->dy * oneoverarea; 141 142 tri->inputs.dadx[slot][i] = dadx; 143 tri->inputs.dady[slot][i] = dady; 144 145 tri->inputs.a0[slot][i] = (a1 - 146 (dadx * (v1[0][0] - setup->pixel_offset) + 147 dady * (v1[0][1] - setup->pixel_offset))); 148} 149 150/** 151 * Compute the tri->coef[] array dadx, dady, a0 values. 152 */ 153static void setup_line_coefficients( struct lp_setup_context *setup, 154 struct lp_rast_triangle *tri, 155 float oneoverarea, 156 const float (*v1)[4], 157 const float (*v2)[4]) 158{ 159 unsigned fragcoord_usage_mask = TGSI_WRITEMASK_XYZ; 160 unsigned slot; 161 162 /* setup interpolation for all the remaining attributes: 163 */ 164 for (slot = 0; slot < setup->fs.nr_inputs; slot++) { 165 unsigned vert_attr = setup->fs.input[slot].src_index; 166 unsigned usage_mask = setup->fs.input[slot].usage_mask; 167 unsigned i; 168 169 switch (setup->fs.input[slot].interp) { 170 case LP_INTERP_CONSTANT: 171 if (setup->flatshade_first) { 172 for (i = 0; i < NUM_CHANNELS; i++) 173 if (usage_mask & (1 << i)) 174 constant_coef(setup, tri, slot+1, v1[vert_attr][i], i); 175 } 176 else { 177 for (i = 0; i < NUM_CHANNELS; i++) 178 if (usage_mask & (1 << i)) 179 constant_coef(setup, tri, slot+1, v2[vert_attr][i], i); 180 } 181 break; 182 183 case LP_INTERP_LINEAR: 184 for (i = 0; i < NUM_CHANNELS; i++) 185 if (usage_mask & (1 << i)) 186 linear_coef(setup, tri, oneoverarea, slot+1, v1, v2, vert_attr, i); 187 break; 188 189 case LP_INTERP_PERSPECTIVE: 190 for (i = 0; i < NUM_CHANNELS; i++) 191 if (usage_mask & (1 << i)) 192 perspective_coef(setup, tri, oneoverarea, slot+1, v1, v2, vert_attr, i); 193 fragcoord_usage_mask |= TGSI_WRITEMASK_W; 194 break; 195 196 case LP_INTERP_POSITION: 197 /* 198 * The generated pixel interpolators will pick up the coeffs from 199 * slot 0, so all need to ensure that the usage mask is covers all 200 * usages. 201 */ 202 fragcoord_usage_mask |= usage_mask; 203 break; 204 205 default: 206 assert(0); 207 } 208 } 209 210 /* The internal position input is in slot zero: 211 */ 212 lp_setup_fragcoord_coef(setup, tri, oneoverarea, 0, v1, v2, v2, 213 fragcoord_usage_mask); 214} 215 216 217 218static INLINE int subpixel_snap( float a ) 219{ 220 return util_iround(FIXED_ONE * a); 221} 222 223 224/** 225 * Print line vertex attribs (for debug). 226 */ 227static void 228print_line(struct lp_setup_context *setup, 229 const float (*v1)[4], 230 const float (*v2)[4]) 231{ 232 uint i; 233 234 debug_printf("llvmpipe line\n"); 235 for (i = 0; i < 1 + setup->fs.nr_inputs; i++) { 236 debug_printf(" v1[%d]: %f %f %f %f\n", i, 237 v1[i][0], v1[i][1], v1[i][2], v1[i][3]); 238 } 239 for (i = 0; i < 1 + setup->fs.nr_inputs; i++) { 240 debug_printf(" v2[%d]: %f %f %f %f\n", i, 241 v2[i][0], v2[i][1], v2[i][2], v2[i][3]); 242 } 243} 244 245 246static INLINE boolean sign(float x){ 247 return x >= 0; 248} 249 250 251static void 252lp_setup_line( struct lp_setup_context *setup, 253 const float (*v1)[4], 254 const float (*v2)[4]) 255{ 256 struct lp_scene *scene = lp_setup_get_current_scene(setup); 257 struct lp_rast_triangle *line; 258 float oneoverarea; 259 float width = MAX2(1.0, setup->line_width); 260 int minx, maxx, miny, maxy; 261 int ix0, ix1, iy0, iy1; 262 unsigned tri_bytes; 263 int x[4]; 264 int y[4]; 265 int i; 266 int nr_planes = 4; 267 boolean opaque; 268 269 /* linewidth should be interpreted as integer */ 270 int fixed_width = subpixel_snap(round(width)); 271 272 float xdiamond_offset=0; 273 float ydiamond_offset=0; 274 float xdiamond_offset_end=0; 275 float ydiamond_offset_end=0; 276 277 float x1diff; 278 float y1diff; 279 float x2diff; 280 float y2diff; 281 282 boolean draw_start; 283 boolean draw_end; 284 boolean will_draw_start; 285 boolean will_draw_end; 286 287 if (0) 288 print_line(setup, v1, v2); 289 290 if (setup->scissor_test) { 291 nr_planes = 8; 292 } 293 else { 294 nr_planes = 4; 295 } 296 297 line = lp_setup_alloc_triangle(scene, 298 setup->fs.nr_inputs, 299 nr_planes, 300 &tri_bytes); 301 if (!line) 302 return; 303 304#ifdef DEBUG 305 line->v[0][0] = v1[0][0]; 306 line->v[1][0] = v2[0][0]; 307 line->v[0][1] = v1[0][1]; 308 line->v[1][1] = v2[0][1]; 309#endif 310 311 line->dx = v1[0][0] - v2[0][0]; 312 line->dy = v1[0][1] - v2[0][1]; 313 314/* X-MAJOR LINE */ 315 if (fabsf(line->dx) >= fabsf(line->dy)) { 316 317 x1diff = v1[0][0] - (float) floor(v1[0][0]) - 0.5; 318 y1diff = v1[0][1] - (float) floor(v1[0][1]) - 0.5; 319 x2diff = v2[0][0] - (float) floor(v2[0][0]) - 0.5; 320 y2diff = v2[0][1] - (float) floor(v2[0][1]) - 0.5; 321 322 if (y2diff==-0.5 && line->dy<0){ 323 y2diff = 0.5; 324 } 325 326 /* 327 * Diamond exit rule test for starting point 328 */ 329 if (fabsf(x1diff) + fabsf(y1diff) < 0.5) { 330 draw_start = TRUE; 331 } 332 else if (sign(x1diff) == sign(-line->dx)) { 333 draw_start = FALSE; 334 } 335 else if (sign(-y1diff) != sign(line->dy)) { 336 draw_start = TRUE; 337 } 338 else { 339 /* do intersection test */ 340 float yintersect = v1[0][1] + x1diff*((float)line->dy/(float)line->dx); 341 if (yintersect < ceil(v1[0][1]) && yintersect > floor(v1[0][1])){ 342 draw_start = TRUE; 343 } 344 else draw_start = FALSE; 345 } 346 347 348 /* 349 * Diamond exit rule test for ending point 350 */ 351 if (fabsf(x2diff) + fabsf(y2diff) < 0.5) { 352 draw_end = FALSE; 353 } 354 else if (sign(x2diff) != sign(-line->dx)) { 355 draw_end = FALSE; 356 } 357 else if (sign(-y2diff) == sign(line->dy)) { 358 draw_end = TRUE; 359 } 360 else { 361 /* do intersection test */ 362 float yintersect = v2[0][1] + x2diff*((float)line->dy/(float)line->dx); 363 if (yintersect < ceil(v2[0][1]) && yintersect > floor(v2[0][1])){ 364 draw_end = TRUE; 365 } 366 else draw_end = FALSE; 367 } 368 369 /* Are we already drawing start/end? 370 */ 371 will_draw_start = sign(-x1diff) != sign(line->dx); 372 will_draw_end = (sign(x2diff) == sign(-line->dx)) || x2diff==0; 373 374 if (line->dx < 0) { 375 /* if v2 is to the right of v1, swap pointers */ 376 const float (*temp)[4] = v1; 377 v1 = v2; 378 v2 = temp; 379 line->dx = -line->dx; 380 line->dy = -line->dy; 381 /* Otherwise shift planes appropriately */ 382 if (will_draw_start != draw_start) { 383 xdiamond_offset_end = - x1diff - 0.5; 384 ydiamond_offset_end = xdiamond_offset_end*(float)line->dy/(float)line->dx; 385 386 } 387 if (will_draw_end != draw_end) { 388 xdiamond_offset = - x2diff - 0.5; 389 ydiamond_offset = xdiamond_offset*(float)line->dy/(float)line->dx; 390 } 391 392 } 393 else{ 394 /* Otherwise shift planes appropriately */ 395 if (will_draw_start != draw_start) { 396 xdiamond_offset = - x1diff + 0.5; 397 ydiamond_offset = xdiamond_offset*(float)line->dy/(float)line->dx; 398 } 399 if (will_draw_end != draw_end) { 400 xdiamond_offset_end = - x2diff + 0.5; 401 ydiamond_offset_end = xdiamond_offset_end*(float)line->dy/(float)line->dx; 402 } 403 } 404 405 /* x/y positions in fixed point */ 406 x[0] = subpixel_snap(v1[0][0] + xdiamond_offset - setup->pixel_offset); 407 x[1] = subpixel_snap(v2[0][0] + xdiamond_offset_end - setup->pixel_offset); 408 x[2] = subpixel_snap(v2[0][0] + xdiamond_offset_end - setup->pixel_offset); 409 x[3] = subpixel_snap(v1[0][0] + xdiamond_offset - setup->pixel_offset); 410 411 y[0] = subpixel_snap(v1[0][1] + ydiamond_offset - setup->pixel_offset) - fixed_width/2; 412 y[1] = subpixel_snap(v2[0][1] + ydiamond_offset_end - setup->pixel_offset) - fixed_width/2; 413 y[2] = subpixel_snap(v2[0][1] + ydiamond_offset_end - setup->pixel_offset) + fixed_width/2; 414 y[3] = subpixel_snap(v1[0][1] + ydiamond_offset - setup->pixel_offset) + fixed_width/2; 415 416 } 417 418 419 else{ 420/* Y-MAJOR LINE */ 421 x1diff = v1[0][0] - (float) floor(v1[0][0]) - 0.5; 422 y1diff = v1[0][1] - (float) floor(v1[0][1]) - 0.5; 423 x2diff = v2[0][0] - (float) floor(v2[0][0]) - 0.5; 424 y2diff = v2[0][1] - (float) floor(v2[0][1]) - 0.5; 425 426 if (x2diff==-0.5 && line->dx<0){ 427 x2diff = 0.5; 428 } 429 430/* 431 * Diamond exit rule test for starting point 432 */ 433 if (fabsf(x1diff) + fabsf(y1diff) < 0.5) { 434 draw_start = TRUE; 435 } 436 else if (sign(-y1diff) == sign(line->dy)) { 437 draw_start = FALSE; 438 } 439 else if (sign(x1diff) != sign(-line->dx)) { 440 draw_start = TRUE; 441 } 442 else { 443 /* do intersection test */ 444 float xintersect = v1[0][0] + y1diff*((float)line->dx/(float)line->dy); 445 if (xintersect < ceil(v1[0][0]) && xintersect > floor(v1[0][0])){ 446 draw_start = TRUE; 447 } 448 else draw_start = FALSE; 449 } 450 451 /* 452 * Diamond exit rule test for ending point 453 */ 454 if (fabsf(x2diff) + fabsf(y2diff) < 0.5) { 455 draw_end = FALSE; 456 } 457 else if (sign(-y2diff) != sign(line->dy) ) { 458 draw_end = FALSE; 459 } 460 else if (sign(x2diff) == sign(-line->dx) ) { 461 draw_end = TRUE; 462 } 463 else { 464 /* do intersection test */ 465 float xintersect = v2[0][0] + y2diff*((float)line->dx/(float)line->dy); 466 if (xintersect < ceil(v2[0][0]) && xintersect > floor(v2[0][0])){ 467 draw_end = TRUE; 468 } 469 else draw_end = FALSE; 470 } 471 472 /* Are we already drawing start/end? 473 */ 474 will_draw_start = sign(y1diff) == sign(line->dy); 475 will_draw_end = (sign(-y2diff) == sign(line->dy)) || y2diff==0; 476 477 if (line->dy > 0) { 478 /* if v2 is on top of v1, swap pointers */ 479 const float (*temp)[4] = v1; 480 v1 = v2; 481 v2 = temp; 482 line->dx = -line->dx; 483 line->dy = -line->dy; 484 485 /* Otherwise shift planes appropriately */ 486 if (will_draw_start != draw_start) { 487 ydiamond_offset_end = - y1diff + 0.5; 488 xdiamond_offset_end = ydiamond_offset_end*(float)line->dx/(float)line->dy; 489 } 490 if (will_draw_end != draw_end) { 491 ydiamond_offset = - y2diff + 0.5; 492 xdiamond_offset = ydiamond_offset*(float)line->dx/(float)line->dy; 493 } 494 } 495 496 else{ 497 /* Otherwise shift planes appropriately */ 498 if (will_draw_start != draw_start) { 499 ydiamond_offset = - y1diff - 0.5; 500 xdiamond_offset = ydiamond_offset*(float)line->dx/(float)line->dy; 501 502 } 503 if (will_draw_end != draw_end) { 504 ydiamond_offset_end = - y2diff - 0.5; 505 xdiamond_offset_end = ydiamond_offset_end*(float)line->dx/(float)line->dy; 506 } 507 } 508 509 /* x/y positions in fixed point */ 510 x[0] = subpixel_snap(v1[0][0] + xdiamond_offset - setup->pixel_offset) - fixed_width/2; 511 x[1] = subpixel_snap(v2[0][0] + xdiamond_offset_end - setup->pixel_offset) - fixed_width/2; 512 x[2] = subpixel_snap(v2[0][0] + xdiamond_offset_end - setup->pixel_offset) + fixed_width/2; 513 x[3] = subpixel_snap(v1[0][0] + xdiamond_offset - setup->pixel_offset) + fixed_width/2; 514 515 y[0] = subpixel_snap(v1[0][1] + ydiamond_offset - setup->pixel_offset); 516 y[1] = subpixel_snap(v2[0][1] + ydiamond_offset_end - setup->pixel_offset); 517 y[2] = subpixel_snap(v2[0][1] + ydiamond_offset_end - setup->pixel_offset); 518 y[3] = subpixel_snap(v1[0][1] + ydiamond_offset - setup->pixel_offset); 519 } 520 521 522 /* calculate the deltas */ 523 line->plane[0].dcdy = x[0] - x[1]; 524 line->plane[1].dcdy = x[1] - x[2]; 525 line->plane[2].dcdy = x[2] - x[3]; 526 line->plane[3].dcdy = x[3] - x[0]; 527 528 line->plane[0].dcdx = y[0] - y[1]; 529 line->plane[1].dcdx = y[1] - y[2]; 530 line->plane[2].dcdx = y[2] - y[3]; 531 line->plane[3].dcdx = y[3] - y[0]; 532 533 534 LP_COUNT(nr_tris); 535 536 537 /* Bounding rectangle (in pixels) */ 538 { 539 /* Yes this is necessary to accurately calculate bounding boxes 540 * with the two fill-conventions we support. GL (normally) ends 541 * up needing a bottom-left fill convention, which requires 542 * slightly different rounding. 543 */ 544 int adj = (setup->pixel_offset != 0) ? 1 : 0; 545 546 minx = (MIN4(x[0], x[1], x[2], x[3]) + (FIXED_ONE-1)) >> FIXED_ORDER; 547 maxx = (MAX4(x[0], x[1], x[2], x[3]) + (FIXED_ONE-1)) >> FIXED_ORDER; 548 miny = (MIN4(y[0], y[1], y[2], y[3]) + (FIXED_ONE-1) + adj) >> FIXED_ORDER; 549 maxy = (MAX4(y[0], y[1], y[2], y[3]) + (FIXED_ONE-1) + adj) >> FIXED_ORDER; 550 } 551 552 if (setup->scissor_test) { 553 minx = MAX2(minx, setup->scissor.current.minx); 554 maxx = MIN2(maxx, setup->scissor.current.maxx); 555 miny = MAX2(miny, setup->scissor.current.miny); 556 maxy = MIN2(maxy, setup->scissor.current.maxy); 557 } 558 else { 559 minx = MAX2(minx, 0); 560 miny = MAX2(miny, 0); 561 maxx = MIN2(maxx, scene->fb.width); 562 maxy = MIN2(maxy, scene->fb.height); 563 } 564 565 566 if (miny >= maxy || minx >= maxx) { 567 lp_scene_putback_data( scene, tri_bytes ); 568 return; 569 } 570 571 oneoverarea = 1.0f / (line->dx * line->dx + line->dy * line->dy); 572 573 /* Setup parameter interpolants: 574 */ 575 setup_line_coefficients( setup, line, oneoverarea, v1, v2); 576 577 for (i = 0; i < 4; i++) { 578 struct lp_rast_plane *plane = &line->plane[i]; 579 580 /* half-edge constants, will be interated over the whole render 581 * target. 582 */ 583 plane->c = plane->dcdx * x[i] - plane->dcdy * y[i]; 584 585 586 /* correct for top-left vs. bottom-left fill convention. 587 * 588 * note that we're overloading gl_rasterization_rules to mean 589 * both (0.5,0.5) pixel centers *and* bottom-left filling 590 * convention. 591 * 592 * GL actually has a top-left filling convention, but GL's 593 * notion of "top" differs from gallium's... 594 * 595 * Also, sometimes (in FBO cases) GL will render upside down 596 * to its usual method, in which case it will probably want 597 * to use the opposite, top-left convention. 598 */ 599 if (plane->dcdx < 0) { 600 /* both fill conventions want this - adjust for left edges */ 601 plane->c++; 602 } 603 else if (plane->dcdx == 0) { 604 if (setup->pixel_offset == 0) { 605 /* correct for top-left fill convention: 606 */ 607 if (plane->dcdy > 0) plane->c++; 608 } 609 else { 610 /* correct for bottom-left fill convention: 611 */ 612 if (plane->dcdy < 0) plane->c++; 613 } 614 } 615 616 plane->dcdx *= FIXED_ONE; 617 plane->dcdy *= FIXED_ONE; 618 619 /* find trivial reject offsets for each edge for a single-pixel 620 * sized block. These will be scaled up at each recursive level to 621 * match the active blocksize. Scaling in this way works best if 622 * the blocks are square. 623 */ 624 plane->eo = 0; 625 if (plane->dcdx < 0) plane->eo -= plane->dcdx; 626 if (plane->dcdy > 0) plane->eo += plane->dcdy; 627 628 /* Calculate trivial accept offsets from the above. 629 */ 630 plane->ei = plane->dcdy - plane->dcdx - plane->eo; 631 632 plane->step = line->step[i]; 633 634 /* Fill in the inputs.step[][] arrays. 635 * We've manually unrolled some loops here. 636 */ 637#define SETUP_STEP(j, x, y) \ 638 line->step[i][j] = y * plane->dcdy - x * plane->dcdx 639 640 SETUP_STEP(0, 0, 0); 641 SETUP_STEP(1, 1, 0); 642 SETUP_STEP(2, 0, 1); 643 SETUP_STEP(3, 1, 1); 644 645 SETUP_STEP(4, 2, 0); 646 SETUP_STEP(5, 3, 0); 647 SETUP_STEP(6, 2, 1); 648 SETUP_STEP(7, 3, 1); 649 650 SETUP_STEP(8, 0, 2); 651 SETUP_STEP(9, 1, 2); 652 SETUP_STEP(10, 0, 3); 653 SETUP_STEP(11, 1, 3); 654 655 SETUP_STEP(12, 2, 2); 656 SETUP_STEP(13, 3, 2); 657 SETUP_STEP(14, 2, 3); 658 SETUP_STEP(15, 3, 3); 659#undef STEP 660 } 661 662 663 /* 664 * When rasterizing scissored tris, use the intersection of the 665 * triangle bounding box and the scissor rect to generate the 666 * scissor planes. 667 * 668 * This permits us to cut off the triangle "tails" that are present 669 * in the intermediate recursive levels caused when two of the 670 * triangles edges don't diverge quickly enough to trivially reject 671 * exterior blocks from the triangle. 672 * 673 * It's not really clear if it's worth worrying about these tails, 674 * but since we generate the planes for each scissored tri, it's 675 * free to trim them in this case. 676 * 677 * Note that otherwise, the scissor planes only vary in 'C' value, 678 * and even then only on state-changes. Could alternatively store 679 * these planes elsewhere. 680 */ 681 if (nr_planes == 8) { 682 line->plane[4].step = step_scissor_maxx; 683 line->plane[4].dcdx = 1; 684 line->plane[4].dcdy = 0; 685 line->plane[4].c = maxx; 686 line->plane[4].ei = -1; 687 line->plane[4].eo = 0; 688 689 line->plane[5].step = step_scissor_miny; 690 line->plane[5].dcdx = 0; 691 line->plane[5].dcdy = 1; 692 line->plane[5].c = 1-miny; 693 line->plane[5].ei = 0; 694 line->plane[5].eo = 1; 695 696 line->plane[6].step = step_scissor_maxy; 697 line->plane[6].dcdx = 0; 698 line->plane[6].dcdy = -1; 699 line->plane[6].c = maxy; 700 line->plane[6].ei = -1; 701 line->plane[6].eo = 0; 702 703 line->plane[7].step = step_scissor_minx; 704 line->plane[7].dcdx = -1; 705 line->plane[7].dcdy = 0; 706 line->plane[7].c = 1-minx; 707 line->plane[7].ei = 0; 708 line->plane[7].eo = 1; 709 } 710 711 712 /* 713 * All fields of 'line' are now set. The remaining code here is 714 * concerned with binning. 715 */ 716 717 /* Convert to tile coordinates, and inclusive ranges: 718 */ 719 ix0 = minx / TILE_SIZE; 720 iy0 = miny / TILE_SIZE; 721 ix1 = (maxx-1) / TILE_SIZE; 722 iy1 = (maxy-1) / TILE_SIZE; 723 724 /* 725 * Clamp to framebuffer size 726 */ 727 assert(ix0 == MAX2(ix0, 0)); 728 assert(iy0 == MAX2(iy0, 0)); 729 assert(ix1 == MIN2(ix1, scene->tiles_x - 1)); 730 assert(iy1 == MIN2(iy1, scene->tiles_y - 1)); 731 732 /* Determine which tile(s) intersect the triangle's bounding box 733 */ 734 if (iy0 == iy1 && ix0 == ix1) 735 { 736 /* Triangle is contained in a single tile: 737 */ 738 lp_scene_bin_command( scene, ix0, iy0, 739 lp_rast_tri_tab[nr_planes], 740 lp_rast_arg_triangle(line, (1<<nr_planes)-1) ); 741 } 742 else 743 { 744 int c[8]; 745 int ei[8]; 746 int eo[8]; 747 int xstep[8]; 748 int ystep[8]; 749 int x, y; 750 int is_blit = -1; /* undetermined */ 751 752 for (i = 0; i < nr_planes; i++) { 753 c[i] = (line->plane[i].c + 754 line->plane[i].dcdy * iy0 * TILE_SIZE - 755 line->plane[i].dcdx * ix0 * TILE_SIZE); 756 757 ei[i] = line->plane[i].ei << TILE_ORDER; 758 eo[i] = line->plane[i].eo << TILE_ORDER; 759 xstep[i] = -(line->plane[i].dcdx << TILE_ORDER); 760 ystep[i] = line->plane[i].dcdy << TILE_ORDER; 761 } 762 763 764 765 /* Test tile-sized blocks against the triangle. 766 * Discard blocks fully outside the tri. If the block is fully 767 * contained inside the tri, bin an lp_rast_shade_tile command. 768 * Else, bin a lp_rast_triangle command. 769 */ 770 for (y = iy0; y <= iy1; y++) 771 { 772 boolean in = FALSE; /* are we inside the triangle? */ 773 int cx[8]; 774 775 for (i = 0; i < nr_planes; i++) 776 cx[i] = c[i]; 777 778 for (x = ix0; x <= ix1; x++) 779 { 780 int out = 0; 781 int partial = 0; 782 783 for (i = 0; i < nr_planes; i++) { 784 int planeout = cx[i] + eo[i]; 785 int planepartial = cx[i] + ei[i] - 1; 786 out |= (planeout >> 31); 787 partial |= (planepartial >> 31) & (1<<i); 788 } 789 if (out) { 790 /* do nothing */ 791 if (in) 792 break; /* exiting triangle, all done with this row */ 793 LP_COUNT(nr_empty_64); 794 } 795 else if (partial) { 796 /* Not trivially accepted by at least one plane - 797 * rasterize/shade partial tile 798 */ 799 int count = util_bitcount(partial); 800 in = TRUE; 801 lp_scene_bin_command( scene, x, y, 802 lp_rast_tri_tab[count], 803 lp_rast_arg_triangle(line, partial) ); 804 805 LP_COUNT(nr_partially_covered_64); 806 } 807 else { 808 /* triangle covers the whole tile- shade whole tile */ 809 LP_COUNT(nr_fully_covered_64); 810 in = TRUE; 811 /* leverages on existing code in lp_setup_tri.c */ 812 do_triangle_ccw_whole_tile(setup, scene, line, x, y, 813 opaque, &is_blit); 814 } 815 816 /* Iterate cx values across the region: 817 */ 818 for (i = 0; i < nr_planes; i++) 819 cx[i] += xstep[i]; 820 } 821 822 /* Iterate c values down the region: 823 */ 824 for (i = 0; i < nr_planes; i++) 825 c[i] += ystep[i]; 826 } 827 } 828} 829 830 831void lp_setup_choose_line( struct lp_setup_context *setup ) 832{ 833 setup->line = lp_setup_line; 834} 835 836 837