• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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