• 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/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 
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          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 
309 static enum pipe_error
emit_framebuffer(struct svga_context * svga,uint64_t dirty)310 emit_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  */
329 enum pipe_error
svga_reemit_framebuffer_bindings(struct svga_context * svga)330 svga_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  */
352 enum pipe_error
svga_rebind_framebuffer_bindings(struct svga_context * svga)353 svga_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 
390 struct 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 
403 static void
get_viewport_prescale(struct svga_context * svga,struct pipe_viewport_state * viewport,SVGA3dViewport * vp,struct svga_prescale * prescale)404 get_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 
676 out:
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 
694 static enum pipe_error
emit_viewport(struct svga_context * svga,uint64_t dirty)695 emit_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 
772 struct 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  */
786 static enum pipe_error
emit_scissor_rect(struct svga_context * svga,uint64_t dirty)787 emit_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 
832 struct 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 
844 static enum pipe_error
emit_clip_planes(struct svga_context * svga,uint64_t dirty)845 emit_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 
888 struct svga_tracked_state svga_hw_clip_planes =
889 {
890    "hw viewport state",
891    SVGA_NEW_CLIP,
892    emit_clip_planes
893 };
894