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