lp_setup_line.c revision 0a1c9001037a13b69b157994e7983aa3dee158d3
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 41struct lp_line_info { 42 43 float dx; 44 float dy; 45 float oneoverarea; 46 47 const float (*v1)[4]; 48 const float (*v2)[4]; 49}; 50 51 52/** 53 * Compute a0 for a constant-valued coefficient (GL_FLAT shading). 54 */ 55static void constant_coef( struct lp_setup_context *setup, 56 struct lp_rast_triangle *tri, 57 unsigned slot, 58 const float value, 59 unsigned i ) 60{ 61 tri->inputs.a0[slot][i] = value; 62 tri->inputs.dadx[slot][i] = 0.0f; 63 tri->inputs.dady[slot][i] = 0.0f; 64} 65 66 67/** 68 * Compute a0, dadx and dady for a linearly interpolated coefficient, 69 * for a triangle. 70 */ 71static void linear_coef( struct lp_setup_context *setup, 72 struct lp_rast_triangle *tri, 73 struct lp_line_info *info, 74 unsigned slot, 75 unsigned vert_attr, 76 unsigned i) 77{ 78 float a1 = info->v1[vert_attr][i]; 79 float a2 = info->v2[vert_attr][i]; 80 81 float da21 = a1 - a2; 82 float dadx = da21 * info->dx * info->oneoverarea; 83 float dady = da21 * info->dy * info->oneoverarea; 84 85 tri->inputs.dadx[slot][i] = dadx; 86 tri->inputs.dady[slot][i] = dady; 87 88 tri->inputs.a0[slot][i] = (a1 - 89 (dadx * (info->v1[0][0] - setup->pixel_offset) + 90 dady * (info->v1[0][1] - setup->pixel_offset))); 91} 92 93 94/** 95 * Compute a0, dadx and dady for a perspective-corrected interpolant, 96 * for a triangle. 97 * We basically multiply the vertex value by 1/w before computing 98 * the plane coefficients (a0, dadx, dady). 99 * Later, when we compute the value at a particular fragment position we'll 100 * divide the interpolated value by the interpolated W at that fragment. 101 */ 102static void perspective_coef( struct lp_setup_context *setup, 103 struct lp_rast_triangle *tri, 104 struct lp_line_info *info, 105 unsigned slot, 106 unsigned vert_attr, 107 unsigned i) 108{ 109 /* premultiply by 1/w (v[0][3] is always 1/w): 110 */ 111 float a1 = info->v1[vert_attr][i] * info->v1[0][3]; 112 float a2 = info->v2[vert_attr][i] * info->v2[0][3]; 113 114 float da21 = a1 - a2; 115 float dadx = da21 * info->dx * info->oneoverarea; 116 float dady = da21 * info->dy * info->oneoverarea; 117 118 tri->inputs.dadx[slot][i] = dadx; 119 tri->inputs.dady[slot][i] = dady; 120 121 tri->inputs.a0[slot][i] = (a1 - 122 (dadx * (info->v1[0][0] - setup->pixel_offset) + 123 dady * (info->v1[0][1] - setup->pixel_offset))); 124} 125 126static void 127setup_fragcoord_coef( struct lp_setup_context *setup, 128 struct lp_rast_triangle *tri, 129 struct lp_line_info *info, 130 unsigned slot, 131 unsigned usage_mask) 132{ 133 /*X*/ 134 if (usage_mask & TGSI_WRITEMASK_X) { 135 tri->inputs.a0[slot][0] = 0.0; 136 tri->inputs.dadx[slot][0] = 1.0; 137 tri->inputs.dady[slot][0] = 0.0; 138 } 139 140 /*Y*/ 141 if (usage_mask & TGSI_WRITEMASK_Y) { 142 tri->inputs.a0[slot][1] = 0.0; 143 tri->inputs.dadx[slot][1] = 0.0; 144 tri->inputs.dady[slot][1] = 1.0; 145 } 146 147 /*Z*/ 148 if (usage_mask & TGSI_WRITEMASK_Z) { 149 linear_coef(setup, tri, info, slot, 0, 2); 150 } 151 152 /*W*/ 153 if (usage_mask & TGSI_WRITEMASK_W) { 154 linear_coef(setup, tri, info, slot, 0, 3); 155 } 156} 157 158/** 159 * Compute the tri->coef[] array dadx, dady, a0 values. 160 */ 161static void setup_line_coefficients( struct lp_setup_context *setup, 162 struct lp_rast_triangle *tri, 163 struct lp_line_info *info) 164{ 165 unsigned fragcoord_usage_mask = TGSI_WRITEMASK_XYZ; 166 unsigned slot; 167 168 /* setup interpolation for all the remaining attributes: 169 */ 170 for (slot = 0; slot < setup->fs.nr_inputs; slot++) { 171 unsigned vert_attr = setup->fs.input[slot].src_index; 172 unsigned usage_mask = setup->fs.input[slot].usage_mask; 173 unsigned i; 174 175 switch (setup->fs.input[slot].interp) { 176 case LP_INTERP_CONSTANT: 177 if (setup->flatshade_first) { 178 for (i = 0; i < NUM_CHANNELS; i++) 179 if (usage_mask & (1 << i)) 180 constant_coef(setup, tri, slot+1, info->v1[vert_attr][i], i); 181 } 182 else { 183 for (i = 0; i < NUM_CHANNELS; i++) 184 if (usage_mask & (1 << i)) 185 constant_coef(setup, tri, slot+1, info->v2[vert_attr][i], i); 186 } 187 break; 188 189 case LP_INTERP_LINEAR: 190 for (i = 0; i < NUM_CHANNELS; i++) 191 if (usage_mask & (1 << i)) 192 linear_coef(setup, tri, info, slot+1, vert_attr, i); 193 break; 194 195 case LP_INTERP_PERSPECTIVE: 196 for (i = 0; i < NUM_CHANNELS; i++) 197 if (usage_mask & (1 << i)) 198 perspective_coef(setup, tri, info, slot+1, vert_attr, i); 199 fragcoord_usage_mask |= TGSI_WRITEMASK_W; 200 break; 201 202 case LP_INTERP_POSITION: 203 /* 204 * The generated pixel interpolators will pick up the coeffs from 205 * slot 0, so all need to ensure that the usage mask is covers all 206 * usages. 207 */ 208 fragcoord_usage_mask |= usage_mask; 209 break; 210 211 case LP_INTERP_FACING: 212 for (i = 0; i < NUM_CHANNELS; i++) 213 if (usage_mask & (1 << i)) 214 constant_coef(setup, tri, slot+1, 1.0, i); 215 break; 216 217 default: 218 assert(0); 219 } 220 } 221 222 /* The internal position input is in slot zero: 223 */ 224 setup_fragcoord_coef(setup, tri, info, 0, 225 fragcoord_usage_mask); 226} 227 228 229 230static INLINE int subpixel_snap( float a ) 231{ 232 return util_iround(FIXED_ONE * a); 233} 234 235 236/** 237 * Print line vertex attribs (for debug). 238 */ 239static void 240print_line(struct lp_setup_context *setup, 241 const float (*v1)[4], 242 const float (*v2)[4]) 243{ 244 uint i; 245 246 debug_printf("llvmpipe line\n"); 247 for (i = 0; i < 1 + setup->fs.nr_inputs; i++) { 248 debug_printf(" v1[%d]: %f %f %f %f\n", i, 249 v1[i][0], v1[i][1], v1[i][2], v1[i][3]); 250 } 251 for (i = 0; i < 1 + setup->fs.nr_inputs; i++) { 252 debug_printf(" v2[%d]: %f %f %f %f\n", i, 253 v2[i][0], v2[i][1], v2[i][2], v2[i][3]); 254 } 255} 256 257 258static INLINE boolean sign(float x){ 259 return x >= 0; 260} 261 262 263/* Used on positive floats only: 264 */ 265static INLINE float fracf(float f) 266{ 267 return f - floorf(f); 268} 269 270 271 272static boolean 273try_setup_line( struct lp_setup_context *setup, 274 const float (*v1)[4], 275 const float (*v2)[4]) 276{ 277 struct lp_scene *scene = setup->scene; 278 struct lp_rast_triangle *line; 279 struct lp_line_info info; 280 float width = MAX2(1.0, setup->line_width); 281 struct u_rect bbox; 282 unsigned tri_bytes; 283 int x[4]; 284 int y[4]; 285 int i; 286 int nr_planes = 4; 287 288 /* linewidth should be interpreted as integer */ 289 int fixed_width = util_iround(width) * FIXED_ONE; 290 291 float x_offset=0; 292 float y_offset=0; 293 float x_offset_end=0; 294 float y_offset_end=0; 295 296 float x1diff; 297 float y1diff; 298 float x2diff; 299 float y2diff; 300 float dx, dy; 301 float area; 302 303 boolean draw_start; 304 boolean draw_end; 305 boolean will_draw_start; 306 boolean will_draw_end; 307 308 if (0) 309 print_line(setup, v1, v2); 310 311 if (setup->scissor_test) { 312 nr_planes = 8; 313 } 314 else { 315 nr_planes = 4; 316 } 317 318 319 dx = v1[0][0] - v2[0][0]; 320 dy = v1[0][1] - v2[0][1]; 321 area = (dx * dx + dy * dy); 322 if (area == 0) { 323 LP_COUNT(nr_culled_tris); 324 return TRUE; 325 } 326 327 info.oneoverarea = 1.0f / area; 328 info.dx = dx; 329 info.dy = dy; 330 info.v1 = v1; 331 info.v2 = v2; 332 333 334 /* X-MAJOR LINE */ 335 if (fabsf(dx) >= fabsf(dy)) { 336 float dydx = dy / dx; 337 338 x1diff = v1[0][0] - (float) floor(v1[0][0]) - 0.5; 339 y1diff = v1[0][1] - (float) floor(v1[0][1]) - 0.5; 340 x2diff = v2[0][0] - (float) floor(v2[0][0]) - 0.5; 341 y2diff = v2[0][1] - (float) floor(v2[0][1]) - 0.5; 342 343 if (y2diff==-0.5 && dy<0){ 344 y2diff = 0.5; 345 } 346 347 /* 348 * Diamond exit rule test for starting point 349 */ 350 if (fabsf(x1diff) + fabsf(y1diff) < 0.5) { 351 draw_start = TRUE; 352 } 353 else if (sign(x1diff) == sign(-dx)) { 354 draw_start = FALSE; 355 } 356 else if (sign(-y1diff) != sign(dy)) { 357 draw_start = TRUE; 358 } 359 else { 360 /* do intersection test */ 361 float yintersect = fracf(v1[0][1]) + x1diff * dydx; 362 draw_start = (yintersect < 1.0 && yintersect > 0.0); 363 } 364 365 366 /* 367 * Diamond exit rule test for ending point 368 */ 369 if (fabsf(x2diff) + fabsf(y2diff) < 0.5) { 370 draw_end = FALSE; 371 } 372 else if (sign(x2diff) != sign(-dx)) { 373 draw_end = FALSE; 374 } 375 else if (sign(-y2diff) == sign(dy)) { 376 draw_end = TRUE; 377 } 378 else { 379 /* do intersection test */ 380 float yintersect = fracf(v2[0][1]) + x2diff * dydx; 381 draw_end = (yintersect < 1.0 && yintersect > 0.0); 382 } 383 384 /* Are we already drawing start/end? 385 */ 386 will_draw_start = sign(-x1diff) != sign(dx); 387 will_draw_end = (sign(x2diff) == sign(-dx)) || x2diff==0; 388 389 if (dx < 0) { 390 /* if v2 is to the right of v1, swap pointers */ 391 const float (*temp)[4] = v1; 392 v1 = v2; 393 v2 = temp; 394 dx = -dx; 395 dy = -dy; 396 /* Otherwise shift planes appropriately */ 397 if (will_draw_start != draw_start) { 398 x_offset_end = - x1diff - 0.5; 399 y_offset_end = x_offset_end * dydx; 400 401 } 402 if (will_draw_end != draw_end) { 403 x_offset = - x2diff - 0.5; 404 y_offset = x_offset * dydx; 405 } 406 407 } 408 else{ 409 /* Otherwise shift planes appropriately */ 410 if (will_draw_start != draw_start) { 411 x_offset = - x1diff + 0.5; 412 y_offset = x_offset * dydx; 413 } 414 if (will_draw_end != draw_end) { 415 x_offset_end = - x2diff + 0.5; 416 y_offset_end = x_offset_end * dydx; 417 } 418 } 419 420 /* x/y positions in fixed point */ 421 x[0] = subpixel_snap(v1[0][0] + x_offset - setup->pixel_offset); 422 x[1] = subpixel_snap(v2[0][0] + x_offset_end - setup->pixel_offset); 423 x[2] = subpixel_snap(v2[0][0] + x_offset_end - setup->pixel_offset); 424 x[3] = subpixel_snap(v1[0][0] + x_offset - setup->pixel_offset); 425 426 y[0] = subpixel_snap(v1[0][1] + y_offset - setup->pixel_offset) - fixed_width/2; 427 y[1] = subpixel_snap(v2[0][1] + y_offset_end - setup->pixel_offset) - fixed_width/2; 428 y[2] = subpixel_snap(v2[0][1] + y_offset_end - setup->pixel_offset) + fixed_width/2; 429 y[3] = subpixel_snap(v1[0][1] + y_offset - setup->pixel_offset) + fixed_width/2; 430 431 } 432 else { 433 const float dxdy = dx / dy; 434 435 /* Y-MAJOR LINE */ 436 x1diff = v1[0][0] - (float) floor(v1[0][0]) - 0.5; 437 y1diff = v1[0][1] - (float) floor(v1[0][1]) - 0.5; 438 x2diff = v2[0][0] - (float) floor(v2[0][0]) - 0.5; 439 y2diff = v2[0][1] - (float) floor(v2[0][1]) - 0.5; 440 441 if (x2diff==-0.5 && dx<0) { 442 x2diff = 0.5; 443 } 444 445 /* 446 * Diamond exit rule test for starting point 447 */ 448 if (fabsf(x1diff) + fabsf(y1diff) < 0.5) { 449 draw_start = TRUE; 450 } 451 else if (sign(-y1diff) == sign(dy)) { 452 draw_start = FALSE; 453 } 454 else if (sign(x1diff) != sign(-dx)) { 455 draw_start = TRUE; 456 } 457 else { 458 /* do intersection test */ 459 float xintersect = fracf(v1[0][0]) + y1diff * dxdy; 460 draw_start = (xintersect < 1.0 && xintersect > 0.0); 461 } 462 463 /* 464 * Diamond exit rule test for ending point 465 */ 466 if (fabsf(x2diff) + fabsf(y2diff) < 0.5) { 467 draw_end = FALSE; 468 } 469 else if (sign(-y2diff) != sign(dy) ) { 470 draw_end = FALSE; 471 } 472 else if (sign(x2diff) == sign(-dx) ) { 473 draw_end = TRUE; 474 } 475 else { 476 /* do intersection test */ 477 float xintersect = fracf(v2[0][0]) + y2diff * dxdy; 478 draw_end = (xintersect < 1.0 && xintersect >= 0.0); 479 } 480 481 /* Are we already drawing start/end? 482 */ 483 will_draw_start = sign(y1diff) == sign(dy); 484 will_draw_end = (sign(-y2diff) == sign(dy)) || y2diff==0; 485 486 if (dy > 0) { 487 /* if v2 is on top of v1, swap pointers */ 488 const float (*temp)[4] = v1; 489 v1 = v2; 490 v2 = temp; 491 dx = -dx; 492 dy = -dy; 493 494 /* Otherwise shift planes appropriately */ 495 if (will_draw_start != draw_start) { 496 y_offset_end = - y1diff + 0.5; 497 x_offset_end = y_offset_end * dxdy; 498 } 499 if (will_draw_end != draw_end) { 500 y_offset = - y2diff + 0.5; 501 x_offset = y_offset * dxdy; 502 } 503 } 504 else { 505 /* Otherwise shift planes appropriately */ 506 if (will_draw_start != draw_start) { 507 y_offset = - y1diff - 0.5; 508 x_offset = y_offset * dxdy; 509 510 } 511 if (will_draw_end != draw_end) { 512 y_offset_end = - y2diff - 0.5; 513 x_offset_end = y_offset_end * dxdy; 514 } 515 } 516 517 /* x/y positions in fixed point */ 518 x[0] = subpixel_snap(v1[0][0] + x_offset - setup->pixel_offset) - fixed_width/2; 519 x[1] = subpixel_snap(v2[0][0] + x_offset_end - setup->pixel_offset) - fixed_width/2; 520 x[2] = subpixel_snap(v2[0][0] + x_offset_end - setup->pixel_offset) + fixed_width/2; 521 x[3] = subpixel_snap(v1[0][0] + x_offset - setup->pixel_offset) + fixed_width/2; 522 523 y[0] = subpixel_snap(v1[0][1] + y_offset - setup->pixel_offset); 524 y[1] = subpixel_snap(v2[0][1] + y_offset_end - setup->pixel_offset); 525 y[2] = subpixel_snap(v2[0][1] + y_offset_end - setup->pixel_offset); 526 y[3] = subpixel_snap(v1[0][1] + y_offset - setup->pixel_offset); 527 } 528 529 530 531 LP_COUNT(nr_tris); 532 533 534 /* Bounding rectangle (in pixels) */ 535 { 536 /* Yes this is necessary to accurately calculate bounding boxes 537 * with the two fill-conventions we support. GL (normally) ends 538 * up needing a bottom-left fill convention, which requires 539 * slightly different rounding. 540 */ 541 int adj = (setup->pixel_offset != 0) ? 1 : 0; 542 543 bbox.x0 = (MIN4(x[0], x[1], x[2], x[3]) + (FIXED_ONE-1)) >> FIXED_ORDER; 544 bbox.x1 = (MAX4(x[0], x[1], x[2], x[3]) + (FIXED_ONE-1)) >> FIXED_ORDER; 545 bbox.y0 = (MIN4(y[0], y[1], y[2], y[3]) + (FIXED_ONE-1) + adj) >> FIXED_ORDER; 546 bbox.y1 = (MAX4(y[0], y[1], y[2], y[3]) + (FIXED_ONE-1) + adj) >> FIXED_ORDER; 547 548 /* Inclusive coordinates: 549 */ 550 bbox.x1--; 551 bbox.y1--; 552 } 553 554 if (bbox.x1 < bbox.x0 || 555 bbox.y1 < bbox.y0) { 556 if (0) debug_printf("empty bounding box\n"); 557 LP_COUNT(nr_culled_tris); 558 return TRUE; 559 } 560 561 if (!u_rect_test_intersection(&setup->draw_region, &bbox)) { 562 if (0) debug_printf("offscreen\n"); 563 LP_COUNT(nr_culled_tris); 564 return TRUE; 565 } 566 567 u_rect_find_intersection(&setup->draw_region, &bbox); 568 569 line = lp_setup_alloc_triangle(scene, 570 setup->fs.nr_inputs, 571 nr_planes, 572 &tri_bytes); 573 if (!line) 574 return FALSE; 575 576#ifdef DEBUG 577 line->v[0][0] = v1[0][0]; 578 line->v[1][0] = v2[0][0]; 579 line->v[0][1] = v1[0][1]; 580 line->v[1][1] = v2[0][1]; 581#endif 582 583 /* calculate the deltas */ 584 line->plane[0].dcdy = x[0] - x[1]; 585 line->plane[1].dcdy = x[1] - x[2]; 586 line->plane[2].dcdy = x[2] - x[3]; 587 line->plane[3].dcdy = x[3] - x[0]; 588 589 line->plane[0].dcdx = y[0] - y[1]; 590 line->plane[1].dcdx = y[1] - y[2]; 591 line->plane[2].dcdx = y[2] - y[3]; 592 line->plane[3].dcdx = y[3] - y[0]; 593 594 595 /* Setup parameter interpolants: 596 */ 597 setup_line_coefficients( setup, line, &info); 598 599 line->inputs.frontfacing = TRUE; 600 line->inputs.disable = FALSE; 601 line->inputs.opaque = FALSE; 602 603 for (i = 0; i < 4; i++) { 604 struct lp_rast_plane *plane = &line->plane[i]; 605 606 /* half-edge constants, will be interated over the whole render 607 * target. 608 */ 609 plane->c = plane->dcdx * x[i] - plane->dcdy * y[i]; 610 611 612 /* correct for top-left vs. bottom-left fill convention. 613 * 614 * note that we're overloading gl_rasterization_rules to mean 615 * both (0.5,0.5) pixel centers *and* bottom-left filling 616 * convention. 617 * 618 * GL actually has a top-left filling convention, but GL's 619 * notion of "top" differs from gallium's... 620 * 621 * Also, sometimes (in FBO cases) GL will render upside down 622 * to its usual method, in which case it will probably want 623 * to use the opposite, top-left convention. 624 */ 625 if (plane->dcdx < 0) { 626 /* both fill conventions want this - adjust for left edges */ 627 plane->c++; 628 } 629 else if (plane->dcdx == 0) { 630 if (setup->pixel_offset == 0) { 631 /* correct for top-left fill convention: 632 */ 633 if (plane->dcdy > 0) plane->c++; 634 } 635 else { 636 /* correct for bottom-left fill convention: 637 */ 638 if (plane->dcdy < 0) plane->c++; 639 } 640 } 641 642 plane->dcdx *= FIXED_ONE; 643 plane->dcdy *= FIXED_ONE; 644 645 /* find trivial reject offsets for each edge for a single-pixel 646 * sized block. These will be scaled up at each recursive level to 647 * match the active blocksize. Scaling in this way works best if 648 * the blocks are square. 649 */ 650 plane->eo = 0; 651 if (plane->dcdx < 0) plane->eo -= plane->dcdx; 652 if (plane->dcdy > 0) plane->eo += plane->dcdy; 653 654 /* Calculate trivial accept offsets from the above. 655 */ 656 plane->ei = plane->dcdy - plane->dcdx - plane->eo; 657 } 658 659 660 /* 661 * When rasterizing scissored tris, use the intersection of the 662 * triangle bounding box and the scissor rect to generate the 663 * scissor planes. 664 * 665 * This permits us to cut off the triangle "tails" that are present 666 * in the intermediate recursive levels caused when two of the 667 * triangles edges don't diverge quickly enough to trivially reject 668 * exterior blocks from the triangle. 669 * 670 * It's not really clear if it's worth worrying about these tails, 671 * but since we generate the planes for each scissored tri, it's 672 * free to trim them in this case. 673 * 674 * Note that otherwise, the scissor planes only vary in 'C' value, 675 * and even then only on state-changes. Could alternatively store 676 * these planes elsewhere. 677 */ 678 if (nr_planes == 8) { 679 line->plane[4].dcdx = -1; 680 line->plane[4].dcdy = 0; 681 line->plane[4].c = 1-bbox.x0; 682 line->plane[4].ei = 0; 683 line->plane[4].eo = 1; 684 685 line->plane[5].dcdx = 1; 686 line->plane[5].dcdy = 0; 687 line->plane[5].c = bbox.x1+1; 688 line->plane[5].ei = -1; 689 line->plane[5].eo = 0; 690 691 line->plane[6].dcdx = 0; 692 line->plane[6].dcdy = 1; 693 line->plane[6].c = 1-bbox.y0; 694 line->plane[6].ei = 0; 695 line->plane[6].eo = 1; 696 697 line->plane[7].dcdx = 0; 698 line->plane[7].dcdy = -1; 699 line->plane[7].c = bbox.y1+1; 700 line->plane[7].ei = -1; 701 line->plane[7].eo = 0; 702 } 703 704 return lp_setup_bin_triangle(setup, line, &bbox, nr_planes); 705} 706 707 708static void lp_setup_line( struct lp_setup_context *setup, 709 const float (*v0)[4], 710 const float (*v1)[4] ) 711{ 712 if (!try_setup_line( setup, v0, v1 )) 713 { 714 if (!lp_setup_flush_and_restart(setup)) 715 return; 716 717 if (!try_setup_line( setup, v0, v1 )) 718 return; 719 } 720} 721 722 723void lp_setup_choose_line( struct lp_setup_context *setup ) 724{ 725 setup->line = lp_setup_line; 726} 727 728 729