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