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