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 (at) lunarg.com> 26 */ 27 28 #include "ilo_debug.h" 29 #include "ilo_state_viewport.h" 30 31 static void 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 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 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 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 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 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 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 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 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 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 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 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