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.
29 * \author Brian Paul, Ian Romanick
37 #include "bufferobj.h"
40 struct gl_buffer_object
{
55 * Get the buffer object bound to the specified target in a GL context.
57 * \param ctx GL context
58 * \param target Buffer object target to be retrieved. Currently this must
59 * be either \c GL_ARRAY_BUFFER or \c GL_ELEMENT_ARRAY_BUFFER.
60 * \param str Name of caller for logging errors.
61 * \return A pointer to the buffer object bound to \c target in the
62 * specified context or \c NULL if \c target is invalid or no
63 * buffer object is bound.
65 static INLINE
struct gl_buffer_object
*
66 buffer_object_get_target( GLcontext
*ctx
, GLenum target
, const char * str
)
68 struct gl_buffer_object
* bufObj
= NULL
;
71 case GL_ARRAY_BUFFER_ARB
:
72 bufObj
= ctx
->ArrayBuffer
;
74 case GL_ELEMENT_ARRAY_BUFFER_ARB
:
75 bufObj
= ctx
->ElementArrayBuffer
;
78 _mesa_error(ctx
, GL_INVALID_ENUM
, "gl%s(target)", str
);
87 * Tests the subdata range parameters and sets the GL error code for
88 * \c glBufferSubDataARB and \c glGetBufferSubDataARB.
90 * \param ctx GL context.
91 * \param target Buffer object target on which to operate.
92 * \param offset Offset of the first byte of the subdata range.
93 * \param size Size, in bytes, of the subdata range.
94 * \param str Name of caller for logging errors.
95 * \return A pointer to the buffer object bound to \c target in the
96 * specified context or \c NULL if any of the parameter or state
97 * conditions for \c glBufferSubDataARB or \c glGetBufferSubDataARB
100 * \sa glBufferSubDataARB, glGetBufferSubDataARB
102 static struct gl_buffer_object
*
103 buffer_object_subdata_range_good( GLcontext
* ctx
, GLenum target
,
104 GLintptrARB offset
, GLsizeiptrARB size
,
107 struct gl_buffer_object
*bufObj
;
110 _mesa_error(ctx
, GL_INVALID_VALUE
, "gl%s(size < 0)", str
);
115 _mesa_error(ctx
, GL_INVALID_VALUE
, "gl%s(offset < 0)", str
);
119 bufObj
= buffer_object_get_target( ctx
, target
, str
);
120 if ( bufObj
== NULL
) {
124 if ( (offset
+ size
) > bufObj
->size
) {
125 _mesa_error(ctx
, GL_INVALID_VALUE
,
126 "gl%s(size + offset > buffer size)", str
);
130 if ( bufObj
->pointer
!= NULL
) {
131 _mesa_error(ctx
, GL_INVALID_OPERATION
, "gl%s", str
);
140 * Allocate and initialize a new buffer object.
142 * This function is intended to be called via
143 * \c dd_function_table::NewBufferObject.
145 struct gl_buffer_object
*
146 _mesa_new_buffer_object( GLcontext
*ctx
, GLuint name
, GLenum target
)
148 struct gl_buffer_object
*obj
;
149 obj
= MALLOC_STRUCT(gl_buffer_object
);
150 _mesa_initialize_buffer_object(obj
, name
, target
);
156 * Initialize a buffer object to default values.
159 _mesa_initialize_buffer_object( struct gl_buffer_object
*obj
,
160 GLuint name
, GLenum target
)
162 _mesa_bzero(obj
, sizeof(struct gl_buffer_object
));
169 * Add the given buffer object to the buffer object pool.
172 _mesa_save_buffer_object( GLcontext
*ctx
, struct gl_buffer_object
*obj
)
175 /* insert into hash table */
176 _mesa_HashInsert(ctx
->Shared
->BufferObjects
, obj
->Name
, obj
);
182 * Remove the given buffer object from the buffer object pool.
183 * Do not deallocate the buffer object though.
186 _mesa_remove_buffer_object( GLcontext
*ctx
, struct gl_buffer_object
*bufObj
)
188 if (bufObj
->Name
> 0) {
189 /* remove from hash table */
190 _mesa_HashRemove(ctx
->Shared
->BufferObjects
, bufObj
->Name
);
196 * Allocate space for and store data in a buffer object. Any data that was
197 * previously stored in the buffer object is lost. If \c data is \c NULL,
198 * memory will be allocated, but no copy will occur.
200 * This function is intended to be called via
201 * \c dd_function_table::BufferData. This function need not set GL error
202 * codes. The input parameters will have been tested before calling.
204 * \param ctx GL context.
205 * \param target Buffer object target on which to operate.
206 * \param size Size, in bytes, of the new data store.
207 * \param data Pointer to the data to store in the buffer object. This
208 * pointer may be \c NULL.
209 * \param usage Hints about how the data will be used.
210 * \param bufObj Object to be used.
212 * \sa glBufferDataARB, dd_function_table::BufferData.
215 _mesa_buffer_data( GLcontext
*ctx
, GLenum target
, GLsizeiptrARB size
,
216 const GLvoid
* data
, GLenum usage
,
217 struct gl_buffer_object
* bufObj
)
223 new_data
= _mesa_realloc( bufObj
->data
, bufObj
->size
, size
);
224 if ( new_data
!= NULL
) {
225 bufObj
->data
= new_data
;
227 bufObj
->usage
= usage
;
229 if ( data
!= NULL
) {
230 _mesa_memcpy( bufObj
->data
, data
, size
);
237 * Replace data in a subrange of buffer object. If the data range
238 * specified by \c size + \c offset extends beyond the end of the buffer or
239 * if \c data is \c NULL, no copy is performed.
241 * This function is intended to be called by
242 * \c dd_function_table::BufferSubData. This function need not set GL error
243 * codes. The input parameters will have been tested before calling.
245 * \param ctx GL context.
246 * \param target Buffer object target on which to operate.
247 * \param offset Offset of the first byte to be modified.
248 * \param size Size, in bytes, of the data range.
249 * \param data Pointer to the data to store in the buffer object.
250 * \param bufObj Object to be used.
252 * \sa glBufferSubDataARB, dd_function_table::BufferSubData.
255 _mesa_buffer_subdata( GLcontext
*ctx
, GLenum target
, GLintptrARB offset
,
256 GLsizeiptrARB size
, const GLvoid
* data
,
257 struct gl_buffer_object
* bufObj
)
259 if ( (bufObj
->data
!= NULL
)
260 && ((size
+ offset
) <= bufObj
->size
) ) {
261 _mesa_memcpy( (GLubyte
*) bufObj
->data
+ offset
, data
, size
);
267 * Retrieve data from a subrange of buffer object. If the data range
268 * specified by \c size + \c offset extends beyond the end of the buffer or
269 * if \c data is \c NULL, no copy is performed.
271 * This function is intended to be called by
272 * \c dd_function_table::BufferGetSubData. This function need not set GL error
273 * codes. The input parameters will have been tested before calling.
275 * \param ctx GL context.
276 * \param target Buffer object target on which to operate.
277 * \param offset Offset of the first byte to be modified.
278 * \param size Size, in bytes, of the data range.
279 * \param data Pointer to the data to store in the buffer object.
280 * \param bufObj Object to be used.
282 * \sa glBufferGetSubDataARB, dd_function_table::GetBufferSubData.
285 _mesa_buffer_get_subdata( GLcontext
*ctx
, GLenum target
, GLintptrARB offset
,
286 GLsizeiptrARB size
, GLvoid
* data
,
287 struct gl_buffer_object
* bufObj
)
289 if ( (bufObj
->data
!= NULL
)
290 && ((size
+ offset
) <= bufObj
->size
) ) {
291 _mesa_memcpy( data
, (GLubyte
*) bufObj
->data
+ offset
, size
);
297 * Maps the private data buffer into the processor's address space.
299 * This function is intended to be called by \c dd_function_table::MapBuffer.
300 * This function need not set GL error codes. The input parameters will have
301 * been tested before calling.
303 * \param ctx GL context.
304 * \param target Buffer object target on which to operate.
305 * \param access Information about how the buffer will be accessed.
306 * \param bufObj Object to be used.
307 * \return A pointer to the object's internal data store that can be accessed
310 * \sa glMapBufferARB, dd_function_table::MapBuffer
313 _mesa_buffer_map( GLcontext
*ctx
, GLenum target
, GLenum access
,
314 struct gl_buffer_object
* bufObj
)
321 _mesa_BindBufferARB(GLenum target
, GLuint buffer
)
323 GET_CURRENT_CONTEXT(ctx
);
324 struct gl_buffer_object
*oldBufObj
;
325 struct gl_buffer_object
*newBufObj
= 0;
326 ASSERT_OUTSIDE_BEGIN_END(ctx
);
328 oldBufObj
= buffer_object_get_target( ctx
, target
, "BindBufferARB" );
329 if ( (oldBufObj
!= NULL
) && (oldBufObj
->Name
== buffer
) )
330 return; /* rebinding the same buffer object- no change */
333 * Get pointer to new buffer object (newBufObj)
339 /* non-default buffer object */
340 const struct _mesa_HashTable
*hash
= ctx
->Shared
->BufferObjects
;
341 newBufObj
= (struct gl_buffer_object
*) _mesa_HashLookup(hash
, buffer
);
342 if ( newBufObj
!= NULL
) {
344 if (newBufObj
->Target
!= 0 && newBufObj
->Target
!= target
) {
345 /* the named buffer object's target doesn't match the target */
346 _mesa_error( ctx
, GL_INVALID_OPERATION
,
347 "glBindBufferARB(wrong target)" );
352 /* if this is a new buffer object id, allocate a buffer object now */
353 newBufObj
= (*ctx
->Driver
.NewBufferObject
)(ctx
, buffer
, target
);
355 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glBindBufferARB");
358 _mesa_save_buffer_object(ctx
, newBufObj
);
360 newBufObj
->Target
= target
;
361 newBufObj
->RefCount
++;
365 case GL_ARRAY_BUFFER_ARB
:
366 ctx
->ArrayBuffer
= newBufObj
;
368 case GL_ELEMENT_ARRAY_BUFFER_ARB
:
369 ctx
->ElementArrayBuffer
= newBufObj
;
373 /* Pass BindBuffer call to device driver */
374 if ( (ctx
->Driver
.BindBuffer
!= NULL
) && (newBufObj
!= NULL
) )
375 (*ctx
->Driver
.BindBuffer
)( ctx
, target
, newBufObj
);
377 if ( oldBufObj
!= NULL
) {
378 oldBufObj
->RefCount
--;
379 assert(oldBufObj
->RefCount
>= 0);
380 if (oldBufObj
->RefCount
== 0) {
381 assert(oldBufObj
->Name
!= 0);
382 _mesa_remove_buffer_object(ctx
, oldBufObj
);
383 ASSERT(ctx
->Driver
.DeleteBuffer
);
384 (*ctx
->Driver
.DeleteBuffer
)( ctx
, oldBufObj
);
391 * Delete a set of buffer objects.
393 * \param n Number of buffer objects to delete.
394 * \param buffer Array of \c n buffer object IDs.
397 _mesa_DeleteBuffersARB(GLsizei n
, const GLuint
*ids
)
399 GET_CURRENT_CONTEXT(ctx
);
401 ASSERT_OUTSIDE_BEGIN_END(ctx
);
404 _mesa_error(ctx
, GL_INVALID_VALUE
, "glDeleteBuffersARB(n)");
408 _glthread_LOCK_MUTEX(ctx
->Shared
->Mutex
);
410 for (i
= 0; i
< n
; i
++) {
412 struct gl_buffer_object
*bufObj
= (struct gl_buffer_object
*)
413 _mesa_HashLookup(ctx
->Shared
->BufferObjects
, ids
[i
]);
415 if ( (bufObj
->Target
== GL_ARRAY_BUFFER_ARB
)
416 || (bufObj
->Target
== GL_ELEMENT_ARRAY_BUFFER_ARB
) ) {
417 _mesa_BindBufferARB( bufObj
->Target
, 0 );
419 else if (bufObj
->Target
== 0) {
420 /* The buffer object is not bound.
424 _mesa_problem(ctx
, "bad target in glDeleteBufferARB");
428 if (bufObj
->RefCount
<= 0) {
429 ASSERT(bufObj
->Name
!= 0);
430 _mesa_remove_buffer_object(ctx
, bufObj
);
431 ASSERT(ctx
->Driver
.DeleteBuffer
);
432 (*ctx
->Driver
.DeleteBuffer
)(ctx
, bufObj
);
438 _glthread_UNLOCK_MUTEX(ctx
->Shared
->Mutex
);
443 * Generate a set of unique buffer object IDs and store them in \c buffer.
445 * \param n Number of IDs to generate.
446 * \param buffer Array of \c n locations to store the IDs.
449 _mesa_GenBuffersARB(GLsizei n
, GLuint
*buffer
)
451 GET_CURRENT_CONTEXT(ctx
);
454 ASSERT_OUTSIDE_BEGIN_END(ctx
);
457 _mesa_error(ctx
, GL_INVALID_VALUE
, "glGenBuffersARB");
461 if ( buffer
== NULL
) {
466 * This must be atomic (generation and allocation of buffer object IDs)
468 _glthread_LOCK_MUTEX(ctx
->Shared
->Mutex
);
470 first
= _mesa_HashFindFreeKeyBlock(ctx
->Shared
->BufferObjects
, n
);
472 /* Allocate new, empty buffer objects and return identifiers */
473 for (i
= 0; i
< n
; i
++) {
474 struct gl_buffer_object
*bufObj
;
475 GLuint name
= first
+ i
;
477 bufObj
= (*ctx
->Driver
.NewBufferObject
)( ctx
, name
, target
);
478 if ( bufObj
!= NULL
) {
479 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glGenBuffersARB");
482 _mesa_save_buffer_object(ctx
, bufObj
);
483 buffer
[i
] = first
+ i
;
486 _glthread_UNLOCK_MUTEX(ctx
->Shared
->Mutex
);
491 * Determine if ID is the name of a buffer object.
493 * \param id ID of the potential buffer object.
494 * \return \c GL_TRUE if \c id is the name of a buffer object,
495 * \c GL_FALSE otherwise.
498 _mesa_IsBufferARB(GLuint id
)
500 struct gl_buffer_object
* bufObj
;
501 GET_CURRENT_CONTEXT(ctx
);
502 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx
, GL_FALSE
);
507 _glthread_LOCK_MUTEX(ctx
->Shared
->Mutex
);
508 bufObj
= (struct gl_buffer_object
*) _mesa_HashLookup(ctx
->Shared
->BufferObjects
, id
);
509 _glthread_UNLOCK_MUTEX(ctx
->Shared
->Mutex
);
511 return (bufObj
!= NULL
);
516 _mesa_BufferDataARB(GLenum target
, GLsizeiptrARB size
,
517 const GLvoid
* data
, GLenum usage
)
519 GET_CURRENT_CONTEXT(ctx
);
520 struct gl_buffer_object
*bufObj
;
521 ASSERT_OUTSIDE_BEGIN_END(ctx
);
524 _mesa_error(ctx
, GL_INVALID_VALUE
, "glBufferDataARB(size < 0)");
529 case GL_STREAM_DRAW_ARB
:
530 case GL_STREAM_READ_ARB
:
531 case GL_STREAM_COPY_ARB
:
532 case GL_STATIC_DRAW_ARB
:
533 case GL_STATIC_READ_ARB
:
534 case GL_STATIC_COPY_ARB
:
535 case GL_DYNAMIC_DRAW_ARB
:
536 case GL_DYNAMIC_READ_ARB
:
537 case GL_DYNAMIC_COPY_ARB
:
541 _mesa_error(ctx
, GL_INVALID_ENUM
, "glBufferDataARB(usage)");
545 bufObj
= buffer_object_get_target( ctx
, target
, "BufferDataARB" );
546 if ( bufObj
== NULL
) {
547 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glBufferDataARB" );
551 ASSERT(ctx
->Driver
.BufferData
);
553 /* Give the buffer object to the driver! <data> may be null! */
554 (*ctx
->Driver
.BufferData
)( ctx
, target
, size
, data
, usage
, bufObj
);
559 _mesa_BufferSubDataARB(GLenum target
, GLintptrARB offset
,
560 GLsizeiptrARB size
, const GLvoid
* data
)
562 GET_CURRENT_CONTEXT(ctx
);
563 struct gl_buffer_object
*bufObj
;
564 ASSERT_OUTSIDE_BEGIN_END(ctx
);
566 bufObj
= buffer_object_subdata_range_good( ctx
, target
, offset
, size
,
567 "glBufferSubDataARB" );
569 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glBufferSubDataARB" );
573 ASSERT(ctx
->Driver
.BufferSubData
);
574 (*ctx
->Driver
.BufferSubData
)( ctx
, target
, offset
, size
, data
, bufObj
);
579 _mesa_GetBufferSubDataARB(GLenum target
, GLintptrARB offset
,
580 GLsizeiptrARB size
, void * data
)
582 GET_CURRENT_CONTEXT(ctx
);
583 struct gl_buffer_object
*bufObj
;
584 ASSERT_OUTSIDE_BEGIN_END(ctx
);
586 bufObj
= buffer_object_subdata_range_good( ctx
, target
, offset
, size
,
587 "glGetBufferSubDataARB" );
589 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glGetBufferSubDataARB" );
592 ASSERT(ctx
->Driver
.GetBufferSubData
);
593 (*ctx
->Driver
.GetBufferSubData
)( ctx
, target
, offset
, size
, data
, bufObj
);
598 _mesa_MapBufferARB(GLenum target
, GLenum access
)
600 GET_CURRENT_CONTEXT(ctx
);
601 struct gl_buffer_object
* bufObj
;
602 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx
, NULL
);
605 case GL_READ_ONLY_ARB
:
606 case GL_WRITE_ONLY_ARB
:
607 case GL_READ_WRITE_ARB
:
611 _mesa_error(ctx
, GL_INVALID_ENUM
, "glMapBufferARB(access)");
615 bufObj
= buffer_object_get_target( ctx
, target
, "MapBufferARB" );
616 if ( bufObj
== NULL
) {
617 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glMapBufferARB" );
621 if ( bufObj
->pointer
!= NULL
) {
622 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glMapBufferARB");
626 ASSERT(ctx
->Driver
.MapBuffer
);
627 bufObj
->pointer
= (*ctx
->Driver
.MapBuffer
)( ctx
, target
, access
, bufObj
);
628 if ( bufObj
->pointer
== NULL
) {
629 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glMapBufferARB(access)");
632 return bufObj
->pointer
;
637 _mesa_UnmapBufferARB(GLenum target
)
639 GET_CURRENT_CONTEXT(ctx
);
640 struct gl_buffer_object
*bufObj
;
641 GLboolean status
= GL_TRUE
;
642 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx
, GL_FALSE
);
645 bufObj
= buffer_object_get_target( ctx
, target
, "UnmapBufferARB" );
646 if ( bufObj
== NULL
) {
647 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glBufferSubDataARB" );
651 if ( bufObj
->pointer
== NULL
) {
652 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glUnmapBufferARB");
656 if ( ctx
->Driver
.UnmapBuffer
!= NULL
) {
657 status
= (*ctx
->Driver
.UnmapBuffer
)( ctx
, target
, bufObj
);
660 bufObj
->pointer
= NULL
;
667 _mesa_GetBufferParameterivARB(GLenum target
, GLenum pname
, GLint
*params
)
669 GET_CURRENT_CONTEXT(ctx
);
670 struct gl_buffer_object
*bufObj
;
671 ASSERT_OUTSIDE_BEGIN_END(ctx
);
673 bufObj
= buffer_object_get_target( ctx
, target
, "GetBufferParameterivARB" );
675 _mesa_error(ctx
, GL_INVALID_OPERATION
, "GetBufferParameterivARB" );
680 case GL_BUFFER_SIZE_ARB
:
681 *params
= bufObj
->size
;
683 case GL_BUFFER_USAGE_ARB
:
684 *params
= bufObj
->usage
;
686 case GL_BUFFER_ACCESS_ARB
:
687 *params
= bufObj
->access
;
689 case GL_BUFFER_MAPPED_ARB
:
690 *params
= (bufObj
->pointer
!= NULL
);
693 _mesa_error(ctx
, GL_INVALID_ENUM
, "glGetBufferParameterivARB(pname)");
700 _mesa_GetBufferPointervARB(GLenum target
, GLenum pname
, GLvoid
**params
)
702 GET_CURRENT_CONTEXT(ctx
);
703 struct gl_buffer_object
* bufObj
;
704 ASSERT_OUTSIDE_BEGIN_END(ctx
);
706 if (pname
!= GL_BUFFER_MAP_POINTER_ARB
) {
707 _mesa_error(ctx
, GL_INVALID_ENUM
, "glGetBufferPointervARB(pname)");
711 bufObj
= buffer_object_get_target( ctx
, target
, "GetBufferPointervARB" );
712 if ( bufObj
== NULL
) {
713 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glGetBufferPointervARB" );
717 *params
= bufObj
->pointer
;