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 s->u.tex.first_layer, s->u.tex.level); 92 } 93 } 94 95 if ((curr->zsbuf != hw->zsbuf) || (reemit && hw->zsbuf)) { 96 ret = SVGA3D_SetRenderTarget(svga->swc, SVGA3D_RT_DEPTH, curr->zsbuf); 97 if (ret != PIPE_OK) 98 return ret; 99 100 /* Check to see if we need to propagate the depth stencil surface */ 101 if (hw->zsbuf && svga_surface_needs_propagation(hw->zsbuf)) 102 svga_propagate_surface(svga, hw->zsbuf, TRUE); 103 104 if (curr->zsbuf && 105 util_format_is_depth_and_stencil(curr->zsbuf->format)) { 106 ret = SVGA3D_SetRenderTarget(svga->swc, SVGA3D_RT_STENCIL, 107 curr->zsbuf); 108 if (ret != PIPE_OK) 109 return ret; 110 } 111 else { 112 ret = SVGA3D_SetRenderTarget(svga->swc, SVGA3D_RT_STENCIL, NULL); 113 if (ret != PIPE_OK) 114 return ret; 115 } 116 117 pipe_surface_reference(&hw->zsbuf, curr->zsbuf); 118 119 /* Set the rendered-to flag */ 120 struct pipe_surface *s = curr->zsbuf; 121 if (s) { 122 svga_set_texture_rendered_to(svga_texture(s->texture), 123 s->u.tex.first_layer, s->u.tex.level); 124 } 125 } 126 127 return PIPE_OK; 128} 129 130 131/* 132 * Rebind rendertargets. 133 * 134 * Similar to emit_framebuffer, but without any state checking/update. 135 * 136 * Called at the beginning of every new command buffer to ensure that 137 * non-dirty rendertargets are properly paged-in. 138 */ 139static enum pipe_error 140svga_reemit_framebuffer_bindings_vgpu9(struct svga_context *svga) 141{ 142 struct svga_screen *svgascreen = svga_screen(svga->pipe.screen); 143 struct pipe_framebuffer_state *hw = &svga->state.hw_clear.framebuffer; 144 unsigned i; 145 enum pipe_error ret; 146 147 assert(!svga_have_vgpu10(svga)); 148 149 for (i = 0; i < svgascreen->max_color_buffers; i++) { 150 if (hw->cbufs[i]) { 151 ret = SVGA3D_SetRenderTarget(svga->swc, SVGA3D_RT_COLOR0 + i, 152 hw->cbufs[i]); 153 if (ret != PIPE_OK) { 154 return ret; 155 } 156 } 157 } 158 159 if (hw->zsbuf) { 160 ret = SVGA3D_SetRenderTarget(svga->swc, SVGA3D_RT_DEPTH, hw->zsbuf); 161 if (ret != PIPE_OK) { 162 return ret; 163 } 164 165 if (hw->zsbuf && 166 util_format_is_depth_and_stencil(hw->zsbuf->format)) { 167 ret = SVGA3D_SetRenderTarget(svga->swc, SVGA3D_RT_STENCIL, hw->zsbuf); 168 if (ret != PIPE_OK) { 169 return ret; 170 } 171 } 172 else { 173 ret = SVGA3D_SetRenderTarget(svga->swc, SVGA3D_RT_STENCIL, NULL); 174 if (ret != PIPE_OK) { 175 return ret; 176 } 177 } 178 } 179 180 return PIPE_OK; 181} 182 183 184 185static enum pipe_error 186emit_fb_vgpu10(struct svga_context *svga) 187{ 188 const struct svga_screen *ss = svga_screen(svga->pipe.screen); 189 struct pipe_surface *rtv[SVGA3D_MAX_RENDER_TARGETS]; 190 struct pipe_surface *dsv; 191 struct pipe_framebuffer_state *curr = &svga->curr.framebuffer; 192 struct pipe_framebuffer_state *hw = &svga->state.hw_clear.framebuffer; 193 const unsigned num_color = MAX2(curr->nr_cbufs, hw->nr_cbufs); 194 int last_rtv = -1; 195 unsigned i; 196 enum pipe_error ret = PIPE_OK; 197 198 assert(svga_have_vgpu10(svga)); 199 200 /* Reset the has_backed_views flag. 201 * The flag is set in svga_validate_surface_view() if 202 * a backed surface view is used. 203 */ 204 svga->state.hw_draw.has_backed_views = FALSE; 205 206 /* Setup render targets array. Note that we loop over the max of the 207 * number of previously bound buffers and the new buffers to unbind 208 * any previously bound buffers when the new number of buffers is less 209 * than the old number of buffers. 210 */ 211 for (i = 0; i < num_color; i++) { 212 if (curr->cbufs[i]) { 213 struct pipe_surface *s = curr->cbufs[i]; 214 215 if (curr->cbufs[i] != hw->cbufs[i]) { 216 rtv[i] = svga_validate_surface_view(svga, svga_surface(s)); 217 if (rtv[i] == NULL) { 218 return PIPE_ERROR_OUT_OF_MEMORY; 219 } 220 } else { 221 rtv[i] = svga->state.hw_clear.rtv[i]; 222 } 223 224 assert(svga_surface(rtv[i])->view_id != SVGA3D_INVALID_ID); 225 last_rtv = i; 226 227 /* Set the rendered-to flag */ 228 svga_set_texture_rendered_to(svga_texture(s->texture), 229 s->u.tex.first_layer, s->u.tex.level); 230 } 231 else { 232 rtv[i] = NULL; 233 } 234 } 235 236 /* Setup depth stencil view */ 237 if (curr->zsbuf) { 238 struct pipe_surface *s = curr->zsbuf; 239 240 if (curr->zsbuf != hw->zsbuf) { 241 dsv = svga_validate_surface_view(svga, svga_surface(curr->zsbuf)); 242 if (!dsv) { 243 return PIPE_ERROR_OUT_OF_MEMORY; 244 } 245 } else { 246 dsv = svga->state.hw_clear.dsv; 247 } 248 249 /* Set the rendered-to flag */ 250 svga_set_texture_rendered_to(svga_texture(s->texture), 251 s->u.tex.first_layer, s->u.tex.level); 252 } 253 else { 254 dsv = NULL; 255 } 256 257 /* avoid emitting redundant SetRenderTargets command */ 258 if ((num_color != svga->state.hw_clear.num_rendertargets) || 259 (dsv != svga->state.hw_clear.dsv) || 260 memcmp(rtv, svga->state.hw_clear.rtv, num_color * sizeof(rtv[0]))) { 261 262 ret = SVGA3D_vgpu10_SetRenderTargets(svga->swc, num_color, rtv, dsv); 263 if (ret != PIPE_OK) 264 return ret; 265 266 /* number of render targets sent to the device, not including trailing 267 * unbound render targets. 268 */ 269 for (i = 0; i < ss->max_color_buffers; i++) { 270 if (hw->cbufs[i] != curr->cbufs[i]) { 271 /* propagate the backed view surface before unbinding it */ 272 if (hw->cbufs[i] && svga_surface(hw->cbufs[i])->backed) { 273 svga_propagate_surface(svga, 274 &svga_surface(hw->cbufs[i])->backed->base, 275 TRUE); 276 } 277 else if (svga->state.hw_clear.rtv[i] != hw->cbufs[i] && 278 svga->state.hw_clear.rtv[i]) { 279 /* Free the alternate surface view when it is unbound. */ 280 svga->pipe.surface_destroy(&svga->pipe, svga->state.hw_clear.rtv[i]); 281 } 282 pipe_surface_reference(&hw->cbufs[i], curr->cbufs[i]); 283 } 284 } 285 svga->state.hw_clear.num_rendertargets = last_rtv + 1; 286 memcpy(svga->state.hw_clear.rtv, rtv, num_color * sizeof(rtv[0])); 287 hw->nr_cbufs = curr->nr_cbufs; 288 289 if (hw->zsbuf != curr->zsbuf) { 290 /* propagate the backed view surface before unbinding it */ 291 if (hw->zsbuf && svga_surface(hw->zsbuf)->backed) { 292 svga_propagate_surface(svga, 293 &svga_surface(hw->zsbuf)->backed->base, 294 TRUE); 295 } 296 else if (svga->state.hw_clear.dsv != hw->zsbuf && svga->state.hw_clear.dsv) { 297 /* Free the alternate surface view when it is unbound. */ 298 svga->pipe.surface_destroy(&svga->pipe, svga->state.hw_clear.dsv); 299 } 300 pipe_surface_reference(&hw->zsbuf, curr->zsbuf); 301 } 302 svga->state.hw_clear.dsv = dsv; 303 } 304 305 return ret; 306} 307 308 309static enum pipe_error 310emit_framebuffer(struct svga_context *svga, uint64_t dirty) 311{ 312 if (svga_have_vgpu10(svga)) { 313 return emit_fb_vgpu10(svga); 314 } 315 else { 316 return emit_fb_vgpu9(svga); 317 } 318} 319 320 321/* 322 * Rebind rendertargets. 323 * 324 * Similar to emit_framebuffer, but without any state checking/update. 325 * 326 * Called at the beginning of every new command buffer to ensure that 327 * non-dirty rendertargets are properly paged-in. 328 */ 329enum pipe_error 330svga_reemit_framebuffer_bindings(struct svga_context *svga) 331{ 332 enum pipe_error ret; 333 334 assert(svga->rebind.flags.rendertargets); 335 336 if (svga_have_vgpu10(svga)) { 337 ret = emit_fb_vgpu10(svga); 338 } 339 else { 340 ret = svga_reemit_framebuffer_bindings_vgpu9(svga); 341 } 342 343 svga->rebind.flags.rendertargets = FALSE; 344 345 return ret; 346} 347 348 349/* 350 * Send a private allocation command to page in rendertargets resource. 351 */ 352enum pipe_error 353svga_rebind_framebuffer_bindings(struct svga_context *svga) 354{ 355 struct svga_hw_clear_state *hw = &svga->state.hw_clear; 356 unsigned i; 357 enum pipe_error ret; 358 359 assert(svga_have_vgpu10(svga)); 360 361 if (!svga->rebind.flags.rendertargets) 362 return PIPE_OK; 363 364 for (i = 0; i < hw->num_rendertargets; i++) { 365 if (hw->rtv[i]) { 366 ret = svga->swc->resource_rebind(svga->swc, 367 svga_surface(hw->rtv[i])->handle, 368 NULL, 369 SVGA_RELOC_WRITE); 370 if (ret != PIPE_OK) 371 return ret; 372 } 373 } 374 375 if (hw->dsv) { 376 ret = svga->swc->resource_rebind(svga->swc, 377 svga_surface(hw->dsv)->handle, 378 NULL, 379 SVGA_RELOC_WRITE); 380 if (ret != PIPE_OK) 381 return ret; 382 } 383 384 svga->rebind.flags.rendertargets = 0; 385 386 return PIPE_OK; 387} 388 389 390struct svga_tracked_state svga_hw_framebuffer = 391{ 392 "hw framebuffer state", 393 SVGA_NEW_FRAME_BUFFER, 394 emit_framebuffer 395}; 396 397 398 399 400/*********************************************************************** 401 */ 402 403static void 404get_viewport_prescale(struct svga_context *svga, 405 struct pipe_viewport_state *viewport, 406 SVGA3dViewport *vp, 407 struct svga_prescale *prescale) 408{ 409 SVGA3dRect rect; 410 411 /* Not sure if this state is relevant with POSITIONT. Probably 412 * not, but setting to 0,1 avoids some state pingponging. 413 */ 414 float range_min = 0.0; 415 float range_max = 1.0; 416 float flip = -1.0; 417 boolean degenerate = FALSE; 418 boolean invertY = FALSE; 419 420 float fb_width = (float) svga->curr.framebuffer.width; 421 float fb_height = (float) svga->curr.framebuffer.height; 422 423 float fx = viewport->scale[0] * -1.0f + viewport->translate[0]; 424 float fy = flip * viewport->scale[1] * -1.0f + viewport->translate[1]; 425 float fw = viewport->scale[0] * 2.0f; 426 float fh = flip * viewport->scale[1] * 2.0f; 427 428 memset(prescale, 0, sizeof(*prescale)); 429 430 /* Examine gallium viewport transformation and produce a screen 431 * rectangle and possibly vertex shader pre-transformation to 432 * get the same results. 433 */ 434 435 SVGA_DBG(DEBUG_VIEWPORT, 436 "\ninitial %f,%f %fx%f\n", 437 fx, 438 fy, 439 fw, 440 fh); 441 442 prescale->scale[0] = 1.0; 443 prescale->scale[1] = 1.0; 444 prescale->scale[2] = 1.0; 445 prescale->scale[3] = 1.0; 446 prescale->translate[0] = 0; 447 prescale->translate[1] = 0; 448 prescale->translate[2] = 0; 449 prescale->translate[3] = 0; 450 451 /* Enable prescale to adjust vertex positions to match 452 VGPU10 convention only if rasterization is enabled. 453 */ 454 if (svga->curr.rast && svga->curr.rast->templ.rasterizer_discard) { 455 degenerate = TRUE; 456 goto out; 457 } else { 458 prescale->enabled = TRUE; 459 } 460 461 if (fw < 0) { 462 prescale->scale[0] *= -1.0f; 463 prescale->translate[0] += -fw; 464 fw = -fw; 465 fx = viewport->scale[0] * 1.0f + viewport->translate[0]; 466 } 467 468 if (fh < 0.0) { 469 if (svga_have_vgpu10(svga)) { 470 /* floating point viewport params below */ 471 prescale->translate[1] = fh + fy * 2.0f; 472 } 473 else { 474 /* integer viewport params below */ 475 prescale->translate[1] = fh - 1.0f + fy * 2.0f; 476 } 477 fh = -fh; 478 fy -= fh; 479 prescale->scale[1] = -1.0f; 480 invertY = TRUE; 481 } 482 483 if (fx < 0) { 484 prescale->translate[0] += fx; 485 prescale->scale[0] *= fw / (fw + fx); 486 fw += fx; 487 fx = 0.0f; 488 } 489 490 if (fy < 0) { 491 if (invertY) { 492 prescale->translate[1] -= fy; 493 } 494 else { 495 prescale->translate[1] += fy; 496 } 497 prescale->scale[1] *= fh / (fh + fy); 498 fh += fy; 499 fy = 0.0f; 500 } 501 502 if (fx + fw > fb_width) { 503 prescale->scale[0] *= fw / (fb_width - fx); 504 prescale->translate[0] -= fx * (fw / (fb_width - fx)); 505 prescale->translate[0] += fx; 506 fw = fb_width - fx; 507 } 508 509 if (fy + fh > fb_height) { 510 prescale->scale[1] *= fh / (fb_height - fy); 511 if (invertY) { 512 float in = fb_height - fy; /* number of vp pixels inside view */ 513 float out = fy + fh - fb_height; /* number of vp pixels out of view */ 514 prescale->translate[1] += fy * out / in; 515 } 516 else { 517 prescale->translate[1] -= fy * (fh / (fb_height - fy)); 518 prescale->translate[1] += fy; 519 } 520 fh = fb_height - fy; 521 } 522 523 if (fw < 0 || fh < 0) { 524 fw = fh = fx = fy = 0; 525 degenerate = TRUE; 526 goto out; 527 } 528 529 /* D3D viewport is integer space. Convert fx,fy,etc. to 530 * integers. 531 * 532 * TODO: adjust pretranslate correct for any subpixel error 533 * introduced converting to integers. 534 */ 535 rect.x = (uint32) fx; 536 rect.y = (uint32) fy; 537 rect.w = (uint32) fw; 538 rect.h = (uint32) fh; 539 540 SVGA_DBG(DEBUG_VIEWPORT, 541 "viewport error %f,%f %fx%f\n", 542 fabs((float)rect.x - fx), 543 fabs((float)rect.y - fy), 544 fabs((float)rect.w - fw), 545 fabs((float)rect.h - fh)); 546 547 SVGA_DBG(DEBUG_VIEWPORT, 548 "viewport %d,%d %dx%d\n", 549 rect.x, 550 rect.y, 551 rect.w, 552 rect.h); 553 554 /* Finally, to get GL rasterization rules, need to tweak the 555 * screen-space coordinates slightly relative to D3D which is 556 * what hardware implements natively. 557 */ 558 if (svga->curr.rast && svga->curr.rast->templ.half_pixel_center) { 559 float adjust_x = 0.0; 560 float adjust_y = 0.0; 561 562 if (svga_have_vgpu10(svga)) { 563 /* Normally, we don't have to do any sub-pixel coordinate 564 * adjustments for VGPU10. But when we draw wide points with 565 * a GS we need an X adjustment in order to be conformant. 566 */ 567 if (svga->curr.reduced_prim == PIPE_PRIM_POINTS && 568 svga->curr.rast->pointsize > 1.0f) { 569 adjust_x = 0.5; 570 } 571 } 572 else { 573 /* Use (-0.5, -0.5) bias for all prim types. 574 * Regarding line rasterization, this does not seem to satisfy 575 * the Piglit gl-1.0-ortho-pos test but it generally produces 576 * results identical or very similar to VGPU10. 577 */ 578 adjust_x = -0.5; 579 adjust_y = -0.5; 580 } 581 582 if (invertY) 583 adjust_y = -adjust_y; 584 585 prescale->translate[0] += adjust_x; 586 prescale->translate[1] += adjust_y; 587 prescale->translate[2] = 0.5; /* D3D clip space */ 588 prescale->scale[2] = 0.5; /* D3D clip space */ 589 } 590 591 range_min = viewport->scale[2] * -1.0f + viewport->translate[2]; 592 range_max = viewport->scale[2] * 1.0f + viewport->translate[2]; 593 594 /* D3D (and by implication SVGA) doesn't like dealing with zmax 595 * less than zmin. Detect that case, flip the depth range and 596 * invert our z-scale factor to achieve the same effect. 597 */ 598 if (range_min > range_max) { 599 float range_tmp; 600 range_tmp = range_min; 601 range_min = range_max; 602 range_max = range_tmp; 603 prescale->scale[2] = -prescale->scale[2]; 604 } 605 606 /* If zmin is less than 0, clamp zmin to 0 and adjust the prescale. 607 * zmin can be set to -1 when viewport->scale[2] is set to 1 and 608 * viewport->translate[2] is set to 0 in the blit code. 609 */ 610 if (range_min < 0.0f) { 611 range_min = -0.5f * viewport->scale[2] + 0.5f + viewport->translate[2]; 612 range_max = 0.5f * viewport->scale[2] + 0.5f + viewport->translate[2]; 613 prescale->scale[2] *= 2.0f; 614 prescale->translate[2] -= 0.5f; 615 } 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