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 
     30 #include "svga_context.h"
     31 #include "svga_state.h"
     32 #include "svga_cmd.h"
     33 #include "svga_debug.h"
     34 
     35 
     36 /***********************************************************************
     37  * Hardware state update
     38  */
     39 
     40 
     41 static enum pipe_error
     42 emit_framebuffer( struct svga_context *svga,
     43                   unsigned dirty )
     44 {
     45    const struct pipe_framebuffer_state *curr = &svga->curr.framebuffer;
     46    struct pipe_framebuffer_state *hw = &svga->state.hw_clear.framebuffer;
     47    boolean reemit = svga->rebind.rendertargets;
     48    unsigned i;
     49    enum pipe_error ret;
     50 
     51    /*
     52     * We need to reemit non-null surface bindings, even when they are not
     53     * dirty, to ensure that the resources are paged in.
     54     */
     55 
     56    for(i = 0; i < PIPE_MAX_COLOR_BUFS; ++i) {
     57       if (curr->cbufs[i] != hw->cbufs[i] ||
     58           (reemit && hw->cbufs[i])) {
     59          if (svga->curr.nr_fbs++ > 8)
     60             return PIPE_ERROR_OUT_OF_MEMORY;
     61 
     62          ret = SVGA3D_SetRenderTarget(svga->swc, SVGA3D_RT_COLOR0 + i, curr->cbufs[i]);
     63          if (ret != PIPE_OK)
     64             return ret;
     65 
     66          pipe_surface_reference(&hw->cbufs[i], curr->cbufs[i]);
     67       }
     68    }
     69 
     70 
     71    if (curr->zsbuf != hw->zsbuf ||
     72        (reemit && hw->zsbuf)) {
     73       ret = SVGA3D_SetRenderTarget(svga->swc, SVGA3D_RT_DEPTH, curr->zsbuf);
     74       if (ret != PIPE_OK)
     75          return ret;
     76 
     77       if (curr->zsbuf &&
     78           curr->zsbuf->format == PIPE_FORMAT_S8_UINT_Z24_UNORM) {
     79          ret = SVGA3D_SetRenderTarget(svga->swc, SVGA3D_RT_STENCIL, curr->zsbuf);
     80          if (ret != PIPE_OK)
     81             return ret;
     82       }
     83       else {
     84          ret = SVGA3D_SetRenderTarget(svga->swc, SVGA3D_RT_STENCIL, NULL);
     85          if (ret != PIPE_OK)
     86             return ret;
     87       }
     88 
     89       pipe_surface_reference(&hw->zsbuf, curr->zsbuf);
     90    }
     91 
     92    svga->rebind.rendertargets = FALSE;
     93 
     94    return PIPE_OK;
     95 }
     96 
     97 
     98 /*
     99  * Rebind rendertargets.
    100  *
    101  * Similar to emit_framebuffer, but without any state checking/update.
    102  *
    103  * Called at the beginning of every new command buffer to ensure that
    104  * non-dirty rendertargets are properly paged-in.
    105  */
    106 enum pipe_error
    107 svga_reemit_framebuffer_bindings(struct svga_context *svga)
    108 {
    109    struct pipe_framebuffer_state *hw = &svga->state.hw_clear.framebuffer;
    110    unsigned i;
    111    enum pipe_error ret;
    112 
    113    assert(svga->rebind.rendertargets);
    114 
    115    for (i = 0; i < MIN2(PIPE_MAX_COLOR_BUFS, 8); ++i) {
    116       if (hw->cbufs[i]) {
    117          ret = SVGA3D_SetRenderTarget(svga->swc, SVGA3D_RT_COLOR0 + i, hw->cbufs[i]);
    118          if (ret != PIPE_OK) {
    119             return ret;
    120          }
    121       }
    122    }
    123 
    124    if (hw->zsbuf) {
    125       ret = SVGA3D_SetRenderTarget(svga->swc, SVGA3D_RT_DEPTH, hw->zsbuf);
    126       if (ret != PIPE_OK) {
    127          return ret;
    128       }
    129 
    130       if (hw->zsbuf &&
    131           hw->zsbuf->format == PIPE_FORMAT_S8_UINT_Z24_UNORM) {
    132          ret = SVGA3D_SetRenderTarget(svga->swc, SVGA3D_RT_STENCIL, hw->zsbuf);
    133          if (ret != PIPE_OK) {
    134             return ret;
    135          }
    136       }
    137       else {
    138          ret = SVGA3D_SetRenderTarget(svga->swc, SVGA3D_RT_STENCIL, NULL);
    139          if (ret != PIPE_OK) {
    140             return ret;
    141          }
    142       }
    143    }
    144 
    145    svga->rebind.rendertargets = FALSE;
    146 
    147    return PIPE_OK;
    148 }
    149 
    150 
    151 struct svga_tracked_state svga_hw_framebuffer =
    152 {
    153    "hw framebuffer state",
    154    SVGA_NEW_FRAME_BUFFER,
    155    emit_framebuffer
    156 };
    157 
    158 
    159 
    160 
    161 /***********************************************************************
    162  */
    163 
    164 static enum pipe_error
    165 emit_viewport( struct svga_context *svga,
    166                unsigned dirty )
    167 {
    168    const struct pipe_viewport_state *viewport = &svga->curr.viewport;
    169    struct svga_prescale prescale;
    170    SVGA3dRect rect;
    171    /* Not sure if this state is relevant with POSITIONT.  Probably
    172     * not, but setting to 0,1 avoids some state pingponging.
    173     */
    174    float range_min = 0.0;
    175    float range_max = 1.0;
    176    float flip = -1.0;
    177    boolean degenerate = FALSE;
    178    boolean invertY = FALSE;
    179    enum pipe_error ret;
    180 
    181    float fb_width = svga->curr.framebuffer.width;
    182    float fb_height = svga->curr.framebuffer.height;
    183 
    184    float fx =        viewport->scale[0] * -1.0 + viewport->translate[0];
    185    float fy = flip * viewport->scale[1] * -1.0 + viewport->translate[1];
    186    float fw =        viewport->scale[0] * 2;
    187    float fh = flip * viewport->scale[1] * 2;
    188 
    189    memset( &prescale, 0, sizeof(prescale) );
    190 
    191    /* Examine gallium viewport transformation and produce a screen
    192     * rectangle and possibly vertex shader pre-transformation to
    193     * get the same results.
    194     */
    195 
    196    SVGA_DBG(DEBUG_VIEWPORT,
    197             "\ninitial %f,%f %fx%f\n",
    198             fx,
    199             fy,
    200             fw,
    201             fh);
    202 
    203    prescale.scale[0] = 1.0;
    204    prescale.scale[1] = 1.0;
    205    prescale.scale[2] = 1.0;
    206    prescale.scale[3] = 1.0;
    207    prescale.translate[0] = 0;
    208    prescale.translate[1] = 0;
    209    prescale.translate[2] = 0;
    210    prescale.translate[3] = 0;
    211    prescale.enabled = TRUE;
    212 
    213 
    214 
    215    if (fw < 0) {
    216       prescale.scale[0] *= -1.0;
    217       prescale.translate[0] += -fw;
    218       fw = -fw;
    219       fx =        viewport->scale[0] * 1.0 + viewport->translate[0];
    220    }
    221 
    222    if (fh < 0.0) {
    223       prescale.translate[1] = fh - 1 + fy * 2;
    224       fh = -fh;
    225       fy -= fh;
    226       prescale.scale[1] = -1.0;
    227       invertY = TRUE;
    228    }
    229 
    230    if (fx < 0) {
    231       prescale.translate[0] += fx;
    232       prescale.scale[0] *= fw / (fw + fx);
    233       fw += fx;
    234       fx = 0;
    235    }
    236 
    237    if (fy < 0) {
    238       if (invertY) {
    239          prescale.translate[1] -= fy;
    240       }
    241       else {
    242          prescale.translate[1] += fy;
    243       }
    244       prescale.scale[1] *= fh / (fh + fy);
    245       fh += fy;
    246       fy = 0;
    247    }
    248 
    249    if (fx + fw > fb_width) {
    250       prescale.scale[0] *= fw / (fb_width - fx);
    251       prescale.translate[0] -= fx * (fw / (fb_width - fx));
    252       prescale.translate[0] += fx;
    253       fw = fb_width - fx;
    254 
    255    }
    256 
    257    if (fy + fh > fb_height) {
    258       prescale.scale[1] *= fh / (fb_height - fy);
    259       if (invertY) {
    260          float in = fb_height - fy;       /* number of vp pixels inside view */
    261          float out = fy + fh - fb_height; /* number of vp pixels out of view */
    262          prescale.translate[1] += fy * out / in;
    263       }
    264       else {
    265          prescale.translate[1] -= fy * (fh / (fb_height - fy));
    266          prescale.translate[1] += fy;
    267       }
    268       fh = fb_height - fy;
    269    }
    270 
    271    if (fw < 0 || fh < 0) {
    272       fw = fh = fx = fy = 0;
    273       degenerate = TRUE;
    274       goto out;
    275    }
    276 
    277 
    278    /* D3D viewport is integer space.  Convert fx,fy,etc. to
    279     * integers.
    280     *
    281     * TODO: adjust pretranslate correct for any subpixel error
    282     * introduced converting to integers.
    283     */
    284    rect.x = fx;
    285    rect.y = fy;
    286    rect.w = fw;
    287    rect.h = fh;
    288 
    289    SVGA_DBG(DEBUG_VIEWPORT,
    290             "viewport error %f,%f %fx%f\n",
    291             fabs((float)rect.x - fx),
    292             fabs((float)rect.y - fy),
    293             fabs((float)rect.w - fw),
    294             fabs((float)rect.h - fh));
    295 
    296    SVGA_DBG(DEBUG_VIEWPORT,
    297             "viewport %d,%d %dx%d\n",
    298             rect.x,
    299             rect.y,
    300             rect.w,
    301             rect.h);
    302 
    303 
    304    /* Finally, to get GL rasterization rules, need to tweak the
    305     * screen-space coordinates slightly relative to D3D which is
    306     * what hardware implements natively.
    307     */
    308    if (svga->curr.rast->templ.gl_rasterization_rules) {
    309       float adjust_x = 0.0;
    310       float adjust_y = 0.0;
    311 
    312       switch (svga->curr.reduced_prim) {
    313       case PIPE_PRIM_LINES:
    314          adjust_x = -0.5;
    315          adjust_y = 0;
    316          break;
    317       case PIPE_PRIM_POINTS:
    318       case PIPE_PRIM_TRIANGLES:
    319          adjust_x = -0.5;
    320          adjust_y = -0.5;
    321          break;
    322       }
    323 
    324       if (invertY)
    325          adjust_y = -adjust_y;
    326 
    327       prescale.translate[0] += adjust_x;
    328       prescale.translate[1] += adjust_y;
    329       prescale.translate[2] = 0.5; /* D3D clip space */
    330       prescale.scale[2]     = 0.5; /* D3D clip space */
    331    }
    332 
    333 
    334    range_min = viewport->scale[2] * -1.0 + viewport->translate[2];
    335    range_max = viewport->scale[2] *  1.0 + viewport->translate[2];
    336 
    337    /* D3D (and by implication SVGA) doesn't like dealing with zmax
    338     * less than zmin.  Detect that case, flip the depth range and
    339     * invert our z-scale factor to achieve the same effect.
    340     */
    341    if (range_min > range_max) {
    342       float range_tmp;
    343       range_tmp = range_min;
    344       range_min = range_max;
    345       range_max = range_tmp;
    346       prescale.scale[2]     = -prescale.scale[2];
    347    }
    348 
    349    if (prescale.enabled) {
    350       float H[2];
    351       float J[2];
    352       int i;
    353 
    354       SVGA_DBG(DEBUG_VIEWPORT,
    355                "prescale %f,%f %fx%f\n",
    356                prescale.translate[0],
    357                prescale.translate[1],
    358                prescale.scale[0],
    359                prescale.scale[1]);
    360 
    361       H[0] = (float)rect.w / 2.0;
    362       H[1] = -(float)rect.h / 2.0;
    363       J[0] = (float)rect.x + (float)rect.w / 2.0;
    364       J[1] = (float)rect.y + (float)rect.h / 2.0;
    365 
    366       SVGA_DBG(DEBUG_VIEWPORT,
    367                "H %f,%f\n"
    368                "J %fx%f\n",
    369                H[0],
    370                H[1],
    371                J[0],
    372                J[1]);
    373 
    374       /* Adjust prescale to take into account the fact that it is
    375        * going to be applied prior to the perspective divide and
    376        * viewport transformation.
    377        *
    378        * Vwin = H(Vc/Vc.w) + J
    379        *
    380        * We want to tweak Vwin with scale and translation from above,
    381        * as in:
    382        *
    383        * Vwin' = S Vwin + T
    384        *
    385        * But we can only modify the values at Vc.  Plugging all the
    386        * above together, and rearranging, eventually we get:
    387        *
    388        *   Vwin' = H(Vc'/Vc'.w) + J
    389        * where:
    390        *   Vc' = SVc + KVc.w
    391        *   K = (T + (S-1)J) / H
    392        *
    393        * Overwrite prescale.translate with values for K:
    394        */
    395       for (i = 0; i < 2; i++) {
    396          prescale.translate[i] = ((prescale.translate[i] +
    397                                    (prescale.scale[i] - 1.0) * J[i]) / H[i]);
    398       }
    399 
    400       SVGA_DBG(DEBUG_VIEWPORT,
    401                "clipspace %f,%f %fx%f\n",
    402                prescale.translate[0],
    403                prescale.translate[1],
    404                prescale.scale[0],
    405                prescale.scale[1]);
    406    }
    407 
    408 out:
    409    if (degenerate) {
    410       rect.x = 0;
    411       rect.y = 0;
    412       rect.w = 1;
    413       rect.h = 1;
    414       prescale.enabled = FALSE;
    415    }
    416 
    417    if (memcmp(&rect, &svga->state.hw_clear.viewport, sizeof(rect)) != 0) {
    418       ret = SVGA3D_SetViewport(svga->swc, &rect);
    419       if(ret != PIPE_OK)
    420          return ret;
    421 
    422       memcpy(&svga->state.hw_clear.viewport, &rect, sizeof(rect));
    423       assert(sizeof(rect) == sizeof(svga->state.hw_clear.viewport));
    424    }
    425 
    426    if (svga->state.hw_clear.depthrange.zmin != range_min ||
    427        svga->state.hw_clear.depthrange.zmax != range_max)
    428    {
    429       ret = SVGA3D_SetZRange(svga->swc, range_min, range_max );
    430       if(ret != PIPE_OK)
    431          return ret;
    432 
    433       svga->state.hw_clear.depthrange.zmin = range_min;
    434       svga->state.hw_clear.depthrange.zmax = range_max;
    435    }
    436 
    437    if (memcmp(&prescale, &svga->state.hw_clear.prescale, sizeof prescale) != 0) {
    438       svga->dirty |= SVGA_NEW_PRESCALE;
    439       svga->state.hw_clear.prescale = prescale;
    440    }
    441 
    442    return PIPE_OK;
    443 }
    444 
    445 
    446 struct svga_tracked_state svga_hw_viewport =
    447 {
    448    "hw viewport state",
    449    ( SVGA_NEW_FRAME_BUFFER |
    450      SVGA_NEW_VIEWPORT |
    451      SVGA_NEW_RAST |
    452      SVGA_NEW_REDUCED_PRIMITIVE ),
    453    emit_viewport
    454 };
    455 
    456 
    457 /***********************************************************************
    458  * Scissor state
    459  */
    460 static enum pipe_error
    461 emit_scissor_rect( struct svga_context *svga,
    462                    unsigned dirty )
    463 {
    464    const struct pipe_scissor_state *scissor = &svga->curr.scissor;
    465    SVGA3dRect rect;
    466 
    467    rect.x = scissor->minx;
    468    rect.y = scissor->miny;
    469    rect.w = scissor->maxx - scissor->minx; /* + 1 ?? */
    470    rect.h = scissor->maxy - scissor->miny; /* + 1 ?? */
    471 
    472    return SVGA3D_SetScissorRect(svga->swc, &rect);
    473 }
    474 
    475 
    476 struct svga_tracked_state svga_hw_scissor =
    477 {
    478    "hw scissor state",
    479    SVGA_NEW_SCISSOR,
    480    emit_scissor_rect
    481 };
    482 
    483 
    484 /***********************************************************************
    485  * Userclip state
    486  */
    487 
    488 static enum pipe_error
    489 emit_clip_planes( struct svga_context *svga,
    490                   unsigned dirty )
    491 {
    492    unsigned i;
    493    enum pipe_error ret;
    494 
    495    /* TODO: just emit directly from svga_set_clip_state()?
    496     */
    497    for (i = 0; i < SVGA3D_MAX_CLIP_PLANES; i++) {
    498       /* need to express the plane in D3D-style coordinate space.
    499        * GL coords get converted to D3D coords with the matrix:
    500        * [ 1  0  0  0 ]
    501        * [ 0 -1  0  0 ]
    502        * [ 0  0  2  0 ]
    503        * [ 0  0 -1  1 ]
    504        * Apply that matrix to our plane equation, and invert Y.
    505        */
    506       float a = svga->curr.clip.ucp[i][0];
    507       float b = svga->curr.clip.ucp[i][1];
    508       float c = svga->curr.clip.ucp[i][2];
    509       float d = svga->curr.clip.ucp[i][3];
    510       float plane[4];
    511 
    512       plane[0] = a;
    513       plane[1] = b;
    514       plane[2] = 2.0f * c;
    515       plane[3] = d - c;
    516 
    517       ret = SVGA3D_SetClipPlane(svga->swc, i, plane);
    518       if(ret != PIPE_OK)
    519          return ret;
    520    }
    521 
    522    return PIPE_OK;
    523 }
    524 
    525 
    526 struct svga_tracked_state svga_hw_clip_planes =
    527 {
    528    "hw viewport state",
    529    SVGA_NEW_CLIP,
    530    emit_clip_planes
    531 };
    532