Home | History | Annotate | Download | only in state_tracker
      1 /**************************************************************************
      2  *
      3  * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
      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 TUNGSTEN GRAPHICS 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 
     29 /**
     30  * Functions for pixel buffer objects and vertex/element buffer objects.
     31  */
     32 
     33 
     34 #include "main/imports.h"
     35 #include "main/mtypes.h"
     36 #include "main/arrayobj.h"
     37 #include "main/bufferobj.h"
     38 
     39 #include "st_context.h"
     40 #include "st_cb_bufferobjects.h"
     41 
     42 #include "pipe/p_context.h"
     43 #include "pipe/p_defines.h"
     44 #include "util/u_inlines.h"
     45 
     46 
     47 /**
     48  * There is some duplication between mesa's bufferobjects and our
     49  * bufmgr buffers.  Both have an integer handle and a hashtable to
     50  * lookup an opaque structure.  It would be nice if the handles and
     51  * internal structure where somehow shared.
     52  */
     53 static struct gl_buffer_object *
     54 st_bufferobj_alloc(struct gl_context *ctx, GLuint name, GLenum target)
     55 {
     56    struct st_buffer_object *st_obj = ST_CALLOC_STRUCT(st_buffer_object);
     57 
     58    if (!st_obj)
     59       return NULL;
     60 
     61    _mesa_initialize_buffer_object(ctx, &st_obj->Base, name, target);
     62 
     63    return &st_obj->Base;
     64 }
     65 
     66 
     67 
     68 /**
     69  * Deallocate/free a vertex/pixel buffer object.
     70  * Called via glDeleteBuffersARB().
     71  */
     72 static void
     73 st_bufferobj_free(struct gl_context *ctx, struct gl_buffer_object *obj)
     74 {
     75    struct st_buffer_object *st_obj = st_buffer_object(obj);
     76 
     77    assert(obj->RefCount == 0);
     78    assert(st_obj->transfer == NULL);
     79 
     80    if (st_obj->buffer)
     81       pipe_resource_reference(&st_obj->buffer, NULL);
     82 
     83    free(st_obj);
     84 }
     85 
     86 
     87 
     88 /**
     89  * Replace data in a subrange of buffer object.  If the data range
     90  * specified by size + offset extends beyond the end of the buffer or
     91  * if data is NULL, no copy is performed.
     92  * Called via glBufferSubDataARB().
     93  */
     94 static void
     95 st_bufferobj_subdata(struct gl_context *ctx,
     96 		     GLintptrARB offset,
     97 		     GLsizeiptrARB size,
     98 		     const GLvoid * data, struct gl_buffer_object *obj)
     99 {
    100    struct st_buffer_object *st_obj = st_buffer_object(obj);
    101 
    102    /* we may be called from VBO code, so double-check params here */
    103    ASSERT(offset >= 0);
    104    ASSERT(size >= 0);
    105    ASSERT(offset + size <= obj->Size);
    106 
    107    if (!size)
    108       return;
    109 
    110    /*
    111     * According to ARB_vertex_buffer_object specification, if data is null,
    112     * then the contents of the buffer object's data store is undefined. We just
    113     * ignore, and leave it unchanged.
    114     */
    115    if (!data)
    116       return;
    117 
    118    if (!st_obj->buffer) {
    119       /* we probably ran out of memory during buffer allocation */
    120       return;
    121    }
    122 
    123    /* Now that transfers are per-context, we don't have to figure out
    124     * flushing here.  Usually drivers won't need to flush in this case
    125     * even if the buffer is currently referenced by hardware - they
    126     * just queue the upload as dma rather than mapping the underlying
    127     * buffer directly.
    128     */
    129    pipe_buffer_write(st_context(ctx)->pipe,
    130 		     st_obj->buffer,
    131 		     offset, size, data);
    132 }
    133 
    134 
    135 /**
    136  * Called via glGetBufferSubDataARB().
    137  */
    138 static void
    139 st_bufferobj_get_subdata(struct gl_context *ctx,
    140                          GLintptrARB offset,
    141                          GLsizeiptrARB size,
    142                          GLvoid * data, struct gl_buffer_object *obj)
    143 {
    144    struct st_buffer_object *st_obj = st_buffer_object(obj);
    145 
    146    /* we may be called from VBO code, so double-check params here */
    147    ASSERT(offset >= 0);
    148    ASSERT(size >= 0);
    149    ASSERT(offset + size <= obj->Size);
    150 
    151    if (!size)
    152       return;
    153 
    154    if (!st_obj->buffer) {
    155       /* we probably ran out of memory during buffer allocation */
    156       return;
    157    }
    158 
    159    pipe_buffer_read(st_context(ctx)->pipe, st_obj->buffer,
    160                     offset, size, data);
    161 }
    162 
    163 
    164 /**
    165  * Allocate space for and store data in a buffer object.  Any data that was
    166  * previously stored in the buffer object is lost.  If data is NULL,
    167  * memory will be allocated, but no copy will occur.
    168  * Called via ctx->Driver.BufferData().
    169  * \return GL_TRUE for success, GL_FALSE if out of memory
    170  */
    171 static GLboolean
    172 st_bufferobj_data(struct gl_context *ctx,
    173 		  GLenum target,
    174 		  GLsizeiptrARB size,
    175 		  const GLvoid * data,
    176 		  GLenum usage,
    177 		  struct gl_buffer_object *obj)
    178 {
    179    struct st_context *st = st_context(ctx);
    180    struct pipe_context *pipe = st->pipe;
    181    struct st_buffer_object *st_obj = st_buffer_object(obj);
    182    unsigned bind, pipe_usage;
    183 
    184    st_obj->Base.Size = size;
    185    st_obj->Base.Usage = usage;
    186 
    187    switch(target) {
    188    case GL_PIXEL_PACK_BUFFER_ARB:
    189    case GL_PIXEL_UNPACK_BUFFER_ARB:
    190       bind = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW;
    191       break;
    192    case GL_ARRAY_BUFFER_ARB:
    193       bind = PIPE_BIND_VERTEX_BUFFER;
    194       break;
    195    case GL_ELEMENT_ARRAY_BUFFER_ARB:
    196       bind = PIPE_BIND_INDEX_BUFFER;
    197       break;
    198    case GL_TRANSFORM_FEEDBACK_BUFFER:
    199       bind = PIPE_BIND_STREAM_OUTPUT;
    200       break;
    201    default:
    202       bind = 0;
    203    }
    204 
    205    switch (usage) {
    206    case GL_STATIC_DRAW:
    207    case GL_STATIC_READ:
    208    case GL_STATIC_COPY:
    209       pipe_usage = PIPE_USAGE_STATIC;
    210       break;
    211    case GL_DYNAMIC_DRAW:
    212    case GL_DYNAMIC_READ:
    213    case GL_DYNAMIC_COPY:
    214       pipe_usage = PIPE_USAGE_DYNAMIC;
    215       break;
    216    case GL_STREAM_DRAW:
    217    case GL_STREAM_READ:
    218    case GL_STREAM_COPY:
    219       pipe_usage = PIPE_USAGE_STREAM;
    220       break;
    221    default:
    222       pipe_usage = PIPE_USAGE_DEFAULT;
    223    }
    224 
    225    pipe_resource_reference( &st_obj->buffer, NULL );
    226 
    227    if (size != 0) {
    228       st_obj->buffer = pipe_buffer_create(pipe->screen, bind,
    229                                           pipe_usage, size);
    230 
    231       if (!st_obj->buffer) {
    232          /* out of memory */
    233          st_obj->Base.Size = 0;
    234          return GL_FALSE;
    235       }
    236 
    237       if (data)
    238          pipe_buffer_write(pipe, st_obj->buffer, 0, size, data);
    239       return GL_TRUE;
    240    }
    241 
    242    return GL_TRUE;
    243 }
    244 
    245 
    246 /**
    247  * Called via glMapBufferRange().
    248  */
    249 static void *
    250 st_bufferobj_map_range(struct gl_context *ctx,
    251                        GLintptr offset, GLsizeiptr length, GLbitfield access,
    252                        struct gl_buffer_object *obj)
    253 {
    254    struct pipe_context *pipe = st_context(ctx)->pipe;
    255    struct st_buffer_object *st_obj = st_buffer_object(obj);
    256    enum pipe_transfer_usage flags = 0x0;
    257 
    258    if (access & GL_MAP_WRITE_BIT)
    259       flags |= PIPE_TRANSFER_WRITE;
    260 
    261    if (access & GL_MAP_READ_BIT)
    262       flags |= PIPE_TRANSFER_READ;
    263 
    264    if (access & GL_MAP_FLUSH_EXPLICIT_BIT)
    265       flags |= PIPE_TRANSFER_FLUSH_EXPLICIT;
    266 
    267    if (access & GL_MAP_INVALIDATE_BUFFER_BIT) {
    268       flags |= PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE;
    269    }
    270    else if (access & GL_MAP_INVALIDATE_RANGE_BIT) {
    271       if (offset == 0 && length == obj->Size)
    272          flags |= PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE;
    273       else
    274          flags |= PIPE_TRANSFER_DISCARD_RANGE;
    275    }
    276 
    277    if (access & GL_MAP_UNSYNCHRONIZED_BIT)
    278       flags |= PIPE_TRANSFER_UNSYNCHRONIZED;
    279 
    280    /* ... other flags ...
    281     */
    282 
    283    if (access & MESA_MAP_NOWAIT_BIT)
    284       flags |= PIPE_TRANSFER_DONTBLOCK;
    285 
    286    assert(offset >= 0);
    287    assert(length >= 0);
    288    assert(offset < obj->Size);
    289    assert(offset + length <= obj->Size);
    290 
    291    obj->Pointer = pipe_buffer_map_range(pipe,
    292                                         st_obj->buffer,
    293                                         offset, length,
    294                                         flags,
    295                                         &st_obj->transfer);
    296    if (obj->Pointer) {
    297       obj->Offset = offset;
    298       obj->Length = length;
    299       obj->AccessFlags = access;
    300    }
    301 
    302    return obj->Pointer;
    303 }
    304 
    305 
    306 static void
    307 st_bufferobj_flush_mapped_range(struct gl_context *ctx,
    308                                 GLintptr offset, GLsizeiptr length,
    309                                 struct gl_buffer_object *obj)
    310 {
    311    struct pipe_context *pipe = st_context(ctx)->pipe;
    312    struct st_buffer_object *st_obj = st_buffer_object(obj);
    313 
    314    /* Subrange is relative to mapped range */
    315    assert(offset >= 0);
    316    assert(length >= 0);
    317    assert(offset + length <= obj->Length);
    318    assert(obj->Pointer);
    319 
    320    if (!length)
    321       return;
    322 
    323    pipe_buffer_flush_mapped_range(pipe, st_obj->transfer,
    324                                   obj->Offset + offset, length);
    325 }
    326 
    327 
    328 /**
    329  * Called via glUnmapBufferARB().
    330  */
    331 static GLboolean
    332 st_bufferobj_unmap(struct gl_context *ctx, struct gl_buffer_object *obj)
    333 {
    334    struct pipe_context *pipe = st_context(ctx)->pipe;
    335    struct st_buffer_object *st_obj = st_buffer_object(obj);
    336 
    337    if (obj->Length)
    338       pipe_buffer_unmap(pipe, st_obj->transfer);
    339 
    340    st_obj->transfer = NULL;
    341    obj->Pointer = NULL;
    342    obj->Offset = 0;
    343    obj->Length = 0;
    344    return GL_TRUE;
    345 }
    346 
    347 
    348 /**
    349  * Called via glCopyBufferSubData().
    350  */
    351 static void
    352 st_copy_buffer_subdata(struct gl_context *ctx,
    353                        struct gl_buffer_object *src,
    354                        struct gl_buffer_object *dst,
    355                        GLintptr readOffset, GLintptr writeOffset,
    356                        GLsizeiptr size)
    357 {
    358    struct pipe_context *pipe = st_context(ctx)->pipe;
    359    struct st_buffer_object *srcObj = st_buffer_object(src);
    360    struct st_buffer_object *dstObj = st_buffer_object(dst);
    361    struct pipe_box box;
    362 
    363    if(!size)
    364       return;
    365 
    366    /* buffer should not already be mapped */
    367    assert(!src->Pointer);
    368    assert(!dst->Pointer);
    369 
    370    u_box_1d(readOffset, size, &box);
    371 
    372    pipe->resource_copy_region(pipe, dstObj->buffer, 0, writeOffset, 0, 0,
    373                               srcObj->buffer, 0, &box);
    374 }
    375 
    376 
    377 /* TODO: if buffer wasn't created with appropriate usage flags, need
    378  * to recreate it now and copy contents -- or possibly create a
    379  * gallium entrypoint to extend the usage flags and let the driver
    380  * decide if a copy is necessary.
    381  */
    382 void
    383 st_bufferobj_validate_usage(struct st_context *st,
    384 			    struct st_buffer_object *obj,
    385 			    unsigned usage)
    386 {
    387 }
    388 
    389 
    390 void
    391 st_init_bufferobject_functions(struct dd_function_table *functions)
    392 {
    393    functions->NewBufferObject = st_bufferobj_alloc;
    394    functions->DeleteBuffer = st_bufferobj_free;
    395    functions->BufferData = st_bufferobj_data;
    396    functions->BufferSubData = st_bufferobj_subdata;
    397    functions->GetBufferSubData = st_bufferobj_get_subdata;
    398    functions->MapBufferRange = st_bufferobj_map_range;
    399    functions->FlushMappedBufferRange = st_bufferobj_flush_mapped_range;
    400    functions->UnmapBuffer = st_bufferobj_unmap;
    401    functions->CopyBufferSubData = st_copy_buffer_subdata;
    402 
    403    /* For GL_APPLE_vertex_array_object */
    404    functions->NewArrayObject = _mesa_new_array_object;
    405    functions->DeleteArrayObject = _mesa_delete_array_object;
    406 }
    407