Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | Download | 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.  
  48.    struct pipe_resource *buffer;   /* Upload buffer. */
  49.    struct pipe_transfer *transfer; /* Transfer object for the upload buffer. */
  50.    uint8_t *map;    /* Pointer to the mapped upload buffer. */
  51.    unsigned size;   /* Actual size of the upload buffer. */
  52.    unsigned offset; /* Aligned offset to the upload buffer, pointing
  53.                      * at the first unused byte. */
  54. };
  55.  
  56.  
  57. struct u_upload_mgr *u_upload_create( struct pipe_context *pipe,
  58.                                       unsigned default_size,
  59.                                       unsigned alignment,
  60.                                       unsigned bind )
  61. {
  62.    struct u_upload_mgr *upload = CALLOC_STRUCT( u_upload_mgr );
  63.    if (!upload)
  64.       return NULL;
  65.  
  66.    upload->pipe = pipe;
  67.    upload->default_size = default_size;
  68.    upload->alignment = alignment;
  69.    upload->bind = bind;
  70.    upload->buffer = NULL;
  71.  
  72.    return upload;
  73. }
  74.  
  75. void u_upload_unmap( struct u_upload_mgr *upload )
  76. {
  77.    if (upload->transfer) {
  78.       struct pipe_box *box = &upload->transfer->box;
  79.       if ((int) upload->offset > box->x) {
  80.  
  81.          pipe_buffer_flush_mapped_range(upload->pipe, upload->transfer,
  82.                                         box->x, upload->offset - box->x);
  83.       }
  84.       pipe_transfer_unmap(upload->pipe, upload->transfer);
  85.       upload->transfer = NULL;
  86.       upload->map = NULL;
  87.    }
  88. }
  89.  
  90. /* Release old buffer.
  91.  *
  92.  * This must usually be called prior to firing the command stream
  93.  * which references the upload buffer, as many memory managers will
  94.  * cause subsequent maps of a fired buffer to wait.
  95.  *
  96.  * Can improve this with a change to pipe_buffer_write to use the
  97.  * DONT_WAIT bit, but for now, it's easiest just to grab a new buffer.
  98.  */
  99. void u_upload_flush( struct u_upload_mgr *upload )
  100. {
  101.    /* Unmap and unreference the upload buffer. */
  102.    u_upload_unmap(upload);
  103.    pipe_resource_reference( &upload->buffer, NULL );
  104.    upload->size = 0;
  105. }
  106.  
  107.  
  108. void u_upload_destroy( struct u_upload_mgr *upload )
  109. {
  110.    u_upload_flush( upload );
  111.    FREE( upload );
  112. }
  113.  
  114.  
  115. static enum pipe_error
  116. u_upload_alloc_buffer( struct u_upload_mgr *upload,
  117.                        unsigned min_size )
  118. {
  119.    unsigned size;
  120.  
  121.    /* Release the old buffer, if present:
  122.     */
  123.    u_upload_flush( upload );
  124.  
  125.    /* Allocate a new one:
  126.     */
  127.    size = align(MAX2(upload->default_size, min_size), 4096);
  128.  
  129.    upload->buffer = pipe_buffer_create( upload->pipe->screen,
  130.                                         upload->bind,
  131.                                         PIPE_USAGE_STREAM,
  132.                                         size );
  133.    if (upload->buffer == NULL) {
  134.       return PIPE_ERROR_OUT_OF_MEMORY;
  135.    }
  136.  
  137.    /* Map the new buffer. */
  138.    upload->map = pipe_buffer_map_range(upload->pipe, upload->buffer,
  139.                                        0, size,
  140.                                        PIPE_TRANSFER_WRITE |
  141.                                        PIPE_TRANSFER_FLUSH_EXPLICIT,
  142.                                        &upload->transfer);
  143.    if (upload->map == NULL) {
  144.       upload->transfer = NULL;
  145.       upload->size = 0;
  146.       pipe_resource_reference(&upload->buffer, NULL);
  147.       return PIPE_ERROR_OUT_OF_MEMORY;
  148.    }
  149.  
  150.    upload->size = size;
  151.    upload->offset = 0;
  152.    return PIPE_OK;
  153. }
  154.  
  155. enum pipe_error u_upload_alloc( struct u_upload_mgr *upload,
  156.                                 unsigned min_out_offset,
  157.                                 unsigned size,
  158.                                 unsigned *out_offset,
  159.                                 struct pipe_resource **outbuf,
  160.                                 void **ptr )
  161. {
  162.    unsigned alloc_size = align( size, upload->alignment );
  163.    unsigned alloc_offset = align(min_out_offset, upload->alignment);
  164.    unsigned offset;
  165.  
  166.    /* Init these return values here in case we fail below to make
  167.     * sure the caller doesn't get garbage values.
  168.     */
  169.    *out_offset = ~0;
  170.    pipe_resource_reference(outbuf, NULL);
  171.    *ptr = NULL;
  172.  
  173.    /* Make sure we have enough space in the upload buffer
  174.     * for the sub-allocation. */
  175.    if (MAX2(upload->offset, alloc_offset) + alloc_size > upload->size) {
  176.       enum pipe_error ret = u_upload_alloc_buffer(upload,
  177.                                                   alloc_offset + alloc_size);
  178.       if (ret != PIPE_OK)
  179.          return ret;
  180.    }
  181.  
  182.    offset = MAX2(upload->offset, alloc_offset);
  183.  
  184.    if (!upload->map) {
  185.       upload->map = pipe_buffer_map_range(upload->pipe, upload->buffer,
  186.                                           offset, upload->size - offset,
  187.                                           PIPE_TRANSFER_WRITE |
  188.                                           PIPE_TRANSFER_FLUSH_EXPLICIT |
  189.                                           PIPE_TRANSFER_UNSYNCHRONIZED,
  190.                                           &upload->transfer);
  191.       if (!upload->map) {
  192.          upload->transfer = NULL;
  193.          return PIPE_ERROR_OUT_OF_MEMORY;
  194.       }
  195.  
  196.       upload->map -= offset;
  197.    }
  198.  
  199.    assert(offset < upload->buffer->width0);
  200.    assert(offset + size <= upload->buffer->width0);
  201.    assert(size);
  202.  
  203.    /* Emit the return values: */
  204.    *ptr = upload->map + offset;
  205.    pipe_resource_reference( outbuf, upload->buffer );
  206.    *out_offset = offset;
  207.  
  208.    upload->offset = offset + alloc_size;
  209.    return PIPE_OK;
  210. }
  211.  
  212. enum pipe_error u_upload_data( struct u_upload_mgr *upload,
  213.                                unsigned min_out_offset,
  214.                                unsigned size,
  215.                                const void *data,
  216.                                unsigned *out_offset,
  217.                                struct pipe_resource **outbuf)
  218. {
  219.    uint8_t *ptr;
  220.    enum pipe_error ret = u_upload_alloc(upload, min_out_offset, size,
  221.                                         out_offset, outbuf,
  222.                                         (void**)&ptr);
  223.    if (ret != PIPE_OK)
  224.       return ret;
  225.  
  226.    memcpy(ptr, data, size);
  227.    return PIPE_OK;
  228. }
  229.  
  230.  
  231. /* As above, but upload the full contents of a buffer.  Useful for
  232.  * uploading user buffers, avoids generating an explosion of GPU
  233.  * buffers if you have an app that does lots of small vertex buffer
  234.  * renders or DrawElements calls.
  235.  */
  236. enum pipe_error u_upload_buffer( struct u_upload_mgr *upload,
  237.                                  unsigned min_out_offset,
  238.                                  unsigned offset,
  239.                                  unsigned size,
  240.                                  struct pipe_resource *inbuf,
  241.                                  unsigned *out_offset,
  242.                                  struct pipe_resource **outbuf)
  243. {
  244.    enum pipe_error ret = PIPE_OK;
  245.    struct pipe_transfer *transfer = NULL;
  246.    const char *map = NULL;
  247.  
  248.    map = (const char *)pipe_buffer_map_range(upload->pipe,
  249.                                              inbuf,
  250.                                              offset, size,
  251.                                              PIPE_TRANSFER_READ,
  252.                                              &transfer);
  253.  
  254.    if (map == NULL) {
  255.       return PIPE_ERROR_OUT_OF_MEMORY;
  256.    }
  257.  
  258.    if (0)
  259.       debug_printf("upload ptr %p ofs %d sz %d\n", map, offset, size);
  260.  
  261.    ret = u_upload_data( upload,
  262.                         min_out_offset,
  263.                         size,
  264.                         map,
  265.                         out_offset,
  266.                         outbuf);
  267.  
  268.    pipe_buffer_unmap( upload->pipe, transfer );
  269.  
  270.    return ret;
  271. }
  272.