Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

  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 = (float) svga->curr.framebuffer.width;
  182.    float fb_height = (float) svga->curr.framebuffer.height;
  183.  
  184.    float fx =        viewport->scale[0] * -1.0f + viewport->translate[0];
  185.    float fy = flip * viewport->scale[1] * -1.0f + viewport->translate[1];
  186.    float fw =        viewport->scale[0] * 2.0f;
  187.    float fh = flip * viewport->scale[1] * 2.0f;
  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.0f;
  217.       prescale.translate[0] += -fw;
  218.       fw = -fw;
  219.       fx =        viewport->scale[0] * 1.0f + viewport->translate[0];
  220.    }
  221.  
  222.    if (fh < 0.0) {
  223.       prescale.translate[1] = fh - 1.0f + fy * 2.0f;
  224.       fh = -fh;
  225.       fy -= fh;
  226.       prescale.scale[1] = -1.0f;
  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.0f;
  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.0f;
  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 = (uint32) fx;
  285.    rect.y = (uint32) fy;
  286.    rect.w = (uint32) fw;
  287.    rect.h = (uint32) 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.half_pixel_center) {
  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.0f + viewport->translate[2];
  335.    range_max = viewport->scale[2] *  1.0f + 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.0f;
  362.       H[1] = -(float)rect.h / 2.0f;
  363.       J[0] = (float)rect.x + (float)rect.w / 2.0f;
  364.       J[1] = (float)rect.y + (float)rect.h / 2.0f;
  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.0f) * 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.