2 * Mesa 3-D graphics library
5 * Copyright (C) 1999-2008 Brian Paul All Rights Reserved.
6 * Copyright (C) 2009 VMware, Inc. All Rights Reserved.
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the "Software"),
10 * to deal in the Software without restriction, including without limitation
11 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 * and/or sell copies of the Software, and to permit persons to whom the
13 * Software is furnished to do so, subject to the following conditions:
15 * The above copyright notice and this permission notice shall be included
16 * in all copies or substantial portions of the Software.
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
22 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 * \brief Functions for the GL_ARB_vertex/pixel_buffer_object extensions.
30 * \author Brian Paul, Ian Romanick
39 #include "bufferobj.h"
42 #ifdef FEATURE_OES_mapbuffer
43 #define DEFAULT_ACCESS GL_WRITE_ONLY;
45 #define DEFAULT_ACCESS GL_READ_WRITE;
50 * Get the buffer object bound to the specified target in a GL context.
52 * \param ctx GL context
53 * \param target Buffer object target to be retrieved. Currently this must
54 * be either \c GL_ARRAY_BUFFER or \c GL_ELEMENT_ARRAY_BUFFER.
55 * \return A pointer to the buffer object bound to \c target in the
56 * specified context or \c NULL if \c target is invalid.
58 static INLINE
struct gl_buffer_object
*
59 get_buffer(GLcontext
*ctx
, GLenum target
)
61 struct gl_buffer_object
* bufObj
= NULL
;
64 case GL_ARRAY_BUFFER_ARB
:
65 bufObj
= ctx
->Array
.ArrayBufferObj
;
67 case GL_ELEMENT_ARRAY_BUFFER_ARB
:
68 bufObj
= ctx
->Array
.ElementArrayBufferObj
;
70 case GL_PIXEL_PACK_BUFFER_EXT
:
71 bufObj
= ctx
->Pack
.BufferObj
;
73 case GL_PIXEL_UNPACK_BUFFER_EXT
:
74 bufObj
= ctx
->Unpack
.BufferObj
;
76 case GL_COPY_READ_BUFFER
:
77 if (ctx
->Extensions
.ARB_copy_buffer
) {
78 bufObj
= ctx
->CopyReadBuffer
;
81 case GL_COPY_WRITE_BUFFER
:
82 if (ctx
->Extensions
.ARB_copy_buffer
) {
83 bufObj
= ctx
->CopyWriteBuffer
;
87 /* error must be recorded by caller */
91 /* bufObj should point to NullBufferObj or a user-created buffer object */
99 * Tests the subdata range parameters and sets the GL error code for
100 * \c glBufferSubDataARB and \c glGetBufferSubDataARB.
102 * \param ctx GL context.
103 * \param target Buffer object target on which to operate.
104 * \param offset Offset of the first byte of the subdata range.
105 * \param size Size, in bytes, of the subdata range.
106 * \param caller Name of calling function for recording errors.
107 * \return A pointer to the buffer object bound to \c target in the
108 * specified context or \c NULL if any of the parameter or state
109 * conditions for \c glBufferSubDataARB or \c glGetBufferSubDataARB
112 * \sa glBufferSubDataARB, glGetBufferSubDataARB
114 static struct gl_buffer_object
*
115 buffer_object_subdata_range_good( GLcontext
* ctx
, GLenum target
,
116 GLintptrARB offset
, GLsizeiptrARB size
,
119 struct gl_buffer_object
*bufObj
;
122 _mesa_error(ctx
, GL_INVALID_VALUE
, "%s(size < 0)", caller
);
127 _mesa_error(ctx
, GL_INVALID_VALUE
, "%s(offset < 0)", caller
);
131 bufObj
= get_buffer(ctx
, target
);
133 _mesa_error(ctx
, GL_INVALID_ENUM
, "%s(target)", caller
);
136 if (bufObj
->Name
== 0) {
137 _mesa_error(ctx
, GL_INVALID_OPERATION
, "%s", caller
);
140 if (offset
+ size
> bufObj
->Size
) {
141 _mesa_error(ctx
, GL_INVALID_VALUE
,
142 "%s(size + offset > buffer size)", caller
);
145 if (bufObj
->Pointer
) {
146 /* Buffer is currently mapped */
147 _mesa_error(ctx
, GL_INVALID_OPERATION
, "%s", caller
);
156 * Allocate and initialize a new buffer object.
158 * Default callback for the \c dd_function_table::NewBufferObject() hook.
160 struct gl_buffer_object
*
161 _mesa_new_buffer_object( GLcontext
*ctx
, GLuint name
, GLenum target
)
163 struct gl_buffer_object
*obj
;
167 obj
= MALLOC_STRUCT(gl_buffer_object
);
168 _mesa_initialize_buffer_object(obj
, name
, target
);
174 * Delete a buffer object.
176 * Default callback for the \c dd_function_table::DeleteBuffer() hook.
179 _mesa_delete_buffer_object( GLcontext
*ctx
, struct gl_buffer_object
*bufObj
)
184 _mesa_free(bufObj
->Data
);
186 /* assign strange values here to help w/ debugging */
187 bufObj
->RefCount
= -1000;
196 * Set ptr to bufObj w/ reference counting.
199 _mesa_reference_buffer_object(GLcontext
*ctx
,
200 struct gl_buffer_object
**ptr
,
201 struct gl_buffer_object
*bufObj
)
207 /* Unreference the old buffer */
208 GLboolean deleteFlag
= GL_FALSE
;
209 struct gl_buffer_object
*oldObj
= *ptr
;
211 /*_glthread_LOCK_MUTEX(oldObj->Mutex);*/
212 ASSERT(oldObj
->RefCount
> 0);
215 printf("BufferObj %p %d DECR to %d\n",
216 (void *) oldObj
, oldObj
->Name
, oldObj
->RefCount
);
218 deleteFlag
= (oldObj
->RefCount
== 0);
219 /*_glthread_UNLOCK_MUTEX(oldObj->Mutex);*/
223 /* some sanity checking: don't delete a buffer still in use */
225 /* unfortunately, these tests are invalid during context tear-down */
226 ASSERT(ctx
->Array
.ArrayBufferObj
!= bufObj
);
227 ASSERT(ctx
->Array
.ElementArrayBufferObj
!= bufObj
);
228 ASSERT(ctx
->Array
.ArrayObj
->Vertex
.BufferObj
!= bufObj
);
231 ASSERT(ctx
->Driver
.DeleteBuffer
);
232 ctx
->Driver
.DeleteBuffer(ctx
, oldObj
);
240 /* reference new buffer */
241 /*_glthread_LOCK_MUTEX(tex->Mutex);*/
242 if (bufObj
->RefCount
== 0) {
243 /* this buffer's being deleted (look just above) */
244 /* Not sure this can every really happen. Warn if it does. */
245 _mesa_problem(NULL
, "referencing deleted buffer object");
251 printf("BufferObj %p %d INCR to %d\n",
252 (void *) bufObj
, bufObj
->Name
, bufObj
->RefCount
);
256 /*_glthread_UNLOCK_MUTEX(tex->Mutex);*/
262 * Initialize a buffer object to default values.
265 _mesa_initialize_buffer_object( struct gl_buffer_object
*obj
,
266 GLuint name
, GLenum target
)
270 _mesa_bzero(obj
, sizeof(struct gl_buffer_object
));
273 obj
->Usage
= GL_STATIC_DRAW_ARB
;
274 obj
->Access
= DEFAULT_ACCESS
;
279 * Allocate space for and store data in a buffer object. Any data that was
280 * previously stored in the buffer object is lost. If \c data is \c NULL,
281 * memory will be allocated, but no copy will occur.
283 * This is the default callback for \c dd_function_table::BufferData()
284 * Note that all GL error checking will have been done already.
286 * \param ctx GL context.
287 * \param target Buffer object target on which to operate.
288 * \param size Size, in bytes, of the new data store.
289 * \param data Pointer to the data to store in the buffer object. This
290 * pointer may be \c NULL.
291 * \param usage Hints about how the data will be used.
292 * \param bufObj Object to be used.
294 * \sa glBufferDataARB, dd_function_table::BufferData.
297 _mesa_buffer_data( GLcontext
*ctx
, GLenum target
, GLsizeiptrARB size
,
298 const GLvoid
* data
, GLenum usage
,
299 struct gl_buffer_object
* bufObj
)
303 (void) ctx
; (void) target
;
305 new_data
= _mesa_realloc( bufObj
->Data
, bufObj
->Size
, size
);
307 bufObj
->Data
= (GLubyte
*) new_data
;
309 bufObj
->Usage
= usage
;
312 _mesa_memcpy( bufObj
->Data
, data
, size
);
319 * Replace data in a subrange of buffer object. If the data range
320 * specified by \c size + \c offset extends beyond the end of the buffer or
321 * if \c data is \c NULL, no copy is performed.
323 * This is the default callback for \c dd_function_table::BufferSubData()
324 * Note that all GL error checking will have been done already.
326 * \param ctx GL context.
327 * \param target Buffer object target on which to operate.
328 * \param offset Offset of the first byte to be modified.
329 * \param size Size, in bytes, of the data range.
330 * \param data Pointer to the data to store in the buffer object.
331 * \param bufObj Object to be used.
333 * \sa glBufferSubDataARB, dd_function_table::BufferSubData.
336 _mesa_buffer_subdata( GLcontext
*ctx
, GLenum target
, GLintptrARB offset
,
337 GLsizeiptrARB size
, const GLvoid
* data
,
338 struct gl_buffer_object
* bufObj
)
340 (void) ctx
; (void) target
;
342 /* this should have been caught in _mesa_BufferSubData() */
343 ASSERT(size
+ offset
<= bufObj
->Size
);
346 _mesa_memcpy( (GLubyte
*) bufObj
->Data
+ offset
, data
, size
);
352 * Retrieve data from a subrange of buffer object. If the data range
353 * specified by \c size + \c offset extends beyond the end of the buffer or
354 * if \c data is \c NULL, no copy is performed.
356 * This is the default callback for \c dd_function_table::GetBufferSubData()
357 * Note that all GL error checking will have been done already.
359 * \param ctx GL context.
360 * \param target Buffer object target on which to operate.
361 * \param offset Offset of the first byte to be fetched.
362 * \param size Size, in bytes, of the data range.
363 * \param data Destination for data
364 * \param bufObj Object to be used.
366 * \sa glBufferGetSubDataARB, dd_function_table::GetBufferSubData.
369 _mesa_buffer_get_subdata( GLcontext
*ctx
, GLenum target
, GLintptrARB offset
,
370 GLsizeiptrARB size
, GLvoid
* data
,
371 struct gl_buffer_object
* bufObj
)
373 (void) ctx
; (void) target
;
375 if (bufObj
->Data
&& ((GLsizeiptrARB
) (size
+ offset
) <= bufObj
->Size
)) {
376 _mesa_memcpy( data
, (GLubyte
*) bufObj
->Data
+ offset
, size
);
382 * Default callback for \c dd_function_tabel::MapBuffer().
384 * The function parameters will have been already tested for errors.
386 * \param ctx GL context.
387 * \param target Buffer object target on which to operate.
388 * \param access Information about how the buffer will be accessed.
389 * \param bufObj Object to be mapped.
390 * \return A pointer to the object's internal data store that can be accessed
393 * \sa glMapBufferARB, dd_function_table::MapBuffer
396 _mesa_buffer_map( GLcontext
*ctx
, GLenum target
, GLenum access
,
397 struct gl_buffer_object
*bufObj
)
402 /* Just return a direct pointer to the data */
403 if (bufObj
->Pointer
) {
404 /* already mapped! */
407 bufObj
->Pointer
= bufObj
->Data
;
408 return bufObj
->Pointer
;
413 * Default callback for \c dd_function_table::MapBuffer().
415 * The input parameters will have been already tested for errors.
417 * \sa glUnmapBufferARB, dd_function_table::UnmapBuffer
420 _mesa_buffer_unmap( GLcontext
*ctx
, GLenum target
,
421 struct gl_buffer_object
*bufObj
)
425 /* XXX we might assert here that bufObj->Pointer is non-null */
426 bufObj
->Pointer
= NULL
;
432 * Default fallback for \c dd_function_table::CopyBufferSubData().
433 * Called via glCopyBuffserSubData().
436 _mesa_copy_buffer_subdata(GLcontext
*ctx
,
437 struct gl_buffer_object
*src
,
438 struct gl_buffer_object
*dst
,
439 GLintptr readOffset
, GLintptr writeOffset
,
442 GLubyte
*srcPtr
, *dstPtr
;
444 /* buffer should not already be mapped */
445 assert(!src
->Pointer
);
446 assert(!dst
->Pointer
);
448 srcPtr
= (GLubyte
*) ctx
->Driver
.MapBuffer(ctx
, GL_COPY_READ_BUFFER
,
450 dstPtr
= (GLubyte
*) ctx
->Driver
.MapBuffer(ctx
, GL_COPY_WRITE_BUFFER
,
453 if (srcPtr
&& dstPtr
)
454 _mesa_memcpy(dstPtr
+ writeOffset
, srcPtr
+ readOffset
, size
);
456 ctx
->Driver
.UnmapBuffer(ctx
, GL_COPY_READ_BUFFER
, src
);
457 ctx
->Driver
.UnmapBuffer(ctx
, GL_COPY_WRITE_BUFFER
, dst
);
463 * Initialize the state associated with buffer objects
466 _mesa_init_buffer_objects( GLcontext
*ctx
)
468 ctx
->Array
.ArrayBufferObj
= ctx
->Shared
->NullBufferObj
;
469 ctx
->Array
.ElementArrayBufferObj
= ctx
->Shared
->NullBufferObj
;
471 ctx
->CopyReadBuffer
= ctx
->Shared
->NullBufferObj
;
472 ctx
->CopyWriteBuffer
= ctx
->Shared
->NullBufferObj
;
477 * Bind the specified target to buffer for the specified context.
480 bind_buffer_object(GLcontext
*ctx
, GLenum target
, GLuint buffer
)
482 struct gl_buffer_object
*oldBufObj
;
483 struct gl_buffer_object
*newBufObj
= NULL
;
484 struct gl_buffer_object
**bindTarget
= NULL
;
487 case GL_ARRAY_BUFFER_ARB
:
488 bindTarget
= &ctx
->Array
.ArrayBufferObj
;
490 case GL_ELEMENT_ARRAY_BUFFER_ARB
:
491 bindTarget
= &ctx
->Array
.ElementArrayBufferObj
;
493 case GL_PIXEL_PACK_BUFFER_EXT
:
494 bindTarget
= &ctx
->Pack
.BufferObj
;
496 case GL_PIXEL_UNPACK_BUFFER_EXT
:
497 bindTarget
= &ctx
->Unpack
.BufferObj
;
499 case GL_COPY_READ_BUFFER
:
500 if (ctx
->Extensions
.ARB_copy_buffer
) {
501 bindTarget
= &ctx
->CopyReadBuffer
;
504 case GL_COPY_WRITE_BUFFER
:
505 if (ctx
->Extensions
.ARB_copy_buffer
) {
506 bindTarget
= &ctx
->CopyWriteBuffer
;
510 ; /* no-op / we'll hit the follow error test next */
514 _mesa_error(ctx
, GL_INVALID_ENUM
, "glBindBufferARB(target 0x%x)");
518 /* Get pointer to old buffer object (to be unbound) */
519 oldBufObj
= get_buffer(ctx
, target
);
520 if (oldBufObj
&& oldBufObj
->Name
== buffer
)
521 return; /* rebinding the same buffer object- no change */
524 * Get pointer to new buffer object (newBufObj)
527 /* The spec says there's not a buffer object named 0, but we use
528 * one internally because it simplifies things.
530 newBufObj
= ctx
->Shared
->NullBufferObj
;
533 /* non-default buffer object */
534 newBufObj
= _mesa_lookup_bufferobj(ctx
, buffer
);
536 /* if this is a new buffer object id, allocate a buffer object now */
537 ASSERT(ctx
->Driver
.NewBufferObject
);
538 newBufObj
= ctx
->Driver
.NewBufferObject(ctx
, buffer
, target
);
540 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glBindBufferARB");
543 _mesa_HashInsert(ctx
->Shared
->BufferObjects
, buffer
, newBufObj
);
547 /* bind new buffer */
548 _mesa_reference_buffer_object(ctx
, bindTarget
, newBufObj
);
550 /* Pass BindBuffer call to device driver */
551 if (ctx
->Driver
.BindBuffer
)
552 ctx
->Driver
.BindBuffer( ctx
, target
, newBufObj
);
557 * Update the default buffer objects in the given context to reference those
558 * specified in the shared state and release those referencing the old
562 _mesa_update_default_objects_buffer_objects(GLcontext
*ctx
)
564 /* Bind the NullBufferObj to remove references to those
565 * in the shared context hash table.
567 bind_buffer_object( ctx
, GL_ARRAY_BUFFER_ARB
, 0);
568 bind_buffer_object( ctx
, GL_ELEMENT_ARRAY_BUFFER_ARB
, 0);
569 bind_buffer_object( ctx
, GL_PIXEL_PACK_BUFFER_ARB
, 0);
570 bind_buffer_object( ctx
, GL_PIXEL_UNPACK_BUFFER_ARB
, 0);
575 * When we're about to read pixel data out of a PBO (via glDrawPixels,
576 * glTexImage, etc) or write data into a PBO (via glReadPixels,
577 * glGetTexImage, etc) we call this function to check that we're not
578 * going to read out of bounds.
580 * XXX This would also be a convenient time to check that the PBO isn't
581 * currently mapped. Whoever calls this function should check for that.
582 * Remember, we can't use a PBO when it's mapped!
584 * \param width width of image to read/write
585 * \param height height of image to read/write
586 * \param depth depth of image to read/write
587 * \param format format of image to read/write
588 * \param type datatype of image to read/write
589 * \param ptr the user-provided pointer/offset
590 * \return GL_TRUE if the PBO access is OK, GL_FALSE if the access would
594 _mesa_validate_pbo_access(GLuint dimensions
,
595 const struct gl_pixelstore_attrib
*pack
,
596 GLsizei width
, GLsizei height
, GLsizei depth
,
597 GLenum format
, GLenum type
, const GLvoid
*ptr
)
600 const GLubyte
*sizeAddr
; /* buffer size, cast to a pointer */
602 ASSERT(pack
->BufferObj
->Name
!= 0);
604 if (pack
->BufferObj
->Size
== 0)
608 /* get address of first pixel we'll read */
609 start
= _mesa_image_address(dimensions
, pack
, ptr
, width
, height
,
610 format
, type
, 0, 0, 0);
612 /* get address just past the last pixel we'll read */
613 end
= _mesa_image_address(dimensions
, pack
, ptr
, width
, height
,
614 format
, type
, depth
-1, height
-1, width
);
617 sizeAddr
= ((const GLubyte
*) 0) + pack
->BufferObj
->Size
;
619 if ((const GLubyte
*) start
> sizeAddr
) {
620 /* This will catch negative values / wrap-around */
623 if ((const GLubyte
*) end
> sizeAddr
) {
624 /* Image read goes beyond end of buffer */
634 * If the source of glBitmap data is a PBO, check that we won't read out
635 * of buffer bounds, then map the buffer.
636 * If not sourcing from a PBO, just return the bitmap pointer.
637 * This is a helper function for (some) drivers.
638 * Return NULL if error.
639 * If non-null return, must call _mesa_unmap_bitmap_pbo() when done.
642 _mesa_map_bitmap_pbo(GLcontext
*ctx
,
643 const struct gl_pixelstore_attrib
*unpack
,
644 const GLubyte
*bitmap
)
648 if (unpack
->BufferObj
->Name
) {
649 /* unpack from PBO */
650 buf
= (GLubyte
*) ctx
->Driver
.MapBuffer(ctx
, GL_PIXEL_UNPACK_BUFFER_EXT
,
656 buf
= ADD_POINTERS(buf
, bitmap
);
659 /* unpack from normal memory */
668 * Counterpart to _mesa_map_bitmap_pbo()
669 * This is a helper function for (some) drivers.
672 _mesa_unmap_bitmap_pbo(GLcontext
*ctx
,
673 const struct gl_pixelstore_attrib
*unpack
)
675 if (unpack
->BufferObj
->Name
) {
676 ctx
->Driver
.UnmapBuffer(ctx
, GL_PIXEL_UNPACK_BUFFER_EXT
,
683 * \sa _mesa_map_bitmap_pbo
686 _mesa_map_drawpix_pbo(GLcontext
*ctx
,
687 const struct gl_pixelstore_attrib
*unpack
,
688 const GLvoid
*pixels
)
692 if (unpack
->BufferObj
->Name
) {
693 /* unpack from PBO */
694 buf
= (GLubyte
*) ctx
->Driver
.MapBuffer(ctx
, GL_PIXEL_UNPACK_BUFFER_EXT
,
700 buf
= ADD_POINTERS(buf
, pixels
);
703 /* unpack from normal memory */
712 * \sa _mesa_unmap_bitmap_pbo
715 _mesa_unmap_drawpix_pbo(GLcontext
*ctx
,
716 const struct gl_pixelstore_attrib
*unpack
)
718 if (unpack
->BufferObj
->Name
) {
719 ctx
->Driver
.UnmapBuffer(ctx
, GL_PIXEL_UNPACK_BUFFER_EXT
,
726 * If PBO is bound, map the buffer, return dest pointer in mapped buffer.
727 * Call _mesa_unmap_readpix_pbo() when finished
728 * \return NULL if error
731 _mesa_map_readpix_pbo(GLcontext
*ctx
,
732 const struct gl_pixelstore_attrib
*pack
,
737 if (pack
->BufferObj
->Name
) {
739 buf
= (GLubyte
*) ctx
->Driver
.MapBuffer(ctx
, GL_PIXEL_PACK_BUFFER_EXT
,
745 buf
= ADD_POINTERS(buf
, dest
);
748 /* pack to normal memory */
757 * Counterpart to _mesa_map_readpix_pbo()
760 _mesa_unmap_readpix_pbo(GLcontext
*ctx
,
761 const struct gl_pixelstore_attrib
*pack
)
763 if (pack
->BufferObj
->Name
) {
764 ctx
->Driver
.UnmapBuffer(ctx
, GL_PIXEL_PACK_BUFFER_EXT
, pack
->BufferObj
);
771 * Return the gl_buffer_object for the given ID.
772 * Always return NULL for ID 0.
774 struct gl_buffer_object
*
775 _mesa_lookup_bufferobj(GLcontext
*ctx
, GLuint buffer
)
780 return (struct gl_buffer_object
*)
781 _mesa_HashLookup(ctx
->Shared
->BufferObjects
, buffer
);
786 * If *ptr points to obj, set ptr = the Null/default buffer object.
787 * This is a helper for buffer object deletion.
788 * The GL spec says that deleting a buffer object causes it to get
789 * unbound from all arrays in the current context.
792 unbind(GLcontext
*ctx
,
793 struct gl_buffer_object
**ptr
,
794 struct gl_buffer_object
*obj
)
797 _mesa_reference_buffer_object(ctx
, ptr
, ctx
->Shared
->NullBufferObj
);
803 /**********************************************************************/
805 /**********************************************************************/
808 _mesa_BindBufferARB(GLenum target
, GLuint buffer
)
810 GET_CURRENT_CONTEXT(ctx
);
811 ASSERT_OUTSIDE_BEGIN_END(ctx
);
813 bind_buffer_object(ctx
, target
, buffer
);
818 * Delete a set of buffer objects.
820 * \param n Number of buffer objects to delete.
821 * \param ids Array of \c n buffer object IDs.
824 _mesa_DeleteBuffersARB(GLsizei n
, const GLuint
*ids
)
826 GET_CURRENT_CONTEXT(ctx
);
828 ASSERT_OUTSIDE_BEGIN_END(ctx
);
831 _mesa_error(ctx
, GL_INVALID_VALUE
, "glDeleteBuffersARB(n)");
835 _glthread_LOCK_MUTEX(ctx
->Shared
->Mutex
);
837 for (i
= 0; i
< n
; i
++) {
838 struct gl_buffer_object
*bufObj
= _mesa_lookup_bufferobj(ctx
, ids
[i
]);
840 struct gl_array_object
*arrayObj
= ctx
->Array
.ArrayObj
;
843 ASSERT(bufObj
->Name
== ids
[i
]);
845 if (bufObj
->Pointer
) {
846 /* if mapped, unmap it now */
847 ctx
->Driver
.UnmapBuffer(ctx
, 0, bufObj
);
848 bufObj
->Access
= DEFAULT_ACCESS
;
849 bufObj
->Pointer
= NULL
;
852 /* unbind any vertex pointers bound to this buffer */
853 unbind(ctx
, &arrayObj
->Vertex
.BufferObj
, bufObj
);
854 unbind(ctx
, &arrayObj
->Weight
.BufferObj
, bufObj
);
855 unbind(ctx
, &arrayObj
->Normal
.BufferObj
, bufObj
);
856 unbind(ctx
, &arrayObj
->Color
.BufferObj
, bufObj
);
857 unbind(ctx
, &arrayObj
->SecondaryColor
.BufferObj
, bufObj
);
858 unbind(ctx
, &arrayObj
->FogCoord
.BufferObj
, bufObj
);
859 unbind(ctx
, &arrayObj
->Index
.BufferObj
, bufObj
);
860 unbind(ctx
, &arrayObj
->EdgeFlag
.BufferObj
, bufObj
);
861 for (j
= 0; j
< Elements(arrayObj
->TexCoord
); j
++) {
862 unbind(ctx
, &arrayObj
->TexCoord
[j
].BufferObj
, bufObj
);
864 for (j
= 0; j
< Elements(arrayObj
->VertexAttrib
); j
++) {
865 unbind(ctx
, &arrayObj
->VertexAttrib
[j
].BufferObj
, bufObj
);
868 if (ctx
->Array
.ArrayBufferObj
== bufObj
) {
869 _mesa_BindBufferARB( GL_ARRAY_BUFFER_ARB
, 0 );
871 if (ctx
->Array
.ElementArrayBufferObj
== bufObj
) {
872 _mesa_BindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB
, 0 );
875 /* unbind any pixel pack/unpack pointers bound to this buffer */
876 if (ctx
->Pack
.BufferObj
== bufObj
) {
877 _mesa_BindBufferARB( GL_PIXEL_PACK_BUFFER_EXT
, 0 );
879 if (ctx
->Unpack
.BufferObj
== bufObj
) {
880 _mesa_BindBufferARB( GL_PIXEL_UNPACK_BUFFER_EXT
, 0 );
883 /* The ID is immediately freed for re-use */
884 _mesa_HashRemove(ctx
->Shared
->BufferObjects
, bufObj
->Name
);
885 _mesa_reference_buffer_object(ctx
, &bufObj
, NULL
);
889 _glthread_UNLOCK_MUTEX(ctx
->Shared
->Mutex
);
894 * Generate a set of unique buffer object IDs and store them in \c buffer.
896 * \param n Number of IDs to generate.
897 * \param buffer Array of \c n locations to store the IDs.
900 _mesa_GenBuffersARB(GLsizei n
, GLuint
*buffer
)
902 GET_CURRENT_CONTEXT(ctx
);
905 ASSERT_OUTSIDE_BEGIN_END(ctx
);
908 _mesa_error(ctx
, GL_INVALID_VALUE
, "glGenBuffersARB");
917 * This must be atomic (generation and allocation of buffer object IDs)
919 _glthread_LOCK_MUTEX(ctx
->Shared
->Mutex
);
921 first
= _mesa_HashFindFreeKeyBlock(ctx
->Shared
->BufferObjects
, n
);
923 /* Allocate new, empty buffer objects and return identifiers */
924 for (i
= 0; i
< n
; i
++) {
925 struct gl_buffer_object
*bufObj
;
926 GLuint name
= first
+ i
;
928 bufObj
= ctx
->Driver
.NewBufferObject( ctx
, name
, target
);
930 _glthread_UNLOCK_MUTEX(ctx
->Shared
->Mutex
);
931 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glGenBuffersARB");
934 _mesa_HashInsert(ctx
->Shared
->BufferObjects
, first
+ i
, bufObj
);
935 buffer
[i
] = first
+ i
;
938 _glthread_UNLOCK_MUTEX(ctx
->Shared
->Mutex
);
943 * Determine if ID is the name of a buffer object.
945 * \param id ID of the potential buffer object.
946 * \return \c GL_TRUE if \c id is the name of a buffer object,
947 * \c GL_FALSE otherwise.
950 _mesa_IsBufferARB(GLuint id
)
952 struct gl_buffer_object
*bufObj
;
953 GET_CURRENT_CONTEXT(ctx
);
954 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx
, GL_FALSE
);
956 _glthread_LOCK_MUTEX(ctx
->Shared
->Mutex
);
957 bufObj
= _mesa_lookup_bufferobj(ctx
, id
);
958 _glthread_UNLOCK_MUTEX(ctx
->Shared
->Mutex
);
960 return bufObj
? GL_TRUE
: GL_FALSE
;
965 _mesa_BufferDataARB(GLenum target
, GLsizeiptrARB size
,
966 const GLvoid
* data
, GLenum usage
)
968 GET_CURRENT_CONTEXT(ctx
);
969 struct gl_buffer_object
*bufObj
;
970 ASSERT_OUTSIDE_BEGIN_END(ctx
);
973 _mesa_error(ctx
, GL_INVALID_VALUE
, "glBufferDataARB(size < 0)");
978 case GL_STREAM_DRAW_ARB
:
979 case GL_STREAM_READ_ARB
:
980 case GL_STREAM_COPY_ARB
:
981 case GL_STATIC_DRAW_ARB
:
982 case GL_STATIC_READ_ARB
:
983 case GL_STATIC_COPY_ARB
:
984 case GL_DYNAMIC_DRAW_ARB
:
985 case GL_DYNAMIC_READ_ARB
:
986 case GL_DYNAMIC_COPY_ARB
:
990 _mesa_error(ctx
, GL_INVALID_ENUM
, "glBufferDataARB(usage)");
994 bufObj
= get_buffer(ctx
, target
);
996 _mesa_error(ctx
, GL_INVALID_ENUM
, "glBufferDataARB(target)" );
999 if (bufObj
->Name
== 0) {
1000 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glBufferDataARB(buffer 0)" );
1004 if (bufObj
->Pointer
) {
1005 /* Unmap the existing buffer. We'll replace it now. Not an error. */
1006 ctx
->Driver
.UnmapBuffer(ctx
, target
, bufObj
);
1007 bufObj
->Access
= DEFAULT_ACCESS
;
1008 bufObj
->Pointer
= NULL
;
1011 FLUSH_VERTICES(ctx
, _NEW_BUFFER_OBJECT
);
1013 ASSERT(ctx
->Driver
.BufferData
);
1015 bufObj
->Written
= GL_TRUE
;
1018 _mesa_printf("glBufferDataARB(%u, sz %ld, from %p, usage 0x%x)\n",
1019 bufObj
->Name
, size
, data
, usage
);
1022 /* Give the buffer object to the driver! <data> may be null! */
1023 ctx
->Driver
.BufferData( ctx
, target
, size
, data
, usage
, bufObj
);
1028 _mesa_BufferSubDataARB(GLenum target
, GLintptrARB offset
,
1029 GLsizeiptrARB size
, const GLvoid
* data
)
1031 GET_CURRENT_CONTEXT(ctx
);
1032 struct gl_buffer_object
*bufObj
;
1033 ASSERT_OUTSIDE_BEGIN_END(ctx
);
1035 bufObj
= buffer_object_subdata_range_good( ctx
, target
, offset
, size
,
1036 "glBufferSubDataARB" );
1038 /* error already recorded */
1042 bufObj
->Written
= GL_TRUE
;
1044 ASSERT(ctx
->Driver
.BufferSubData
);
1045 ctx
->Driver
.BufferSubData( ctx
, target
, offset
, size
, data
, bufObj
);
1050 _mesa_GetBufferSubDataARB(GLenum target
, GLintptrARB offset
,
1051 GLsizeiptrARB size
, void * data
)
1053 GET_CURRENT_CONTEXT(ctx
);
1054 struct gl_buffer_object
*bufObj
;
1055 ASSERT_OUTSIDE_BEGIN_END(ctx
);
1057 bufObj
= buffer_object_subdata_range_good( ctx
, target
, offset
, size
,
1058 "glGetBufferSubDataARB" );
1060 /* error already recorded */
1064 ASSERT(ctx
->Driver
.GetBufferSubData
);
1065 ctx
->Driver
.GetBufferSubData( ctx
, target
, offset
, size
, data
, bufObj
);
1070 _mesa_MapBufferARB(GLenum target
, GLenum access
)
1072 GET_CURRENT_CONTEXT(ctx
);
1073 struct gl_buffer_object
* bufObj
;
1074 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx
, NULL
);
1077 case GL_READ_ONLY_ARB
:
1078 case GL_WRITE_ONLY_ARB
:
1079 case GL_READ_WRITE_ARB
:
1083 _mesa_error(ctx
, GL_INVALID_ENUM
, "glMapBufferARB(access)");
1087 bufObj
= get_buffer(ctx
, target
);
1089 _mesa_error(ctx
, GL_INVALID_ENUM
, "glMapBufferARB(target)" );
1092 if (bufObj
->Name
== 0) {
1093 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glMapBufferARB(buffer 0)" );
1096 if (bufObj
->Pointer
) {
1097 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glMapBufferARB(already mapped)");
1101 ASSERT(ctx
->Driver
.MapBuffer
);
1102 bufObj
->Pointer
= ctx
->Driver
.MapBuffer( ctx
, target
, access
, bufObj
);
1103 if (!bufObj
->Pointer
) {
1104 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glMapBufferARB(access)");
1107 bufObj
->Access
= access
;
1108 if (access
== GL_WRITE_ONLY_ARB
|| access
== GL_READ_WRITE_ARB
)
1109 bufObj
->Written
= GL_TRUE
;
1112 _mesa_printf("glMapBufferARB(%u, sz %ld, access 0x%x)\n",
1113 bufObj
->Name
, bufObj
->Size
, access
);
1114 if (access
== GL_WRITE_ONLY_ARB
) {
1116 GLubyte
*b
= (GLubyte
*) bufObj
->Pointer
;
1117 for (i
= 0; i
< bufObj
->Size
; i
++)
1122 return bufObj
->Pointer
;
1126 GLboolean GLAPIENTRY
1127 _mesa_UnmapBufferARB(GLenum target
)
1129 GET_CURRENT_CONTEXT(ctx
);
1130 struct gl_buffer_object
*bufObj
;
1131 GLboolean status
= GL_TRUE
;
1132 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx
, GL_FALSE
);
1134 bufObj
= get_buffer(ctx
, target
);
1136 _mesa_error(ctx
, GL_INVALID_ENUM
, "glUnmapBufferARB(target)" );
1139 if (bufObj
->Name
== 0) {
1140 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glUnmapBufferARB" );
1143 if (!bufObj
->Pointer
) {
1144 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glUnmapBufferARB");
1149 if (bufObj
->Access
== GL_WRITE_ONLY_ARB
) {
1150 GLuint i
, unchanged
= 0;
1151 GLubyte
*b
= (GLubyte
*) bufObj
->Pointer
;
1153 /* check which bytes changed */
1154 for (i
= 0; i
< bufObj
->Size
- 1; i
++) {
1155 if (b
[i
] == (i
& 0xff) && b
[i
+1] == ((i
+1) & 0xff)) {
1162 _mesa_printf("glUnmapBufferARB(%u): %u of %ld unchanged, starting at %d\n",
1163 bufObj
->Name
, unchanged
, bufObj
->Size
, pos
);
1168 status
= ctx
->Driver
.UnmapBuffer( ctx
, target
, bufObj
);
1169 bufObj
->Access
= DEFAULT_ACCESS
;
1170 bufObj
->Pointer
= NULL
;
1177 _mesa_GetBufferParameterivARB(GLenum target
, GLenum pname
, GLint
*params
)
1179 GET_CURRENT_CONTEXT(ctx
);
1180 struct gl_buffer_object
*bufObj
;
1181 ASSERT_OUTSIDE_BEGIN_END(ctx
);
1183 bufObj
= get_buffer(ctx
, target
);
1185 _mesa_error(ctx
, GL_INVALID_ENUM
, "GetBufferParameterivARB(target)" );
1188 if (bufObj
->Name
== 0) {
1189 _mesa_error(ctx
, GL_INVALID_OPERATION
, "GetBufferParameterivARB" );
1194 case GL_BUFFER_SIZE_ARB
:
1195 *params
= (GLint
) bufObj
->Size
;
1197 case GL_BUFFER_USAGE_ARB
:
1198 *params
= bufObj
->Usage
;
1200 case GL_BUFFER_ACCESS_ARB
:
1201 *params
= bufObj
->Access
;
1203 case GL_BUFFER_MAPPED_ARB
:
1204 *params
= (bufObj
->Pointer
!= NULL
);
1207 _mesa_error(ctx
, GL_INVALID_ENUM
, "glGetBufferParameterivARB(pname)");
1214 _mesa_GetBufferPointervARB(GLenum target
, GLenum pname
, GLvoid
**params
)
1216 GET_CURRENT_CONTEXT(ctx
);
1217 struct gl_buffer_object
* bufObj
;
1218 ASSERT_OUTSIDE_BEGIN_END(ctx
);
1220 if (pname
!= GL_BUFFER_MAP_POINTER_ARB
) {
1221 _mesa_error(ctx
, GL_INVALID_ENUM
, "glGetBufferPointervARB(pname)");
1225 bufObj
= get_buffer(ctx
, target
);
1227 _mesa_error(ctx
, GL_INVALID_ENUM
, "glGetBufferPointervARB(target)" );
1230 if (bufObj
->Name
== 0) {
1231 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glGetBufferPointervARB" );
1235 *params
= bufObj
->Pointer
;
1240 _mesa_CopyBufferSubData(GLenum readTarget
, GLenum writeTarget
,
1241 GLintptr readOffset
, GLintptr writeOffset
,
1244 GET_CURRENT_CONTEXT(ctx
);
1245 struct gl_buffer_object
*src
, *dst
;
1246 ASSERT_OUTSIDE_BEGIN_END(ctx
);
1248 src
= get_buffer(ctx
, readTarget
);
1249 if (!src
|| src
->Name
== 0) {
1250 _mesa_error(ctx
, GL_INVALID_ENUM
,
1251 "glCopyBuffserSubData(readTarget = 0x%x)", readTarget
);
1255 dst
= get_buffer(ctx
, writeTarget
);
1256 if (!dst
|| dst
->Name
== 0) {
1257 _mesa_error(ctx
, GL_INVALID_ENUM
,
1258 "glCopyBuffserSubData(writeTarget = 0x%x)", writeTarget
);
1263 _mesa_error(ctx
, GL_INVALID_OPERATION
,
1264 "glCopyBuffserSubData(readBuffer is mapped)");
1269 _mesa_error(ctx
, GL_INVALID_OPERATION
,
1270 "glCopyBuffserSubData(writeBuffer is mapped)");
1274 if (readOffset
< 0) {
1275 _mesa_error(ctx
, GL_INVALID_VALUE
,
1276 "glCopyBuffserSubData(readOffset = %d)", readOffset
);
1280 if (writeOffset
< 0) {
1281 _mesa_error(ctx
, GL_INVALID_VALUE
,
1282 "glCopyBuffserSubData(writeOffset = %d)", writeOffset
);
1286 if (readOffset
+ size
> src
->Size
) {
1287 _mesa_error(ctx
, GL_INVALID_VALUE
,
1288 "glCopyBuffserSubData(readOffset + size = %d)",
1293 if (writeOffset
+ size
> dst
->Size
) {
1294 _mesa_error(ctx
, GL_INVALID_VALUE
,
1295 "glCopyBuffserSubData(writeOffset + size = %d)",
1301 if (readOffset
+ size
<= writeOffset
) {
1304 else if (writeOffset
+ size
<= readOffset
) {
1308 /* overlapping src/dst is illegal */
1309 _mesa_error(ctx
, GL_INVALID_VALUE
,
1310 "glCopyBuffserSubData(overlapping src/dst)");
1315 ctx
->Driver
.CopyBufferSubData(ctx
, src
, dst
, readOffset
, writeOffset
, size
);