Introduce .editorconfig
[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->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->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 }
529 }
530
531 if (invertY)
532 adjust_y = -adjust_y;
533
534 prescale.translate[0] += adjust_x;
535 prescale.translate[1] += adjust_y;
536 prescale.translate[2] = 0.5; /* D3D clip space */
537 prescale.scale[2] = 0.5; /* D3D clip space */
538 }
539
540 range_min = viewport->scale[2] * -1.0f + viewport->translate[2];
541 range_max = viewport->scale[2] * 1.0f + viewport->translate[2];
542
543 /* D3D (and by implication SVGA) doesn't like dealing with zmax
544 * less than zmin. Detect that case, flip the depth range and
545 * invert our z-scale factor to achieve the same effect.
546 */
547 if (range_min > range_max) {
548 float range_tmp;
549 range_tmp = range_min;
550 range_min = range_max;
551 range_max = range_tmp;
552 prescale.scale[2] = -prescale.scale[2];
553 }
554
555 /* If zmin is less than 0, clamp zmin to 0 and adjust the prescale.
556 * zmin can be set to -1 when viewport->scale[2] is set to 1 and
557 * viewport->translate[2] is set to 0 in the blit code.
558 */
559 if (range_min < 0.0f) {
560 range_min = -0.5f * viewport->scale[2] + 0.5f + viewport->translate[2];
561 range_max = 0.5f * viewport->scale[2] + 0.5f + viewport->translate[2];
562 prescale.scale[2] *= 2.0f;
563 prescale.translate[2] -= 0.5f;
564 }
565
566 if (prescale.enabled) {
567 float H[2];
568 float J[2];
569 int i;
570
571 SVGA_DBG(DEBUG_VIEWPORT,
572 "prescale %f,%f %fx%f\n",
573 prescale.translate[0],
574 prescale.translate[1],
575 prescale.scale[0],
576 prescale.scale[1]);
577
578 H[0] = (float)rect.w / 2.0f;
579 H[1] = -(float)rect.h / 2.0f;
580 J[0] = (float)rect.x + (float)rect.w / 2.0f;
581 J[1] = (float)rect.y + (float)rect.h / 2.0f;
582
583 SVGA_DBG(DEBUG_VIEWPORT,
584 "H %f,%f\n"
585 "J %fx%f\n",
586 H[0],
587 H[1],
588 J[0],
589 J[1]);
590
591 /* Adjust prescale to take into account the fact that it is
592 * going to be applied prior to the perspective divide and
593 * viewport transformation.
594 *
595 * Vwin = H(Vc/Vc.w) + J
596 *
597 * We want to tweak Vwin with scale and translation from above,
598 * as in:
599 *
600 * Vwin' = S Vwin + T
601 *
602 * But we can only modify the values at Vc. Plugging all the
603 * above together, and rearranging, eventually we get:
604 *
605 * Vwin' = H(Vc'/Vc'.w) + J
606 * where:
607 * Vc' = SVc + KVc.w
608 * K = (T + (S-1)J) / H
609 *
610 * Overwrite prescale.translate with values for K:
611 */
612 for (i = 0; i < 2; i++) {
613 prescale.translate[i] = ((prescale.translate[i] +
614 (prescale.scale[i] - 1.0f) * J[i]) / H[i]);
615 }
616
617 SVGA_DBG(DEBUG_VIEWPORT,
618 "clipspace %f,%f %fx%f\n",
619 prescale.translate[0],
620 prescale.translate[1],
621 prescale.scale[0],
622 prescale.scale[1]);
623 }
624
625 out:
626 if (degenerate) {
627 rect.x = 0;
628 rect.y = 0;
629 rect.w = 1;
630 rect.h = 1;
631 prescale.enabled = FALSE;
632 }
633
634 if (!svga_rects_equal(&rect, &svga->state.hw_clear.viewport)) {
635 if (svga_have_vgpu10(svga)) {
636 emit_vgpu10_viewport = TRUE;
637 }
638 else {
639 ret = SVGA3D_SetViewport(svga->swc, &rect);
640 if (ret != PIPE_OK)
641 return ret;
642
643 svga->state.hw_clear.viewport = rect;
644 }
645 }
646
647 if (svga->state.hw_clear.depthrange.zmin != range_min ||
648 svga->state.hw_clear.depthrange.zmax != range_max)
649 {
650 if (svga_have_vgpu10(svga)) {
651 emit_vgpu10_viewport = TRUE;
652 }
653 else {
654 ret = SVGA3D_SetZRange(svga->swc, range_min, range_max );
655 if (ret != PIPE_OK)
656 return ret;
657
658 svga->state.hw_clear.depthrange.zmin = range_min;
659 svga->state.hw_clear.depthrange.zmax = range_max;
660 }
661 }
662
663 if (emit_vgpu10_viewport) {
664 SVGA3dViewport vp;
665 vp.x = (float) rect.x;
666 vp.y = (float) rect.y;
667 vp.width = (float) rect.w;
668 vp.height = (float) rect.h;
669 vp.minDepth = range_min;
670 vp.maxDepth = range_max;
671 ret = SVGA3D_vgpu10_SetViewports(svga->swc, 1, &vp);
672 if (ret != PIPE_OK)
673 return ret;
674
675 svga->state.hw_clear.viewport = rect;
676
677 svga->state.hw_clear.depthrange.zmin = range_min;
678 svga->state.hw_clear.depthrange.zmax = range_max;
679 }
680
681 if (memcmp(&prescale, &svga->state.hw_clear.prescale, sizeof prescale) != 0) {
682 svga->dirty |= SVGA_NEW_PRESCALE;
683 svga->state.hw_clear.prescale = prescale;
684 }
685
686 return PIPE_OK;
687 }
688
689
690 struct svga_tracked_state svga_hw_viewport =
691 {
692 "hw viewport state",
693 ( SVGA_NEW_FRAME_BUFFER |
694 SVGA_NEW_VIEWPORT |
695 SVGA_NEW_RAST |
696 SVGA_NEW_REDUCED_PRIMITIVE ),
697 emit_viewport
698 };
699
700
701 /***********************************************************************
702 * Scissor state
703 */
704 static enum pipe_error
705 emit_scissor_rect( struct svga_context *svga,
706 unsigned dirty )
707 {
708 const struct pipe_scissor_state *scissor = &svga->curr.scissor;
709
710 if (svga_have_vgpu10(svga)) {
711 SVGASignedRect rect;
712
713 rect.left = scissor->minx;
714 rect.top = scissor->miny;
715 rect.right = scissor->maxx;
716 rect.bottom = scissor->maxy;
717
718 return SVGA3D_vgpu10_SetScissorRects(svga->swc, 1, &rect);
719 }
720 else {
721 SVGA3dRect rect;
722
723 rect.x = scissor->minx;
724 rect.y = scissor->miny;
725 rect.w = scissor->maxx - scissor->minx; /* + 1 ?? */
726 rect.h = scissor->maxy - scissor->miny; /* + 1 ?? */
727
728 return SVGA3D_SetScissorRect(svga->swc, &rect);
729 }
730 }
731
732
733 struct svga_tracked_state svga_hw_scissor =
734 {
735 "hw scissor state",
736 SVGA_NEW_SCISSOR,
737 emit_scissor_rect
738 };
739
740
741 /***********************************************************************
742 * Userclip state
743 */
744
745 static enum pipe_error
746 emit_clip_planes( struct svga_context *svga,
747 unsigned dirty )
748 {
749 unsigned i;
750 enum pipe_error ret;
751
752 /* TODO: just emit directly from svga_set_clip_state()?
753 */
754 for (i = 0; i < SVGA3D_MAX_CLIP_PLANES; i++) {
755 /* need to express the plane in D3D-style coordinate space.
756 * GL coords get converted to D3D coords with the matrix:
757 * [ 1 0 0 0 ]
758 * [ 0 -1 0 0 ]
759 * [ 0 0 2 0 ]
760 * [ 0 0 -1 1 ]
761 * Apply that matrix to our plane equation, and invert Y.
762 */
763 float a = svga->curr.clip.ucp[i][0];
764 float b = svga->curr.clip.ucp[i][1];
765 float c = svga->curr.clip.ucp[i][2];
766 float d = svga->curr.clip.ucp[i][3];
767 float plane[4];
768
769 plane[0] = a;
770 plane[1] = b;
771 plane[2] = 2.0f * c;
772 plane[3] = d - c;
773
774 if (svga_have_vgpu10(svga)) {
775 //debug_printf("XXX emit DX10 clip plane\n");
776 ret = PIPE_OK;
777 }
778 else {
779 ret = SVGA3D_SetClipPlane(svga->swc, i, plane);
780 if (ret != PIPE_OK)
781 return ret;
782 }
783 }
784
785 return PIPE_OK;
786 }
787
788
789 struct svga_tracked_state svga_hw_clip_planes =
790 {
791 "hw viewport state",
792 SVGA_NEW_CLIP,
793 emit_clip_planes
794 };