bufferobj.c revision cdc920a0
17117f1b4Smrg/*
27117f1b4Smrg * Mesa 3-D graphics library
34a49301eSmrg * Version:  7.6
47117f1b4Smrg *
5c1f859d4Smrg * Copyright (C) 1999-2008  Brian Paul   All Rights Reserved.
64a49301eSmrg * Copyright (C) 2009  VMware, Inc.  All Rights Reserved.
77117f1b4Smrg *
87117f1b4Smrg * Permission is hereby granted, free of charge, to any person obtaining a
97117f1b4Smrg * copy of this software and associated documentation files (the "Software"),
107117f1b4Smrg * to deal in the Software without restriction, including without limitation
117117f1b4Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
127117f1b4Smrg * and/or sell copies of the Software, and to permit persons to whom the
137117f1b4Smrg * Software is furnished to do so, subject to the following conditions:
147117f1b4Smrg *
157117f1b4Smrg * The above copyright notice and this permission notice shall be included
167117f1b4Smrg * in all copies or substantial portions of the Software.
177117f1b4Smrg *
187117f1b4Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
197117f1b4Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
207117f1b4Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
217117f1b4Smrg * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
227117f1b4Smrg * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
237117f1b4Smrg * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
247117f1b4Smrg */
257117f1b4Smrg
267117f1b4Smrg
277117f1b4Smrg/**
287117f1b4Smrg * \file bufferobj.c
294a49301eSmrg * \brief Functions for the GL_ARB_vertex/pixel_buffer_object extensions.
307117f1b4Smrg * \author Brian Paul, Ian Romanick
317117f1b4Smrg */
327117f1b4Smrg
337117f1b4Smrg
347117f1b4Smrg#include "glheader.h"
357117f1b4Smrg#include "hash.h"
367117f1b4Smrg#include "imports.h"
377117f1b4Smrg#include "image.h"
387117f1b4Smrg#include "context.h"
397117f1b4Smrg#include "bufferobj.h"
40cdc920a0Smrg#include "fbobject.h"
41cdc920a0Smrg#include "texobj.h"
427117f1b4Smrg
437117f1b4Smrg
444a49301eSmrg/* Debug flags */
454a49301eSmrg/*#define VBO_DEBUG*/
464a49301eSmrg/*#define BOUNDS_CHECK*/
474a49301eSmrg
484a49301eSmrg
494a49301eSmrg#ifdef FEATURE_OES_mapbuffer
504a49301eSmrg#define DEFAULT_ACCESS GL_MAP_WRITE_BIT
514a49301eSmrg#else
524a49301eSmrg#define DEFAULT_ACCESS (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)
534a49301eSmrg#endif
544a49301eSmrg
554a49301eSmrg
564a49301eSmrg/**
574a49301eSmrg * Return pointer to address of a buffer object target.
584a49301eSmrg * \param ctx  the GL context
594a49301eSmrg * \param target  the buffer object target to be retrieved.
604a49301eSmrg * \return   pointer to pointer to the buffer object bound to \c target in the
614a49301eSmrg *           specified context or \c NULL if \c target is invalid.
624a49301eSmrg */
634a49301eSmrgstatic INLINE struct gl_buffer_object **
644a49301eSmrgget_buffer_target(GLcontext *ctx, GLenum target)
654a49301eSmrg{
664a49301eSmrg   switch (target) {
674a49301eSmrg   case GL_ARRAY_BUFFER_ARB:
684a49301eSmrg      return &ctx->Array.ArrayBufferObj;
694a49301eSmrg   case GL_ELEMENT_ARRAY_BUFFER_ARB:
704a49301eSmrg      return &ctx->Array.ElementArrayBufferObj;
714a49301eSmrg   case GL_PIXEL_PACK_BUFFER_EXT:
724a49301eSmrg      return &ctx->Pack.BufferObj;
734a49301eSmrg   case GL_PIXEL_UNPACK_BUFFER_EXT:
744a49301eSmrg      return &ctx->Unpack.BufferObj;
754a49301eSmrg   case GL_COPY_READ_BUFFER:
764a49301eSmrg      if (ctx->Extensions.ARB_copy_buffer) {
774a49301eSmrg         return &ctx->CopyReadBuffer;
784a49301eSmrg      }
794a49301eSmrg      break;
804a49301eSmrg   case GL_COPY_WRITE_BUFFER:
814a49301eSmrg      if (ctx->Extensions.ARB_copy_buffer) {
824a49301eSmrg         return &ctx->CopyWriteBuffer;
834a49301eSmrg      }
844a49301eSmrg      break;
854a49301eSmrg   default:
864a49301eSmrg      return NULL;
874a49301eSmrg   }
884a49301eSmrg   return NULL;
894a49301eSmrg}
904a49301eSmrg
914a49301eSmrg
927117f1b4Smrg/**
937117f1b4Smrg * Get the buffer object bound to the specified target in a GL context.
944a49301eSmrg * \param ctx  the GL context
954a49301eSmrg * \param target  the buffer object target to be retrieved.
964a49301eSmrg * \return   pointer to the buffer object bound to \c target in the
977117f1b4Smrg *           specified context or \c NULL if \c target is invalid.
987117f1b4Smrg */
997117f1b4Smrgstatic INLINE struct gl_buffer_object *
1007117f1b4Smrgget_buffer(GLcontext *ctx, GLenum target)
1017117f1b4Smrg{
1024a49301eSmrg   struct gl_buffer_object **bufObj = get_buffer_target(ctx, target);
1034a49301eSmrg   if (bufObj)
1044a49301eSmrg      return *bufObj;
1054a49301eSmrg   return NULL;
1064a49301eSmrg}
1077117f1b4Smrg
1087117f1b4Smrg
1094a49301eSmrg/**
1104a49301eSmrg * Convert a GLbitfield describing the mapped buffer access flags
1114a49301eSmrg * into one of GL_READ_WRITE, GL_READ_ONLY, or GL_WRITE_ONLY.
1124a49301eSmrg */
1134a49301eSmrgstatic GLenum
1144a49301eSmrgsimplified_access_mode(GLbitfield access)
1154a49301eSmrg{
1164a49301eSmrg   const GLbitfield rwFlags = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT;
1174a49301eSmrg   if ((access & rwFlags) == rwFlags)
1184a49301eSmrg      return GL_READ_WRITE;
1194a49301eSmrg   if ((access & GL_MAP_READ_BIT) == GL_MAP_READ_BIT)
1204a49301eSmrg      return GL_READ_ONLY;
1214a49301eSmrg   if ((access & GL_MAP_WRITE_BIT) == GL_MAP_WRITE_BIT)
1224a49301eSmrg      return GL_WRITE_ONLY;
1234a49301eSmrg   return GL_READ_WRITE; /* this should never happen, but no big deal */
1247117f1b4Smrg}
1257117f1b4Smrg
1267117f1b4Smrg
1277117f1b4Smrg/**
1287117f1b4Smrg * Tests the subdata range parameters and sets the GL error code for
1297117f1b4Smrg * \c glBufferSubDataARB and \c glGetBufferSubDataARB.
1307117f1b4Smrg *
1317117f1b4Smrg * \param ctx     GL context.
1327117f1b4Smrg * \param target  Buffer object target on which to operate.
1337117f1b4Smrg * \param offset  Offset of the first byte of the subdata range.
1347117f1b4Smrg * \param size    Size, in bytes, of the subdata range.
1357117f1b4Smrg * \param caller  Name of calling function for recording errors.
1367117f1b4Smrg * \return   A pointer to the buffer object bound to \c target in the
1377117f1b4Smrg *           specified context or \c NULL if any of the parameter or state
1387117f1b4Smrg *           conditions for \c glBufferSubDataARB or \c glGetBufferSubDataARB
1397117f1b4Smrg *           are invalid.
1407117f1b4Smrg *
1417117f1b4Smrg * \sa glBufferSubDataARB, glGetBufferSubDataARB
1427117f1b4Smrg */
1437117f1b4Smrgstatic struct gl_buffer_object *
1447117f1b4Smrgbuffer_object_subdata_range_good( GLcontext * ctx, GLenum target,
1457117f1b4Smrg                                  GLintptrARB offset, GLsizeiptrARB size,
1467117f1b4Smrg                                  const char *caller )
1477117f1b4Smrg{
1487117f1b4Smrg   struct gl_buffer_object *bufObj;
1497117f1b4Smrg
1507117f1b4Smrg   if (size < 0) {
1517117f1b4Smrg      _mesa_error(ctx, GL_INVALID_VALUE, "%s(size < 0)", caller);
1527117f1b4Smrg      return NULL;
1537117f1b4Smrg   }
1547117f1b4Smrg
1557117f1b4Smrg   if (offset < 0) {
1567117f1b4Smrg      _mesa_error(ctx, GL_INVALID_VALUE, "%s(offset < 0)", caller);
1577117f1b4Smrg      return NULL;
1587117f1b4Smrg   }
1597117f1b4Smrg
1607117f1b4Smrg   bufObj = get_buffer(ctx, target);
1617117f1b4Smrg   if (!bufObj) {
1627117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "%s(target)", caller);
1637117f1b4Smrg      return NULL;
1647117f1b4Smrg   }
1654a49301eSmrg   if (!_mesa_is_bufferobj(bufObj)) {
1667117f1b4Smrg      _mesa_error(ctx, GL_INVALID_OPERATION, "%s", caller);
1677117f1b4Smrg      return NULL;
1687117f1b4Smrg   }
1697117f1b4Smrg   if (offset + size > bufObj->Size) {
1707117f1b4Smrg      _mesa_error(ctx, GL_INVALID_VALUE,
1717117f1b4Smrg		  "%s(size + offset > buffer size)", caller);
1727117f1b4Smrg      return NULL;
1737117f1b4Smrg   }
1744a49301eSmrg   if (_mesa_bufferobj_mapped(bufObj)) {
1757117f1b4Smrg      /* Buffer is currently mapped */
1767117f1b4Smrg      _mesa_error(ctx, GL_INVALID_OPERATION, "%s", caller);
1777117f1b4Smrg      return NULL;
1787117f1b4Smrg   }
1797117f1b4Smrg
1807117f1b4Smrg   return bufObj;
1817117f1b4Smrg}
1827117f1b4Smrg
1837117f1b4Smrg
1847117f1b4Smrg/**
1857117f1b4Smrg * Allocate and initialize a new buffer object.
1867117f1b4Smrg *
1874a49301eSmrg * Default callback for the \c dd_function_table::NewBufferObject() hook.
1887117f1b4Smrg */
1894a49301eSmrgstatic struct gl_buffer_object *
1907117f1b4Smrg_mesa_new_buffer_object( GLcontext *ctx, GLuint name, GLenum target )
1917117f1b4Smrg{
1927117f1b4Smrg   struct gl_buffer_object *obj;
1937117f1b4Smrg
1947117f1b4Smrg   (void) ctx;
1957117f1b4Smrg
1967117f1b4Smrg   obj = MALLOC_STRUCT(gl_buffer_object);
1977117f1b4Smrg   _mesa_initialize_buffer_object(obj, name, target);
1987117f1b4Smrg   return obj;
1997117f1b4Smrg}
2007117f1b4Smrg
2017117f1b4Smrg
2027117f1b4Smrg/**
2037117f1b4Smrg * Delete a buffer object.
2047117f1b4Smrg *
2054a49301eSmrg * Default callback for the \c dd_function_table::DeleteBuffer() hook.
2067117f1b4Smrg */
2074a49301eSmrgstatic void
2087117f1b4Smrg_mesa_delete_buffer_object( GLcontext *ctx, struct gl_buffer_object *bufObj )
2097117f1b4Smrg{
2107117f1b4Smrg   (void) ctx;
2117117f1b4Smrg
2127117f1b4Smrg   if (bufObj->Data)
213cdc920a0Smrg      free(bufObj->Data);
214c1f859d4Smrg
215c1f859d4Smrg   /* assign strange values here to help w/ debugging */
216c1f859d4Smrg   bufObj->RefCount = -1000;
217c1f859d4Smrg   bufObj->Name = ~0;
218c1f859d4Smrg
2194a49301eSmrg   _glthread_DESTROY_MUTEX(bufObj->Mutex);
220cdc920a0Smrg   free(bufObj);
2217117f1b4Smrg}
2227117f1b4Smrg
2237117f1b4Smrg
224c1f859d4Smrg
225c1f859d4Smrg/**
226c1f859d4Smrg * Set ptr to bufObj w/ reference counting.
227c1f859d4Smrg */
2287117f1b4Smrgvoid
229c1f859d4Smrg_mesa_reference_buffer_object(GLcontext *ctx,
230c1f859d4Smrg                              struct gl_buffer_object **ptr,
231c1f859d4Smrg                              struct gl_buffer_object *bufObj)
2327117f1b4Smrg{
233c1f859d4Smrg   if (*ptr == bufObj)
234c1f859d4Smrg      return;
235c1f859d4Smrg
236c1f859d4Smrg   if (*ptr) {
2374a49301eSmrg      /* Unreference the old buffer */
238c1f859d4Smrg      GLboolean deleteFlag = GL_FALSE;
239c1f859d4Smrg      struct gl_buffer_object *oldObj = *ptr;
240c1f859d4Smrg
2414a49301eSmrg      _glthread_LOCK_MUTEX(oldObj->Mutex);
242c1f859d4Smrg      ASSERT(oldObj->RefCount > 0);
243c1f859d4Smrg      oldObj->RefCount--;
244c1f859d4Smrg#if 0
245c1f859d4Smrg      printf("BufferObj %p %d DECR to %d\n",
246c1f859d4Smrg             (void *) oldObj, oldObj->Name, oldObj->RefCount);
247c1f859d4Smrg#endif
248c1f859d4Smrg      deleteFlag = (oldObj->RefCount == 0);
2494a49301eSmrg      _glthread_UNLOCK_MUTEX(oldObj->Mutex);
250c1f859d4Smrg
251c1f859d4Smrg      if (deleteFlag) {
252c1f859d4Smrg
253c1f859d4Smrg         /* some sanity checking: don't delete a buffer still in use */
254c1f859d4Smrg#if 0
255c1f859d4Smrg         /* unfortunately, these tests are invalid during context tear-down */
2567117f1b4Smrg	 ASSERT(ctx->Array.ArrayBufferObj != bufObj);
2577117f1b4Smrg	 ASSERT(ctx->Array.ElementArrayBufferObj != bufObj);
2587117f1b4Smrg	 ASSERT(ctx->Array.ArrayObj->Vertex.BufferObj != bufObj);
259c1f859d4Smrg#endif
260c1f859d4Smrg
2617117f1b4Smrg	 ASSERT(ctx->Driver.DeleteBuffer);
262c1f859d4Smrg         ctx->Driver.DeleteBuffer(ctx, oldObj);
2637117f1b4Smrg      }
264c1f859d4Smrg
265c1f859d4Smrg      *ptr = NULL;
266c1f859d4Smrg   }
267c1f859d4Smrg   ASSERT(!*ptr);
268c1f859d4Smrg
269c1f859d4Smrg   if (bufObj) {
2704a49301eSmrg      /* reference new buffer */
2714a49301eSmrg      _glthread_LOCK_MUTEX(bufObj->Mutex);
272c1f859d4Smrg      if (bufObj->RefCount == 0) {
273c1f859d4Smrg         /* this buffer's being deleted (look just above) */
274c1f859d4Smrg         /* Not sure this can every really happen.  Warn if it does. */
275c1f859d4Smrg         _mesa_problem(NULL, "referencing deleted buffer object");
276c1f859d4Smrg         *ptr = NULL;
277c1f859d4Smrg      }
278c1f859d4Smrg      else {
279c1f859d4Smrg         bufObj->RefCount++;
280c1f859d4Smrg#if 0
281c1f859d4Smrg         printf("BufferObj %p %d INCR to %d\n",
282c1f859d4Smrg                (void *) bufObj, bufObj->Name, bufObj->RefCount);
283c1f859d4Smrg#endif
284c1f859d4Smrg         *ptr = bufObj;
285c1f859d4Smrg      }
2864a49301eSmrg      _glthread_UNLOCK_MUTEX(bufObj->Mutex);
2877117f1b4Smrg   }
2887117f1b4Smrg}
2897117f1b4Smrg
2907117f1b4Smrg
2917117f1b4Smrg/**
2927117f1b4Smrg * Initialize a buffer object to default values.
2937117f1b4Smrg */
2947117f1b4Smrgvoid
2957117f1b4Smrg_mesa_initialize_buffer_object( struct gl_buffer_object *obj,
2967117f1b4Smrg				GLuint name, GLenum target )
2977117f1b4Smrg{
2987117f1b4Smrg   (void) target;
2997117f1b4Smrg
300cdc920a0Smrg   memset(obj, 0, sizeof(struct gl_buffer_object));
3014a49301eSmrg   _glthread_INIT_MUTEX(obj->Mutex);
3027117f1b4Smrg   obj->RefCount = 1;
3037117f1b4Smrg   obj->Name = name;
3047117f1b4Smrg   obj->Usage = GL_STATIC_DRAW_ARB;
3054a49301eSmrg   obj->AccessFlags = DEFAULT_ACCESS;
3067117f1b4Smrg}
3077117f1b4Smrg
3087117f1b4Smrg
3097117f1b4Smrg/**
3107117f1b4Smrg * Allocate space for and store data in a buffer object.  Any data that was
3117117f1b4Smrg * previously stored in the buffer object is lost.  If \c data is \c NULL,
3127117f1b4Smrg * memory will be allocated, but no copy will occur.
3137117f1b4Smrg *
3144a49301eSmrg * This is the default callback for \c dd_function_table::BufferData()
3154a49301eSmrg * Note that all GL error checking will have been done already.
3167117f1b4Smrg *
3177117f1b4Smrg * \param ctx     GL context.
3187117f1b4Smrg * \param target  Buffer object target on which to operate.
3197117f1b4Smrg * \param size    Size, in bytes, of the new data store.
3207117f1b4Smrg * \param data    Pointer to the data to store in the buffer object.  This
3217117f1b4Smrg *                pointer may be \c NULL.
3227117f1b4Smrg * \param usage   Hints about how the data will be used.
3237117f1b4Smrg * \param bufObj  Object to be used.
3247117f1b4Smrg *
3254a49301eSmrg * \return GL_TRUE for success, GL_FALSE for failure
3267117f1b4Smrg * \sa glBufferDataARB, dd_function_table::BufferData.
3277117f1b4Smrg */
3284a49301eSmrgstatic GLboolean
3297117f1b4Smrg_mesa_buffer_data( GLcontext *ctx, GLenum target, GLsizeiptrARB size,
3307117f1b4Smrg		   const GLvoid * data, GLenum usage,
3317117f1b4Smrg		   struct gl_buffer_object * bufObj )
3327117f1b4Smrg{
3337117f1b4Smrg   void * new_data;
3347117f1b4Smrg
3357117f1b4Smrg   (void) ctx; (void) target;
3367117f1b4Smrg
3377117f1b4Smrg   new_data = _mesa_realloc( bufObj->Data, bufObj->Size, size );
3387117f1b4Smrg   if (new_data) {
3397117f1b4Smrg      bufObj->Data = (GLubyte *) new_data;
3407117f1b4Smrg      bufObj->Size = size;
3417117f1b4Smrg      bufObj->Usage = usage;
3427117f1b4Smrg
3437117f1b4Smrg      if (data) {
344cdc920a0Smrg	 memcpy( bufObj->Data, data, size );
3457117f1b4Smrg      }
3464a49301eSmrg
3474a49301eSmrg      return GL_TRUE;
3484a49301eSmrg   }
3494a49301eSmrg   else {
3504a49301eSmrg      return GL_FALSE;
3517117f1b4Smrg   }
3527117f1b4Smrg}
3537117f1b4Smrg
3547117f1b4Smrg
3557117f1b4Smrg/**
3567117f1b4Smrg * Replace data in a subrange of buffer object.  If the data range
3577117f1b4Smrg * specified by \c size + \c offset extends beyond the end of the buffer or
3587117f1b4Smrg * if \c data is \c NULL, no copy is performed.
3597117f1b4Smrg *
3604a49301eSmrg * This is the default callback for \c dd_function_table::BufferSubData()
3614a49301eSmrg * Note that all GL error checking will have been done already.
3627117f1b4Smrg *
3637117f1b4Smrg * \param ctx     GL context.
3647117f1b4Smrg * \param target  Buffer object target on which to operate.
3657117f1b4Smrg * \param offset  Offset of the first byte to be modified.
3667117f1b4Smrg * \param size    Size, in bytes, of the data range.
3677117f1b4Smrg * \param data    Pointer to the data to store in the buffer object.
3687117f1b4Smrg * \param bufObj  Object to be used.
3697117f1b4Smrg *
3707117f1b4Smrg * \sa glBufferSubDataARB, dd_function_table::BufferSubData.
3717117f1b4Smrg */
3724a49301eSmrgstatic void
3737117f1b4Smrg_mesa_buffer_subdata( GLcontext *ctx, GLenum target, GLintptrARB offset,
3747117f1b4Smrg		      GLsizeiptrARB size, const GLvoid * data,
3757117f1b4Smrg		      struct gl_buffer_object * bufObj )
3767117f1b4Smrg{
3777117f1b4Smrg   (void) ctx; (void) target;
3787117f1b4Smrg
3797117f1b4Smrg   /* this should have been caught in _mesa_BufferSubData() */
3807117f1b4Smrg   ASSERT(size + offset <= bufObj->Size);
3817117f1b4Smrg
3827117f1b4Smrg   if (bufObj->Data) {
383cdc920a0Smrg      memcpy( (GLubyte *) bufObj->Data + offset, data, size );
3847117f1b4Smrg   }
3857117f1b4Smrg}
3867117f1b4Smrg
3877117f1b4Smrg
3887117f1b4Smrg/**
3897117f1b4Smrg * Retrieve data from a subrange of buffer object.  If the data range
3907117f1b4Smrg * specified by \c size + \c offset extends beyond the end of the buffer or
3917117f1b4Smrg * if \c data is \c NULL, no copy is performed.
3927117f1b4Smrg *
3934a49301eSmrg * This is the default callback for \c dd_function_table::GetBufferSubData()
3944a49301eSmrg * Note that all GL error checking will have been done already.
3957117f1b4Smrg *
3967117f1b4Smrg * \param ctx     GL context.
3977117f1b4Smrg * \param target  Buffer object target on which to operate.
3984a49301eSmrg * \param offset  Offset of the first byte to be fetched.
3997117f1b4Smrg * \param size    Size, in bytes, of the data range.
4004a49301eSmrg * \param data    Destination for data
4017117f1b4Smrg * \param bufObj  Object to be used.
4027117f1b4Smrg *
4037117f1b4Smrg * \sa glBufferGetSubDataARB, dd_function_table::GetBufferSubData.
4047117f1b4Smrg */
4054a49301eSmrgstatic void
4067117f1b4Smrg_mesa_buffer_get_subdata( GLcontext *ctx, GLenum target, GLintptrARB offset,
4077117f1b4Smrg			  GLsizeiptrARB size, GLvoid * data,
4087117f1b4Smrg			  struct gl_buffer_object * bufObj )
4097117f1b4Smrg{
4107117f1b4Smrg   (void) ctx; (void) target;
4117117f1b4Smrg
4127117f1b4Smrg   if (bufObj->Data && ((GLsizeiptrARB) (size + offset) <= bufObj->Size)) {
413cdc920a0Smrg      memcpy( data, (GLubyte *) bufObj->Data + offset, size );
4147117f1b4Smrg   }
4157117f1b4Smrg}
4167117f1b4Smrg
4177117f1b4Smrg
4187117f1b4Smrg/**
4194a49301eSmrg * Default callback for \c dd_function_tabel::MapBuffer().
4207117f1b4Smrg *
4217117f1b4Smrg * The function parameters will have been already tested for errors.
4227117f1b4Smrg *
4237117f1b4Smrg * \param ctx     GL context.
4247117f1b4Smrg * \param target  Buffer object target on which to operate.
4257117f1b4Smrg * \param access  Information about how the buffer will be accessed.
4267117f1b4Smrg * \param bufObj  Object to be mapped.
4277117f1b4Smrg * \return  A pointer to the object's internal data store that can be accessed
4287117f1b4Smrg *          by the processor
4297117f1b4Smrg *
4307117f1b4Smrg * \sa glMapBufferARB, dd_function_table::MapBuffer
4317117f1b4Smrg */
4324a49301eSmrgstatic void *
4337117f1b4Smrg_mesa_buffer_map( GLcontext *ctx, GLenum target, GLenum access,
4347117f1b4Smrg		  struct gl_buffer_object *bufObj )
4357117f1b4Smrg{
4367117f1b4Smrg   (void) ctx;
4377117f1b4Smrg   (void) target;
4387117f1b4Smrg   (void) access;
4397117f1b4Smrg   /* Just return a direct pointer to the data */
4404a49301eSmrg   if (_mesa_bufferobj_mapped(bufObj)) {
4417117f1b4Smrg      /* already mapped! */
4427117f1b4Smrg      return NULL;
4437117f1b4Smrg   }
4447117f1b4Smrg   bufObj->Pointer = bufObj->Data;
4454a49301eSmrg   bufObj->Length = bufObj->Size;
4464a49301eSmrg   bufObj->Offset = 0;
4477117f1b4Smrg   return bufObj->Pointer;
4487117f1b4Smrg}
4497117f1b4Smrg
4507117f1b4Smrg
4517117f1b4Smrg/**
4524a49301eSmrg * Default fallback for \c dd_function_table::MapBufferRange().
4534a49301eSmrg * Called via glMapBufferRange().
4544a49301eSmrg */
4554a49301eSmrgstatic void *
4564a49301eSmrg_mesa_buffer_map_range( GLcontext *ctx, GLenum target, GLintptr offset,
4574a49301eSmrg                        GLsizeiptr length, GLbitfield access,
4584a49301eSmrg                        struct gl_buffer_object *bufObj )
4594a49301eSmrg{
4604a49301eSmrg   (void) ctx;
4614a49301eSmrg   (void) target;
4624a49301eSmrg   assert(!_mesa_bufferobj_mapped(bufObj));
4634a49301eSmrg   /* Just return a direct pointer to the data */
4644a49301eSmrg   bufObj->Pointer = bufObj->Data + offset;
4654a49301eSmrg   bufObj->Length = length;
4664a49301eSmrg   bufObj->Offset = offset;
4674a49301eSmrg   bufObj->AccessFlags = access;
4684a49301eSmrg   return bufObj->Pointer;
4694a49301eSmrg}
4704a49301eSmrg
4714a49301eSmrg
4724a49301eSmrg/**
4734a49301eSmrg * Default fallback for \c dd_function_table::FlushMappedBufferRange().
4744a49301eSmrg * Called via glFlushMappedBufferRange().
4754a49301eSmrg */
4764a49301eSmrgstatic void
4774a49301eSmrg_mesa_buffer_flush_mapped_range( GLcontext *ctx, GLenum target,
4784a49301eSmrg                                 GLintptr offset, GLsizeiptr length,
4794a49301eSmrg                                 struct gl_buffer_object *obj )
4804a49301eSmrg{
4814a49301eSmrg   (void) ctx;
4824a49301eSmrg   (void) target;
4834a49301eSmrg   (void) offset;
4844a49301eSmrg   (void) length;
4854a49301eSmrg   (void) obj;
4864a49301eSmrg   /* no-op */
4874a49301eSmrg}
4884a49301eSmrg
4894a49301eSmrg
4904a49301eSmrg/**
4914a49301eSmrg * Default callback for \c dd_function_table::MapBuffer().
4927117f1b4Smrg *
4937117f1b4Smrg * The input parameters will have been already tested for errors.
4947117f1b4Smrg *
4957117f1b4Smrg * \sa glUnmapBufferARB, dd_function_table::UnmapBuffer
4967117f1b4Smrg */
4974a49301eSmrgstatic GLboolean
4987117f1b4Smrg_mesa_buffer_unmap( GLcontext *ctx, GLenum target,
4997117f1b4Smrg                    struct gl_buffer_object *bufObj )
5007117f1b4Smrg{
5017117f1b4Smrg   (void) ctx;
5027117f1b4Smrg   (void) target;
5037117f1b4Smrg   /* XXX we might assert here that bufObj->Pointer is non-null */
5047117f1b4Smrg   bufObj->Pointer = NULL;
5054a49301eSmrg   bufObj->Length = 0;
5064a49301eSmrg   bufObj->Offset = 0;
5074a49301eSmrg   bufObj->AccessFlags = 0x0;
5087117f1b4Smrg   return GL_TRUE;
5097117f1b4Smrg}
5107117f1b4Smrg
5117117f1b4Smrg
5124a49301eSmrg/**
5134a49301eSmrg * Default fallback for \c dd_function_table::CopyBufferSubData().
5144a49301eSmrg * Called via glCopyBuffserSubData().
5154a49301eSmrg */
5164a49301eSmrgstatic void
5174a49301eSmrg_mesa_copy_buffer_subdata(GLcontext *ctx,
5184a49301eSmrg                          struct gl_buffer_object *src,
5194a49301eSmrg                          struct gl_buffer_object *dst,
5204a49301eSmrg                          GLintptr readOffset, GLintptr writeOffset,
5214a49301eSmrg                          GLsizeiptr size)
5224a49301eSmrg{
5234a49301eSmrg   GLubyte *srcPtr, *dstPtr;
5244a49301eSmrg
5254a49301eSmrg   /* buffer should not already be mapped */
5264a49301eSmrg   assert(!_mesa_bufferobj_mapped(src));
5274a49301eSmrg   assert(!_mesa_bufferobj_mapped(dst));
5284a49301eSmrg
5294a49301eSmrg   srcPtr = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_COPY_READ_BUFFER,
5304a49301eSmrg                                              GL_READ_ONLY, src);
5314a49301eSmrg   dstPtr = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_COPY_WRITE_BUFFER,
5324a49301eSmrg                                              GL_WRITE_ONLY, dst);
5334a49301eSmrg
5344a49301eSmrg   if (srcPtr && dstPtr)
535cdc920a0Smrg      memcpy(dstPtr + writeOffset, srcPtr + readOffset, size);
5364a49301eSmrg
5374a49301eSmrg   ctx->Driver.UnmapBuffer(ctx, GL_COPY_READ_BUFFER, src);
5384a49301eSmrg   ctx->Driver.UnmapBuffer(ctx, GL_COPY_WRITE_BUFFER, dst);
5394a49301eSmrg}
5404a49301eSmrg
5414a49301eSmrg
5424a49301eSmrg
5437117f1b4Smrg/**
5447117f1b4Smrg * Initialize the state associated with buffer objects
5457117f1b4Smrg */
5467117f1b4Smrgvoid
5477117f1b4Smrg_mesa_init_buffer_objects( GLcontext *ctx )
5487117f1b4Smrg{
5494a49301eSmrg   _mesa_reference_buffer_object(ctx, &ctx->Array.ArrayBufferObj,
5504a49301eSmrg                                 ctx->Shared->NullBufferObj);
5514a49301eSmrg   _mesa_reference_buffer_object(ctx, &ctx->Array.ElementArrayBufferObj,
5524a49301eSmrg                                 ctx->Shared->NullBufferObj);
5534a49301eSmrg
5544a49301eSmrg   _mesa_reference_buffer_object(ctx, &ctx->CopyReadBuffer,
5554a49301eSmrg                                 ctx->Shared->NullBufferObj);
5564a49301eSmrg   _mesa_reference_buffer_object(ctx, &ctx->CopyWriteBuffer,
5574a49301eSmrg                                 ctx->Shared->NullBufferObj);
5584a49301eSmrg}
5594a49301eSmrg
5607117f1b4Smrg
5614a49301eSmrgvoid
5624a49301eSmrg_mesa_free_buffer_objects( GLcontext *ctx )
5634a49301eSmrg{
5644a49301eSmrg   _mesa_reference_buffer_object(ctx, &ctx->Array.ArrayBufferObj, NULL);
5654a49301eSmrg   _mesa_reference_buffer_object(ctx, &ctx->Array.ElementArrayBufferObj, NULL);
5664a49301eSmrg
5674a49301eSmrg   _mesa_reference_buffer_object(ctx, &ctx->CopyReadBuffer, NULL);
5684a49301eSmrg   _mesa_reference_buffer_object(ctx, &ctx->CopyWriteBuffer, NULL);
5697117f1b4Smrg}
5707117f1b4Smrg
5714a49301eSmrg
572c1f859d4Smrg/**
573c1f859d4Smrg * Bind the specified target to buffer for the specified context.
5744a49301eSmrg * Called by glBindBuffer() and other functions.
575c1f859d4Smrg */
576c1f859d4Smrgstatic void
577c1f859d4Smrgbind_buffer_object(GLcontext *ctx, GLenum target, GLuint buffer)
578c1f859d4Smrg{
579c1f859d4Smrg   struct gl_buffer_object *oldBufObj;
580c1f859d4Smrg   struct gl_buffer_object *newBufObj = NULL;
581c1f859d4Smrg   struct gl_buffer_object **bindTarget = NULL;
582c1f859d4Smrg
5834a49301eSmrg   bindTarget = get_buffer_target(ctx, target);
5844a49301eSmrg   if (!bindTarget) {
5854a49301eSmrg      _mesa_error(ctx, GL_INVALID_ENUM, "glBindBufferARB(target 0x%x)");
586c1f859d4Smrg      return;
587c1f859d4Smrg   }
588c1f859d4Smrg
589c1f859d4Smrg   /* Get pointer to old buffer object (to be unbound) */
5904a49301eSmrg   oldBufObj = *bindTarget;
591c1f859d4Smrg   if (oldBufObj && oldBufObj->Name == buffer)
592c1f859d4Smrg      return;   /* rebinding the same buffer object- no change */
593c1f859d4Smrg
594c1f859d4Smrg   /*
595c1f859d4Smrg    * Get pointer to new buffer object (newBufObj)
596c1f859d4Smrg    */
597c1f859d4Smrg   if (buffer == 0) {
598c1f859d4Smrg      /* The spec says there's not a buffer object named 0, but we use
599c1f859d4Smrg       * one internally because it simplifies things.
600c1f859d4Smrg       */
6014a49301eSmrg      newBufObj = ctx->Shared->NullBufferObj;
602c1f859d4Smrg   }
603c1f859d4Smrg   else {
604c1f859d4Smrg      /* non-default buffer object */
605c1f859d4Smrg      newBufObj = _mesa_lookup_bufferobj(ctx, buffer);
606c1f859d4Smrg      if (!newBufObj) {
607c1f859d4Smrg         /* if this is a new buffer object id, allocate a buffer object now */
608c1f859d4Smrg         ASSERT(ctx->Driver.NewBufferObject);
609c1f859d4Smrg         newBufObj = ctx->Driver.NewBufferObject(ctx, buffer, target);
610c1f859d4Smrg         if (!newBufObj) {
611c1f859d4Smrg            _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindBufferARB");
612c1f859d4Smrg            return;
613c1f859d4Smrg         }
614c1f859d4Smrg         _mesa_HashInsert(ctx->Shared->BufferObjects, buffer, newBufObj);
615c1f859d4Smrg      }
616c1f859d4Smrg   }
617c1f859d4Smrg
618c1f859d4Smrg   /* bind new buffer */
619c1f859d4Smrg   _mesa_reference_buffer_object(ctx, bindTarget, newBufObj);
620c1f859d4Smrg
621c1f859d4Smrg   /* Pass BindBuffer call to device driver */
6224a49301eSmrg   if (ctx->Driver.BindBuffer)
623c1f859d4Smrg      ctx->Driver.BindBuffer( ctx, target, newBufObj );
624c1f859d4Smrg}
625c1f859d4Smrg
626c1f859d4Smrg
627c1f859d4Smrg/**
628c1f859d4Smrg * Update the default buffer objects in the given context to reference those
629c1f859d4Smrg * specified in the shared state and release those referencing the old
630c1f859d4Smrg * shared state.
631c1f859d4Smrg */
632c1f859d4Smrgvoid
633c1f859d4Smrg_mesa_update_default_objects_buffer_objects(GLcontext *ctx)
634c1f859d4Smrg{
635c1f859d4Smrg   /* Bind the NullBufferObj to remove references to those
636c1f859d4Smrg    * in the shared context hash table.
637c1f859d4Smrg    */
638c1f859d4Smrg   bind_buffer_object( ctx, GL_ARRAY_BUFFER_ARB, 0);
639c1f859d4Smrg   bind_buffer_object( ctx, GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
640c1f859d4Smrg   bind_buffer_object( ctx, GL_PIXEL_PACK_BUFFER_ARB, 0);
641c1f859d4Smrg   bind_buffer_object( ctx, GL_PIXEL_UNPACK_BUFFER_ARB, 0);
642c1f859d4Smrg}
643c1f859d4Smrg
6447117f1b4Smrg
6457117f1b4Smrg/**
6467117f1b4Smrg * When we're about to read pixel data out of a PBO (via glDrawPixels,
6477117f1b4Smrg * glTexImage, etc) or write data into a PBO (via glReadPixels,
6487117f1b4Smrg * glGetTexImage, etc) we call this function to check that we're not
6497117f1b4Smrg * going to read out of bounds.
6507117f1b4Smrg *
6517117f1b4Smrg * XXX This would also be a convenient time to check that the PBO isn't
6527117f1b4Smrg * currently mapped.  Whoever calls this function should check for that.
6537117f1b4Smrg * Remember, we can't use a PBO when it's mapped!
6547117f1b4Smrg *
6554a49301eSmrg * If we're not using a PBO, this is a no-op.
6564a49301eSmrg *
6577117f1b4Smrg * \param width  width of image to read/write
6587117f1b4Smrg * \param height  height of image to read/write
6597117f1b4Smrg * \param depth  depth of image to read/write
6607117f1b4Smrg * \param format  format of image to read/write
6617117f1b4Smrg * \param type  datatype of image to read/write
6627117f1b4Smrg * \param ptr  the user-provided pointer/offset
6637117f1b4Smrg * \return GL_TRUE if the PBO access is OK, GL_FALSE if the access would
6647117f1b4Smrg *         go out of bounds.
6657117f1b4Smrg */
6667117f1b4SmrgGLboolean
6677117f1b4Smrg_mesa_validate_pbo_access(GLuint dimensions,
6687117f1b4Smrg                          const struct gl_pixelstore_attrib *pack,
6697117f1b4Smrg                          GLsizei width, GLsizei height, GLsizei depth,
6707117f1b4Smrg                          GLenum format, GLenum type, const GLvoid *ptr)
6717117f1b4Smrg{
6727117f1b4Smrg   GLvoid *start, *end;
6737117f1b4Smrg   const GLubyte *sizeAddr; /* buffer size, cast to a pointer */
6747117f1b4Smrg
6754a49301eSmrg   if (!_mesa_is_bufferobj(pack->BufferObj))
6764a49301eSmrg      return GL_TRUE;  /* no PBO, OK */
6777117f1b4Smrg
6787117f1b4Smrg   if (pack->BufferObj->Size == 0)
6797117f1b4Smrg      /* no buffer! */
6807117f1b4Smrg      return GL_FALSE;
6817117f1b4Smrg
6827117f1b4Smrg   /* get address of first pixel we'll read */
6837117f1b4Smrg   start = _mesa_image_address(dimensions, pack, ptr, width, height,
6847117f1b4Smrg                               format, type, 0, 0, 0);
6857117f1b4Smrg
6867117f1b4Smrg   /* get address just past the last pixel we'll read */
6877117f1b4Smrg   end =  _mesa_image_address(dimensions, pack, ptr, width, height,
6887117f1b4Smrg                              format, type, depth-1, height-1, width);
6897117f1b4Smrg
6907117f1b4Smrg
6917117f1b4Smrg   sizeAddr = ((const GLubyte *) 0) + pack->BufferObj->Size;
6927117f1b4Smrg
6937117f1b4Smrg   if ((const GLubyte *) start > sizeAddr) {
6947117f1b4Smrg      /* This will catch negative values / wrap-around */
6957117f1b4Smrg      return GL_FALSE;
6967117f1b4Smrg   }
6977117f1b4Smrg   if ((const GLubyte *) end > sizeAddr) {
6987117f1b4Smrg      /* Image read goes beyond end of buffer */
6997117f1b4Smrg      return GL_FALSE;
7007117f1b4Smrg   }
7017117f1b4Smrg
7027117f1b4Smrg   /* OK! */
7037117f1b4Smrg   return GL_TRUE;
7047117f1b4Smrg}
7057117f1b4Smrg
7067117f1b4Smrg
707c1f859d4Smrg/**
7084a49301eSmrg * For commands that read from a PBO (glDrawPixels, glTexImage,
7094a49301eSmrg * glPolygonStipple, etc), if we're reading from a PBO, map it read-only
7104a49301eSmrg * and return the pointer into the PBO.  If we're not reading from a
7114a49301eSmrg * PBO, return \p src as-is.
7124a49301eSmrg * If non-null return, must call _mesa_unmap_pbo_source() when done.
7134a49301eSmrg *
7144a49301eSmrg * \return NULL if error, else pointer to start of data
715c1f859d4Smrg */
7164a49301eSmrgconst GLvoid *
7174a49301eSmrg_mesa_map_pbo_source(GLcontext *ctx,
718c1f859d4Smrg                     const struct gl_pixelstore_attrib *unpack,
7194a49301eSmrg                     const GLvoid *src)
720c1f859d4Smrg{
721c1f859d4Smrg   const GLubyte *buf;
722c1f859d4Smrg
7234a49301eSmrg   if (_mesa_is_bufferobj(unpack->BufferObj)) {
724c1f859d4Smrg      /* unpack from PBO */
725c1f859d4Smrg      buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
726c1f859d4Smrg                                              GL_READ_ONLY_ARB,
727c1f859d4Smrg                                              unpack->BufferObj);
728c1f859d4Smrg      if (!buf)
729c1f859d4Smrg         return NULL;
730c1f859d4Smrg
7314a49301eSmrg      buf = ADD_POINTERS(buf, src);
732c1f859d4Smrg   }
733c1f859d4Smrg   else {
734c1f859d4Smrg      /* unpack from normal memory */
7354a49301eSmrg      buf = src;
736c1f859d4Smrg   }
737c1f859d4Smrg
738c1f859d4Smrg   return buf;
739c1f859d4Smrg}
740c1f859d4Smrg
741c1f859d4Smrg
742c1f859d4Smrg/**
7434a49301eSmrg * Combine PBO-read validation and mapping.
7444a49301eSmrg * If any GL errors are detected, they'll be recorded and NULL returned.
7454a49301eSmrg * \sa _mesa_validate_pbo_access
7464a49301eSmrg * \sa _mesa_map_pbo_source
7474a49301eSmrg * A call to this function should have a matching call to
7484a49301eSmrg * _mesa_unmap_pbo_source().
749c1f859d4Smrg */
750c1f859d4Smrgconst GLvoid *
7514a49301eSmrg_mesa_map_validate_pbo_source(GLcontext *ctx,
7524a49301eSmrg                              GLuint dimensions,
7534a49301eSmrg                              const struct gl_pixelstore_attrib *unpack,
7544a49301eSmrg                              GLsizei width, GLsizei height, GLsizei depth,
7554a49301eSmrg                              GLenum format, GLenum type, const GLvoid *ptr,
7564a49301eSmrg                              const char *where)
757c1f859d4Smrg{
7584a49301eSmrg   ASSERT(dimensions == 1 || dimensions == 2 || dimensions == 3);
759c1f859d4Smrg
7604a49301eSmrg   if (!_mesa_is_bufferobj(unpack->BufferObj)) {
7614a49301eSmrg      /* non-PBO access: no validation to be done */
7624a49301eSmrg      return ptr;
7634a49301eSmrg   }
764c1f859d4Smrg
7654a49301eSmrg   if (!_mesa_validate_pbo_access(dimensions, unpack,
7664a49301eSmrg                                  width, height, depth, format, type, ptr)) {
7674a49301eSmrg      _mesa_error(ctx, GL_INVALID_OPERATION,
7684a49301eSmrg                  "%s(out of bounds PBO access)", where);
7694a49301eSmrg      return NULL;
770c1f859d4Smrg   }
7714a49301eSmrg
7724a49301eSmrg   if (_mesa_bufferobj_mapped(unpack->BufferObj)) {
7734a49301eSmrg      /* buffer is already mapped - that's an error */
7744a49301eSmrg      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(PBO is mapped)", where);
7754a49301eSmrg      return NULL;
776c1f859d4Smrg   }
777c1f859d4Smrg
7784a49301eSmrg   ptr = _mesa_map_pbo_source(ctx, unpack, ptr);
7794a49301eSmrg   return ptr;
780c1f859d4Smrg}
781c1f859d4Smrg
782c1f859d4Smrg
783c1f859d4Smrg/**
7844a49301eSmrg * Counterpart to _mesa_map_pbo_source()
785c1f859d4Smrg */
786c1f859d4Smrgvoid
7874a49301eSmrg_mesa_unmap_pbo_source(GLcontext *ctx,
788c1f859d4Smrg                       const struct gl_pixelstore_attrib *unpack)
789c1f859d4Smrg{
7904a49301eSmrg   ASSERT(unpack != &ctx->Pack); /* catch pack/unpack mismatch */
7914a49301eSmrg   if (_mesa_is_bufferobj(unpack->BufferObj)) {
792c1f859d4Smrg      ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
793c1f859d4Smrg                              unpack->BufferObj);
794c1f859d4Smrg   }
795c1f859d4Smrg}
796c1f859d4Smrg
797c1f859d4Smrg
798c1f859d4Smrg/**
7994a49301eSmrg * For commands that write to a PBO (glReadPixels, glGetColorTable, etc),
8004a49301eSmrg * if we're writing to a PBO, map it write-only and return the pointer
8014a49301eSmrg * into the PBO.  If we're not writing to a PBO, return \p dst as-is.
8024a49301eSmrg * If non-null return, must call _mesa_unmap_pbo_dest() when done.
8034a49301eSmrg *
8044a49301eSmrg * \return NULL if error, else pointer to start of data
805c1f859d4Smrg */
806c1f859d4Smrgvoid *
8074a49301eSmrg_mesa_map_pbo_dest(GLcontext *ctx,
8084a49301eSmrg                   const struct gl_pixelstore_attrib *pack,
8094a49301eSmrg                   GLvoid *dest)
810c1f859d4Smrg{
811c1f859d4Smrg   void *buf;
812c1f859d4Smrg
8134a49301eSmrg   if (_mesa_is_bufferobj(pack->BufferObj)) {
814c1f859d4Smrg      /* pack into PBO */
815c1f859d4Smrg      buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT,
816c1f859d4Smrg                                              GL_WRITE_ONLY_ARB,
817c1f859d4Smrg                                              pack->BufferObj);
818c1f859d4Smrg      if (!buf)
819c1f859d4Smrg         return NULL;
820c1f859d4Smrg
821c1f859d4Smrg      buf = ADD_POINTERS(buf, dest);
822c1f859d4Smrg   }
823c1f859d4Smrg   else {
824c1f859d4Smrg      /* pack to normal memory */
825c1f859d4Smrg      buf = dest;
826c1f859d4Smrg   }
827c1f859d4Smrg
828c1f859d4Smrg   return buf;
829c1f859d4Smrg}
830c1f859d4Smrg
831c1f859d4Smrg
832c1f859d4Smrg/**
8334a49301eSmrg * Combine PBO-write validation and mapping.
8344a49301eSmrg * If any GL errors are detected, they'll be recorded and NULL returned.
8354a49301eSmrg * \sa _mesa_validate_pbo_access
8364a49301eSmrg * \sa _mesa_map_pbo_dest
8374a49301eSmrg * A call to this function should have a matching call to
8384a49301eSmrg * _mesa_unmap_pbo_dest().
8394a49301eSmrg */
8404a49301eSmrgGLvoid *
8414a49301eSmrg_mesa_map_validate_pbo_dest(GLcontext *ctx,
8424a49301eSmrg                            GLuint dimensions,
8434a49301eSmrg                            const struct gl_pixelstore_attrib *unpack,
8444a49301eSmrg                            GLsizei width, GLsizei height, GLsizei depth,
8454a49301eSmrg                            GLenum format, GLenum type, GLvoid *ptr,
8464a49301eSmrg                            const char *where)
8474a49301eSmrg{
8484a49301eSmrg   ASSERT(dimensions == 1 || dimensions == 2 || dimensions == 3);
8494a49301eSmrg
8504a49301eSmrg   if (!_mesa_is_bufferobj(unpack->BufferObj)) {
8514a49301eSmrg      /* non-PBO access: no validation to be done */
8524a49301eSmrg      return ptr;
8534a49301eSmrg   }
8544a49301eSmrg
8554a49301eSmrg   if (!_mesa_validate_pbo_access(dimensions, unpack,
8564a49301eSmrg                                  width, height, depth, format, type, ptr)) {
8574a49301eSmrg      _mesa_error(ctx, GL_INVALID_OPERATION,
8584a49301eSmrg                  "%s(out of bounds PBO access)", where);
8594a49301eSmrg      return NULL;
8604a49301eSmrg   }
8614a49301eSmrg
8624a49301eSmrg   if (_mesa_bufferobj_mapped(unpack->BufferObj)) {
8634a49301eSmrg      /* buffer is already mapped - that's an error */
8644a49301eSmrg      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(PBO is mapped)", where);
8654a49301eSmrg      return NULL;
8664a49301eSmrg   }
8674a49301eSmrg
8684a49301eSmrg   ptr = _mesa_map_pbo_dest(ctx, unpack, ptr);
8694a49301eSmrg   return ptr;
8704a49301eSmrg}
8714a49301eSmrg
8724a49301eSmrg
8734a49301eSmrg/**
8744a49301eSmrg * Counterpart to _mesa_map_pbo_dest()
875c1f859d4Smrg */
876c1f859d4Smrgvoid
8774a49301eSmrg_mesa_unmap_pbo_dest(GLcontext *ctx,
8784a49301eSmrg                     const struct gl_pixelstore_attrib *pack)
879c1f859d4Smrg{
8804a49301eSmrg   ASSERT(pack != &ctx->Unpack); /* catch pack/unpack mismatch */
8814a49301eSmrg   if (_mesa_is_bufferobj(pack->BufferObj)) {
882c1f859d4Smrg      ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT, pack->BufferObj);
883c1f859d4Smrg   }
884c1f859d4Smrg}
885c1f859d4Smrg
886c1f859d4Smrg
887c1f859d4Smrg
8887117f1b4Smrg/**
8897117f1b4Smrg * Return the gl_buffer_object for the given ID.
8907117f1b4Smrg * Always return NULL for ID 0.
8917117f1b4Smrg */
8927117f1b4Smrgstruct gl_buffer_object *
8937117f1b4Smrg_mesa_lookup_bufferobj(GLcontext *ctx, GLuint buffer)
8947117f1b4Smrg{
8957117f1b4Smrg   if (buffer == 0)
8967117f1b4Smrg      return NULL;
8977117f1b4Smrg   else
8987117f1b4Smrg      return (struct gl_buffer_object *)
8997117f1b4Smrg         _mesa_HashLookup(ctx->Shared->BufferObjects, buffer);
9007117f1b4Smrg}
9017117f1b4Smrg
9027117f1b4Smrg
903c1f859d4Smrg/**
904c1f859d4Smrg * If *ptr points to obj, set ptr = the Null/default buffer object.
905c1f859d4Smrg * This is a helper for buffer object deletion.
906c1f859d4Smrg * The GL spec says that deleting a buffer object causes it to get
907c1f859d4Smrg * unbound from all arrays in the current context.
908c1f859d4Smrg */
909c1f859d4Smrgstatic void
910c1f859d4Smrgunbind(GLcontext *ctx,
911c1f859d4Smrg       struct gl_buffer_object **ptr,
912c1f859d4Smrg       struct gl_buffer_object *obj)
913c1f859d4Smrg{
914c1f859d4Smrg   if (*ptr == obj) {
9154a49301eSmrg      _mesa_reference_buffer_object(ctx, ptr, ctx->Shared->NullBufferObj);
916c1f859d4Smrg   }
917c1f859d4Smrg}
918c1f859d4Smrg
919c1f859d4Smrg
9204a49301eSmrg/**
9214a49301eSmrg * Plug default/fallback buffer object functions into the device
9224a49301eSmrg * driver hooks.
9234a49301eSmrg */
9244a49301eSmrgvoid
9254a49301eSmrg_mesa_init_buffer_object_functions(struct dd_function_table *driver)
9264a49301eSmrg{
9274a49301eSmrg   /* GL_ARB_vertex/pixel_buffer_object */
9284a49301eSmrg   driver->NewBufferObject = _mesa_new_buffer_object;
9294a49301eSmrg   driver->DeleteBuffer = _mesa_delete_buffer_object;
9304a49301eSmrg   driver->BindBuffer = NULL;
9314a49301eSmrg   driver->BufferData = _mesa_buffer_data;
9324a49301eSmrg   driver->BufferSubData = _mesa_buffer_subdata;
9334a49301eSmrg   driver->GetBufferSubData = _mesa_buffer_get_subdata;
9344a49301eSmrg   driver->MapBuffer = _mesa_buffer_map;
9354a49301eSmrg   driver->UnmapBuffer = _mesa_buffer_unmap;
9364a49301eSmrg
9374a49301eSmrg   /* GL_ARB_map_buffer_range */
9384a49301eSmrg   driver->MapBufferRange = _mesa_buffer_map_range;
9394a49301eSmrg   driver->FlushMappedBufferRange = _mesa_buffer_flush_mapped_range;
9404a49301eSmrg
9414a49301eSmrg   /* GL_ARB_copy_buffer */
9424a49301eSmrg   driver->CopyBufferSubData = _mesa_copy_buffer_subdata;
9434a49301eSmrg}
9444a49301eSmrg
9454a49301eSmrg
9467117f1b4Smrg
9477117f1b4Smrg/**********************************************************************/
9487117f1b4Smrg/* API Functions                                                      */
9497117f1b4Smrg/**********************************************************************/
9507117f1b4Smrg
9517117f1b4Smrgvoid GLAPIENTRY
9527117f1b4Smrg_mesa_BindBufferARB(GLenum target, GLuint buffer)
9537117f1b4Smrg{
9547117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
9557117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
9567117f1b4Smrg
957c1f859d4Smrg   bind_buffer_object(ctx, target, buffer);
9587117f1b4Smrg}
9597117f1b4Smrg
9607117f1b4Smrg
9617117f1b4Smrg/**
9627117f1b4Smrg * Delete a set of buffer objects.
9637117f1b4Smrg *
9647117f1b4Smrg * \param n      Number of buffer objects to delete.
9657117f1b4Smrg * \param ids    Array of \c n buffer object IDs.
9667117f1b4Smrg */
9677117f1b4Smrgvoid GLAPIENTRY
9687117f1b4Smrg_mesa_DeleteBuffersARB(GLsizei n, const GLuint *ids)
9697117f1b4Smrg{
9707117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
9717117f1b4Smrg   GLsizei i;
9727117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
9737117f1b4Smrg
9747117f1b4Smrg   if (n < 0) {
9757117f1b4Smrg      _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteBuffersARB(n)");
9767117f1b4Smrg      return;
9777117f1b4Smrg   }
9787117f1b4Smrg
9797117f1b4Smrg   _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
9807117f1b4Smrg
9817117f1b4Smrg   for (i = 0; i < n; i++) {
9827117f1b4Smrg      struct gl_buffer_object *bufObj = _mesa_lookup_bufferobj(ctx, ids[i]);
9837117f1b4Smrg      if (bufObj) {
9844a49301eSmrg         struct gl_array_object *arrayObj = ctx->Array.ArrayObj;
9857117f1b4Smrg         GLuint j;
9867117f1b4Smrg
9877117f1b4Smrg         ASSERT(bufObj->Name == ids[i]);
9887117f1b4Smrg
9894a49301eSmrg         if (_mesa_bufferobj_mapped(bufObj)) {
990c1f859d4Smrg            /* if mapped, unmap it now */
991c1f859d4Smrg            ctx->Driver.UnmapBuffer(ctx, 0, bufObj);
9924a49301eSmrg            bufObj->AccessFlags = DEFAULT_ACCESS;
993c1f859d4Smrg            bufObj->Pointer = NULL;
9947117f1b4Smrg         }
995c1f859d4Smrg
9964a49301eSmrg         /* unbind any vertex pointers bound to this buffer */
9974a49301eSmrg         unbind(ctx, &arrayObj->Vertex.BufferObj, bufObj);
9984a49301eSmrg         unbind(ctx, &arrayObj->Weight.BufferObj, bufObj);
9994a49301eSmrg         unbind(ctx, &arrayObj->Normal.BufferObj, bufObj);
10004a49301eSmrg         unbind(ctx, &arrayObj->Color.BufferObj, bufObj);
10014a49301eSmrg         unbind(ctx, &arrayObj->SecondaryColor.BufferObj, bufObj);
10024a49301eSmrg         unbind(ctx, &arrayObj->FogCoord.BufferObj, bufObj);
10034a49301eSmrg         unbind(ctx, &arrayObj->Index.BufferObj, bufObj);
10044a49301eSmrg         unbind(ctx, &arrayObj->EdgeFlag.BufferObj, bufObj);
10054a49301eSmrg         for (j = 0; j < Elements(arrayObj->TexCoord); j++) {
10064a49301eSmrg            unbind(ctx, &arrayObj->TexCoord[j].BufferObj, bufObj);
10077117f1b4Smrg         }
10084a49301eSmrg         for (j = 0; j < Elements(arrayObj->VertexAttrib); j++) {
10094a49301eSmrg            unbind(ctx, &arrayObj->VertexAttrib[j].BufferObj, bufObj);
10107117f1b4Smrg         }
10117117f1b4Smrg
10127117f1b4Smrg         if (ctx->Array.ArrayBufferObj == bufObj) {
10137117f1b4Smrg            _mesa_BindBufferARB( GL_ARRAY_BUFFER_ARB, 0 );
10147117f1b4Smrg         }
10157117f1b4Smrg         if (ctx->Array.ElementArrayBufferObj == bufObj) {
10167117f1b4Smrg            _mesa_BindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, 0 );
10177117f1b4Smrg         }
10187117f1b4Smrg
10194a49301eSmrg         /* unbind any pixel pack/unpack pointers bound to this buffer */
10207117f1b4Smrg         if (ctx->Pack.BufferObj == bufObj) {
10217117f1b4Smrg            _mesa_BindBufferARB( GL_PIXEL_PACK_BUFFER_EXT, 0 );
10227117f1b4Smrg         }
10237117f1b4Smrg         if (ctx->Unpack.BufferObj == bufObj) {
10247117f1b4Smrg            _mesa_BindBufferARB( GL_PIXEL_UNPACK_BUFFER_EXT, 0 );
10257117f1b4Smrg         }
10267117f1b4Smrg
1027c1f859d4Smrg         /* The ID is immediately freed for re-use */
1028c1f859d4Smrg         _mesa_HashRemove(ctx->Shared->BufferObjects, bufObj->Name);
1029c1f859d4Smrg         _mesa_reference_buffer_object(ctx, &bufObj, NULL);
10307117f1b4Smrg      }
10317117f1b4Smrg   }
10327117f1b4Smrg
10337117f1b4Smrg   _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
10347117f1b4Smrg}
10357117f1b4Smrg
10367117f1b4Smrg
10377117f1b4Smrg/**
10387117f1b4Smrg * Generate a set of unique buffer object IDs and store them in \c buffer.
10397117f1b4Smrg *
10407117f1b4Smrg * \param n       Number of IDs to generate.
10417117f1b4Smrg * \param buffer  Array of \c n locations to store the IDs.
10427117f1b4Smrg */
10437117f1b4Smrgvoid GLAPIENTRY
10447117f1b4Smrg_mesa_GenBuffersARB(GLsizei n, GLuint *buffer)
10457117f1b4Smrg{
10467117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
10477117f1b4Smrg   GLuint first;
10487117f1b4Smrg   GLint i;
10497117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
10507117f1b4Smrg
10517117f1b4Smrg   if (n < 0) {
10527117f1b4Smrg      _mesa_error(ctx, GL_INVALID_VALUE, "glGenBuffersARB");
10537117f1b4Smrg      return;
10547117f1b4Smrg   }
10557117f1b4Smrg
10567117f1b4Smrg   if (!buffer) {
10577117f1b4Smrg      return;
10587117f1b4Smrg   }
10597117f1b4Smrg
10607117f1b4Smrg   /*
10617117f1b4Smrg    * This must be atomic (generation and allocation of buffer object IDs)
10627117f1b4Smrg    */
10637117f1b4Smrg   _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
10647117f1b4Smrg
10657117f1b4Smrg   first = _mesa_HashFindFreeKeyBlock(ctx->Shared->BufferObjects, n);
10667117f1b4Smrg
10677117f1b4Smrg   /* Allocate new, empty buffer objects and return identifiers */
10687117f1b4Smrg   for (i = 0; i < n; i++) {
10697117f1b4Smrg      struct gl_buffer_object *bufObj;
10707117f1b4Smrg      GLuint name = first + i;
10717117f1b4Smrg      GLenum target = 0;
10727117f1b4Smrg      bufObj = ctx->Driver.NewBufferObject( ctx, name, target );
10737117f1b4Smrg      if (!bufObj) {
10747117f1b4Smrg         _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
10757117f1b4Smrg         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenBuffersARB");
10767117f1b4Smrg         return;
10777117f1b4Smrg      }
1078c1f859d4Smrg      _mesa_HashInsert(ctx->Shared->BufferObjects, first + i, bufObj);
10797117f1b4Smrg      buffer[i] = first + i;
10807117f1b4Smrg   }
10817117f1b4Smrg
10827117f1b4Smrg   _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
10837117f1b4Smrg}
10847117f1b4Smrg
10857117f1b4Smrg
10867117f1b4Smrg/**
10877117f1b4Smrg * Determine if ID is the name of a buffer object.
10887117f1b4Smrg *
10897117f1b4Smrg * \param id  ID of the potential buffer object.
10907117f1b4Smrg * \return  \c GL_TRUE if \c id is the name of a buffer object,
10917117f1b4Smrg *          \c GL_FALSE otherwise.
10927117f1b4Smrg */
10937117f1b4SmrgGLboolean GLAPIENTRY
10947117f1b4Smrg_mesa_IsBufferARB(GLuint id)
10957117f1b4Smrg{
10967117f1b4Smrg   struct gl_buffer_object *bufObj;
10977117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
10987117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
10997117f1b4Smrg
11007117f1b4Smrg   _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
11017117f1b4Smrg   bufObj = _mesa_lookup_bufferobj(ctx, id);
11027117f1b4Smrg   _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
11037117f1b4Smrg
11047117f1b4Smrg   return bufObj ? GL_TRUE : GL_FALSE;
11057117f1b4Smrg}
11067117f1b4Smrg
11077117f1b4Smrg
11087117f1b4Smrgvoid GLAPIENTRY
11097117f1b4Smrg_mesa_BufferDataARB(GLenum target, GLsizeiptrARB size,
11107117f1b4Smrg                    const GLvoid * data, GLenum usage)
11117117f1b4Smrg{
11127117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
11137117f1b4Smrg   struct gl_buffer_object *bufObj;
11147117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
11157117f1b4Smrg
11167117f1b4Smrg   if (size < 0) {
11177117f1b4Smrg      _mesa_error(ctx, GL_INVALID_VALUE, "glBufferDataARB(size < 0)");
11187117f1b4Smrg      return;
11197117f1b4Smrg   }
11207117f1b4Smrg
11217117f1b4Smrg   switch (usage) {
1122cdc920a0Smrg   case GL_STREAM_DRAW_ARB:
1123cdc920a0Smrg   case GL_STREAM_READ_ARB:
1124cdc920a0Smrg   case GL_STREAM_COPY_ARB:
1125cdc920a0Smrg   case GL_STATIC_DRAW_ARB:
1126cdc920a0Smrg   case GL_STATIC_READ_ARB:
1127cdc920a0Smrg   case GL_STATIC_COPY_ARB:
1128cdc920a0Smrg   case GL_DYNAMIC_DRAW_ARB:
1129cdc920a0Smrg   case GL_DYNAMIC_READ_ARB:
1130cdc920a0Smrg   case GL_DYNAMIC_COPY_ARB:
1131cdc920a0Smrg      /* OK */
1132cdc920a0Smrg      break;
1133cdc920a0Smrg   default:
1134cdc920a0Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glBufferDataARB(usage)");
1135cdc920a0Smrg      return;
11367117f1b4Smrg   }
11377117f1b4Smrg
11387117f1b4Smrg   bufObj = get_buffer(ctx, target);
11397117f1b4Smrg   if (!bufObj) {
11407117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glBufferDataARB(target)" );
11417117f1b4Smrg      return;
11427117f1b4Smrg   }
11434a49301eSmrg   if (!_mesa_is_bufferobj(bufObj)) {
11444a49301eSmrg      _mesa_error(ctx, GL_INVALID_OPERATION, "glBufferDataARB(buffer 0)" );
11457117f1b4Smrg      return;
11467117f1b4Smrg   }
11477117f1b4Smrg
11484a49301eSmrg   if (_mesa_bufferobj_mapped(bufObj)) {
1149c1f859d4Smrg      /* Unmap the existing buffer.  We'll replace it now.  Not an error. */
1150c1f859d4Smrg      ctx->Driver.UnmapBuffer(ctx, target, bufObj);
11514a49301eSmrg      bufObj->AccessFlags = DEFAULT_ACCESS;
11524a49301eSmrg      ASSERT(bufObj->Pointer == NULL);
11537117f1b4Smrg   }
11547117f1b4Smrg
11554a49301eSmrg   FLUSH_VERTICES(ctx, _NEW_BUFFER_OBJECT);
11564a49301eSmrg
11574a49301eSmrg   bufObj->Written = GL_TRUE;
11587117f1b4Smrg
11594a49301eSmrg#ifdef VBO_DEBUG
1160cdc920a0Smrg   printf("glBufferDataARB(%u, sz %ld, from %p, usage 0x%x)\n",
11614a49301eSmrg                bufObj->Name, size, data, usage);
11624a49301eSmrg#endif
11634a49301eSmrg
11644a49301eSmrg#ifdef BOUNDS_CHECK
11654a49301eSmrg   size += 100;
11664a49301eSmrg#endif
11674a49301eSmrg
11684a49301eSmrg   ASSERT(ctx->Driver.BufferData);
11694a49301eSmrg   if (!ctx->Driver.BufferData( ctx, target, size, data, usage, bufObj )) {
11704a49301eSmrg      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBufferDataARB()");
11714a49301eSmrg   }
11727117f1b4Smrg}
11737117f1b4Smrg
11747117f1b4Smrg
11757117f1b4Smrgvoid GLAPIENTRY
11767117f1b4Smrg_mesa_BufferSubDataARB(GLenum target, GLintptrARB offset,
11777117f1b4Smrg                       GLsizeiptrARB size, const GLvoid * data)
11787117f1b4Smrg{
11797117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
11807117f1b4Smrg   struct gl_buffer_object *bufObj;
11817117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
11827117f1b4Smrg
11837117f1b4Smrg   bufObj = buffer_object_subdata_range_good( ctx, target, offset, size,
11847117f1b4Smrg                                              "glBufferSubDataARB" );
11857117f1b4Smrg   if (!bufObj) {
11867117f1b4Smrg      /* error already recorded */
11877117f1b4Smrg      return;
11887117f1b4Smrg   }
11897117f1b4Smrg
11904a49301eSmrg   bufObj->Written = GL_TRUE;
11914a49301eSmrg
11927117f1b4Smrg   ASSERT(ctx->Driver.BufferSubData);
11937117f1b4Smrg   ctx->Driver.BufferSubData( ctx, target, offset, size, data, bufObj );
11947117f1b4Smrg}
11957117f1b4Smrg
11967117f1b4Smrg
11977117f1b4Smrgvoid GLAPIENTRY
11987117f1b4Smrg_mesa_GetBufferSubDataARB(GLenum target, GLintptrARB offset,
11997117f1b4Smrg                          GLsizeiptrARB size, void * data)
12007117f1b4Smrg{
12017117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
12027117f1b4Smrg   struct gl_buffer_object *bufObj;
12037117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
12047117f1b4Smrg
12057117f1b4Smrg   bufObj = buffer_object_subdata_range_good( ctx, target, offset, size,
12067117f1b4Smrg                                              "glGetBufferSubDataARB" );
12077117f1b4Smrg   if (!bufObj) {
12087117f1b4Smrg      /* error already recorded */
12097117f1b4Smrg      return;
12107117f1b4Smrg   }
12117117f1b4Smrg
12127117f1b4Smrg   ASSERT(ctx->Driver.GetBufferSubData);
12137117f1b4Smrg   ctx->Driver.GetBufferSubData( ctx, target, offset, size, data, bufObj );
12147117f1b4Smrg}
12157117f1b4Smrg
12167117f1b4Smrg
12177117f1b4Smrgvoid * GLAPIENTRY
12187117f1b4Smrg_mesa_MapBufferARB(GLenum target, GLenum access)
12197117f1b4Smrg{
12207117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
12217117f1b4Smrg   struct gl_buffer_object * bufObj;
12224a49301eSmrg   GLbitfield accessFlags;
12234a49301eSmrg   void *map;
12244a49301eSmrg
12257117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, NULL);
12267117f1b4Smrg
12277117f1b4Smrg   switch (access) {
1228cdc920a0Smrg   case GL_READ_ONLY_ARB:
1229cdc920a0Smrg      accessFlags = GL_MAP_READ_BIT;
1230cdc920a0Smrg      break;
1231cdc920a0Smrg   case GL_WRITE_ONLY_ARB:
1232cdc920a0Smrg      accessFlags = GL_MAP_WRITE_BIT;
1233cdc920a0Smrg      break;
1234cdc920a0Smrg   case GL_READ_WRITE_ARB:
1235cdc920a0Smrg      accessFlags = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT;
1236cdc920a0Smrg      break;
1237cdc920a0Smrg   default:
1238cdc920a0Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glMapBufferARB(access)");
1239cdc920a0Smrg      return NULL;
12407117f1b4Smrg   }
12417117f1b4Smrg
12427117f1b4Smrg   bufObj = get_buffer(ctx, target);
12437117f1b4Smrg   if (!bufObj) {
12447117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glMapBufferARB(target)" );
12457117f1b4Smrg      return NULL;
12467117f1b4Smrg   }
12474a49301eSmrg   if (!_mesa_is_bufferobj(bufObj)) {
12484a49301eSmrg      _mesa_error(ctx, GL_INVALID_OPERATION, "glMapBufferARB(buffer 0)" );
12497117f1b4Smrg      return NULL;
12507117f1b4Smrg   }
12514a49301eSmrg   if (_mesa_bufferobj_mapped(bufObj)) {
12527117f1b4Smrg      _mesa_error(ctx, GL_INVALID_OPERATION, "glMapBufferARB(already mapped)");
12537117f1b4Smrg      return NULL;
12547117f1b4Smrg   }
12557117f1b4Smrg
12567117f1b4Smrg   ASSERT(ctx->Driver.MapBuffer);
12574a49301eSmrg   map = ctx->Driver.MapBuffer( ctx, target, access, bufObj );
12584a49301eSmrg   if (!map) {
12594a49301eSmrg      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glMapBufferARB(map failed)");
12604a49301eSmrg      return NULL;
12614a49301eSmrg   }
12624a49301eSmrg   else {
12634a49301eSmrg      /* The driver callback should have set these fields.
12644a49301eSmrg       * This is important because other modules (like VBO) might call
12654a49301eSmrg       * the driver function directly.
12664a49301eSmrg       */
12674a49301eSmrg      ASSERT(bufObj->Pointer == map);
12684a49301eSmrg      ASSERT(bufObj->Length == bufObj->Size);
12694a49301eSmrg      ASSERT(bufObj->Offset == 0);
12704a49301eSmrg      bufObj->AccessFlags = accessFlags;
12717117f1b4Smrg   }
12727117f1b4Smrg
12734a49301eSmrg   if (access == GL_WRITE_ONLY_ARB || access == GL_READ_WRITE_ARB)
12744a49301eSmrg      bufObj->Written = GL_TRUE;
12754a49301eSmrg
12764a49301eSmrg#ifdef VBO_DEBUG
1277cdc920a0Smrg   printf("glMapBufferARB(%u, sz %ld, access 0x%x)\n",
1278cdc920a0Smrg	  bufObj->Name, bufObj->Size, access);
12794a49301eSmrg   if (access == GL_WRITE_ONLY_ARB) {
12804a49301eSmrg      GLuint i;
12814a49301eSmrg      GLubyte *b = (GLubyte *) bufObj->Pointer;
12824a49301eSmrg      for (i = 0; i < bufObj->Size; i++)
12834a49301eSmrg         b[i] = i & 0xff;
12844a49301eSmrg   }
12854a49301eSmrg#endif
12864a49301eSmrg
12874a49301eSmrg#ifdef BOUNDS_CHECK
12884a49301eSmrg   {
12894a49301eSmrg      GLubyte *buf = (GLubyte *) bufObj->Pointer;
12904a49301eSmrg      GLuint i;
12914a49301eSmrg      /* buffer is 100 bytes larger than requested, fill with magic value */
12924a49301eSmrg      for (i = 0; i < 100; i++) {
12934a49301eSmrg         buf[bufObj->Size - i - 1] = 123;
12944a49301eSmrg      }
12954a49301eSmrg   }
12964a49301eSmrg#endif
12977117f1b4Smrg
12987117f1b4Smrg   return bufObj->Pointer;
12997117f1b4Smrg}
13007117f1b4Smrg
13017117f1b4Smrg
13027117f1b4SmrgGLboolean GLAPIENTRY
13037117f1b4Smrg_mesa_UnmapBufferARB(GLenum target)
13047117f1b4Smrg{
13057117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
13067117f1b4Smrg   struct gl_buffer_object *bufObj;
13077117f1b4Smrg   GLboolean status = GL_TRUE;
13087117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
13097117f1b4Smrg
13107117f1b4Smrg   bufObj = get_buffer(ctx, target);
13117117f1b4Smrg   if (!bufObj) {
13127117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glUnmapBufferARB(target)" );
13137117f1b4Smrg      return GL_FALSE;
13147117f1b4Smrg   }
13154a49301eSmrg   if (!_mesa_is_bufferobj(bufObj)) {
13167117f1b4Smrg      _mesa_error(ctx, GL_INVALID_OPERATION, "glUnmapBufferARB" );
13177117f1b4Smrg      return GL_FALSE;
13187117f1b4Smrg   }
13194a49301eSmrg   if (!_mesa_bufferobj_mapped(bufObj)) {
13207117f1b4Smrg      _mesa_error(ctx, GL_INVALID_OPERATION, "glUnmapBufferARB");
13217117f1b4Smrg      return GL_FALSE;
13227117f1b4Smrg   }
13237117f1b4Smrg
13244a49301eSmrg#ifdef BOUNDS_CHECK
13254a49301eSmrg   if (bufObj->Access != GL_READ_ONLY_ARB) {
13264a49301eSmrg      GLubyte *buf = (GLubyte *) bufObj->Pointer;
13274a49301eSmrg      GLuint i;
13284a49301eSmrg      /* check that last 100 bytes are still = magic value */
13294a49301eSmrg      for (i = 0; i < 100; i++) {
13304a49301eSmrg         GLuint pos = bufObj->Size - i - 1;
13314a49301eSmrg         if (buf[pos] != 123) {
13324a49301eSmrg            _mesa_warning(ctx, "Out of bounds buffer object write detected"
13334a49301eSmrg                          " at position %d (value = %u)\n",
13344a49301eSmrg                          pos, buf[pos]);
13354a49301eSmrg         }
13364a49301eSmrg      }
13374a49301eSmrg   }
13384a49301eSmrg#endif
13394a49301eSmrg
13404a49301eSmrg#ifdef VBO_DEBUG
13414a49301eSmrg   if (bufObj->AccessFlags & GL_MAP_WRITE_BIT) {
13424a49301eSmrg      GLuint i, unchanged = 0;
13434a49301eSmrg      GLubyte *b = (GLubyte *) bufObj->Pointer;
13444a49301eSmrg      GLint pos = -1;
13454a49301eSmrg      /* check which bytes changed */
13464a49301eSmrg      for (i = 0; i < bufObj->Size - 1; i++) {
13474a49301eSmrg         if (b[i] == (i & 0xff) && b[i+1] == ((i+1) & 0xff)) {
13484a49301eSmrg            unchanged++;
13494a49301eSmrg            if (pos == -1)
13504a49301eSmrg               pos = i;
13514a49301eSmrg         }
13524a49301eSmrg      }
13534a49301eSmrg      if (unchanged) {
1354cdc920a0Smrg         printf("glUnmapBufferARB(%u): %u of %ld unchanged, starting at %d\n",
13554a49301eSmrg                      bufObj->Name, unchanged, bufObj->Size, pos);
13564a49301eSmrg      }
13574a49301eSmrg   }
13584a49301eSmrg#endif
13594a49301eSmrg
1360c1f859d4Smrg   status = ctx->Driver.UnmapBuffer( ctx, target, bufObj );
13614a49301eSmrg   bufObj->AccessFlags = DEFAULT_ACCESS;
13624a49301eSmrg   ASSERT(bufObj->Pointer == NULL);
13634a49301eSmrg   ASSERT(bufObj->Offset == 0);
13644a49301eSmrg   ASSERT(bufObj->Length == 0);
13657117f1b4Smrg
13667117f1b4Smrg   return status;
13677117f1b4Smrg}
13687117f1b4Smrg
13697117f1b4Smrg
13707117f1b4Smrgvoid GLAPIENTRY
13717117f1b4Smrg_mesa_GetBufferParameterivARB(GLenum target, GLenum pname, GLint *params)
13727117f1b4Smrg{
13737117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
13747117f1b4Smrg   struct gl_buffer_object *bufObj;
13757117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
13767117f1b4Smrg
13777117f1b4Smrg   bufObj = get_buffer(ctx, target);
13787117f1b4Smrg   if (!bufObj) {
13797117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "GetBufferParameterivARB(target)" );
13807117f1b4Smrg      return;
13817117f1b4Smrg   }
13824a49301eSmrg   if (!_mesa_is_bufferobj(bufObj)) {
13837117f1b4Smrg      _mesa_error(ctx, GL_INVALID_OPERATION, "GetBufferParameterivARB" );
13847117f1b4Smrg      return;
13857117f1b4Smrg   }
13867117f1b4Smrg
13877117f1b4Smrg   switch (pname) {
1388cdc920a0Smrg   case GL_BUFFER_SIZE_ARB:
1389cdc920a0Smrg      *params = (GLint) bufObj->Size;
1390cdc920a0Smrg      break;
1391cdc920a0Smrg   case GL_BUFFER_USAGE_ARB:
1392cdc920a0Smrg      *params = bufObj->Usage;
1393cdc920a0Smrg      break;
1394cdc920a0Smrg   case GL_BUFFER_ACCESS_ARB:
1395cdc920a0Smrg      *params = simplified_access_mode(bufObj->AccessFlags);
1396cdc920a0Smrg      break;
1397cdc920a0Smrg   case GL_BUFFER_MAPPED_ARB:
1398cdc920a0Smrg      *params = _mesa_bufferobj_mapped(bufObj);
1399cdc920a0Smrg      break;
1400cdc920a0Smrg   default:
1401cdc920a0Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferParameterivARB(pname)");
1402cdc920a0Smrg      return;
1403cdc920a0Smrg   }
1404cdc920a0Smrg}
1405cdc920a0Smrg
1406cdc920a0Smrg
1407cdc920a0Smrg/**
1408cdc920a0Smrg * New in GL 3.2
1409cdc920a0Smrg * This is pretty much a duplicate of GetBufferParameteriv() but the
1410cdc920a0Smrg * GL_BUFFER_SIZE_ARB attribute will be 64-bits on a 64-bit system.
1411cdc920a0Smrg */
1412cdc920a0Smrgvoid GLAPIENTRY
1413cdc920a0Smrg_mesa_GetBufferParameteri64v(GLenum target, GLenum pname, GLint64 *params)
1414cdc920a0Smrg{
1415cdc920a0Smrg   GET_CURRENT_CONTEXT(ctx);
1416cdc920a0Smrg   struct gl_buffer_object *bufObj;
1417cdc920a0Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
1418cdc920a0Smrg
1419cdc920a0Smrg   bufObj = get_buffer(ctx, target);
1420cdc920a0Smrg   if (!bufObj) {
1421cdc920a0Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "GetBufferParameteri64v(target)" );
1422cdc920a0Smrg      return;
1423cdc920a0Smrg   }
1424cdc920a0Smrg   if (!_mesa_is_bufferobj(bufObj)) {
1425cdc920a0Smrg      _mesa_error(ctx, GL_INVALID_OPERATION, "GetBufferParameteri64v" );
1426cdc920a0Smrg      return;
1427cdc920a0Smrg   }
1428cdc920a0Smrg
1429cdc920a0Smrg   switch (pname) {
1430cdc920a0Smrg   case GL_BUFFER_SIZE_ARB:
1431cdc920a0Smrg      *params = bufObj->Size;
1432cdc920a0Smrg      break;
1433cdc920a0Smrg   case GL_BUFFER_USAGE_ARB:
1434cdc920a0Smrg      *params = bufObj->Usage;
1435cdc920a0Smrg      break;
1436cdc920a0Smrg   case GL_BUFFER_ACCESS_ARB:
1437cdc920a0Smrg      *params = simplified_access_mode(bufObj->AccessFlags);
1438cdc920a0Smrg      break;
1439cdc920a0Smrg   case GL_BUFFER_MAPPED_ARB:
1440cdc920a0Smrg      *params = _mesa_bufferobj_mapped(bufObj);
1441cdc920a0Smrg      break;
1442cdc920a0Smrg   default:
1443cdc920a0Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferParameteri64v(pname)");
1444cdc920a0Smrg      return;
14457117f1b4Smrg   }
14467117f1b4Smrg}
14477117f1b4Smrg
14487117f1b4Smrg
14497117f1b4Smrgvoid GLAPIENTRY
14507117f1b4Smrg_mesa_GetBufferPointervARB(GLenum target, GLenum pname, GLvoid **params)
14517117f1b4Smrg{
14527117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
14537117f1b4Smrg   struct gl_buffer_object * bufObj;
14547117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
14557117f1b4Smrg
14567117f1b4Smrg   if (pname != GL_BUFFER_MAP_POINTER_ARB) {
14577117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferPointervARB(pname)");
14587117f1b4Smrg      return;
14597117f1b4Smrg   }
14607117f1b4Smrg
14617117f1b4Smrg   bufObj = get_buffer(ctx, target);
14627117f1b4Smrg   if (!bufObj) {
14637117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferPointervARB(target)" );
14647117f1b4Smrg      return;
14657117f1b4Smrg   }
14664a49301eSmrg   if (!_mesa_is_bufferobj(bufObj)) {
14677117f1b4Smrg      _mesa_error(ctx, GL_INVALID_OPERATION, "glGetBufferPointervARB" );
14687117f1b4Smrg      return;
14697117f1b4Smrg   }
14707117f1b4Smrg
14717117f1b4Smrg   *params = bufObj->Pointer;
14727117f1b4Smrg}
14734a49301eSmrg
14744a49301eSmrg
14754a49301eSmrgvoid GLAPIENTRY
14764a49301eSmrg_mesa_CopyBufferSubData(GLenum readTarget, GLenum writeTarget,
14774a49301eSmrg                        GLintptr readOffset, GLintptr writeOffset,
14784a49301eSmrg                        GLsizeiptr size)
14794a49301eSmrg{
14804a49301eSmrg   GET_CURRENT_CONTEXT(ctx);
14814a49301eSmrg   struct gl_buffer_object *src, *dst;
14824a49301eSmrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
14834a49301eSmrg
14844a49301eSmrg   src = get_buffer(ctx, readTarget);
14854a49301eSmrg   if (!src || !_mesa_is_bufferobj(src)) {
14864a49301eSmrg      _mesa_error(ctx, GL_INVALID_ENUM,
14874a49301eSmrg                  "glCopyBuffserSubData(readTarget = 0x%x)", readTarget);
14884a49301eSmrg      return;
14894a49301eSmrg   }
14904a49301eSmrg
14914a49301eSmrg   dst = get_buffer(ctx, writeTarget);
14924a49301eSmrg   if (!dst || !_mesa_is_bufferobj(dst)) {
14934a49301eSmrg      _mesa_error(ctx, GL_INVALID_ENUM,
14944a49301eSmrg                  "glCopyBuffserSubData(writeTarget = 0x%x)", writeTarget);
14954a49301eSmrg      return;
14964a49301eSmrg   }
14974a49301eSmrg
14984a49301eSmrg   if (_mesa_bufferobj_mapped(src)) {
14994a49301eSmrg      _mesa_error(ctx, GL_INVALID_OPERATION,
15004a49301eSmrg                  "glCopyBuffserSubData(readBuffer is mapped)");
15014a49301eSmrg      return;
15024a49301eSmrg   }
15034a49301eSmrg
15044a49301eSmrg   if (_mesa_bufferobj_mapped(dst)) {
15054a49301eSmrg      _mesa_error(ctx, GL_INVALID_OPERATION,
15064a49301eSmrg                  "glCopyBuffserSubData(writeBuffer is mapped)");
15074a49301eSmrg      return;
15084a49301eSmrg   }
15094a49301eSmrg
15104a49301eSmrg   if (readOffset < 0) {
15114a49301eSmrg      _mesa_error(ctx, GL_INVALID_VALUE,
15124a49301eSmrg                  "glCopyBuffserSubData(readOffset = %d)", readOffset);
15134a49301eSmrg      return;
15144a49301eSmrg   }
15154a49301eSmrg
15164a49301eSmrg   if (writeOffset < 0) {
15174a49301eSmrg      _mesa_error(ctx, GL_INVALID_VALUE,
15184a49301eSmrg                  "glCopyBuffserSubData(writeOffset = %d)", writeOffset);
15194a49301eSmrg      return;
15204a49301eSmrg   }
15214a49301eSmrg
15224a49301eSmrg   if (readOffset + size > src->Size) {
15234a49301eSmrg      _mesa_error(ctx, GL_INVALID_VALUE,
15244a49301eSmrg                  "glCopyBuffserSubData(readOffset + size = %d)",
15254a49301eSmrg                  readOffset, size);
15264a49301eSmrg      return;
15274a49301eSmrg   }
15284a49301eSmrg
15294a49301eSmrg   if (writeOffset + size > dst->Size) {
15304a49301eSmrg      _mesa_error(ctx, GL_INVALID_VALUE,
15314a49301eSmrg                  "glCopyBuffserSubData(writeOffset + size = %d)",
15324a49301eSmrg                  writeOffset, size);
15334a49301eSmrg      return;
15344a49301eSmrg   }
15354a49301eSmrg
15364a49301eSmrg   if (src == dst) {
15374a49301eSmrg      if (readOffset + size <= writeOffset) {
15384a49301eSmrg         /* OK */
15394a49301eSmrg      }
15404a49301eSmrg      else if (writeOffset + size <= readOffset) {
15414a49301eSmrg         /* OK */
15424a49301eSmrg      }
15434a49301eSmrg      else {
15444a49301eSmrg         /* overlapping src/dst is illegal */
15454a49301eSmrg         _mesa_error(ctx, GL_INVALID_VALUE,
15464a49301eSmrg                     "glCopyBuffserSubData(overlapping src/dst)");
15474a49301eSmrg         return;
15484a49301eSmrg      }
15494a49301eSmrg   }
15504a49301eSmrg
15514a49301eSmrg   ctx->Driver.CopyBufferSubData(ctx, src, dst, readOffset, writeOffset, size);
15524a49301eSmrg}
15534a49301eSmrg
15544a49301eSmrg
15554a49301eSmrg/**
15564a49301eSmrg * See GL_ARB_map_buffer_range spec
15574a49301eSmrg */
15584a49301eSmrgvoid * GLAPIENTRY
15594a49301eSmrg_mesa_MapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length,
15604a49301eSmrg                     GLbitfield access)
15614a49301eSmrg{
15624a49301eSmrg   GET_CURRENT_CONTEXT(ctx);
15634a49301eSmrg   struct gl_buffer_object *bufObj;
15644a49301eSmrg   void *map;
15654a49301eSmrg
15664a49301eSmrg   ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, NULL);
15674a49301eSmrg
15684a49301eSmrg   if (!ctx->Extensions.ARB_map_buffer_range) {
15694a49301eSmrg      _mesa_error(ctx, GL_INVALID_OPERATION,
15704a49301eSmrg                  "glMapBufferRange(extension not supported)");
15714a49301eSmrg      return NULL;
15724a49301eSmrg   }
15734a49301eSmrg
15744a49301eSmrg   if (offset < 0) {
15754a49301eSmrg      _mesa_error(ctx, GL_INVALID_VALUE,
15764a49301eSmrg                  "glMapBufferRange(offset = %ld)", offset);
15774a49301eSmrg      return NULL;
15784a49301eSmrg   }
15794a49301eSmrg
15804a49301eSmrg   if (length < 0) {
15814a49301eSmrg      _mesa_error(ctx, GL_INVALID_VALUE,
15824a49301eSmrg                  "glMapBufferRange(length = %ld)", length);
15834a49301eSmrg      return NULL;
15844a49301eSmrg   }
15854a49301eSmrg
15864a49301eSmrg   if ((access & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)) == 0) {
15874a49301eSmrg      _mesa_error(ctx, GL_INVALID_OPERATION,
15884a49301eSmrg                  "glMapBufferRange(access indicates neither read or write)");
15894a49301eSmrg      return NULL;
15904a49301eSmrg   }
15914a49301eSmrg
15924a49301eSmrg   if (access & GL_MAP_READ_BIT) {
15934a49301eSmrg      if ((access & GL_MAP_INVALIDATE_RANGE_BIT) ||
15944a49301eSmrg          (access & GL_MAP_INVALIDATE_BUFFER_BIT) ||
15954a49301eSmrg          (access & GL_MAP_UNSYNCHRONIZED_BIT)) {
15964a49301eSmrg         _mesa_error(ctx, GL_INVALID_OPERATION,
15974a49301eSmrg                     "glMapBufferRange(invalid access flags)");
15984a49301eSmrg         return NULL;
15994a49301eSmrg      }
16004a49301eSmrg   }
16014a49301eSmrg
16024a49301eSmrg   if ((access & GL_MAP_FLUSH_EXPLICIT_BIT) &&
16034a49301eSmrg       ((access & GL_MAP_WRITE_BIT) == 0)) {
16044a49301eSmrg      _mesa_error(ctx, GL_INVALID_OPERATION,
16054a49301eSmrg                  "glMapBufferRange(invalid access flags)");
16064a49301eSmrg      return NULL;
16074a49301eSmrg   }
16084a49301eSmrg
16094a49301eSmrg   bufObj = get_buffer(ctx, target);
16104a49301eSmrg   if (!bufObj || !_mesa_is_bufferobj(bufObj)) {
16114a49301eSmrg      _mesa_error(ctx, GL_INVALID_ENUM,
16124a49301eSmrg                  "glMapBufferRange(target = 0x%x)", target);
16134a49301eSmrg      return NULL;
16144a49301eSmrg   }
16154a49301eSmrg
16164a49301eSmrg   if (offset + length > bufObj->Size) {
16174a49301eSmrg      _mesa_error(ctx, GL_INVALID_VALUE,
16184a49301eSmrg                  "glMapBufferRange(offset + length > size)");
16194a49301eSmrg      return NULL;
16204a49301eSmrg   }
16214a49301eSmrg
16224a49301eSmrg   if (_mesa_bufferobj_mapped(bufObj)) {
16234a49301eSmrg      _mesa_error(ctx, GL_INVALID_OPERATION,
16244a49301eSmrg                  "glMapBufferRange(buffer already mapped)");
16254a49301eSmrg      return NULL;
16264a49301eSmrg   }
16274a49301eSmrg
16284a49301eSmrg   ASSERT(ctx->Driver.MapBufferRange);
16294a49301eSmrg   map = ctx->Driver.MapBufferRange(ctx, target, offset, length,
16304a49301eSmrg                                    access, bufObj);
16314a49301eSmrg   if (!map) {
16324a49301eSmrg      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glMapBufferARB(map failed)");
16334a49301eSmrg   }
16344a49301eSmrg   else {
16354a49301eSmrg      /* The driver callback should have set all these fields.
16364a49301eSmrg       * This is important because other modules (like VBO) might call
16374a49301eSmrg       * the driver function directly.
16384a49301eSmrg       */
16394a49301eSmrg      ASSERT(bufObj->Pointer == map);
16404a49301eSmrg      ASSERT(bufObj->Length == length);
16414a49301eSmrg      ASSERT(bufObj->Offset == offset);
16424a49301eSmrg      ASSERT(bufObj->AccessFlags == access);
16434a49301eSmrg   }
16444a49301eSmrg
16454a49301eSmrg   return map;
16464a49301eSmrg}
16474a49301eSmrg
16484a49301eSmrg
16494a49301eSmrg/**
16504a49301eSmrg * See GL_ARB_map_buffer_range spec
16514a49301eSmrg */
16524a49301eSmrgvoid GLAPIENTRY
16534a49301eSmrg_mesa_FlushMappedBufferRange(GLenum target, GLintptr offset, GLsizeiptr length)
16544a49301eSmrg{
16554a49301eSmrg   GET_CURRENT_CONTEXT(ctx);
16564a49301eSmrg   struct gl_buffer_object *bufObj;
16574a49301eSmrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
16584a49301eSmrg
16594a49301eSmrg   if (!ctx->Extensions.ARB_map_buffer_range) {
16604a49301eSmrg      _mesa_error(ctx, GL_INVALID_OPERATION,
16614a49301eSmrg                  "glMapBufferRange(extension not supported)");
16624a49301eSmrg      return;
16634a49301eSmrg   }
16644a49301eSmrg
16654a49301eSmrg   if (offset < 0) {
16664a49301eSmrg      _mesa_error(ctx, GL_INVALID_VALUE,
16674a49301eSmrg                  "glMapBufferRange(offset = %ld)", offset);
16684a49301eSmrg      return;
16694a49301eSmrg   }
16704a49301eSmrg
16714a49301eSmrg   if (length < 0) {
16724a49301eSmrg      _mesa_error(ctx, GL_INVALID_VALUE,
16734a49301eSmrg                  "glMapBufferRange(length = %ld)", length);
16744a49301eSmrg      return;
16754a49301eSmrg   }
16764a49301eSmrg
16774a49301eSmrg   bufObj = get_buffer(ctx, target);
16784a49301eSmrg   if (!bufObj) {
16794a49301eSmrg      _mesa_error(ctx, GL_INVALID_ENUM,
16804a49301eSmrg                  "glMapBufferRange(target = 0x%x)", target);
16814a49301eSmrg      return;
16824a49301eSmrg   }
16834a49301eSmrg
16844a49301eSmrg   if (!_mesa_is_bufferobj(bufObj)) {
16854a49301eSmrg      _mesa_error(ctx, GL_INVALID_OPERATION,
16864a49301eSmrg                  "glMapBufferRange(current buffer is 0)");
16874a49301eSmrg      return;
16884a49301eSmrg   }
16894a49301eSmrg
16904a49301eSmrg   if (!_mesa_bufferobj_mapped(bufObj)) {
16914a49301eSmrg      /* buffer is not mapped */
16924a49301eSmrg      _mesa_error(ctx, GL_INVALID_OPERATION,
16934a49301eSmrg                  "glMapBufferRange(buffer is not mapped)");
16944a49301eSmrg      return;
16954a49301eSmrg   }
16964a49301eSmrg
16974a49301eSmrg   if ((bufObj->AccessFlags & GL_MAP_FLUSH_EXPLICIT_BIT) == 0) {
16984a49301eSmrg      _mesa_error(ctx, GL_INVALID_OPERATION,
16994a49301eSmrg                  "glMapBufferRange(GL_MAP_FLUSH_EXPLICIT_BIT not set)");
17004a49301eSmrg      return;
17014a49301eSmrg   }
17024a49301eSmrg
17034a49301eSmrg   if (offset + length > bufObj->Length) {
17044a49301eSmrg      _mesa_error(ctx, GL_INVALID_VALUE,
17054a49301eSmrg             "glMapBufferRange(offset %ld + length %ld > mapped length %ld)",
17064a49301eSmrg             offset, length, bufObj->Length);
17074a49301eSmrg      return;
17084a49301eSmrg   }
17094a49301eSmrg
17104a49301eSmrg   ASSERT(bufObj->AccessFlags & GL_MAP_WRITE_BIT);
17114a49301eSmrg
17124a49301eSmrg   if (ctx->Driver.FlushMappedBufferRange)
17134a49301eSmrg      ctx->Driver.FlushMappedBufferRange(ctx, target, offset, length, bufObj);
17144a49301eSmrg}
1715cdc920a0Smrg
1716cdc920a0Smrg
1717cdc920a0Smrg#if FEATURE_APPLE_object_purgeable
1718cdc920a0Smrgstatic GLenum
1719cdc920a0Smrg_mesa_BufferObjectPurgeable(GLcontext *ctx, GLuint name, GLenum option)
1720cdc920a0Smrg{
1721cdc920a0Smrg   struct gl_buffer_object *bufObj;
1722cdc920a0Smrg   GLenum retval;
1723cdc920a0Smrg
1724cdc920a0Smrg   bufObj = _mesa_lookup_bufferobj(ctx, name);
1725cdc920a0Smrg   if (!bufObj) {
1726cdc920a0Smrg      _mesa_error(ctx, GL_INVALID_VALUE,
1727cdc920a0Smrg                  "glObjectPurgeable(name = 0x%x)", name);
1728cdc920a0Smrg      return 0;
1729cdc920a0Smrg   }
1730cdc920a0Smrg   if (!_mesa_is_bufferobj(bufObj)) {
1731cdc920a0Smrg      _mesa_error(ctx, GL_INVALID_OPERATION, "glObjectPurgeable(buffer 0)" );
1732cdc920a0Smrg      return 0;
1733cdc920a0Smrg   }
1734cdc920a0Smrg
1735cdc920a0Smrg   if (bufObj->Purgeable) {
1736cdc920a0Smrg      _mesa_error(ctx, GL_INVALID_OPERATION,
1737cdc920a0Smrg                  "glObjectPurgeable(name = 0x%x) is already purgeable", name);
1738cdc920a0Smrg      return GL_VOLATILE_APPLE;
1739cdc920a0Smrg   }
1740cdc920a0Smrg
1741cdc920a0Smrg   bufObj->Purgeable = GL_TRUE;
1742cdc920a0Smrg
1743cdc920a0Smrg   retval = GL_VOLATILE_APPLE;
1744cdc920a0Smrg   if (ctx->Driver.BufferObjectPurgeable)
1745cdc920a0Smrg      retval = ctx->Driver.BufferObjectPurgeable(ctx, bufObj, option);
1746cdc920a0Smrg
1747cdc920a0Smrg   return retval;
1748cdc920a0Smrg}
1749cdc920a0Smrg
1750cdc920a0Smrg
1751cdc920a0Smrgstatic GLenum
1752cdc920a0Smrg_mesa_RenderObjectPurgeable(GLcontext *ctx, GLuint name, GLenum option)
1753cdc920a0Smrg{
1754cdc920a0Smrg   struct gl_renderbuffer *bufObj;
1755cdc920a0Smrg   GLenum retval;
1756cdc920a0Smrg
1757cdc920a0Smrg   bufObj = _mesa_lookup_renderbuffer(ctx, name);
1758cdc920a0Smrg   if (!bufObj) {
1759cdc920a0Smrg      _mesa_error(ctx, GL_INVALID_VALUE,
1760cdc920a0Smrg                  "glObjectUnpurgeable(name = 0x%x)", name);
1761cdc920a0Smrg      return 0;
1762cdc920a0Smrg   }
1763cdc920a0Smrg
1764cdc920a0Smrg   if (bufObj->Purgeable) {
1765cdc920a0Smrg      _mesa_error(ctx, GL_INVALID_OPERATION,
1766cdc920a0Smrg                  "glObjectPurgeable(name = 0x%x) is already purgeable", name);
1767cdc920a0Smrg      return GL_VOLATILE_APPLE;
1768cdc920a0Smrg   }
1769cdc920a0Smrg
1770cdc920a0Smrg   bufObj->Purgeable = GL_TRUE;
1771cdc920a0Smrg
1772cdc920a0Smrg   retval = GL_VOLATILE_APPLE;
1773cdc920a0Smrg   if (ctx->Driver.RenderObjectPurgeable)
1774cdc920a0Smrg      retval = ctx->Driver.RenderObjectPurgeable(ctx, bufObj, option);
1775cdc920a0Smrg
1776cdc920a0Smrg   return retval;
1777cdc920a0Smrg}
1778cdc920a0Smrg
1779cdc920a0Smrg
1780cdc920a0Smrgstatic GLenum
1781cdc920a0Smrg_mesa_TextureObjectPurgeable(GLcontext *ctx, GLuint name, GLenum option)
1782cdc920a0Smrg{
1783cdc920a0Smrg   struct gl_texture_object *bufObj;
1784cdc920a0Smrg   GLenum retval;
1785cdc920a0Smrg
1786cdc920a0Smrg   bufObj = _mesa_lookup_texture(ctx, name);
1787cdc920a0Smrg   if (!bufObj) {
1788cdc920a0Smrg      _mesa_error(ctx, GL_INVALID_VALUE,
1789cdc920a0Smrg                  "glObjectPurgeable(name = 0x%x)", name);
1790cdc920a0Smrg      return 0;
1791cdc920a0Smrg   }
1792cdc920a0Smrg
1793cdc920a0Smrg   if (bufObj->Purgeable) {
1794cdc920a0Smrg      _mesa_error(ctx, GL_INVALID_OPERATION,
1795cdc920a0Smrg                  "glObjectPurgeable(name = 0x%x) is already purgeable", name);
1796cdc920a0Smrg      return GL_VOLATILE_APPLE;
1797cdc920a0Smrg   }
1798cdc920a0Smrg
1799cdc920a0Smrg   bufObj->Purgeable = GL_TRUE;
1800cdc920a0Smrg
1801cdc920a0Smrg   retval = GL_VOLATILE_APPLE;
1802cdc920a0Smrg   if (ctx->Driver.TextureObjectPurgeable)
1803cdc920a0Smrg      retval = ctx->Driver.TextureObjectPurgeable(ctx, bufObj, option);
1804cdc920a0Smrg
1805cdc920a0Smrg   return retval;
1806cdc920a0Smrg}
1807cdc920a0Smrg
1808cdc920a0Smrg
1809cdc920a0SmrgGLenum GLAPIENTRY
1810cdc920a0Smrg_mesa_ObjectPurgeableAPPLE(GLenum objectType, GLuint name, GLenum option)
1811cdc920a0Smrg{
1812cdc920a0Smrg   GLenum retval;
1813cdc920a0Smrg
1814cdc920a0Smrg   GET_CURRENT_CONTEXT(ctx);
1815cdc920a0Smrg   ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0);
1816cdc920a0Smrg
1817cdc920a0Smrg   if (name == 0) {
1818cdc920a0Smrg      _mesa_error(ctx, GL_INVALID_VALUE,
1819cdc920a0Smrg                  "glObjectPurgeable(name = 0x%x)", name);
1820cdc920a0Smrg      return 0;
1821cdc920a0Smrg   }
1822cdc920a0Smrg
1823cdc920a0Smrg   switch (option) {
1824cdc920a0Smrg   case GL_VOLATILE_APPLE:
1825cdc920a0Smrg   case GL_RELEASED_APPLE:
1826cdc920a0Smrg      /* legal */
1827cdc920a0Smrg      break;
1828cdc920a0Smrg   default:
1829cdc920a0Smrg      _mesa_error(ctx, GL_INVALID_ENUM,
1830cdc920a0Smrg                  "glObjectPurgeable(name = 0x%x) invalid option: %d",
1831cdc920a0Smrg                  name, option);
1832cdc920a0Smrg      return 0;
1833cdc920a0Smrg   }
1834cdc920a0Smrg
1835cdc920a0Smrg   switch (objectType) {
1836cdc920a0Smrg   case GL_TEXTURE:
1837cdc920a0Smrg      retval = _mesa_TextureObjectPurgeable (ctx, name, option);
1838cdc920a0Smrg      break;
1839cdc920a0Smrg   case GL_RENDERBUFFER_EXT:
1840cdc920a0Smrg      retval = _mesa_RenderObjectPurgeable (ctx, name, option);
1841cdc920a0Smrg      break;
1842cdc920a0Smrg   case GL_BUFFER_OBJECT_APPLE:
1843cdc920a0Smrg      retval = _mesa_BufferObjectPurgeable (ctx, name, option);
1844cdc920a0Smrg      break;
1845cdc920a0Smrg   default:
1846cdc920a0Smrg      _mesa_error(ctx, GL_INVALID_ENUM,
1847cdc920a0Smrg                  "glObjectPurgeable(name = 0x%x) invalid type: %d",
1848cdc920a0Smrg                  name, objectType);
1849cdc920a0Smrg      return 0;
1850cdc920a0Smrg   }
1851cdc920a0Smrg
1852cdc920a0Smrg   /* In strict conformance to the spec, we must only return VOLATILE when
1853cdc920a0Smrg    * when passed the VOLATILE option. Madness.
1854cdc920a0Smrg    *
1855cdc920a0Smrg    * XXX First fix the spec, then fix me.
1856cdc920a0Smrg    */
1857cdc920a0Smrg   return option == GL_VOLATILE_APPLE ? GL_VOLATILE_APPLE : retval;
1858cdc920a0Smrg}
1859cdc920a0Smrg
1860cdc920a0Smrg
1861cdc920a0Smrgstatic GLenum
1862cdc920a0Smrg_mesa_BufferObjectUnpurgeable(GLcontext *ctx, GLuint name, GLenum option)
1863cdc920a0Smrg{
1864cdc920a0Smrg   struct gl_buffer_object *bufObj;
1865cdc920a0Smrg   GLenum retval;
1866cdc920a0Smrg
1867cdc920a0Smrg   bufObj = _mesa_lookup_bufferobj(ctx, name);
1868cdc920a0Smrg   if (!bufObj) {
1869cdc920a0Smrg      _mesa_error(ctx, GL_INVALID_VALUE,
1870cdc920a0Smrg                  "glObjectUnpurgeable(name = 0x%x)", name);
1871cdc920a0Smrg      return 0;
1872cdc920a0Smrg   }
1873cdc920a0Smrg
1874cdc920a0Smrg   if (! bufObj->Purgeable) {
1875cdc920a0Smrg      _mesa_error(ctx, GL_INVALID_OPERATION,
1876cdc920a0Smrg                  "glObjectUnpurgeable(name = 0x%x) object is "
1877cdc920a0Smrg                  " already \"unpurged\"", name);
1878cdc920a0Smrg      return 0;
1879cdc920a0Smrg   }
1880cdc920a0Smrg
1881cdc920a0Smrg   bufObj->Purgeable = GL_FALSE;
1882cdc920a0Smrg
1883cdc920a0Smrg   retval = GL_RETAINED_APPLE;
1884cdc920a0Smrg   if (ctx->Driver.BufferObjectUnpurgeable)
1885cdc920a0Smrg      retval = ctx->Driver.BufferObjectUnpurgeable(ctx, bufObj, option);
1886cdc920a0Smrg
1887cdc920a0Smrg   return retval;
1888cdc920a0Smrg}
1889cdc920a0Smrg
1890cdc920a0Smrg
1891cdc920a0Smrgstatic GLenum
1892cdc920a0Smrg_mesa_RenderObjectUnpurgeable(GLcontext *ctx, GLuint name, GLenum option)
1893cdc920a0Smrg{
1894cdc920a0Smrg   struct gl_renderbuffer *bufObj;
1895cdc920a0Smrg   GLenum retval;
1896cdc920a0Smrg
1897cdc920a0Smrg   bufObj = _mesa_lookup_renderbuffer(ctx, name);
1898cdc920a0Smrg   if (!bufObj) {
1899cdc920a0Smrg      _mesa_error(ctx, GL_INVALID_VALUE,
1900cdc920a0Smrg                  "glObjectUnpurgeable(name = 0x%x)", name);
1901cdc920a0Smrg      return 0;
1902cdc920a0Smrg   }
1903cdc920a0Smrg
1904cdc920a0Smrg   if (! bufObj->Purgeable) {
1905cdc920a0Smrg      _mesa_error(ctx, GL_INVALID_OPERATION,
1906cdc920a0Smrg                  "glObjectUnpurgeable(name = 0x%x) object is "
1907cdc920a0Smrg                  " already \"unpurged\"", name);
1908cdc920a0Smrg      return 0;
1909cdc920a0Smrg   }
1910cdc920a0Smrg
1911cdc920a0Smrg   bufObj->Purgeable = GL_FALSE;
1912cdc920a0Smrg
1913cdc920a0Smrg   retval = GL_RETAINED_APPLE;
1914cdc920a0Smrg   if (ctx->Driver.RenderObjectUnpurgeable)
1915cdc920a0Smrg      retval = ctx->Driver.RenderObjectUnpurgeable(ctx, bufObj, option);
1916cdc920a0Smrg
1917cdc920a0Smrg   return option;
1918cdc920a0Smrg}
1919cdc920a0Smrg
1920cdc920a0Smrg
1921cdc920a0Smrgstatic GLenum
1922cdc920a0Smrg_mesa_TextureObjectUnpurgeable(GLcontext *ctx, GLuint name, GLenum option)
1923cdc920a0Smrg{
1924cdc920a0Smrg   struct gl_texture_object *bufObj;
1925cdc920a0Smrg   GLenum retval;
1926cdc920a0Smrg
1927cdc920a0Smrg   bufObj = _mesa_lookup_texture(ctx, name);
1928cdc920a0Smrg   if (!bufObj) {
1929cdc920a0Smrg      _mesa_error(ctx, GL_INVALID_VALUE,
1930cdc920a0Smrg                  "glObjectUnpurgeable(name = 0x%x)", name);
1931cdc920a0Smrg      return 0;
1932cdc920a0Smrg   }
1933cdc920a0Smrg
1934cdc920a0Smrg   if (! bufObj->Purgeable) {
1935cdc920a0Smrg      _mesa_error(ctx, GL_INVALID_OPERATION,
1936cdc920a0Smrg                  "glObjectUnpurgeable(name = 0x%x) object is"
1937cdc920a0Smrg                  " already \"unpurged\"", name);
1938cdc920a0Smrg      return 0;
1939cdc920a0Smrg   }
1940cdc920a0Smrg
1941cdc920a0Smrg   bufObj->Purgeable = GL_FALSE;
1942cdc920a0Smrg
1943cdc920a0Smrg   retval = GL_RETAINED_APPLE;
1944cdc920a0Smrg   if (ctx->Driver.TextureObjectUnpurgeable)
1945cdc920a0Smrg      retval = ctx->Driver.TextureObjectUnpurgeable(ctx, bufObj, option);
1946cdc920a0Smrg
1947cdc920a0Smrg   return retval;
1948cdc920a0Smrg}
1949cdc920a0Smrg
1950cdc920a0Smrg
1951cdc920a0SmrgGLenum GLAPIENTRY
1952cdc920a0Smrg_mesa_ObjectUnpurgeableAPPLE(GLenum objectType, GLuint name, GLenum option)
1953cdc920a0Smrg{
1954cdc920a0Smrg   GET_CURRENT_CONTEXT(ctx);
1955cdc920a0Smrg   ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0);
1956cdc920a0Smrg
1957cdc920a0Smrg   if (name == 0) {
1958cdc920a0Smrg      _mesa_error(ctx, GL_INVALID_VALUE,
1959cdc920a0Smrg                  "glObjectUnpurgeable(name = 0x%x)", name);
1960cdc920a0Smrg      return 0;
1961cdc920a0Smrg   }
1962cdc920a0Smrg
1963cdc920a0Smrg   switch (option) {
1964cdc920a0Smrg   case GL_RETAINED_APPLE:
1965cdc920a0Smrg   case GL_UNDEFINED_APPLE:
1966cdc920a0Smrg      /* legal */
1967cdc920a0Smrg      break;
1968cdc920a0Smrg   default:
1969cdc920a0Smrg      _mesa_error(ctx, GL_INVALID_ENUM,
1970cdc920a0Smrg                  "glObjectUnpurgeable(name = 0x%x) invalid option: %d",
1971cdc920a0Smrg                  name, option);
1972cdc920a0Smrg      return 0;
1973cdc920a0Smrg   }
1974cdc920a0Smrg
1975cdc920a0Smrg   switch (objectType) {
1976cdc920a0Smrg   case GL_BUFFER_OBJECT_APPLE:
1977cdc920a0Smrg      return _mesa_BufferObjectUnpurgeable(ctx, name, option);
1978cdc920a0Smrg   case GL_TEXTURE:
1979cdc920a0Smrg      return _mesa_TextureObjectUnpurgeable(ctx, name, option);
1980cdc920a0Smrg   case GL_RENDERBUFFER_EXT:
1981cdc920a0Smrg      return _mesa_RenderObjectUnpurgeable(ctx, name, option);
1982cdc920a0Smrg   default:
1983cdc920a0Smrg      _mesa_error(ctx, GL_INVALID_ENUM,
1984cdc920a0Smrg                  "glObjectUnpurgeable(name = 0x%x) invalid type: %d",
1985cdc920a0Smrg                  name, objectType);
1986cdc920a0Smrg      return 0;
1987cdc920a0Smrg   }
1988cdc920a0Smrg}
1989cdc920a0Smrg
1990cdc920a0Smrg
1991cdc920a0Smrgstatic void
1992cdc920a0Smrg_mesa_GetBufferObjectParameterivAPPLE(GLcontext *ctx, GLuint name,
1993cdc920a0Smrg                                      GLenum pname, GLint* params)
1994cdc920a0Smrg{
1995cdc920a0Smrg   struct gl_buffer_object *bufObj;
1996cdc920a0Smrg
1997cdc920a0Smrg   bufObj = _mesa_lookup_bufferobj(ctx, name);
1998cdc920a0Smrg   if (!bufObj) {
1999cdc920a0Smrg      _mesa_error(ctx, GL_INVALID_VALUE,
2000cdc920a0Smrg                  "glGetObjectParameteriv(name = 0x%x) invalid object", name);
2001cdc920a0Smrg      return;
2002cdc920a0Smrg   }
2003cdc920a0Smrg
2004cdc920a0Smrg   switch (pname) {
2005cdc920a0Smrg   case GL_PURGEABLE_APPLE:
2006cdc920a0Smrg      *params = bufObj->Purgeable;
2007cdc920a0Smrg      break;
2008cdc920a0Smrg   default:
2009cdc920a0Smrg      _mesa_error(ctx, GL_INVALID_ENUM,
2010cdc920a0Smrg                  "glGetObjectParameteriv(name = 0x%x) invalid enum: %d",
2011cdc920a0Smrg                  name, pname);
2012cdc920a0Smrg      break;
2013cdc920a0Smrg   }
2014cdc920a0Smrg}
2015cdc920a0Smrg
2016cdc920a0Smrg
2017cdc920a0Smrgstatic void
2018cdc920a0Smrg_mesa_GetRenderObjectParameterivAPPLE(GLcontext *ctx, GLuint name,
2019cdc920a0Smrg                                      GLenum pname, GLint* params)
2020cdc920a0Smrg{
2021cdc920a0Smrg   struct gl_renderbuffer *bufObj;
2022cdc920a0Smrg
2023cdc920a0Smrg   bufObj = _mesa_lookup_renderbuffer(ctx, name);
2024cdc920a0Smrg   if (!bufObj) {
2025cdc920a0Smrg      _mesa_error(ctx, GL_INVALID_VALUE,
2026cdc920a0Smrg                  "glObjectUnpurgeable(name = 0x%x)", name);
2027cdc920a0Smrg      return;
2028cdc920a0Smrg   }
2029cdc920a0Smrg
2030cdc920a0Smrg   switch (pname) {
2031cdc920a0Smrg   case GL_PURGEABLE_APPLE:
2032cdc920a0Smrg      *params = bufObj->Purgeable;
2033cdc920a0Smrg      break;
2034cdc920a0Smrg   default:
2035cdc920a0Smrg      _mesa_error(ctx, GL_INVALID_ENUM,
2036cdc920a0Smrg                  "glGetObjectParameteriv(name = 0x%x) invalid enum: %d",
2037cdc920a0Smrg                  name, pname);
2038cdc920a0Smrg      break;
2039cdc920a0Smrg   }
2040cdc920a0Smrg}
2041cdc920a0Smrg
2042cdc920a0Smrg
2043cdc920a0Smrgstatic void
2044cdc920a0Smrg_mesa_GetTextureObjectParameterivAPPLE(GLcontext *ctx, GLuint name,
2045cdc920a0Smrg                                       GLenum pname, GLint* params)
2046cdc920a0Smrg{
2047cdc920a0Smrg   struct gl_texture_object *bufObj;
2048cdc920a0Smrg
2049cdc920a0Smrg   bufObj = _mesa_lookup_texture(ctx, name);
2050cdc920a0Smrg   if (!bufObj) {
2051cdc920a0Smrg      _mesa_error(ctx, GL_INVALID_VALUE,
2052cdc920a0Smrg                  "glObjectUnpurgeable(name = 0x%x)", name);
2053cdc920a0Smrg      return;
2054cdc920a0Smrg   }
2055cdc920a0Smrg
2056cdc920a0Smrg   switch (pname) {
2057cdc920a0Smrg   case GL_PURGEABLE_APPLE:
2058cdc920a0Smrg      *params = bufObj->Purgeable;
2059cdc920a0Smrg      break;
2060cdc920a0Smrg   default:
2061cdc920a0Smrg      _mesa_error(ctx, GL_INVALID_ENUM,
2062cdc920a0Smrg                  "glGetObjectParameteriv(name = 0x%x) invalid enum: %d",
2063cdc920a0Smrg                  name, pname);
2064cdc920a0Smrg      break;
2065cdc920a0Smrg   }
2066cdc920a0Smrg}
2067cdc920a0Smrg
2068cdc920a0Smrg
2069cdc920a0Smrgvoid GLAPIENTRY
2070cdc920a0Smrg_mesa_GetObjectParameterivAPPLE(GLenum objectType, GLuint name, GLenum pname,
2071cdc920a0Smrg                                GLint* params)
2072cdc920a0Smrg{
2073cdc920a0Smrg   GET_CURRENT_CONTEXT(ctx);
2074cdc920a0Smrg
2075cdc920a0Smrg   if (name == 0) {
2076cdc920a0Smrg      _mesa_error(ctx, GL_INVALID_VALUE,
2077cdc920a0Smrg                  "glGetObjectParameteriv(name = 0x%x)", name);
2078cdc920a0Smrg      return;
2079cdc920a0Smrg   }
2080cdc920a0Smrg
2081cdc920a0Smrg   switch (objectType) {
2082cdc920a0Smrg   case GL_TEXTURE:
2083cdc920a0Smrg      _mesa_GetTextureObjectParameterivAPPLE (ctx, name, pname, params);
2084cdc920a0Smrg      break;
2085cdc920a0Smrg   case GL_BUFFER_OBJECT_APPLE:
2086cdc920a0Smrg      _mesa_GetBufferObjectParameterivAPPLE (ctx, name, pname, params);
2087cdc920a0Smrg      break;
2088cdc920a0Smrg   case GL_RENDERBUFFER_EXT:
2089cdc920a0Smrg      _mesa_GetRenderObjectParameterivAPPLE (ctx, name, pname, params);
2090cdc920a0Smrg      break;
2091cdc920a0Smrg   default:
2092cdc920a0Smrg      _mesa_error(ctx, GL_INVALID_ENUM,
2093cdc920a0Smrg                  "glGetObjectParameteriv(name = 0x%x) invalid type: %d",
2094cdc920a0Smrg                  name, objectType);
2095cdc920a0Smrg   }
2096cdc920a0Smrg}
2097cdc920a0Smrg
2098cdc920a0Smrg#endif /* FEATURE_APPLE_object_purgeable */
2099