Home | History | Annotate | Download | only in svga
      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
     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
    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
    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
    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
    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
    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
    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
    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
    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