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
emit_fb_vgpu9(struct svga_context * svga)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
svga_reemit_framebuffer_bindings_vgpu9(struct svga_context * svga)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
emit_fb_vgpu10(struct svga_context * svga)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
emit_framebuffer(struct svga_context * svga,unsigned dirty)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
svga_reemit_framebuffer_bindings(struct svga_context * svga)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
svga_rebind_framebuffer_bindings(struct svga_context * svga)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
emit_viewport(struct svga_context * svga,unsigned dirty)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 /* 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
660 out:
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
725 struct 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 */
739 static enum pipe_error
emit_scissor_rect(struct svga_context * svga,unsigned dirty)740 emit_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
768 struct 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
780 static enum pipe_error
emit_clip_planes(struct svga_context * svga,unsigned dirty)781 emit_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
824 struct svga_tracked_state svga_hw_clip_planes =
825 {
826 "hw viewport state",
827 SVGA_NEW_CLIP,
828 emit_clip_planes
829 };
830