blob: 0e417a261549f19727e222240fd74b87521cab4c [file] [log] [blame]
Brian Paul6061df02003-03-29 17:01:00 +00001/*
2 * Mesa 3-D graphics library
Brian Paul85ad44b2004-02-13 14:04:26 +00003 * Version: 6.1
Brian Paul6061df02003-03-29 17:01:00 +00004 *
Brian Paul85ad44b2004-02-13 14:04:26 +00005 * Copyright (C) 1999-2004 Brian Paul All Rights Reserved.
Brian Paul6061df02003-03-29 17:01:00 +00006 *
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:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
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.
23 */
24
25
26/**
27 * \file bufferobj.c
Ian Romanick0207b472003-09-09 00:10:12 +000028 * \brief Functions for the GL_ARB_vertex_buffer_object extension.
Brian Paulaa00d122003-09-15 19:55:10 +000029 * \author Brian Paul, Ian Romanick
Brian Paul6061df02003-03-29 17:01:00 +000030 */
31
32
33#include "glheader.h"
Ian Romanick0207b472003-09-09 00:10:12 +000034#include "hash.h"
Brian Paul6061df02003-03-29 17:01:00 +000035#include "imports.h"
Brian Paulaac73252003-04-09 02:31:35 +000036#include "context.h"
Brian Paul6061df02003-03-29 17:01:00 +000037#include "bufferobj.h"
38
Brian Paulc7b872a2003-09-09 13:44:40 +000039
Ian Romanick0207b472003-09-09 00:10:12 +000040/**
41 * Get the buffer object bound to the specified target in a GL context.
42 *
43 * \param ctx GL context
44 * \param target Buffer object target to be retrieved. Currently this must
45 * be either \c GL_ARRAY_BUFFER or \c GL_ELEMENT_ARRAY_BUFFER.
46 * \param str Name of caller for logging errors.
47 * \return A pointer to the buffer object bound to \c target in the
48 * specified context or \c NULL if \c target is invalid or no
49 * buffer object is bound.
50 */
Brian Paulc7b872a2003-09-09 13:44:40 +000051static INLINE struct gl_buffer_object *
52buffer_object_get_target( GLcontext *ctx, GLenum target, const char * str )
Ian Romanick0207b472003-09-09 00:10:12 +000053{
54 struct gl_buffer_object * bufObj = NULL;
55
56 switch (target) {
57 case GL_ARRAY_BUFFER_ARB:
Brian Paul148a2842003-09-17 03:40:11 +000058 bufObj = ctx->Array.ArrayBufferObj;
Ian Romanick0207b472003-09-09 00:10:12 +000059 break;
60 case GL_ELEMENT_ARRAY_BUFFER_ARB:
Brian Paul148a2842003-09-17 03:40:11 +000061 bufObj = ctx->Array.ElementArrayBufferObj;
Ian Romanick0207b472003-09-09 00:10:12 +000062 break;
63 default:
64 _mesa_error(ctx, GL_INVALID_ENUM, "gl%s(target)", str);
Brian Paul4b6f6e12003-10-14 14:49:39 +000065 return NULL;
Ian Romanick0207b472003-09-09 00:10:12 +000066 }
Brian Paul148a2842003-09-17 03:40:11 +000067
68 if (bufObj->Name == 0)
69 return NULL;
70
Ian Romanick0207b472003-09-09 00:10:12 +000071 return bufObj;
72}
73
74
75/**
76 * Tests the subdata range parameters and sets the GL error code for
77 * \c glBufferSubDataARB and \c glGetBufferSubDataARB.
78 *
79 * \param ctx GL context.
80 * \param target Buffer object target on which to operate.
81 * \param offset Offset of the first byte of the subdata range.
82 * \param size Size, in bytes, of the subdata range.
83 * \param str Name of caller for logging errors.
84 * \return A pointer to the buffer object bound to \c target in the
85 * specified context or \c NULL if any of the parameter or state
86 * conditions for \c glBufferSubDataARB or \c glGetBufferSubDataARB
87 * are invalid.
88 *
89 * \sa glBufferSubDataARB, glGetBufferSubDataARB
90 */
Ian Romanick0207b472003-09-09 00:10:12 +000091static struct gl_buffer_object *
Brian Paulc7b872a2003-09-09 13:44:40 +000092buffer_object_subdata_range_good( GLcontext * ctx, GLenum target,
93 GLintptrARB offset, GLsizeiptrARB size,
94 const char * str )
Ian Romanick0207b472003-09-09 00:10:12 +000095{
96 struct gl_buffer_object *bufObj;
97
98 if (size < 0) {
Brian Paul66e6e3e2003-09-17 21:18:22 +000099 _mesa_error(ctx, GL_INVALID_VALUE, "%s(size < 0)", str);
Ian Romanick0207b472003-09-09 00:10:12 +0000100 return NULL;
101 }
102
103 if (offset < 0) {
Brian Paul66e6e3e2003-09-17 21:18:22 +0000104 _mesa_error(ctx, GL_INVALID_VALUE, "%s(offset < 0)", str);
Ian Romanick0207b472003-09-09 00:10:12 +0000105 return NULL;
106 }
107
Brian Paulc7b872a2003-09-09 13:44:40 +0000108 bufObj = buffer_object_get_target( ctx, target, str );
Ian Romanick0207b472003-09-09 00:10:12 +0000109 if ( bufObj == NULL ) {
110 return NULL;
111 }
112
Karl Schultzdf8d3372003-09-18 15:14:10 +0000113 if ( (GLuint)(offset + size) > bufObj->Size ) {
Ian Romanick0207b472003-09-09 00:10:12 +0000114 _mesa_error(ctx, GL_INVALID_VALUE,
Brian Paul66e6e3e2003-09-17 21:18:22 +0000115 "%s(size + offset > buffer size)", str);
Ian Romanick0207b472003-09-09 00:10:12 +0000116 return NULL;
117 }
118
Brian Paul148a2842003-09-17 03:40:11 +0000119 if ( bufObj->Pointer != NULL ) {
Brian Paul66e6e3e2003-09-17 21:18:22 +0000120 _mesa_error(ctx, GL_INVALID_OPERATION, "%s", str);
Ian Romanick0207b472003-09-09 00:10:12 +0000121 return NULL;
122 }
123
124 return bufObj;
125}
126
127
128/**
129 * Allocate and initialize a new buffer object.
130 *
131 * This function is intended to be called via
132 * \c dd_function_table::NewBufferObject.
133 */
Ian Romanick0207b472003-09-09 00:10:12 +0000134struct gl_buffer_object *
135_mesa_new_buffer_object( GLcontext *ctx, GLuint name, GLenum target )
136{
137 struct gl_buffer_object *obj;
Brian Paulaa00d122003-09-15 19:55:10 +0000138 obj = MALLOC_STRUCT(gl_buffer_object);
Ian Romanick0207b472003-09-09 00:10:12 +0000139 _mesa_initialize_buffer_object(obj, name, target);
140 return obj;
141}
142
143
144/**
Brian Paul148a2842003-09-17 03:40:11 +0000145 * Delete a buffer object.
146 *
147 * This function is intended to be called via
Brian Paul26895aa2004-03-03 15:35:08 +0000148 * \c dd_function_table::DeleteBuffer.
Brian Paul148a2842003-09-17 03:40:11 +0000149 */
150void
151_mesa_delete_buffer_object( GLcontext *ctx, struct gl_buffer_object *bufObj )
152{
153 if (bufObj->Data)
154 _mesa_free(bufObj->Data);
155 _mesa_free(bufObj);
156}
157
158
159/**
Ian Romanick0207b472003-09-09 00:10:12 +0000160 * Initialize a buffer object to default values.
161 */
Ian Romanick0207b472003-09-09 00:10:12 +0000162void
163_mesa_initialize_buffer_object( struct gl_buffer_object *obj,
164 GLuint name, GLenum target )
165{
Brian Paulaa00d122003-09-15 19:55:10 +0000166 _mesa_bzero(obj, sizeof(struct gl_buffer_object));
Ian Romanick0207b472003-09-09 00:10:12 +0000167 obj->RefCount = 1;
168 obj->Name = name;
Brian Paul85ad44b2004-02-13 14:04:26 +0000169 obj->Usage = GL_STATIC_DRAW_ARB;
170 obj->Access = GL_READ_WRITE_ARB;
Ian Romanick0207b472003-09-09 00:10:12 +0000171}
172
173
174/**
175 * Add the given buffer object to the buffer object pool.
176 */
Ian Romanick0207b472003-09-09 00:10:12 +0000177void
178_mesa_save_buffer_object( GLcontext *ctx, struct gl_buffer_object *obj )
179{
180 if (obj->Name > 0) {
181 /* insert into hash table */
182 _mesa_HashInsert(ctx->Shared->BufferObjects, obj->Name, obj);
183 }
184}
185
186
187/**
188 * Remove the given buffer object from the buffer object pool.
189 * Do not deallocate the buffer object though.
190 */
Ian Romanick0207b472003-09-09 00:10:12 +0000191void
192_mesa_remove_buffer_object( GLcontext *ctx, struct gl_buffer_object *bufObj )
193{
194 if (bufObj->Name > 0) {
195 /* remove from hash table */
196 _mesa_HashRemove(ctx->Shared->BufferObjects, bufObj->Name);
197 }
198}
199
200
201/**
202 * Allocate space for and store data in a buffer object. Any data that was
203 * previously stored in the buffer object is lost. If \c data is \c NULL,
204 * memory will be allocated, but no copy will occur.
205 *
206 * This function is intended to be called via
207 * \c dd_function_table::BufferData. This function need not set GL error
208 * codes. The input parameters will have been tested before calling.
209 *
210 * \param ctx GL context.
211 * \param target Buffer object target on which to operate.
212 * \param size Size, in bytes, of the new data store.
213 * \param data Pointer to the data to store in the buffer object. This
214 * pointer may be \c NULL.
215 * \param usage Hints about how the data will be used.
216 * \param bufObj Object to be used.
217 *
218 * \sa glBufferDataARB, dd_function_table::BufferData.
219 */
Ian Romanick0207b472003-09-09 00:10:12 +0000220void
221_mesa_buffer_data( GLcontext *ctx, GLenum target, GLsizeiptrARB size,
222 const GLvoid * data, GLenum usage,
223 struct gl_buffer_object * bufObj )
224{
225 void * new_data;
226
227 (void) target;
228
Brian Paul148a2842003-09-17 03:40:11 +0000229 new_data = _mesa_realloc( bufObj->Data, bufObj->Size, size );
Ian Romanick0207b472003-09-09 00:10:12 +0000230 if ( new_data != NULL ) {
Brian Paule4fcea22003-09-19 15:38:15 +0000231 bufObj->Data = (GLubyte *) new_data;
Brian Paul148a2842003-09-17 03:40:11 +0000232 bufObj->Size = size;
233 bufObj->Usage = usage;
Ian Romanick0207b472003-09-09 00:10:12 +0000234
235 if ( data != NULL ) {
Brian Paul148a2842003-09-17 03:40:11 +0000236 _mesa_memcpy( bufObj->Data, data, size );
Ian Romanick0207b472003-09-09 00:10:12 +0000237 }
238 }
239}
240
241
242/**
243 * Replace data in a subrange of buffer object. If the data range
244 * specified by \c size + \c offset extends beyond the end of the buffer or
245 * if \c data is \c NULL, no copy is performed.
246 *
247 * This function is intended to be called by
248 * \c dd_function_table::BufferSubData. This function need not set GL error
249 * codes. The input parameters will have been tested before calling.
250 *
251 * \param ctx GL context.
252 * \param target Buffer object target on which to operate.
253 * \param offset Offset of the first byte to be modified.
254 * \param size Size, in bytes, of the data range.
255 * \param data Pointer to the data to store in the buffer object.
256 * \param bufObj Object to be used.
257 *
258 * \sa glBufferSubDataARB, dd_function_table::BufferSubData.
259 */
Ian Romanick0207b472003-09-09 00:10:12 +0000260void
261_mesa_buffer_subdata( GLcontext *ctx, GLenum target, GLintptrARB offset,
262 GLsizeiptrARB size, const GLvoid * data,
263 struct gl_buffer_object * bufObj )
264{
Brian Paul148a2842003-09-17 03:40:11 +0000265 if ( (bufObj->Data != NULL)
Karl Schultzdf8d3372003-09-18 15:14:10 +0000266 && ((GLuint)(size + offset) <= bufObj->Size) ) {
Brian Paul148a2842003-09-17 03:40:11 +0000267 _mesa_memcpy( (GLubyte *) bufObj->Data + offset, data, size );
Ian Romanick0207b472003-09-09 00:10:12 +0000268 }
269}
270
271
272/**
273 * Retrieve data from a subrange of buffer object. If the data range
274 * specified by \c size + \c offset extends beyond the end of the buffer or
275 * if \c data is \c NULL, no copy is performed.
276 *
277 * This function is intended to be called by
278 * \c dd_function_table::BufferGetSubData. This function need not set GL error
279 * codes. The input parameters will have been tested before calling.
280 *
281 * \param ctx GL context.
282 * \param target Buffer object target on which to operate.
283 * \param offset Offset of the first byte to be modified.
284 * \param size Size, in bytes, of the data range.
285 * \param data Pointer to the data to store in the buffer object.
286 * \param bufObj Object to be used.
287 *
288 * \sa glBufferGetSubDataARB, dd_function_table::GetBufferSubData.
289 */
Ian Romanick0207b472003-09-09 00:10:12 +0000290void
291_mesa_buffer_get_subdata( GLcontext *ctx, GLenum target, GLintptrARB offset,
292 GLsizeiptrARB size, GLvoid * data,
293 struct gl_buffer_object * bufObj )
294{
Brian Paul148a2842003-09-17 03:40:11 +0000295 if ( (bufObj->Data != NULL)
Karl Schultzdf8d3372003-09-18 15:14:10 +0000296 && ((GLuint)(size + offset) <= bufObj->Size) ) {
Brian Paul148a2842003-09-17 03:40:11 +0000297 _mesa_memcpy( data, (GLubyte *) bufObj->Data + offset, size );
Ian Romanick0207b472003-09-09 00:10:12 +0000298 }
299}
300
301
302/**
303 * Maps the private data buffer into the processor's address space.
304 *
305 * This function is intended to be called by \c dd_function_table::MapBuffer.
306 * This function need not set GL error codes. The input parameters will have
307 * been tested before calling.
308 *
309 * \param ctx GL context.
310 * \param target Buffer object target on which to operate.
311 * \param access Information about how the buffer will be accessed.
312 * \param bufObj Object to be used.
313 * \return A pointer to the object's internal data store that can be accessed
314 * by the processor
315 *
316 * \sa glMapBufferARB, dd_function_table::MapBuffer
317 */
Ian Romanick0207b472003-09-09 00:10:12 +0000318void *
319_mesa_buffer_map( GLcontext *ctx, GLenum target, GLenum access,
320 struct gl_buffer_object * bufObj )
321{
Brian Paul148a2842003-09-17 03:40:11 +0000322 return bufObj->Data;
Ian Romanick0207b472003-09-09 00:10:12 +0000323}
324
Brian Paul6061df02003-03-29 17:01:00 +0000325
Brian Paul148a2842003-09-17 03:40:11 +0000326/**
327 * Initialize the state associated with buffer objects
328 */
329void
330_mesa_init_buffer_objects( GLcontext *ctx )
331{
332 GLuint i;
333
Brian Paul20202782004-02-11 22:06:05 +0000334 /* Allocate the default buffer object and set refcount so high that
335 * it never gets deleted.
336 */
Brian Paul148a2842003-09-17 03:40:11 +0000337 ctx->Array.NullBufferObj = _mesa_new_buffer_object(ctx, 0, 0);
Brian Paul20202782004-02-11 22:06:05 +0000338 if (ctx->Array.NullBufferObj)
339 ctx->Array.NullBufferObj->RefCount = 1000;
340
Brian Paul148a2842003-09-17 03:40:11 +0000341 ctx->Array.ArrayBufferObj = ctx->Array.NullBufferObj;
342 ctx->Array.ElementArrayBufferObj = ctx->Array.NullBufferObj;
343
344 /* Vertex array buffers */
345 ctx->Array.Vertex.BufferObj = ctx->Array.NullBufferObj;
346 ctx->Array.Normal.BufferObj = ctx->Array.NullBufferObj;
347 ctx->Array.Color.BufferObj = ctx->Array.NullBufferObj;
348 ctx->Array.SecondaryColor.BufferObj = ctx->Array.NullBufferObj;
349 ctx->Array.FogCoord.BufferObj = ctx->Array.NullBufferObj;
350 ctx->Array.Index.BufferObj = ctx->Array.NullBufferObj;
351 for (i = 0; i < MAX_TEXTURE_UNITS; i++) {
352 ctx->Array.TexCoord[i].BufferObj = ctx->Array.NullBufferObj;
353 }
354 ctx->Array.EdgeFlag.BufferObj = ctx->Array.NullBufferObj;
355 for (i = 0; i < VERT_ATTRIB_MAX; i++) {
356 ctx->Array.VertexAttrib[i].BufferObj = ctx->Array.NullBufferObj;
357 }
358}
359
360
361
362/**********************************************************************/
363/* API Functions */
364/**********************************************************************/
365
Kendall Bennettc40d1dd2003-10-21 22:22:17 +0000366void GLAPIENTRY
Brian Paul6061df02003-03-29 17:01:00 +0000367_mesa_BindBufferARB(GLenum target, GLuint buffer)
368{
Brian Paulaac73252003-04-09 02:31:35 +0000369 GET_CURRENT_CONTEXT(ctx);
Ian Romanick0207b472003-09-09 00:10:12 +0000370 struct gl_buffer_object *oldBufObj;
371 struct gl_buffer_object *newBufObj = 0;
Brian Paulaac73252003-04-09 02:31:35 +0000372 ASSERT_OUTSIDE_BEGIN_END(ctx);
373
Brian Paulc7b872a2003-09-09 13:44:40 +0000374 oldBufObj = buffer_object_get_target( ctx, target, "BindBufferARB" );
Ian Romanick0207b472003-09-09 00:10:12 +0000375 if ( (oldBufObj != NULL) && (oldBufObj->Name == buffer) )
376 return; /* rebinding the same buffer object- no change */
Brian Paulaac73252003-04-09 02:31:35 +0000377
Ian Romanick0207b472003-09-09 00:10:12 +0000378 /*
379 * Get pointer to new buffer object (newBufObj)
380 */
381 if ( buffer == 0 ) {
Brian Paul148a2842003-09-17 03:40:11 +0000382 /* The spec says there's not a buffer object named 0, but we use
383 * one internally because it simplifies things.
384 */
385 newBufObj = ctx->Array.NullBufferObj;
Brian Paulaac73252003-04-09 02:31:35 +0000386 }
387 else {
Ian Romanick0207b472003-09-09 00:10:12 +0000388 /* non-default buffer object */
389 const struct _mesa_HashTable *hash = ctx->Shared->BufferObjects;
390 newBufObj = (struct gl_buffer_object *) _mesa_HashLookup(hash, buffer);
Brian Paul66e6e3e2003-09-17 21:18:22 +0000391 if (!newBufObj) {
Ian Romanick0207b472003-09-09 00:10:12 +0000392 /* if this is a new buffer object id, allocate a buffer object now */
393 newBufObj = (*ctx->Driver.NewBufferObject)(ctx, buffer, target);
394 if (!newBufObj) {
395 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindBufferARB");
396 return;
397 }
398 _mesa_save_buffer_object(ctx, newBufObj);
399 }
Ian Romanick0207b472003-09-09 00:10:12 +0000400 newBufObj->RefCount++;
401 }
402
403 switch (target) {
404 case GL_ARRAY_BUFFER_ARB:
Brian Paul148a2842003-09-17 03:40:11 +0000405 ctx->Array.ArrayBufferObj = newBufObj;
Ian Romanick0207b472003-09-09 00:10:12 +0000406 break;
407 case GL_ELEMENT_ARRAY_BUFFER_ARB:
Brian Paul148a2842003-09-17 03:40:11 +0000408 ctx->Array.ElementArrayBufferObj = newBufObj;
Ian Romanick0207b472003-09-09 00:10:12 +0000409 break;
410 }
411
412 /* Pass BindBuffer call to device driver */
413 if ( (ctx->Driver.BindBuffer != NULL) && (newBufObj != NULL) )
414 (*ctx->Driver.BindBuffer)( ctx, target, newBufObj );
415
416 if ( oldBufObj != NULL ) {
417 oldBufObj->RefCount--;
418 assert(oldBufObj->RefCount >= 0);
419 if (oldBufObj->RefCount == 0) {
420 assert(oldBufObj->Name != 0);
421 _mesa_remove_buffer_object(ctx, oldBufObj);
422 ASSERT(ctx->Driver.DeleteBuffer);
423 (*ctx->Driver.DeleteBuffer)( ctx, oldBufObj );
424 }
Brian Paulaac73252003-04-09 02:31:35 +0000425 }
Brian Paul6061df02003-03-29 17:01:00 +0000426}
427
Ian Romanick0207b472003-09-09 00:10:12 +0000428
429/**
430 * Delete a set of buffer objects.
431 *
432 * \param n Number of buffer objects to delete.
433 * \param buffer Array of \c n buffer object IDs.
434 */
Kendall Bennettc40d1dd2003-10-21 22:22:17 +0000435void GLAPIENTRY
Ian Romanick0207b472003-09-09 00:10:12 +0000436_mesa_DeleteBuffersARB(GLsizei n, const GLuint *ids)
Brian Paul6061df02003-03-29 17:01:00 +0000437{
Brian Paulaac73252003-04-09 02:31:35 +0000438 GET_CURRENT_CONTEXT(ctx);
Karl Schultzdf8d3372003-09-18 15:14:10 +0000439 GLsizei i;
Brian Paulaac73252003-04-09 02:31:35 +0000440 ASSERT_OUTSIDE_BEGIN_END(ctx);
441
442 if (n < 0) {
443 _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteBuffersARB(n)");
444 return;
445 }
446
Ian Romanick0207b472003-09-09 00:10:12 +0000447 _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
448
449 for (i = 0; i < n; i++) {
450 if (ids[i] != 0) {
451 struct gl_buffer_object *bufObj = (struct gl_buffer_object *)
452 _mesa_HashLookup(ctx->Shared->BufferObjects, ids[i]);
453 if (bufObj) {
Brian Paul62962762003-09-17 18:58:09 +0000454 /* unbind any vertex pointers bound to this buffer */
Brian Paul26895aa2004-03-03 15:35:08 +0000455 ASSERT(bufObj->Name == ids[i]);
456 /* decrement refcount and delete if <= 0 */
Ian Romanick0207b472003-09-09 00:10:12 +0000457 bufObj->RefCount--;
458 if (bufObj->RefCount <= 0) {
Brian Paul26895aa2004-03-03 15:35:08 +0000459 /* buffer should not be bound anymore! */
460 ASSERT(ctx->Array.ArrayBufferObj != bufObj);
461 ASSERT(ctx->Array.ElementArrayBufferObj != bufObj);
462 ASSERT(ctx->Array.Vertex.BufferObj != bufObj);
Ian Romanick0207b472003-09-09 00:10:12 +0000463 _mesa_remove_buffer_object(ctx, bufObj);
464 ASSERT(ctx->Driver.DeleteBuffer);
465 (*ctx->Driver.DeleteBuffer)(ctx, bufObj);
466 }
467 }
468 }
469 }
470
471 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
Brian Paul6061df02003-03-29 17:01:00 +0000472}
473
Ian Romanick0207b472003-09-09 00:10:12 +0000474
475/**
476 * Generate a set of unique buffer object IDs and store them in \c buffer.
477 *
478 * \param n Number of IDs to generate.
479 * \param buffer Array of \c n locations to store the IDs.
480 */
Kendall Bennettc40d1dd2003-10-21 22:22:17 +0000481void GLAPIENTRY
Brian Paulaac73252003-04-09 02:31:35 +0000482_mesa_GenBuffersARB(GLsizei n, GLuint *buffer)
Brian Paul6061df02003-03-29 17:01:00 +0000483{
Brian Paulaac73252003-04-09 02:31:35 +0000484 GET_CURRENT_CONTEXT(ctx);
Ian Romanick0207b472003-09-09 00:10:12 +0000485 GLuint first;
486 GLint i;
Brian Paulaac73252003-04-09 02:31:35 +0000487 ASSERT_OUTSIDE_BEGIN_END(ctx);
488
489 if (n < 0) {
Ian Romanick0207b472003-09-09 00:10:12 +0000490 _mesa_error(ctx, GL_INVALID_VALUE, "glGenBuffersARB");
Brian Paulaac73252003-04-09 02:31:35 +0000491 return;
492 }
Ian Romanick0207b472003-09-09 00:10:12 +0000493
494 if ( buffer == NULL ) {
495 return;
496 }
497
498 /*
499 * This must be atomic (generation and allocation of buffer object IDs)
500 */
501 _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
502
503 first = _mesa_HashFindFreeKeyBlock(ctx->Shared->BufferObjects, n);
504
Brian Paulaa00d122003-09-15 19:55:10 +0000505 /* Allocate new, empty buffer objects and return identifiers */
Ian Romanick0207b472003-09-09 00:10:12 +0000506 for (i = 0; i < n; i++) {
507 struct gl_buffer_object *bufObj;
508 GLuint name = first + i;
509 GLenum target = 0;
510 bufObj = (*ctx->Driver.NewBufferObject)( ctx, name, target );
Brian Paul148a2842003-09-17 03:40:11 +0000511 if (!bufObj) {
Ian Romanick0207b472003-09-09 00:10:12 +0000512 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenBuffersARB");
513 return;
514 }
515 _mesa_save_buffer_object(ctx, bufObj);
Brian Paulaa00d122003-09-15 19:55:10 +0000516 buffer[i] = first + i;
Ian Romanick0207b472003-09-09 00:10:12 +0000517 }
518
519 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
Brian Paul6061df02003-03-29 17:01:00 +0000520}
521
Ian Romanick0207b472003-09-09 00:10:12 +0000522
523/**
524 * Determine if ID is the name of a buffer object.
525 *
526 * \param id ID of the potential buffer object.
527 * \return \c GL_TRUE if \c id is the name of a buffer object,
528 * \c GL_FALSE otherwise.
529 */
Kendall Bennettc40d1dd2003-10-21 22:22:17 +0000530GLboolean GLAPIENTRY
Ian Romanick0207b472003-09-09 00:10:12 +0000531_mesa_IsBufferARB(GLuint id)
Brian Paul6061df02003-03-29 17:01:00 +0000532{
Ian Romanick0207b472003-09-09 00:10:12 +0000533 struct gl_buffer_object * bufObj;
534 GET_CURRENT_CONTEXT(ctx);
535 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
536
537 if (id == 0)
538 return GL_FALSE;
539
540 _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
541 bufObj = (struct gl_buffer_object *) _mesa_HashLookup(ctx->Shared->BufferObjects, id);
542 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
543
544 return (bufObj != NULL);
Brian Paul6061df02003-03-29 17:01:00 +0000545}
546
Ian Romanick0207b472003-09-09 00:10:12 +0000547
Kendall Bennettc40d1dd2003-10-21 22:22:17 +0000548void GLAPIENTRY
Brian Paul6061df02003-03-29 17:01:00 +0000549_mesa_BufferDataARB(GLenum target, GLsizeiptrARB size,
550 const GLvoid * data, GLenum usage)
551{
Brian Paulaac73252003-04-09 02:31:35 +0000552 GET_CURRENT_CONTEXT(ctx);
Ian Romanick0207b472003-09-09 00:10:12 +0000553 struct gl_buffer_object *bufObj;
Brian Paulaac73252003-04-09 02:31:35 +0000554 ASSERT_OUTSIDE_BEGIN_END(ctx);
555
556 if (size < 0) {
557 _mesa_error(ctx, GL_INVALID_VALUE, "glBufferDataARB(size < 0)");
558 return;
559 }
560
561 switch (usage) {
562 case GL_STREAM_DRAW_ARB:
563 case GL_STREAM_READ_ARB:
564 case GL_STREAM_COPY_ARB:
565 case GL_STATIC_DRAW_ARB:
566 case GL_STATIC_READ_ARB:
567 case GL_STATIC_COPY_ARB:
568 case GL_DYNAMIC_DRAW_ARB:
569 case GL_DYNAMIC_READ_ARB:
570 case GL_DYNAMIC_COPY_ARB:
571 /* OK */
572 break;
573 default:
574 _mesa_error(ctx, GL_INVALID_ENUM, "glBufferDataARB(usage)");
575 return;
576 }
577
Brian Paulc7b872a2003-09-09 13:44:40 +0000578 bufObj = buffer_object_get_target( ctx, target, "BufferDataARB" );
Ian Romanick0207b472003-09-09 00:10:12 +0000579 if ( bufObj == NULL ) {
Brian Paulaa00d122003-09-15 19:55:10 +0000580 _mesa_error(ctx, GL_INVALID_OPERATION, "glBufferDataARB" );
Brian Paulaac73252003-04-09 02:31:35 +0000581 return;
582 }
Ian Romanick0207b472003-09-09 00:10:12 +0000583
Brian Paul66e6e3e2003-09-17 21:18:22 +0000584 if (bufObj->Pointer) {
Brian Paulce8e13d2003-10-21 14:54:16 +0000585 _mesa_error(ctx, GL_INVALID_OPERATION, "glBufferDataARB(buffer is mapped)" );
Brian Paul66e6e3e2003-09-17 21:18:22 +0000586 return;
587 }
588
Ian Romanick0207b472003-09-09 00:10:12 +0000589 ASSERT(ctx->Driver.BufferData);
590
591 /* Give the buffer object to the driver! <data> may be null! */
592 (*ctx->Driver.BufferData)( ctx, target, size, data, usage, bufObj );
Brian Paul6061df02003-03-29 17:01:00 +0000593}
594
Brian Paulc7b872a2003-09-09 13:44:40 +0000595
Kendall Bennettc40d1dd2003-10-21 22:22:17 +0000596void GLAPIENTRY
Brian Paul6061df02003-03-29 17:01:00 +0000597_mesa_BufferSubDataARB(GLenum target, GLintptrARB offset,
598 GLsizeiptrARB size, const GLvoid * data)
599{
Brian Paulaac73252003-04-09 02:31:35 +0000600 GET_CURRENT_CONTEXT(ctx);
Ian Romanick0207b472003-09-09 00:10:12 +0000601 struct gl_buffer_object *bufObj;
Brian Paulaac73252003-04-09 02:31:35 +0000602 ASSERT_OUTSIDE_BEGIN_END(ctx);
603
Brian Paulc7b872a2003-09-09 13:44:40 +0000604 bufObj = buffer_object_subdata_range_good( ctx, target, offset, size,
Brian Paul49aefce2003-10-15 20:50:41 +0000605 "BufferSubDataARB" );
Brian Paulaa00d122003-09-15 19:55:10 +0000606 if (!bufObj) {
607 _mesa_error(ctx, GL_INVALID_OPERATION, "glBufferSubDataARB" );
608 return;
Brian Paulaac73252003-04-09 02:31:35 +0000609 }
Brian Paulaa00d122003-09-15 19:55:10 +0000610
Brian Paul66e6e3e2003-09-17 21:18:22 +0000611 if (bufObj->Pointer) {
612 _mesa_error(ctx, GL_INVALID_OPERATION, "glBufferSubDataARB(buffer is mapped)" );
613 return;
614 }
615
Brian Paulaa00d122003-09-15 19:55:10 +0000616 ASSERT(ctx->Driver.BufferSubData);
617 (*ctx->Driver.BufferSubData)( ctx, target, offset, size, data, bufObj );
Brian Paul6061df02003-03-29 17:01:00 +0000618}
619
Brian Paulc7b872a2003-09-09 13:44:40 +0000620
Kendall Bennettc40d1dd2003-10-21 22:22:17 +0000621void GLAPIENTRY
Brian Paul6061df02003-03-29 17:01:00 +0000622_mesa_GetBufferSubDataARB(GLenum target, GLintptrARB offset,
623 GLsizeiptrARB size, void * data)
624{
Brian Paulaac73252003-04-09 02:31:35 +0000625 GET_CURRENT_CONTEXT(ctx);
Ian Romanick0207b472003-09-09 00:10:12 +0000626 struct gl_buffer_object *bufObj;
Brian Paulaac73252003-04-09 02:31:35 +0000627 ASSERT_OUTSIDE_BEGIN_END(ctx);
628
Brian Paulc7b872a2003-09-09 13:44:40 +0000629 bufObj = buffer_object_subdata_range_good( ctx, target, offset, size,
Brian Paul49aefce2003-10-15 20:50:41 +0000630 "GetBufferSubDataARB" );
Brian Paulaa00d122003-09-15 19:55:10 +0000631 if (!bufObj) {
632 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetBufferSubDataARB" );
633 return;
Brian Paulaac73252003-04-09 02:31:35 +0000634 }
Brian Paul66e6e3e2003-09-17 21:18:22 +0000635
636 if (bufObj->Pointer) {
637 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetBufferSubDataARB(buffer is mapped)" );
638 return;
639 }
640
Brian Paulaa00d122003-09-15 19:55:10 +0000641 ASSERT(ctx->Driver.GetBufferSubData);
642 (*ctx->Driver.GetBufferSubData)( ctx, target, offset, size, data, bufObj );
Brian Paul6061df02003-03-29 17:01:00 +0000643}
644
Brian Paulc7b872a2003-09-09 13:44:40 +0000645
Kendall Bennettc40d1dd2003-10-21 22:22:17 +0000646void * GLAPIENTRY
Brian Paul6061df02003-03-29 17:01:00 +0000647_mesa_MapBufferARB(GLenum target, GLenum access)
648{
Brian Paulaac73252003-04-09 02:31:35 +0000649 GET_CURRENT_CONTEXT(ctx);
Ian Romanick0207b472003-09-09 00:10:12 +0000650 struct gl_buffer_object * bufObj;
Brian Paulea31ca42003-05-10 04:35:09 +0000651 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, NULL);
Brian Paulaac73252003-04-09 02:31:35 +0000652
653 switch (access) {
654 case GL_READ_ONLY_ARB:
655 case GL_WRITE_ONLY_ARB:
656 case GL_READ_WRITE_ARB:
657 /* OK */
658 break;
659 default:
660 _mesa_error(ctx, GL_INVALID_ENUM, "glMapBufferARB(access)");
Brian Paulea31ca42003-05-10 04:35:09 +0000661 return NULL;
Brian Paulaac73252003-04-09 02:31:35 +0000662 }
663
Brian Paulc7b872a2003-09-09 13:44:40 +0000664 bufObj = buffer_object_get_target( ctx, target, "MapBufferARB" );
Ian Romanick0207b472003-09-09 00:10:12 +0000665 if ( bufObj == NULL ) {
Brian Paulaa00d122003-09-15 19:55:10 +0000666 _mesa_error(ctx, GL_INVALID_OPERATION, "glMapBufferARB" );
Brian Paulea31ca42003-05-10 04:35:09 +0000667 return NULL;
Brian Paulaac73252003-04-09 02:31:35 +0000668 }
Brian Paulea31ca42003-05-10 04:35:09 +0000669
Brian Paul148a2842003-09-17 03:40:11 +0000670 if ( bufObj->Pointer != NULL ) {
Brian Paul66e6e3e2003-09-17 21:18:22 +0000671 _mesa_error(ctx, GL_INVALID_OPERATION, "glMapBufferARB(already mapped)");
Ian Romanick0207b472003-09-09 00:10:12 +0000672 return NULL;
673 }
674
675 ASSERT(ctx->Driver.MapBuffer);
Brian Paul148a2842003-09-17 03:40:11 +0000676 bufObj->Pointer = (*ctx->Driver.MapBuffer)( ctx, target, access, bufObj );
677 if ( bufObj->Pointer == NULL ) {
Ian Romanick0207b472003-09-09 00:10:12 +0000678 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glMapBufferARB(access)");
679 }
680
Brian Paul0bb281b2003-10-14 15:48:39 +0000681 bufObj->Access = access;
682
Brian Paul148a2842003-09-17 03:40:11 +0000683 return bufObj->Pointer;
Brian Paul6061df02003-03-29 17:01:00 +0000684}
685
Brian Paulc7b872a2003-09-09 13:44:40 +0000686
Kendall Bennettc40d1dd2003-10-21 22:22:17 +0000687GLboolean GLAPIENTRY
Brian Paul6061df02003-03-29 17:01:00 +0000688_mesa_UnmapBufferARB(GLenum target)
689{
Brian Paulaac73252003-04-09 02:31:35 +0000690 GET_CURRENT_CONTEXT(ctx);
Ian Romanick0207b472003-09-09 00:10:12 +0000691 struct gl_buffer_object *bufObj;
692 GLboolean status = GL_TRUE;
Brian Paulaac73252003-04-09 02:31:35 +0000693 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
694
Brian Paulc7b872a2003-09-09 13:44:40 +0000695 bufObj = buffer_object_get_target( ctx, target, "UnmapBufferARB" );
Ian Romanick0207b472003-09-09 00:10:12 +0000696 if ( bufObj == NULL ) {
Brian Paul148a2842003-09-17 03:40:11 +0000697 _mesa_error(ctx, GL_INVALID_OPERATION, "glUnmapBufferARB" );
Brian Paulaac73252003-04-09 02:31:35 +0000698 return GL_FALSE;
699 }
Ian Romanick0207b472003-09-09 00:10:12 +0000700
Brian Paul148a2842003-09-17 03:40:11 +0000701 if ( bufObj->Pointer == NULL ) {
Ian Romanick0207b472003-09-09 00:10:12 +0000702 _mesa_error(ctx, GL_INVALID_OPERATION, "glUnmapBufferARB");
703 return GL_FALSE;
704 }
705
706 if ( ctx->Driver.UnmapBuffer != NULL ) {
707 status = (*ctx->Driver.UnmapBuffer)( ctx, target, bufObj );
708 }
709
Brian Paul0bb281b2003-10-14 15:48:39 +0000710 bufObj->Access = GL_READ_WRITE_ARB; /* initial value, OK? */
Brian Paul148a2842003-09-17 03:40:11 +0000711 bufObj->Pointer = NULL;
Ian Romanick0207b472003-09-09 00:10:12 +0000712
713 return status;
Brian Paul6061df02003-03-29 17:01:00 +0000714}
715
Brian Paulc7b872a2003-09-09 13:44:40 +0000716
Kendall Bennettc40d1dd2003-10-21 22:22:17 +0000717void GLAPIENTRY
Brian Paul6061df02003-03-29 17:01:00 +0000718_mesa_GetBufferParameterivARB(GLenum target, GLenum pname, GLint *params)
719{
Brian Paulaac73252003-04-09 02:31:35 +0000720 GET_CURRENT_CONTEXT(ctx);
Ian Romanick0207b472003-09-09 00:10:12 +0000721 struct gl_buffer_object *bufObj;
Brian Paulaac73252003-04-09 02:31:35 +0000722 ASSERT_OUTSIDE_BEGIN_END(ctx);
723
Brian Paulc7b872a2003-09-09 13:44:40 +0000724 bufObj = buffer_object_get_target( ctx, target, "GetBufferParameterivARB" );
Brian Paulaa00d122003-09-15 19:55:10 +0000725 if (!bufObj) {
726 _mesa_error(ctx, GL_INVALID_OPERATION, "GetBufferParameterivARB" );
Ian Romanick0207b472003-09-09 00:10:12 +0000727 return;
728 }
729
Brian Paulaac73252003-04-09 02:31:35 +0000730 switch (pname) {
731 case GL_BUFFER_SIZE_ARB:
Brian Paul148a2842003-09-17 03:40:11 +0000732 *params = bufObj->Size;
Ian Romanick0207b472003-09-09 00:10:12 +0000733 break;
Brian Paulaac73252003-04-09 02:31:35 +0000734 case GL_BUFFER_USAGE_ARB:
Brian Paul148a2842003-09-17 03:40:11 +0000735 *params = bufObj->Usage;
Ian Romanick0207b472003-09-09 00:10:12 +0000736 break;
Brian Paulaac73252003-04-09 02:31:35 +0000737 case GL_BUFFER_ACCESS_ARB:
Brian Paul148a2842003-09-17 03:40:11 +0000738 *params = bufObj->Access;
Ian Romanick0207b472003-09-09 00:10:12 +0000739 break;
Brian Paulaac73252003-04-09 02:31:35 +0000740 case GL_BUFFER_MAPPED_ARB:
Brian Paul148a2842003-09-17 03:40:11 +0000741 *params = (bufObj->Pointer != NULL);
Brian Paulaac73252003-04-09 02:31:35 +0000742 break;
743 default:
744 _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferParameterivARB(pname)");
745 return;
746 }
Brian Paul6061df02003-03-29 17:01:00 +0000747}
748
Brian Paulc7b872a2003-09-09 13:44:40 +0000749
Kendall Bennettc40d1dd2003-10-21 22:22:17 +0000750void GLAPIENTRY
Brian Paul6061df02003-03-29 17:01:00 +0000751_mesa_GetBufferPointervARB(GLenum target, GLenum pname, GLvoid **params)
752{
Brian Paulaac73252003-04-09 02:31:35 +0000753 GET_CURRENT_CONTEXT(ctx);
Ian Romanick0207b472003-09-09 00:10:12 +0000754 struct gl_buffer_object * bufObj;
Brian Paulaac73252003-04-09 02:31:35 +0000755 ASSERT_OUTSIDE_BEGIN_END(ctx);
756
757 if (pname != GL_BUFFER_MAP_POINTER_ARB) {
758 _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferPointervARB(pname)");
759 return;
760 }
761
Brian Paulc7b872a2003-09-09 13:44:40 +0000762 bufObj = buffer_object_get_target( ctx, target, "GetBufferPointervARB" );
Ian Romanick0207b472003-09-09 00:10:12 +0000763 if ( bufObj == NULL ) {
Brian Paulaa00d122003-09-15 19:55:10 +0000764 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetBufferPointervARB" );
Brian Paulaac73252003-04-09 02:31:35 +0000765 return;
766 }
Ian Romanick0207b472003-09-09 00:10:12 +0000767
Brian Paul148a2842003-09-17 03:40:11 +0000768 *params = bufObj->Pointer;
Brian Paul6061df02003-03-29 17:01:00 +0000769}