1/* 2 * Copyright 2012 Advanced Micro Devices, Inc. 3 * All Rights Reserved. 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a 6 * copy of this software and associated documentation files (the "Software"), 7 * to deal in the Software without restriction, including without limitation 8 * on the rights to use, copy, modify, merge, publish, distribute, sub 9 * license, and/or sell copies of the Software, and to permit persons to whom 10 * the Software is furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice (including the next 13 * paragraph) shall be included in all copies or substantial portions of the 14 * 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 NON-INFRINGEMENT. IN NO EVENT SHALL 19 * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, 20 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 21 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 22 * USE OR OTHER DEALINGS IN THE SOFTWARE. 23 */ 24 25#include "si_build_pm4.h" 26#include "util/u_viewport.h" 27#include "tgsi/tgsi_scan.h" 28 29#define SI_MAX_SCISSOR 16384 30 31static void si_set_scissor_states(struct pipe_context *pctx, 32 unsigned start_slot, 33 unsigned num_scissors, 34 const struct pipe_scissor_state *state) 35{ 36 struct si_context *ctx = (struct si_context *)pctx; 37 int i; 38 39 for (i = 0; i < num_scissors; i++) 40 ctx->scissors[start_slot + i] = state[i]; 41 42 if (!ctx->queued.named.rasterizer || 43 !ctx->queued.named.rasterizer->scissor_enable) 44 return; 45 46 si_mark_atom_dirty(ctx, &ctx->atoms.s.scissors); 47} 48 49/* Since the guard band disables clipping, we have to clip per-pixel 50 * using a scissor. 51 */ 52static void si_get_scissor_from_viewport(struct si_context *ctx, 53 const struct pipe_viewport_state *vp, 54 struct si_signed_scissor *scissor) 55{ 56 float tmp, minx, miny, maxx, maxy; 57 58 /* Convert (-1, -1) and (1, 1) from clip space into window space. */ 59 minx = -vp->scale[0] + vp->translate[0]; 60 miny = -vp->scale[1] + vp->translate[1]; 61 maxx = vp->scale[0] + vp->translate[0]; 62 maxy = vp->scale[1] + vp->translate[1]; 63 64 /* Handle inverted viewports. */ 65 if (minx > maxx) { 66 tmp = minx; 67 minx = maxx; 68 maxx = tmp; 69 } 70 if (miny > maxy) { 71 tmp = miny; 72 miny = maxy; 73 maxy = tmp; 74 } 75 76 /* Convert to integer and round up the max bounds. */ 77 scissor->minx = minx; 78 scissor->miny = miny; 79 scissor->maxx = ceilf(maxx); 80 scissor->maxy = ceilf(maxy); 81} 82 83static void si_clamp_scissor(struct si_context *ctx, 84 struct pipe_scissor_state *out, 85 struct si_signed_scissor *scissor) 86{ 87 out->minx = CLAMP(scissor->minx, 0, SI_MAX_SCISSOR); 88 out->miny = CLAMP(scissor->miny, 0, SI_MAX_SCISSOR); 89 out->maxx = CLAMP(scissor->maxx, 0, SI_MAX_SCISSOR); 90 out->maxy = CLAMP(scissor->maxy, 0, SI_MAX_SCISSOR); 91} 92 93static void si_clip_scissor(struct pipe_scissor_state *out, 94 struct pipe_scissor_state *clip) 95{ 96 out->minx = MAX2(out->minx, clip->minx); 97 out->miny = MAX2(out->miny, clip->miny); 98 out->maxx = MIN2(out->maxx, clip->maxx); 99 out->maxy = MIN2(out->maxy, clip->maxy); 100} 101 102static void si_scissor_make_union(struct si_signed_scissor *out, 103 struct si_signed_scissor *in) 104{ 105 out->minx = MIN2(out->minx, in->minx); 106 out->miny = MIN2(out->miny, in->miny); 107 out->maxx = MAX2(out->maxx, in->maxx); 108 out->maxy = MAX2(out->maxy, in->maxy); 109 out->quant_mode = MIN2(out->quant_mode, in->quant_mode); 110} 111 112static void si_emit_one_scissor(struct si_context *ctx, 113 struct radeon_cmdbuf *cs, 114 struct si_signed_scissor *vp_scissor, 115 struct pipe_scissor_state *scissor) 116{ 117 struct pipe_scissor_state final; 118 119 if (ctx->vs_disables_clipping_viewport) { 120 final.minx = final.miny = 0; 121 final.maxx = final.maxy = SI_MAX_SCISSOR; 122 } else { 123 si_clamp_scissor(ctx, &final, vp_scissor); 124 } 125 126 if (scissor) 127 si_clip_scissor(&final, scissor); 128 129 /* Workaround for a hw bug on SI that occurs when PA_SU_HARDWARE_- 130 * SCREEN_OFFSET != 0 and any_scissor.BR_X/Y <= 0. 131 */ 132 if (ctx->chip_class == SI && (final.maxx == 0 || final.maxy == 0)) { 133 radeon_emit(cs, S_028250_TL_X(1) | 134 S_028250_TL_Y(1) | 135 S_028250_WINDOW_OFFSET_DISABLE(1)); 136 radeon_emit(cs, S_028254_BR_X(1) | 137 S_028254_BR_Y(1)); 138 return; 139 } 140 141 radeon_emit(cs, S_028250_TL_X(final.minx) | 142 S_028250_TL_Y(final.miny) | 143 S_028250_WINDOW_OFFSET_DISABLE(1)); 144 radeon_emit(cs, S_028254_BR_X(final.maxx) | 145 S_028254_BR_Y(final.maxy)); 146} 147 148#define MAX_PA_SU_HARDWARE_SCREEN_OFFSET 8176 149 150static void si_emit_guardband(struct si_context *ctx) 151{ 152 const struct si_state_rasterizer *rs = ctx->queued.named.rasterizer; 153 struct si_signed_scissor vp_as_scissor; 154 struct pipe_viewport_state vp; 155 float left, top, right, bottom, max_range, guardband_x, guardband_y; 156 float discard_x, discard_y; 157 158 if (ctx->vs_writes_viewport_index) { 159 /* Shaders can draw to any viewport. Make a union of all 160 * viewports. */ 161 vp_as_scissor = ctx->viewports.as_scissor[0]; 162 for (unsigned i = 1; i < SI_MAX_VIEWPORTS; i++) { 163 si_scissor_make_union(&vp_as_scissor, 164 &ctx->viewports.as_scissor[i]); 165 } 166 } else { 167 vp_as_scissor = ctx->viewports.as_scissor[0]; 168 } 169 170 /* Blits don't set the viewport state. The vertex shader determines 171 * the viewport size by scaling the coordinates, so we don't know 172 * how large the viewport is. Assume the worst case. 173 */ 174 if (ctx->vs_disables_clipping_viewport) 175 vp_as_scissor.quant_mode = SI_QUANT_MODE_16_8_FIXED_POINT_1_256TH; 176 177 /* Determine the optimal hardware screen offset to center the viewport 178 * within the viewport range in order to maximize the guardband size. 179 */ 180 int hw_screen_offset_x = (vp_as_scissor.maxx + vp_as_scissor.minx) / 2; 181 int hw_screen_offset_y = (vp_as_scissor.maxy + vp_as_scissor.miny) / 2; 182 183 /* SI-CI need to align the offset to an ubertile consisting of all SEs. */ 184 const unsigned hw_screen_offset_alignment = 185 ctx->chip_class >= VI ? 16 : MAX2(ctx->screen->se_tile_repeat, 16); 186 187 /* Indexed by quantization modes */ 188 static int max_viewport_size[] = {65535, 16383, 4095}; 189 190 /* Ensure that the whole viewport stays representable in 191 * absolute coordinates. 192 * See comment in si_set_viewport_states. 193 */ 194 assert(vp_as_scissor.maxx <= max_viewport_size[vp_as_scissor.quant_mode] && 195 vp_as_scissor.maxy <= max_viewport_size[vp_as_scissor.quant_mode]); 196 197 hw_screen_offset_x = CLAMP(hw_screen_offset_x, 0, MAX_PA_SU_HARDWARE_SCREEN_OFFSET); 198 hw_screen_offset_y = CLAMP(hw_screen_offset_y, 0, MAX_PA_SU_HARDWARE_SCREEN_OFFSET); 199 200 /* Align the screen offset by dropping the low bits. */ 201 hw_screen_offset_x &= ~(hw_screen_offset_alignment - 1); 202 hw_screen_offset_y &= ~(hw_screen_offset_alignment - 1); 203 204 /* Apply the offset to center the viewport and maximize the guardband. */ 205 vp_as_scissor.minx -= hw_screen_offset_x; 206 vp_as_scissor.maxx -= hw_screen_offset_x; 207 vp_as_scissor.miny -= hw_screen_offset_y; 208 vp_as_scissor.maxy -= hw_screen_offset_y; 209 210 /* Reconstruct the viewport transformation from the scissor. */ 211 vp.translate[0] = (vp_as_scissor.minx + vp_as_scissor.maxx) / 2.0; 212 vp.translate[1] = (vp_as_scissor.miny + vp_as_scissor.maxy) / 2.0; 213 vp.scale[0] = vp_as_scissor.maxx - vp.translate[0]; 214 vp.scale[1] = vp_as_scissor.maxy - vp.translate[1]; 215 216 /* Treat a 0x0 viewport as 1x1 to prevent division by zero. */ 217 if (vp_as_scissor.minx == vp_as_scissor.maxx) 218 vp.scale[0] = 0.5; 219 if (vp_as_scissor.miny == vp_as_scissor.maxy) 220 vp.scale[1] = 0.5; 221 222 /* Find the biggest guard band that is inside the supported viewport 223 * range. The guard band is specified as a horizontal and vertical 224 * distance from (0,0) in clip space. 225 * 226 * This is done by applying the inverse viewport transformation 227 * on the viewport limits to get those limits in clip space. 228 * 229 * The viewport range is [-max_viewport_size/2, max_viewport_size/2]. 230 */ 231 assert(vp_as_scissor.quant_mode < ARRAY_SIZE(max_viewport_size)); 232 max_range = max_viewport_size[vp_as_scissor.quant_mode] / 2; 233 left = (-max_range - vp.translate[0]) / vp.scale[0]; 234 right = ( max_range - vp.translate[0]) / vp.scale[0]; 235 top = (-max_range - vp.translate[1]) / vp.scale[1]; 236 bottom = ( max_range - vp.translate[1]) / vp.scale[1]; 237 238 assert(left <= -1 && top <= -1 && right >= 1 && bottom >= 1); 239 240 guardband_x = MIN2(-left, right); 241 guardband_y = MIN2(-top, bottom); 242 243 discard_x = 1.0; 244 discard_y = 1.0; 245 246 if (unlikely(util_prim_is_points_or_lines(ctx->current_rast_prim))) { 247 /* When rendering wide points or lines, we need to be more 248 * conservative about when to discard them entirely. */ 249 float pixels; 250 251 if (ctx->current_rast_prim == PIPE_PRIM_POINTS) 252 pixels = rs->max_point_size; 253 else 254 pixels = rs->line_width; 255 256 /* Add half the point size / line width */ 257 discard_x += pixels / (2.0 * vp.scale[0]); 258 discard_y += pixels / (2.0 * vp.scale[1]); 259 260 /* Discard primitives that would lie entirely outside the clip 261 * region. */ 262 discard_x = MIN2(discard_x, guardband_x); 263 discard_y = MIN2(discard_y, guardband_y); 264 } 265 266 /* If any of the GB registers is updated, all of them must be updated. 267 * R_028BE8_PA_CL_GB_VERT_CLIP_ADJ, R_028BEC_PA_CL_GB_VERT_DISC_ADJ 268 * R_028BF0_PA_CL_GB_HORZ_CLIP_ADJ, R_028BF4_PA_CL_GB_HORZ_DISC_ADJ 269 */ 270 unsigned initial_cdw = ctx->gfx_cs->current.cdw; 271 radeon_opt_set_context_reg4(ctx, R_028BE8_PA_CL_GB_VERT_CLIP_ADJ, 272 SI_TRACKED_PA_CL_GB_VERT_CLIP_ADJ, 273 fui(guardband_y), fui(discard_y), 274 fui(guardband_x), fui(discard_x)); 275 radeon_opt_set_context_reg(ctx, R_028234_PA_SU_HARDWARE_SCREEN_OFFSET, 276 SI_TRACKED_PA_SU_HARDWARE_SCREEN_OFFSET, 277 S_028234_HW_SCREEN_OFFSET_X(hw_screen_offset_x >> 4) | 278 S_028234_HW_SCREEN_OFFSET_Y(hw_screen_offset_y >> 4)); 279 radeon_opt_set_context_reg(ctx, R_028BE4_PA_SU_VTX_CNTL, 280 SI_TRACKED_PA_SU_VTX_CNTL, 281 S_028BE4_PIX_CENTER(rs->half_pixel_center) | 282 S_028BE4_QUANT_MODE(V_028BE4_X_16_8_FIXED_POINT_1_256TH + 283 vp_as_scissor.quant_mode)); 284 if (initial_cdw != ctx->gfx_cs->current.cdw) 285 ctx->context_roll = true; 286} 287 288static void si_emit_scissors(struct si_context *ctx) 289{ 290 struct radeon_cmdbuf *cs = ctx->gfx_cs; 291 struct pipe_scissor_state *states = ctx->scissors; 292 bool scissor_enabled = ctx->queued.named.rasterizer->scissor_enable; 293 294 /* The simple case: Only 1 viewport is active. */ 295 if (!ctx->vs_writes_viewport_index) { 296 struct si_signed_scissor *vp = &ctx->viewports.as_scissor[0]; 297 298 radeon_set_context_reg_seq(cs, R_028250_PA_SC_VPORT_SCISSOR_0_TL, 2); 299 si_emit_one_scissor(ctx, cs, vp, scissor_enabled ? &states[0] : NULL); 300 return; 301 } 302 303 /* All registers in the array need to be updated if any of them is changed. 304 * This is a hardware requirement. 305 */ 306 radeon_set_context_reg_seq(cs, R_028250_PA_SC_VPORT_SCISSOR_0_TL, 307 SI_MAX_VIEWPORTS * 2); 308 for (unsigned i = 0; i < SI_MAX_VIEWPORTS; i++) { 309 si_emit_one_scissor(ctx, cs, &ctx->viewports.as_scissor[i], 310 scissor_enabled ? &states[i] : NULL); 311 } 312} 313 314static void si_set_viewport_states(struct pipe_context *pctx, 315 unsigned start_slot, 316 unsigned num_viewports, 317 const struct pipe_viewport_state *state) 318{ 319 struct si_context *ctx = (struct si_context *)pctx; 320 int i; 321 322 for (i = 0; i < num_viewports; i++) { 323 unsigned index = start_slot + i; 324 struct si_signed_scissor *scissor = &ctx->viewports.as_scissor[index]; 325 326 ctx->viewports.states[index] = state[i]; 327 328 si_get_scissor_from_viewport(ctx, &state[i], scissor); 329 330 unsigned w = scissor->maxx - scissor->minx; 331 unsigned h = scissor->maxy - scissor->miny; 332 unsigned max_extent = MAX2(w, h); 333 334 int max_corner = MAX2(scissor->maxx, scissor->maxy); 335 336 unsigned center_x = (scissor->maxx + scissor->minx) / 2; 337 unsigned center_y = (scissor->maxy + scissor->miny) / 2; 338 unsigned max_center = MAX2(center_x, center_y); 339 340 /* PA_SU_HARDWARE_SCREEN_OFFSET can't center viewports whose 341 * center start farther than MAX_PA_SU_HARDWARE_SCREEN_OFFSET. 342 * (for example, a 1x1 viewport in the lower right corner of 343 * 16Kx16K) Such viewports need a greater guardband, so they 344 * have to use a worse quantization mode. 345 */ 346 unsigned distance_off_center = 347 MAX2(0, (int)max_center - MAX_PA_SU_HARDWARE_SCREEN_OFFSET); 348 max_extent += distance_off_center; 349 350 /* Determine the best quantization mode (subpixel precision), 351 * but also leave enough space for the guardband. 352 * 353 * Note that primitive binning requires QUANT_MODE == 16_8 on Vega10 354 * and Raven1 for line and rectangle primitive types to work correctly. 355 * Always use 16_8 if primitive binning is possible to occur. 356 */ 357 if ((ctx->family == CHIP_VEGA10 || ctx->family == CHIP_RAVEN) && 358 ctx->screen->dpbb_allowed) 359 max_extent = 16384; /* Use QUANT_MODE == 16_8. */ 360 361 /* Another constraint is that all coordinates in the viewport 362 * are representable in fixed point with respect to the 363 * surface origin. 364 * 365 * It means that PA_SU_HARDWARE_SCREEN_OFFSET can't be given 366 * an offset that would make the upper corner of the viewport 367 * greater than the maximum representable number post 368 * quantization, ie 2^quant_bits. 369 * 370 * This does not matter for 14.10 and 16.8 formats since the 371 * offset is already limited at 8k, but it means we can't use 372 * 12.12 if we are drawing to some pixels outside the lower 373 * 4k x 4k of the render target. 374 */ 375 376 if (max_extent <= 1024 && max_corner < 4096) /* 4K scanline area for guardband */ 377 scissor->quant_mode = SI_QUANT_MODE_12_12_FIXED_POINT_1_4096TH; 378 else if (max_extent <= 4096) /* 16K scanline area for guardband */ 379 scissor->quant_mode = SI_QUANT_MODE_14_10_FIXED_POINT_1_1024TH; 380 else /* 64K scanline area for guardband */ 381 scissor->quant_mode = SI_QUANT_MODE_16_8_FIXED_POINT_1_256TH; 382 } 383 384 si_mark_atom_dirty(ctx, &ctx->atoms.s.viewports); 385 si_mark_atom_dirty(ctx, &ctx->atoms.s.guardband); 386 si_mark_atom_dirty(ctx, &ctx->atoms.s.scissors); 387} 388 389static void si_emit_one_viewport(struct si_context *ctx, 390 struct pipe_viewport_state *state) 391{ 392 struct radeon_cmdbuf *cs = ctx->gfx_cs; 393 394 radeon_emit(cs, fui(state->scale[0])); 395 radeon_emit(cs, fui(state->translate[0])); 396 radeon_emit(cs, fui(state->scale[1])); 397 radeon_emit(cs, fui(state->translate[1])); 398 radeon_emit(cs, fui(state->scale[2])); 399 radeon_emit(cs, fui(state->translate[2])); 400} 401 402static void si_emit_viewports(struct si_context *ctx) 403{ 404 struct radeon_cmdbuf *cs = ctx->gfx_cs; 405 struct pipe_viewport_state *states = ctx->viewports.states; 406 407 /* The simple case: Only 1 viewport is active. */ 408 if (!ctx->vs_writes_viewport_index) { 409 radeon_set_context_reg_seq(cs, R_02843C_PA_CL_VPORT_XSCALE, 6); 410 si_emit_one_viewport(ctx, &states[0]); 411 return; 412 } 413 414 /* All registers in the array need to be updated if any of them is changed. 415 * This is a hardware requirement. 416 */ 417 radeon_set_context_reg_seq(cs, R_02843C_PA_CL_VPORT_XSCALE + 418 0, SI_MAX_VIEWPORTS * 6); 419 for (unsigned i = 0; i < SI_MAX_VIEWPORTS; i++) 420 si_emit_one_viewport(ctx, &states[i]); 421} 422 423static inline void 424si_viewport_zmin_zmax(const struct pipe_viewport_state *vp, bool halfz, 425 bool window_space_position, float *zmin, float *zmax) 426{ 427 if (window_space_position) { 428 *zmin = 0; 429 *zmax = 1; 430 return; 431 } 432 util_viewport_zmin_zmax(vp, halfz, zmin, zmax); 433} 434 435static void si_emit_depth_ranges(struct si_context *ctx) 436{ 437 struct radeon_cmdbuf *cs = ctx->gfx_cs; 438 struct pipe_viewport_state *states = ctx->viewports.states; 439 bool clip_halfz = ctx->queued.named.rasterizer->clip_halfz; 440 bool window_space = ctx->vs_disables_clipping_viewport; 441 float zmin, zmax; 442 443 /* The simple case: Only 1 viewport is active. */ 444 if (!ctx->vs_writes_viewport_index) { 445 si_viewport_zmin_zmax(&states[0], clip_halfz, window_space, 446 &zmin, &zmax); 447 448 radeon_set_context_reg_seq(cs, R_0282D0_PA_SC_VPORT_ZMIN_0, 2); 449 radeon_emit(cs, fui(zmin)); 450 radeon_emit(cs, fui(zmax)); 451 return; 452 } 453 454 /* All registers in the array need to be updated if any of them is changed. 455 * This is a hardware requirement. 456 */ 457 radeon_set_context_reg_seq(cs, R_0282D0_PA_SC_VPORT_ZMIN_0, 458 SI_MAX_VIEWPORTS * 2); 459 for (unsigned i = 0; i < SI_MAX_VIEWPORTS; i++) { 460 si_viewport_zmin_zmax(&states[i], clip_halfz, window_space, 461 &zmin, &zmax); 462 radeon_emit(cs, fui(zmin)); 463 radeon_emit(cs, fui(zmax)); 464 } 465} 466 467static void si_emit_viewport_states(struct si_context *ctx) 468{ 469 si_emit_viewports(ctx); 470 si_emit_depth_ranges(ctx); 471} 472 473/** 474 * This reacts to 2 state changes: 475 * - VS.writes_viewport_index 476 * - VS output position in window space (enable/disable) 477 * 478 * Normally, we only emit 1 viewport and 1 scissor if no shader is using 479 * the VIEWPORT_INDEX output, and emitting the other viewports and scissors 480 * is delayed. When a shader with VIEWPORT_INDEX appears, this should be 481 * called to emit the rest. 482 */ 483void si_update_vs_viewport_state(struct si_context *ctx) 484{ 485 struct tgsi_shader_info *info = si_get_vs_info(ctx); 486 bool vs_window_space; 487 488 if (!info) 489 return; 490 491 /* When the VS disables clipping and viewport transformation. */ 492 vs_window_space = 493 info->properties[TGSI_PROPERTY_VS_WINDOW_SPACE_POSITION]; 494 495 if (ctx->vs_disables_clipping_viewport != vs_window_space) { 496 ctx->vs_disables_clipping_viewport = vs_window_space; 497 si_mark_atom_dirty(ctx, &ctx->atoms.s.scissors); 498 si_mark_atom_dirty(ctx, &ctx->atoms.s.viewports); 499 } 500 501 /* Viewport index handling. */ 502 if (ctx->vs_writes_viewport_index == info->writes_viewport_index) 503 return; 504 505 /* This changes how the guardband is computed. */ 506 ctx->vs_writes_viewport_index = info->writes_viewport_index; 507 si_mark_atom_dirty(ctx, &ctx->atoms.s.guardband); 508 509 /* Emit scissors and viewports that were enabled by having 510 * the ViewportIndex output. 511 */ 512 if (info->writes_viewport_index) { 513 si_mark_atom_dirty(ctx, &ctx->atoms.s.scissors); 514 si_mark_atom_dirty(ctx, &ctx->atoms.s.viewports); 515 } 516} 517 518static void si_emit_window_rectangles(struct si_context *sctx) 519{ 520 /* There are four clipping rectangles. Their corner coordinates are inclusive. 521 * Every pixel is assigned a number from 0 and 15 by setting bits 0-3 depending 522 * on whether the pixel is inside cliprects 0-3, respectively. For example, 523 * if a pixel is inside cliprects 0 and 1, but outside 2 and 3, it is assigned 524 * the number 3 (binary 0011). 525 * 526 * If CLIPRECT_RULE & (1 << number), the pixel is rasterized. 527 */ 528 struct radeon_cmdbuf *cs = sctx->gfx_cs; 529 static const unsigned outside[4] = { 530 /* outside rectangle 0 */ 531 V_02820C_OUT | 532 V_02820C_IN_1 | 533 V_02820C_IN_2 | 534 V_02820C_IN_21 | 535 V_02820C_IN_3 | 536 V_02820C_IN_31 | 537 V_02820C_IN_32 | 538 V_02820C_IN_321, 539 /* outside rectangles 0, 1 */ 540 V_02820C_OUT | 541 V_02820C_IN_2 | 542 V_02820C_IN_3 | 543 V_02820C_IN_32, 544 /* outside rectangles 0, 1, 2 */ 545 V_02820C_OUT | 546 V_02820C_IN_3, 547 /* outside rectangles 0, 1, 2, 3 */ 548 V_02820C_OUT, 549 }; 550 const unsigned disabled = 0xffff; /* all inside and outside cases */ 551 unsigned num_rectangles = sctx->num_window_rectangles; 552 struct pipe_scissor_state *rects = sctx->window_rectangles; 553 unsigned rule; 554 555 assert(num_rectangles <= 4); 556 557 if (num_rectangles == 0) 558 rule = disabled; 559 else if (sctx->window_rectangles_include) 560 rule = ~outside[num_rectangles - 1]; 561 else 562 rule = outside[num_rectangles - 1]; 563 564 radeon_opt_set_context_reg(sctx, R_02820C_PA_SC_CLIPRECT_RULE, 565 SI_TRACKED_PA_SC_CLIPRECT_RULE, rule); 566 if (num_rectangles == 0) 567 return; 568 569 radeon_set_context_reg_seq(cs, R_028210_PA_SC_CLIPRECT_0_TL, 570 num_rectangles * 2); 571 for (unsigned i = 0; i < num_rectangles; i++) { 572 radeon_emit(cs, S_028210_TL_X(rects[i].minx) | 573 S_028210_TL_Y(rects[i].miny)); 574 radeon_emit(cs, S_028214_BR_X(rects[i].maxx) | 575 S_028214_BR_Y(rects[i].maxy)); 576 } 577} 578 579static void si_set_window_rectangles(struct pipe_context *ctx, 580 boolean include, 581 unsigned num_rectangles, 582 const struct pipe_scissor_state *rects) 583{ 584 struct si_context *sctx = (struct si_context *)ctx; 585 586 sctx->num_window_rectangles = num_rectangles; 587 sctx->window_rectangles_include = include; 588 if (num_rectangles) { 589 memcpy(sctx->window_rectangles, rects, 590 sizeof(*rects) * num_rectangles); 591 } 592 593 si_mark_atom_dirty(sctx, &sctx->atoms.s.window_rectangles); 594} 595 596void si_init_viewport_functions(struct si_context *ctx) 597{ 598 ctx->atoms.s.guardband.emit = si_emit_guardband; 599 ctx->atoms.s.scissors.emit = si_emit_scissors; 600 ctx->atoms.s.viewports.emit = si_emit_viewport_states; 601 ctx->atoms.s.window_rectangles.emit = si_emit_window_rectangles; 602 603 ctx->b.set_scissor_states = si_set_scissor_states; 604 ctx->b.set_viewport_states = si_set_viewport_states; 605 ctx->b.set_window_rectangles = si_set_window_rectangles; 606 607 for (unsigned i = 0; i < 16; i++) 608 ctx->viewports.as_scissor[i].quant_mode = SI_QUANT_MODE_16_8_FIXED_POINT_1_256TH; 609} 610