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