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