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