bufferobj.c revision 7117f1b4
17117f1b4Smrg/*
27117f1b4Smrg * Mesa 3-D graphics library
37117f1b4Smrg * Version:  6.5.1
47117f1b4Smrg *
57117f1b4Smrg * Copyright (C) 1999-2006  Brian Paul   All Rights Reserved.
67117f1b4Smrg *
77117f1b4Smrg * Permission is hereby granted, free of charge, to any person obtaining a
87117f1b4Smrg * copy of this software and associated documentation files (the "Software"),
97117f1b4Smrg * to deal in the Software without restriction, including without limitation
107117f1b4Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
117117f1b4Smrg * and/or sell copies of the Software, and to permit persons to whom the
127117f1b4Smrg * Software is furnished to do so, subject to the following conditions:
137117f1b4Smrg *
147117f1b4Smrg * The above copyright notice and this permission notice shall be included
157117f1b4Smrg * in all copies or substantial portions of the Software.
167117f1b4Smrg *
177117f1b4Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
187117f1b4Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
197117f1b4Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
207117f1b4Smrg * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
217117f1b4Smrg * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
227117f1b4Smrg * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
237117f1b4Smrg */
247117f1b4Smrg
257117f1b4Smrg
267117f1b4Smrg/**
277117f1b4Smrg * \file bufferobj.c
287117f1b4Smrg * \brief Functions for the GL_ARB_vertex_buffer_object extension.
297117f1b4Smrg * \author Brian Paul, Ian Romanick
307117f1b4Smrg */
317117f1b4Smrg
327117f1b4Smrg
337117f1b4Smrg#include "glheader.h"
347117f1b4Smrg#include "hash.h"
357117f1b4Smrg#include "imports.h"
367117f1b4Smrg#include "image.h"
377117f1b4Smrg#include "context.h"
387117f1b4Smrg#include "bufferobj.h"
397117f1b4Smrg
407117f1b4Smrg
417117f1b4Smrg/**
427117f1b4Smrg * Get the buffer object bound to the specified target in a GL context.
437117f1b4Smrg *
447117f1b4Smrg * \param ctx     GL context
457117f1b4Smrg * \param target  Buffer object target to be retrieved.  Currently this must
467117f1b4Smrg *                be either \c GL_ARRAY_BUFFER or \c GL_ELEMENT_ARRAY_BUFFER.
477117f1b4Smrg * \return   A pointer to the buffer object bound to \c target in the
487117f1b4Smrg *           specified context or \c NULL if \c target is invalid.
497117f1b4Smrg */
507117f1b4Smrgstatic INLINE struct gl_buffer_object *
517117f1b4Smrgget_buffer(GLcontext *ctx, GLenum target)
527117f1b4Smrg{
537117f1b4Smrg   struct gl_buffer_object * bufObj = NULL;
547117f1b4Smrg
557117f1b4Smrg   switch (target) {
567117f1b4Smrg      case GL_ARRAY_BUFFER_ARB:
577117f1b4Smrg         bufObj = ctx->Array.ArrayBufferObj;
587117f1b4Smrg         break;
597117f1b4Smrg      case GL_ELEMENT_ARRAY_BUFFER_ARB:
607117f1b4Smrg         bufObj = ctx->Array.ElementArrayBufferObj;
617117f1b4Smrg         break;
627117f1b4Smrg      case GL_PIXEL_PACK_BUFFER_EXT:
637117f1b4Smrg         bufObj = ctx->Pack.BufferObj;
647117f1b4Smrg         break;
657117f1b4Smrg      case GL_PIXEL_UNPACK_BUFFER_EXT:
667117f1b4Smrg         bufObj = ctx->Unpack.BufferObj;
677117f1b4Smrg         break;
687117f1b4Smrg      default:
697117f1b4Smrg         /* error must be recorded by caller */
707117f1b4Smrg         return NULL;
717117f1b4Smrg   }
727117f1b4Smrg
737117f1b4Smrg   /* bufObj should point to NullBufferObj or a user-created buffer object */
747117f1b4Smrg   ASSERT(bufObj);
757117f1b4Smrg
767117f1b4Smrg   return bufObj;
777117f1b4Smrg}
787117f1b4Smrg
797117f1b4Smrg
807117f1b4Smrg/**
817117f1b4Smrg * Tests the subdata range parameters and sets the GL error code for
827117f1b4Smrg * \c glBufferSubDataARB and \c glGetBufferSubDataARB.
837117f1b4Smrg *
847117f1b4Smrg * \param ctx     GL context.
857117f1b4Smrg * \param target  Buffer object target on which to operate.
867117f1b4Smrg * \param offset  Offset of the first byte of the subdata range.
877117f1b4Smrg * \param size    Size, in bytes, of the subdata range.
887117f1b4Smrg * \param caller  Name of calling function for recording errors.
897117f1b4Smrg * \return   A pointer to the buffer object bound to \c target in the
907117f1b4Smrg *           specified context or \c NULL if any of the parameter or state
917117f1b4Smrg *           conditions for \c glBufferSubDataARB or \c glGetBufferSubDataARB
927117f1b4Smrg *           are invalid.
937117f1b4Smrg *
947117f1b4Smrg * \sa glBufferSubDataARB, glGetBufferSubDataARB
957117f1b4Smrg */
967117f1b4Smrgstatic struct gl_buffer_object *
977117f1b4Smrgbuffer_object_subdata_range_good( GLcontext * ctx, GLenum target,
987117f1b4Smrg                                  GLintptrARB offset, GLsizeiptrARB size,
997117f1b4Smrg                                  const char *caller )
1007117f1b4Smrg{
1017117f1b4Smrg   struct gl_buffer_object *bufObj;
1027117f1b4Smrg
1037117f1b4Smrg   if (size < 0) {
1047117f1b4Smrg      _mesa_error(ctx, GL_INVALID_VALUE, "%s(size < 0)", caller);
1057117f1b4Smrg      return NULL;
1067117f1b4Smrg   }
1077117f1b4Smrg
1087117f1b4Smrg   if (offset < 0) {
1097117f1b4Smrg      _mesa_error(ctx, GL_INVALID_VALUE, "%s(offset < 0)", caller);
1107117f1b4Smrg      return NULL;
1117117f1b4Smrg   }
1127117f1b4Smrg
1137117f1b4Smrg   bufObj = get_buffer(ctx, target);
1147117f1b4Smrg   if (!bufObj) {
1157117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "%s(target)", caller);
1167117f1b4Smrg      return NULL;
1177117f1b4Smrg   }
1187117f1b4Smrg   if (bufObj->Name == 0) {
1197117f1b4Smrg      _mesa_error(ctx, GL_INVALID_OPERATION, "%s", caller);
1207117f1b4Smrg      return NULL;
1217117f1b4Smrg   }
1227117f1b4Smrg   if (offset + size > bufObj->Size) {
1237117f1b4Smrg      _mesa_error(ctx, GL_INVALID_VALUE,
1247117f1b4Smrg		  "%s(size + offset > buffer size)", caller);
1257117f1b4Smrg      return NULL;
1267117f1b4Smrg   }
1277117f1b4Smrg   if (bufObj->Pointer) {
1287117f1b4Smrg      /* Buffer is currently mapped */
1297117f1b4Smrg      _mesa_error(ctx, GL_INVALID_OPERATION, "%s", caller);
1307117f1b4Smrg      return NULL;
1317117f1b4Smrg   }
1327117f1b4Smrg
1337117f1b4Smrg   return bufObj;
1347117f1b4Smrg}
1357117f1b4Smrg
1367117f1b4Smrg
1377117f1b4Smrg/**
1387117f1b4Smrg * Allocate and initialize a new buffer object.
1397117f1b4Smrg *
1407117f1b4Smrg * This function is intended to be called via
1417117f1b4Smrg * \c dd_function_table::NewBufferObject.
1427117f1b4Smrg */
1437117f1b4Smrgstruct gl_buffer_object *
1447117f1b4Smrg_mesa_new_buffer_object( GLcontext *ctx, GLuint name, GLenum target )
1457117f1b4Smrg{
1467117f1b4Smrg   struct gl_buffer_object *obj;
1477117f1b4Smrg
1487117f1b4Smrg   (void) ctx;
1497117f1b4Smrg
1507117f1b4Smrg   obj = MALLOC_STRUCT(gl_buffer_object);
1517117f1b4Smrg   _mesa_initialize_buffer_object(obj, name, target);
1527117f1b4Smrg   return obj;
1537117f1b4Smrg}
1547117f1b4Smrg
1557117f1b4Smrg
1567117f1b4Smrg/**
1577117f1b4Smrg * Delete a buffer object.
1587117f1b4Smrg *
1597117f1b4Smrg * This function is intended to be called via
1607117f1b4Smrg * \c dd_function_table::DeleteBuffer.
1617117f1b4Smrg */
1627117f1b4Smrgvoid
1637117f1b4Smrg_mesa_delete_buffer_object( GLcontext *ctx, struct gl_buffer_object *bufObj )
1647117f1b4Smrg{
1657117f1b4Smrg   (void) ctx;
1667117f1b4Smrg
1677117f1b4Smrg   if (bufObj->Data)
1687117f1b4Smrg      _mesa_free(bufObj->Data);
1697117f1b4Smrg   _mesa_free(bufObj);
1707117f1b4Smrg}
1717117f1b4Smrg
1727117f1b4Smrg
1737117f1b4Smrgvoid
1747117f1b4Smrg_mesa_unbind_buffer_object( GLcontext *ctx, struct gl_buffer_object *bufObj )
1757117f1b4Smrg{
1767117f1b4Smrg   if (bufObj != ctx->Array.NullBufferObj) {
1777117f1b4Smrg      bufObj->RefCount--;
1787117f1b4Smrg      if (bufObj->RefCount <= 0) {
1797117f1b4Smrg	 ASSERT(ctx->Array.ArrayBufferObj != bufObj);
1807117f1b4Smrg	 ASSERT(ctx->Array.ElementArrayBufferObj != bufObj);
1817117f1b4Smrg	 ASSERT(ctx->Array.ArrayObj->Vertex.BufferObj != bufObj);
1827117f1b4Smrg	 ASSERT(ctx->Driver.DeleteBuffer);
1837117f1b4Smrg	 ctx->Driver.DeleteBuffer(ctx, bufObj);
1847117f1b4Smrg      }
1857117f1b4Smrg   }
1867117f1b4Smrg}
1877117f1b4Smrg
1887117f1b4Smrg
1897117f1b4Smrg/**
1907117f1b4Smrg * Initialize a buffer object to default values.
1917117f1b4Smrg */
1927117f1b4Smrgvoid
1937117f1b4Smrg_mesa_initialize_buffer_object( struct gl_buffer_object *obj,
1947117f1b4Smrg				GLuint name, GLenum target )
1957117f1b4Smrg{
1967117f1b4Smrg   (void) target;
1977117f1b4Smrg
1987117f1b4Smrg   _mesa_bzero(obj, sizeof(struct gl_buffer_object));
1997117f1b4Smrg   obj->RefCount = 1;
2007117f1b4Smrg   obj->Name = name;
2017117f1b4Smrg   obj->Usage = GL_STATIC_DRAW_ARB;
2027117f1b4Smrg   obj->Access = GL_READ_WRITE_ARB;
2037117f1b4Smrg}
2047117f1b4Smrg
2057117f1b4Smrg
2067117f1b4Smrg/**
2077117f1b4Smrg * Add the given buffer object to the buffer object pool.
2087117f1b4Smrg */
2097117f1b4Smrgvoid
2107117f1b4Smrg_mesa_save_buffer_object( GLcontext *ctx, struct gl_buffer_object *obj )
2117117f1b4Smrg{
2127117f1b4Smrg   if (obj->Name > 0) {
2137117f1b4Smrg      /* insert into hash table */
2147117f1b4Smrg      _mesa_HashInsert(ctx->Shared->BufferObjects, obj->Name, obj);
2157117f1b4Smrg   }
2167117f1b4Smrg}
2177117f1b4Smrg
2187117f1b4Smrg
2197117f1b4Smrg/**
2207117f1b4Smrg * Remove the given buffer object from the buffer object pool.
2217117f1b4Smrg * Do not deallocate the buffer object though.
2227117f1b4Smrg */
2237117f1b4Smrgvoid
2247117f1b4Smrg_mesa_remove_buffer_object( GLcontext *ctx, struct gl_buffer_object *bufObj )
2257117f1b4Smrg{
2267117f1b4Smrg   if (bufObj->Name > 0) {
2277117f1b4Smrg      /* remove from hash table */
2287117f1b4Smrg      _mesa_HashRemove(ctx->Shared->BufferObjects, bufObj->Name);
2297117f1b4Smrg   }
2307117f1b4Smrg}
2317117f1b4Smrg
2327117f1b4Smrg
2337117f1b4Smrg/**
2347117f1b4Smrg * Allocate space for and store data in a buffer object.  Any data that was
2357117f1b4Smrg * previously stored in the buffer object is lost.  If \c data is \c NULL,
2367117f1b4Smrg * memory will be allocated, but no copy will occur.
2377117f1b4Smrg *
2387117f1b4Smrg * This function is intended to be called via
2397117f1b4Smrg * \c dd_function_table::BufferData.  This function need not set GL error
2407117f1b4Smrg * codes.  The input parameters will have been tested before calling.
2417117f1b4Smrg *
2427117f1b4Smrg * \param ctx     GL context.
2437117f1b4Smrg * \param target  Buffer object target on which to operate.
2447117f1b4Smrg * \param size    Size, in bytes, of the new data store.
2457117f1b4Smrg * \param data    Pointer to the data to store in the buffer object.  This
2467117f1b4Smrg *                pointer may be \c NULL.
2477117f1b4Smrg * \param usage   Hints about how the data will be used.
2487117f1b4Smrg * \param bufObj  Object to be used.
2497117f1b4Smrg *
2507117f1b4Smrg * \sa glBufferDataARB, dd_function_table::BufferData.
2517117f1b4Smrg */
2527117f1b4Smrgvoid
2537117f1b4Smrg_mesa_buffer_data( GLcontext *ctx, GLenum target, GLsizeiptrARB size,
2547117f1b4Smrg		   const GLvoid * data, GLenum usage,
2557117f1b4Smrg		   struct gl_buffer_object * bufObj )
2567117f1b4Smrg{
2577117f1b4Smrg   void * new_data;
2587117f1b4Smrg
2597117f1b4Smrg   (void) ctx; (void) target;
2607117f1b4Smrg
2617117f1b4Smrg   new_data = _mesa_realloc( bufObj->Data, bufObj->Size, size );
2627117f1b4Smrg   if (new_data) {
2637117f1b4Smrg      bufObj->Data = (GLubyte *) new_data;
2647117f1b4Smrg      bufObj->Size = size;
2657117f1b4Smrg      bufObj->Usage = usage;
2667117f1b4Smrg
2677117f1b4Smrg      if (data) {
2687117f1b4Smrg	 _mesa_memcpy( bufObj->Data, data, size );
2697117f1b4Smrg      }
2707117f1b4Smrg   }
2717117f1b4Smrg}
2727117f1b4Smrg
2737117f1b4Smrg
2747117f1b4Smrg/**
2757117f1b4Smrg * Replace data in a subrange of buffer object.  If the data range
2767117f1b4Smrg * specified by \c size + \c offset extends beyond the end of the buffer or
2777117f1b4Smrg * if \c data is \c NULL, no copy is performed.
2787117f1b4Smrg *
2797117f1b4Smrg * This function is intended to be called by
2807117f1b4Smrg * \c dd_function_table::BufferSubData.  This function need not set GL error
2817117f1b4Smrg * codes.  The input parameters will have been tested before calling.
2827117f1b4Smrg *
2837117f1b4Smrg * \param ctx     GL context.
2847117f1b4Smrg * \param target  Buffer object target on which to operate.
2857117f1b4Smrg * \param offset  Offset of the first byte to be modified.
2867117f1b4Smrg * \param size    Size, in bytes, of the data range.
2877117f1b4Smrg * \param data    Pointer to the data to store in the buffer object.
2887117f1b4Smrg * \param bufObj  Object to be used.
2897117f1b4Smrg *
2907117f1b4Smrg * \sa glBufferSubDataARB, dd_function_table::BufferSubData.
2917117f1b4Smrg */
2927117f1b4Smrgvoid
2937117f1b4Smrg_mesa_buffer_subdata( GLcontext *ctx, GLenum target, GLintptrARB offset,
2947117f1b4Smrg		      GLsizeiptrARB size, const GLvoid * data,
2957117f1b4Smrg		      struct gl_buffer_object * bufObj )
2967117f1b4Smrg{
2977117f1b4Smrg   (void) ctx; (void) target;
2987117f1b4Smrg
2997117f1b4Smrg   /* this should have been caught in _mesa_BufferSubData() */
3007117f1b4Smrg   ASSERT(size + offset <= bufObj->Size);
3017117f1b4Smrg
3027117f1b4Smrg   if (bufObj->Data) {
3037117f1b4Smrg      _mesa_memcpy( (GLubyte *) bufObj->Data + offset, data, size );
3047117f1b4Smrg   }
3057117f1b4Smrg}
3067117f1b4Smrg
3077117f1b4Smrg
3087117f1b4Smrg/**
3097117f1b4Smrg * Retrieve data from a subrange of buffer object.  If the data range
3107117f1b4Smrg * specified by \c size + \c offset extends beyond the end of the buffer or
3117117f1b4Smrg * if \c data is \c NULL, no copy is performed.
3127117f1b4Smrg *
3137117f1b4Smrg * This function is intended to be called by
3147117f1b4Smrg * \c dd_function_table::BufferGetSubData.  This function need not set GL error
3157117f1b4Smrg * codes.  The input parameters will have been tested before calling.
3167117f1b4Smrg *
3177117f1b4Smrg * \param ctx     GL context.
3187117f1b4Smrg * \param target  Buffer object target on which to operate.
3197117f1b4Smrg * \param offset  Offset of the first byte to be modified.
3207117f1b4Smrg * \param size    Size, in bytes, of the data range.
3217117f1b4Smrg * \param data    Pointer to the data to store in the buffer object.
3227117f1b4Smrg * \param bufObj  Object to be used.
3237117f1b4Smrg *
3247117f1b4Smrg * \sa glBufferGetSubDataARB, dd_function_table::GetBufferSubData.
3257117f1b4Smrg */
3267117f1b4Smrgvoid
3277117f1b4Smrg_mesa_buffer_get_subdata( GLcontext *ctx, GLenum target, GLintptrARB offset,
3287117f1b4Smrg			  GLsizeiptrARB size, GLvoid * data,
3297117f1b4Smrg			  struct gl_buffer_object * bufObj )
3307117f1b4Smrg{
3317117f1b4Smrg   (void) ctx; (void) target;
3327117f1b4Smrg
3337117f1b4Smrg   if (bufObj->Data && ((GLsizeiptrARB) (size + offset) <= bufObj->Size)) {
3347117f1b4Smrg      _mesa_memcpy( data, (GLubyte *) bufObj->Data + offset, size );
3357117f1b4Smrg   }
3367117f1b4Smrg}
3377117f1b4Smrg
3387117f1b4Smrg
3397117f1b4Smrg/**
3407117f1b4Smrg * Fallback function called via ctx->Driver.MapBuffer().
3417117f1b4Smrg * Hardware drivers that really implement buffer objects should never use
3427117f1b4Smrg * this function.
3437117f1b4Smrg *
3447117f1b4Smrg * The function parameters will have been already tested for errors.
3457117f1b4Smrg *
3467117f1b4Smrg * \param ctx     GL context.
3477117f1b4Smrg * \param target  Buffer object target on which to operate.
3487117f1b4Smrg * \param access  Information about how the buffer will be accessed.
3497117f1b4Smrg * \param bufObj  Object to be mapped.
3507117f1b4Smrg * \return  A pointer to the object's internal data store that can be accessed
3517117f1b4Smrg *          by the processor
3527117f1b4Smrg *
3537117f1b4Smrg * \sa glMapBufferARB, dd_function_table::MapBuffer
3547117f1b4Smrg */
3557117f1b4Smrgvoid *
3567117f1b4Smrg_mesa_buffer_map( GLcontext *ctx, GLenum target, GLenum access,
3577117f1b4Smrg		  struct gl_buffer_object *bufObj )
3587117f1b4Smrg{
3597117f1b4Smrg   (void) ctx;
3607117f1b4Smrg   (void) target;
3617117f1b4Smrg   (void) access;
3627117f1b4Smrg   ASSERT(!bufObj->OnCard);
3637117f1b4Smrg   /* Just return a direct pointer to the data */
3647117f1b4Smrg   if (bufObj->Pointer) {
3657117f1b4Smrg      /* already mapped! */
3667117f1b4Smrg      return NULL;
3677117f1b4Smrg   }
3687117f1b4Smrg   bufObj->Pointer = bufObj->Data;
3697117f1b4Smrg   return bufObj->Pointer;
3707117f1b4Smrg}
3717117f1b4Smrg
3727117f1b4Smrg
3737117f1b4Smrg/**
3747117f1b4Smrg * Fallback function called via ctx->Driver.MapBuffer().
3757117f1b4Smrg * Hardware drivers that really implement buffer objects should never use
3767117f1b4Smrg * function.
3777117f1b4Smrg *
3787117f1b4Smrg * The input parameters will have been already tested for errors.
3797117f1b4Smrg *
3807117f1b4Smrg * \sa glUnmapBufferARB, dd_function_table::UnmapBuffer
3817117f1b4Smrg */
3827117f1b4SmrgGLboolean
3837117f1b4Smrg_mesa_buffer_unmap( GLcontext *ctx, GLenum target,
3847117f1b4Smrg                    struct gl_buffer_object *bufObj )
3857117f1b4Smrg{
3867117f1b4Smrg   (void) ctx;
3877117f1b4Smrg   (void) target;
3887117f1b4Smrg   ASSERT(!bufObj->OnCard);
3897117f1b4Smrg   /* XXX we might assert here that bufObj->Pointer is non-null */
3907117f1b4Smrg   bufObj->Pointer = NULL;
3917117f1b4Smrg   return GL_TRUE;
3927117f1b4Smrg}
3937117f1b4Smrg
3947117f1b4Smrg
3957117f1b4Smrg/**
3967117f1b4Smrg * Initialize the state associated with buffer objects
3977117f1b4Smrg */
3987117f1b4Smrgvoid
3997117f1b4Smrg_mesa_init_buffer_objects( GLcontext *ctx )
4007117f1b4Smrg{
4017117f1b4Smrg   /* Allocate the default buffer object and set refcount so high that
4027117f1b4Smrg    * it never gets deleted.
4037117f1b4Smrg    */
4047117f1b4Smrg   ctx->Array.NullBufferObj = _mesa_new_buffer_object(ctx, 0, 0);
4057117f1b4Smrg   if (ctx->Array.NullBufferObj)
4067117f1b4Smrg      ctx->Array.NullBufferObj->RefCount = 1000;
4077117f1b4Smrg
4087117f1b4Smrg   ctx->Array.ArrayBufferObj = ctx->Array.NullBufferObj;
4097117f1b4Smrg   ctx->Array.ElementArrayBufferObj = ctx->Array.NullBufferObj;
4107117f1b4Smrg}
4117117f1b4Smrg
4127117f1b4Smrg
4137117f1b4Smrg/**
4147117f1b4Smrg * When we're about to read pixel data out of a PBO (via glDrawPixels,
4157117f1b4Smrg * glTexImage, etc) or write data into a PBO (via glReadPixels,
4167117f1b4Smrg * glGetTexImage, etc) we call this function to check that we're not
4177117f1b4Smrg * going to read out of bounds.
4187117f1b4Smrg *
4197117f1b4Smrg * XXX This would also be a convenient time to check that the PBO isn't
4207117f1b4Smrg * currently mapped.  Whoever calls this function should check for that.
4217117f1b4Smrg * Remember, we can't use a PBO when it's mapped!
4227117f1b4Smrg *
4237117f1b4Smrg * \param width  width of image to read/write
4247117f1b4Smrg * \param height  height of image to read/write
4257117f1b4Smrg * \param depth  depth of image to read/write
4267117f1b4Smrg * \param format  format of image to read/write
4277117f1b4Smrg * \param type  datatype of image to read/write
4287117f1b4Smrg * \param ptr  the user-provided pointer/offset
4297117f1b4Smrg * \return GL_TRUE if the PBO access is OK, GL_FALSE if the access would
4307117f1b4Smrg *         go out of bounds.
4317117f1b4Smrg */
4327117f1b4SmrgGLboolean
4337117f1b4Smrg_mesa_validate_pbo_access(GLuint dimensions,
4347117f1b4Smrg                          const struct gl_pixelstore_attrib *pack,
4357117f1b4Smrg                          GLsizei width, GLsizei height, GLsizei depth,
4367117f1b4Smrg                          GLenum format, GLenum type, const GLvoid *ptr)
4377117f1b4Smrg{
4387117f1b4Smrg   GLvoid *start, *end;
4397117f1b4Smrg   const GLubyte *sizeAddr; /* buffer size, cast to a pointer */
4407117f1b4Smrg
4417117f1b4Smrg   ASSERT(pack->BufferObj->Name != 0);
4427117f1b4Smrg
4437117f1b4Smrg   if (pack->BufferObj->Size == 0)
4447117f1b4Smrg      /* no buffer! */
4457117f1b4Smrg      return GL_FALSE;
4467117f1b4Smrg
4477117f1b4Smrg   /* get address of first pixel we'll read */
4487117f1b4Smrg   start = _mesa_image_address(dimensions, pack, ptr, width, height,
4497117f1b4Smrg                               format, type, 0, 0, 0);
4507117f1b4Smrg
4517117f1b4Smrg   /* get address just past the last pixel we'll read */
4527117f1b4Smrg   end =  _mesa_image_address(dimensions, pack, ptr, width, height,
4537117f1b4Smrg                              format, type, depth-1, height-1, width);
4547117f1b4Smrg
4557117f1b4Smrg
4567117f1b4Smrg   sizeAddr = ((const GLubyte *) 0) + pack->BufferObj->Size;
4577117f1b4Smrg
4587117f1b4Smrg   if ((const GLubyte *) start > sizeAddr) {
4597117f1b4Smrg      /* This will catch negative values / wrap-around */
4607117f1b4Smrg      return GL_FALSE;
4617117f1b4Smrg   }
4627117f1b4Smrg   if ((const GLubyte *) end > sizeAddr) {
4637117f1b4Smrg      /* Image read goes beyond end of buffer */
4647117f1b4Smrg      return GL_FALSE;
4657117f1b4Smrg   }
4667117f1b4Smrg
4677117f1b4Smrg   /* OK! */
4687117f1b4Smrg   return GL_TRUE;
4697117f1b4Smrg}
4707117f1b4Smrg
4717117f1b4Smrg
4727117f1b4Smrg/**
4737117f1b4Smrg * Return the gl_buffer_object for the given ID.
4747117f1b4Smrg * Always return NULL for ID 0.
4757117f1b4Smrg */
4767117f1b4Smrgstruct gl_buffer_object *
4777117f1b4Smrg_mesa_lookup_bufferobj(GLcontext *ctx, GLuint buffer)
4787117f1b4Smrg{
4797117f1b4Smrg   if (buffer == 0)
4807117f1b4Smrg      return NULL;
4817117f1b4Smrg   else
4827117f1b4Smrg      return (struct gl_buffer_object *)
4837117f1b4Smrg         _mesa_HashLookup(ctx->Shared->BufferObjects, buffer);
4847117f1b4Smrg}
4857117f1b4Smrg
4867117f1b4Smrg
4877117f1b4Smrg
4887117f1b4Smrg/**********************************************************************/
4897117f1b4Smrg/* API Functions                                                      */
4907117f1b4Smrg/**********************************************************************/
4917117f1b4Smrg
4927117f1b4Smrgvoid GLAPIENTRY
4937117f1b4Smrg_mesa_BindBufferARB(GLenum target, GLuint buffer)
4947117f1b4Smrg{
4957117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
4967117f1b4Smrg   struct gl_buffer_object *oldBufObj;
4977117f1b4Smrg   struct gl_buffer_object *newBufObj = NULL;
4987117f1b4Smrg   struct gl_buffer_object **bindTarget = NULL;
4997117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
5007117f1b4Smrg
5017117f1b4Smrg   switch (target) {
5027117f1b4Smrg      case GL_ARRAY_BUFFER_ARB:
5037117f1b4Smrg         bindTarget = &ctx->Array.ArrayBufferObj;
5047117f1b4Smrg         break;
5057117f1b4Smrg      case GL_ELEMENT_ARRAY_BUFFER_ARB:
5067117f1b4Smrg         bindTarget = &ctx->Array.ElementArrayBufferObj;
5077117f1b4Smrg         break;
5087117f1b4Smrg      case GL_PIXEL_PACK_BUFFER_EXT:
5097117f1b4Smrg         bindTarget = &ctx->Pack.BufferObj;
5107117f1b4Smrg         break;
5117117f1b4Smrg      case GL_PIXEL_UNPACK_BUFFER_EXT:
5127117f1b4Smrg         bindTarget = &ctx->Unpack.BufferObj;
5137117f1b4Smrg         break;
5147117f1b4Smrg      default:
5157117f1b4Smrg         _mesa_error(ctx, GL_INVALID_ENUM, "glBindBufferARB(target)");
5167117f1b4Smrg         return;
5177117f1b4Smrg   }
5187117f1b4Smrg
5197117f1b4Smrg   /* Get pointer to old buffer object (to be unbound) */
5207117f1b4Smrg   oldBufObj = get_buffer(ctx, target);
5217117f1b4Smrg   if (oldBufObj && oldBufObj->Name == buffer)
5227117f1b4Smrg      return;   /* rebinding the same buffer object- no change */
5237117f1b4Smrg
5247117f1b4Smrg   /*
5257117f1b4Smrg    * Get pointer to new buffer object (newBufObj)
5267117f1b4Smrg    */
5277117f1b4Smrg   if (buffer == 0) {
5287117f1b4Smrg      /* The spec says there's not a buffer object named 0, but we use
5297117f1b4Smrg       * one internally because it simplifies things.
5307117f1b4Smrg       */
5317117f1b4Smrg      newBufObj = ctx->Array.NullBufferObj;
5327117f1b4Smrg   }
5337117f1b4Smrg   else {
5347117f1b4Smrg      /* non-default buffer object */
5357117f1b4Smrg      newBufObj = _mesa_lookup_bufferobj(ctx, buffer);
5367117f1b4Smrg      if (!newBufObj) {
5377117f1b4Smrg         /* if this is a new buffer object id, allocate a buffer object now */
5387117f1b4Smrg         ASSERT(ctx->Driver.NewBufferObject);
5397117f1b4Smrg	 newBufObj = ctx->Driver.NewBufferObject(ctx, buffer, target);
5407117f1b4Smrg         if (!newBufObj) {
5417117f1b4Smrg            _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindBufferARB");
5427117f1b4Smrg            return;
5437117f1b4Smrg         }
5447117f1b4Smrg         _mesa_save_buffer_object(ctx, newBufObj);
5457117f1b4Smrg      }
5467117f1b4Smrg   }
5477117f1b4Smrg
5487117f1b4Smrg   /* Make new binding */
5497117f1b4Smrg   *bindTarget = newBufObj;
5507117f1b4Smrg   newBufObj->RefCount++;
5517117f1b4Smrg
5527117f1b4Smrg   /* Pass BindBuffer call to device driver */
5537117f1b4Smrg   if (ctx->Driver.BindBuffer && newBufObj)
5547117f1b4Smrg      ctx->Driver.BindBuffer( ctx, target, newBufObj );
5557117f1b4Smrg
5567117f1b4Smrg   /* decr ref count on old buffer obj, delete if needed */
5577117f1b4Smrg   if (oldBufObj) {
5587117f1b4Smrg      oldBufObj->RefCount--;
5597117f1b4Smrg      assert(oldBufObj->RefCount >= 0);
5607117f1b4Smrg      if (oldBufObj->RefCount == 0) {
5617117f1b4Smrg	 assert(oldBufObj->Name != 0);
5627117f1b4Smrg	 ASSERT(ctx->Driver.DeleteBuffer);
5637117f1b4Smrg	 ctx->Driver.DeleteBuffer( ctx, oldBufObj );
5647117f1b4Smrg      }
5657117f1b4Smrg   }
5667117f1b4Smrg}
5677117f1b4Smrg
5687117f1b4Smrg
5697117f1b4Smrg/**
5707117f1b4Smrg * Delete a set of buffer objects.
5717117f1b4Smrg *
5727117f1b4Smrg * \param n      Number of buffer objects to delete.
5737117f1b4Smrg * \param ids    Array of \c n buffer object IDs.
5747117f1b4Smrg */
5757117f1b4Smrgvoid GLAPIENTRY
5767117f1b4Smrg_mesa_DeleteBuffersARB(GLsizei n, const GLuint *ids)
5777117f1b4Smrg{
5787117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
5797117f1b4Smrg   GLsizei i;
5807117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
5817117f1b4Smrg
5827117f1b4Smrg   if (n < 0) {
5837117f1b4Smrg      _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteBuffersARB(n)");
5847117f1b4Smrg      return;
5857117f1b4Smrg   }
5867117f1b4Smrg
5877117f1b4Smrg   _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
5887117f1b4Smrg
5897117f1b4Smrg   for (i = 0; i < n; i++) {
5907117f1b4Smrg      struct gl_buffer_object *bufObj = _mesa_lookup_bufferobj(ctx, ids[i]);
5917117f1b4Smrg      if (bufObj) {
5927117f1b4Smrg         /* unbind any vertex pointers bound to this buffer */
5937117f1b4Smrg         GLuint j;
5947117f1b4Smrg
5957117f1b4Smrg         ASSERT(bufObj->Name == ids[i]);
5967117f1b4Smrg
5977117f1b4Smrg         if (ctx->Array.ArrayObj->Vertex.BufferObj == bufObj) {
5987117f1b4Smrg            bufObj->RefCount--;
5997117f1b4Smrg            ctx->Array.ArrayObj->Vertex.BufferObj = ctx->Array.NullBufferObj;
6007117f1b4Smrg            ctx->Array.NullBufferObj->RefCount++;
6017117f1b4Smrg         }
6027117f1b4Smrg         if (ctx->Array.ArrayObj->Normal.BufferObj == bufObj) {
6037117f1b4Smrg            bufObj->RefCount--;
6047117f1b4Smrg            ctx->Array.ArrayObj->Normal.BufferObj = ctx->Array.NullBufferObj;
6057117f1b4Smrg            ctx->Array.NullBufferObj->RefCount++;
6067117f1b4Smrg         }
6077117f1b4Smrg         if (ctx->Array.ArrayObj->Color.BufferObj == bufObj) {
6087117f1b4Smrg            bufObj->RefCount--;
6097117f1b4Smrg            ctx->Array.ArrayObj->Color.BufferObj = ctx->Array.NullBufferObj;
6107117f1b4Smrg            ctx->Array.NullBufferObj->RefCount++;
6117117f1b4Smrg         }
6127117f1b4Smrg         if (ctx->Array.ArrayObj->SecondaryColor.BufferObj == bufObj) {
6137117f1b4Smrg            bufObj->RefCount--;
6147117f1b4Smrg            ctx->Array.ArrayObj->SecondaryColor.BufferObj = ctx->Array.NullBufferObj;
6157117f1b4Smrg            ctx->Array.NullBufferObj->RefCount++;
6167117f1b4Smrg         }
6177117f1b4Smrg         if (ctx->Array.ArrayObj->FogCoord.BufferObj == bufObj) {
6187117f1b4Smrg            bufObj->RefCount--;
6197117f1b4Smrg            ctx->Array.ArrayObj->FogCoord.BufferObj = ctx->Array.NullBufferObj;
6207117f1b4Smrg            ctx->Array.NullBufferObj->RefCount++;
6217117f1b4Smrg         }
6227117f1b4Smrg         if (ctx->Array.ArrayObj->Index.BufferObj == bufObj) {
6237117f1b4Smrg            bufObj->RefCount--;
6247117f1b4Smrg            ctx->Array.ArrayObj->Index.BufferObj = ctx->Array.NullBufferObj;
6257117f1b4Smrg            ctx->Array.NullBufferObj->RefCount++;
6267117f1b4Smrg         }
6277117f1b4Smrg         if (ctx->Array.ArrayObj->EdgeFlag.BufferObj == bufObj) {
6287117f1b4Smrg            bufObj->RefCount--;
6297117f1b4Smrg            ctx->Array.ArrayObj->EdgeFlag.BufferObj = ctx->Array.NullBufferObj;
6307117f1b4Smrg            ctx->Array.NullBufferObj->RefCount++;
6317117f1b4Smrg         }
6327117f1b4Smrg         for (j = 0; j < MAX_TEXTURE_UNITS; j++) {
6337117f1b4Smrg            if (ctx->Array.ArrayObj->TexCoord[j].BufferObj == bufObj) {
6347117f1b4Smrg               bufObj->RefCount--;
6357117f1b4Smrg               ctx->Array.ArrayObj->TexCoord[j].BufferObj = ctx->Array.NullBufferObj;
6367117f1b4Smrg               ctx->Array.NullBufferObj->RefCount++;
6377117f1b4Smrg            }
6387117f1b4Smrg         }
6397117f1b4Smrg         for (j = 0; j < VERT_ATTRIB_MAX; j++) {
6407117f1b4Smrg            if (ctx->Array.ArrayObj->VertexAttrib[j].BufferObj == bufObj) {
6417117f1b4Smrg               bufObj->RefCount--;
6427117f1b4Smrg               ctx->Array.ArrayObj->VertexAttrib[j].BufferObj = ctx->Array.NullBufferObj;
6437117f1b4Smrg               ctx->Array.NullBufferObj->RefCount++;
6447117f1b4Smrg            }
6457117f1b4Smrg         }
6467117f1b4Smrg
6477117f1b4Smrg         if (ctx->Array.ArrayBufferObj == bufObj) {
6487117f1b4Smrg            _mesa_BindBufferARB( GL_ARRAY_BUFFER_ARB, 0 );
6497117f1b4Smrg         }
6507117f1b4Smrg         if (ctx->Array.ElementArrayBufferObj == bufObj) {
6517117f1b4Smrg            _mesa_BindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, 0 );
6527117f1b4Smrg         }
6537117f1b4Smrg
6547117f1b4Smrg         if (ctx->Pack.BufferObj == bufObj) {
6557117f1b4Smrg            _mesa_BindBufferARB( GL_PIXEL_PACK_BUFFER_EXT, 0 );
6567117f1b4Smrg         }
6577117f1b4Smrg         if (ctx->Unpack.BufferObj == bufObj) {
6587117f1b4Smrg            _mesa_BindBufferARB( GL_PIXEL_UNPACK_BUFFER_EXT, 0 );
6597117f1b4Smrg         }
6607117f1b4Smrg
6617117f1b4Smrg	 /* The ID is immediately freed for re-use */
6627117f1b4Smrg	 _mesa_remove_buffer_object(ctx, bufObj);
6637117f1b4Smrg	 _mesa_unbind_buffer_object(ctx, bufObj);
6647117f1b4Smrg      }
6657117f1b4Smrg   }
6667117f1b4Smrg
6677117f1b4Smrg   _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
6687117f1b4Smrg}
6697117f1b4Smrg
6707117f1b4Smrg
6717117f1b4Smrg/**
6727117f1b4Smrg * Generate a set of unique buffer object IDs and store them in \c buffer.
6737117f1b4Smrg *
6747117f1b4Smrg * \param n       Number of IDs to generate.
6757117f1b4Smrg * \param buffer  Array of \c n locations to store the IDs.
6767117f1b4Smrg */
6777117f1b4Smrgvoid GLAPIENTRY
6787117f1b4Smrg_mesa_GenBuffersARB(GLsizei n, GLuint *buffer)
6797117f1b4Smrg{
6807117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
6817117f1b4Smrg   GLuint first;
6827117f1b4Smrg   GLint i;
6837117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
6847117f1b4Smrg
6857117f1b4Smrg   if (n < 0) {
6867117f1b4Smrg      _mesa_error(ctx, GL_INVALID_VALUE, "glGenBuffersARB");
6877117f1b4Smrg      return;
6887117f1b4Smrg   }
6897117f1b4Smrg
6907117f1b4Smrg   if (!buffer) {
6917117f1b4Smrg      return;
6927117f1b4Smrg   }
6937117f1b4Smrg
6947117f1b4Smrg   /*
6957117f1b4Smrg    * This must be atomic (generation and allocation of buffer object IDs)
6967117f1b4Smrg    */
6977117f1b4Smrg   _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
6987117f1b4Smrg
6997117f1b4Smrg   first = _mesa_HashFindFreeKeyBlock(ctx->Shared->BufferObjects, n);
7007117f1b4Smrg
7017117f1b4Smrg   /* Allocate new, empty buffer objects and return identifiers */
7027117f1b4Smrg   for (i = 0; i < n; i++) {
7037117f1b4Smrg      struct gl_buffer_object *bufObj;
7047117f1b4Smrg      GLuint name = first + i;
7057117f1b4Smrg      GLenum target = 0;
7067117f1b4Smrg      bufObj = ctx->Driver.NewBufferObject( ctx, name, target );
7077117f1b4Smrg      if (!bufObj) {
7087117f1b4Smrg         _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
7097117f1b4Smrg         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenBuffersARB");
7107117f1b4Smrg         return;
7117117f1b4Smrg      }
7127117f1b4Smrg      _mesa_save_buffer_object(ctx, bufObj);
7137117f1b4Smrg      buffer[i] = first + i;
7147117f1b4Smrg   }
7157117f1b4Smrg
7167117f1b4Smrg   _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
7177117f1b4Smrg}
7187117f1b4Smrg
7197117f1b4Smrg
7207117f1b4Smrg/**
7217117f1b4Smrg * Determine if ID is the name of a buffer object.
7227117f1b4Smrg *
7237117f1b4Smrg * \param id  ID of the potential buffer object.
7247117f1b4Smrg * \return  \c GL_TRUE if \c id is the name of a buffer object,
7257117f1b4Smrg *          \c GL_FALSE otherwise.
7267117f1b4Smrg */
7277117f1b4SmrgGLboolean GLAPIENTRY
7287117f1b4Smrg_mesa_IsBufferARB(GLuint id)
7297117f1b4Smrg{
7307117f1b4Smrg   struct gl_buffer_object *bufObj;
7317117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
7327117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
7337117f1b4Smrg
7347117f1b4Smrg   _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
7357117f1b4Smrg   bufObj = _mesa_lookup_bufferobj(ctx, id);
7367117f1b4Smrg   _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
7377117f1b4Smrg
7387117f1b4Smrg   return bufObj ? GL_TRUE : GL_FALSE;
7397117f1b4Smrg}
7407117f1b4Smrg
7417117f1b4Smrg
7427117f1b4Smrgvoid GLAPIENTRY
7437117f1b4Smrg_mesa_BufferDataARB(GLenum target, GLsizeiptrARB size,
7447117f1b4Smrg                    const GLvoid * data, GLenum usage)
7457117f1b4Smrg{
7467117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
7477117f1b4Smrg   struct gl_buffer_object *bufObj;
7487117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
7497117f1b4Smrg
7507117f1b4Smrg   if (size < 0) {
7517117f1b4Smrg      _mesa_error(ctx, GL_INVALID_VALUE, "glBufferDataARB(size < 0)");
7527117f1b4Smrg      return;
7537117f1b4Smrg   }
7547117f1b4Smrg
7557117f1b4Smrg   switch (usage) {
7567117f1b4Smrg      case GL_STREAM_DRAW_ARB:
7577117f1b4Smrg      case GL_STREAM_READ_ARB:
7587117f1b4Smrg      case GL_STREAM_COPY_ARB:
7597117f1b4Smrg      case GL_STATIC_DRAW_ARB:
7607117f1b4Smrg      case GL_STATIC_READ_ARB:
7617117f1b4Smrg      case GL_STATIC_COPY_ARB:
7627117f1b4Smrg      case GL_DYNAMIC_DRAW_ARB:
7637117f1b4Smrg      case GL_DYNAMIC_READ_ARB:
7647117f1b4Smrg      case GL_DYNAMIC_COPY_ARB:
7657117f1b4Smrg         /* OK */
7667117f1b4Smrg         break;
7677117f1b4Smrg      default:
7687117f1b4Smrg         _mesa_error(ctx, GL_INVALID_ENUM, "glBufferDataARB(usage)");
7697117f1b4Smrg         return;
7707117f1b4Smrg   }
7717117f1b4Smrg
7727117f1b4Smrg   bufObj = get_buffer(ctx, target);
7737117f1b4Smrg   if (!bufObj) {
7747117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glBufferDataARB(target)" );
7757117f1b4Smrg      return;
7767117f1b4Smrg   }
7777117f1b4Smrg   if (bufObj->Name == 0) {
7787117f1b4Smrg      _mesa_error(ctx, GL_INVALID_OPERATION, "glBufferDataARB" );
7797117f1b4Smrg      return;
7807117f1b4Smrg   }
7817117f1b4Smrg
7827117f1b4Smrg   if (bufObj->Pointer) {
7837117f1b4Smrg      _mesa_error(ctx, GL_INVALID_OPERATION, "glBufferDataARB(buffer is mapped)" );
7847117f1b4Smrg      return;
7857117f1b4Smrg   }
7867117f1b4Smrg
7877117f1b4Smrg   ASSERT(ctx->Driver.BufferData);
7887117f1b4Smrg
7897117f1b4Smrg   /* Give the buffer object to the driver!  <data> may be null! */
7907117f1b4Smrg   ctx->Driver.BufferData( ctx, target, size, data, usage, bufObj );
7917117f1b4Smrg}
7927117f1b4Smrg
7937117f1b4Smrg
7947117f1b4Smrgvoid GLAPIENTRY
7957117f1b4Smrg_mesa_BufferSubDataARB(GLenum target, GLintptrARB offset,
7967117f1b4Smrg                       GLsizeiptrARB size, const GLvoid * data)
7977117f1b4Smrg{
7987117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
7997117f1b4Smrg   struct gl_buffer_object *bufObj;
8007117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
8017117f1b4Smrg
8027117f1b4Smrg   bufObj = buffer_object_subdata_range_good( ctx, target, offset, size,
8037117f1b4Smrg                                              "glBufferSubDataARB" );
8047117f1b4Smrg   if (!bufObj) {
8057117f1b4Smrg      /* error already recorded */
8067117f1b4Smrg      return;
8077117f1b4Smrg   }
8087117f1b4Smrg
8097117f1b4Smrg   ASSERT(ctx->Driver.BufferSubData);
8107117f1b4Smrg   ctx->Driver.BufferSubData( ctx, target, offset, size, data, bufObj );
8117117f1b4Smrg}
8127117f1b4Smrg
8137117f1b4Smrg
8147117f1b4Smrgvoid GLAPIENTRY
8157117f1b4Smrg_mesa_GetBufferSubDataARB(GLenum target, GLintptrARB offset,
8167117f1b4Smrg                          GLsizeiptrARB size, void * data)
8177117f1b4Smrg{
8187117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
8197117f1b4Smrg   struct gl_buffer_object *bufObj;
8207117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
8217117f1b4Smrg
8227117f1b4Smrg   bufObj = buffer_object_subdata_range_good( ctx, target, offset, size,
8237117f1b4Smrg                                              "glGetBufferSubDataARB" );
8247117f1b4Smrg   if (!bufObj) {
8257117f1b4Smrg      /* error already recorded */
8267117f1b4Smrg      return;
8277117f1b4Smrg   }
8287117f1b4Smrg
8297117f1b4Smrg   ASSERT(ctx->Driver.GetBufferSubData);
8307117f1b4Smrg   ctx->Driver.GetBufferSubData( ctx, target, offset, size, data, bufObj );
8317117f1b4Smrg}
8327117f1b4Smrg
8337117f1b4Smrg
8347117f1b4Smrgvoid * GLAPIENTRY
8357117f1b4Smrg_mesa_MapBufferARB(GLenum target, GLenum access)
8367117f1b4Smrg{
8377117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
8387117f1b4Smrg   struct gl_buffer_object * bufObj;
8397117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, NULL);
8407117f1b4Smrg
8417117f1b4Smrg   switch (access) {
8427117f1b4Smrg      case GL_READ_ONLY_ARB:
8437117f1b4Smrg      case GL_WRITE_ONLY_ARB:
8447117f1b4Smrg      case GL_READ_WRITE_ARB:
8457117f1b4Smrg         /* OK */
8467117f1b4Smrg         break;
8477117f1b4Smrg      default:
8487117f1b4Smrg         _mesa_error(ctx, GL_INVALID_ENUM, "glMapBufferARB(access)");
8497117f1b4Smrg         return NULL;
8507117f1b4Smrg   }
8517117f1b4Smrg
8527117f1b4Smrg   bufObj = get_buffer(ctx, target);
8537117f1b4Smrg   if (!bufObj) {
8547117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glMapBufferARB(target)" );
8557117f1b4Smrg      return NULL;
8567117f1b4Smrg   }
8577117f1b4Smrg   if (bufObj->Name == 0) {
8587117f1b4Smrg      _mesa_error(ctx, GL_INVALID_OPERATION, "glMapBufferARB" );
8597117f1b4Smrg      return NULL;
8607117f1b4Smrg   }
8617117f1b4Smrg   if (bufObj->Pointer) {
8627117f1b4Smrg      _mesa_error(ctx, GL_INVALID_OPERATION, "glMapBufferARB(already mapped)");
8637117f1b4Smrg      return NULL;
8647117f1b4Smrg   }
8657117f1b4Smrg
8667117f1b4Smrg   ASSERT(ctx->Driver.MapBuffer);
8677117f1b4Smrg   bufObj->Pointer = ctx->Driver.MapBuffer( ctx, target, access, bufObj );
8687117f1b4Smrg   if (!bufObj->Pointer) {
8697117f1b4Smrg      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glMapBufferARB(access)");
8707117f1b4Smrg   }
8717117f1b4Smrg
8727117f1b4Smrg   bufObj->Access = access;
8737117f1b4Smrg
8747117f1b4Smrg   return bufObj->Pointer;
8757117f1b4Smrg}
8767117f1b4Smrg
8777117f1b4Smrg
8787117f1b4SmrgGLboolean GLAPIENTRY
8797117f1b4Smrg_mesa_UnmapBufferARB(GLenum target)
8807117f1b4Smrg{
8817117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
8827117f1b4Smrg   struct gl_buffer_object *bufObj;
8837117f1b4Smrg   GLboolean status = GL_TRUE;
8847117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
8857117f1b4Smrg
8867117f1b4Smrg   bufObj = get_buffer(ctx, target);
8877117f1b4Smrg   if (!bufObj) {
8887117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glUnmapBufferARB(target)" );
8897117f1b4Smrg      return GL_FALSE;
8907117f1b4Smrg   }
8917117f1b4Smrg   if (bufObj->Name == 0) {
8927117f1b4Smrg      _mesa_error(ctx, GL_INVALID_OPERATION, "glUnmapBufferARB" );
8937117f1b4Smrg      return GL_FALSE;
8947117f1b4Smrg   }
8957117f1b4Smrg   if (!bufObj->Pointer) {
8967117f1b4Smrg      _mesa_error(ctx, GL_INVALID_OPERATION, "glUnmapBufferARB");
8977117f1b4Smrg      return GL_FALSE;
8987117f1b4Smrg   }
8997117f1b4Smrg
9007117f1b4Smrg   if (ctx->Driver.UnmapBuffer) {
9017117f1b4Smrg      status = ctx->Driver.UnmapBuffer( ctx, target, bufObj );
9027117f1b4Smrg   }
9037117f1b4Smrg
9047117f1b4Smrg   bufObj->Access = GL_READ_WRITE_ARB; /* initial value, OK? */
9057117f1b4Smrg   bufObj->Pointer = NULL;
9067117f1b4Smrg
9077117f1b4Smrg   return status;
9087117f1b4Smrg}
9097117f1b4Smrg
9107117f1b4Smrg
9117117f1b4Smrgvoid GLAPIENTRY
9127117f1b4Smrg_mesa_GetBufferParameterivARB(GLenum target, GLenum pname, GLint *params)
9137117f1b4Smrg{
9147117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
9157117f1b4Smrg   struct gl_buffer_object *bufObj;
9167117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
9177117f1b4Smrg
9187117f1b4Smrg   bufObj = get_buffer(ctx, target);
9197117f1b4Smrg   if (!bufObj) {
9207117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "GetBufferParameterivARB(target)" );
9217117f1b4Smrg      return;
9227117f1b4Smrg   }
9237117f1b4Smrg   if (bufObj->Name == 0) {
9247117f1b4Smrg      _mesa_error(ctx, GL_INVALID_OPERATION, "GetBufferParameterivARB" );
9257117f1b4Smrg      return;
9267117f1b4Smrg   }
9277117f1b4Smrg
9287117f1b4Smrg   switch (pname) {
9297117f1b4Smrg      case GL_BUFFER_SIZE_ARB:
9307117f1b4Smrg         *params = (GLint) bufObj->Size;
9317117f1b4Smrg         break;
9327117f1b4Smrg      case GL_BUFFER_USAGE_ARB:
9337117f1b4Smrg         *params = bufObj->Usage;
9347117f1b4Smrg         break;
9357117f1b4Smrg      case GL_BUFFER_ACCESS_ARB:
9367117f1b4Smrg         *params = bufObj->Access;
9377117f1b4Smrg         break;
9387117f1b4Smrg      case GL_BUFFER_MAPPED_ARB:
9397117f1b4Smrg         *params = (bufObj->Pointer != NULL);
9407117f1b4Smrg         break;
9417117f1b4Smrg      default:
9427117f1b4Smrg         _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferParameterivARB(pname)");
9437117f1b4Smrg         return;
9447117f1b4Smrg   }
9457117f1b4Smrg}
9467117f1b4Smrg
9477117f1b4Smrg
9487117f1b4Smrgvoid GLAPIENTRY
9497117f1b4Smrg_mesa_GetBufferPointervARB(GLenum target, GLenum pname, GLvoid **params)
9507117f1b4Smrg{
9517117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
9527117f1b4Smrg   struct gl_buffer_object * bufObj;
9537117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
9547117f1b4Smrg
9557117f1b4Smrg   if (pname != GL_BUFFER_MAP_POINTER_ARB) {
9567117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferPointervARB(pname)");
9577117f1b4Smrg      return;
9587117f1b4Smrg   }
9597117f1b4Smrg
9607117f1b4Smrg   bufObj = get_buffer(ctx, target);
9617117f1b4Smrg   if (!bufObj) {
9627117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferPointervARB(target)" );
9637117f1b4Smrg      return;
9647117f1b4Smrg   }
9657117f1b4Smrg   if (bufObj->Name == 0) {
9667117f1b4Smrg      _mesa_error(ctx, GL_INVALID_OPERATION, "glGetBufferPointervARB" );
9677117f1b4Smrg      return;
9687117f1b4Smrg   }
9697117f1b4Smrg
9707117f1b4Smrg   *params = bufObj->Pointer;
9717117f1b4Smrg}
972