xref: /aosp_15_r20/external/mesa3d/src/gallium/drivers/llvmpipe/lp_rast_rect.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 /**************************************************************************
2  *
3  * Copyright 2007-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 VMWARE 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  * Rasterization for binned rectangles within a tile
30  */
31 
32 #include <limits.h>
33 #include "util/u_math.h"
34 #include "lp_debug.h"
35 #include "lp_perf.h"
36 #include "lp_rast_priv.h"
37 
38 /* Our 16-pixel stamps are layed out as:
39  *
40  *    0  1  2  3
41  *    4  5  6  7
42  *    8  9  10 11
43  *    12 13 14 15
44  *
45  * Define bitmasks for each row and column in this layout:
46  */
47 #define COLUMN0 ((1<<0)|(1<<4)|(1<<8) |(1<<12))
48 #define COLUMN1 ((1<<1)|(1<<5)|(1<<9) |(1<<13))
49 #define COLUMN2 ((1<<2)|(1<<6)|(1<<10)|(1<<14))
50 #define COLUMN3 ((1<<3)|(1<<7)|(1<<11)|(1<<15))
51 
52 #define ROW0 ((1<<0) |(1<<1) |(1<<2) |(1<<3))
53 #define ROW1 ((1<<4) |(1<<5) |(1<<6) |(1<<7))
54 #define ROW2 ((1<<8) |(1<<9) |(1<<10)|(1<<11))
55 #define ROW3 ((1<<12)|(1<<13)|(1<<14)|(1<<15))
56 
57 #define STAMP_SIZE 4
58 
59 static unsigned left_mask_tab[STAMP_SIZE] = {
60    COLUMN0 | COLUMN1 | COLUMN2 | COLUMN3,
61    COLUMN1 | COLUMN2 | COLUMN3,
62    COLUMN2 | COLUMN3,
63    COLUMN3,
64 };
65 
66 static unsigned right_mask_tab[STAMP_SIZE] = {
67    COLUMN0,
68    COLUMN0 | COLUMN1,
69    COLUMN0 | COLUMN1 | COLUMN2,
70    COLUMN0 | COLUMN1 | COLUMN2 | COLUMN3,
71 };
72 
73 static unsigned top_mask_tab[STAMP_SIZE] = {
74    ROW0 | ROW1 | ROW2 | ROW3,
75    ROW1 | ROW2 | ROW3,
76    ROW2 | ROW3,
77    ROW3,
78 };
79 
80 static unsigned bottom_mask_tab[STAMP_SIZE] = {
81    ROW0,
82    ROW0 | ROW1,
83    ROW0 | ROW1 | ROW2,
84    ROW0 | ROW1 | ROW2 | ROW3,
85 };
86 
87 
88 static inline void
full(struct lp_rasterizer_task * task,const struct lp_rast_rectangle * rect,unsigned ix,unsigned iy)89 full(struct lp_rasterizer_task *task,
90      const struct lp_rast_rectangle *rect,
91      unsigned ix, unsigned iy)
92 {
93    LP_COUNT(nr_rect_fully_covered_4);
94    lp_rast_shade_quads_all(task,
95                            &rect->inputs,
96                            task->x + ix * STAMP_SIZE,
97                            task->y + iy * STAMP_SIZE);
98 }
99 
100 
101 static inline void
partial(struct lp_rasterizer_task * task,const struct lp_rast_rectangle * rect,unsigned ix,unsigned iy,unsigned mask)102 partial(struct lp_rasterizer_task *task,
103         const struct lp_rast_rectangle *rect,
104         unsigned ix, unsigned iy,
105         unsigned mask)
106 {
107    /* Unfortunately we can end up generating full blocks on this path,
108     * need to catch them.
109     */
110    if (mask == 0xffff) {
111       full(task, rect, ix, iy);
112    } else {
113       assert(mask);
114       LP_COUNT(nr_rect_partially_covered_4);
115       lp_rast_shade_quads_mask(task,
116                                &rect->inputs,
117                                task->x + ix * STAMP_SIZE,
118                                task->y + iy * STAMP_SIZE,
119                                mask);
120    }
121 }
122 
123 
124 static inline void
intersect_rect_and_tile(struct lp_rasterizer_task * task,const struct lp_rast_rectangle * rect,struct u_rect * box)125 intersect_rect_and_tile(struct lp_rasterizer_task *task,
126                         const struct lp_rast_rectangle *rect,
127                         struct u_rect *box)
128 {
129    box->x0 = task->x;
130    box->y0 = task->y;
131    box->x1 = task->x + TILE_SIZE - 1;
132    box->y1 = task->y + TILE_SIZE - 1;
133 
134    assert(u_rect_test_intersection(&rect->box, box));
135 
136    u_rect_find_intersection(&rect->box, box);
137 
138    box->x0 -= task->x;
139    box->x1 -= task->x;
140    box->y0 -= task->y;
141    box->y1 -= task->y;
142 }
143 
144 
145 /**
146  * Scan the tile in chunks and figure out which pixels to rasterize
147  * for this rectangle.
148  */
149 void
lp_rast_rectangle(struct lp_rasterizer_task * task,const union lp_rast_cmd_arg arg)150 lp_rast_rectangle(struct lp_rasterizer_task *task,
151                   const union lp_rast_cmd_arg arg)
152 {
153    const struct lp_rast_rectangle *rect = arg.rectangle;
154 
155    /* Check for "disabled" rectangles generated in out-of-memory
156     * conditions.
157     */
158    if (rect->inputs.disable) {
159       /* This command was partially binned and has been disabled */
160       return;
161    }
162 
163    /* Intersect the rectangle with this tile.
164     */
165    struct u_rect box;
166    intersect_rect_and_tile(task, rect, &box);
167 
168    /* The interior of the rectangle (if there is one) will be
169     * rasterized as full 4x4 stamps.
170     *
171     * At each edge of the rectangle, however, there will be a fringe
172     * of partial blocks where the edge lands somewhere in the middle
173     * of a 4-pixel stamp.
174     *
175     * For each edge, precalculate a mask of the pixels inside that
176     * edge for the first 4-pixel stamp.
177     *
178     * Note that at the corners, and for narrow rectangles, an
179     * individual stamp may have two or more edges active.  We'll deal
180     * with that below by combining these masks as appropriate.
181     */
182    unsigned left_mask   = left_mask_tab   [box.x0 & (STAMP_SIZE - 1)];
183    unsigned right_mask  = right_mask_tab  [box.x1 & (STAMP_SIZE - 1)];
184    unsigned top_mask    = top_mask_tab    [box.y0 & (STAMP_SIZE - 1)];
185    unsigned bottom_mask = bottom_mask_tab [box.y1 & (STAMP_SIZE - 1)];
186 
187    unsigned ix0 = box.x0 / STAMP_SIZE;
188    unsigned ix1 = box.x1 / STAMP_SIZE;
189    unsigned iy0 = box.y0 / STAMP_SIZE;
190    unsigned iy1 = box.y1 / STAMP_SIZE;
191 
192    /* Various special cases.
193     */
194    if (ix0 == ix1 && iy0 == iy1) {
195       /* Rectangle is contained within a single 4x4 stamp:
196        */
197       partial(task, rect, ix0, iy0,
198               (left_mask & right_mask & top_mask & bottom_mask));
199    } else if (ix0 == ix1) {
200       /* Left and right edges fall on the same 4-pixel-wide column:
201        */
202       unsigned mask = left_mask & right_mask;
203       partial(task, rect, ix0, iy0, mask & top_mask);
204       for (unsigned i = iy0 + 1; i < iy1; i++)
205          partial(task, rect, ix0, i, mask);
206       partial(task, rect, ix0, iy1, mask & bottom_mask);
207    } else if (iy0 == iy1) {
208       /* Top and bottom edges fall on the same 4-pixel-wide row:
209        */
210       unsigned mask = top_mask & bottom_mask;
211       partial(task, rect, ix0, iy0, mask & left_mask);
212       for (unsigned i = ix0 + 1; i < ix1; i++)
213          partial(task, rect, i, iy0, mask);
214       partial(task, rect, ix1, iy0, mask & right_mask);
215    } else {
216       /* Each pair of edges falls in a separate 4-pixel-wide
217        * row/column.
218        */
219       partial(task, rect, ix0, iy0, left_mask  & top_mask);
220       partial(task, rect, ix0, iy1, left_mask  & bottom_mask);
221       partial(task, rect, ix1, iy0, right_mask & top_mask);
222       partial(task, rect, ix1, iy1, right_mask & bottom_mask);
223 
224       for (unsigned i = ix0 + 1; i < ix1; i++)
225          partial(task, rect, i, iy0, top_mask);
226 
227       for (unsigned i = ix0 + 1; i < ix1; i++)
228          partial(task, rect, i, iy1, bottom_mask);
229 
230       for (unsigned i = iy0 + 1; i < iy1; i++)
231          partial(task, rect, ix0, i, left_mask);
232 
233       for (unsigned i = iy0 + 1; i < iy1; i++)
234          partial(task, rect, ix1, i, right_mask);
235 
236       /* Full interior blocks
237        */
238       for (unsigned j = iy0 + 1; j < iy1; j++) {
239          for (unsigned i = ix0 + 1; i < ix1; i++) {
240             full(task, rect, i, j);
241          }
242       }
243    }
244 }
245 
246 
247