Subversion Repositories Kolibri OS

Rev

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