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