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