• 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 
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
emit_fb_vgpu9(struct svga_context * svga)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
svga_reemit_framebuffer_bindings_vgpu9(struct svga_context * svga)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
emit_fb_vgpu10(struct svga_context * svga)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
emit_framebuffer(struct svga_context * svga,unsigned dirty)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
svga_reemit_framebuffer_bindings(struct svga_context * svga)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
svga_rebind_framebuffer_bindings(struct svga_context * svga)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
emit_viewport(struct svga_context * svga,unsigned dirty)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
emit_scissor_rect(struct svga_context * svga,unsigned dirty)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
emit_clip_planes(struct svga_context * svga,unsigned dirty)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 };
795