1/********************************************************** 2 * Copyright 2008-2009 VMware, Inc. All rights reserved. 3 * 4 * Permission is hereby granted, free of charge, to any person 5 * obtaining a copy of this software and associated documentation 6 * files (the "Software"), to deal in the Software without 7 * restriction, including without limitation the rights to use, copy, 8 * modify, merge, publish, distribute, sublicense, and/or sell copies 9 * of the Software, and to permit persons to whom the Software is 10 * furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice shall be 13 * included in all copies or substantial portions of the Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 19 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 20 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 * SOFTWARE. 23 * 24 **********************************************************/ 25 26#include "util/u_inlines.h" 27#include "pipe/p_defines.h" 28#include "util/u_math.h" 29#include "util/format/u_format.h" 30 31#include "svga_context.h" 32#include "svga_state.h" 33#include "svga_cmd.h" 34#include "svga_debug.h" 35#include "svga_screen.h" 36#include "svga_surface.h" 37#include "svga_resource_texture.h" 38 39 40/* 41 * flush our command buffer after the 8th distinct render target 42 * 43 * This helps improve the surface cache behaviour in the face of the 44 * large number of single-use render targets generated by EXA and the xorg 45 * state tracker. Without this we can reference hundreds of individual 46 * render targets from a command buffer, which leaves little scope for 47 * sharing or reuse of those targets. 48 */ 49#define MAX_RT_PER_BATCH 8 50 51 52 53static enum pipe_error 54emit_fb_vgpu9(struct svga_context *svga) 55{ 56 struct svga_screen *svgascreen = svga_screen(svga->pipe.screen); 57 const struct pipe_framebuffer_state *curr = &svga->curr.framebuffer; 58 struct pipe_framebuffer_state *hw = &svga->state.hw_clear.framebuffer; 59 boolean reemit = svga->rebind.flags.rendertargets; 60 unsigned i; 61 enum pipe_error ret; 62 63 assert(!svga_have_vgpu10(svga)); 64 65 /* 66 * We need to reemit non-null surface bindings, even when they are not 67 * dirty, to ensure that the resources are paged in. 68 */ 69 70 for (i = 0; i < svgascreen->max_color_buffers; i++) { 71 if ((curr->cbufs[i] != hw->cbufs[i]) || (reemit && hw->cbufs[i])) { 72 if (svga->curr.nr_fbs++ > MAX_RT_PER_BATCH) 73 return PIPE_ERROR_OUT_OF_MEMORY; 74 75 /* Check to see if we need to propagate the render target surface */ 76 if (hw->cbufs[i] && svga_surface_needs_propagation(hw->cbufs[i])) 77 svga_propagate_surface(svga, hw->cbufs[i], TRUE); 78 79 ret = SVGA3D_SetRenderTarget(svga->swc, SVGA3D_RT_COLOR0 + i, 80 curr->cbufs[i]); 81 if (ret != PIPE_OK) 82 return ret; 83 84 pipe_surface_reference(&hw->cbufs[i], curr->cbufs[i]); 85 } 86 87 /* Set the rendered-to flag */ 88 struct pipe_surface *s = curr->cbufs[i]; 89 if (s) { 90 svga_set_texture_rendered_to(svga_texture(s->texture)); 91 } 92 } 93 94 if ((curr->zsbuf != hw->zsbuf) || (reemit && hw->zsbuf)) { 95 ret = SVGA3D_SetRenderTarget(svga->swc, SVGA3D_RT_DEPTH, curr->zsbuf); 96 if (ret != PIPE_OK) 97 return ret; 98 99 /* Check to see if we need to propagate the depth stencil surface */ 100 if (hw->zsbuf && svga_surface_needs_propagation(hw->zsbuf)) 101 svga_propagate_surface(svga, hw->zsbuf, TRUE); 102 103 if (curr->zsbuf && 104 util_format_is_depth_and_stencil(curr->zsbuf->format)) { 105 ret = SVGA3D_SetRenderTarget(svga->swc, SVGA3D_RT_STENCIL, 106 curr->zsbuf); 107 if (ret != PIPE_OK) 108 return ret; 109 } 110 else { 111 ret = SVGA3D_SetRenderTarget(svga->swc, SVGA3D_RT_STENCIL, NULL); 112 if (ret != PIPE_OK) 113 return ret; 114 } 115 116 pipe_surface_reference(&hw->zsbuf, curr->zsbuf); 117 118 /* Set the rendered-to flag */ 119 struct pipe_surface *s = curr->zsbuf; 120 if (s) { 121 svga_set_texture_rendered_to(svga_texture(s->texture)); 122 } 123 } 124 125 return PIPE_OK; 126} 127 128 129/* 130 * Rebind rendertargets. 131 * 132 * Similar to emit_framebuffer, but without any state checking/update. 133 * 134 * Called at the beginning of every new command buffer to ensure that 135 * non-dirty rendertargets are properly paged-in. 136 */ 137static enum pipe_error 138svga_reemit_framebuffer_bindings_vgpu9(struct svga_context *svga) 139{ 140 struct svga_screen *svgascreen = svga_screen(svga->pipe.screen); 141 struct pipe_framebuffer_state *hw = &svga->state.hw_clear.framebuffer; 142 unsigned i; 143 enum pipe_error ret; 144 145 assert(!svga_have_vgpu10(svga)); 146 147 for (i = 0; i < svgascreen->max_color_buffers; i++) { 148 if (hw->cbufs[i]) { 149 ret = SVGA3D_SetRenderTarget(svga->swc, SVGA3D_RT_COLOR0 + i, 150 hw->cbufs[i]); 151 if (ret != PIPE_OK) { 152 return ret; 153 } 154 } 155 } 156 157 if (hw->zsbuf) { 158 ret = SVGA3D_SetRenderTarget(svga->swc, SVGA3D_RT_DEPTH, hw->zsbuf); 159 if (ret != PIPE_OK) { 160 return ret; 161 } 162 163 if (hw->zsbuf && 164 util_format_is_depth_and_stencil(hw->zsbuf->format)) { 165 ret = SVGA3D_SetRenderTarget(svga->swc, SVGA3D_RT_STENCIL, hw->zsbuf); 166 if (ret != PIPE_OK) { 167 return ret; 168 } 169 } 170 else { 171 ret = SVGA3D_SetRenderTarget(svga->swc, SVGA3D_RT_STENCIL, NULL); 172 if (ret != PIPE_OK) { 173 return ret; 174 } 175 } 176 } 177 178 return PIPE_OK; 179} 180 181 182 183static enum pipe_error 184emit_fb_vgpu10(struct svga_context *svga) 185{ 186 const struct svga_screen *ss = svga_screen(svga->pipe.screen); 187 struct pipe_surface *rtv[SVGA3D_MAX_RENDER_TARGETS]; 188 struct pipe_surface *dsv; 189 struct pipe_framebuffer_state *curr = &svga->curr.framebuffer; 190 struct pipe_framebuffer_state *hw = &svga->state.hw_clear.framebuffer; 191 const unsigned num_color = MAX2(curr->nr_cbufs, hw->nr_cbufs); 192 int last_rtv = -1; 193 unsigned i; 194 enum pipe_error ret = PIPE_OK; 195 196 assert(svga_have_vgpu10(svga)); 197 198 /* Reset the has_backed_views flag. 199 * The flag is set in svga_validate_surface_view() if 200 * a backed surface view is used. 201 */ 202 svga->state.hw_draw.has_backed_views = FALSE; 203 204 /* Setup render targets array. Note that we loop over the max of the 205 * number of previously bound buffers and the new buffers to unbind 206 * any previously bound buffers when the new number of buffers is less 207 * than the old number of buffers. 208 */ 209 for (i = 0; i < num_color; i++) { 210 if (curr->cbufs[i]) { 211 struct pipe_surface *s = curr->cbufs[i]; 212 213 if (curr->cbufs[i] != hw->cbufs[i]) { 214 rtv[i] = svga_validate_surface_view(svga, svga_surface(s)); 215 if (rtv[i] == NULL) { 216 return PIPE_ERROR_OUT_OF_MEMORY; 217 } 218 } else { 219 rtv[i] = svga->state.hw_clear.rtv[i]; 220 } 221 222 assert(svga_surface(rtv[i])->view_id != SVGA3D_INVALID_ID); 223 last_rtv = i; 224 225 /* Set the rendered-to flag */ 226 svga_set_texture_rendered_to(svga_texture(s->texture)); 227 } 228 else { 229 rtv[i] = NULL; 230 } 231 } 232 233 /* Setup depth stencil view */ 234 if (curr->zsbuf) { 235 struct pipe_surface *s = curr->zsbuf; 236 237 if (curr->zsbuf != hw->zsbuf) { 238 dsv = svga_validate_surface_view(svga, svga_surface(curr->zsbuf)); 239 if (!dsv) { 240 return PIPE_ERROR_OUT_OF_MEMORY; 241 } 242 } else { 243 dsv = svga->state.hw_clear.dsv; 244 } 245 246 /* Set the rendered-to flag */ 247 svga_set_texture_rendered_to(svga_texture(s->texture)); 248 } 249 else { 250 dsv = NULL; 251 } 252 253 /* avoid emitting redundant SetRenderTargets command */ 254 if ((num_color != svga->state.hw_clear.num_rendertargets) || 255 (dsv != svga->state.hw_clear.dsv) || 256 memcmp(rtv, svga->state.hw_clear.rtv, num_color * sizeof(rtv[0]))) { 257 258 ret = SVGA3D_vgpu10_SetRenderTargets(svga->swc, num_color, rtv, dsv); 259 if (ret != PIPE_OK) 260 return ret; 261 262 /* number of render targets sent to the device, not including trailing 263 * unbound render targets. 264 */ 265 for (i = 0; i < ss->max_color_buffers; i++) { 266 if (hw->cbufs[i] != curr->cbufs[i]) { 267 /* propagate the backed view surface before unbinding it */ 268 if (hw->cbufs[i] && svga_surface(hw->cbufs[i])->backed) { 269 svga_propagate_surface(svga, 270 &svga_surface(hw->cbufs[i])->backed->base, 271 TRUE); 272 } 273 else if (svga->state.hw_clear.rtv[i] != hw->cbufs[i] && 274 svga->state.hw_clear.rtv[i]) { 275 /* Free the alternate surface view when it is unbound. */ 276 svga->pipe.surface_destroy(&svga->pipe, svga->state.hw_clear.rtv[i]); 277 } 278 pipe_surface_reference(&hw->cbufs[i], curr->cbufs[i]); 279 } 280 } 281 svga->state.hw_clear.num_rendertargets = last_rtv + 1; 282 memcpy(svga->state.hw_clear.rtv, rtv, num_color * sizeof(rtv[0])); 283 hw->nr_cbufs = curr->nr_cbufs; 284 285 if (hw->zsbuf != curr->zsbuf) { 286 /* propagate the backed view surface before unbinding it */ 287 if (hw->zsbuf && svga_surface(hw->zsbuf)->backed) { 288 svga_propagate_surface(svga, 289 &svga_surface(hw->zsbuf)->backed->base, 290 TRUE); 291 } 292 else if (svga->state.hw_clear.dsv != hw->zsbuf && svga->state.hw_clear.dsv) { 293 /* Free the alternate surface view when it is unbound. */ 294 svga->pipe.surface_destroy(&svga->pipe, svga->state.hw_clear.dsv); 295 } 296 pipe_surface_reference(&hw->zsbuf, curr->zsbuf); 297 } 298 svga->state.hw_clear.dsv = dsv; 299 } 300 301 return ret; 302} 303 304 305static enum pipe_error 306emit_framebuffer(struct svga_context *svga, uint64_t dirty) 307{ 308 if (svga_have_vgpu10(svga)) { 309 return emit_fb_vgpu10(svga); 310 } 311 else { 312 return emit_fb_vgpu9(svga); 313 } 314} 315 316 317/* 318 * Rebind rendertargets. 319 * 320 * Similar to emit_framebuffer, but without any state checking/update. 321 * 322 * Called at the beginning of every new command buffer to ensure that 323 * non-dirty rendertargets are properly paged-in. 324 */ 325enum pipe_error 326svga_reemit_framebuffer_bindings(struct svga_context *svga) 327{ 328 enum pipe_error ret; 329 330 assert(svga->rebind.flags.rendertargets); 331 332 if (svga_have_vgpu10(svga)) { 333 ret = emit_fb_vgpu10(svga); 334 } 335 else { 336 ret = svga_reemit_framebuffer_bindings_vgpu9(svga); 337 } 338 339 svga->rebind.flags.rendertargets = FALSE; 340 341 return ret; 342} 343 344 345/* 346 * Send a private allocation command to page in rendertargets resource. 347 */ 348enum pipe_error 349svga_rebind_framebuffer_bindings(struct svga_context *svga) 350{ 351 struct svga_hw_clear_state *hw = &svga->state.hw_clear; 352 unsigned i; 353 enum pipe_error ret; 354 355 assert(svga_have_vgpu10(svga)); 356 357 if (!svga->rebind.flags.rendertargets) 358 return PIPE_OK; 359 360 for (i = 0; i < hw->num_rendertargets; i++) { 361 if (hw->rtv[i]) { 362 ret = svga->swc->resource_rebind(svga->swc, 363 svga_surface(hw->rtv[i])->handle, 364 NULL, 365 SVGA_RELOC_WRITE); 366 if (ret != PIPE_OK) 367 return ret; 368 } 369 } 370 371 if (hw->dsv) { 372 ret = svga->swc->resource_rebind(svga->swc, 373 svga_surface(hw->dsv)->handle, 374 NULL, 375 SVGA_RELOC_WRITE); 376 if (ret != PIPE_OK) 377 return ret; 378 } 379 380 svga->rebind.flags.rendertargets = 0; 381 382 return PIPE_OK; 383} 384 385 386struct svga_tracked_state svga_hw_framebuffer = 387{ 388 "hw framebuffer state", 389 SVGA_NEW_FRAME_BUFFER, 390 emit_framebuffer 391}; 392 393 394 395 396/*********************************************************************** 397 */ 398 399static void 400get_viewport_prescale(struct svga_context *svga, 401 struct pipe_viewport_state *viewport, 402 SVGA3dViewport *vp, 403 struct svga_prescale *prescale) 404{ 405 SVGA3dRect rect; 406 407 /* Not sure if this state is relevant with POSITIONT. Probably 408 * not, but setting to 0,1 avoids some state pingponging. 409 */ 410 float range_min = 0.0; 411 float range_max = 1.0; 412 float flip = -1.0; 413 boolean degenerate = FALSE; 414 boolean invertY = FALSE; 415 416 float fb_width = (float) svga->curr.framebuffer.width; 417 float fb_height = (float) svga->curr.framebuffer.height; 418 419 float fx = viewport->scale[0] * -1.0f + viewport->translate[0]; 420 float fy = flip * viewport->scale[1] * -1.0f + viewport->translate[1]; 421 float fw = viewport->scale[0] * 2.0f; 422 float fh = flip * viewport->scale[1] * 2.0f; 423 424 memset(prescale, 0, sizeof(*prescale)); 425 426 /* Examine gallium viewport transformation and produce a screen 427 * rectangle and possibly vertex shader pre-transformation to 428 * get the same results. 429 */ 430 431 SVGA_DBG(DEBUG_VIEWPORT, 432 "\ninitial %f,%f %fx%f\n", 433 fx, 434 fy, 435 fw, 436 fh); 437 438 prescale->scale[0] = 1.0; 439 prescale->scale[1] = 1.0; 440 prescale->scale[2] = 1.0; 441 prescale->scale[3] = 1.0; 442 prescale->translate[0] = 0; 443 prescale->translate[1] = 0; 444 prescale->translate[2] = 0; 445 prescale->translate[3] = 0; 446 447 /* Enable prescale to adjust vertex positions to match 448 VGPU10 convention only if rasterization is enabled. 449 */ 450 if (svga->curr.rast && svga->curr.rast->templ.rasterizer_discard) { 451 degenerate = TRUE; 452 goto out; 453 } else { 454 prescale->enabled = TRUE; 455 } 456 457 if (fw < 0) { 458 prescale->scale[0] *= -1.0f; 459 prescale->translate[0] += -fw; 460 fw = -fw; 461 fx = viewport->scale[0] * 1.0f + viewport->translate[0]; 462 } 463 464 if (fh < 0.0) { 465 if (svga_have_vgpu10(svga)) { 466 /* floating point viewport params below */ 467 prescale->translate[1] = fh + fy * 2.0f; 468 } 469 else { 470 /* integer viewport params below */ 471 prescale->translate[1] = fh - 1.0f + fy * 2.0f; 472 } 473 fh = -fh; 474 fy -= fh; 475 prescale->scale[1] = -1.0f; 476 invertY = TRUE; 477 } 478 479 if (fx < 0) { 480 prescale->translate[0] += fx; 481 prescale->scale[0] *= fw / (fw + fx); 482 fw += fx; 483 fx = 0.0f; 484 } 485 486 if (fy < 0) { 487 if (invertY) { 488 prescale->translate[1] -= fy; 489 } 490 else { 491 prescale->translate[1] += fy; 492 } 493 prescale->scale[1] *= fh / (fh + fy); 494 fh += fy; 495 fy = 0.0f; 496 } 497 498 if (fx + fw > fb_width) { 499 prescale->scale[0] *= fw / (fb_width - fx); 500 prescale->translate[0] -= fx * (fw / (fb_width - fx)); 501 prescale->translate[0] += fx; 502 fw = fb_width - fx; 503 } 504 505 if (fy + fh > fb_height) { 506 prescale->scale[1] *= fh / (fb_height - fy); 507 if (invertY) { 508 float in = fb_height - fy; /* number of vp pixels inside view */ 509 float out = fy + fh - fb_height; /* number of vp pixels out of view */ 510 prescale->translate[1] += fy * out / in; 511 } 512 else { 513 prescale->translate[1] -= fy * (fh / (fb_height - fy)); 514 prescale->translate[1] += fy; 515 } 516 fh = fb_height - fy; 517 } 518 519 if (fw < 0 || fh < 0) { 520 fw = fh = fx = fy = 0; 521 degenerate = TRUE; 522 goto out; 523 } 524 525 /* D3D viewport is integer space. Convert fx,fy,etc. to 526 * integers. 527 * 528 * TODO: adjust pretranslate correct for any subpixel error 529 * introduced converting to integers. 530 */ 531 rect.x = (uint32) fx; 532 rect.y = (uint32) fy; 533 rect.w = (uint32) fw; 534 rect.h = (uint32) fh; 535 536 SVGA_DBG(DEBUG_VIEWPORT, 537 "viewport error %f,%f %fx%f\n", 538 fabs((float)rect.x - fx), 539 fabs((float)rect.y - fy), 540 fabs((float)rect.w - fw), 541 fabs((float)rect.h - fh)); 542 543 SVGA_DBG(DEBUG_VIEWPORT, 544 "viewport %d,%d %dx%d\n", 545 rect.x, 546 rect.y, 547 rect.w, 548 rect.h); 549 550 /* Finally, to get GL rasterization rules, need to tweak the 551 * screen-space coordinates slightly relative to D3D which is 552 * what hardware implements natively. 553 */ 554 if (svga->curr.rast && svga->curr.rast->templ.half_pixel_center) { 555 float adjust_x = 0.0; 556 float adjust_y = 0.0; 557 558 if (svga_have_vgpu10(svga)) { 559 /* Normally, we don't have to do any sub-pixel coordinate 560 * adjustments for VGPU10. But when we draw wide points with 561 * a GS we need an X adjustment in order to be conformant. 562 */ 563 if (svga->curr.reduced_prim == PIPE_PRIM_POINTS && 564 svga->curr.rast->pointsize > 1.0f) { 565 adjust_x = 0.5; 566 } 567 } 568 else { 569 /* Use (-0.5, -0.5) bias for all prim types. 570 * Regarding line rasterization, this does not seem to satisfy 571 * the Piglit gl-1.0-ortho-pos test but it generally produces 572 * results identical or very similar to VGPU10. 573 */ 574 adjust_x = -0.5; 575 adjust_y = -0.5; 576 } 577 578 if (invertY) 579 adjust_y = -adjust_y; 580 581 prescale->translate[0] += adjust_x; 582 prescale->translate[1] += adjust_y; 583 prescale->translate[2] = 0.5; /* D3D clip space */ 584 prescale->scale[2] = 0.5; /* D3D clip space */ 585 } 586 587 range_min = viewport->scale[2] * -1.0f + viewport->translate[2]; 588 range_max = viewport->scale[2] * 1.0f + viewport->translate[2]; 589 590 /* D3D (and by implication SVGA) doesn't like dealing with zmax 591 * less than zmin. Detect that case, flip the depth range and 592 * invert our z-scale factor to achieve the same effect. 593 */ 594 if (range_min > range_max) { 595 float range_tmp; 596 range_tmp = range_min; 597 range_min = range_max; 598 range_max = range_tmp; 599 prescale->scale[2] = -prescale->scale[2]; 600 } 601 602 /* If zmin is less than 0, clamp zmin to 0 and adjust the prescale. 603 * zmin can be set to -1 when viewport->scale[2] is set to 1 and 604 * viewport->translate[2] is set to 0 in the blit code. 605 */ 606 if (range_min < 0.0f) { 607 range_min = -0.5f * viewport->scale[2] + 0.5f + viewport->translate[2]; 608 range_max = 0.5f * viewport->scale[2] + 0.5f + viewport->translate[2]; 609 prescale->scale[2] *= 2.0f; 610 prescale->translate[2] -= 0.5f; 611 } 612 613 /* Clamp depth range, making sure it's between 0 and 1 */ 614 range_min = CLAMP(range_min, 0.0f, 1.0f); 615 range_max = CLAMP(range_max, 0.0f, 1.0f); 616 617 if (prescale->enabled) { 618 float H[2]; 619 float J[2]; 620 int i; 621 622 SVGA_DBG(DEBUG_VIEWPORT, 623 "prescale %f,%f %fx%f\n", 624 prescale->translate[0], 625 prescale->translate[1], 626 prescale->scale[0], 627 prescale->scale[1]); 628 629 H[0] = (float)rect.w / 2.0f; 630 H[1] = -(float)rect.h / 2.0f; 631 J[0] = (float)rect.x + (float)rect.w / 2.0f; 632 J[1] = (float)rect.y + (float)rect.h / 2.0f; 633 634 SVGA_DBG(DEBUG_VIEWPORT, 635 "H %f,%f\n" 636 "J %fx%f\n", 637 H[0], 638 H[1], 639 J[0], 640 J[1]); 641 642 /* Adjust prescale to take into account the fact that it is 643 * going to be applied prior to the perspective divide and 644 * viewport transformation. 645 * 646 * Vwin = H(Vc/Vc.w) + J 647 * 648 * We want to tweak Vwin with scale and translation from above, 649 * as in: 650 * 651 * Vwin' = S Vwin + T 652 * 653 * But we can only modify the values at Vc. Plugging all the 654 * above together, and rearranging, eventually we get: 655 * 656 * Vwin' = H(Vc'/Vc'.w) + J 657 * where: 658 * Vc' = SVc + KVc.w 659 * K = (T + (S-1)J) / H 660 * 661 * Overwrite prescale.translate with values for K: 662 */ 663 for (i = 0; i < 2; i++) { 664 prescale->translate[i] = ((prescale->translate[i] + 665 (prescale->scale[i] - 1.0f) * J[i]) / H[i]); 666 } 667 668 SVGA_DBG(DEBUG_VIEWPORT, 669 "clipspace %f,%f %fx%f\n", 670 prescale->translate[0], 671 prescale->translate[1], 672 prescale->scale[0], 673 prescale->scale[1]); 674 } 675 676out: 677 if (degenerate) { 678 rect.x = 0; 679 rect.y = 0; 680 rect.w = 1; 681 rect.h = 1; 682 prescale->enabled = FALSE; 683 } 684 685 vp->x = (float) rect.x; 686 vp->y = (float) rect.y; 687 vp->width = (float) rect.w; 688 vp->height = (float) rect.h; 689 vp->minDepth = range_min; 690 vp->maxDepth = range_max; 691} 692 693 694static enum pipe_error 695emit_viewport( struct svga_context *svga, 696 uint64_t dirty ) 697{ 698 struct svga_screen *svgascreen = svga_screen(svga->pipe.screen); 699 SVGA3dViewport viewports[SVGA3D_DX_MAX_VIEWPORTS]; 700 struct svga_prescale prescale[SVGA3D_DX_MAX_VIEWPORTS]; 701 unsigned i; 702 enum pipe_error ret; 703 unsigned max_viewports = svgascreen->max_viewports; 704 705 for (i = 0; i < max_viewports; i++) { 706 get_viewport_prescale(svga, &svga->curr.viewport[i], 707 &viewports[i], &prescale[i]); 708 } 709 710 if (memcmp(viewports, svga->state.hw_clear.viewports, 711 max_viewports * sizeof viewports[0]) != 0) { 712 713 if (!svga_have_vgpu10(svga)) { 714 SVGA3dRect rect; 715 SVGA3dViewport *vp = &viewports[0]; 716 717 rect.x = (uint32)vp->x; 718 rect.y = (uint32)vp->y; 719 rect.w = (uint32)vp->width; 720 rect.h = (uint32)vp->height; 721 722 ret = SVGA3D_SetViewport(svga->swc, &rect); 723 if (ret != PIPE_OK) 724 return ret; 725 726 ret = SVGA3D_SetZRange(svga->swc, vp->minDepth, vp->maxDepth); 727 if (ret != PIPE_OK) 728 return ret; 729 730 svga->state.hw_clear.viewport = rect; 731 svga->state.hw_clear.depthrange.zmin = vp->minDepth; 732 svga->state.hw_clear.depthrange.zmax = vp->maxDepth; 733 } 734 else { 735 ret = SVGA3D_vgpu10_SetViewports(svga->swc, max_viewports, 736 viewports); 737 if (ret != PIPE_OK) 738 return ret; 739 } 740 memcpy(svga->state.hw_clear.viewports, viewports, 741 max_viewports * sizeof viewports[0]); 742 } 743 744 if (memcmp(prescale, svga->state.hw_clear.prescale, 745 max_viewports * sizeof prescale[0]) != 0) { 746 svga->dirty |= SVGA_NEW_PRESCALE; 747 memcpy(svga->state.hw_clear.prescale, prescale, 748 max_viewports * sizeof prescale[0]); 749 750 /* 751 * Determine number of unique prescales. This is to minimize the 752 * if check needed in the geometry shader to identify the prescale 753 * for the specified viewport. 754 */ 755 unsigned last_prescale = SVGA3D_DX_MAX_VIEWPORTS - 1; 756 unsigned i; 757 for (i = SVGA3D_DX_MAX_VIEWPORTS-1; i > 0; i--) { 758 if (memcmp(&svga->state.hw_clear.prescale[i], 759 &svga->state.hw_clear.prescale[i-1], 760 sizeof svga->state.hw_clear.prescale[0])) { 761 break; 762 } 763 last_prescale--; 764 } 765 svga->state.hw_clear.num_prescale = last_prescale + 1; 766 } 767 768 return PIPE_OK; 769} 770 771 772struct svga_tracked_state svga_hw_viewport = 773{ 774 "hw viewport state", 775 ( SVGA_NEW_FRAME_BUFFER | 776 SVGA_NEW_VIEWPORT | 777 SVGA_NEW_RAST | 778 SVGA_NEW_REDUCED_PRIMITIVE ), 779 emit_viewport 780}; 781 782 783/*********************************************************************** 784 * Scissor state 785 */ 786static enum pipe_error 787emit_scissor_rect( struct svga_context *svga, 788 uint64_t dirty ) 789{ 790 struct svga_screen *svgascreen = svga_screen(svga->pipe.screen); 791 const struct pipe_scissor_state *scissor = svga->curr.scissor; 792 unsigned max_viewports = svgascreen->max_viewports; 793 enum pipe_error ret; 794 795 if (memcmp(&svga->state.hw_clear.scissors[0], scissor, 796 max_viewports * sizeof *scissor) != 0) { 797 798 if (svga_have_vgpu10(svga)) { 799 SVGASignedRect rect[SVGA3D_DX_MAX_VIEWPORTS]; 800 unsigned i; 801 802 for (i = 0; i < max_viewports; i++) { 803 rect[i].left = scissor[i].minx; 804 rect[i].top = scissor[i].miny; 805 rect[i].right = scissor[i].maxx; 806 rect[i].bottom = scissor[i].maxy; 807 } 808 809 ret = SVGA3D_vgpu10_SetScissorRects(svga->swc, max_viewports, rect); 810 } 811 else { 812 SVGA3dRect rect; 813 814 rect.x = scissor[0].minx; 815 rect.y = scissor[0].miny; 816 rect.w = scissor[0].maxx - scissor[0].minx; /* + 1 ?? */ 817 rect.h = scissor[0].maxy - scissor[0].miny; /* + 1 ?? */ 818 819 ret = SVGA3D_SetScissorRect(svga->swc, &rect); 820 } 821 822 if (ret != PIPE_OK) 823 return ret; 824 825 memcpy(svga->state.hw_clear.scissors, scissor, 826 max_viewports * sizeof *scissor); 827 } 828 829 return PIPE_OK; 830} 831 832struct svga_tracked_state svga_hw_scissor = 833{ 834 "hw scissor state", 835 SVGA_NEW_SCISSOR, 836 emit_scissor_rect 837}; 838 839 840/*********************************************************************** 841 * Userclip state 842 */ 843 844static enum pipe_error 845emit_clip_planes( struct svga_context *svga, 846 uint64_t dirty ) 847{ 848 unsigned i; 849 enum pipe_error ret; 850 851 /* TODO: just emit directly from svga_set_clip_state()? 852 */ 853 for (i = 0; i < SVGA3D_MAX_CLIP_PLANES; i++) { 854 /* need to express the plane in D3D-style coordinate space. 855 * GL coords get converted to D3D coords with the matrix: 856 * [ 1 0 0 0 ] 857 * [ 0 -1 0 0 ] 858 * [ 0 0 2 0 ] 859 * [ 0 0 -1 1 ] 860 * Apply that matrix to our plane equation, and invert Y. 861 */ 862 float a = svga->curr.clip.ucp[i][0]; 863 float b = svga->curr.clip.ucp[i][1]; 864 float c = svga->curr.clip.ucp[i][2]; 865 float d = svga->curr.clip.ucp[i][3]; 866 float plane[4]; 867 868 plane[0] = a; 869 plane[1] = b; 870 plane[2] = 2.0f * c; 871 plane[3] = d - c; 872 873 if (svga_have_vgpu10(svga)) { 874 //debug_printf("XXX emit DX10 clip plane\n"); 875 ret = PIPE_OK; 876 } 877 else { 878 ret = SVGA3D_SetClipPlane(svga->swc, i, plane); 879 if (ret != PIPE_OK) 880 return ret; 881 } 882 } 883 884 return PIPE_OK; 885} 886 887 888struct svga_tracked_state svga_hw_clip_planes = 889{ 890 "hw viewport state", 891 SVGA_NEW_CLIP, 892 emit_clip_planes 893}; 894