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/format/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         if (curr->cbufs[i] != hw->cbufs[i]) {
216            rtv[i] = svga_validate_surface_view(svga, svga_surface(s));
217            if (rtv[i] == NULL) {
218               return PIPE_ERROR_OUT_OF_MEMORY;
219            }
220         } else {
221           rtv[i] = svga->state.hw_clear.rtv[i];
222         }
223
224         assert(svga_surface(rtv[i])->view_id != SVGA3D_INVALID_ID);
225         last_rtv = i;
226
227         /* Set the rendered-to flag */
228         svga_set_texture_rendered_to(svga_texture(s->texture),
229                                      s->u.tex.first_layer, s->u.tex.level);
230      }
231      else {
232         rtv[i] = NULL;
233      }
234   }
235
236   /* Setup depth stencil view */
237   if (curr->zsbuf) {
238      struct pipe_surface *s = curr->zsbuf;
239
240      if (curr->zsbuf != hw->zsbuf) {
241         dsv = svga_validate_surface_view(svga, svga_surface(curr->zsbuf));
242         if (!dsv) {
243            return PIPE_ERROR_OUT_OF_MEMORY;
244         }
245      } else {
246         dsv = svga->state.hw_clear.dsv;
247      }
248
249      /* Set the rendered-to flag */
250      svga_set_texture_rendered_to(svga_texture(s->texture),
251                                      s->u.tex.first_layer, s->u.tex.level);
252   }
253   else {
254      dsv = NULL;
255   }
256
257   /* avoid emitting redundant SetRenderTargets command */
258   if ((num_color != svga->state.hw_clear.num_rendertargets) ||
259       (dsv != svga->state.hw_clear.dsv) ||
260       memcmp(rtv, svga->state.hw_clear.rtv, num_color * sizeof(rtv[0]))) {
261
262      ret = SVGA3D_vgpu10_SetRenderTargets(svga->swc, num_color, rtv, dsv);
263      if (ret != PIPE_OK)
264         return ret;
265
266      /* number of render targets sent to the device, not including trailing
267       * unbound render targets.
268       */
269      for (i = 0; i < ss->max_color_buffers; i++) {
270         if (hw->cbufs[i] != curr->cbufs[i]) {
271            /* propagate the backed view surface before unbinding it */
272            if (hw->cbufs[i] && svga_surface(hw->cbufs[i])->backed) {
273               svga_propagate_surface(svga,
274                                      &svga_surface(hw->cbufs[i])->backed->base,
275                                      TRUE);
276            }
277            else if (svga->state.hw_clear.rtv[i] != hw->cbufs[i] &&
278                     svga->state.hw_clear.rtv[i]) {
279               /* Free the alternate surface view when it is unbound.  */
280               svga->pipe.surface_destroy(&svga->pipe, svga->state.hw_clear.rtv[i]);
281            }
282            pipe_surface_reference(&hw->cbufs[i], curr->cbufs[i]);
283         }
284      }
285      svga->state.hw_clear.num_rendertargets = last_rtv + 1;
286      memcpy(svga->state.hw_clear.rtv, rtv, num_color * sizeof(rtv[0]));
287      hw->nr_cbufs = curr->nr_cbufs;
288
289      if (hw->zsbuf != curr->zsbuf) {
290         /* propagate the backed view surface before unbinding it */
291         if (hw->zsbuf && svga_surface(hw->zsbuf)->backed) {
292            svga_propagate_surface(svga,
293                                   &svga_surface(hw->zsbuf)->backed->base,
294                                   TRUE);
295         }
296         else if (svga->state.hw_clear.dsv != hw->zsbuf && svga->state.hw_clear.dsv) {
297            /* Free the alternate surface view when it is unbound.  */
298            svga->pipe.surface_destroy(&svga->pipe, svga->state.hw_clear.dsv);
299         }
300         pipe_surface_reference(&hw->zsbuf, curr->zsbuf);
301      }
302      svga->state.hw_clear.dsv = dsv;
303   }
304
305   return ret;
306}
307
308
309static enum pipe_error
310emit_framebuffer(struct svga_context *svga, uint64_t dirty)
311{
312   if (svga_have_vgpu10(svga)) {
313      return emit_fb_vgpu10(svga);
314   }
315   else {
316      return emit_fb_vgpu9(svga);
317   }
318}
319
320
321/*
322 * Rebind rendertargets.
323 *
324 * Similar to emit_framebuffer, but without any state checking/update.
325 *
326 * Called at the beginning of every new command buffer to ensure that
327 * non-dirty rendertargets are properly paged-in.
328 */
329enum pipe_error
330svga_reemit_framebuffer_bindings(struct svga_context *svga)
331{
332   enum pipe_error ret;
333
334   assert(svga->rebind.flags.rendertargets);
335
336   if (svga_have_vgpu10(svga)) {
337      ret = emit_fb_vgpu10(svga);
338   }
339   else {
340      ret = svga_reemit_framebuffer_bindings_vgpu9(svga);
341   }
342
343   svga->rebind.flags.rendertargets = FALSE;
344
345   return ret;
346}
347
348
349/*
350 * Send a private allocation command to page in rendertargets resource.
351 */
352enum pipe_error
353svga_rebind_framebuffer_bindings(struct svga_context *svga)
354{
355   struct svga_hw_clear_state *hw = &svga->state.hw_clear;
356   unsigned i;
357   enum pipe_error ret;
358
359   assert(svga_have_vgpu10(svga));
360
361   if (!svga->rebind.flags.rendertargets)
362      return PIPE_OK;
363
364   for (i = 0; i < hw->num_rendertargets; i++) {
365      if (hw->rtv[i]) {
366         ret = svga->swc->resource_rebind(svga->swc,
367                                          svga_surface(hw->rtv[i])->handle,
368                                          NULL,
369                                          SVGA_RELOC_WRITE);
370         if (ret != PIPE_OK)
371            return ret;
372      }
373   }
374
375   if (hw->dsv) {
376      ret = svga->swc->resource_rebind(svga->swc,
377                                       svga_surface(hw->dsv)->handle,
378                                       NULL,
379                                       SVGA_RELOC_WRITE);
380      if (ret != PIPE_OK)
381         return ret;
382   }
383
384   svga->rebind.flags.rendertargets = 0;
385
386   return PIPE_OK;
387}
388
389
390struct svga_tracked_state svga_hw_framebuffer =
391{
392   "hw framebuffer state",
393   SVGA_NEW_FRAME_BUFFER,
394   emit_framebuffer
395};
396
397
398
399
400/***********************************************************************
401 */
402
403static void
404get_viewport_prescale(struct svga_context *svga,
405                      struct pipe_viewport_state *viewport,
406                      SVGA3dViewport *vp,
407                      struct svga_prescale *prescale)
408{
409   SVGA3dRect rect;
410
411   /* Not sure if this state is relevant with POSITIONT.  Probably
412    * not, but setting to 0,1 avoids some state pingponging.
413    */
414   float range_min = 0.0;
415   float range_max = 1.0;
416   float flip = -1.0;
417   boolean degenerate = FALSE;
418   boolean invertY = FALSE;
419
420   float fb_width = (float) svga->curr.framebuffer.width;
421   float fb_height = (float) svga->curr.framebuffer.height;
422
423   float fx =        viewport->scale[0] * -1.0f + viewport->translate[0];
424   float fy = flip * viewport->scale[1] * -1.0f + viewport->translate[1];
425   float fw =        viewport->scale[0] * 2.0f;
426   float fh = flip * viewport->scale[1] * 2.0f;
427
428   memset(prescale, 0, sizeof(*prescale));
429
430   /* Examine gallium viewport transformation and produce a screen
431    * rectangle and possibly vertex shader pre-transformation to
432    * get the same results.
433    */
434
435   SVGA_DBG(DEBUG_VIEWPORT,
436            "\ninitial %f,%f %fx%f\n",
437            fx,
438            fy,
439            fw,
440            fh);
441
442   prescale->scale[0] = 1.0;
443   prescale->scale[1] = 1.0;
444   prescale->scale[2] = 1.0;
445   prescale->scale[3] = 1.0;
446   prescale->translate[0] = 0;
447   prescale->translate[1] = 0;
448   prescale->translate[2] = 0;
449   prescale->translate[3] = 0;
450
451   /* Enable prescale to adjust vertex positions to match
452      VGPU10 convention only if rasterization is enabled.
453    */
454   if (svga->curr.rast && svga->curr.rast->templ.rasterizer_discard) {
455      degenerate = TRUE;
456      goto out;
457   } else {
458      prescale->enabled = TRUE;
459   }
460
461   if (fw < 0) {
462      prescale->scale[0] *= -1.0f;
463      prescale->translate[0] += -fw;
464      fw = -fw;
465      fx = viewport->scale[0] * 1.0f + viewport->translate[0];
466   }
467
468   if (fh < 0.0) {
469      if (svga_have_vgpu10(svga)) {
470         /* floating point viewport params below */
471         prescale->translate[1] = fh + fy * 2.0f;
472      }
473      else {
474         /* integer viewport params below */
475         prescale->translate[1] = fh - 1.0f + fy * 2.0f;
476      }
477      fh = -fh;
478      fy -= fh;
479      prescale->scale[1] = -1.0f;
480      invertY = TRUE;
481   }
482
483   if (fx < 0) {
484      prescale->translate[0] += fx;
485      prescale->scale[0] *= fw / (fw + fx);
486      fw += fx;
487      fx = 0.0f;
488   }
489
490   if (fy < 0) {
491      if (invertY) {
492         prescale->translate[1] -= fy;
493      }
494      else {
495         prescale->translate[1] += fy;
496      }
497      prescale->scale[1] *= fh / (fh + fy);
498      fh += fy;
499      fy = 0.0f;
500   }
501
502   if (fx + fw > fb_width) {
503      prescale->scale[0] *= fw / (fb_width - fx);
504      prescale->translate[0] -= fx * (fw / (fb_width - fx));
505      prescale->translate[0] += fx;
506      fw = fb_width - fx;
507   }
508
509   if (fy + fh > fb_height) {
510      prescale->scale[1] *= fh / (fb_height - fy);
511      if (invertY) {
512         float in = fb_height - fy;       /* number of vp pixels inside view */
513         float out = fy + fh - fb_height; /* number of vp pixels out of view */
514         prescale->translate[1] += fy * out / in;
515      }
516      else {
517         prescale->translate[1] -= fy * (fh / (fb_height - fy));
518         prescale->translate[1] += fy;
519      }
520      fh = fb_height - fy;
521   }
522
523   if (fw < 0 || fh < 0) {
524      fw = fh = fx = fy = 0;
525      degenerate = TRUE;
526      goto out;
527   }
528
529   /* D3D viewport is integer space.  Convert fx,fy,etc. to
530    * integers.
531    *
532    * TODO: adjust pretranslate correct for any subpixel error
533    * introduced converting to integers.
534    */
535   rect.x = (uint32) fx;
536   rect.y = (uint32) fy;
537   rect.w = (uint32) fw;
538   rect.h = (uint32) fh;
539
540   SVGA_DBG(DEBUG_VIEWPORT,
541            "viewport error %f,%f %fx%f\n",
542            fabs((float)rect.x - fx),
543            fabs((float)rect.y - fy),
544            fabs((float)rect.w - fw),
545            fabs((float)rect.h - fh));
546
547   SVGA_DBG(DEBUG_VIEWPORT,
548            "viewport %d,%d %dx%d\n",
549            rect.x,
550            rect.y,
551            rect.w,
552            rect.h);
553
554   /* Finally, to get GL rasterization rules, need to tweak the
555    * screen-space coordinates slightly relative to D3D which is
556    * what hardware implements natively.
557    */
558   if (svga->curr.rast && svga->curr.rast->templ.half_pixel_center) {
559      float adjust_x = 0.0;
560      float adjust_y = 0.0;
561
562      if (svga_have_vgpu10(svga)) {
563         /* Normally, we don't have to do any sub-pixel coordinate
564          * adjustments for VGPU10.  But when we draw wide points with
565          * a GS we need an X adjustment in order to be conformant.
566          */
567         if (svga->curr.reduced_prim == PIPE_PRIM_POINTS &&
568             svga->curr.rast->pointsize > 1.0f) {
569            adjust_x = 0.5;
570         }
571      }
572      else {
573         /* Use (-0.5, -0.5) bias for all prim types.
574          * Regarding line rasterization, this does not seem to satisfy
575          * the Piglit gl-1.0-ortho-pos test but it generally produces
576          * results identical or very similar to VGPU10.
577          */
578         adjust_x = -0.5;
579         adjust_y = -0.5;
580      }
581
582      if (invertY)
583         adjust_y = -adjust_y;
584
585      prescale->translate[0] += adjust_x;
586      prescale->translate[1] += adjust_y;
587      prescale->translate[2] = 0.5; /* D3D clip space */
588      prescale->scale[2]     = 0.5; /* D3D clip space */
589   }
590
591   range_min = viewport->scale[2] * -1.0f + viewport->translate[2];
592   range_max = viewport->scale[2] *  1.0f + viewport->translate[2];
593
594   /* D3D (and by implication SVGA) doesn't like dealing with zmax
595    * less than zmin.  Detect that case, flip the depth range and
596    * invert our z-scale factor to achieve the same effect.
597    */
598   if (range_min > range_max) {
599      float range_tmp;
600      range_tmp = range_min;
601      range_min = range_max;
602      range_max = range_tmp;
603      prescale->scale[2] = -prescale->scale[2];
604   }
605
606   /* If zmin is less than 0, clamp zmin to 0 and adjust the prescale.
607    * zmin can be set to -1 when viewport->scale[2] is set to 1 and
608    * viewport->translate[2] is set to 0 in the blit code.
609    */
610   if (range_min < 0.0f) {
611      range_min = -0.5f * viewport->scale[2] + 0.5f + viewport->translate[2];
612      range_max = 0.5f * viewport->scale[2] + 0.5f + viewport->translate[2];
613      prescale->scale[2] *= 2.0f;
614      prescale->translate[2] -= 0.5f;
615   }
616
617   if (prescale->enabled) {
618      float H[2];
619      float J[2];
620      int i;
621
622      SVGA_DBG(DEBUG_VIEWPORT,
623               "prescale %f,%f %fx%f\n",
624               prescale->translate[0],
625               prescale->translate[1],
626               prescale->scale[0],
627               prescale->scale[1]);
628
629      H[0] = (float)rect.w / 2.0f;
630      H[1] = -(float)rect.h / 2.0f;
631      J[0] = (float)rect.x + (float)rect.w / 2.0f;
632      J[1] = (float)rect.y + (float)rect.h / 2.0f;
633
634      SVGA_DBG(DEBUG_VIEWPORT,
635               "H %f,%f\n"
636               "J %fx%f\n",
637               H[0],
638               H[1],
639               J[0],
640               J[1]);
641
642      /* Adjust prescale to take into account the fact that it is
643       * going to be applied prior to the perspective divide and
644       * viewport transformation.
645       *
646       * Vwin = H(Vc/Vc.w) + J
647       *
648       * We want to tweak Vwin with scale and translation from above,
649       * as in:
650       *
651       * Vwin' = S Vwin + T
652       *
653       * But we can only modify the values at Vc.  Plugging all the
654       * above together, and rearranging, eventually we get:
655       *
656       *   Vwin' = H(Vc'/Vc'.w) + J
657       * where:
658       *   Vc' = SVc + KVc.w
659       *   K = (T + (S-1)J) / H
660       *
661       * Overwrite prescale.translate with values for K:
662       */
663      for (i = 0; i < 2; i++) {
664         prescale->translate[i] = ((prescale->translate[i] +
665                                   (prescale->scale[i] - 1.0f) * J[i]) / H[i]);
666      }
667
668      SVGA_DBG(DEBUG_VIEWPORT,
669               "clipspace %f,%f %fx%f\n",
670               prescale->translate[0],
671               prescale->translate[1],
672               prescale->scale[0],
673               prescale->scale[1]);
674   }
675
676out:
677   if (degenerate) {
678      rect.x = 0;
679      rect.y = 0;
680      rect.w = 1;
681      rect.h = 1;
682      prescale->enabled = FALSE;
683   }
684
685   vp->x = (float) rect.x;
686   vp->y = (float) rect.y;
687   vp->width = (float) rect.w;
688   vp->height = (float) rect.h;
689   vp->minDepth = range_min;
690   vp->maxDepth = range_max;
691}
692
693
694static enum pipe_error
695emit_viewport( struct svga_context *svga,
696               uint64_t dirty )
697{
698   struct svga_screen *svgascreen = svga_screen(svga->pipe.screen);
699   SVGA3dViewport viewports[SVGA3D_DX_MAX_VIEWPORTS];
700   struct svga_prescale prescale[SVGA3D_DX_MAX_VIEWPORTS];
701   unsigned i;
702   enum pipe_error ret;
703   unsigned max_viewports = svgascreen->max_viewports;
704
705   for (i = 0; i < max_viewports; i++) {
706      get_viewport_prescale(svga, &svga->curr.viewport[i],
707                            &viewports[i], &prescale[i]);
708   }
709
710   if (memcmp(viewports, svga->state.hw_clear.viewports,
711              max_viewports * sizeof viewports[0]) != 0) {
712
713      if (!svga_have_vgpu10(svga)) {
714         SVGA3dRect rect;
715         SVGA3dViewport *vp = &viewports[0];
716
717         rect.x = (uint32)vp->x;
718         rect.y = (uint32)vp->y;
719         rect.w = (uint32)vp->width;
720         rect.h = (uint32)vp->height;
721
722         ret = SVGA3D_SetViewport(svga->swc, &rect);
723         if (ret != PIPE_OK)
724            return ret;
725
726         ret = SVGA3D_SetZRange(svga->swc, vp->minDepth, vp->maxDepth);
727         if (ret != PIPE_OK)
728            return ret;
729
730         svga->state.hw_clear.viewport = rect;
731         svga->state.hw_clear.depthrange.zmin = vp->minDepth;
732         svga->state.hw_clear.depthrange.zmax = vp->maxDepth;
733      }
734      else {
735         ret = SVGA3D_vgpu10_SetViewports(svga->swc, max_viewports,
736                                          viewports);
737         if (ret != PIPE_OK)
738            return ret;
739      }
740      memcpy(svga->state.hw_clear.viewports, viewports,
741             max_viewports * sizeof viewports[0]);
742   }
743
744   if (memcmp(prescale, svga->state.hw_clear.prescale,
745              max_viewports * sizeof prescale[0]) != 0) {
746      svga->dirty |= SVGA_NEW_PRESCALE;
747      memcpy(svga->state.hw_clear.prescale, prescale,
748             max_viewports * sizeof prescale[0]);
749
750      /*
751       * Determine number of unique prescales. This is to minimize the
752       * if check needed in the geometry shader to identify the prescale
753       * for the specified viewport.
754       */
755      unsigned last_prescale = SVGA3D_DX_MAX_VIEWPORTS - 1;
756      unsigned i;
757      for (i = SVGA3D_DX_MAX_VIEWPORTS-1; i > 0; i--) {
758         if (memcmp(&svga->state.hw_clear.prescale[i],
759                    &svga->state.hw_clear.prescale[i-1],
760                    sizeof svga->state.hw_clear.prescale[0])) {
761            break;
762         }
763         last_prescale--;
764      }
765      svga->state.hw_clear.num_prescale = last_prescale + 1;
766   }
767
768   return PIPE_OK;
769}
770
771
772struct svga_tracked_state svga_hw_viewport =
773{
774   "hw viewport state",
775   ( SVGA_NEW_FRAME_BUFFER |
776     SVGA_NEW_VIEWPORT |
777     SVGA_NEW_RAST |
778     SVGA_NEW_REDUCED_PRIMITIVE ),
779   emit_viewport
780};
781
782
783/***********************************************************************
784 * Scissor state
785 */
786static enum pipe_error
787emit_scissor_rect( struct svga_context *svga,
788                   uint64_t dirty )
789{
790   struct svga_screen *svgascreen = svga_screen(svga->pipe.screen);
791   const struct pipe_scissor_state *scissor = svga->curr.scissor;
792   unsigned max_viewports = svgascreen->max_viewports;
793   enum pipe_error ret;
794
795   if (memcmp(&svga->state.hw_clear.scissors[0], scissor,
796              max_viewports * sizeof *scissor) != 0) {
797
798      if (svga_have_vgpu10(svga)) {
799         SVGASignedRect rect[SVGA3D_DX_MAX_VIEWPORTS];
800         unsigned i;
801
802         for (i = 0; i < max_viewports; i++) {
803            rect[i].left = scissor[i].minx;
804            rect[i].top = scissor[i].miny;
805            rect[i].right = scissor[i].maxx;
806            rect[i].bottom = scissor[i].maxy;
807         }
808
809         ret = SVGA3D_vgpu10_SetScissorRects(svga->swc, max_viewports, rect);
810      }
811      else {
812         SVGA3dRect rect;
813
814         rect.x = scissor[0].minx;
815         rect.y = scissor[0].miny;
816         rect.w = scissor[0].maxx - scissor[0].minx; /* + 1 ?? */
817         rect.h = scissor[0].maxy - scissor[0].miny; /* + 1 ?? */
818
819         ret = SVGA3D_SetScissorRect(svga->swc, &rect);
820      }
821
822      if (ret != PIPE_OK)
823         return ret;
824
825      memcpy(svga->state.hw_clear.scissors, scissor,
826             max_viewports * sizeof *scissor);
827   }
828
829   return PIPE_OK;
830}
831
832struct svga_tracked_state svga_hw_scissor =
833{
834   "hw scissor state",
835   SVGA_NEW_SCISSOR,
836   emit_scissor_rect
837};
838
839
840/***********************************************************************
841 * Userclip state
842 */
843
844static enum pipe_error
845emit_clip_planes( struct svga_context *svga,
846                  uint64_t dirty )
847{
848   unsigned i;
849   enum pipe_error ret;
850
851   /* TODO: just emit directly from svga_set_clip_state()?
852    */
853   for (i = 0; i < SVGA3D_MAX_CLIP_PLANES; i++) {
854      /* need to express the plane in D3D-style coordinate space.
855       * GL coords get converted to D3D coords with the matrix:
856       * [ 1  0  0  0 ]
857       * [ 0 -1  0  0 ]
858       * [ 0  0  2  0 ]
859       * [ 0  0 -1  1 ]
860       * Apply that matrix to our plane equation, and invert Y.
861       */
862      float a = svga->curr.clip.ucp[i][0];
863      float b = svga->curr.clip.ucp[i][1];
864      float c = svga->curr.clip.ucp[i][2];
865      float d = svga->curr.clip.ucp[i][3];
866      float plane[4];
867
868      plane[0] = a;
869      plane[1] = b;
870      plane[2] = 2.0f * c;
871      plane[3] = d - c;
872
873      if (svga_have_vgpu10(svga)) {
874         //debug_printf("XXX emit DX10 clip plane\n");
875         ret = PIPE_OK;
876      }
877      else {
878         ret = SVGA3D_SetClipPlane(svga->swc, i, plane);
879         if (ret != PIPE_OK)
880            return ret;
881      }
882   }
883
884   return PIPE_OK;
885}
886
887
888struct svga_tracked_state svga_hw_clip_planes =
889{
890   "hw viewport state",
891   SVGA_NEW_CLIP,
892   emit_clip_planes
893};
894