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 "svga_cmd.h"
  27.  
  28. #include "pipe/p_state.h"
  29. #include "pipe/p_defines.h"
  30. #include "util/u_inlines.h"
  31. #include "os/os_thread.h"
  32. #include "util/u_format.h"
  33. #include "util/u_math.h"
  34. #include "util/u_memory.h"
  35. #include "util/u_resource.h"
  36.  
  37. #include "svga_format.h"
  38. #include "svga_screen.h"
  39. #include "svga_context.h"
  40. #include "svga_resource_texture.h"
  41. #include "svga_resource_buffer.h"
  42. #include "svga_sampler_view.h"
  43. #include "svga_winsys.h"
  44. #include "svga_debug.h"
  45.  
  46.  
  47. /* XXX: This isn't a real hardware flag, but just a hack for kernel to
  48.  * know about primary surfaces. Find a better way to accomplish this.
  49.  */
  50. #define SVGA3D_SURFACE_HINT_SCANOUT (1 << 9)
  51.  
  52.  
  53. static INLINE void
  54. svga_transfer_dma_band(struct svga_context *svga,
  55.                        struct svga_transfer *st,
  56.                        SVGA3dTransferType transfer,
  57.                        unsigned y, unsigned h, unsigned srcy,
  58.                        SVGA3dSurfaceDMAFlags flags)
  59. {
  60.    struct svga_texture *texture = svga_texture(st->base.resource);
  61.    SVGA3dCopyBox box;
  62.    enum pipe_error ret;
  63.  
  64.    box.x = st->base.box.x;
  65.    box.y = y;
  66.    box.z = st->base.box.z;
  67.    box.w = st->base.box.width;
  68.    box.h = h;
  69.    box.d = 1;
  70.    box.srcx = 0;
  71.    box.srcy = srcy;
  72.    box.srcz = 0;
  73.  
  74.    if (st->base.resource->target == PIPE_TEXTURE_CUBE) {
  75.       st->face = st->base.box.z;
  76.       box.z = 0;
  77.    }
  78.    else
  79.       st->face = 0;
  80.  
  81.    SVGA_DBG(DEBUG_DMA, "dma %s sid %p, face %u, (%u, %u, %u) - (%u, %u, %u), %ubpp\n",
  82.                 transfer == SVGA3D_WRITE_HOST_VRAM ? "to" : "from",
  83.                 texture->handle,
  84.                 st->face,
  85.                 st->base.box.x,
  86.                 y,
  87.                 box.z,
  88.                 st->base.box.x + st->base.box.width,
  89.                 y + h,
  90.                 box.z + 1,
  91.                 util_format_get_blocksize(texture->b.b.format) * 8 /
  92.                 (util_format_get_blockwidth(texture->b.b.format)*util_format_get_blockheight(texture->b.b.format)));
  93.  
  94.    ret = SVGA3D_SurfaceDMA(svga->swc, st, transfer, &box, 1, flags);
  95.    if(ret != PIPE_OK) {
  96.       svga_context_flush(svga, NULL);
  97.       ret = SVGA3D_SurfaceDMA(svga->swc, st, transfer, &box, 1, flags);
  98.       assert(ret == PIPE_OK);
  99.    }
  100. }
  101.  
  102.  
  103. static INLINE void
  104. svga_transfer_dma(struct svga_context *svga,
  105.                   struct svga_transfer *st,
  106.                   SVGA3dTransferType transfer,
  107.                   SVGA3dSurfaceDMAFlags flags)
  108. {
  109.    struct svga_texture *texture = svga_texture(st->base.resource);
  110.    struct svga_screen *screen = svga_screen(texture->b.b.screen);
  111.    struct svga_winsys_screen *sws = screen->sws;
  112.    struct pipe_fence_handle *fence = NULL;
  113.  
  114.    if (transfer == SVGA3D_READ_HOST_VRAM) {
  115.       SVGA_DBG(DEBUG_PERF, "%s: readback transfer\n", __FUNCTION__);
  116.    }
  117.  
  118.    /* Ensure any pending operations on host surfaces are queued on the command
  119.     * buffer first.
  120.     */
  121.    svga_surfaces_flush( svga );
  122.  
  123.    if(!st->swbuf) {
  124.       /* Do the DMA transfer in a single go */
  125.  
  126.       svga_transfer_dma_band(svga, st, transfer,
  127.                              st->base.box.y, st->base.box.height, 0,
  128.                              flags);
  129.  
  130.       if(transfer == SVGA3D_READ_HOST_VRAM) {
  131.          svga_context_flush(svga, &fence);
  132.          sws->fence_finish(sws, fence, 0);
  133.          sws->fence_reference(sws, &fence, NULL);
  134.       }
  135.    }
  136.    else {
  137.       int y, h, srcy;
  138.       unsigned blockheight = util_format_get_blockheight(st->base.resource->format);
  139.       h = st->hw_nblocksy * blockheight;
  140.       srcy = 0;
  141.       for(y = 0; y < st->base.box.height; y += h) {
  142.          unsigned offset, length;
  143.          void *hw, *sw;
  144.  
  145.          if (y + h > st->base.box.height)
  146.             h = st->base.box.height - y;
  147.  
  148.          /* Transfer band must be aligned to pixel block boundaries */
  149.          assert(y % blockheight == 0);
  150.          assert(h % blockheight == 0);
  151.  
  152.          offset = y * st->base.stride / blockheight;
  153.          length = h * st->base.stride / blockheight;
  154.  
  155.          sw = (uint8_t *)st->swbuf + offset;
  156.  
  157.          if (transfer == SVGA3D_WRITE_HOST_VRAM) {
  158.             unsigned usage = PIPE_TRANSFER_WRITE;
  159.  
  160.             /* Wait for the previous DMAs to complete */
  161.             /* TODO: keep one DMA (at half the size) in the background */
  162.             if (y) {
  163.                svga_context_flush(svga, NULL);
  164.                usage |= PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE;
  165.             }
  166.  
  167.             hw = sws->buffer_map(sws, st->hwbuf, usage);
  168.             assert(hw);
  169.             if (hw) {
  170.                memcpy(hw, sw, length);
  171.                sws->buffer_unmap(sws, st->hwbuf);
  172.             }
  173.          }
  174.  
  175.          svga_transfer_dma_band(svga, st, transfer, y, h, srcy, flags);
  176.  
  177.          /*
  178.           * Prevent the texture contents to be discarded on the next band
  179.           * upload.
  180.           */
  181.  
  182.          flags.discard = FALSE;
  183.  
  184.          if(transfer == SVGA3D_READ_HOST_VRAM) {
  185.             svga_context_flush(svga, &fence);
  186.             sws->fence_finish(sws, fence, 0);
  187.  
  188.             hw = sws->buffer_map(sws, st->hwbuf, PIPE_TRANSFER_READ);
  189.             assert(hw);
  190.             if(hw) {
  191.                memcpy(sw, hw, length);
  192.                sws->buffer_unmap(sws, st->hwbuf);
  193.             }
  194.          }
  195.       }
  196.    }
  197. }
  198.  
  199.  
  200. static boolean
  201. svga_texture_get_handle(struct pipe_screen *screen,
  202.                                struct pipe_resource *texture,
  203.                                struct winsys_handle *whandle)
  204. {
  205.    struct svga_winsys_screen *sws = svga_winsys_screen(texture->screen);
  206.    unsigned stride;
  207.  
  208.    assert(svga_texture(texture)->key.cachable == 0);
  209.    svga_texture(texture)->key.cachable = 0;
  210.    stride = util_format_get_nblocksx(texture->format, texture->width0) *
  211.             util_format_get_blocksize(texture->format);
  212.    return sws->surface_get_handle(sws, svga_texture(texture)->handle, stride, whandle);
  213. }
  214.  
  215.  
  216. static void
  217. svga_texture_destroy(struct pipe_screen *screen,
  218.                      struct pipe_resource *pt)
  219. {
  220.    struct svga_screen *ss = svga_screen(screen);
  221.    struct svga_texture *tex = svga_texture(pt);
  222.  
  223.    ss->texture_timestamp++;
  224.  
  225.    svga_sampler_view_reference(&tex->cached_view, NULL);
  226.  
  227.    /*
  228.      DBG("%s deleting %p\n", __FUNCTION__, (void *) tex);
  229.    */
  230.    SVGA_DBG(DEBUG_DMA, "unref sid %p (texture)\n", tex->handle);
  231.    svga_screen_surface_destroy(ss, &tex->key, &tex->handle);
  232.  
  233.    ss->total_resource_bytes -= tex->size;
  234.  
  235.    FREE(tex);
  236. }
  237.  
  238.  
  239. /* XXX: Still implementing this as if it was a screen function, but
  240.  * can now modify it to queue transfers on the context.
  241.  */
  242. static void *
  243. svga_texture_transfer_map(struct pipe_context *pipe,
  244.                           struct pipe_resource *texture,
  245.                           unsigned level,
  246.                           unsigned usage,
  247.                           const struct pipe_box *box,
  248.                           struct pipe_transfer **ptransfer)
  249. {
  250.    struct svga_context *svga = svga_context(pipe);
  251.    struct svga_screen *ss = svga_screen(pipe->screen);
  252.    struct svga_winsys_screen *sws = ss->sws;
  253.    struct svga_transfer *st;
  254.    unsigned nblocksx = util_format_get_nblocksx(texture->format, box->width);
  255.    unsigned nblocksy = util_format_get_nblocksy(texture->format, box->height);
  256.  
  257.    /* We can't map texture storage directly */
  258.    if (usage & PIPE_TRANSFER_MAP_DIRECTLY)
  259.       return NULL;
  260.  
  261.    st = CALLOC_STRUCT(svga_transfer);
  262.    if (!st)
  263.       return NULL;
  264.  
  265.    st->base.resource = texture;
  266.    st->base.level = level;
  267.    st->base.usage = usage;
  268.    st->base.box = *box;
  269.    st->base.stride = nblocksx*util_format_get_blocksize(texture->format);
  270.    st->base.layer_stride = st->base.stride * nblocksy;
  271.  
  272.    st->hw_nblocksy = nblocksy;
  273.  
  274.    st->hwbuf = svga_winsys_buffer_create(svga,
  275.                                          1,
  276.                                          0,
  277.                                          st->hw_nblocksy * st->base.stride * box->depth);
  278.    while(!st->hwbuf && (st->hw_nblocksy /= 2)) {
  279.       st->hwbuf = svga_winsys_buffer_create(svga,
  280.                                             1,
  281.                                             0,
  282.                                             st->hw_nblocksy * st->base.stride * box->depth);
  283.    }
  284.  
  285.    if(!st->hwbuf)
  286.       goto no_hwbuf;
  287.  
  288.    if(st->hw_nblocksy < nblocksy) {
  289.       /* We couldn't allocate a hardware buffer big enough for the transfer,
  290.        * so allocate regular malloc memory instead */
  291.       if (0) {
  292.          debug_printf("%s: failed to allocate %u KB of DMA, "
  293.                       "splitting into %u x %u KB DMA transfers\n",
  294.                       __FUNCTION__,
  295.                       (nblocksy*st->base.stride + 1023)/1024,
  296.                       (nblocksy + st->hw_nblocksy - 1)/st->hw_nblocksy,
  297.                       (st->hw_nblocksy*st->base.stride + 1023)/1024);
  298.       }
  299.  
  300.       st->swbuf = MALLOC(nblocksy*st->base.stride);
  301.       if(!st->swbuf)
  302.          goto no_swbuf;
  303.    }
  304.  
  305.    if (usage & PIPE_TRANSFER_READ) {
  306.       SVGA3dSurfaceDMAFlags flags;
  307.       memset(&flags, 0, sizeof flags);
  308.       svga_transfer_dma(svga, st, SVGA3D_READ_HOST_VRAM, flags);
  309.    }
  310.  
  311.    if (st->swbuf) {
  312.       *ptransfer = &st->base;
  313.       return st->swbuf;
  314.    } else {
  315.       /* The wait for read transfers already happened when svga_transfer_dma
  316.        * was called. */
  317.       void *map = sws->buffer_map(sws, st->hwbuf, usage);
  318.       if (!map)
  319.          goto fail;
  320.  
  321.       *ptransfer = &st->base;
  322.       return map;
  323.    }
  324.  
  325. fail:
  326.    FREE(st->swbuf);
  327. no_swbuf:
  328.    sws->buffer_destroy(sws, st->hwbuf);
  329. no_hwbuf:
  330.    FREE(st);
  331.    return NULL;
  332. }
  333.  
  334.  
  335. /* XXX: Still implementing this as if it was a screen function, but
  336.  * can now modify it to queue transfers on the context.
  337.  */
  338. static void
  339. svga_texture_transfer_unmap(struct pipe_context *pipe,
  340.                             struct pipe_transfer *transfer)
  341. {
  342.    struct svga_context *svga = svga_context(pipe);
  343.    struct svga_screen *ss = svga_screen(pipe->screen);
  344.    struct svga_winsys_screen *sws = ss->sws;
  345.    struct svga_transfer *st = svga_transfer(transfer);
  346.    struct svga_texture *tex = svga_texture(transfer->resource);
  347.  
  348.    if(!st->swbuf)
  349.       sws->buffer_unmap(sws, st->hwbuf);
  350.  
  351.    if (st->base.usage & PIPE_TRANSFER_WRITE) {
  352.       SVGA3dSurfaceDMAFlags flags;
  353.  
  354.       memset(&flags, 0, sizeof flags);
  355.       if (transfer->usage & PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE) {
  356.          flags.discard = TRUE;
  357.       }
  358.       if (transfer->usage & PIPE_TRANSFER_UNSYNCHRONIZED) {
  359.          flags.unsynchronized = TRUE;
  360.       }
  361.  
  362.       svga_transfer_dma(svga, st, SVGA3D_WRITE_HOST_VRAM, flags);
  363.       ss->texture_timestamp++;
  364.       svga_age_texture_view(tex, transfer->level);
  365.       if (transfer->resource->target == PIPE_TEXTURE_CUBE)
  366.          svga_define_texture_level(tex, transfer->box.z, transfer->level);
  367.       else
  368.          svga_define_texture_level(tex, 0, transfer->level);
  369.    }
  370.  
  371.    FREE(st->swbuf);
  372.    sws->buffer_destroy(sws, st->hwbuf);
  373.    FREE(st);
  374. }
  375.  
  376.  
  377. struct u_resource_vtbl svga_texture_vtbl =
  378. {
  379.    svga_texture_get_handle,           /* get_handle */
  380.    svga_texture_destroy,              /* resource_destroy */
  381.    svga_texture_transfer_map,         /* transfer_map */
  382.    u_default_transfer_flush_region,   /* transfer_flush_region */
  383.    svga_texture_transfer_unmap,       /* transfer_unmap */
  384.    u_default_transfer_inline_write    /* transfer_inline_write */
  385. };
  386.  
  387.  
  388. struct pipe_resource *
  389. svga_texture_create(struct pipe_screen *screen,
  390.                     const struct pipe_resource *template)
  391. {
  392.    struct svga_screen *svgascreen = svga_screen(screen);
  393.    struct svga_texture *tex = CALLOC_STRUCT(svga_texture);
  394.  
  395.    if (!tex)
  396.       goto error1;
  397.  
  398.    tex->b.b = *template;
  399.    tex->b.vtbl = &svga_texture_vtbl;
  400.    pipe_reference_init(&tex->b.b.reference, 1);
  401.    tex->b.b.screen = screen;
  402.  
  403.    assert(template->last_level < SVGA_MAX_TEXTURE_LEVELS);
  404.    if(template->last_level >= SVGA_MAX_TEXTURE_LEVELS)
  405.       goto error2;
  406.    
  407.    tex->key.flags = 0;
  408.    tex->key.size.width = template->width0;
  409.    tex->key.size.height = template->height0;
  410.    tex->key.size.depth = template->depth0;
  411.  
  412.    if(template->target == PIPE_TEXTURE_CUBE) {
  413.       tex->key.flags |= SVGA3D_SURFACE_CUBEMAP;
  414.       tex->key.numFaces = 6;
  415.    }
  416.    else {
  417.       tex->key.numFaces = 1;
  418.    }
  419.  
  420.    if (template->target == PIPE_TEXTURE_3D) {
  421.       tex->key.flags |= SVGA3D_SURFACE_HINT_VOLUME;
  422.    }
  423.  
  424.    tex->key.cachable = 1;
  425.  
  426.    if (template->bind & PIPE_BIND_SAMPLER_VIEW)
  427.       tex->key.flags |= SVGA3D_SURFACE_HINT_TEXTURE;
  428.  
  429.    if (template->bind & PIPE_BIND_DISPLAY_TARGET) {
  430.       tex->key.cachable = 0;
  431.    }
  432.  
  433.    if (template->bind & PIPE_BIND_SHARED) {
  434.       tex->key.cachable = 0;
  435.    }
  436.  
  437.    if (template->bind & (PIPE_BIND_SCANOUT |
  438.                          PIPE_BIND_CURSOR)) {
  439.       tex->key.flags |= SVGA3D_SURFACE_HINT_SCANOUT;
  440.       tex->key.cachable = 0;
  441.    }
  442.  
  443.    /*
  444.     * Note: Previously we never passed the
  445.     * SVGA3D_SURFACE_HINT_RENDERTARGET hint. Mesa cannot
  446.     * know beforehand whether a texture will be used as a rendertarget or not
  447.     * and it always requests PIPE_BIND_RENDER_TARGET, therefore
  448.     * passing the SVGA3D_SURFACE_HINT_RENDERTARGET here defeats its purpose.
  449.     *
  450.     * However, this was changed since other state trackers
  451.     * (XA for example) uses it accurately and certain device versions
  452.     * relies on it in certain situations to render correctly.
  453.     */
  454.    if((template->bind & PIPE_BIND_RENDER_TARGET) &&
  455.       !util_format_is_s3tc(template->format))
  456.       tex->key.flags |= SVGA3D_SURFACE_HINT_RENDERTARGET;
  457.    
  458.    if(template->bind & PIPE_BIND_DEPTH_STENCIL)
  459.       tex->key.flags |= SVGA3D_SURFACE_HINT_DEPTHSTENCIL;
  460.    
  461.    tex->key.numMipLevels = template->last_level + 1;
  462.    
  463.    tex->key.format = svga_translate_format(svgascreen, template->format, template->bind);
  464.    if(tex->key.format == SVGA3D_FORMAT_INVALID)
  465.       goto error2;
  466.  
  467.    SVGA_DBG(DEBUG_DMA, "surface_create for texture\n", tex->handle);
  468.    tex->handle = svga_screen_surface_create(svgascreen, &tex->key);
  469.    if (tex->handle)
  470.       SVGA_DBG(DEBUG_DMA, "  --> got sid %p (texture)\n", tex->handle);
  471.  
  472.    debug_reference(&tex->b.b.reference,
  473.                    (debug_reference_descriptor)debug_describe_resource, 0);
  474.  
  475.    tex->size = util_resource_size(template);
  476.    svgascreen->total_resource_bytes += tex->size;
  477.  
  478.    return &tex->b.b;
  479.  
  480. error2:
  481.    FREE(tex);
  482. error1:
  483.    return NULL;
  484. }
  485.  
  486.  
  487. struct pipe_resource *
  488. svga_texture_from_handle(struct pipe_screen *screen,
  489.                          const struct pipe_resource *template,
  490.                          struct winsys_handle *whandle)
  491. {
  492.    struct svga_winsys_screen *sws = svga_winsys_screen(screen);
  493.    struct svga_winsys_surface *srf;
  494.    struct svga_texture *tex;
  495.    enum SVGA3dSurfaceFormat format = 0;
  496.    assert(screen);
  497.  
  498.    /* Only supports one type */
  499.    if ((template->target != PIPE_TEXTURE_2D &&
  500.        template->target != PIPE_TEXTURE_RECT) ||
  501.        template->last_level != 0 ||
  502.        template->depth0 != 1) {
  503.       return NULL;
  504.    }
  505.  
  506.    srf = sws->surface_from_handle(sws, whandle, &format);
  507.  
  508.    if (!srf)
  509.       return NULL;
  510.  
  511.    if (svga_translate_format(svga_screen(screen), template->format, template->bind) != format) {
  512.       unsigned f1 = svga_translate_format(svga_screen(screen), template->format, template->bind);
  513.       unsigned f2 = format;
  514.  
  515.       /* It's okay for XRGB and ARGB or depth with/out stencil to get mixed up */
  516.       if ( !( (f1 == SVGA3D_X8R8G8B8 && f2 == SVGA3D_A8R8G8B8) ||
  517.               (f1 == SVGA3D_A8R8G8B8 && f2 == SVGA3D_X8R8G8B8) ||
  518.               (f1 == SVGA3D_Z_D24X8 && f2 == SVGA3D_Z_D24S8) ||
  519.               (f1 == SVGA3D_Z_DF24 && f2 == SVGA3D_Z_D24S8_INT) ) ) {
  520.          debug_printf("%s wrong format %u != %u\n", __FUNCTION__, f1, f2);
  521.          return NULL;
  522.       }
  523.    }
  524.  
  525.    tex = CALLOC_STRUCT(svga_texture);
  526.    if (!tex)
  527.       return NULL;
  528.  
  529.    tex->b.b = *template;
  530.    tex->b.vtbl = &svga_texture_vtbl;
  531.    pipe_reference_init(&tex->b.b.reference, 1);
  532.    tex->b.b.screen = screen;
  533.  
  534.    SVGA_DBG(DEBUG_DMA, "wrap surface sid %p\n", srf);
  535.  
  536.    tex->key.cachable = 0;
  537.    tex->handle = srf;
  538.  
  539.    return &tex->b.b;
  540. }
  541.