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/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 rtv[i] = svga_validate_surface_view(svga, svga_surface(s)); 216 if (rtv[i] == NULL) { 217 return PIPE_ERROR_OUT_OF_MEMORY; 218 } 219 220 assert(svga_surface(rtv[i])->view_id != SVGA3D_INVALID_ID); 221 last_rtv = i; 222 223 /* Set the rendered-to flag */ 224 svga_set_texture_rendered_to(svga_texture(s->texture), 225 s->u.tex.first_layer, s->u.tex.level); 226 } 227 else { 228 rtv[i] = NULL; 229 } 230 } 231 232 /* Setup depth stencil view */ 233 if (curr->zsbuf) { 234 struct pipe_surface *s = curr->zsbuf; 235 236 dsv = svga_validate_surface_view(svga, svga_surface(curr->zsbuf)); 237 if (!dsv) { 238 return PIPE_ERROR_OUT_OF_MEMORY; 239 } 240 241 /* Set the rendered-to flag */ 242 svga_set_texture_rendered_to(svga_texture(s->texture), 243 s->u.tex.first_layer, s->u.tex.level); 244 } 245 else { 246 dsv = NULL; 247 } 248 249 /* avoid emitting redundant SetRenderTargets command */ 250 if ((num_color != svga->state.hw_clear.num_rendertargets) || 251 (dsv != svga->state.hw_clear.dsv) || 252 memcmp(rtv, svga->state.hw_clear.rtv, num_color * sizeof(rtv[0]))) { 253 254 ret = SVGA3D_vgpu10_SetRenderTargets(svga->swc, num_color, rtv, dsv); 255 if (ret != PIPE_OK) 256 return ret; 257 258 /* number of render targets sent to the device, not including trailing 259 * unbound render targets. 260 */ 261 svga->state.hw_clear.num_rendertargets = last_rtv + 1; 262 svga->state.hw_clear.dsv = dsv; 263 memcpy(svga->state.hw_clear.rtv, rtv, num_color * sizeof(rtv[0])); 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 pipe_surface_reference(&hw->cbufs[i], curr->cbufs[i]); 274 } 275 } 276 hw->nr_cbufs = curr->nr_cbufs; 277 278 if (hw->zsbuf != curr->zsbuf) { 279 /* propagate the backed view surface before unbinding it */ 280 if (hw->zsbuf && svga_surface(hw->zsbuf)->backed) { 281 svga_propagate_surface(svga, &svga_surface(hw->zsbuf)->backed->base, 282 TRUE); 283 } 284 pipe_surface_reference(&hw->zsbuf, curr->zsbuf); 285 } 286 } 287 288 return ret; 289} 290 291 292static enum pipe_error 293emit_framebuffer(struct svga_context *svga, unsigned dirty) 294{ 295 if (svga_have_vgpu10(svga)) { 296 return emit_fb_vgpu10(svga); 297 } 298 else { 299 return emit_fb_vgpu9(svga); 300 } 301} 302 303 304/* 305 * Rebind rendertargets. 306 * 307 * Similar to emit_framebuffer, but without any state checking/update. 308 * 309 * Called at the beginning of every new command buffer to ensure that 310 * non-dirty rendertargets are properly paged-in. 311 */ 312enum pipe_error 313svga_reemit_framebuffer_bindings(struct svga_context *svga) 314{ 315 enum pipe_error ret; 316 317 assert(svga->rebind.flags.rendertargets); 318 319 if (svga_have_vgpu10(svga)) { 320 ret = emit_fb_vgpu10(svga); 321 } 322 else { 323 ret = svga_reemit_framebuffer_bindings_vgpu9(svga); 324 } 325 326 svga->rebind.flags.rendertargets = FALSE; 327 328 return ret; 329} 330 331 332/* 333 * Send a private allocation command to page in rendertargets resource. 334 */ 335enum pipe_error 336svga_rebind_framebuffer_bindings(struct svga_context *svga) 337{ 338 struct svga_hw_clear_state *hw = &svga->state.hw_clear; 339 unsigned i; 340 enum pipe_error ret; 341 342 assert(svga_have_vgpu10(svga)); 343 344 if (!svga->rebind.flags.rendertargets) 345 return PIPE_OK; 346 347 for (i = 0; i < hw->num_rendertargets; i++) { 348 if (hw->rtv[i]) { 349 ret = svga->swc->resource_rebind(svga->swc, 350 svga_surface(hw->rtv[i])->handle, 351 NULL, 352 SVGA_RELOC_WRITE); 353 if (ret != PIPE_OK) 354 return ret; 355 } 356 } 357 358 if (hw->dsv) { 359 ret = svga->swc->resource_rebind(svga->swc, 360 svga_surface(hw->dsv)->handle, 361 NULL, 362 SVGA_RELOC_WRITE); 363 if (ret != PIPE_OK) 364 return ret; 365 } 366 367 svga->rebind.flags.rendertargets = 0; 368 369 return PIPE_OK; 370} 371 372 373struct svga_tracked_state svga_hw_framebuffer = 374{ 375 "hw framebuffer state", 376 SVGA_NEW_FRAME_BUFFER, 377 emit_framebuffer 378}; 379 380 381 382 383/*********************************************************************** 384 */ 385 386static enum pipe_error 387emit_viewport( struct svga_context *svga, 388 unsigned dirty ) 389{ 390 const struct pipe_viewport_state *viewport = &svga->curr.viewport; 391 struct svga_prescale prescale; 392 SVGA3dRect rect; 393 /* Not sure if this state is relevant with POSITIONT. Probably 394 * not, but setting to 0,1 avoids some state pingponging. 395 */ 396 float range_min = 0.0; 397 float range_max = 1.0; 398 float flip = -1.0; 399 boolean degenerate = FALSE; 400 boolean invertY = FALSE; 401 enum pipe_error ret; 402 403 float fb_width = (float) svga->curr.framebuffer.width; 404 float fb_height = (float) svga->curr.framebuffer.height; 405 406 float fx = viewport->scale[0] * -1.0f + viewport->translate[0]; 407 float fy = flip * viewport->scale[1] * -1.0f + viewport->translate[1]; 408 float fw = viewport->scale[0] * 2.0f; 409 float fh = flip * viewport->scale[1] * 2.0f; 410 boolean emit_vgpu10_viewport = FALSE; 411 412 memset( &prescale, 0, sizeof(prescale) ); 413 414 /* Examine gallium viewport transformation and produce a screen 415 * rectangle and possibly vertex shader pre-transformation to 416 * get the same results. 417 */ 418 419 SVGA_DBG(DEBUG_VIEWPORT, 420 "\ninitial %f,%f %fx%f\n", 421 fx, 422 fy, 423 fw, 424 fh); 425 426 prescale.scale[0] = 1.0; 427 prescale.scale[1] = 1.0; 428 prescale.scale[2] = 1.0; 429 prescale.scale[3] = 1.0; 430 prescale.translate[0] = 0; 431 prescale.translate[1] = 0; 432 prescale.translate[2] = 0; 433 prescale.translate[3] = 0; 434 435 /* Enable prescale to adjust vertex positions to match 436 VGPU10 convention only if rasterization is enabled. 437 */ 438 if (svga->curr.rast && svga->curr.rast->templ.rasterizer_discard) { 439 degenerate = TRUE; 440 goto out; 441 } else { 442 prescale.enabled = TRUE; 443 } 444 445 if (fw < 0) { 446 prescale.scale[0] *= -1.0f; 447 prescale.translate[0] += -fw; 448 fw = -fw; 449 fx = viewport->scale[0] * 1.0f + viewport->translate[0]; 450 } 451 452 if (fh < 0.0) { 453 if (svga_have_vgpu10(svga)) { 454 /* floating point viewport params below */ 455 prescale.translate[1] = fh + fy * 2.0f; 456 } 457 else { 458 /* integer viewport params below */ 459 prescale.translate[1] = fh - 1.0f + fy * 2.0f; 460 } 461 fh = -fh; 462 fy -= fh; 463 prescale.scale[1] = -1.0f; 464 invertY = TRUE; 465 } 466 467 if (fx < 0) { 468 prescale.translate[0] += fx; 469 prescale.scale[0] *= fw / (fw + fx); 470 fw += fx; 471 fx = 0.0f; 472 } 473 474 if (fy < 0) { 475 if (invertY) { 476 prescale.translate[1] -= fy; 477 } 478 else { 479 prescale.translate[1] += fy; 480 } 481 prescale.scale[1] *= fh / (fh + fy); 482 fh += fy; 483 fy = 0.0f; 484 } 485 486 if (fx + fw > fb_width) { 487 prescale.scale[0] *= fw / (fb_width - fx); 488 prescale.translate[0] -= fx * (fw / (fb_width - fx)); 489 prescale.translate[0] += fx; 490 fw = fb_width - fx; 491 } 492 493 if (fy + fh > fb_height) { 494 prescale.scale[1] *= fh / (fb_height - fy); 495 if (invertY) { 496 float in = fb_height - fy; /* number of vp pixels inside view */ 497 float out = fy + fh - fb_height; /* number of vp pixels out of view */ 498 prescale.translate[1] += fy * out / in; 499 } 500 else { 501 prescale.translate[1] -= fy * (fh / (fb_height - fy)); 502 prescale.translate[1] += fy; 503 } 504 fh = fb_height - fy; 505 } 506 507 if (fw < 0 || fh < 0) { 508 fw = fh = fx = fy = 0; 509 degenerate = TRUE; 510 goto out; 511 } 512 513 /* D3D viewport is integer space. Convert fx,fy,etc. to 514 * integers. 515 * 516 * TODO: adjust pretranslate correct for any subpixel error 517 * introduced converting to integers. 518 */ 519 rect.x = (uint32) fx; 520 rect.y = (uint32) fy; 521 rect.w = (uint32) fw; 522 rect.h = (uint32) fh; 523 524 SVGA_DBG(DEBUG_VIEWPORT, 525 "viewport error %f,%f %fx%f\n", 526 fabs((float)rect.x - fx), 527 fabs((float)rect.y - fy), 528 fabs((float)rect.w - fw), 529 fabs((float)rect.h - fh)); 530 531 SVGA_DBG(DEBUG_VIEWPORT, 532 "viewport %d,%d %dx%d\n", 533 rect.x, 534 rect.y, 535 rect.w, 536 rect.h); 537 538 /* Finally, to get GL rasterization rules, need to tweak the 539 * screen-space coordinates slightly relative to D3D which is 540 * what hardware implements natively. 541 */ 542 if (svga->curr.rast && svga->curr.rast->templ.half_pixel_center) { 543 float adjust_x = 0.0; 544 float adjust_y = 0.0; 545 546 if (svga_have_vgpu10(svga)) { 547 /* Normally, we don't have to do any sub-pixel coordinate 548 * adjustments for VGPU10. But when we draw wide points with 549 * a GS we need an X adjustment in order to be conformant. 550 */ 551 if (svga->curr.reduced_prim == PIPE_PRIM_POINTS && 552 svga->curr.rast->pointsize > 1.0f) { 553 adjust_x = 0.5; 554 } 555 } 556 else { 557 /* Use (-0.5, -0.5) bias for all prim types. 558 * Regarding line rasterization, this does not seem to satisfy 559 * the Piglit gl-1.0-ortho-pos test but it generally produces 560 * results identical or very similar to VGPU10. 561 */ 562 adjust_x = -0.5; 563 adjust_y = -0.5; 564 } 565 566 if (invertY) 567 adjust_y = -adjust_y; 568 569 prescale.translate[0] += adjust_x; 570 prescale.translate[1] += adjust_y; 571 prescale.translate[2] = 0.5; /* D3D clip space */ 572 prescale.scale[2] = 0.5; /* D3D clip space */ 573 } 574 575 range_min = viewport->scale[2] * -1.0f + viewport->translate[2]; 576 range_max = viewport->scale[2] * 1.0f + viewport->translate[2]; 577 578 /* D3D (and by implication SVGA) doesn't like dealing with zmax 579 * less than zmin. Detect that case, flip the depth range and 580 * invert our z-scale factor to achieve the same effect. 581 */ 582 if (range_min > range_max) { 583 float range_tmp; 584 range_tmp = range_min; 585 range_min = range_max; 586 range_max = range_tmp; 587 prescale.scale[2] = -prescale.scale[2]; 588 } 589 590 /* If zmin is less than 0, clamp zmin to 0 and adjust the prescale. 591 * zmin can be set to -1 when viewport->scale[2] is set to 1 and 592 * viewport->translate[2] is set to 0 in the blit code. 593 */ 594 if (range_min < 0.0f) { 595 range_min = -0.5f * viewport->scale[2] + 0.5f + viewport->translate[2]; 596 range_max = 0.5f * viewport->scale[2] + 0.5f + viewport->translate[2]; 597 prescale.scale[2] *= 2.0f; 598 prescale.translate[2] -= 0.5f; 599 } 600 601 if (prescale.enabled) { 602 float H[2]; 603 float J[2]; 604 int i; 605 606 SVGA_DBG(DEBUG_VIEWPORT, 607 "prescale %f,%f %fx%f\n", 608 prescale.translate[0], 609 prescale.translate[1], 610 prescale.scale[0], 611 prescale.scale[1]); 612 613 H[0] = (float)rect.w / 2.0f; 614 H[1] = -(float)rect.h / 2.0f; 615 J[0] = (float)rect.x + (float)rect.w / 2.0f; 616 J[1] = (float)rect.y + (float)rect.h / 2.0f; 617 618 SVGA_DBG(DEBUG_VIEWPORT, 619 "H %f,%f\n" 620 "J %fx%f\n", 621 H[0], 622 H[1], 623 J[0], 624 J[1]); 625 626 /* Adjust prescale to take into account the fact that it is 627 * going to be applied prior to the perspective divide and 628 * viewport transformation. 629 * 630 * Vwin = H(Vc/Vc.w) + J 631 * 632 * We want to tweak Vwin with scale and translation from above, 633 * as in: 634 * 635 * Vwin' = S Vwin + T 636 * 637 * But we can only modify the values at Vc. Plugging all the 638 * above together, and rearranging, eventually we get: 639 * 640 * Vwin' = H(Vc'/Vc'.w) + J 641 * where: 642 * Vc' = SVc + KVc.w 643 * K = (T + (S-1)J) / H 644 * 645 * Overwrite prescale.translate with values for K: 646 */ 647 for (i = 0; i < 2; i++) { 648 prescale.translate[i] = ((prescale.translate[i] + 649 (prescale.scale[i] - 1.0f) * J[i]) / H[i]); 650 } 651 652 SVGA_DBG(DEBUG_VIEWPORT, 653 "clipspace %f,%f %fx%f\n", 654 prescale.translate[0], 655 prescale.translate[1], 656 prescale.scale[0], 657 prescale.scale[1]); 658 } 659 660out: 661 if (degenerate) { 662 rect.x = 0; 663 rect.y = 0; 664 rect.w = 1; 665 rect.h = 1; 666 prescale.enabled = FALSE; 667 } 668 669 if (!svga_rects_equal(&rect, &svga->state.hw_clear.viewport)) { 670 if (svga_have_vgpu10(svga)) { 671 emit_vgpu10_viewport = TRUE; 672 } 673 else { 674 ret = SVGA3D_SetViewport(svga->swc, &rect); 675 if (ret != PIPE_OK) 676 return ret; 677 678 svga->state.hw_clear.viewport = rect; 679 } 680 } 681 682 if (svga->state.hw_clear.depthrange.zmin != range_min || 683 svga->state.hw_clear.depthrange.zmax != range_max) 684 { 685 if (svga_have_vgpu10(svga)) { 686 emit_vgpu10_viewport = TRUE; 687 } 688 else { 689 ret = SVGA3D_SetZRange(svga->swc, range_min, range_max ); 690 if (ret != PIPE_OK) 691 return ret; 692 693 svga->state.hw_clear.depthrange.zmin = range_min; 694 svga->state.hw_clear.depthrange.zmax = range_max; 695 } 696 } 697 698 if (emit_vgpu10_viewport) { 699 SVGA3dViewport vp; 700 vp.x = (float) rect.x; 701 vp.y = (float) rect.y; 702 vp.width = (float) rect.w; 703 vp.height = (float) rect.h; 704 vp.minDepth = range_min; 705 vp.maxDepth = range_max; 706 ret = SVGA3D_vgpu10_SetViewports(svga->swc, 1, &vp); 707 if (ret != PIPE_OK) 708 return ret; 709 710 svga->state.hw_clear.viewport = rect; 711 712 svga->state.hw_clear.depthrange.zmin = range_min; 713 svga->state.hw_clear.depthrange.zmax = range_max; 714 } 715 716 if (memcmp(&prescale, &svga->state.hw_clear.prescale, sizeof prescale) != 0) { 717 svga->dirty |= SVGA_NEW_PRESCALE; 718 svga->state.hw_clear.prescale = prescale; 719 } 720 721 return PIPE_OK; 722} 723 724 725struct svga_tracked_state svga_hw_viewport = 726{ 727 "hw viewport state", 728 ( SVGA_NEW_FRAME_BUFFER | 729 SVGA_NEW_VIEWPORT | 730 SVGA_NEW_RAST | 731 SVGA_NEW_REDUCED_PRIMITIVE ), 732 emit_viewport 733}; 734 735 736/*********************************************************************** 737 * Scissor state 738 */ 739static enum pipe_error 740emit_scissor_rect( struct svga_context *svga, 741 unsigned dirty ) 742{ 743 const struct pipe_scissor_state *scissor = &svga->curr.scissor; 744 745 if (svga_have_vgpu10(svga)) { 746 SVGASignedRect rect; 747 748 rect.left = scissor->minx; 749 rect.top = scissor->miny; 750 rect.right = scissor->maxx; 751 rect.bottom = scissor->maxy; 752 753 return SVGA3D_vgpu10_SetScissorRects(svga->swc, 1, &rect); 754 } 755 else { 756 SVGA3dRect rect; 757 758 rect.x = scissor->minx; 759 rect.y = scissor->miny; 760 rect.w = scissor->maxx - scissor->minx; /* + 1 ?? */ 761 rect.h = scissor->maxy - scissor->miny; /* + 1 ?? */ 762 763 return SVGA3D_SetScissorRect(svga->swc, &rect); 764 } 765} 766 767 768struct svga_tracked_state svga_hw_scissor = 769{ 770 "hw scissor state", 771 SVGA_NEW_SCISSOR, 772 emit_scissor_rect 773}; 774 775 776/*********************************************************************** 777 * Userclip state 778 */ 779 780static enum pipe_error 781emit_clip_planes( struct svga_context *svga, 782 unsigned dirty ) 783{ 784 unsigned i; 785 enum pipe_error ret; 786 787 /* TODO: just emit directly from svga_set_clip_state()? 788 */ 789 for (i = 0; i < SVGA3D_MAX_CLIP_PLANES; i++) { 790 /* need to express the plane in D3D-style coordinate space. 791 * GL coords get converted to D3D coords with the matrix: 792 * [ 1 0 0 0 ] 793 * [ 0 -1 0 0 ] 794 * [ 0 0 2 0 ] 795 * [ 0 0 -1 1 ] 796 * Apply that matrix to our plane equation, and invert Y. 797 */ 798 float a = svga->curr.clip.ucp[i][0]; 799 float b = svga->curr.clip.ucp[i][1]; 800 float c = svga->curr.clip.ucp[i][2]; 801 float d = svga->curr.clip.ucp[i][3]; 802 float plane[4]; 803 804 plane[0] = a; 805 plane[1] = b; 806 plane[2] = 2.0f * c; 807 plane[3] = d - c; 808 809 if (svga_have_vgpu10(svga)) { 810 //debug_printf("XXX emit DX10 clip plane\n"); 811 ret = PIPE_OK; 812 } 813 else { 814 ret = SVGA3D_SetClipPlane(svga->swc, i, plane); 815 if (ret != PIPE_OK) 816 return ret; 817 } 818 } 819 820 return PIPE_OK; 821} 822 823 824struct svga_tracked_state svga_hw_clip_planes = 825{ 826 "hw viewport state", 827 SVGA_NEW_CLIP, 828 emit_clip_planes 829}; 830