Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /**************************************************************************
  2.  *
  3.  * Copyright 2009 VMware, Inc.
  4.  * All Rights Reserved.
  5.  *
  6.  * Permission is hereby granted, free of charge, to any person obtaining a
  7.  * copy of this software and associated documentation files (the
  8.  * "Software"), to deal in the Software without restriction, including
  9.  * without limitation the rights to use, copy, modify, merge, publish,
  10.  * distribute, sub license, and/or sell copies of the Software, and to
  11.  * permit persons to whom the Software is furnished to do so, subject to
  12.  * the following conditions:
  13.  *
  14.  * The above copyright notice and this permission notice (including the
  15.  * next paragraph) shall be included in all copies or substantial portions
  16.  * of the Software.
  17.  *
  18.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  19.  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  20.  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
  21.  * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
  22.  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
  23.  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
  24.  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  25.  *
  26.  **************************************************************************/
  27.  
  28. /* Helper utility for uploading user buffers & other data, and
  29.  * coalescing small buffers into larger ones.
  30.  */
  31.  
  32. #include "pipe/p_defines.h"
  33. #include "util/u_inlines.h"
  34. #include "pipe/p_context.h"
  35. #include "util/u_memory.h"
  36. #include "util/u_math.h"
  37.  
  38. #include "u_upload_mgr.h"
  39.  
  40.  
  41. struct u_upload_mgr {
  42.    struct pipe_context *pipe;
  43.  
  44.    unsigned default_size;  /* Minimum size of the upload buffer, in bytes. */
  45.    unsigned alignment;     /* Alignment of each sub-allocation. */
  46.    unsigned bind;          /* Bitmask of PIPE_BIND_* flags. */
  47.    unsigned map_flags;     /* Bitmask of PIPE_TRANSFER_* flags. */
  48.    boolean map_persistent; /* If persistent mappings are supported. */
  49.  
  50.    struct pipe_resource *buffer;   /* Upload buffer. */
  51.    struct pipe_transfer *transfer; /* Transfer object for the upload buffer. */
  52.    uint8_t *map;    /* Pointer to the mapped upload buffer. */
  53.    unsigned offset; /* Aligned offset to the upload buffer, pointing
  54.                      * at the first unused byte. */
  55. };
  56.  
  57.  
  58. struct u_upload_mgr *u_upload_create( struct pipe_context *pipe,
  59.                                       unsigned default_size,
  60.                                       unsigned alignment,
  61.                                       unsigned bind )
  62. {
  63.    struct u_upload_mgr *upload = CALLOC_STRUCT( u_upload_mgr );
  64.    if (!upload)
  65.       return NULL;
  66.  
  67.    upload->pipe = pipe;
  68.    upload->default_size = default_size;
  69.    upload->alignment = alignment;
  70.    upload->bind = bind;
  71.  
  72.    upload->map_persistent =
  73.       pipe->screen->get_param(pipe->screen,
  74.                               PIPE_CAP_BUFFER_MAP_PERSISTENT_COHERENT);
  75.  
  76.    if (upload->map_persistent) {
  77.       upload->map_flags = PIPE_TRANSFER_WRITE |
  78.                           PIPE_TRANSFER_PERSISTENT |
  79.                           PIPE_TRANSFER_COHERENT;
  80.    }
  81.    else {
  82.       upload->map_flags = PIPE_TRANSFER_WRITE |
  83.                           PIPE_TRANSFER_UNSYNCHRONIZED |
  84.                           PIPE_TRANSFER_FLUSH_EXPLICIT;
  85.    }
  86.  
  87.    return upload;
  88. }
  89.  
  90.  
  91. static void upload_unmap_internal(struct u_upload_mgr *upload, boolean destroying)
  92. {
  93.    if (!destroying && upload->map_persistent)
  94.       return;
  95.  
  96.    if (upload->transfer) {
  97.       struct pipe_box *box = &upload->transfer->box;
  98.  
  99.       if (!upload->map_persistent && (int) upload->offset > box->x) {
  100.          pipe_buffer_flush_mapped_range(upload->pipe, upload->transfer,
  101.                                         box->x, upload->offset - box->x);
  102.       }
  103.  
  104.       pipe_transfer_unmap(upload->pipe, upload->transfer);
  105.       upload->transfer = NULL;
  106.       upload->map = NULL;
  107.    }
  108. }
  109.  
  110.  
  111. void u_upload_unmap( struct u_upload_mgr *upload )
  112. {
  113.    upload_unmap_internal(upload, FALSE);
  114. }
  115.  
  116.  
  117. static void u_upload_release_buffer(struct u_upload_mgr *upload)
  118. {
  119.    /* Unmap and unreference the upload buffer. */
  120.    upload_unmap_internal(upload, TRUE);
  121.    pipe_resource_reference( &upload->buffer, NULL );
  122. }
  123.  
  124.  
  125. void u_upload_destroy( struct u_upload_mgr *upload )
  126. {
  127.    u_upload_release_buffer( upload );
  128.    FREE( upload );
  129. }
  130.  
  131.  
  132. static enum pipe_error
  133. u_upload_alloc_buffer( struct u_upload_mgr *upload,
  134.                        unsigned min_size )
  135. {
  136.    struct pipe_screen *screen = upload->pipe->screen;
  137.    struct pipe_resource buffer;
  138.    unsigned size;
  139.  
  140.    /* Release the old buffer, if present:
  141.     */
  142.    u_upload_release_buffer( upload );
  143.  
  144.    /* Allocate a new one:
  145.     */
  146.    size = align(MAX2(upload->default_size, min_size), 4096);
  147.  
  148.    memset(&buffer, 0, sizeof buffer);
  149.    buffer.target = PIPE_BUFFER;
  150.    buffer.format = PIPE_FORMAT_R8_UNORM; /* want TYPELESS or similar */
  151.    buffer.bind = upload->bind;
  152.    buffer.usage = PIPE_USAGE_STREAM;
  153.    buffer.width0 = size;
  154.    buffer.height0 = 1;
  155.    buffer.depth0 = 1;
  156.    buffer.array_size = 1;
  157.  
  158.    if (upload->map_persistent) {
  159.       buffer.flags = PIPE_RESOURCE_FLAG_MAP_PERSISTENT |
  160.                      PIPE_RESOURCE_FLAG_MAP_COHERENT;
  161.    }
  162.  
  163.    upload->buffer = screen->resource_create(screen, &buffer);
  164.    if (upload->buffer == NULL) {
  165.       return PIPE_ERROR_OUT_OF_MEMORY;
  166.    }
  167.  
  168.    /* Map the new buffer. */
  169.    upload->map = pipe_buffer_map_range(upload->pipe, upload->buffer,
  170.                                        0, size, upload->map_flags,
  171.                                        &upload->transfer);
  172.    if (upload->map == NULL) {
  173.       upload->transfer = NULL;
  174.       pipe_resource_reference(&upload->buffer, NULL);
  175.       return PIPE_ERROR_OUT_OF_MEMORY;
  176.    }
  177.  
  178.    upload->offset = 0;
  179.    return PIPE_OK;
  180. }
  181.  
  182. enum pipe_error u_upload_alloc( struct u_upload_mgr *upload,
  183.                                 unsigned min_out_offset,
  184.                                 unsigned size,
  185.                                 unsigned *out_offset,
  186.                                 struct pipe_resource **outbuf,
  187.                                 void **ptr )
  188. {
  189.    unsigned alloc_size = align( size, upload->alignment );
  190.    unsigned alloc_offset = align(min_out_offset, upload->alignment);
  191.    unsigned offset;
  192.  
  193.    /* Init these return values here in case we fail below to make
  194.     * sure the caller doesn't get garbage values.
  195.     */
  196.    *out_offset = ~0;
  197.    pipe_resource_reference(outbuf, NULL);
  198.    *ptr = NULL;
  199.  
  200.    /* Make sure we have enough space in the upload buffer
  201.     * for the sub-allocation. */
  202.    if (!upload->buffer ||
  203.        MAX2(upload->offset, alloc_offset) + alloc_size > upload->buffer->width0) {
  204.       enum pipe_error ret = u_upload_alloc_buffer(upload,
  205.                                                   alloc_offset + alloc_size);
  206.       if (ret != PIPE_OK)
  207.          return ret;
  208.    }
  209.  
  210.    offset = MAX2(upload->offset, alloc_offset);
  211.  
  212.    if (!upload->map) {
  213.       upload->map = pipe_buffer_map_range(upload->pipe, upload->buffer,
  214.                                           offset,
  215.                                           upload->buffer->width0 - offset,
  216.                                           upload->map_flags,
  217.                                           &upload->transfer);
  218.       if (!upload->map) {
  219.          upload->transfer = NULL;
  220.          return PIPE_ERROR_OUT_OF_MEMORY;
  221.       }
  222.  
  223.       upload->map -= offset;
  224.    }
  225.  
  226.    assert(offset < upload->buffer->width0);
  227.    assert(offset + size <= upload->buffer->width0);
  228.    assert(size);
  229.  
  230.    /* Emit the return values: */
  231.    *ptr = upload->map + offset;
  232.    pipe_resource_reference( outbuf, upload->buffer );
  233.    *out_offset = offset;
  234.  
  235.    upload->offset = offset + alloc_size;
  236.    return PIPE_OK;
  237. }
  238.  
  239. enum pipe_error u_upload_data( struct u_upload_mgr *upload,
  240.                                unsigned min_out_offset,
  241.                                unsigned size,
  242.                                const void *data,
  243.                                unsigned *out_offset,
  244.                                struct pipe_resource **outbuf)
  245. {
  246.    uint8_t *ptr;
  247.    enum pipe_error ret = u_upload_alloc(upload, min_out_offset, size,
  248.                                         out_offset, outbuf,
  249.                                         (void**)&ptr);
  250.    if (ret != PIPE_OK)
  251.       return ret;
  252.  
  253.    memcpy(ptr, data, size);
  254.    return PIPE_OK;
  255. }
  256.  
  257.  
  258. /* As above, but upload the full contents of a buffer.  Useful for
  259.  * uploading user buffers, avoids generating an explosion of GPU
  260.  * buffers if you have an app that does lots of small vertex buffer
  261.  * renders or DrawElements calls.
  262.  */
  263. enum pipe_error u_upload_buffer( struct u_upload_mgr *upload,
  264.                                  unsigned min_out_offset,
  265.                                  unsigned offset,
  266.                                  unsigned size,
  267.                                  struct pipe_resource *inbuf,
  268.                                  unsigned *out_offset,
  269.                                  struct pipe_resource **outbuf)
  270. {
  271.    enum pipe_error ret = PIPE_OK;
  272.    struct pipe_transfer *transfer = NULL;
  273.    const char *map = NULL;
  274.  
  275.    map = (const char *)pipe_buffer_map_range(upload->pipe,
  276.                                              inbuf,
  277.                                              offset, size,
  278.                                              PIPE_TRANSFER_READ,
  279.                                              &transfer);
  280.  
  281.    if (map == NULL) {
  282.       return PIPE_ERROR_OUT_OF_MEMORY;
  283.    }
  284.  
  285.    if (0)
  286.       debug_printf("upload ptr %p ofs %d sz %d\n", map, offset, size);
  287.  
  288.    ret = u_upload_data( upload,
  289.                         min_out_offset,
  290.                         size,
  291.                         map,
  292.                         out_offset,
  293.                         outbuf);
  294.  
  295.    pipe_buffer_unmap( upload->pipe, transfer );
  296.  
  297.    return ret;
  298. }
  299.