svga: Fix the index buffer rebind regression
[mesa.git] / src / gallium / drivers / svga / svga_state_framebuffer.c
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
38
39 /*
40 * flush our command buffer after the 8th distinct render target
41 *
42 * This helps improve the surface cache behaviour in the face of the
43 * large number of single-use render targets generated by EXA and the xorg
44 * state tracker. Without this we can reference hundreds of individual
45 * render targets from a command buffer, which leaves little scope for
46 * sharing or reuse of those targets.
47 */
48 #define MAX_RT_PER_BATCH 8
49
50
51
52 static enum pipe_error
53 emit_fb_vgpu9(struct svga_context *svga)
54 {
55 struct svga_screen *svgascreen = svga_screen(svga->pipe.screen);
56 const struct pipe_framebuffer_state *curr = &svga->curr.framebuffer;
57 struct pipe_framebuffer_state *hw = &svga->state.hw_clear.framebuffer;
58 boolean reemit = svga->rebind.flags.rendertargets;
59 unsigned i;
60 enum pipe_error ret;
61
62 assert(!svga_have_vgpu10(svga));
63
64 /*
65 * We need to reemit non-null surface bindings, even when they are not
66 * dirty, to ensure that the resources are paged in.
67 */
68
69 for (i = 0; i < svgascreen->max_color_buffers; i++) {
70 if ((curr->cbufs[i] != hw->cbufs[i]) || (reemit && hw->cbufs[i])) {
71 if (svga->curr.nr_fbs++ > MAX_RT_PER_BATCH)
72 return PIPE_ERROR_OUT_OF_MEMORY;
73
74 ret = SVGA3D_SetRenderTarget(svga->swc, SVGA3D_RT_COLOR0 + i,
75 curr->cbufs[i]);
76 if (ret != PIPE_OK)
77 return ret;
78
79 pipe_surface_reference(&hw->cbufs[i], curr->cbufs[i]);
80 }
81 }
82
83 if ((curr->zsbuf != hw->zsbuf) || (reemit && hw->zsbuf)) {
84 ret = SVGA3D_SetRenderTarget(svga->swc, SVGA3D_RT_DEPTH, curr->zsbuf);
85 if (ret != PIPE_OK)
86 return ret;
87
88 if (curr->zsbuf &&
89 util_format_is_depth_and_stencil(curr->zsbuf->format)) {
90 ret = SVGA3D_SetRenderTarget(svga->swc, SVGA3D_RT_STENCIL,
91 curr->zsbuf);
92 if (ret != PIPE_OK)
93 return ret;
94 }
95 else {
96 ret = SVGA3D_SetRenderTarget(svga->swc, SVGA3D_RT_STENCIL, NULL);
97 if (ret != PIPE_OK)
98 return ret;
99 }
100
101 pipe_surface_reference(&hw->zsbuf, curr->zsbuf);
102 }
103
104 return PIPE_OK;
105 }
106
107
108 /*
109 * Rebind rendertargets.
110 *
111 * Similar to emit_framebuffer, but without any state checking/update.
112 *
113 * Called at the beginning of every new command buffer to ensure that
114 * non-dirty rendertargets are properly paged-in.
115 */
116 static enum pipe_error
117 svga_reemit_framebuffer_bindings_vgpu9(struct svga_context *svga)
118 {
119 struct svga_screen *svgascreen = svga_screen(svga->pipe.screen);
120 struct pipe_framebuffer_state *hw = &svga->state.hw_clear.framebuffer;
121 unsigned i;
122 enum pipe_error ret;
123
124 assert(!svga_have_vgpu10(svga));
125
126 for (i = 0; i < svgascreen->max_color_buffers; i++) {
127 if (hw->cbufs[i]) {
128 ret = SVGA3D_SetRenderTarget(svga->swc, SVGA3D_RT_COLOR0 + i,
129 hw->cbufs[i]);
130 if (ret != PIPE_OK) {
131 return ret;
132 }
133 }
134 }
135
136 if (hw->zsbuf) {
137 ret = SVGA3D_SetRenderTarget(svga->swc, SVGA3D_RT_DEPTH, hw->zsbuf);
138 if (ret != PIPE_OK) {
139 return ret;
140 }
141
142 if (hw->zsbuf &&
143 util_format_is_depth_and_stencil(hw->zsbuf->format)) {
144 ret = SVGA3D_SetRenderTarget(svga->swc, SVGA3D_RT_STENCIL, hw->zsbuf);
145 if (ret != PIPE_OK) {
146 return ret;
147 }
148 }
149 else {
150 ret = SVGA3D_SetRenderTarget(svga->swc, SVGA3D_RT_STENCIL, NULL);
151 if (ret != PIPE_OK) {
152 return ret;
153 }
154 }
155 }
156
157 return PIPE_OK;
158 }
159
160
161
162 static enum pipe_error
163 emit_fb_vgpu10(struct svga_context *svga)
164 {
165 const struct svga_screen *ss = svga_screen(svga->pipe.screen);
166 struct pipe_surface *rtv[SVGA3D_MAX_RENDER_TARGETS];
167 struct pipe_surface *dsv;
168 struct pipe_framebuffer_state *curr = &svga->curr.framebuffer;
169 struct pipe_framebuffer_state *hw = &svga->state.hw_clear.framebuffer;
170 const unsigned num_color = MAX2(curr->nr_cbufs, hw->nr_cbufs);
171 unsigned i;
172 enum pipe_error ret;
173
174 assert(svga_have_vgpu10(svga));
175
176 /* Setup render targets array. Note that we loop over the max of the
177 * number of previously bound buffers and the new buffers to unbind
178 * any previously bound buffers when the new number of buffers is less
179 * than the old number of buffers.
180 */
181 for (i = 0; i < num_color; i++) {
182 if (curr->cbufs[i]) {
183 rtv[i] = svga_validate_surface_view(svga,
184 svga_surface(curr->cbufs[i]));
185 if (rtv[i] == NULL) {
186 return PIPE_ERROR_OUT_OF_MEMORY;
187 }
188
189 assert(svga_surface(rtv[i])->view_id != SVGA3D_INVALID_ID);
190 }
191 else {
192 rtv[i] = NULL;
193 }
194 }
195
196 /* Setup depth stencil view */
197 if (curr->zsbuf) {
198 dsv = svga_validate_surface_view(svga, svga_surface(curr->zsbuf));
199 if (!dsv) {
200 return PIPE_ERROR_OUT_OF_MEMORY;
201 }
202 }
203 else {
204 dsv = NULL;
205 }
206
207 ret = SVGA3D_vgpu10_SetRenderTargets(svga->swc, num_color, rtv, dsv);
208 if (ret != PIPE_OK)
209 return ret;
210
211 for (i = 0; i < ss->max_color_buffers; i++) {
212 if (hw->cbufs[i] != curr->cbufs[i]) {
213 /* propagate the backed view surface before unbinding it */
214 if (hw->cbufs[i] && svga_surface(hw->cbufs[i])->backed) {
215 svga_propagate_surface(svga,
216 &svga_surface(hw->cbufs[i])->backed->base);
217 }
218 pipe_surface_reference(&hw->cbufs[i], curr->cbufs[i]);
219 }
220 }
221 hw->nr_cbufs = curr->nr_cbufs;
222
223 if (hw->zsbuf != curr->zsbuf) {
224 /* propagate the backed view surface before unbinding it */
225 if (hw->zsbuf && svga_surface(hw->zsbuf)->backed) {
226 svga_propagate_surface(svga, &svga_surface(hw->zsbuf)->backed->base);
227 }
228 pipe_surface_reference(&hw->zsbuf, curr->zsbuf);
229 }
230
231 return ret;
232 }
233
234
235 static enum pipe_error
236 emit_framebuffer(struct svga_context *svga, unsigned dirty)
237 {
238 if (svga_have_vgpu10(svga)) {
239 return emit_fb_vgpu10(svga);
240 }
241 else {
242 return emit_fb_vgpu9(svga);
243 }
244 }
245
246
247 /*
248 * Rebind rendertargets.
249 *
250 * Similar to emit_framebuffer, but without any state checking/update.
251 *
252 * Called at the beginning of every new command buffer to ensure that
253 * non-dirty rendertargets are properly paged-in.
254 */
255 enum pipe_error
256 svga_reemit_framebuffer_bindings(struct svga_context *svga)
257 {
258 enum pipe_error ret;
259
260 assert(svga->rebind.flags.rendertargets);
261
262 if (svga_have_vgpu10(svga)) {
263 ret = emit_fb_vgpu10(svga);
264 }
265 else {
266 ret = svga_reemit_framebuffer_bindings_vgpu9(svga);
267 }
268
269 svga->rebind.flags.rendertargets = FALSE;
270
271 return ret;
272 }
273
274
275 /*
276 * Send a private allocation command to page in rendertargets resource.
277 */
278 enum pipe_error
279 svga_rebind_framebuffer_bindings(struct svga_context *svga)
280 {
281 const struct svga_screen *ss = svga_screen(svga->pipe.screen);
282 struct pipe_framebuffer_state *hw = &svga->state.hw_clear.framebuffer;
283 unsigned i;
284 enum pipe_error ret;
285
286 assert(svga_have_vgpu10(svga));
287
288 if (!svga->rebind.flags.rendertargets)
289 return PIPE_OK;
290
291 for (i = 0; i < ss->max_color_buffers; i++) {
292 if (hw->cbufs[i]) {
293 ret = svga->swc->resource_rebind(svga->swc,
294 svga_surface(hw->cbufs[i])->handle,
295 NULL,
296 SVGA_RELOC_WRITE);
297 if (ret != PIPE_OK)
298 return ret;
299 }
300 }
301
302 if (hw->zsbuf) {
303 ret = svga->swc->resource_rebind(svga->swc,
304 svga_surface(hw->zsbuf)->handle,
305 NULL,
306 SVGA_RELOC_WRITE);
307 if (ret != PIPE_OK)
308 return ret;
309 }
310
311 svga->rebind.flags.rendertargets = 0;
312
313 return PIPE_OK;
314 }
315
316
317 struct svga_tracked_state svga_hw_framebuffer =
318 {
319 "hw framebuffer state",
320 SVGA_NEW_FRAME_BUFFER,
321 emit_framebuffer
322 };
323
324
325
326
327 /***********************************************************************
328 */
329
330 static enum pipe_error
331 emit_viewport( struct svga_context *svga,
332 unsigned dirty )
333 {
334 const struct pipe_viewport_state *viewport = &svga->curr.viewport;
335 struct svga_prescale prescale;
336 SVGA3dRect rect;
337 /* Not sure if this state is relevant with POSITIONT. Probably
338 * not, but setting to 0,1 avoids some state pingponging.
339 */
340 float range_min = 0.0;
341 float range_max = 1.0;
342 float flip = -1.0;
343 boolean degenerate = FALSE;
344 boolean invertY = FALSE;
345 enum pipe_error ret;
346
347 float fb_width = (float) svga->curr.framebuffer.width;
348 float fb_height = (float) svga->curr.framebuffer.height;
349
350 float fx = viewport->scale[0] * -1.0f + viewport->translate[0];
351 float fy = flip * viewport->scale[1] * -1.0f + viewport->translate[1];
352 float fw = viewport->scale[0] * 2.0f;
353 float fh = flip * viewport->scale[1] * 2.0f;
354 boolean emit_vgpu10_viewport = FALSE;
355
356 memset( &prescale, 0, sizeof(prescale) );
357
358 /* Examine gallium viewport transformation and produce a screen
359 * rectangle and possibly vertex shader pre-transformation to
360 * get the same results.
361 */
362
363 SVGA_DBG(DEBUG_VIEWPORT,
364 "\ninitial %f,%f %fx%f\n",
365 fx,
366 fy,
367 fw,
368 fh);
369
370 prescale.scale[0] = 1.0;
371 prescale.scale[1] = 1.0;
372 prescale.scale[2] = 1.0;
373 prescale.scale[3] = 1.0;
374 prescale.translate[0] = 0;
375 prescale.translate[1] = 0;
376 prescale.translate[2] = 0;
377 prescale.translate[3] = 0;
378
379 /* Enable prescale to adjust vertex positions to match
380 VGPU10 convention only if rasterization is enabled.
381 */
382 if (svga->curr.rast->templ.rasterizer_discard) {
383 degenerate = TRUE;
384 goto out;
385 } else {
386 prescale.enabled = TRUE;
387 }
388
389 if (fw < 0) {
390 prescale.scale[0] *= -1.0f;
391 prescale.translate[0] += -fw;
392 fw = -fw;
393 fx = viewport->scale[0] * 1.0f + viewport->translate[0];
394 }
395
396 if (fh < 0.0) {
397 if (svga_have_vgpu10(svga)) {
398 /* floating point viewport params below */
399 prescale.translate[1] = fh + fy * 2.0f;
400 }
401 else {
402 /* integer viewport params below */
403 prescale.translate[1] = fh - 1.0f + fy * 2.0f;
404 }
405 fh = -fh;
406 fy -= fh;
407 prescale.scale[1] = -1.0f;
408 invertY = TRUE;
409 }
410
411 if (fx < 0) {
412 prescale.translate[0] += fx;
413 prescale.scale[0] *= fw / (fw + fx);
414 fw += fx;
415 fx = 0.0f;
416 }
417
418 if (fy < 0) {
419 if (invertY) {
420 prescale.translate[1] -= fy;
421 }
422 else {
423 prescale.translate[1] += fy;
424 }
425 prescale.scale[1] *= fh / (fh + fy);
426 fh += fy;
427 fy = 0.0f;
428 }
429
430 if (fx + fw > fb_width) {
431 prescale.scale[0] *= fw / (fb_width - fx);
432 prescale.translate[0] -= fx * (fw / (fb_width - fx));
433 prescale.translate[0] += fx;
434 fw = fb_width - fx;
435 }
436
437 if (fy + fh > fb_height) {
438 prescale.scale[1] *= fh / (fb_height - fy);
439 if (invertY) {
440 float in = fb_height - fy; /* number of vp pixels inside view */
441 float out = fy + fh - fb_height; /* number of vp pixels out of view */
442 prescale.translate[1] += fy * out / in;
443 }
444 else {
445 prescale.translate[1] -= fy * (fh / (fb_height - fy));
446 prescale.translate[1] += fy;
447 }
448 fh = fb_height - fy;
449 }
450
451 if (fw < 0 || fh < 0) {
452 fw = fh = fx = fy = 0;
453 degenerate = TRUE;
454 goto out;
455 }
456
457 /* D3D viewport is integer space. Convert fx,fy,etc. to
458 * integers.
459 *
460 * TODO: adjust pretranslate correct for any subpixel error
461 * introduced converting to integers.
462 */
463 rect.x = (uint32) fx;
464 rect.y = (uint32) fy;
465 rect.w = (uint32) fw;
466 rect.h = (uint32) fh;
467
468 SVGA_DBG(DEBUG_VIEWPORT,
469 "viewport error %f,%f %fx%f\n",
470 fabs((float)rect.x - fx),
471 fabs((float)rect.y - fy),
472 fabs((float)rect.w - fw),
473 fabs((float)rect.h - fh));
474
475 SVGA_DBG(DEBUG_VIEWPORT,
476 "viewport %d,%d %dx%d\n",
477 rect.x,
478 rect.y,
479 rect.w,
480 rect.h);
481
482 /* Finally, to get GL rasterization rules, need to tweak the
483 * screen-space coordinates slightly relative to D3D which is
484 * what hardware implements natively.
485 */
486 if (svga->curr.rast->templ.half_pixel_center) {
487 float adjust_x = 0.0;
488 float adjust_y = 0.0;
489
490 if (svga_have_vgpu10(svga)) {
491 /* Normally, we don't have to do any sub-pixel coordinate
492 * adjustments for VGPU10. But when we draw wide points with
493 * a GS we need an X adjustment in order to be conformant.
494 */
495 if (svga->curr.reduced_prim == PIPE_PRIM_POINTS &&
496 svga->curr.rast->pointsize > 1.0f) {
497 adjust_x = 0.5;
498 }
499 }
500 else {
501 switch (svga->curr.reduced_prim) {
502 case PIPE_PRIM_POINTS:
503 adjust_x = -0.375;
504 adjust_y = -0.75;
505 break;
506 case PIPE_PRIM_LINES:
507 adjust_x = -0.5;
508 adjust_y = 0;
509 break;
510 case PIPE_PRIM_TRIANGLES:
511 adjust_x = -0.5;
512 adjust_y = -0.5;
513 break;
514 }
515 }
516
517 if (invertY)
518 adjust_y = -adjust_y;
519
520 prescale.translate[0] += adjust_x;
521 prescale.translate[1] += adjust_y;
522 prescale.translate[2] = 0.5; /* D3D clip space */
523 prescale.scale[2] = 0.5; /* D3D clip space */
524 }
525
526 range_min = viewport->scale[2] * -1.0f + viewport->translate[2];
527 range_max = viewport->scale[2] * 1.0f + viewport->translate[2];
528
529 /* D3D (and by implication SVGA) doesn't like dealing with zmax
530 * less than zmin. Detect that case, flip the depth range and
531 * invert our z-scale factor to achieve the same effect.
532 */
533 if (range_min > range_max) {
534 float range_tmp;
535 range_tmp = range_min;
536 range_min = range_max;
537 range_max = range_tmp;
538 prescale.scale[2] = -prescale.scale[2];
539 }
540
541 /* If zmin is less than 0, clamp zmin to 0 and adjust the prescale.
542 * zmin can be set to -1 when viewport->scale[2] is set to 1 and
543 * viewport->translate[2] is set to 0 in the blit code.
544 */
545 if (range_min < 0.0f) {
546 range_min = -0.5f * viewport->scale[2] + 0.5f + viewport->translate[2];
547 range_max = 0.5f * viewport->scale[2] + 0.5f + viewport->translate[2];
548 prescale.scale[2] *= 2.0f;
549 prescale.translate[2] -= 0.5f;
550 }
551
552 if (prescale.enabled) {
553 float H[2];
554 float J[2];
555 int i;
556
557 SVGA_DBG(DEBUG_VIEWPORT,
558 "prescale %f,%f %fx%f\n",
559 prescale.translate[0],
560 prescale.translate[1],
561 prescale.scale[0],
562 prescale.scale[1]);
563
564 H[0] = (float)rect.w / 2.0f;
565 H[1] = -(float)rect.h / 2.0f;
566 J[0] = (float)rect.x + (float)rect.w / 2.0f;
567 J[1] = (float)rect.y + (float)rect.h / 2.0f;
568
569 SVGA_DBG(DEBUG_VIEWPORT,
570 "H %f,%f\n"
571 "J %fx%f\n",
572 H[0],
573 H[1],
574 J[0],
575 J[1]);
576
577 /* Adjust prescale to take into account the fact that it is
578 * going to be applied prior to the perspective divide and
579 * viewport transformation.
580 *
581 * Vwin = H(Vc/Vc.w) + J
582 *
583 * We want to tweak Vwin with scale and translation from above,
584 * as in:
585 *
586 * Vwin' = S Vwin + T
587 *
588 * But we can only modify the values at Vc. Plugging all the
589 * above together, and rearranging, eventually we get:
590 *
591 * Vwin' = H(Vc'/Vc'.w) + J
592 * where:
593 * Vc' = SVc + KVc.w
594 * K = (T + (S-1)J) / H
595 *
596 * Overwrite prescale.translate with values for K:
597 */
598 for (i = 0; i < 2; i++) {
599 prescale.translate[i] = ((prescale.translate[i] +
600 (prescale.scale[i] - 1.0f) * J[i]) / H[i]);
601 }
602
603 SVGA_DBG(DEBUG_VIEWPORT,
604 "clipspace %f,%f %fx%f\n",
605 prescale.translate[0],
606 prescale.translate[1],
607 prescale.scale[0],
608 prescale.scale[1]);
609 }
610
611 out:
612 if (degenerate) {
613 rect.x = 0;
614 rect.y = 0;
615 rect.w = 1;
616 rect.h = 1;
617 prescale.enabled = FALSE;
618 }
619
620 if (!svga_rects_equal(&rect, &svga->state.hw_clear.viewport)) {
621 if (svga_have_vgpu10(svga)) {
622 emit_vgpu10_viewport = TRUE;
623 }
624 else {
625 ret = SVGA3D_SetViewport(svga->swc, &rect);
626 if (ret != PIPE_OK)
627 return ret;
628
629 svga->state.hw_clear.viewport = rect;
630 }
631 }
632
633 if (svga->state.hw_clear.depthrange.zmin != range_min ||
634 svga->state.hw_clear.depthrange.zmax != range_max)
635 {
636 if (svga_have_vgpu10(svga)) {
637 emit_vgpu10_viewport = TRUE;
638 }
639 else {
640 ret = SVGA3D_SetZRange(svga->swc, range_min, range_max );
641 if (ret != PIPE_OK)
642 return ret;
643
644 svga->state.hw_clear.depthrange.zmin = range_min;
645 svga->state.hw_clear.depthrange.zmax = range_max;
646 }
647 }
648
649 if (emit_vgpu10_viewport) {
650 SVGA3dViewport vp;
651 vp.x = (float) rect.x;
652 vp.y = (float) rect.y;
653 vp.width = (float) rect.w;
654 vp.height = (float) rect.h;
655 vp.minDepth = range_min;
656 vp.maxDepth = range_max;
657 ret = SVGA3D_vgpu10_SetViewports(svga->swc, 1, &vp);
658 if (ret != PIPE_OK)
659 return ret;
660
661 svga->state.hw_clear.viewport = rect;
662
663 svga->state.hw_clear.depthrange.zmin = range_min;
664 svga->state.hw_clear.depthrange.zmax = range_max;
665 }
666
667 if (memcmp(&prescale, &svga->state.hw_clear.prescale, sizeof prescale) != 0) {
668 svga->dirty |= SVGA_NEW_PRESCALE;
669 svga->state.hw_clear.prescale = prescale;
670 }
671
672 return PIPE_OK;
673 }
674
675
676 struct svga_tracked_state svga_hw_viewport =
677 {
678 "hw viewport state",
679 ( SVGA_NEW_FRAME_BUFFER |
680 SVGA_NEW_VIEWPORT |
681 SVGA_NEW_RAST |
682 SVGA_NEW_REDUCED_PRIMITIVE ),
683 emit_viewport
684 };
685
686
687 /***********************************************************************
688 * Scissor state
689 */
690 static enum pipe_error
691 emit_scissor_rect( struct svga_context *svga,
692 unsigned dirty )
693 {
694 const struct pipe_scissor_state *scissor = &svga->curr.scissor;
695
696 if (svga_have_vgpu10(svga)) {
697 SVGASignedRect rect;
698
699 rect.left = scissor->minx;
700 rect.top = scissor->miny;
701 rect.right = scissor->maxx;
702 rect.bottom = scissor->maxy;
703
704 return SVGA3D_vgpu10_SetScissorRects(svga->swc, 1, &rect);
705 }
706 else {
707 SVGA3dRect rect;
708
709 rect.x = scissor->minx;
710 rect.y = scissor->miny;
711 rect.w = scissor->maxx - scissor->minx; /* + 1 ?? */
712 rect.h = scissor->maxy - scissor->miny; /* + 1 ?? */
713
714 return SVGA3D_SetScissorRect(svga->swc, &rect);
715 }
716 }
717
718
719 struct svga_tracked_state svga_hw_scissor =
720 {
721 "hw scissor state",
722 SVGA_NEW_SCISSOR,
723 emit_scissor_rect
724 };
725
726
727 /***********************************************************************
728 * Userclip state
729 */
730
731 static enum pipe_error
732 emit_clip_planes( struct svga_context *svga,
733 unsigned dirty )
734 {
735 unsigned i;
736 enum pipe_error ret;
737
738 /* TODO: just emit directly from svga_set_clip_state()?
739 */
740 for (i = 0; i < SVGA3D_MAX_CLIP_PLANES; i++) {
741 /* need to express the plane in D3D-style coordinate space.
742 * GL coords get converted to D3D coords with the matrix:
743 * [ 1 0 0 0 ]
744 * [ 0 -1 0 0 ]
745 * [ 0 0 2 0 ]
746 * [ 0 0 -1 1 ]
747 * Apply that matrix to our plane equation, and invert Y.
748 */
749 float a = svga->curr.clip.ucp[i][0];
750 float b = svga->curr.clip.ucp[i][1];
751 float c = svga->curr.clip.ucp[i][2];
752 float d = svga->curr.clip.ucp[i][3];
753 float plane[4];
754
755 plane[0] = a;
756 plane[1] = b;
757 plane[2] = 2.0f * c;
758 plane[3] = d - c;
759
760 if (svga_have_vgpu10(svga)) {
761 //debug_printf("XXX emit DX10 clip plane\n");
762 ret = PIPE_OK;
763 }
764 else {
765 ret = SVGA3D_SetClipPlane(svga->swc, i, plane);
766 if (ret != PIPE_OK)
767 return ret;
768 }
769 }
770
771 return PIPE_OK;
772 }
773
774
775 struct svga_tracked_state svga_hw_clip_planes =
776 {
777 "hw viewport state",
778 SVGA_NEW_CLIP,
779 emit_clip_planes
780 };