2 * Mesa 3-D graphics library
5 * Copyright (C) 1999-2003 Brian Paul All Rights Reserved.
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 * \brief Functions for the GL_ARB_vertex_buffer_object extension.
37 #include "bufferobj.h"
39 struct gl_buffer_object
{
52 void _mesa_initialize_buffer_object( struct gl_buffer_object
*obj
,
53 GLuint name
, GLenum target
);
57 * Get the buffer object bound to the specified target in a GL context.
59 * \param ctx GL context
60 * \param target Buffer object target to be retrieved. Currently this must
61 * be either \c GL_ARRAY_BUFFER or \c GL_ELEMENT_ARRAY_BUFFER.
62 * \param str Name of caller for logging errors.
63 * \return A pointer to the buffer object bound to \c target in the
64 * specified context or \c NULL if \c target is invalid or no
65 * buffer object is bound.
68 static __inline
struct gl_buffer_object
*
69 _mesa_buffer_object_get_target( GLcontext
*ctx
, GLenum target
,
72 struct gl_buffer_object
* bufObj
= NULL
;
75 case GL_ARRAY_BUFFER_ARB
:
76 bufObj
= ctx
->ArrayBuffer
;
78 case GL_ELEMENT_ARRAY_BUFFER_ARB
:
79 bufObj
= ctx
->ElementArrayBuffer
;
82 _mesa_error(ctx
, GL_INVALID_ENUM
, "gl%s(target)", str
);
91 * Tests the subdata range parameters and sets the GL error code for
92 * \c glBufferSubDataARB and \c glGetBufferSubDataARB.
94 * \param ctx GL context.
95 * \param target Buffer object target on which to operate.
96 * \param offset Offset of the first byte of the subdata range.
97 * \param size Size, in bytes, of the subdata range.
98 * \param str Name of caller for logging errors.
99 * \return A pointer to the buffer object bound to \c target in the
100 * specified context or \c NULL if any of the parameter or state
101 * conditions for \c glBufferSubDataARB or \c glGetBufferSubDataARB
104 * \sa glBufferSubDataARB, glGetBufferSubDataARB
107 static struct gl_buffer_object
*
108 _mesa_buffer_object_subdata_range_good( GLcontext
* ctx
, GLenum target
,
109 GLintptrARB offset
, GLsizeiptrARB size
,
112 struct gl_buffer_object
*bufObj
;
115 _mesa_error(ctx
, GL_INVALID_VALUE
, "gl%s(size < 0)", str
);
120 _mesa_error(ctx
, GL_INVALID_VALUE
, "gl%s(offset < 0)", str
);
124 bufObj
= _mesa_buffer_object_get_target( ctx
, target
, str
);
125 if ( bufObj
== NULL
) {
129 if ( (offset
+ size
) > bufObj
->size
) {
130 _mesa_error(ctx
, GL_INVALID_VALUE
,
131 "gl%s(size + offset > buffer size)", str
);
135 if ( bufObj
->pointer
!= NULL
) {
136 _mesa_error(ctx
, GL_INVALID_OPERATION
, "gl%s", str
);
145 * Allocate and initialize a new buffer object.
147 * This function is intended to be called via
148 * \c dd_function_table::NewBufferObject.
151 struct gl_buffer_object
*
152 _mesa_new_buffer_object( GLcontext
*ctx
, GLuint name
, GLenum target
)
154 struct gl_buffer_object
*obj
;
155 obj
= CALLOC_STRUCT(gl_buffer_object
);
156 _mesa_initialize_buffer_object(obj
, name
, target
);
162 * Initialize a buffer object to default values.
166 _mesa_initialize_buffer_object( struct gl_buffer_object
*obj
,
167 GLuint name
, GLenum target
)
175 * Add the given buffer object to the buffer object pool.
179 _mesa_save_buffer_object( GLcontext
*ctx
, struct gl_buffer_object
*obj
)
182 /* insert into hash table */
183 _mesa_HashInsert(ctx
->Shared
->BufferObjects
, obj
->Name
, obj
);
189 * Remove the given buffer object from the buffer object pool.
190 * Do not deallocate the buffer object though.
194 _mesa_remove_buffer_object( GLcontext
*ctx
, struct gl_buffer_object
*bufObj
)
196 if (bufObj
->Name
> 0) {
197 /* remove from hash table */
198 _mesa_HashRemove(ctx
->Shared
->BufferObjects
, bufObj
->Name
);
204 * Allocate space for and store data in a buffer object. Any data that was
205 * previously stored in the buffer object is lost. If \c data is \c NULL,
206 * memory will be allocated, but no copy will occur.
208 * This function is intended to be called via
209 * \c dd_function_table::BufferData. This function need not set GL error
210 * codes. The input parameters will have been tested before calling.
212 * \param ctx GL context.
213 * \param target Buffer object target on which to operate.
214 * \param size Size, in bytes, of the new data store.
215 * \param data Pointer to the data to store in the buffer object. This
216 * pointer may be \c NULL.
217 * \param usage Hints about how the data will be used.
218 * \param bufObj Object to be used.
220 * \sa glBufferDataARB, dd_function_table::BufferData.
224 _mesa_buffer_data( GLcontext
*ctx
, GLenum target
, GLsizeiptrARB size
,
225 const GLvoid
* data
, GLenum usage
,
226 struct gl_buffer_object
* bufObj
)
232 new_data
= _mesa_realloc( bufObj
->data
, bufObj
->size
, size
);
233 if ( new_data
!= NULL
) {
234 bufObj
->data
= new_data
;
236 bufObj
->usage
= usage
;
238 if ( data
!= NULL
) {
239 memcpy( bufObj
->data
, data
, size
);
246 * Replace data in a subrange of buffer object. If the data range
247 * specified by \c size + \c offset extends beyond the end of the buffer or
248 * if \c data is \c NULL, no copy is performed.
250 * This function is intended to be called by
251 * \c dd_function_table::BufferSubData. This function need not set GL error
252 * codes. The input parameters will have been tested before calling.
254 * \param ctx GL context.
255 * \param target Buffer object target on which to operate.
256 * \param offset Offset of the first byte to be modified.
257 * \param size Size, in bytes, of the data range.
258 * \param data Pointer to the data to store in the buffer object.
259 * \param bufObj Object to be used.
261 * \sa glBufferSubDataARB, dd_function_table::BufferSubData.
265 _mesa_buffer_subdata( GLcontext
*ctx
, GLenum target
, GLintptrARB offset
,
266 GLsizeiptrARB size
, const GLvoid
* data
,
267 struct gl_buffer_object
* bufObj
)
269 if ( (bufObj
->data
!= NULL
)
270 && ((size
+ offset
) <= bufObj
->size
) ) {
271 memcpy( (GLubyte
*) bufObj
->data
+ offset
, data
, size
);
277 * Retrieve data from a subrange of buffer object. If the data range
278 * specified by \c size + \c offset extends beyond the end of the buffer or
279 * if \c data is \c NULL, no copy is performed.
281 * This function is intended to be called by
282 * \c dd_function_table::BufferGetSubData. This function need not set GL error
283 * codes. The input parameters will have been tested before calling.
285 * \param ctx GL context.
286 * \param target Buffer object target on which to operate.
287 * \param offset Offset of the first byte to be modified.
288 * \param size Size, in bytes, of the data range.
289 * \param data Pointer to the data to store in the buffer object.
290 * \param bufObj Object to be used.
292 * \sa glBufferGetSubDataARB, dd_function_table::GetBufferSubData.
296 _mesa_buffer_get_subdata( GLcontext
*ctx
, GLenum target
, GLintptrARB offset
,
297 GLsizeiptrARB size
, GLvoid
* data
,
298 struct gl_buffer_object
* bufObj
)
300 if ( (bufObj
->data
!= NULL
)
301 && ((size
+ offset
) <= bufObj
->size
) ) {
302 memcpy( data
, (GLubyte
*) bufObj
->data
+ offset
, size
);
308 * Maps the private data buffer into the processor's address space.
310 * This function is intended to be called by \c dd_function_table::MapBuffer.
311 * This function need not set GL error codes. The input parameters will have
312 * been tested before calling.
314 * \param ctx GL context.
315 * \param target Buffer object target on which to operate.
316 * \param access Information about how the buffer will be accessed.
317 * \param bufObj Object to be used.
318 * \return A pointer to the object's internal data store that can be accessed
321 * \sa glMapBufferARB, dd_function_table::MapBuffer
325 _mesa_buffer_map( GLcontext
*ctx
, GLenum target
, GLenum access
,
326 struct gl_buffer_object
* bufObj
)
333 _mesa_BindBufferARB(GLenum target
, GLuint buffer
)
335 GET_CURRENT_CONTEXT(ctx
);
336 struct gl_buffer_object
*oldBufObj
;
337 struct gl_buffer_object
*newBufObj
= 0;
338 ASSERT_OUTSIDE_BEGIN_END(ctx
);
340 oldBufObj
= _mesa_buffer_object_get_target( ctx
, target
, "BindBufferARB" );
341 if ( (oldBufObj
!= NULL
) && (oldBufObj
->Name
== buffer
) )
342 return; /* rebinding the same buffer object- no change */
345 * Get pointer to new buffer object (newBufObj)
351 /* non-default buffer object */
352 const struct _mesa_HashTable
*hash
= ctx
->Shared
->BufferObjects
;
353 newBufObj
= (struct gl_buffer_object
*) _mesa_HashLookup(hash
, buffer
);
354 if ( newBufObj
!= NULL
) {
356 if (newBufObj
->Target
!= 0 && newBufObj
->Target
!= target
) {
357 /* the named buffer object's target doesn't match the target */
358 _mesa_error( ctx
, GL_INVALID_OPERATION
,
359 "glBindBufferARB(wrong target)" );
364 /* if this is a new buffer object id, allocate a buffer object now */
365 newBufObj
= (*ctx
->Driver
.NewBufferObject
)(ctx
, buffer
, target
);
367 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glBindBufferARB");
370 _mesa_save_buffer_object(ctx
, newBufObj
);
372 newBufObj
->Target
= target
;
373 newBufObj
->RefCount
++;
377 case GL_ARRAY_BUFFER_ARB
:
378 ctx
->ArrayBuffer
= newBufObj
;
380 case GL_ELEMENT_ARRAY_BUFFER_ARB
:
381 ctx
->ElementArrayBuffer
= newBufObj
;
385 /* Pass BindBuffer call to device driver */
386 if ( (ctx
->Driver
.BindBuffer
!= NULL
) && (newBufObj
!= NULL
) )
387 (*ctx
->Driver
.BindBuffer
)( ctx
, target
, newBufObj
);
389 if ( oldBufObj
!= NULL
) {
390 oldBufObj
->RefCount
--;
391 assert(oldBufObj
->RefCount
>= 0);
392 if (oldBufObj
->RefCount
== 0) {
393 assert(oldBufObj
->Name
!= 0);
394 _mesa_remove_buffer_object(ctx
, oldBufObj
);
395 ASSERT(ctx
->Driver
.DeleteBuffer
);
396 (*ctx
->Driver
.DeleteBuffer
)( ctx
, oldBufObj
);
403 * Delete a set of buffer objects.
405 * \param n Number of buffer objects to delete.
406 * \param buffer Array of \c n buffer object IDs.
410 _mesa_DeleteBuffersARB(GLsizei n
, const GLuint
*ids
)
412 GET_CURRENT_CONTEXT(ctx
);
414 ASSERT_OUTSIDE_BEGIN_END(ctx
);
417 _mesa_error(ctx
, GL_INVALID_VALUE
, "glDeleteBuffersARB(n)");
421 _glthread_LOCK_MUTEX(ctx
->Shared
->Mutex
);
423 for (i
= 0; i
< n
; i
++) {
425 struct gl_buffer_object
*bufObj
= (struct gl_buffer_object
*)
426 _mesa_HashLookup(ctx
->Shared
->BufferObjects
, ids
[i
]);
428 if ( (bufObj
->Target
== GL_ARRAY_BUFFER_ARB
)
429 || (bufObj
->Target
== GL_ELEMENT_ARRAY_BUFFER_ARB
) ) {
430 _mesa_BindBufferARB( bufObj
->Target
, 0 );
432 else if (bufObj
->Target
== 0) {
433 /* The buffer object is not bound.
437 _mesa_problem(ctx
, "bad target in glDeleteBufferARB");
441 if (bufObj
->RefCount
<= 0) {
442 ASSERT(bufObj
->Name
!= 0);
443 _mesa_remove_buffer_object(ctx
, bufObj
);
444 ASSERT(ctx
->Driver
.DeleteBuffer
);
445 (*ctx
->Driver
.DeleteBuffer
)(ctx
, bufObj
);
451 _glthread_UNLOCK_MUTEX(ctx
->Shared
->Mutex
);
456 * Generate a set of unique buffer object IDs and store them in \c buffer.
458 * \param n Number of IDs to generate.
459 * \param buffer Array of \c n locations to store the IDs.
463 _mesa_GenBuffersARB(GLsizei n
, GLuint
*buffer
)
465 GET_CURRENT_CONTEXT(ctx
);
468 ASSERT_OUTSIDE_BEGIN_END(ctx
);
471 _mesa_error(ctx
, GL_INVALID_VALUE
, "glGenBuffersARB");
475 if ( buffer
== NULL
) {
480 * This must be atomic (generation and allocation of buffer object IDs)
482 _glthread_LOCK_MUTEX(ctx
->Shared
->Mutex
);
484 first
= _mesa_HashFindFreeKeyBlock(ctx
->Shared
->BufferObjects
, n
);
486 /* Return the buffer names */
488 buffer
[i
] = first
+ i
;
491 /* Allocate new, empty buffer objects */
492 for (i
= 0; i
< n
; i
++) {
493 struct gl_buffer_object
*bufObj
;
494 GLuint name
= first
+ i
;
496 bufObj
= (*ctx
->Driver
.NewBufferObject
)( ctx
, name
, target
);
497 if ( bufObj
!= NULL
) {
498 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glGenBuffersARB");
501 _mesa_save_buffer_object(ctx
, bufObj
);
504 _glthread_UNLOCK_MUTEX(ctx
->Shared
->Mutex
);
509 * Determine if ID is the name of a buffer object.
511 * \param id ID of the potential buffer object.
512 * \return \c GL_TRUE if \c id is the name of a buffer object,
513 * \c GL_FALSE otherwise.
517 _mesa_IsBufferARB(GLuint id
)
519 struct gl_buffer_object
* bufObj
;
520 GET_CURRENT_CONTEXT(ctx
);
521 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx
, GL_FALSE
);
526 _glthread_LOCK_MUTEX(ctx
->Shared
->Mutex
);
527 bufObj
= (struct gl_buffer_object
*) _mesa_HashLookup(ctx
->Shared
->BufferObjects
, id
);
528 _glthread_UNLOCK_MUTEX(ctx
->Shared
->Mutex
);
530 return (bufObj
!= NULL
);
535 _mesa_BufferDataARB(GLenum target
, GLsizeiptrARB size
,
536 const GLvoid
* data
, GLenum usage
)
538 GET_CURRENT_CONTEXT(ctx
);
539 struct gl_buffer_object
*bufObj
;
540 ASSERT_OUTSIDE_BEGIN_END(ctx
);
543 _mesa_error(ctx
, GL_INVALID_VALUE
, "glBufferDataARB(size < 0)");
548 case GL_STREAM_DRAW_ARB
:
549 case GL_STREAM_READ_ARB
:
550 case GL_STREAM_COPY_ARB
:
551 case GL_STATIC_DRAW_ARB
:
552 case GL_STATIC_READ_ARB
:
553 case GL_STATIC_COPY_ARB
:
554 case GL_DYNAMIC_DRAW_ARB
:
555 case GL_DYNAMIC_READ_ARB
:
556 case GL_DYNAMIC_COPY_ARB
:
560 _mesa_error(ctx
, GL_INVALID_ENUM
, "glBufferDataARB(usage)");
564 bufObj
= _mesa_buffer_object_get_target( ctx
, target
, "BufferDataARB" );
565 if ( bufObj
== NULL
) {
569 ASSERT(ctx
->Driver
.BufferData
);
571 /* Give the buffer object to the driver! <data> may be null! */
572 (*ctx
->Driver
.BufferData
)( ctx
, target
, size
, data
, usage
, bufObj
);
576 _mesa_BufferSubDataARB(GLenum target
, GLintptrARB offset
,
577 GLsizeiptrARB size
, const GLvoid
* data
)
579 GET_CURRENT_CONTEXT(ctx
);
580 struct gl_buffer_object
*bufObj
;
581 ASSERT_OUTSIDE_BEGIN_END(ctx
);
583 bufObj
= _mesa_buffer_object_subdata_range_good( ctx
, target
, offset
, size
,
584 "BufferSubDataARB" );
585 if ( bufObj
!= NULL
) {
586 ASSERT(ctx
->Driver
.BufferSubData
);
587 (*ctx
->Driver
.BufferSubData
)( ctx
, target
, offset
, size
, data
, bufObj
);
592 _mesa_GetBufferSubDataARB(GLenum target
, GLintptrARB offset
,
593 GLsizeiptrARB size
, void * data
)
595 GET_CURRENT_CONTEXT(ctx
);
596 struct gl_buffer_object
*bufObj
;
597 ASSERT_OUTSIDE_BEGIN_END(ctx
);
599 bufObj
= _mesa_buffer_object_subdata_range_good( ctx
, target
, offset
, size
,
600 "GetBufferSubDataARB" );
601 if ( bufObj
!= NULL
) {
602 ASSERT(ctx
->Driver
.GetBufferSubData
);
603 (*ctx
->Driver
.GetBufferSubData
)( ctx
, target
, offset
, size
, data
, bufObj
);
608 _mesa_MapBufferARB(GLenum target
, GLenum access
)
610 GET_CURRENT_CONTEXT(ctx
);
611 struct gl_buffer_object
* bufObj
;
612 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx
, NULL
);
615 case GL_READ_ONLY_ARB
:
616 case GL_WRITE_ONLY_ARB
:
617 case GL_READ_WRITE_ARB
:
621 _mesa_error(ctx
, GL_INVALID_ENUM
, "glMapBufferARB(access)");
625 bufObj
= _mesa_buffer_object_get_target( ctx
, target
,
627 if ( bufObj
== NULL
) {
631 if ( bufObj
->pointer
!= NULL
) {
632 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glMapBufferARB");
636 ASSERT(ctx
->Driver
.MapBuffer
);
637 bufObj
->pointer
= (*ctx
->Driver
.MapBuffer
)( ctx
, target
, access
, bufObj
);
638 if ( bufObj
->pointer
== NULL
) {
639 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glMapBufferARB(access)");
642 return bufObj
->pointer
;
646 _mesa_UnmapBufferARB(GLenum target
)
648 GET_CURRENT_CONTEXT(ctx
);
649 struct gl_buffer_object
*bufObj
;
650 GLboolean status
= GL_TRUE
;
651 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx
, GL_FALSE
);
654 bufObj
= _mesa_buffer_object_get_target( ctx
, target
,
656 if ( bufObj
== NULL
) {
660 if ( bufObj
->pointer
== NULL
) {
661 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glUnmapBufferARB");
665 if ( ctx
->Driver
.UnmapBuffer
!= NULL
) {
666 status
= (*ctx
->Driver
.UnmapBuffer
)( ctx
, target
, bufObj
);
669 bufObj
->pointer
= NULL
;
675 _mesa_GetBufferParameterivARB(GLenum target
, GLenum pname
, GLint
*params
)
677 GET_CURRENT_CONTEXT(ctx
);
678 struct gl_buffer_object
*bufObj
;
679 ASSERT_OUTSIDE_BEGIN_END(ctx
);
681 bufObj
= _mesa_buffer_object_get_target( ctx
, target
,
682 "GetBufferParameterivARB" );
683 if ( bufObj
== NULL
) {
688 case GL_BUFFER_SIZE_ARB
:
689 *params
= bufObj
->size
;
691 case GL_BUFFER_USAGE_ARB
:
692 *params
= bufObj
->usage
;
694 case GL_BUFFER_ACCESS_ARB
:
695 *params
= bufObj
->access
;
697 case GL_BUFFER_MAPPED_ARB
:
698 *params
= (bufObj
->pointer
!= NULL
);
701 _mesa_error(ctx
, GL_INVALID_ENUM
, "glGetBufferParameterivARB(pname)");
707 _mesa_GetBufferPointervARB(GLenum target
, GLenum pname
, GLvoid
**params
)
709 GET_CURRENT_CONTEXT(ctx
);
710 struct gl_buffer_object
* bufObj
;
711 ASSERT_OUTSIDE_BEGIN_END(ctx
);
713 if (pname
!= GL_BUFFER_MAP_POINTER_ARB
) {
714 _mesa_error(ctx
, GL_INVALID_ENUM
, "glGetBufferPointervARB(pname)");
718 bufObj
= _mesa_buffer_object_get_target( ctx
, target
,
719 "GetBufferPointervARB" );
720 if ( bufObj
== NULL
) {
724 *params
= bufObj
->pointer
;