Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * Mesa 3-D graphics library
  3.  * Version:  7.6
  4.  *
  5.  * Copyright (C) 1999-2008  Brian Paul   All Rights Reserved.
  6.  * Copyright (C) 2009  VMware, Inc.  All Rights Reserved.
  7.  *
  8.  * Permission is hereby granted, free of charge, to any person obtaining a
  9.  * copy of this software and associated documentation files (the "Software"),
  10.  * to deal in the Software without restriction, including without limitation
  11.  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  12.  * and/or sell copies of the Software, and to permit persons to whom the
  13.  * Software is furnished to do so, subject to the following conditions:
  14.  *
  15.  * The above copyright notice and this permission notice shall be included
  16.  * in all copies or substantial portions 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 MERCHANTABILITY,
  20.  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  21.  * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
  22.  * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  23.  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  24.  */
  25.  
  26.  
  27. /**
  28.  * \file bufferobj.c
  29.  * \brief Functions for the GL_ARB_vertex/pixel_buffer_object extensions.
  30.  * \author Brian Paul, Ian Romanick
  31.  */
  32.  
  33.  
  34. #include "glheader.h"
  35. #include "enums.h"
  36. #include "hash.h"
  37. #include "imports.h"
  38. #include "image.h"
  39. #include "context.h"
  40. #include "bufferobj.h"
  41. #include "fbobject.h"
  42. #include "texobj.h"
  43.  
  44.  
  45. /* Debug flags */
  46. /*#define VBO_DEBUG*/
  47. /*#define BOUNDS_CHECK*/
  48.  
  49.  
  50. #if FEATURE_OES_mapbuffer
  51. #define DEFAULT_ACCESS GL_MAP_WRITE_BIT
  52. #else
  53. #define DEFAULT_ACCESS (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)
  54. #endif
  55.  
  56.  
  57. /**
  58.  * Used as a placeholder for buffer objects between glGenBuffers() and
  59.  * glBindBuffer() so that glIsBuffer() can work correctly.
  60.  */
  61. static struct gl_buffer_object DummyBufferObject;
  62.  
  63.  
  64. /**
  65.  * Return pointer to address of a buffer object target.
  66.  * \param ctx  the GL context
  67.  * \param target  the buffer object target to be retrieved.
  68.  * \return   pointer to pointer to the buffer object bound to \c target in the
  69.  *           specified context or \c NULL if \c target is invalid.
  70.  */
  71. static INLINE struct gl_buffer_object **
  72. get_buffer_target(struct gl_context *ctx, GLenum target)
  73. {
  74.    switch (target) {
  75.    case GL_ARRAY_BUFFER_ARB:
  76.       return &ctx->Array.ArrayBufferObj;
  77.    case GL_ELEMENT_ARRAY_BUFFER_ARB:
  78.       return &ctx->Array.ElementArrayBufferObj;
  79.    case GL_PIXEL_PACK_BUFFER_EXT:
  80.       return &ctx->Pack.BufferObj;
  81.    case GL_PIXEL_UNPACK_BUFFER_EXT:
  82.       return &ctx->Unpack.BufferObj;
  83.    case GL_COPY_READ_BUFFER:
  84.       return &ctx->CopyReadBuffer;
  85.    case GL_COPY_WRITE_BUFFER:
  86.       return &ctx->CopyWriteBuffer;
  87. #if FEATURE_EXT_transform_feedback
  88.    case GL_TRANSFORM_FEEDBACK_BUFFER:
  89.       if (ctx->Extensions.EXT_transform_feedback) {
  90.          return &ctx->TransformFeedback.CurrentBuffer;
  91.       }
  92.       break;
  93. #endif
  94.    default:
  95.       return NULL;
  96.    }
  97.    return NULL;
  98. }
  99.  
  100.  
  101. /**
  102.  * Get the buffer object bound to the specified target in a GL context.
  103.  * \param ctx  the GL context
  104.  * \param target  the buffer object target to be retrieved.
  105.  * \return   pointer to the buffer object bound to \c target in the
  106.  *           specified context or \c NULL if \c target is invalid.
  107.  */
  108. static INLINE struct gl_buffer_object *
  109. get_buffer(struct gl_context *ctx, GLenum target)
  110. {
  111.    struct gl_buffer_object **bufObj = get_buffer_target(ctx, target);
  112.    if (bufObj)
  113.       return *bufObj;
  114.    return NULL;
  115. }
  116.  
  117.  
  118. /**
  119.  * Convert a GLbitfield describing the mapped buffer access flags
  120.  * into one of GL_READ_WRITE, GL_READ_ONLY, or GL_WRITE_ONLY.
  121.  */
  122. static GLenum
  123. simplified_access_mode(GLbitfield access)
  124. {
  125.    const GLbitfield rwFlags = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT;
  126.    if ((access & rwFlags) == rwFlags)
  127.       return GL_READ_WRITE;
  128.    if ((access & GL_MAP_READ_BIT) == GL_MAP_READ_BIT)
  129.       return GL_READ_ONLY;
  130.    if ((access & GL_MAP_WRITE_BIT) == GL_MAP_WRITE_BIT)
  131.       return GL_WRITE_ONLY;
  132.    return GL_READ_WRITE; /* this should never happen, but no big deal */
  133. }
  134.  
  135.  
  136. /**
  137.  * Tests the subdata range parameters and sets the GL error code for
  138.  * \c glBufferSubDataARB and \c glGetBufferSubDataARB.
  139.  *
  140.  * \param ctx     GL context.
  141.  * \param target  Buffer object target on which to operate.
  142.  * \param offset  Offset of the first byte of the subdata range.
  143.  * \param size    Size, in bytes, of the subdata range.
  144.  * \param caller  Name of calling function for recording errors.
  145.  * \return   A pointer to the buffer object bound to \c target in the
  146.  *           specified context or \c NULL if any of the parameter or state
  147.  *           conditions for \c glBufferSubDataARB or \c glGetBufferSubDataARB
  148.  *           are invalid.
  149.  *
  150.  * \sa glBufferSubDataARB, glGetBufferSubDataARB
  151.  */
  152. static struct gl_buffer_object *
  153. buffer_object_subdata_range_good( struct gl_context * ctx, GLenum target,
  154.                                   GLintptrARB offset, GLsizeiptrARB size,
  155.                                   const char *caller )
  156. {
  157.    struct gl_buffer_object *bufObj;
  158.  
  159.    if (size < 0) {
  160.       _mesa_error(ctx, GL_INVALID_VALUE, "%s(size < 0)", caller);
  161.       return NULL;
  162.    }
  163.  
  164.    if (offset < 0) {
  165.       _mesa_error(ctx, GL_INVALID_VALUE, "%s(offset < 0)", caller);
  166.       return NULL;
  167.    }
  168.  
  169.    bufObj = get_buffer(ctx, target);
  170.    if (!bufObj) {
  171.       _mesa_error(ctx, GL_INVALID_ENUM, "%s(target)", caller);
  172.       return NULL;
  173.    }
  174.    if (!_mesa_is_bufferobj(bufObj)) {
  175.       _mesa_error(ctx, GL_INVALID_OPERATION, "%s", caller);
  176.       return NULL;
  177.    }
  178.    if (offset + size > bufObj->Size) {
  179.       _mesa_error(ctx, GL_INVALID_VALUE,
  180.                   "%s(size + offset > buffer size)", caller);
  181.       return NULL;
  182.    }
  183.    if (_mesa_bufferobj_mapped(bufObj)) {
  184.       /* Buffer is currently mapped */
  185.       _mesa_error(ctx, GL_INVALID_OPERATION, "%s", caller);
  186.       return NULL;
  187.    }
  188.  
  189.    return bufObj;
  190. }
  191.  
  192.  
  193. /**
  194.  * Allocate and initialize a new buffer object.
  195.  *
  196.  * Default callback for the \c dd_function_table::NewBufferObject() hook.
  197.  */
  198. static struct gl_buffer_object *
  199. _mesa_new_buffer_object( struct gl_context *ctx, GLuint name, GLenum target )
  200. {
  201.    struct gl_buffer_object *obj;
  202.  
  203.    (void) ctx;
  204.  
  205.    obj = MALLOC_STRUCT(gl_buffer_object);
  206.    _mesa_initialize_buffer_object(obj, name, target);
  207.    return obj;
  208. }
  209.  
  210.  
  211. /**
  212.  * Delete a buffer object.
  213.  *
  214.  * Default callback for the \c dd_function_table::DeleteBuffer() hook.
  215.  */
  216. static void
  217. _mesa_delete_buffer_object( struct gl_context *ctx, struct gl_buffer_object *bufObj )
  218. {
  219.    (void) ctx;
  220.  
  221.    if (bufObj->Data)
  222.       free(bufObj->Data);
  223.  
  224.    /* assign strange values here to help w/ debugging */
  225.    bufObj->RefCount = -1000;
  226.    bufObj->Name = ~0;
  227.  
  228.    _glthread_DESTROY_MUTEX(bufObj->Mutex);
  229.    free(bufObj);
  230. }
  231.  
  232.  
  233.  
  234. /**
  235.  * Set ptr to bufObj w/ reference counting.
  236.  */
  237. void
  238. _mesa_reference_buffer_object(struct gl_context *ctx,
  239.                               struct gl_buffer_object **ptr,
  240.                               struct gl_buffer_object *bufObj)
  241. {
  242.    if (*ptr == bufObj)
  243.       return;
  244.  
  245.    if (*ptr) {
  246.       /* Unreference the old buffer */
  247.       GLboolean deleteFlag = GL_FALSE;
  248.       struct gl_buffer_object *oldObj = *ptr;
  249.  
  250.       _glthread_LOCK_MUTEX(oldObj->Mutex);
  251.       ASSERT(oldObj->RefCount > 0);
  252.       oldObj->RefCount--;
  253. #if 0
  254.       printf("BufferObj %p %d DECR to %d\n",
  255.              (void *) oldObj, oldObj->Name, oldObj->RefCount);
  256. #endif
  257.       deleteFlag = (oldObj->RefCount == 0);
  258.       _glthread_UNLOCK_MUTEX(oldObj->Mutex);
  259.  
  260.       if (deleteFlag) {
  261.  
  262.          /* some sanity checking: don't delete a buffer still in use */
  263. #if 0
  264.          /* unfortunately, these tests are invalid during context tear-down */
  265.          ASSERT(ctx->Array.ArrayBufferObj != bufObj);
  266.          ASSERT(ctx->Array.ElementArrayBufferObj != bufObj);
  267.          ASSERT(ctx->Array.ArrayObj->Vertex.BufferObj != bufObj);
  268. #endif
  269.  
  270.          ASSERT(ctx->Driver.DeleteBuffer);
  271.          ctx->Driver.DeleteBuffer(ctx, oldObj);
  272.       }
  273.  
  274.       *ptr = NULL;
  275.    }
  276.    ASSERT(!*ptr);
  277.  
  278.    if (bufObj) {
  279.       /* reference new buffer */
  280.       _glthread_LOCK_MUTEX(bufObj->Mutex);
  281.       if (bufObj->RefCount == 0) {
  282.          /* this buffer's being deleted (look just above) */
  283.          /* Not sure this can every really happen.  Warn if it does. */
  284.          _mesa_problem(NULL, "referencing deleted buffer object");
  285.          *ptr = NULL;
  286.       }
  287.       else {
  288.          bufObj->RefCount++;
  289. #if 0
  290.          printf("BufferObj %p %d INCR to %d\n",
  291.                 (void *) bufObj, bufObj->Name, bufObj->RefCount);
  292. #endif
  293.          *ptr = bufObj;
  294.       }
  295.       _glthread_UNLOCK_MUTEX(bufObj->Mutex);
  296.    }
  297. }
  298.  
  299.  
  300. /**
  301.  * Initialize a buffer object to default values.
  302.  */
  303. void
  304. _mesa_initialize_buffer_object( struct gl_buffer_object *obj,
  305.                                 GLuint name, GLenum target )
  306. {
  307.    (void) target;
  308.  
  309.    memset(obj, 0, sizeof(struct gl_buffer_object));
  310.    _glthread_INIT_MUTEX(obj->Mutex);
  311.    obj->RefCount = 1;
  312.    obj->Name = name;
  313.    obj->Usage = GL_STATIC_DRAW_ARB;
  314.    obj->AccessFlags = DEFAULT_ACCESS;
  315. }
  316.  
  317.  
  318. /**
  319.  * Allocate space for and store data in a buffer object.  Any data that was
  320.  * previously stored in the buffer object is lost.  If \c data is \c NULL,
  321.  * memory will be allocated, but no copy will occur.
  322.  *
  323.  * This is the default callback for \c dd_function_table::BufferData()
  324.  * Note that all GL error checking will have been done already.
  325.  *
  326.  * \param ctx     GL context.
  327.  * \param target  Buffer object target on which to operate.
  328.  * \param size    Size, in bytes, of the new data store.
  329.  * \param data    Pointer to the data to store in the buffer object.  This
  330.  *                pointer may be \c NULL.
  331.  * \param usage   Hints about how the data will be used.
  332.  * \param bufObj  Object to be used.
  333.  *
  334.  * \return GL_TRUE for success, GL_FALSE for failure
  335.  * \sa glBufferDataARB, dd_function_table::BufferData.
  336.  */
  337. static GLboolean
  338. _mesa_buffer_data( struct gl_context *ctx, GLenum target, GLsizeiptrARB size,
  339.                    const GLvoid * data, GLenum usage,
  340.                    struct gl_buffer_object * bufObj )
  341. {
  342.    void * new_data;
  343.  
  344.    (void) ctx; (void) target;
  345.  
  346.    new_data = _mesa_realloc( bufObj->Data, bufObj->Size, size );
  347.    if (new_data) {
  348.       bufObj->Data = (GLubyte *) new_data;
  349.       bufObj->Size = size;
  350.       bufObj->Usage = usage;
  351.  
  352.       if (data) {
  353.          memcpy( bufObj->Data, data, size );
  354.       }
  355.  
  356.       return GL_TRUE;
  357.    }
  358.    else {
  359.       return GL_FALSE;
  360.    }
  361. }
  362.  
  363.  
  364. /**
  365.  * Replace data in a subrange of buffer object.  If the data range
  366.  * specified by \c size + \c offset extends beyond the end of the buffer or
  367.  * if \c data is \c NULL, no copy is performed.
  368.  *
  369.  * This is the default callback for \c dd_function_table::BufferSubData()
  370.  * Note that all GL error checking will have been done already.
  371.  *
  372.  * \param ctx     GL context.
  373.  * \param target  Buffer object target on which to operate.
  374.  * \param offset  Offset of the first byte to be modified.
  375.  * \param size    Size, in bytes, of the data range.
  376.  * \param data    Pointer to the data to store in the buffer object.
  377.  * \param bufObj  Object to be used.
  378.  *
  379.  * \sa glBufferSubDataARB, dd_function_table::BufferSubData.
  380.  */
  381. static void
  382. _mesa_buffer_subdata( struct gl_context *ctx, GLenum target, GLintptrARB offset,
  383.                       GLsizeiptrARB size, const GLvoid * data,
  384.                       struct gl_buffer_object * bufObj )
  385. {
  386.    (void) ctx; (void) target;
  387.  
  388.    /* this should have been caught in _mesa_BufferSubData() */
  389.    ASSERT(size + offset <= bufObj->Size);
  390.  
  391.    if (bufObj->Data) {
  392.       memcpy( (GLubyte *) bufObj->Data + offset, data, size );
  393.    }
  394. }
  395.  
  396.  
  397. /**
  398.  * Retrieve data from a subrange of buffer object.  If the data range
  399.  * specified by \c size + \c offset extends beyond the end of the buffer or
  400.  * if \c data is \c NULL, no copy is performed.
  401.  *
  402.  * This is the default callback for \c dd_function_table::GetBufferSubData()
  403.  * Note that all GL error checking will have been done already.
  404.  *
  405.  * \param ctx     GL context.
  406.  * \param target  Buffer object target on which to operate.
  407.  * \param offset  Offset of the first byte to be fetched.
  408.  * \param size    Size, in bytes, of the data range.
  409.  * \param data    Destination for data
  410.  * \param bufObj  Object to be used.
  411.  *
  412.  * \sa glBufferGetSubDataARB, dd_function_table::GetBufferSubData.
  413.  */
  414. static void
  415. _mesa_buffer_get_subdata( struct gl_context *ctx, GLenum target, GLintptrARB offset,
  416.                           GLsizeiptrARB size, GLvoid * data,
  417.                           struct gl_buffer_object * bufObj )
  418. {
  419.    (void) ctx; (void) target;
  420.  
  421.    if (bufObj->Data && ((GLsizeiptrARB) (size + offset) <= bufObj->Size)) {
  422.       memcpy( data, (GLubyte *) bufObj->Data + offset, size );
  423.    }
  424. }
  425.  
  426.  
  427. /**
  428.  * Default callback for \c dd_function_tabel::MapBuffer().
  429.  *
  430.  * The function parameters will have been already tested for errors.
  431.  *
  432.  * \param ctx     GL context.
  433.  * \param target  Buffer object target on which to operate.
  434.  * \param access  Information about how the buffer will be accessed.
  435.  * \param bufObj  Object to be mapped.
  436.  * \return  A pointer to the object's internal data store that can be accessed
  437.  *          by the processor
  438.  *
  439.  * \sa glMapBufferARB, dd_function_table::MapBuffer
  440.  */
  441. static void *
  442. _mesa_buffer_map( struct gl_context *ctx, GLenum target, GLenum access,
  443.                   struct gl_buffer_object *bufObj )
  444. {
  445.    (void) ctx;
  446.    (void) target;
  447.    (void) access;
  448.    /* Just return a direct pointer to the data */
  449.    if (_mesa_bufferobj_mapped(bufObj)) {
  450.       /* already mapped! */
  451.       return NULL;
  452.    }
  453.    bufObj->Pointer = bufObj->Data;
  454.    bufObj->Length = bufObj->Size;
  455.    bufObj->Offset = 0;
  456.    return bufObj->Pointer;
  457. }
  458.  
  459.  
  460. /**
  461.  * Default fallback for \c dd_function_table::MapBufferRange().
  462.  * Called via glMapBufferRange().
  463.  */
  464. static void *
  465. _mesa_buffer_map_range( struct gl_context *ctx, GLenum target, GLintptr offset,
  466.                         GLsizeiptr length, GLbitfield access,
  467.                         struct gl_buffer_object *bufObj )
  468. {
  469.    (void) ctx;
  470.    (void) target;
  471.    assert(!_mesa_bufferobj_mapped(bufObj));
  472.    /* Just return a direct pointer to the data */
  473.    bufObj->Pointer = bufObj->Data + offset;
  474.    bufObj->Length = length;
  475.    bufObj->Offset = offset;
  476.    bufObj->AccessFlags = access;
  477.    return bufObj->Pointer;
  478. }
  479.  
  480.  
  481. /**
  482.  * Default fallback for \c dd_function_table::FlushMappedBufferRange().
  483.  * Called via glFlushMappedBufferRange().
  484.  */
  485. static void
  486. _mesa_buffer_flush_mapped_range( struct gl_context *ctx, GLenum target,
  487.                                  GLintptr offset, GLsizeiptr length,
  488.                                  struct gl_buffer_object *obj )
  489. {
  490.    (void) ctx;
  491.    (void) target;
  492.    (void) offset;
  493.    (void) length;
  494.    (void) obj;
  495.    /* no-op */
  496. }
  497.  
  498.  
  499. /**
  500.  * Default callback for \c dd_function_table::MapBuffer().
  501.  *
  502.  * The input parameters will have been already tested for errors.
  503.  *
  504.  * \sa glUnmapBufferARB, dd_function_table::UnmapBuffer
  505.  */
  506. static GLboolean
  507. _mesa_buffer_unmap( struct gl_context *ctx, GLenum target,
  508.                     struct gl_buffer_object *bufObj )
  509. {
  510.    (void) ctx;
  511.    (void) target;
  512.    /* XXX we might assert here that bufObj->Pointer is non-null */
  513.    bufObj->Pointer = NULL;
  514.    bufObj->Length = 0;
  515.    bufObj->Offset = 0;
  516.    bufObj->AccessFlags = 0x0;
  517.    return GL_TRUE;
  518. }
  519.  
  520.  
  521. /**
  522.  * Default fallback for \c dd_function_table::CopyBufferSubData().
  523.  * Called via glCopyBuffserSubData().
  524.  */
  525. static void
  526. _mesa_copy_buffer_subdata(struct gl_context *ctx,
  527.                           struct gl_buffer_object *src,
  528.                           struct gl_buffer_object *dst,
  529.                           GLintptr readOffset, GLintptr writeOffset,
  530.                           GLsizeiptr size)
  531. {
  532.    GLubyte *srcPtr, *dstPtr;
  533.  
  534.    /* buffer should not already be mapped */
  535.    assert(!_mesa_bufferobj_mapped(src));
  536.    assert(!_mesa_bufferobj_mapped(dst));
  537.  
  538.    srcPtr = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_COPY_READ_BUFFER,
  539.                                               GL_READ_ONLY, src);
  540.    dstPtr = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_COPY_WRITE_BUFFER,
  541.                                               GL_WRITE_ONLY, dst);
  542.  
  543.    if (srcPtr && dstPtr)
  544.       memcpy(dstPtr + writeOffset, srcPtr + readOffset, size);
  545.  
  546.    ctx->Driver.UnmapBuffer(ctx, GL_COPY_READ_BUFFER, src);
  547.    ctx->Driver.UnmapBuffer(ctx, GL_COPY_WRITE_BUFFER, dst);
  548. }
  549.  
  550.  
  551.  
  552. /**
  553.  * Initialize the state associated with buffer objects
  554.  */
  555. void
  556. _mesa_init_buffer_objects( struct gl_context *ctx )
  557. {
  558.    memset(&DummyBufferObject, 0, sizeof(DummyBufferObject));
  559.    DummyBufferObject.RefCount = 1000*1000*1000; /* never delete */
  560.  
  561.    _mesa_reference_buffer_object(ctx, &ctx->Array.ArrayBufferObj,
  562.                                  ctx->Shared->NullBufferObj);
  563.    _mesa_reference_buffer_object(ctx, &ctx->Array.ElementArrayBufferObj,
  564.                                  ctx->Shared->NullBufferObj);
  565.  
  566.    _mesa_reference_buffer_object(ctx, &ctx->CopyReadBuffer,
  567.                                  ctx->Shared->NullBufferObj);
  568.    _mesa_reference_buffer_object(ctx, &ctx->CopyWriteBuffer,
  569.                                  ctx->Shared->NullBufferObj);
  570. }
  571.  
  572.  
  573. void
  574. _mesa_free_buffer_objects( struct gl_context *ctx )
  575. {
  576.    _mesa_reference_buffer_object(ctx, &ctx->Array.ArrayBufferObj, NULL);
  577.    _mesa_reference_buffer_object(ctx, &ctx->Array.ElementArrayBufferObj, NULL);
  578.  
  579.    _mesa_reference_buffer_object(ctx, &ctx->CopyReadBuffer, NULL);
  580.    _mesa_reference_buffer_object(ctx, &ctx->CopyWriteBuffer, NULL);
  581. }
  582.  
  583.  
  584. /**
  585.  * Bind the specified target to buffer for the specified context.
  586.  * Called by glBindBuffer() and other functions.
  587.  */
  588. static void
  589. bind_buffer_object(struct gl_context *ctx, GLenum target, GLuint buffer)
  590. {
  591.    struct gl_buffer_object *oldBufObj;
  592.    struct gl_buffer_object *newBufObj = NULL;
  593.    struct gl_buffer_object **bindTarget = NULL;
  594.  
  595.    bindTarget = get_buffer_target(ctx, target);
  596.    if (!bindTarget) {
  597.       _mesa_error(ctx, GL_INVALID_ENUM, "glBindBufferARB(target 0x%x)", target);
  598.       return;
  599.    }
  600.  
  601.    /* Get pointer to old buffer object (to be unbound) */
  602.    oldBufObj = *bindTarget;
  603.    if (oldBufObj && oldBufObj->Name == buffer)
  604.       return;   /* rebinding the same buffer object- no change */
  605.  
  606.    /*
  607.     * Get pointer to new buffer object (newBufObj)
  608.     */
  609.    if (buffer == 0) {
  610.       /* The spec says there's not a buffer object named 0, but we use
  611.        * one internally because it simplifies things.
  612.        */
  613.       newBufObj = ctx->Shared->NullBufferObj;
  614.    }
  615.    else {
  616.       /* non-default buffer object */
  617.       newBufObj = _mesa_lookup_bufferobj(ctx, buffer);
  618.       if (!newBufObj || newBufObj == &DummyBufferObject) {
  619.          /* If this is a new buffer object id, or one which was generated but
  620.           * never used before, allocate a buffer object now.
  621.           */
  622.          ASSERT(ctx->Driver.NewBufferObject);
  623.          newBufObj = ctx->Driver.NewBufferObject(ctx, buffer, target);
  624.          if (!newBufObj) {
  625.             _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindBufferARB");
  626.             return;
  627.          }
  628.          _mesa_HashInsert(ctx->Shared->BufferObjects, buffer, newBufObj);
  629.       }
  630.    }
  631.    
  632.    /* bind new buffer */
  633.    _mesa_reference_buffer_object(ctx, bindTarget, newBufObj);
  634.  
  635.    /* Pass BindBuffer call to device driver */
  636.    if (ctx->Driver.BindBuffer)
  637.       ctx->Driver.BindBuffer( ctx, target, newBufObj );
  638. }
  639.  
  640.  
  641. /**
  642.  * Update the default buffer objects in the given context to reference those
  643.  * specified in the shared state and release those referencing the old
  644.  * shared state.
  645.  */
  646. void
  647. _mesa_update_default_objects_buffer_objects(struct gl_context *ctx)
  648. {
  649.    /* Bind the NullBufferObj to remove references to those
  650.     * in the shared context hash table.
  651.     */
  652.    bind_buffer_object( ctx, GL_ARRAY_BUFFER_ARB, 0);
  653.    bind_buffer_object( ctx, GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
  654.    bind_buffer_object( ctx, GL_PIXEL_PACK_BUFFER_ARB, 0);
  655.    bind_buffer_object( ctx, GL_PIXEL_UNPACK_BUFFER_ARB, 0);
  656. }
  657.  
  658.  
  659. /**
  660.  * When we're about to read pixel data out of a PBO (via glDrawPixels,
  661.  * glTexImage, etc) or write data into a PBO (via glReadPixels,
  662.  * glGetTexImage, etc) we call this function to check that we're not
  663.  * going to read out of bounds.
  664.  *
  665.  * XXX This would also be a convenient time to check that the PBO isn't
  666.  * currently mapped.  Whoever calls this function should check for that.
  667.  * Remember, we can't use a PBO when it's mapped!
  668.  *
  669.  * If we're not using a PBO, this is a no-op.
  670.  *
  671.  * \param width  width of image to read/write
  672.  * \param height  height of image to read/write
  673.  * \param depth  depth of image to read/write
  674.  * \param format  format of image to read/write
  675.  * \param type  datatype of image to read/write
  676.  * \param ptr  the user-provided pointer/offset
  677.  * \return GL_TRUE if the PBO access is OK, GL_FALSE if the access would
  678.  *         go out of bounds.
  679.  */
  680. GLboolean
  681. _mesa_validate_pbo_access(GLuint dimensions,
  682.                           const struct gl_pixelstore_attrib *pack,
  683.                           GLsizei width, GLsizei height, GLsizei depth,
  684.                           GLenum format, GLenum type, const GLvoid *ptr)
  685. {
  686.    GLvoid *start, *end;
  687.    const GLubyte *sizeAddr; /* buffer size, cast to a pointer */
  688.  
  689.    if (!_mesa_is_bufferobj(pack->BufferObj))
  690.       return GL_TRUE;  /* no PBO, OK */
  691.  
  692.    if (pack->BufferObj->Size == 0)
  693.       /* no buffer! */
  694.       return GL_FALSE;
  695.  
  696.    /* get address of first pixel we'll read */
  697.    start = _mesa_image_address(dimensions, pack, ptr, width, height,
  698.                                format, type, 0, 0, 0);
  699.  
  700.    /* get address just past the last pixel we'll read */
  701.    end =  _mesa_image_address(dimensions, pack, ptr, width, height,
  702.                               format, type, depth-1, height-1, width);
  703.  
  704.  
  705.    sizeAddr = ((const GLubyte *) 0) + pack->BufferObj->Size;
  706.  
  707.    if ((const GLubyte *) start > sizeAddr) {
  708.       /* This will catch negative values / wrap-around */
  709.       return GL_FALSE;
  710.    }
  711.    if ((const GLubyte *) end > sizeAddr) {
  712.       /* Image read goes beyond end of buffer */
  713.       return GL_FALSE;
  714.    }
  715.  
  716.    /* OK! */
  717.    return GL_TRUE;
  718. }
  719.  
  720.  
  721. /**
  722.  * For commands that read from a PBO (glDrawPixels, glTexImage,
  723.  * glPolygonStipple, etc), if we're reading from a PBO, map it read-only
  724.  * and return the pointer into the PBO.  If we're not reading from a
  725.  * PBO, return \p src as-is.
  726.  * If non-null return, must call _mesa_unmap_pbo_source() when done.
  727.  *
  728.  * \return NULL if error, else pointer to start of data
  729.  */
  730. const GLvoid *
  731. _mesa_map_pbo_source(struct gl_context *ctx,
  732.                      const struct gl_pixelstore_attrib *unpack,
  733.                      const GLvoid *src)
  734. {
  735.    const GLubyte *buf;
  736.  
  737.    if (_mesa_is_bufferobj(unpack->BufferObj)) {
  738.       /* unpack from PBO */
  739.       buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
  740.                                               GL_READ_ONLY_ARB,
  741.                                               unpack->BufferObj);
  742.       if (!buf)
  743.          return NULL;
  744.  
  745.       buf = ADD_POINTERS(buf, src);
  746.    }
  747.    else {
  748.       /* unpack from normal memory */
  749.       buf = src;
  750.    }
  751.  
  752.    return buf;
  753. }
  754.  
  755.  
  756. /**
  757.  * Combine PBO-read validation and mapping.
  758.  * If any GL errors are detected, they'll be recorded and NULL returned.
  759.  * \sa _mesa_validate_pbo_access
  760.  * \sa _mesa_map_pbo_source
  761.  * A call to this function should have a matching call to
  762.  * _mesa_unmap_pbo_source().
  763.  */
  764. const GLvoid *
  765. _mesa_map_validate_pbo_source(struct gl_context *ctx,
  766.                               GLuint dimensions,
  767.                               const struct gl_pixelstore_attrib *unpack,
  768.                               GLsizei width, GLsizei height, GLsizei depth,
  769.                               GLenum format, GLenum type, const GLvoid *ptr,
  770.                               const char *where)
  771. {
  772.    ASSERT(dimensions == 1 || dimensions == 2 || dimensions == 3);
  773.  
  774.    if (!_mesa_is_bufferobj(unpack->BufferObj)) {
  775.       /* non-PBO access: no validation to be done */
  776.       return ptr;
  777.    }
  778.  
  779.    if (!_mesa_validate_pbo_access(dimensions, unpack,
  780.                                   width, height, depth, format, type, ptr)) {
  781.       _mesa_error(ctx, GL_INVALID_OPERATION,
  782.                   "%s(out of bounds PBO access)", where);
  783.       return NULL;
  784.    }
  785.  
  786.    if (_mesa_bufferobj_mapped(unpack->BufferObj)) {
  787.       /* buffer is already mapped - that's an error */
  788.       _mesa_error(ctx, GL_INVALID_OPERATION, "%s(PBO is mapped)", where);
  789.       return NULL;
  790.    }
  791.  
  792.    ptr = _mesa_map_pbo_source(ctx, unpack, ptr);
  793.    return ptr;
  794. }
  795.  
  796.  
  797. /**
  798.  * Counterpart to _mesa_map_pbo_source()
  799.  */
  800. void
  801. _mesa_unmap_pbo_source(struct gl_context *ctx,
  802.                        const struct gl_pixelstore_attrib *unpack)
  803. {
  804.    ASSERT(unpack != &ctx->Pack); /* catch pack/unpack mismatch */
  805.    if (_mesa_is_bufferobj(unpack->BufferObj)) {
  806.       ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
  807.                               unpack->BufferObj);
  808.    }
  809. }
  810.  
  811.  
  812. /**
  813.  * For commands that write to a PBO (glReadPixels, glGetColorTable, etc),
  814.  * if we're writing to a PBO, map it write-only and return the pointer
  815.  * into the PBO.  If we're not writing to a PBO, return \p dst as-is.
  816.  * If non-null return, must call _mesa_unmap_pbo_dest() when done.
  817.  *
  818.  * \return NULL if error, else pointer to start of data
  819.  */
  820. void *
  821. _mesa_map_pbo_dest(struct gl_context *ctx,
  822.                    const struct gl_pixelstore_attrib *pack,
  823.                    GLvoid *dest)
  824. {
  825.    void *buf;
  826.  
  827.    if (_mesa_is_bufferobj(pack->BufferObj)) {
  828.       /* pack into PBO */
  829.       buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT,
  830.                                               GL_WRITE_ONLY_ARB,
  831.                                               pack->BufferObj);
  832.       if (!buf)
  833.          return NULL;
  834.  
  835.       buf = ADD_POINTERS(buf, dest);
  836.    }
  837.    else {
  838.       /* pack to normal memory */
  839.       buf = dest;
  840.    }
  841.  
  842.    return buf;
  843. }
  844.  
  845.  
  846. /**
  847.  * Combine PBO-write validation and mapping.
  848.  * If any GL errors are detected, they'll be recorded and NULL returned.
  849.  * \sa _mesa_validate_pbo_access
  850.  * \sa _mesa_map_pbo_dest
  851.  * A call to this function should have a matching call to
  852.  * _mesa_unmap_pbo_dest().
  853.  */
  854. GLvoid *
  855. _mesa_map_validate_pbo_dest(struct gl_context *ctx,
  856.                             GLuint dimensions,
  857.                             const struct gl_pixelstore_attrib *unpack,
  858.                             GLsizei width, GLsizei height, GLsizei depth,
  859.                             GLenum format, GLenum type, GLvoid *ptr,
  860.                             const char *where)
  861. {
  862.    ASSERT(dimensions == 1 || dimensions == 2 || dimensions == 3);
  863.  
  864.    if (!_mesa_is_bufferobj(unpack->BufferObj)) {
  865.       /* non-PBO access: no validation to be done */
  866.       return ptr;
  867.    }
  868.  
  869.    if (!_mesa_validate_pbo_access(dimensions, unpack,
  870.                                   width, height, depth, format, type, ptr)) {
  871.       _mesa_error(ctx, GL_INVALID_OPERATION,
  872.                   "%s(out of bounds PBO access)", where);
  873.       return NULL;
  874.    }
  875.  
  876.    if (_mesa_bufferobj_mapped(unpack->BufferObj)) {
  877.       /* buffer is already mapped - that's an error */
  878.       _mesa_error(ctx, GL_INVALID_OPERATION, "%s(PBO is mapped)", where);
  879.       return NULL;
  880.    }
  881.  
  882.    ptr = _mesa_map_pbo_dest(ctx, unpack, ptr);
  883.    return ptr;
  884. }
  885.  
  886.  
  887. /**
  888.  * Counterpart to _mesa_map_pbo_dest()
  889.  */
  890. void
  891. _mesa_unmap_pbo_dest(struct gl_context *ctx,
  892.                      const struct gl_pixelstore_attrib *pack)
  893. {
  894.    ASSERT(pack != &ctx->Unpack); /* catch pack/unpack mismatch */
  895.    if (_mesa_is_bufferobj(pack->BufferObj)) {
  896.       ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT, pack->BufferObj);
  897.    }
  898. }
  899.  
  900.  
  901.  
  902. /**
  903.  * Return the gl_buffer_object for the given ID.
  904.  * Always return NULL for ID 0.
  905.  */
  906. struct gl_buffer_object *
  907. _mesa_lookup_bufferobj(struct gl_context *ctx, GLuint buffer)
  908. {
  909.    if (buffer == 0)
  910.       return NULL;
  911.    else
  912.       return (struct gl_buffer_object *)
  913.          _mesa_HashLookup(ctx->Shared->BufferObjects, buffer);
  914. }
  915.  
  916.  
  917. /**
  918.  * If *ptr points to obj, set ptr = the Null/default buffer object.
  919.  * This is a helper for buffer object deletion.
  920.  * The GL spec says that deleting a buffer object causes it to get
  921.  * unbound from all arrays in the current context.
  922.  */
  923. static void
  924. unbind(struct gl_context *ctx,
  925.        struct gl_buffer_object **ptr,
  926.        struct gl_buffer_object *obj)
  927. {
  928.    if (*ptr == obj) {
  929.       _mesa_reference_buffer_object(ctx, ptr, ctx->Shared->NullBufferObj);
  930.    }
  931. }
  932.  
  933.  
  934. /**
  935.  * Plug default/fallback buffer object functions into the device
  936.  * driver hooks.
  937.  */
  938. void
  939. _mesa_init_buffer_object_functions(struct dd_function_table *driver)
  940. {
  941.    /* GL_ARB_vertex/pixel_buffer_object */
  942.    driver->NewBufferObject = _mesa_new_buffer_object;
  943.    driver->DeleteBuffer = _mesa_delete_buffer_object;
  944.    driver->BindBuffer = NULL;
  945.    driver->BufferData = _mesa_buffer_data;
  946.    driver->BufferSubData = _mesa_buffer_subdata;
  947.    driver->GetBufferSubData = _mesa_buffer_get_subdata;
  948.    driver->MapBuffer = _mesa_buffer_map;
  949.    driver->UnmapBuffer = _mesa_buffer_unmap;
  950.  
  951.    /* GL_ARB_map_buffer_range */
  952.    driver->MapBufferRange = _mesa_buffer_map_range;
  953.    driver->FlushMappedBufferRange = _mesa_buffer_flush_mapped_range;
  954.  
  955.    /* GL_ARB_copy_buffer */
  956.    driver->CopyBufferSubData = _mesa_copy_buffer_subdata;
  957. }
  958.  
  959.  
  960.  
  961. /**********************************************************************/
  962. /* API Functions                                                      */
  963. /**********************************************************************/
  964.  
  965. void GLAPIENTRY
  966. _mesa_BindBufferARB(GLenum target, GLuint buffer)
  967. {
  968.    GET_CURRENT_CONTEXT(ctx);
  969.    ASSERT_OUTSIDE_BEGIN_END(ctx);
  970.  
  971.    bind_buffer_object(ctx, target, buffer);
  972. }
  973.  
  974.  
  975. /**
  976.  * Delete a set of buffer objects.
  977.  *
  978.  * \param n      Number of buffer objects to delete.
  979.  * \param ids    Array of \c n buffer object IDs.
  980.  */
  981. void GLAPIENTRY
  982. _mesa_DeleteBuffersARB(GLsizei n, const GLuint *ids)
  983. {
  984.    GET_CURRENT_CONTEXT(ctx);
  985.    GLsizei i;
  986.    ASSERT_OUTSIDE_BEGIN_END(ctx);
  987.  
  988.    if (n < 0) {
  989.       _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteBuffersARB(n)");
  990.       return;
  991.    }
  992.  
  993.    _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
  994.  
  995.    for (i = 0; i < n; i++) {
  996.       struct gl_buffer_object *bufObj = _mesa_lookup_bufferobj(ctx, ids[i]);
  997.       if (bufObj) {
  998.          struct gl_array_object *arrayObj = ctx->Array.ArrayObj;
  999.          GLuint j;
  1000.  
  1001.          ASSERT(bufObj->Name == ids[i] || bufObj == &DummyBufferObject);
  1002.  
  1003.          if (_mesa_bufferobj_mapped(bufObj)) {
  1004.             /* if mapped, unmap it now */
  1005.             ctx->Driver.UnmapBuffer(ctx, 0, bufObj);
  1006.             bufObj->AccessFlags = DEFAULT_ACCESS;
  1007.             bufObj->Pointer = NULL;
  1008.          }
  1009.  
  1010.          /* unbind any vertex pointers bound to this buffer */
  1011.          unbind(ctx, &arrayObj->Vertex.BufferObj, bufObj);
  1012.          unbind(ctx, &arrayObj->Weight.BufferObj, bufObj);
  1013.          unbind(ctx, &arrayObj->Normal.BufferObj, bufObj);
  1014.          unbind(ctx, &arrayObj->Color.BufferObj, bufObj);
  1015.          unbind(ctx, &arrayObj->SecondaryColor.BufferObj, bufObj);
  1016.          unbind(ctx, &arrayObj->FogCoord.BufferObj, bufObj);
  1017.          unbind(ctx, &arrayObj->Index.BufferObj, bufObj);
  1018.          unbind(ctx, &arrayObj->EdgeFlag.BufferObj, bufObj);
  1019.          for (j = 0; j < Elements(arrayObj->TexCoord); j++) {
  1020.             unbind(ctx, &arrayObj->TexCoord[j].BufferObj, bufObj);
  1021.          }
  1022.          for (j = 0; j < Elements(arrayObj->VertexAttrib); j++) {
  1023.             unbind(ctx, &arrayObj->VertexAttrib[j].BufferObj, bufObj);
  1024.          }
  1025.  
  1026.          if (ctx->Array.ArrayBufferObj == bufObj) {
  1027.             _mesa_BindBufferARB( GL_ARRAY_BUFFER_ARB, 0 );
  1028.          }
  1029.          if (ctx->Array.ElementArrayBufferObj == bufObj) {
  1030.             _mesa_BindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, 0 );
  1031.          }
  1032.  
  1033.          /* unbind any pixel pack/unpack pointers bound to this buffer */
  1034.          if (ctx->Pack.BufferObj == bufObj) {
  1035.             _mesa_BindBufferARB( GL_PIXEL_PACK_BUFFER_EXT, 0 );
  1036.          }
  1037.          if (ctx->Unpack.BufferObj == bufObj) {
  1038.             _mesa_BindBufferARB( GL_PIXEL_UNPACK_BUFFER_EXT, 0 );
  1039.          }
  1040.  
  1041.          /* The ID is immediately freed for re-use */
  1042.          _mesa_HashRemove(ctx->Shared->BufferObjects, ids[i]);
  1043.          _mesa_reference_buffer_object(ctx, &bufObj, NULL);
  1044.       }
  1045.    }
  1046.  
  1047.    _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
  1048. }
  1049.  
  1050.  
  1051. /**
  1052.  * Generate a set of unique buffer object IDs and store them in \c buffer.
  1053.  *
  1054.  * \param n       Number of IDs to generate.
  1055.  * \param buffer  Array of \c n locations to store the IDs.
  1056.  */
  1057. void GLAPIENTRY
  1058. _mesa_GenBuffersARB(GLsizei n, GLuint *buffer)
  1059. {
  1060.    GET_CURRENT_CONTEXT(ctx);
  1061.    GLuint first;
  1062.    GLint i;
  1063.    ASSERT_OUTSIDE_BEGIN_END(ctx);
  1064.  
  1065.    if (n < 0) {
  1066.       _mesa_error(ctx, GL_INVALID_VALUE, "glGenBuffersARB");
  1067.       return;
  1068.    }
  1069.  
  1070.    if (!buffer) {
  1071.       return;
  1072.    }
  1073.  
  1074.    /*
  1075.     * This must be atomic (generation and allocation of buffer object IDs)
  1076.     */
  1077.    _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
  1078.  
  1079.    first = _mesa_HashFindFreeKeyBlock(ctx->Shared->BufferObjects, n);
  1080.  
  1081.    /* Insert the ID and pointer to dummy buffer object into hash table */
  1082.    for (i = 0; i < n; i++) {
  1083.       _mesa_HashInsert(ctx->Shared->BufferObjects, first + i,
  1084.                        &DummyBufferObject);
  1085.       buffer[i] = first + i;
  1086.    }
  1087.  
  1088.    _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
  1089. }
  1090.  
  1091.  
  1092. /**
  1093.  * Determine if ID is the name of a buffer object.
  1094.  *
  1095.  * \param id  ID of the potential buffer object.
  1096.  * \return  \c GL_TRUE if \c id is the name of a buffer object,
  1097.  *          \c GL_FALSE otherwise.
  1098.  */
  1099. GLboolean GLAPIENTRY
  1100. _mesa_IsBufferARB(GLuint id)
  1101. {
  1102.    struct gl_buffer_object *bufObj;
  1103.    GET_CURRENT_CONTEXT(ctx);
  1104.    ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
  1105.  
  1106.    _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
  1107.    bufObj = _mesa_lookup_bufferobj(ctx, id);
  1108.    _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
  1109.  
  1110.    return bufObj && bufObj != &DummyBufferObject;
  1111. }
  1112.  
  1113.  
  1114. void GLAPIENTRY
  1115. _mesa_BufferDataARB(GLenum target, GLsizeiptrARB size,
  1116.                     const GLvoid * data, GLenum usage)
  1117. {
  1118.    GET_CURRENT_CONTEXT(ctx);
  1119.    struct gl_buffer_object *bufObj;
  1120.    ASSERT_OUTSIDE_BEGIN_END(ctx);
  1121.  
  1122.    if (size < 0) {
  1123.       _mesa_error(ctx, GL_INVALID_VALUE, "glBufferDataARB(size < 0)");
  1124.       return;
  1125.    }
  1126.  
  1127.    switch (usage) {
  1128.    case GL_STREAM_DRAW_ARB:
  1129.    case GL_STREAM_READ_ARB:
  1130.    case GL_STREAM_COPY_ARB:
  1131.    case GL_STATIC_DRAW_ARB:
  1132.    case GL_STATIC_READ_ARB:
  1133.    case GL_STATIC_COPY_ARB:
  1134.    case GL_DYNAMIC_DRAW_ARB:
  1135.    case GL_DYNAMIC_READ_ARB:
  1136.    case GL_DYNAMIC_COPY_ARB:
  1137.       /* OK */
  1138.       break;
  1139.    default:
  1140.       _mesa_error(ctx, GL_INVALID_ENUM, "glBufferDataARB(usage)");
  1141.       return;
  1142.    }
  1143.  
  1144.    bufObj = get_buffer(ctx, target);
  1145.    if (!bufObj) {
  1146.       _mesa_error(ctx, GL_INVALID_ENUM, "glBufferDataARB(target)" );
  1147.       return;
  1148.    }
  1149.    if (!_mesa_is_bufferobj(bufObj)) {
  1150.       _mesa_error(ctx, GL_INVALID_OPERATION, "glBufferDataARB(buffer 0)" );
  1151.       return;
  1152.    }
  1153.    
  1154.    if (_mesa_bufferobj_mapped(bufObj)) {
  1155.       /* Unmap the existing buffer.  We'll replace it now.  Not an error. */
  1156.       ctx->Driver.UnmapBuffer(ctx, target, bufObj);
  1157.       bufObj->AccessFlags = DEFAULT_ACCESS;
  1158.       ASSERT(bufObj->Pointer == NULL);
  1159.    }  
  1160.  
  1161.    FLUSH_VERTICES(ctx, _NEW_BUFFER_OBJECT);
  1162.  
  1163.    bufObj->Written = GL_TRUE;
  1164.  
  1165. #ifdef VBO_DEBUG
  1166.    printf("glBufferDataARB(%u, sz %ld, from %p, usage 0x%x)\n",
  1167.                 bufObj->Name, size, data, usage);
  1168. #endif
  1169.  
  1170. #ifdef BOUNDS_CHECK
  1171.    size += 100;
  1172. #endif
  1173.  
  1174.    ASSERT(ctx->Driver.BufferData);
  1175.    if (!ctx->Driver.BufferData( ctx, target, size, data, usage, bufObj )) {
  1176.       _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBufferDataARB()");
  1177.    }
  1178. }
  1179.  
  1180.  
  1181. void GLAPIENTRY
  1182. _mesa_BufferSubDataARB(GLenum target, GLintptrARB offset,
  1183.                        GLsizeiptrARB size, const GLvoid * data)
  1184. {
  1185.    GET_CURRENT_CONTEXT(ctx);
  1186.    struct gl_buffer_object *bufObj;
  1187.    ASSERT_OUTSIDE_BEGIN_END(ctx);
  1188.  
  1189.    bufObj = buffer_object_subdata_range_good( ctx, target, offset, size,
  1190.                                               "glBufferSubDataARB" );
  1191.    if (!bufObj) {
  1192.       /* error already recorded */
  1193.       return;
  1194.    }
  1195.  
  1196.    if (size == 0)
  1197.       return;
  1198.  
  1199.    bufObj->Written = GL_TRUE;
  1200.  
  1201.    ASSERT(ctx->Driver.BufferSubData);
  1202.    ctx->Driver.BufferSubData( ctx, target, offset, size, data, bufObj );
  1203. }
  1204.  
  1205.  
  1206. void GLAPIENTRY
  1207. _mesa_GetBufferSubDataARB(GLenum target, GLintptrARB offset,
  1208.                           GLsizeiptrARB size, void * data)
  1209. {
  1210.    GET_CURRENT_CONTEXT(ctx);
  1211.    struct gl_buffer_object *bufObj;
  1212.    ASSERT_OUTSIDE_BEGIN_END(ctx);
  1213.  
  1214.    bufObj = buffer_object_subdata_range_good( ctx, target, offset, size,
  1215.                                               "glGetBufferSubDataARB" );
  1216.    if (!bufObj) {
  1217.       /* error already recorded */
  1218.       return;
  1219.    }
  1220.  
  1221.    ASSERT(ctx->Driver.GetBufferSubData);
  1222.    ctx->Driver.GetBufferSubData( ctx, target, offset, size, data, bufObj );
  1223. }
  1224.  
  1225.  
  1226. void * GLAPIENTRY
  1227. _mesa_MapBufferARB(GLenum target, GLenum access)
  1228. {
  1229.    GET_CURRENT_CONTEXT(ctx);
  1230.    struct gl_buffer_object * bufObj;
  1231.    GLbitfield accessFlags;
  1232.    void *map;
  1233.  
  1234.    ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, NULL);
  1235.  
  1236.    switch (access) {
  1237.    case GL_READ_ONLY_ARB:
  1238.       accessFlags = GL_MAP_READ_BIT;
  1239.       break;
  1240.    case GL_WRITE_ONLY_ARB:
  1241.       accessFlags = GL_MAP_WRITE_BIT;
  1242.       break;
  1243.    case GL_READ_WRITE_ARB:
  1244.       accessFlags = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT;
  1245.       break;
  1246.    default:
  1247.       _mesa_error(ctx, GL_INVALID_ENUM, "glMapBufferARB(access)");
  1248.       return NULL;
  1249.    }
  1250.  
  1251.    bufObj = get_buffer(ctx, target);
  1252.    if (!bufObj) {
  1253.       _mesa_error(ctx, GL_INVALID_ENUM, "glMapBufferARB(target)" );
  1254.       return NULL;
  1255.    }
  1256.    if (!_mesa_is_bufferobj(bufObj)) {
  1257.       _mesa_error(ctx, GL_INVALID_OPERATION, "glMapBufferARB(buffer 0)" );
  1258.       return NULL;
  1259.    }
  1260.    if (_mesa_bufferobj_mapped(bufObj)) {
  1261.       _mesa_error(ctx, GL_INVALID_OPERATION, "glMapBufferARB(already mapped)");
  1262.       return NULL;
  1263.    }
  1264.  
  1265.    ASSERT(ctx->Driver.MapBuffer);
  1266.    map = ctx->Driver.MapBuffer( ctx, target, access, bufObj );
  1267.    if (!map) {
  1268.       _mesa_error(ctx, GL_OUT_OF_MEMORY, "glMapBufferARB(map failed)");
  1269.       return NULL;
  1270.    }
  1271.    else {
  1272.       /* The driver callback should have set these fields.
  1273.        * This is important because other modules (like VBO) might call
  1274.        * the driver function directly.
  1275.        */
  1276.       ASSERT(bufObj->Pointer == map);
  1277.       ASSERT(bufObj->Length == bufObj->Size);
  1278.       ASSERT(bufObj->Offset == 0);
  1279.       bufObj->AccessFlags = accessFlags;
  1280.    }
  1281.  
  1282.    if (access == GL_WRITE_ONLY_ARB || access == GL_READ_WRITE_ARB)
  1283.       bufObj->Written = GL_TRUE;
  1284.  
  1285. #ifdef VBO_DEBUG
  1286.    printf("glMapBufferARB(%u, sz %ld, access 0x%x)\n",
  1287.           bufObj->Name, bufObj->Size, access);
  1288.    if (access == GL_WRITE_ONLY_ARB) {
  1289.       GLuint i;
  1290.       GLubyte *b = (GLubyte *) bufObj->Pointer;
  1291.       for (i = 0; i < bufObj->Size; i++)
  1292.          b[i] = i & 0xff;
  1293.    }
  1294. #endif
  1295.  
  1296. #ifdef BOUNDS_CHECK
  1297.    {
  1298.       GLubyte *buf = (GLubyte *) bufObj->Pointer;
  1299.       GLuint i;
  1300.       /* buffer is 100 bytes larger than requested, fill with magic value */
  1301.       for (i = 0; i < 100; i++) {
  1302.          buf[bufObj->Size - i - 1] = 123;
  1303.       }
  1304.    }
  1305. #endif
  1306.  
  1307.    return bufObj->Pointer;
  1308. }
  1309.  
  1310.  
  1311. GLboolean GLAPIENTRY
  1312. _mesa_UnmapBufferARB(GLenum target)
  1313. {
  1314.    GET_CURRENT_CONTEXT(ctx);
  1315.    struct gl_buffer_object *bufObj;
  1316.    GLboolean status = GL_TRUE;
  1317.    ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
  1318.  
  1319.    bufObj = get_buffer(ctx, target);
  1320.    if (!bufObj) {
  1321.       _mesa_error(ctx, GL_INVALID_ENUM, "glUnmapBufferARB(target)" );
  1322.       return GL_FALSE;
  1323.    }
  1324.    if (!_mesa_is_bufferobj(bufObj)) {
  1325.       _mesa_error(ctx, GL_INVALID_OPERATION, "glUnmapBufferARB" );
  1326.       return GL_FALSE;
  1327.    }
  1328.    if (!_mesa_bufferobj_mapped(bufObj)) {
  1329.       _mesa_error(ctx, GL_INVALID_OPERATION, "glUnmapBufferARB");
  1330.       return GL_FALSE;
  1331.    }
  1332.  
  1333. #ifdef BOUNDS_CHECK
  1334.    if (bufObj->Access != GL_READ_ONLY_ARB) {
  1335.       GLubyte *buf = (GLubyte *) bufObj->Pointer;
  1336.       GLuint i;
  1337.       /* check that last 100 bytes are still = magic value */
  1338.       for (i = 0; i < 100; i++) {
  1339.          GLuint pos = bufObj->Size - i - 1;
  1340.          if (buf[pos] != 123) {
  1341.             _mesa_warning(ctx, "Out of bounds buffer object write detected"
  1342.                           " at position %d (value = %u)\n",
  1343.                           pos, buf[pos]);
  1344.          }
  1345.       }
  1346.    }
  1347. #endif
  1348.  
  1349. #ifdef VBO_DEBUG
  1350.    if (bufObj->AccessFlags & GL_MAP_WRITE_BIT) {
  1351.       GLuint i, unchanged = 0;
  1352.       GLubyte *b = (GLubyte *) bufObj->Pointer;
  1353.       GLint pos = -1;
  1354.       /* check which bytes changed */
  1355.       for (i = 0; i < bufObj->Size - 1; i++) {
  1356.          if (b[i] == (i & 0xff) && b[i+1] == ((i+1) & 0xff)) {
  1357.             unchanged++;
  1358.             if (pos == -1)
  1359.                pos = i;
  1360.          }
  1361.       }
  1362.       if (unchanged) {
  1363.          printf("glUnmapBufferARB(%u): %u of %ld unchanged, starting at %d\n",
  1364.                       bufObj->Name, unchanged, bufObj->Size, pos);
  1365.       }
  1366.    }
  1367. #endif
  1368.  
  1369.    status = ctx->Driver.UnmapBuffer( ctx, target, bufObj );
  1370.    bufObj->AccessFlags = DEFAULT_ACCESS;
  1371.    ASSERT(bufObj->Pointer == NULL);
  1372.    ASSERT(bufObj->Offset == 0);
  1373.    ASSERT(bufObj->Length == 0);
  1374.  
  1375.    return status;
  1376. }
  1377.  
  1378.  
  1379. void GLAPIENTRY
  1380. _mesa_GetBufferParameterivARB(GLenum target, GLenum pname, GLint *params)
  1381. {
  1382.    GET_CURRENT_CONTEXT(ctx);
  1383.    struct gl_buffer_object *bufObj;
  1384.    ASSERT_OUTSIDE_BEGIN_END(ctx);
  1385.  
  1386.    bufObj = get_buffer(ctx, target);
  1387.    if (!bufObj) {
  1388.       _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferParameterivARB(target)" );
  1389.       return;
  1390.    }
  1391.    if (!_mesa_is_bufferobj(bufObj)) {
  1392.       _mesa_error(ctx, GL_INVALID_OPERATION, "glGetBufferParameterivARB" );
  1393.       return;
  1394.    }
  1395.  
  1396.    switch (pname) {
  1397.    case GL_BUFFER_SIZE_ARB:
  1398.       *params = (GLint) bufObj->Size;
  1399.       return;
  1400.    case GL_BUFFER_USAGE_ARB:
  1401.       *params = bufObj->Usage;
  1402.       return;
  1403.    case GL_BUFFER_ACCESS_ARB:
  1404.       *params = simplified_access_mode(bufObj->AccessFlags);
  1405.       return;
  1406.    case GL_BUFFER_MAPPED_ARB:
  1407.       *params = _mesa_bufferobj_mapped(bufObj);
  1408.       return;
  1409.    case GL_BUFFER_ACCESS_FLAGS:
  1410.       if (ctx->VersionMajor < 3)
  1411.          goto invalid_pname;
  1412.       *params = bufObj->AccessFlags;
  1413.       return;
  1414.    case GL_BUFFER_MAP_OFFSET:
  1415.       if (ctx->VersionMajor < 3)
  1416.          goto invalid_pname;
  1417.       *params = (GLint) bufObj->Offset;
  1418.       return;
  1419.    case GL_BUFFER_MAP_LENGTH:
  1420.       if (ctx->VersionMajor < 3)
  1421.          goto invalid_pname;
  1422.       *params = (GLint) bufObj->Length;
  1423.       return;
  1424.    default:
  1425.       ; /* fall-through */
  1426.    }
  1427.  
  1428. invalid_pname:
  1429.    _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferParameterivARB(pname=%s)",
  1430.                _mesa_lookup_enum_by_nr(pname));
  1431. }
  1432.  
  1433.  
  1434. /**
  1435.  * New in GL 3.2
  1436.  * This is pretty much a duplicate of GetBufferParameteriv() but the
  1437.  * GL_BUFFER_SIZE_ARB attribute will be 64-bits on a 64-bit system.
  1438.  */
  1439. void GLAPIENTRY
  1440. _mesa_GetBufferParameteri64v(GLenum target, GLenum pname, GLint64 *params)
  1441. {
  1442.    GET_CURRENT_CONTEXT(ctx);
  1443.    struct gl_buffer_object *bufObj;
  1444.    ASSERT_OUTSIDE_BEGIN_END(ctx);
  1445.  
  1446.    bufObj = get_buffer(ctx, target);
  1447.    if (!bufObj) {
  1448.       _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferParameteri64v(target)" );
  1449.       return;
  1450.    }
  1451.    if (!_mesa_is_bufferobj(bufObj)) {
  1452.       _mesa_error(ctx, GL_INVALID_OPERATION, "glGetBufferParameteri64v" );
  1453.       return;
  1454.    }
  1455.  
  1456.    switch (pname) {
  1457.    case GL_BUFFER_SIZE_ARB:
  1458.       *params = bufObj->Size;
  1459.       return;
  1460.    case GL_BUFFER_USAGE_ARB:
  1461.       *params = bufObj->Usage;
  1462.       return;
  1463.    case GL_BUFFER_ACCESS_ARB:
  1464.       *params = simplified_access_mode(bufObj->AccessFlags);
  1465.       return;
  1466.    case GL_BUFFER_ACCESS_FLAGS:
  1467.       if (ctx->VersionMajor < 3)
  1468.          goto invalid_pname;
  1469.       *params = bufObj->AccessFlags;
  1470.       return;
  1471.    case GL_BUFFER_MAPPED_ARB:
  1472.       *params = _mesa_bufferobj_mapped(bufObj);
  1473.       return;
  1474.    case GL_BUFFER_MAP_OFFSET:
  1475.       if (ctx->VersionMajor < 3)
  1476.          goto invalid_pname;
  1477.       *params = bufObj->Offset;
  1478.       return;
  1479.    case GL_BUFFER_MAP_LENGTH:
  1480.       if (ctx->VersionMajor < 3)
  1481.          goto invalid_pname;
  1482.       *params = bufObj->Length;
  1483.       return;
  1484.    default:
  1485.       ; /* fall-through */
  1486.    }
  1487.  
  1488. invalid_pname:
  1489.    _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferParameteri64v(pname=%s)",
  1490.                _mesa_lookup_enum_by_nr(pname));
  1491. }
  1492.  
  1493.  
  1494. void GLAPIENTRY
  1495. _mesa_GetBufferPointervARB(GLenum target, GLenum pname, GLvoid **params)
  1496. {
  1497.    GET_CURRENT_CONTEXT(ctx);
  1498.    struct gl_buffer_object * bufObj;
  1499.    ASSERT_OUTSIDE_BEGIN_END(ctx);
  1500.  
  1501.    if (pname != GL_BUFFER_MAP_POINTER_ARB) {
  1502.       _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferPointervARB(pname)");
  1503.       return;
  1504.    }
  1505.  
  1506.    bufObj = get_buffer(ctx, target);
  1507.    if (!bufObj) {
  1508.       _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferPointervARB(target)" );
  1509.       return;
  1510.    }
  1511.    if (!_mesa_is_bufferobj(bufObj)) {
  1512.       _mesa_error(ctx, GL_INVALID_OPERATION, "glGetBufferPointervARB" );
  1513.       return;
  1514.    }
  1515.  
  1516.    *params = bufObj->Pointer;
  1517. }
  1518.  
  1519.  
  1520. void GLAPIENTRY
  1521. _mesa_CopyBufferSubData(GLenum readTarget, GLenum writeTarget,
  1522.                         GLintptr readOffset, GLintptr writeOffset,
  1523.                         GLsizeiptr size)
  1524. {
  1525.    GET_CURRENT_CONTEXT(ctx);
  1526.    struct gl_buffer_object *src, *dst;
  1527.    ASSERT_OUTSIDE_BEGIN_END(ctx);
  1528.  
  1529.    src = get_buffer(ctx, readTarget);
  1530.    if (!src || !_mesa_is_bufferobj(src)) {
  1531.       _mesa_error(ctx, GL_INVALID_ENUM,
  1532.                   "glCopyBuffserSubData(readTarget = 0x%x)", readTarget);
  1533.       return;
  1534.    }
  1535.  
  1536.    dst = get_buffer(ctx, writeTarget);
  1537.    if (!dst || !_mesa_is_bufferobj(dst)) {
  1538.       _mesa_error(ctx, GL_INVALID_ENUM,
  1539.                   "glCopyBuffserSubData(writeTarget = 0x%x)", writeTarget);
  1540.       return;
  1541.    }
  1542.  
  1543.    if (_mesa_bufferobj_mapped(src)) {
  1544.       _mesa_error(ctx, GL_INVALID_OPERATION,
  1545.                   "glCopyBuffserSubData(readBuffer is mapped)");
  1546.       return;
  1547.    }
  1548.  
  1549.    if (_mesa_bufferobj_mapped(dst)) {
  1550.       _mesa_error(ctx, GL_INVALID_OPERATION,
  1551.                   "glCopyBuffserSubData(writeBuffer is mapped)");
  1552.       return;
  1553.    }
  1554.  
  1555.    if (readOffset < 0) {
  1556.       _mesa_error(ctx, GL_INVALID_VALUE,
  1557.                   "glCopyBuffserSubData(readOffset = %d)", (int) readOffset);
  1558.       return;
  1559.    }
  1560.  
  1561.    if (writeOffset < 0) {
  1562.       _mesa_error(ctx, GL_INVALID_VALUE,
  1563.                   "glCopyBuffserSubData(writeOffset = %d)", (int) writeOffset);
  1564.       return;
  1565.    }
  1566.  
  1567.    if (readOffset + size > src->Size) {
  1568.       _mesa_error(ctx, GL_INVALID_VALUE,
  1569.                   "glCopyBuffserSubData(readOffset + size = %d)",
  1570.                   (int) (readOffset + size));
  1571.       return;
  1572.    }
  1573.  
  1574.    if (writeOffset + size > dst->Size) {
  1575.       _mesa_error(ctx, GL_INVALID_VALUE,
  1576.                   "glCopyBuffserSubData(writeOffset + size = %d)",
  1577.                   (int) (writeOffset + size));
  1578.       return;
  1579.    }
  1580.  
  1581.    if (src == dst) {
  1582.       if (readOffset + size <= writeOffset) {
  1583.          /* OK */
  1584.       }
  1585.       else if (writeOffset + size <= readOffset) {
  1586.          /* OK */
  1587.       }
  1588.       else {
  1589.          /* overlapping src/dst is illegal */
  1590.          _mesa_error(ctx, GL_INVALID_VALUE,
  1591.                      "glCopyBuffserSubData(overlapping src/dst)");
  1592.          return;
  1593.       }
  1594.    }
  1595.  
  1596.    ctx->Driver.CopyBufferSubData(ctx, src, dst, readOffset, writeOffset, size);
  1597. }
  1598.  
  1599.  
  1600. /**
  1601.  * See GL_ARB_map_buffer_range spec
  1602.  */
  1603. void * GLAPIENTRY
  1604. _mesa_MapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length,
  1605.                      GLbitfield access)
  1606. {
  1607.    GET_CURRENT_CONTEXT(ctx);
  1608.    struct gl_buffer_object *bufObj;
  1609.    void *map;
  1610.  
  1611.    ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, NULL);
  1612.  
  1613.    if (!ctx->Extensions.ARB_map_buffer_range) {
  1614.       _mesa_error(ctx, GL_INVALID_OPERATION,
  1615.                   "glMapBufferRange(extension not supported)");
  1616.       return NULL;
  1617.    }
  1618.  
  1619.    if (offset < 0) {
  1620.       _mesa_error(ctx, GL_INVALID_VALUE,
  1621.                   "glMapBufferRange(offset = %ld)", (long)offset);
  1622.       return NULL;
  1623.    }
  1624.  
  1625.    if (length < 0) {
  1626.       _mesa_error(ctx, GL_INVALID_VALUE,
  1627.                   "glMapBufferRange(length = %ld)", (long)length);
  1628.       return NULL;
  1629.    }
  1630.  
  1631.    if ((access & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)) == 0) {
  1632.       _mesa_error(ctx, GL_INVALID_OPERATION,
  1633.                   "glMapBufferRange(access indicates neither read or write)");
  1634.       return NULL;
  1635.    }
  1636.  
  1637.    if (access & GL_MAP_READ_BIT) {
  1638.       if ((access & GL_MAP_INVALIDATE_RANGE_BIT) ||
  1639.           (access & GL_MAP_INVALIDATE_BUFFER_BIT) ||
  1640.           (access & GL_MAP_UNSYNCHRONIZED_BIT)) {
  1641.          _mesa_error(ctx, GL_INVALID_OPERATION,
  1642.                      "glMapBufferRange(invalid access flags)");
  1643.          return NULL;
  1644.       }
  1645.    }
  1646.  
  1647.    if ((access & GL_MAP_FLUSH_EXPLICIT_BIT) &&
  1648.        ((access & GL_MAP_WRITE_BIT) == 0)) {
  1649.       _mesa_error(ctx, GL_INVALID_OPERATION,
  1650.                   "glMapBufferRange(invalid access flags)");
  1651.       return NULL;
  1652.    }
  1653.  
  1654.    bufObj = get_buffer(ctx, target);
  1655.    if (!bufObj || !_mesa_is_bufferobj(bufObj)) {
  1656.       _mesa_error(ctx, GL_INVALID_ENUM,
  1657.                   "glMapBufferRange(target = 0x%x)", target);
  1658.       return NULL;
  1659.    }
  1660.  
  1661.    if (offset + length > bufObj->Size) {
  1662.       _mesa_error(ctx, GL_INVALID_VALUE,
  1663.                   "glMapBufferRange(offset + length > size)");
  1664.       return NULL;
  1665.    }
  1666.  
  1667.    if (_mesa_bufferobj_mapped(bufObj)) {
  1668.       _mesa_error(ctx, GL_INVALID_OPERATION,
  1669.                   "glMapBufferRange(buffer already mapped)");
  1670.       return NULL;
  1671.    }
  1672.      
  1673.    ASSERT(ctx->Driver.MapBufferRange);
  1674.    map = ctx->Driver.MapBufferRange(ctx, target, offset, length,
  1675.                                     access, bufObj);
  1676.    if (!map) {
  1677.       _mesa_error(ctx, GL_OUT_OF_MEMORY, "glMapBufferARB(map failed)");
  1678.    }
  1679.    else {
  1680.       /* The driver callback should have set all these fields.
  1681.        * This is important because other modules (like VBO) might call
  1682.        * the driver function directly.
  1683.        */
  1684.       ASSERT(bufObj->Pointer == map);
  1685.       ASSERT(bufObj->Length == length);
  1686.       ASSERT(bufObj->Offset == offset);
  1687.       ASSERT(bufObj->AccessFlags == access);
  1688.    }
  1689.  
  1690.    return map;
  1691. }
  1692.  
  1693.  
  1694. /**
  1695.  * See GL_ARB_map_buffer_range spec
  1696.  */
  1697. void GLAPIENTRY
  1698. _mesa_FlushMappedBufferRange(GLenum target, GLintptr offset, GLsizeiptr length)
  1699. {
  1700.    GET_CURRENT_CONTEXT(ctx);
  1701.    struct gl_buffer_object *bufObj;
  1702.    ASSERT_OUTSIDE_BEGIN_END(ctx);
  1703.  
  1704.    if (!ctx->Extensions.ARB_map_buffer_range) {
  1705.       _mesa_error(ctx, GL_INVALID_OPERATION,
  1706.                   "glMapBufferRange(extension not supported)");
  1707.       return;
  1708.    }
  1709.  
  1710.    if (offset < 0) {
  1711.       _mesa_error(ctx, GL_INVALID_VALUE,
  1712.                   "glMapBufferRange(offset = %ld)", (long)offset);
  1713.       return;
  1714.    }
  1715.  
  1716.    if (length < 0) {
  1717.       _mesa_error(ctx, GL_INVALID_VALUE,
  1718.                   "glMapBufferRange(length = %ld)", (long)length);
  1719.       return;
  1720.    }
  1721.  
  1722.    bufObj = get_buffer(ctx, target);
  1723.    if (!bufObj) {
  1724.       _mesa_error(ctx, GL_INVALID_ENUM,
  1725.                   "glMapBufferRange(target = 0x%x)", target);
  1726.       return;
  1727.    }
  1728.  
  1729.    if (!_mesa_is_bufferobj(bufObj)) {
  1730.       _mesa_error(ctx, GL_INVALID_OPERATION,
  1731.                   "glMapBufferRange(current buffer is 0)");
  1732.       return;
  1733.    }
  1734.  
  1735.    if (!_mesa_bufferobj_mapped(bufObj)) {
  1736.       /* buffer is not mapped */
  1737.       _mesa_error(ctx, GL_INVALID_OPERATION,
  1738.                   "glMapBufferRange(buffer is not mapped)");
  1739.       return;
  1740.    }
  1741.  
  1742.    if ((bufObj->AccessFlags & GL_MAP_FLUSH_EXPLICIT_BIT) == 0) {
  1743.       _mesa_error(ctx, GL_INVALID_OPERATION,
  1744.                   "glMapBufferRange(GL_MAP_FLUSH_EXPLICIT_BIT not set)");
  1745.       return;
  1746.    }
  1747.  
  1748.    if (offset + length > bufObj->Length) {
  1749.       _mesa_error(ctx, GL_INVALID_VALUE,
  1750.                   "glMapBufferRange(offset %ld + length %ld > mapped length %ld)",
  1751.                   (long)offset, (long)length, (long)bufObj->Length);
  1752.       return;
  1753.    }
  1754.  
  1755.    ASSERT(bufObj->AccessFlags & GL_MAP_WRITE_BIT);
  1756.  
  1757.    if (ctx->Driver.FlushMappedBufferRange)
  1758.       ctx->Driver.FlushMappedBufferRange(ctx, target, offset, length, bufObj);
  1759. }
  1760.  
  1761.  
  1762. #if FEATURE_APPLE_object_purgeable
  1763. static GLenum
  1764. _mesa_BufferObjectPurgeable(struct gl_context *ctx, GLuint name, GLenum option)
  1765. {
  1766.    struct gl_buffer_object *bufObj;
  1767.    GLenum retval;
  1768.  
  1769.    bufObj = _mesa_lookup_bufferobj(ctx, name);
  1770.    if (!bufObj) {
  1771.       _mesa_error(ctx, GL_INVALID_VALUE,
  1772.                   "glObjectPurgeable(name = 0x%x)", name);
  1773.       return 0;
  1774.    }
  1775.    if (!_mesa_is_bufferobj(bufObj)) {
  1776.       _mesa_error(ctx, GL_INVALID_OPERATION, "glObjectPurgeable(buffer 0)" );
  1777.       return 0;
  1778.    }
  1779.  
  1780.    if (bufObj->Purgeable) {
  1781.       _mesa_error(ctx, GL_INVALID_OPERATION,
  1782.                   "glObjectPurgeable(name = 0x%x) is already purgeable", name);
  1783.       return GL_VOLATILE_APPLE;
  1784.    }
  1785.  
  1786.    bufObj->Purgeable = GL_TRUE;
  1787.  
  1788.    retval = GL_VOLATILE_APPLE;
  1789.    if (ctx->Driver.BufferObjectPurgeable)
  1790.       retval = ctx->Driver.BufferObjectPurgeable(ctx, bufObj, option);
  1791.  
  1792.    return retval;
  1793. }
  1794.  
  1795.  
  1796. static GLenum
  1797. _mesa_RenderObjectPurgeable(struct gl_context *ctx, GLuint name, GLenum option)
  1798. {
  1799.    struct gl_renderbuffer *bufObj;
  1800.    GLenum retval;
  1801.  
  1802.    bufObj = _mesa_lookup_renderbuffer(ctx, name);
  1803.    if (!bufObj) {
  1804.       _mesa_error(ctx, GL_INVALID_VALUE,
  1805.                   "glObjectUnpurgeable(name = 0x%x)", name);
  1806.       return 0;
  1807.    }
  1808.  
  1809.    if (bufObj->Purgeable) {
  1810.       _mesa_error(ctx, GL_INVALID_OPERATION,
  1811.                   "glObjectPurgeable(name = 0x%x) is already purgeable", name);
  1812.       return GL_VOLATILE_APPLE;
  1813.    }
  1814.  
  1815.    bufObj->Purgeable = GL_TRUE;
  1816.  
  1817.    retval = GL_VOLATILE_APPLE;
  1818.    if (ctx->Driver.RenderObjectPurgeable)
  1819.       retval = ctx->Driver.RenderObjectPurgeable(ctx, bufObj, option);
  1820.  
  1821.    return retval;
  1822. }
  1823.  
  1824.  
  1825. static GLenum
  1826. _mesa_TextureObjectPurgeable(struct gl_context *ctx, GLuint name, GLenum option)
  1827. {
  1828.    struct gl_texture_object *bufObj;
  1829.    GLenum retval;
  1830.  
  1831.    bufObj = _mesa_lookup_texture(ctx, name);
  1832.    if (!bufObj) {
  1833.       _mesa_error(ctx, GL_INVALID_VALUE,
  1834.                   "glObjectPurgeable(name = 0x%x)", name);
  1835.       return 0;
  1836.    }
  1837.  
  1838.    if (bufObj->Purgeable) {
  1839.       _mesa_error(ctx, GL_INVALID_OPERATION,
  1840.                   "glObjectPurgeable(name = 0x%x) is already purgeable", name);
  1841.       return GL_VOLATILE_APPLE;
  1842.    }
  1843.  
  1844.    bufObj->Purgeable = GL_TRUE;
  1845.  
  1846.    retval = GL_VOLATILE_APPLE;
  1847.    if (ctx->Driver.TextureObjectPurgeable)
  1848.       retval = ctx->Driver.TextureObjectPurgeable(ctx, bufObj, option);
  1849.  
  1850.    return retval;
  1851. }
  1852.  
  1853.  
  1854. GLenum GLAPIENTRY
  1855. _mesa_ObjectPurgeableAPPLE(GLenum objectType, GLuint name, GLenum option)
  1856. {
  1857.    GLenum retval;
  1858.  
  1859.    GET_CURRENT_CONTEXT(ctx);
  1860.    ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0);
  1861.  
  1862.    if (name == 0) {
  1863.       _mesa_error(ctx, GL_INVALID_VALUE,
  1864.                   "glObjectPurgeable(name = 0x%x)", name);
  1865.       return 0;
  1866.    }
  1867.  
  1868.    switch (option) {
  1869.    case GL_VOLATILE_APPLE:
  1870.    case GL_RELEASED_APPLE:
  1871.       /* legal */
  1872.       break;
  1873.    default:
  1874.       _mesa_error(ctx, GL_INVALID_ENUM,
  1875.                   "glObjectPurgeable(name = 0x%x) invalid option: %d",
  1876.                   name, option);
  1877.       return 0;
  1878.    }
  1879.  
  1880.    switch (objectType) {
  1881.    case GL_TEXTURE:
  1882.       retval = _mesa_TextureObjectPurgeable (ctx, name, option);
  1883.       break;
  1884.    case GL_RENDERBUFFER_EXT:
  1885.       retval = _mesa_RenderObjectPurgeable (ctx, name, option);
  1886.       break;
  1887.    case GL_BUFFER_OBJECT_APPLE:
  1888.       retval = _mesa_BufferObjectPurgeable (ctx, name, option);
  1889.       break;
  1890.    default:
  1891.       _mesa_error(ctx, GL_INVALID_ENUM,
  1892.                   "glObjectPurgeable(name = 0x%x) invalid type: %d",
  1893.                   name, objectType);
  1894.       return 0;
  1895.    }
  1896.  
  1897.    /* In strict conformance to the spec, we must only return VOLATILE when
  1898.     * when passed the VOLATILE option. Madness.
  1899.     *
  1900.     * XXX First fix the spec, then fix me.
  1901.     */
  1902.    return option == GL_VOLATILE_APPLE ? GL_VOLATILE_APPLE : retval;
  1903. }
  1904.  
  1905.  
  1906. static GLenum
  1907. _mesa_BufferObjectUnpurgeable(struct gl_context *ctx, GLuint name, GLenum option)
  1908. {
  1909.    struct gl_buffer_object *bufObj;
  1910.    GLenum retval;
  1911.  
  1912.    bufObj = _mesa_lookup_bufferobj(ctx, name);
  1913.    if (!bufObj) {
  1914.       _mesa_error(ctx, GL_INVALID_VALUE,
  1915.                   "glObjectUnpurgeable(name = 0x%x)", name);
  1916.       return 0;
  1917.    }
  1918.  
  1919.    if (! bufObj->Purgeable) {
  1920.       _mesa_error(ctx, GL_INVALID_OPERATION,
  1921.                   "glObjectUnpurgeable(name = 0x%x) object is "
  1922.                   " already \"unpurged\"", name);
  1923.       return 0;
  1924.    }
  1925.  
  1926.    bufObj->Purgeable = GL_FALSE;
  1927.  
  1928.    retval = option;
  1929.    if (ctx->Driver.BufferObjectUnpurgeable)
  1930.       retval = ctx->Driver.BufferObjectUnpurgeable(ctx, bufObj, option);
  1931.  
  1932.    return retval;
  1933. }
  1934.  
  1935.  
  1936. static GLenum
  1937. _mesa_RenderObjectUnpurgeable(struct gl_context *ctx, GLuint name, GLenum option)
  1938. {
  1939.    struct gl_renderbuffer *bufObj;
  1940.    GLenum retval;
  1941.  
  1942.    bufObj = _mesa_lookup_renderbuffer(ctx, name);
  1943.    if (!bufObj) {
  1944.       _mesa_error(ctx, GL_INVALID_VALUE,
  1945.                   "glObjectUnpurgeable(name = 0x%x)", name);
  1946.       return 0;
  1947.    }
  1948.  
  1949.    if (! bufObj->Purgeable) {
  1950.       _mesa_error(ctx, GL_INVALID_OPERATION,
  1951.                   "glObjectUnpurgeable(name = 0x%x) object is "
  1952.                   " already \"unpurged\"", name);
  1953.       return 0;
  1954.    }
  1955.  
  1956.    bufObj->Purgeable = GL_FALSE;
  1957.  
  1958.    retval = option;
  1959.    if (ctx->Driver.RenderObjectUnpurgeable)
  1960.       retval = ctx->Driver.RenderObjectUnpurgeable(ctx, bufObj, option);
  1961.  
  1962.    return retval;
  1963. }
  1964.  
  1965.  
  1966. static GLenum
  1967. _mesa_TextureObjectUnpurgeable(struct gl_context *ctx, GLuint name, GLenum option)
  1968. {
  1969.    struct gl_texture_object *bufObj;
  1970.    GLenum retval;
  1971.  
  1972.    bufObj = _mesa_lookup_texture(ctx, name);
  1973.    if (!bufObj) {
  1974.       _mesa_error(ctx, GL_INVALID_VALUE,
  1975.                   "glObjectUnpurgeable(name = 0x%x)", name);
  1976.       return 0;
  1977.    }
  1978.  
  1979.    if (! bufObj->Purgeable) {
  1980.       _mesa_error(ctx, GL_INVALID_OPERATION,
  1981.                   "glObjectUnpurgeable(name = 0x%x) object is"
  1982.                   " already \"unpurged\"", name);
  1983.       return 0;
  1984.    }
  1985.  
  1986.    bufObj->Purgeable = GL_FALSE;
  1987.  
  1988.    retval = option;
  1989.    if (ctx->Driver.TextureObjectUnpurgeable)
  1990.       retval = ctx->Driver.TextureObjectUnpurgeable(ctx, bufObj, option);
  1991.  
  1992.    return retval;
  1993. }
  1994.  
  1995.  
  1996. GLenum GLAPIENTRY
  1997. _mesa_ObjectUnpurgeableAPPLE(GLenum objectType, GLuint name, GLenum option)
  1998. {
  1999.    GET_CURRENT_CONTEXT(ctx);
  2000.    ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0);
  2001.  
  2002.    if (name == 0) {
  2003.       _mesa_error(ctx, GL_INVALID_VALUE,
  2004.                   "glObjectUnpurgeable(name = 0x%x)", name);
  2005.       return 0;
  2006.    }
  2007.  
  2008.    switch (option) {
  2009.    case GL_RETAINED_APPLE:
  2010.    case GL_UNDEFINED_APPLE:
  2011.       /* legal */
  2012.       break;
  2013.    default:
  2014.       _mesa_error(ctx, GL_INVALID_ENUM,
  2015.                   "glObjectUnpurgeable(name = 0x%x) invalid option: %d",
  2016.                   name, option);
  2017.       return 0;
  2018.    }
  2019.  
  2020.    switch (objectType) {
  2021.    case GL_BUFFER_OBJECT_APPLE:
  2022.       return _mesa_BufferObjectUnpurgeable(ctx, name, option);
  2023.    case GL_TEXTURE:
  2024.       return _mesa_TextureObjectUnpurgeable(ctx, name, option);
  2025.    case GL_RENDERBUFFER_EXT:
  2026.       return _mesa_RenderObjectUnpurgeable(ctx, name, option);
  2027.    default:
  2028.       _mesa_error(ctx, GL_INVALID_ENUM,
  2029.                   "glObjectUnpurgeable(name = 0x%x) invalid type: %d",
  2030.                   name, objectType);
  2031.       return 0;
  2032.    }
  2033. }
  2034.  
  2035.  
  2036. static void
  2037. _mesa_GetBufferObjectParameterivAPPLE(struct gl_context *ctx, GLuint name,
  2038.                                       GLenum pname, GLint* params)
  2039. {
  2040.    struct gl_buffer_object *bufObj;
  2041.  
  2042.    bufObj = _mesa_lookup_bufferobj(ctx, name);
  2043.    if (!bufObj) {
  2044.       _mesa_error(ctx, GL_INVALID_VALUE,
  2045.                   "glGetObjectParameteriv(name = 0x%x) invalid object", name);
  2046.       return;
  2047.    }
  2048.  
  2049.    switch (pname) {
  2050.    case GL_PURGEABLE_APPLE:
  2051.       *params = bufObj->Purgeable;
  2052.       break;
  2053.    default:
  2054.       _mesa_error(ctx, GL_INVALID_ENUM,
  2055.                   "glGetObjectParameteriv(name = 0x%x) invalid enum: %d",
  2056.                   name, pname);
  2057.       break;
  2058.    }
  2059. }
  2060.  
  2061.  
  2062. static void
  2063. _mesa_GetRenderObjectParameterivAPPLE(struct gl_context *ctx, GLuint name,
  2064.                                       GLenum pname, GLint* params)
  2065. {
  2066.    struct gl_renderbuffer *bufObj;
  2067.  
  2068.    bufObj = _mesa_lookup_renderbuffer(ctx, name);
  2069.    if (!bufObj) {
  2070.       _mesa_error(ctx, GL_INVALID_VALUE,
  2071.                   "glObjectUnpurgeable(name = 0x%x)", name);
  2072.       return;
  2073.    }
  2074.  
  2075.    switch (pname) {
  2076.    case GL_PURGEABLE_APPLE:
  2077.       *params = bufObj->Purgeable;
  2078.       break;
  2079.    default:
  2080.       _mesa_error(ctx, GL_INVALID_ENUM,
  2081.                   "glGetObjectParameteriv(name = 0x%x) invalid enum: %d",
  2082.                   name, pname);
  2083.       break;
  2084.    }
  2085. }
  2086.  
  2087.  
  2088. static void
  2089. _mesa_GetTextureObjectParameterivAPPLE(struct gl_context *ctx, GLuint name,
  2090.                                        GLenum pname, GLint* params)
  2091. {
  2092.    struct gl_texture_object *bufObj;
  2093.  
  2094.    bufObj = _mesa_lookup_texture(ctx, name);
  2095.    if (!bufObj) {
  2096.       _mesa_error(ctx, GL_INVALID_VALUE,
  2097.                   "glObjectUnpurgeable(name = 0x%x)", name);
  2098.       return;
  2099.    }
  2100.  
  2101.    switch (pname) {
  2102.    case GL_PURGEABLE_APPLE:
  2103.       *params = bufObj->Purgeable;
  2104.       break;
  2105.    default:
  2106.       _mesa_error(ctx, GL_INVALID_ENUM,
  2107.                   "glGetObjectParameteriv(name = 0x%x) invalid enum: %d",
  2108.                   name, pname);
  2109.       break;
  2110.    }
  2111. }
  2112.  
  2113.  
  2114. void GLAPIENTRY
  2115. _mesa_GetObjectParameterivAPPLE(GLenum objectType, GLuint name, GLenum pname,
  2116.                                 GLint* params)
  2117. {
  2118.    GET_CURRENT_CONTEXT(ctx);
  2119.  
  2120.    if (name == 0) {
  2121.       _mesa_error(ctx, GL_INVALID_VALUE,
  2122.                   "glGetObjectParameteriv(name = 0x%x)", name);
  2123.       return;
  2124.    }
  2125.  
  2126.    switch (objectType) {
  2127.    case GL_TEXTURE:
  2128.       _mesa_GetTextureObjectParameterivAPPLE (ctx, name, pname, params);
  2129.       break;
  2130.    case GL_BUFFER_OBJECT_APPLE:
  2131.       _mesa_GetBufferObjectParameterivAPPLE (ctx, name, pname, params);
  2132.       break;
  2133.    case GL_RENDERBUFFER_EXT:
  2134.       _mesa_GetRenderObjectParameterivAPPLE (ctx, name, pname, params);
  2135.       break;
  2136.    default:
  2137.       _mesa_error(ctx, GL_INVALID_ENUM,
  2138.                   "glGetObjectParameteriv(name = 0x%x) invalid type: %d",
  2139.                   name, objectType);
  2140.    }
  2141. }
  2142.  
  2143. #endif /* FEATURE_APPLE_object_purgeable */
  2144.