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
53static enum pipe_error
54emit_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 */
139static enum pipe_error
140svga_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
185static enum pipe_error
186emit_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
292static enum pipe_error
293emit_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 */
312enum pipe_error
313svga_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 */
335enum pipe_error
336svga_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
373struct 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
386static enum pipe_error
387emit_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
660out:
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
725struct 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 */
739static enum pipe_error
740emit_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
768struct 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
780static enum pipe_error
781emit_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
824struct svga_tracked_state svga_hw_clip_planes =
825{
826   "hw viewport state",
827   SVGA_NEW_CLIP,
828   emit_clip_planes
829};
830