1/************************************************************************** 2 * 3 * Copyright 2010-2021 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 THE AUTHORS 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 * Setup/binning code for screen-aligned quads. 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#include "lp_state_setup.h" 39 40 41#define NUM_CHANNELS 4 42 43#define UNDETERMINED_BLIT -1 44 45 46static inline int 47subpixel_snap(float a) 48{ 49 return util_iround(FIXED_ONE * a); 50} 51 52 53static inline float 54fixed_to_float(int a) 55{ 56 return a * (1.0f / FIXED_ONE); 57} 58 59 60/** 61 * Alloc space for a new rectangle plus the input.a0/dadx/dady arrays 62 * immediately after it. 63 * The memory is allocated from the per-scene pool, not per-tile. 64 * \param size returns number of bytes allocated 65 * \param nr_inputs number of fragment shader inputs 66 * \return pointer to rectangle space 67 */ 68struct lp_rast_rectangle * 69lp_setup_alloc_rectangle(struct lp_scene *scene, unsigned nr_inputs) 70{ 71 unsigned input_array_sz = NUM_CHANNELS * (nr_inputs + 1) * sizeof(float); 72 struct lp_rast_rectangle *rect; 73 unsigned bytes = sizeof(*rect) + (3 * input_array_sz); 74 rect = lp_scene_alloc_aligned(scene, bytes, 16); 75 if (rect == NULL) 76 return NULL; 77 78 rect->inputs.stride = input_array_sz; 79 80 return rect; 81} 82 83 84/** 85 * The rectangle covers the whole tile- shade whole tile. 86 * XXX no rectangle/triangle dependencies in this file - share it with 87 * the same code in lp_setup_tri.c 88 * \param tx, ty the tile position in tiles, not pixels 89 */ 90boolean 91lp_setup_whole_tile(struct lp_setup_context *setup, 92 const struct lp_rast_shader_inputs *inputs, 93 int tx, int ty, boolean opaque) 94{ 95 struct lp_scene *scene = setup->scene; 96 97 LP_COUNT(nr_fully_covered_64); 98 99 /* if variant is opaque and scissor doesn't effect the tile */ 100 if (opaque) { 101 /* Several things prevent this optimization from working: 102 * - For layered rendering we can't determine if this covers the same 103 * layer as previous rendering (or in case of clears those actually 104 * always cover all layers so optimization is impossible). Need to use 105 * fb_max_layer and not setup->layer_slot to determine this since even 106 * if there's currently no slot assigned previous rendering could have 107 * used one. 108 * - If there were any Begin/End query commands in the scene then those 109 * would get removed which would be very wrong. Furthermore, if queries 110 * were just active we also can't do the optimization since to get 111 * accurate query results we unfortunately need to execute the rendering 112 * commands. 113 */ 114 if (!scene->fb.zsbuf && scene->fb_max_layer == 0 && 115 !scene->had_queries) { 116 /* 117 * All previous rendering will be overwritten so reset the bin. 118 */ 119 lp_scene_bin_reset(scene, tx, ty); 120 } 121 122 if (inputs->is_blit) { 123 LP_COUNT(nr_blit_64); 124 return lp_scene_bin_cmd_with_state(scene, tx, ty, 125 setup->fs.stored, 126 LP_RAST_OP_BLIT, 127 lp_rast_arg_inputs(inputs)); 128 } else { 129 LP_COUNT(nr_shade_opaque_64); 130 return lp_scene_bin_cmd_with_state(scene, tx, ty, 131 setup->fs.stored, 132 LP_RAST_OP_SHADE_TILE_OPAQUE, 133 lp_rast_arg_inputs(inputs)); 134 } 135 } else { 136 LP_COUNT(nr_shade_64); 137 return lp_scene_bin_cmd_with_state(scene, tx, ty, 138 setup->fs.stored, 139 LP_RAST_OP_SHADE_TILE, 140 lp_rast_arg_inputs(inputs)); 141 } 142} 143 144 145boolean 146lp_setup_is_blit(const struct lp_setup_context *setup, 147 const struct lp_rast_shader_inputs *inputs) 148{ 149 const struct lp_fragment_shader_variant *variant = 150 setup->fs.current.variant; 151 152 if (variant->blit) { 153 /* 154 * Detect blits. 155 */ 156 const struct lp_jit_texture *texture = 157 &setup->fs.current.jit_context.textures[0]; 158 159 /* XXX: dadx vs dady confusion below? 160 */ 161 const float dsdx = GET_DADX(inputs)[1][0] * texture->width; 162 const float dsdy = GET_DADX(inputs)[1][1] * texture->width; 163 const float dtdx = GET_DADY(inputs)[1][0] * texture->height; 164 const float dtdy = GET_DADY(inputs)[1][1] * texture->height; 165 166 /* 167 * We don't need to check s0/t0 tolerances 168 * as we establish as pre-condition that there is no 169 * texture filtering. 170 */ 171 172 ASSERTED struct lp_sampler_static_state *samp0 = lp_fs_variant_key_sampler_idx(&variant->key, 0); 173 assert(samp0); 174 assert(samp0->sampler_state.min_img_filter == PIPE_TEX_FILTER_NEAREST); 175 assert(samp0->sampler_state.mag_img_filter == PIPE_TEX_FILTER_NEAREST); 176 177 /* 178 * Check for 1:1 match of texels to dest pixels 179 */ 180 181 if (util_is_approx(dsdx, 1.0f, 1.0f/LP_MAX_WIDTH) && 182 util_is_approx(dsdy, 0.0f, 1.0f/LP_MAX_HEIGHT) && 183 util_is_approx(dtdx, 0.0f, 1.0f/LP_MAX_WIDTH) && 184 util_is_approx(dtdy, 1.0f, 1.0f/LP_MAX_HEIGHT)) { 185 return true; 186 } else { 187#if 0 188 debug_printf("dsdx = %f\n", dsdx); 189 debug_printf("dsdy = %f\n", dsdy); 190 debug_printf("dtdx = %f\n", dtdx); 191 debug_printf("dtdy = %f\n", dtdy); 192 debug_printf("\n"); 193#endif 194 return FALSE; 195 } 196 } 197 198 return FALSE; 199} 200 201 202static inline void 203partial(struct lp_setup_context *setup, 204 const struct lp_rast_rectangle *rect, 205 boolean opaque, 206 unsigned ix, unsigned iy, 207 unsigned mask) // RECT_PLANE_x bits 208{ 209 if (mask == 0) { 210 assert(rect->box.x0 <= ix * TILE_SIZE); 211 assert(rect->box.y0 <= iy * TILE_SIZE); 212 assert(rect->box.x1 >= (ix+1) * TILE_SIZE - 1); 213 assert(rect->box.y1 >= (iy+1) * TILE_SIZE - 1); 214 215 lp_setup_whole_tile(setup, &rect->inputs, ix, iy, opaque); 216 } else { 217 LP_COUNT(nr_partially_covered_64); 218 lp_scene_bin_cmd_with_state(setup->scene, 219 ix, iy, 220 setup->fs.stored, 221 LP_RAST_OP_RECTANGLE, 222 lp_rast_arg_rectangle(rect)); 223 } 224} 225 226 227/** 228 * Setup/bin a screen-aligned rect. 229 * We need three corner vertices in order to correctly setup 230 * interpolated parameters. We *could* get away with just the 231 * diagonal vertices but it'd cause ugliness elsewhere. 232 * 233 * + -------v0 234 * | | 235 * v2 ------ v1 236 * 237 * By an unfortunate mixup between GL and D3D coordinate spaces, half 238 * of this file talks about clockwise rectangles (which were CCW in GL 239 * coordinate space), while the other half prefers to work with D3D 240 * CCW rectangles. 241 */ 242static boolean 243try_rect_cw(struct lp_setup_context *setup, 244 const float (*v0)[4], 245 const float (*v1)[4], 246 const float (*v2)[4], 247 boolean frontfacing) 248{ 249 const struct lp_fragment_shader_variant *variant = 250 setup->fs.current.variant; 251 const struct lp_setup_variant_key *key = &setup->setup.variant->key; 252 struct lp_scene *scene = setup->scene; 253 254 /* x/y positions in fixed point */ 255 int x0 = subpixel_snap(v0[0][0] - setup->pixel_offset); 256 int x1 = subpixel_snap(v1[0][0] - setup->pixel_offset); 257 int x2 = subpixel_snap(v2[0][0] - setup->pixel_offset); 258 int y0 = subpixel_snap(v0[0][1] - setup->pixel_offset); 259 int y1 = subpixel_snap(v1[0][1] - setup->pixel_offset); 260 int y2 = subpixel_snap(v2[0][1] - setup->pixel_offset); 261 262 LP_COUNT(nr_rects); 263 264 /* Cull clockwise rects without overflowing. 265 */ 266 const boolean cw = (x2 < x1) ^ (y0 < y2); 267 if (cw) { 268 LP_COUNT(nr_culled_rects); 269 return TRUE; 270 } 271 272 const float (*pv)[4]; 273 if (setup->flatshade_first) { 274 pv = v0; 275 } else { 276 pv = v2; 277 } 278 279 unsigned viewport_index = 0; 280 if (setup->viewport_index_slot > 0) { 281 unsigned *udata = (unsigned*)pv[setup->viewport_index_slot]; 282 viewport_index = lp_clamp_viewport_idx(*udata); 283 } 284 285 unsigned layer = 0; 286 if (setup->layer_slot > 0) { 287 layer = *(unsigned*)pv[setup->layer_slot]; 288 layer = MIN2(layer, scene->fb_max_layer); 289 } 290 291 /* Bounding rectangle (in pixels) */ 292 struct u_rect bbox; 293 { 294 /* Yes this is necessary to accurately calculate bounding boxes 295 * with the two fill-conventions we support. GL (normally) ends 296 * up needing a bottom-left fill convention, which requires 297 * slightly different rounding. 298 */ 299 int adj = (setup->bottom_edge_rule != 0) ? 1 : 0; 300 301 bbox.x0 = (MIN3(x0, x1, x2) + (FIXED_ONE-1)) >> FIXED_ORDER; 302 bbox.x1 = (MAX3(x0, x1, x2) + (FIXED_ONE-1)) >> FIXED_ORDER; 303 bbox.y0 = (MIN3(y0, y1, y2) + (FIXED_ONE-1) + adj) >> FIXED_ORDER; 304 bbox.y1 = (MAX3(y0, y1, y2) + (FIXED_ONE-1) + adj) >> FIXED_ORDER; 305 306 /* Inclusive coordinates: 307 */ 308 bbox.x1--; 309 bbox.y1--; 310 } 311 312 if (!u_rect_test_intersection(&setup->draw_regions[viewport_index], &bbox)) { 313 if (0) debug_printf("no intersection\n"); 314 LP_COUNT(nr_culled_rects); 315 return TRUE; 316 } 317 318 u_rect_find_intersection(&setup->draw_regions[viewport_index], &bbox); 319 320 struct lp_rast_rectangle *rect = 321 lp_setup_alloc_rectangle(scene, key->num_inputs); 322 if (!rect) 323 return FALSE; 324 325#ifdef DEBUG 326 rect->v[0][0] = v0[0][0]; 327 rect->v[0][1] = v0[0][1]; 328 rect->v[1][0] = v1[0][0]; 329 rect->v[1][1] = v1[0][1]; 330#endif 331 332 rect->box.x0 = bbox.x0; 333 rect->box.x1 = bbox.x1; 334 rect->box.y0 = bbox.y0; 335 rect->box.y1 = bbox.y1; 336 337 /* Setup parameter interpolants: 338 */ 339 setup->setup.variant->jit_function(v0, 340 v1, 341 v2, 342 frontfacing, 343 GET_A0(&rect->inputs), 344 GET_DADX(&rect->inputs), 345 GET_DADY(&rect->inputs), 346 &setup->setup.variant->key); 347 348 rect->inputs.frontfacing = frontfacing; 349 rect->inputs.disable = FALSE; 350 rect->inputs.is_blit = lp_setup_is_blit(setup, &rect->inputs); 351 rect->inputs.layer = layer; 352 rect->inputs.viewport_index = viewport_index; 353 rect->inputs.view_index = setup->view_index; 354 355 return lp_setup_bin_rectangle(setup, rect, variant->opaque); 356} 357 358 359boolean 360lp_setup_bin_rectangle(struct lp_setup_context *setup, 361 struct lp_rast_rectangle *rect, 362 boolean opaque) 363{ 364 struct lp_scene *scene = setup->scene; 365 unsigned left_mask = 0; 366 unsigned right_mask = 0; 367 unsigned top_mask = 0; 368 unsigned bottom_mask = 0; 369 370 /* 371 * All fields of 'rect' are now set. The remaining code here is 372 * concerned with binning. 373 */ 374 375 /* Convert to inclusive tile coordinates: 376 */ 377 const unsigned ix0 = rect->box.x0 / TILE_SIZE; 378 const unsigned iy0 = rect->box.y0 / TILE_SIZE; 379 const unsigned ix1 = rect->box.x1 / TILE_SIZE; 380 const unsigned iy1 = rect->box.y1 / TILE_SIZE; 381 382 /* 383 * Clamp to framebuffer size 384 */ 385 assert(ix0 == MAX2(ix0, 0)); 386 assert(iy0 == MAX2(iy0, 0)); 387 assert(ix1 == MIN2(ix1, scene->tiles_x - 1)); 388 assert(iy1 == MIN2(iy1, scene->tiles_y - 1)); 389 390 if (ix0 * TILE_SIZE != rect->box.x0) 391 left_mask = RECT_PLANE_LEFT; 392 393 if (ix1 * TILE_SIZE + TILE_SIZE - 1 != rect->box.x1) 394 right_mask = RECT_PLANE_RIGHT; 395 396 if (iy0 * TILE_SIZE != rect->box.y0) 397 top_mask = RECT_PLANE_TOP; 398 399 if (iy1 * TILE_SIZE + TILE_SIZE - 1 != rect->box.y1) 400 bottom_mask = RECT_PLANE_BOTTOM; 401 402 /* Determine which tile(s) intersect the rectangle's bounding box 403 */ 404 if (iy0 == iy1 && ix0 == ix1) { 405 partial(setup, rect, opaque, ix0, iy0, 406 (left_mask | right_mask | top_mask | bottom_mask)); 407 } else if (ix0 == ix1) { 408 unsigned mask = left_mask | right_mask; 409 partial(setup, rect, opaque, ix0, iy0, mask | top_mask); 410 for (unsigned i = iy0 + 1; i < iy1; i++) 411 partial(setup, rect, opaque, ix0, i, mask); 412 partial(setup, rect, opaque, ix0, iy1, mask | bottom_mask); 413 } else if (iy0 == iy1) { 414 unsigned mask = top_mask | bottom_mask; 415 partial(setup, rect, opaque, ix0, iy0, mask | left_mask); 416 for (unsigned i = ix0 + 1; i < ix1; i++) 417 partial(setup, rect, opaque, i, iy0, mask); 418 partial(setup, rect, opaque, ix1, iy0, mask | right_mask); 419 } else { 420 partial(setup, rect, opaque, ix0, iy0, left_mask | top_mask); 421 partial(setup, rect, opaque, ix0, iy1, left_mask | bottom_mask); 422 partial(setup, rect, opaque, ix1, iy0, right_mask | top_mask); 423 partial(setup, rect, opaque, ix1, iy1, right_mask | bottom_mask); 424 425 /* Top/Bottom fringes 426 */ 427 for (unsigned i = ix0 + 1; i < ix1; i++) { 428 partial(setup, rect, opaque, i, iy0, top_mask); 429 partial(setup, rect, opaque, i, iy1, bottom_mask); 430 } 431 432 /* Left/Right fringes 433 */ 434 for (unsigned i = iy0 + 1; i < iy1; i++) { 435 partial(setup, rect, opaque, ix0, i, left_mask); 436 partial(setup, rect, opaque, ix1, i, right_mask); 437 } 438 439 /* Full interior tiles 440 */ 441 for (unsigned j = iy0 + 1; j < iy1; j++) { 442 for (unsigned i = ix0 + 1; i < ix1; i++) { 443 lp_setup_whole_tile(setup, &rect->inputs, i, j, opaque); 444 } 445 } 446 } 447 448 /* Catch any out-of-memory which occurred during binning. Do this 449 * once here rather than checking all the return values throughout. 450 */ 451 if (lp_scene_is_oom(scene)) { 452 /* Disable rasterization of this partially-binned rectangle. 453 * We'll flush this scene and re-bin the entire rectangle: 454 */ 455 rect->inputs.disable = TRUE; 456 return FALSE; 457 } 458 459 return TRUE; 460} 461 462 463void 464lp_rect_cw(struct lp_setup_context *setup, 465 const float (*v0)[4], 466 const float (*v1)[4], 467 const float (*v2)[4], 468 boolean frontfacing) 469{ 470 if (!try_rect_cw(setup, v0, v1, v2, frontfacing)) { 471 if (!lp_setup_flush_and_restart(setup)) 472 return; 473 474 if (!try_rect_cw(setup, v0, v1, v2, frontfacing)) 475 return; 476 } 477} 478 479 480/** 481 * Take the six vertices for two triangles and try to determine if they 482 * form a screen-aligned quad/rectangle. If so, draw the rect directly, 483 * else, draw as two regular triangles. 484 */ 485static boolean 486do_rect_ccw(struct lp_setup_context *setup, 487 const float (*v0)[4], 488 const float (*v1)[4], 489 const float (*v2)[4], 490 const float (*v3)[4], 491 const float (*v4)[4], 492 const float (*v5)[4], 493 boolean front) 494{ 495 const float (*rv0)[4], (*rv1)[4], (*rv2)[4], (*rv3)[4]; /* rect verts */ 496 497#define SAME_POS(A, B) (A[0][0] == B[0][0] && \ 498 A[0][1] == B[0][1] && \ 499 A[0][2] == B[0][2] && \ 500 A[0][3] == B[0][3]) 501 502 /* Only need to consider CCW orientations. There are nine ways 503 * that two counter-clockwise triangles can join up: 504 */ 505 if (SAME_POS(v0, v3)) { 506 if (SAME_POS(v2, v4)) { 507 /* 508 * v5 v4/v2 509 * +-----+ 510 * | / | 511 * | / | 512 * | / | 513 * +-----+ 514 * v3/v0 v1 515 */ 516 rv0 = v5; 517 rv1 = v0; 518 rv2 = v1; 519 rv3 = v2; 520 } else if (SAME_POS(v1, v5)) { 521 /* 522 * v4 v3/v0 523 * +-----+ 524 * | / | 525 * | / | 526 * | / | 527 * +-----+ 528 * v5/v1 v2 529 */ 530 rv0 = v4; 531 rv1 = v1; 532 rv2 = v2; 533 rv3 = v0; 534 } else { 535 goto emit_triangles; 536 } 537 } else if (SAME_POS(v0, v5)) { 538 if (SAME_POS(v2, v3)) { 539 /* 540 * v4 v3/v2 541 * +-----+ 542 * | / | 543 * | / | 544 * | / | 545 * +-----+ 546 * v5/v0 v1 547 */ 548 rv0 = v4; 549 rv1 = v0; 550 rv2 = v1; 551 rv3 = v2; 552 } else if (SAME_POS(v1, v4)) { 553 /* 554 * v3 v5/v0 555 * +-----+ 556 * | / | 557 * | / | 558 * | / | 559 * +-----+ 560 * v4/v1 v2 561 */ 562 rv0 = v3; 563 rv1 = v1; 564 rv2 = v2; 565 rv3 = v0; 566 } else { 567 goto emit_triangles; 568 } 569 } else if (SAME_POS(v0, v4)) { 570 if (SAME_POS(v2, v5)) { 571 /* 572 * v3 v5/v2 573 * +-----+ 574 * | / | 575 * | / | 576 * | / | 577 * +-----+ 578 * v4/v0 v1 579 */ 580 rv0 = v3; 581 rv1 = v0; 582 rv2 = v1; 583 rv3 = v2; 584 } else if (SAME_POS(v1, v3)) { 585 /* 586 * v5 v4/v0 587 * +-----+ 588 * | / | 589 * | / | 590 * | / | 591 * +-----+ 592 * v3/v1 v2 593 */ 594 rv0 = v5; 595 rv1 = v1; 596 rv2 = v2; 597 rv3 = v0; 598 } else { 599 goto emit_triangles; 600 } 601 } else if (SAME_POS(v2, v3)) { 602 if (SAME_POS(v1, v4)) { 603 /* 604 * v5 v4/v1 605 * +-----+ 606 * | / | 607 * | / | 608 * | / | 609 * +-----+ 610 * v3/v2 v0 611 */ 612 rv0 = v5; 613 rv1 = v2; 614 rv2 = v0; 615 rv3 = v1; 616 } else { 617 goto emit_triangles; 618 } 619 } else if (SAME_POS(v2, v5)) { 620 if (SAME_POS(v1, v3)) { 621 /* 622 * v4 v3/v1 623 * +-----+ 624 * | / | 625 * | / | 626 * | / | 627 * +-----+ 628 * v5/v2 v0 629 */ 630 rv0 = v4; 631 rv1 = v2; 632 rv2 = v0; 633 rv3 = v1; 634 } else { 635 goto emit_triangles; 636 } 637 } else if (SAME_POS(v2, v4)) { 638 if (SAME_POS(v1, v5)) { 639 /* 640 * v3 v5/v1 641 * +-----+ 642 * | / | 643 * | / | 644 * | / | 645 * +-----+ 646 * v4/v2 v0 647 */ 648 rv0 = v3; 649 rv1 = v2; 650 rv2 = v0; 651 rv3 = v1; 652 } else { 653 goto emit_triangles; 654 } 655 } else { 656 goto emit_triangles; 657 } 658 659#define SAME_X(A, B) (A[0][0] == B[0][0]) 660#define SAME_Y(A, B) (A[0][1] == B[0][1]) 661 662 /* The vertices are now counter clockwise, as such: 663 * 664 * rv0 -------rv3 665 * | | 666 * rv1 ------ rv2 667 * 668 * To render as a rectangle, 669 * * The X values should be the same at v0, v1 and v2, v3. 670 * * The Y values should be the same at v0, v3 and v1, v2. 671 */ 672 if (SAME_Y(rv0, rv1)) { 673 const float (*tmp)[4]; 674 tmp = rv0; 675 rv0 = rv1; 676 rv1 = rv2; 677 rv2 = rv3; 678 rv3 = tmp; 679 } 680 681 if (SAME_X(rv0, rv1) && SAME_X(rv2, rv3) && 682 SAME_Y(rv0, rv3) && SAME_Y(rv1, rv2)) { 683 const struct lp_setup_variant_key *key = &setup->setup.variant->key; 684 const unsigned n = key->num_inputs; 685 unsigned i, j; 686 687 /* We have a rectangle. Check that the other attributes are 688 * coplanar. 689 */ 690 for (i = 0; i < n; i++) { 691 for (j = 0; j < 4; j++) { 692 if (key->inputs[i].usage_mask & (1<<j)) { 693 unsigned k = key->inputs[i].src_index; 694 float dxdx1, dxdx2, dxdy1, dxdy2; 695 dxdx1 = rv0[k][j] - rv3[k][j]; 696 dxdx2 = rv1[k][j] - rv2[k][j]; 697 dxdy1 = rv0[k][j] - rv1[k][j]; 698 dxdy2 = rv3[k][j] - rv2[k][j]; 699 if (dxdx1 != dxdx2 || 700 dxdy1 != dxdy2) { 701 goto emit_triangles; 702 } 703 } 704 } 705 } 706 707 /* Note we're changing to clockwise here. Fix this by reworking 708 * lp_rect_cw to expect/operate on ccw rects. Note that 709 * function was previously misnamed. 710 */ 711 lp_rect_cw(setup, rv0, rv2, rv1, front); 712 return TRUE; 713 } else { 714 /* setup->quad(setup, rv0, rv1, rv2, rv3); */ 715 } 716 717emit_triangles: 718 return FALSE; 719} 720 721 722enum winding { 723 WINDING_NONE = 0, 724 WINDING_CCW, 725 WINDING_CW 726}; 727 728 729static inline enum winding 730winding(const float (*v0)[4], 731 const float (*v1)[4], 732 const float (*v2)[4]) 733{ 734 /* edge vectors e = v0 - v2, f = v1 - v2 */ 735 const float ex = v0[0][0] - v2[0][0]; 736 const float ey = v0[0][1] - v2[0][1]; 737 const float fx = v1[0][0] - v2[0][0]; 738 const float fy = v1[0][1] - v2[0][1]; 739 740 /* det = cross(e,f).z */ 741 const float det = ex * fy - ey * fx; 742 743 if (det < 0.0f) 744 return WINDING_CCW; 745 else if (det > 0.0f) 746 return WINDING_CW; 747 else 748 return WINDING_NONE; 749} 750 751 752static boolean 753setup_rect_cw(struct lp_setup_context *setup, 754 const float (*v0)[4], 755 const float (*v1)[4], 756 const float (*v2)[4], 757 const float (*v3)[4], 758 const float (*v4)[4], 759 const float (*v5)[4]) 760{ 761 enum winding winding0 = winding(v0, v1, v2); 762 enum winding winding1 = winding(v3, v4, v5); 763 764 if (winding0 == WINDING_CW && 765 winding1 == WINDING_CW) { 766 return do_rect_ccw(setup, v0, v2, v1, v3, v5, v4, !setup->ccw_is_frontface); 767 } else if (winding0 == WINDING_CW) { 768 setup->triangle(setup, v0, v1, v2); 769 return TRUE; 770 } else if (winding1 == WINDING_CW) { 771 setup->triangle(setup, v3, v4, v5); 772 return TRUE; 773 } else { 774 return TRUE; 775 } 776} 777 778 779static boolean 780setup_rect_ccw(struct lp_setup_context *setup, 781 const float (*v0)[4], 782 const float (*v1)[4], 783 const float (*v2)[4], 784 const float (*v3)[4], 785 const float (*v4)[4], 786 const float (*v5)[4]) 787{ 788 enum winding winding0 = winding(v0, v1, v2); 789 enum winding winding1 = winding(v3, v4, v5); 790 791 if (winding0 == WINDING_CCW && 792 winding1 == WINDING_CCW) { 793 return do_rect_ccw(setup, v0, v1, v2, v3, v4, v5, setup->ccw_is_frontface); 794 } else if (winding0 == WINDING_CCW) { 795 setup->triangle(setup, v0, v1, v2); 796 return TRUE; 797 } else if (winding1 == WINDING_CCW) { 798 return FALSE; 799 setup->triangle(setup, v3, v4, v5); 800 return TRUE; 801 } else { 802 return TRUE; 803 } 804} 805 806 807static boolean 808setup_rect_noop(struct lp_setup_context *setup, 809 const float (*v0)[4], 810 const float (*v1)[4], 811 const float (*v2)[4], 812 const float (*v3)[4], 813 const float (*v4)[4], 814 const float (*v5)[4]) 815{ 816 return TRUE; 817} 818 819 820static boolean 821setup_rect_both(struct lp_setup_context *setup, 822 const float (*v0)[4], 823 const float (*v1)[4], 824 const float (*v2)[4], 825 const float (*v3)[4], 826 const float (*v4)[4], 827 const float (*v5)[4]) 828{ 829 enum winding winding0 = winding(v0, v1, v2); 830 enum winding winding1 = winding(v3, v4, v5); 831 832 if (winding0 != winding1) { 833 /* If we knew that the "front" parameter wasn't going to be 834 * referenced, could rearrange one of the two triangles such 835 * that they were both CCW. Aero actually does send mixed 836 * CW/CCW rectangles under some circumstances, but we catch them 837 * explicitly. 838 */ 839 return FALSE; 840 } else if (winding0 == WINDING_CCW) { 841 return do_rect_ccw(setup, v0, v1, v2, v3, v4, v5, setup->ccw_is_frontface); 842 } else if (winding0 == WINDING_CW) { 843 return do_rect_ccw(setup, v0, v2, v1, v3, v5, v4, !setup->ccw_is_frontface); 844 } else { 845 return TRUE; 846 } 847} 848 849 850void 851lp_setup_choose_rect(struct lp_setup_context *setup) 852{ 853 if (setup->rasterizer_discard) { 854 setup->rect = setup_rect_noop; 855 return; 856 } 857 858 switch (setup->cullmode) { 859 case PIPE_FACE_NONE: 860 setup->rect = setup_rect_both; 861 break; 862 case PIPE_FACE_BACK: 863 setup->rect = setup->ccw_is_frontface ? setup_rect_ccw : setup_rect_cw; 864 break; 865 case PIPE_FACE_FRONT: 866 setup->rect = setup->ccw_is_frontface ? setup_rect_cw : setup_rect_ccw; 867 break; 868 default: 869 setup->rect = setup_rect_noop; 870 break; 871 } 872} 873