1 /*
2 * Mesa 3-D graphics library
3 *
4 * Copyright (C) 2012-2015 LunarG, Inc.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 *
24 * Authors:
25 * Chia-I Wu <olv@lunarg.com>
26 */
27
28 #include "ilo_debug.h"
29 #include "ilo_state_viewport.h"
30
31 static void
viewport_matrix_get_gen6_guardband(const struct ilo_dev * dev,const struct ilo_state_viewport_matrix_info * mat,float * min_gbx,float * max_gbx,float * min_gby,float * max_gby)32 viewport_matrix_get_gen6_guardband(const struct ilo_dev *dev,
33 const struct ilo_state_viewport_matrix_info *mat,
34 float *min_gbx, float *max_gbx,
35 float *min_gby, float *max_gby)
36 {
37 /*
38 * From the Sandy Bridge PRM, volume 2 part 1, page 234:
39 *
40 * "Per-Device Guardband Extents
41 *
42 * - Supported X,Y ScreenSpace "Guardband" Extent: [-16K,16K-1]
43 * - Maximum Post-Clamp Delta (X or Y): 16K"
44 *
45 * "In addition, in order to be correctly rendered, objects must have a
46 * screenspace bounding box not exceeding 8K in the X or Y direction.
47 * This additional restriction must also be comprehended by software,
48 * i.e., enforced by use of clipping."
49 *
50 * From the Ivy Bridge PRM, volume 2 part 1, page 248:
51 *
52 * "Per-Device Guardband Extents
53 *
54 * - Supported X,Y ScreenSpace "Guardband" Extent: [-32K,32K-1]
55 * - Maximum Post-Clamp Delta (X or Y): N/A"
56 *
57 * "In addition, in order to be correctly rendered, objects must have a
58 * screenspace bounding box not exceeding 8K in the X or Y direction.
59 * This additional restriction must also be comprehended by software,
60 * i.e., enforced by use of clipping."
61 *
62 * Combined, the bounding box of any object can not exceed 8K in both
63 * width and height.
64 *
65 * Below we set the guardband as a squre of length 8K, centered at where
66 * the viewport is. This makes sure all objects passing the GB test are
67 * valid to the renderer, and those failing the XY clipping have a
68 * better chance of passing the GB test.
69 */
70 const int max_extent = (ilo_dev_gen(dev) >= ILO_GEN(7)) ? 32768 : 16384;
71 const int half_len = 8192 / 2;
72 int center_x = (int) mat->translate[0];
73 int center_y = (int) mat->translate[1];
74 float scale_x, scale_y;
75
76 ILO_DEV_ASSERT(dev, 6, 8);
77
78 /* make sure the guardband is within the valid range */
79 if (center_x - half_len < -max_extent)
80 center_x = -max_extent + half_len;
81 else if (center_x + half_len > max_extent - 1)
82 center_x = max_extent - half_len;
83
84 if (center_y - half_len < -max_extent)
85 center_y = -max_extent + half_len;
86 else if (center_y + half_len > max_extent - 1)
87 center_y = max_extent - half_len;
88
89 scale_x = fabsf(mat->scale[0]);
90 scale_y = fabsf(mat->scale[1]);
91 /*
92 * From the Haswell PRM, volume 2d, page 292-293:
93 *
94 * "Note: Minimum allowed value for this field (X/Y Min Clip Guardband)
95 * is -16384."
96 *
97 * "Note: Maximum allowed value for this field (X/Y Max Clip Guardband)
98 * is 16383."
99 *
100 * Avoid small scales.
101 */
102 if (scale_x < 1.0f)
103 scale_x = 1.0f;
104 if (scale_y < 1.0f)
105 scale_y = 1.0f;
106
107 /* in NDC space */
108 *min_gbx = ((float) (center_x - half_len) - mat->translate[0]) / scale_x;
109 *max_gbx = ((float) (center_x + half_len) - mat->translate[0]) / scale_x;
110 *min_gby = ((float) (center_y - half_len) - mat->translate[1]) / scale_y;
111 *max_gby = ((float) (center_y + half_len) - mat->translate[1]) / scale_y;
112 }
113
114 static void
viewport_matrix_get_extent(const struct ilo_state_viewport_matrix_info * mat,int axis,float * min,float * max)115 viewport_matrix_get_extent(const struct ilo_state_viewport_matrix_info *mat,
116 int axis, float *min, float *max)
117 {
118 const float scale_abs = fabsf(mat->scale[axis]);
119
120 *min = -1.0f * scale_abs + mat->translate[axis];
121 *max = 1.0f * scale_abs + mat->translate[axis];
122 }
123
124 static bool
viewport_matrix_set_gen7_SF_CLIP_VIEWPORT(struct ilo_state_viewport * vp,const struct ilo_dev * dev,const struct ilo_state_viewport_matrix_info * matrices,uint8_t count)125 viewport_matrix_set_gen7_SF_CLIP_VIEWPORT(struct ilo_state_viewport *vp,
126 const struct ilo_dev *dev,
127 const struct ilo_state_viewport_matrix_info *matrices,
128 uint8_t count)
129 {
130 uint8_t i;
131
132 ILO_DEV_ASSERT(dev, 6, 8);
133
134 for (i = 0; i < count; i++) {
135 const struct ilo_state_viewport_matrix_info *mat = &matrices[i];
136 float min_gbx, max_gbx, min_gby, max_gby;
137 uint32_t dw[16];
138
139 viewport_matrix_get_gen6_guardband(dev, mat,
140 &min_gbx, &max_gbx, &min_gby, &max_gby);
141
142 dw[0] = fui(mat->scale[0]);
143 dw[1] = fui(mat->scale[1]);
144 dw[2] = fui(mat->scale[2]);
145 dw[3] = fui(mat->translate[0]);
146 dw[4] = fui(mat->translate[1]);
147 dw[5] = fui(mat->translate[2]);
148 dw[6] = 0;
149 dw[7] = 0;
150
151 dw[8] = fui(min_gbx);
152 dw[9] = fui(max_gbx);
153 dw[10] = fui(min_gby);
154 dw[11] = fui(max_gby);
155
156 if (ilo_dev_gen(dev) >= ILO_GEN(8)) {
157 float min_x, max_x, min_y, max_y;
158
159 viewport_matrix_get_extent(mat, 0, &min_x, &max_x);
160 viewport_matrix_get_extent(mat, 1, &min_y, &max_y);
161
162 dw[12] = fui(min_x);
163 dw[13] = fui(max_x - 1.0f);
164 dw[14] = fui(min_y);
165 dw[15] = fui(max_y - 1.0f);
166 } else {
167 dw[12] = 0;
168 dw[13] = 0;
169 dw[14] = 0;
170 dw[15] = 0;
171 }
172
173 STATIC_ASSERT(ARRAY_SIZE(vp->sf_clip[i]) >= 16);
174 memcpy(vp->sf_clip[i], dw, sizeof(dw));
175 }
176
177 return true;
178 }
179
180 static bool
viewport_matrix_set_gen6_CC_VIEWPORT(struct ilo_state_viewport * vp,const struct ilo_dev * dev,const struct ilo_state_viewport_matrix_info * matrices,uint8_t count)181 viewport_matrix_set_gen6_CC_VIEWPORT(struct ilo_state_viewport *vp,
182 const struct ilo_dev *dev,
183 const struct ilo_state_viewport_matrix_info *matrices,
184 uint8_t count)
185 {
186 uint8_t i;
187
188 ILO_DEV_ASSERT(dev, 6, 8);
189
190 for (i = 0; i < count; i++) {
191 const struct ilo_state_viewport_matrix_info *mat = &matrices[i];
192 float min_z, max_z;
193
194 viewport_matrix_get_extent(mat, 2, &min_z, &max_z);
195
196 STATIC_ASSERT(ARRAY_SIZE(vp->cc[i]) >= 2);
197 vp->cc[i][0] = fui(min_z);
198 vp->cc[i][1] = fui(max_z);
199 }
200
201 return true;
202 }
203
204 static bool
viewport_scissor_set_gen6_SCISSOR_RECT(struct ilo_state_viewport * vp,const struct ilo_dev * dev,const struct ilo_state_viewport_scissor_info * scissors,uint8_t count)205 viewport_scissor_set_gen6_SCISSOR_RECT(struct ilo_state_viewport *vp,
206 const struct ilo_dev *dev,
207 const struct ilo_state_viewport_scissor_info *scissors,
208 uint8_t count)
209 {
210 const uint16_t max_size = (ilo_dev_gen(dev) >= ILO_GEN(7)) ? 16384 : 8192;
211 uint8_t i;
212
213 ILO_DEV_ASSERT(dev, 6, 8);
214
215 for (i = 0; i < count; i++) {
216 const struct ilo_state_viewport_scissor_info *scissor = &scissors[i];
217 uint16_t min_x, min_y, max_x, max_y;
218 uint32_t dw0, dw1;
219
220 min_x = (scissor->min_x < max_size) ? scissor->min_x : max_size - 1;
221 min_y = (scissor->min_y < max_size) ? scissor->min_y : max_size - 1;
222 max_x = (scissor->max_x < max_size) ? scissor->max_x : max_size - 1;
223 max_y = (scissor->max_y < max_size) ? scissor->max_y : max_size - 1;
224
225 dw0 = min_y << GEN6_SCISSOR_DW0_MIN_Y__SHIFT |
226 min_x << GEN6_SCISSOR_DW0_MIN_X__SHIFT;
227 dw1 = max_y << GEN6_SCISSOR_DW1_MAX_Y__SHIFT |
228 max_x << GEN6_SCISSOR_DW1_MAX_X__SHIFT;
229
230 STATIC_ASSERT(ARRAY_SIZE(vp->scissor[i]) >= 2);
231 vp->scissor[i][0] = dw0;
232 vp->scissor[i][1] = dw1;
233 }
234
235 return true;
236 }
237
238 bool
ilo_state_viewport_init(struct ilo_state_viewport * vp,const struct ilo_dev * dev,const struct ilo_state_viewport_info * info)239 ilo_state_viewport_init(struct ilo_state_viewport *vp,
240 const struct ilo_dev *dev,
241 const struct ilo_state_viewport_info *info)
242 {
243 const size_t elem_size = ilo_state_viewport_data_size(dev, 1);
244
245 assert(ilo_is_zeroed(vp, sizeof(*vp)));
246 assert(ilo_is_zeroed(info->data, info->data_size));
247
248 vp->data = info->data;
249
250 if (info->data_size / elem_size < ILO_STATE_VIEWPORT_MAX_COUNT)
251 vp->array_size = info->data_size / elem_size;
252 else
253 vp->array_size = ILO_STATE_VIEWPORT_MAX_COUNT;
254
255 return ilo_state_viewport_set_params(vp, dev, &info->params, false);
256 }
257
258 bool
ilo_state_viewport_init_data_only(struct ilo_state_viewport * vp,const struct ilo_dev * dev,void * data,size_t data_size)259 ilo_state_viewport_init_data_only(struct ilo_state_viewport *vp,
260 const struct ilo_dev *dev,
261 void *data, size_t data_size)
262 {
263 struct ilo_state_viewport_info info;
264
265 memset(&info, 0, sizeof(info));
266 info.data = data;
267 info.data_size = data_size;
268
269 return ilo_state_viewport_init(vp, dev, &info);
270 }
271
272 bool
ilo_state_viewport_init_for_rectlist(struct ilo_state_viewport * vp,const struct ilo_dev * dev,void * data,size_t data_size)273 ilo_state_viewport_init_for_rectlist(struct ilo_state_viewport *vp,
274 const struct ilo_dev *dev,
275 void *data, size_t data_size)
276 {
277 struct ilo_state_viewport_info info;
278 struct ilo_state_viewport_matrix_info mat;
279 struct ilo_state_viewport_scissor_info sci;
280
281 memset(&info, 0, sizeof(info));
282 memset(&mat, 0, sizeof(mat));
283 memset(&sci, 0, sizeof(sci));
284
285 info.data = data;
286 info.data_size = data_size;
287 info.params.matrices = &mat;
288 info.params.scissors = &sci;
289 info.params.count = 1;
290
291 mat.scale[0] = 1.0f;
292 mat.scale[1] = 1.0f;
293 mat.scale[2] = 1.0f;
294
295 return ilo_state_viewport_init(vp, dev, &info);
296 }
297
298 static void
viewport_set_count(struct ilo_state_viewport * vp,const struct ilo_dev * dev,uint8_t count)299 viewport_set_count(struct ilo_state_viewport *vp,
300 const struct ilo_dev *dev,
301 uint8_t count)
302 {
303 assert(count <= vp->array_size);
304
305 vp->count = count;
306 vp->sf_clip = (uint32_t (*)[16]) vp->data;
307 vp->cc = (uint32_t (*)[ 2]) (vp->sf_clip + count);
308 vp->scissor = (uint32_t (*)[ 2]) (vp->cc + count);
309 }
310
311 bool
ilo_state_viewport_set_params(struct ilo_state_viewport * vp,const struct ilo_dev * dev,const struct ilo_state_viewport_params_info * params,bool scissors_only)312 ilo_state_viewport_set_params(struct ilo_state_viewport *vp,
313 const struct ilo_dev *dev,
314 const struct ilo_state_viewport_params_info *params,
315 bool scissors_only)
316 {
317 bool ret = true;
318
319 if (scissors_only) {
320 assert(vp->count == params->count);
321
322 ret &= viewport_scissor_set_gen6_SCISSOR_RECT(vp, dev,
323 params->scissors, params->count);
324 } else {
325 viewport_set_count(vp, dev, params->count);
326
327 ret &= viewport_matrix_set_gen7_SF_CLIP_VIEWPORT(vp, dev,
328 params->matrices, params->count);
329 ret &= viewport_matrix_set_gen6_CC_VIEWPORT(vp, dev,
330 params->matrices, params->count);
331 ret &= viewport_scissor_set_gen6_SCISSOR_RECT(vp, dev,
332 params->scissors, params->count);
333 }
334
335 assert(ret);
336
337 return ret;
338 }
339
340 void
ilo_state_viewport_full_delta(const struct ilo_state_viewport * vp,const struct ilo_dev * dev,struct ilo_state_viewport_delta * delta)341 ilo_state_viewport_full_delta(const struct ilo_state_viewport *vp,
342 const struct ilo_dev *dev,
343 struct ilo_state_viewport_delta *delta)
344 {
345 delta->dirty = ILO_STATE_VIEWPORT_SF_CLIP_VIEWPORT |
346 ILO_STATE_VIEWPORT_CC_VIEWPORT |
347 ILO_STATE_VIEWPORT_SCISSOR_RECT;
348 }
349
350 void
ilo_state_viewport_get_delta(const struct ilo_state_viewport * vp,const struct ilo_dev * dev,const struct ilo_state_viewport * old,struct ilo_state_viewport_delta * delta)351 ilo_state_viewport_get_delta(const struct ilo_state_viewport *vp,
352 const struct ilo_dev *dev,
353 const struct ilo_state_viewport *old,
354 struct ilo_state_viewport_delta *delta)
355 {
356 const size_t sf_clip_size = sizeof(vp->sf_clip[0]) * vp->count;
357 const size_t cc_size = sizeof(vp->cc[0]) * vp->count;
358 const size_t scissor_size = sizeof(vp->scissor[0]) * vp->count;
359
360 /* no shallow copying */
361 assert(vp->data != old->data);
362
363 if (vp->count != old->count) {
364 ilo_state_viewport_full_delta(vp, dev, delta);
365 return;
366 }
367
368 delta->dirty = 0;
369
370 if (memcmp(vp->sf_clip, old->sf_clip, sf_clip_size))
371 delta->dirty |= ILO_STATE_VIEWPORT_SF_CLIP_VIEWPORT;
372
373 if (memcmp(vp->cc, old->cc, cc_size))
374 delta->dirty |= ILO_STATE_VIEWPORT_CC_VIEWPORT;
375
376 if (memcmp(vp->scissor, old->scissor, scissor_size))
377 delta->dirty |= ILO_STATE_VIEWPORT_SCISSOR_RECT;
378 }
379