mesa: Move buffer object dispatch setup to bufferobj.c.
[mesa.git] / src / mesa / main / bufferobj.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 7.6
4 *
5 * Copyright (C) 1999-2008 Brian Paul All Rights Reserved.
6 * Copyright (C) 2009 VMware, Inc. All Rights Reserved.
7 *
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:
14 *
15 * The above copyright notice and this permission notice shall be included
16 * in all copies or substantial portions of the Software.
17 *
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.
24 */
25
26
27 /**
28 * \file bufferobj.c
29 * \brief Functions for the GL_ARB_vertex/pixel_buffer_object extensions.
30 * \author Brian Paul, Ian Romanick
31 */
32
33
34 #include "glheader.h"
35 #include "enums.h"
36 #include "hash.h"
37 #include "imports.h"
38 #include "image.h"
39 #include "context.h"
40 #include "bufferobj.h"
41 #include "fbobject.h"
42 #include "mfeatures.h"
43 #include "mtypes.h"
44 #include "texobj.h"
45 #include "transformfeedback.h"
46 #include "dispatch.h"
47
48
49 /* Debug flags */
50 /*#define VBO_DEBUG*/
51 /*#define BOUNDS_CHECK*/
52
53
54 /**
55 * Used as a placeholder for buffer objects between glGenBuffers() and
56 * glBindBuffer() so that glIsBuffer() can work correctly.
57 */
58 static struct gl_buffer_object DummyBufferObject;
59
60
61 /**
62 * Return pointer to address of a buffer object target.
63 * \param ctx the GL context
64 * \param target the buffer object target to be retrieved.
65 * \return pointer to pointer to the buffer object bound to \c target in the
66 * specified context or \c NULL if \c target is invalid.
67 */
68 static inline struct gl_buffer_object **
69 get_buffer_target(struct gl_context *ctx, GLenum target)
70 {
71 switch (target) {
72 case GL_ARRAY_BUFFER_ARB:
73 return &ctx->Array.ArrayBufferObj;
74 case GL_ELEMENT_ARRAY_BUFFER_ARB:
75 return &ctx->Array.ArrayObj->ElementArrayBufferObj;
76 case GL_PIXEL_PACK_BUFFER_EXT:
77 return &ctx->Pack.BufferObj;
78 case GL_PIXEL_UNPACK_BUFFER_EXT:
79 return &ctx->Unpack.BufferObj;
80 case GL_COPY_READ_BUFFER:
81 return &ctx->CopyReadBuffer;
82 case GL_COPY_WRITE_BUFFER:
83 return &ctx->CopyWriteBuffer;
84 #if FEATURE_EXT_transform_feedback
85 case GL_TRANSFORM_FEEDBACK_BUFFER:
86 if (ctx->Extensions.EXT_transform_feedback) {
87 return &ctx->TransformFeedback.CurrentBuffer;
88 }
89 break;
90 #endif
91 case GL_TEXTURE_BUFFER:
92 if (ctx->Extensions.ARB_texture_buffer_object) {
93 return &ctx->Texture.BufferObject;
94 }
95 break;
96 case GL_UNIFORM_BUFFER:
97 if (ctx->Extensions.ARB_uniform_buffer_object) {
98 return &ctx->UniformBuffer;
99 }
100 break;
101 default:
102 return NULL;
103 }
104 return NULL;
105 }
106
107
108 /**
109 * Get the buffer object bound to the specified target in a GL context.
110 * \param ctx the GL context
111 * \param target the buffer object target to be retrieved.
112 * \return pointer to the buffer object bound to \c target in the
113 * specified context or \c NULL if \c target is invalid.
114 */
115 static inline struct gl_buffer_object *
116 get_buffer(struct gl_context *ctx, const char *func, GLenum target)
117 {
118 struct gl_buffer_object **bufObj = get_buffer_target(ctx, target);
119
120 if (!bufObj) {
121 _mesa_error(ctx, GL_INVALID_ENUM, "%s(target)", func);
122 return NULL;
123 }
124
125 if (!_mesa_is_bufferobj(*bufObj)) {
126 _mesa_error(ctx, GL_INVALID_OPERATION, "%s(buffer 0)", func);
127 return NULL;
128 }
129
130 return *bufObj;
131 }
132
133
134 static inline GLenum
135 default_access_mode(const struct gl_context *ctx)
136 {
137 /* Table 2.6 on page 31 (page 44 of the PDF) of the OpenGL 1.5 spec says:
138 *
139 * Name Type Initial Value Legal Values
140 * ... ... ... ...
141 * BUFFER_ACCESS enum READ_WRITE READ_ONLY, WRITE_ONLY
142 * READ_WRITE
143 *
144 * However, table 6.8 in the GL_OES_mapbuffer extension says:
145 *
146 * Get Value Type Get Command Value Description
147 * --------- ---- ----------- ----- -----------
148 * BUFFER_ACCESS_OES Z1 GetBufferParameteriv WRITE_ONLY_OES buffer map flag
149 *
150 * The difference is because GL_OES_mapbuffer only supports mapping buffers
151 * write-only.
152 */
153 return (ctx->API == API_OPENGLES)
154 ? GL_MAP_WRITE_BIT : (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT);
155 }
156
157
158 /**
159 * Convert a GLbitfield describing the mapped buffer access flags
160 * into one of GL_READ_WRITE, GL_READ_ONLY, or GL_WRITE_ONLY.
161 */
162 static GLenum
163 simplified_access_mode(GLbitfield access)
164 {
165 const GLbitfield rwFlags = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT;
166 if ((access & rwFlags) == rwFlags)
167 return GL_READ_WRITE;
168 if ((access & GL_MAP_READ_BIT) == GL_MAP_READ_BIT)
169 return GL_READ_ONLY;
170 if ((access & GL_MAP_WRITE_BIT) == GL_MAP_WRITE_BIT)
171 return GL_WRITE_ONLY;
172 return GL_READ_WRITE; /* this should never happen, but no big deal */
173 }
174
175
176 /**
177 * Tests the subdata range parameters and sets the GL error code for
178 * \c glBufferSubDataARB and \c glGetBufferSubDataARB.
179 *
180 * \param ctx GL context.
181 * \param target Buffer object target on which to operate.
182 * \param offset Offset of the first byte of the subdata range.
183 * \param size Size, in bytes, of the subdata range.
184 * \param caller Name of calling function for recording errors.
185 * \return A pointer to the buffer object bound to \c target in the
186 * specified context or \c NULL if any of the parameter or state
187 * conditions for \c glBufferSubDataARB or \c glGetBufferSubDataARB
188 * are invalid.
189 *
190 * \sa glBufferSubDataARB, glGetBufferSubDataARB
191 */
192 static struct gl_buffer_object *
193 buffer_object_subdata_range_good( struct gl_context * ctx, GLenum target,
194 GLintptrARB offset, GLsizeiptrARB size,
195 const char *caller )
196 {
197 struct gl_buffer_object *bufObj;
198
199 if (size < 0) {
200 _mesa_error(ctx, GL_INVALID_VALUE, "%s(size < 0)", caller);
201 return NULL;
202 }
203
204 if (offset < 0) {
205 _mesa_error(ctx, GL_INVALID_VALUE, "%s(offset < 0)", caller);
206 return NULL;
207 }
208
209 bufObj = get_buffer(ctx, caller, target);
210 if (!bufObj)
211 return NULL;
212
213 if (offset + size > bufObj->Size) {
214 _mesa_error(ctx, GL_INVALID_VALUE,
215 "%s(offset %lu + size %lu > buffer size %lu)", caller,
216 (unsigned long) offset,
217 (unsigned long) size,
218 (unsigned long) bufObj->Size);
219 return NULL;
220 }
221 if (_mesa_bufferobj_mapped(bufObj)) {
222 /* Buffer is currently mapped */
223 _mesa_error(ctx, GL_INVALID_OPERATION, "%s", caller);
224 return NULL;
225 }
226
227 return bufObj;
228 }
229
230
231 /**
232 * Allocate and initialize a new buffer object.
233 *
234 * Default callback for the \c dd_function_table::NewBufferObject() hook.
235 */
236 static struct gl_buffer_object *
237 _mesa_new_buffer_object( struct gl_context *ctx, GLuint name, GLenum target )
238 {
239 struct gl_buffer_object *obj;
240
241 (void) ctx;
242
243 obj = MALLOC_STRUCT(gl_buffer_object);
244 _mesa_initialize_buffer_object(ctx, obj, name, target);
245 return obj;
246 }
247
248
249 /**
250 * Delete a buffer object.
251 *
252 * Default callback for the \c dd_function_table::DeleteBuffer() hook.
253 */
254 static void
255 _mesa_delete_buffer_object(struct gl_context *ctx,
256 struct gl_buffer_object *bufObj)
257 {
258 (void) ctx;
259
260 if (bufObj->Data)
261 free(bufObj->Data);
262
263 /* assign strange values here to help w/ debugging */
264 bufObj->RefCount = -1000;
265 bufObj->Name = ~0;
266
267 _glthread_DESTROY_MUTEX(bufObj->Mutex);
268 free(bufObj);
269 }
270
271
272
273 /**
274 * Set ptr to bufObj w/ reference counting.
275 * This is normally only called from the _mesa_reference_buffer_object() macro
276 * when there's a real pointer change.
277 */
278 void
279 _mesa_reference_buffer_object_(struct gl_context *ctx,
280 struct gl_buffer_object **ptr,
281 struct gl_buffer_object *bufObj)
282 {
283 if (*ptr) {
284 /* Unreference the old buffer */
285 GLboolean deleteFlag = GL_FALSE;
286 struct gl_buffer_object *oldObj = *ptr;
287
288 _glthread_LOCK_MUTEX(oldObj->Mutex);
289 ASSERT(oldObj->RefCount > 0);
290 oldObj->RefCount--;
291 #if 0
292 printf("BufferObj %p %d DECR to %d\n",
293 (void *) oldObj, oldObj->Name, oldObj->RefCount);
294 #endif
295 deleteFlag = (oldObj->RefCount == 0);
296 _glthread_UNLOCK_MUTEX(oldObj->Mutex);
297
298 if (deleteFlag) {
299
300 /* some sanity checking: don't delete a buffer still in use */
301 #if 0
302 /* unfortunately, these tests are invalid during context tear-down */
303 ASSERT(ctx->Array.ArrayBufferObj != bufObj);
304 ASSERT(ctx->Array.ArrayObj->ElementArrayBufferObj != bufObj);
305 ASSERT(ctx->Array.ArrayObj->Vertex.BufferObj != bufObj);
306 #endif
307
308 ASSERT(ctx->Driver.DeleteBuffer);
309 ctx->Driver.DeleteBuffer(ctx, oldObj);
310 }
311
312 *ptr = NULL;
313 }
314 ASSERT(!*ptr);
315
316 if (bufObj) {
317 /* reference new buffer */
318 _glthread_LOCK_MUTEX(bufObj->Mutex);
319 if (bufObj->RefCount == 0) {
320 /* this buffer's being deleted (look just above) */
321 /* Not sure this can every really happen. Warn if it does. */
322 _mesa_problem(NULL, "referencing deleted buffer object");
323 *ptr = NULL;
324 }
325 else {
326 bufObj->RefCount++;
327 #if 0
328 printf("BufferObj %p %d INCR to %d\n",
329 (void *) bufObj, bufObj->Name, bufObj->RefCount);
330 #endif
331 *ptr = bufObj;
332 }
333 _glthread_UNLOCK_MUTEX(bufObj->Mutex);
334 }
335 }
336
337
338 /**
339 * Initialize a buffer object to default values.
340 */
341 void
342 _mesa_initialize_buffer_object( struct gl_context *ctx,
343 struct gl_buffer_object *obj,
344 GLuint name, GLenum target )
345 {
346 (void) target;
347
348 memset(obj, 0, sizeof(struct gl_buffer_object));
349 _glthread_INIT_MUTEX(obj->Mutex);
350 obj->RefCount = 1;
351 obj->Name = name;
352 obj->Usage = GL_STATIC_DRAW_ARB;
353 obj->AccessFlags = default_access_mode(ctx);
354 }
355
356
357
358 /**
359 * Callback called from _mesa_HashWalk()
360 */
361 static void
362 count_buffer_size(GLuint key, void *data, void *userData)
363 {
364 const struct gl_buffer_object *bufObj =
365 (const struct gl_buffer_object *) data;
366 GLuint *total = (GLuint *) userData;
367
368 *total = *total + bufObj->Size;
369 }
370
371
372 /**
373 * Compute total size (in bytes) of all buffer objects for the given context.
374 * For debugging purposes.
375 */
376 GLuint
377 _mesa_total_buffer_object_memory(struct gl_context *ctx)
378 {
379 GLuint total = 0;
380
381 _mesa_HashWalk(ctx->Shared->BufferObjects, count_buffer_size, &total);
382
383 return total;
384 }
385
386
387 /**
388 * Allocate space for and store data in a buffer object. Any data that was
389 * previously stored in the buffer object is lost. If \c data is \c NULL,
390 * memory will be allocated, but no copy will occur.
391 *
392 * This is the default callback for \c dd_function_table::BufferData()
393 * Note that all GL error checking will have been done already.
394 *
395 * \param ctx GL context.
396 * \param target Buffer object target on which to operate.
397 * \param size Size, in bytes, of the new data store.
398 * \param data Pointer to the data to store in the buffer object. This
399 * pointer may be \c NULL.
400 * \param usage Hints about how the data will be used.
401 * \param bufObj Object to be used.
402 *
403 * \return GL_TRUE for success, GL_FALSE for failure
404 * \sa glBufferDataARB, dd_function_table::BufferData.
405 */
406 static GLboolean
407 _mesa_buffer_data( struct gl_context *ctx, GLenum target, GLsizeiptrARB size,
408 const GLvoid * data, GLenum usage,
409 struct gl_buffer_object * bufObj )
410 {
411 void * new_data;
412
413 (void) ctx; (void) target;
414
415 new_data = _mesa_realloc( bufObj->Data, bufObj->Size, size );
416 if (new_data) {
417 bufObj->Data = (GLubyte *) new_data;
418 bufObj->Size = size;
419 bufObj->Usage = usage;
420
421 if (data) {
422 memcpy( bufObj->Data, data, size );
423 }
424
425 return GL_TRUE;
426 }
427 else {
428 return GL_FALSE;
429 }
430 }
431
432
433 /**
434 * Replace data in a subrange of buffer object. If the data range
435 * specified by \c size + \c offset extends beyond the end of the buffer or
436 * if \c data is \c NULL, no copy is performed.
437 *
438 * This is the default callback for \c dd_function_table::BufferSubData()
439 * Note that all GL error checking will have been done already.
440 *
441 * \param ctx GL context.
442 * \param target Buffer object target on which to operate.
443 * \param offset Offset of the first byte to be modified.
444 * \param size Size, in bytes, of the data range.
445 * \param data Pointer to the data to store in the buffer object.
446 * \param bufObj Object to be used.
447 *
448 * \sa glBufferSubDataARB, dd_function_table::BufferSubData.
449 */
450 static void
451 _mesa_buffer_subdata( struct gl_context *ctx, GLintptrARB offset,
452 GLsizeiptrARB size, const GLvoid * data,
453 struct gl_buffer_object * bufObj )
454 {
455 (void) ctx;
456
457 /* this should have been caught in _mesa_BufferSubData() */
458 ASSERT(size + offset <= bufObj->Size);
459
460 if (bufObj->Data) {
461 memcpy( (GLubyte *) bufObj->Data + offset, data, size );
462 }
463 }
464
465
466 /**
467 * Retrieve data from a subrange of buffer object. If the data range
468 * specified by \c size + \c offset extends beyond the end of the buffer or
469 * if \c data is \c NULL, no copy is performed.
470 *
471 * This is the default callback for \c dd_function_table::GetBufferSubData()
472 * Note that all GL error checking will have been done already.
473 *
474 * \param ctx GL context.
475 * \param target Buffer object target on which to operate.
476 * \param offset Offset of the first byte to be fetched.
477 * \param size Size, in bytes, of the data range.
478 * \param data Destination for data
479 * \param bufObj Object to be used.
480 *
481 * \sa glBufferGetSubDataARB, dd_function_table::GetBufferSubData.
482 */
483 static void
484 _mesa_buffer_get_subdata( struct gl_context *ctx, GLintptrARB offset,
485 GLsizeiptrARB size, GLvoid * data,
486 struct gl_buffer_object * bufObj )
487 {
488 (void) ctx;
489
490 if (bufObj->Data && ((GLsizeiptrARB) (size + offset) <= bufObj->Size)) {
491 memcpy( data, (GLubyte *) bufObj->Data + offset, size );
492 }
493 }
494
495
496 /**
497 * Default fallback for \c dd_function_table::MapBufferRange().
498 * Called via glMapBufferRange().
499 */
500 static void *
501 _mesa_buffer_map_range( struct gl_context *ctx, GLintptr offset,
502 GLsizeiptr length, GLbitfield access,
503 struct gl_buffer_object *bufObj )
504 {
505 (void) ctx;
506 assert(!_mesa_bufferobj_mapped(bufObj));
507 /* Just return a direct pointer to the data */
508 bufObj->Pointer = bufObj->Data + offset;
509 bufObj->Length = length;
510 bufObj->Offset = offset;
511 bufObj->AccessFlags = access;
512 return bufObj->Pointer;
513 }
514
515
516 /**
517 * Default fallback for \c dd_function_table::FlushMappedBufferRange().
518 * Called via glFlushMappedBufferRange().
519 */
520 static void
521 _mesa_buffer_flush_mapped_range( struct gl_context *ctx,
522 GLintptr offset, GLsizeiptr length,
523 struct gl_buffer_object *obj )
524 {
525 (void) ctx;
526 (void) offset;
527 (void) length;
528 (void) obj;
529 /* no-op */
530 }
531
532
533 /**
534 * Default callback for \c dd_function_table::MapBuffer().
535 *
536 * The input parameters will have been already tested for errors.
537 *
538 * \sa glUnmapBufferARB, dd_function_table::UnmapBuffer
539 */
540 static GLboolean
541 _mesa_buffer_unmap( struct gl_context *ctx, struct gl_buffer_object *bufObj )
542 {
543 (void) ctx;
544 /* XXX we might assert here that bufObj->Pointer is non-null */
545 bufObj->Pointer = NULL;
546 bufObj->Length = 0;
547 bufObj->Offset = 0;
548 bufObj->AccessFlags = 0x0;
549 return GL_TRUE;
550 }
551
552
553 /**
554 * Default fallback for \c dd_function_table::CopyBufferSubData().
555 * Called via glCopyBufferSubData().
556 */
557 static void
558 _mesa_copy_buffer_subdata(struct gl_context *ctx,
559 struct gl_buffer_object *src,
560 struct gl_buffer_object *dst,
561 GLintptr readOffset, GLintptr writeOffset,
562 GLsizeiptr size)
563 {
564 GLubyte *srcPtr, *dstPtr;
565
566 /* the buffers should not be mapped */
567 assert(!_mesa_bufferobj_mapped(src));
568 assert(!_mesa_bufferobj_mapped(dst));
569
570 if (src == dst) {
571 srcPtr = dstPtr = ctx->Driver.MapBufferRange(ctx, 0, src->Size,
572 GL_MAP_READ_BIT |
573 GL_MAP_WRITE_BIT, src);
574
575 if (!srcPtr)
576 return;
577
578 srcPtr += readOffset;
579 dstPtr += writeOffset;
580 } else {
581 srcPtr = ctx->Driver.MapBufferRange(ctx, readOffset, size,
582 GL_MAP_READ_BIT, src);
583 dstPtr = ctx->Driver.MapBufferRange(ctx, writeOffset, size,
584 (GL_MAP_WRITE_BIT |
585 GL_MAP_INVALIDATE_RANGE_BIT), dst);
586 }
587
588 /* Note: the src and dst regions will never overlap. Trying to do so
589 * would generate GL_INVALID_VALUE earlier.
590 */
591 if (srcPtr && dstPtr)
592 memcpy(dstPtr, srcPtr, size);
593
594 ctx->Driver.UnmapBuffer(ctx, src);
595 if (dst != src)
596 ctx->Driver.UnmapBuffer(ctx, dst);
597 }
598
599
600
601 /**
602 * Initialize the state associated with buffer objects
603 */
604 void
605 _mesa_init_buffer_objects( struct gl_context *ctx )
606 {
607 GLuint i;
608
609 memset(&DummyBufferObject, 0, sizeof(DummyBufferObject));
610 _glthread_INIT_MUTEX(DummyBufferObject.Mutex);
611 DummyBufferObject.RefCount = 1000*1000*1000; /* never delete */
612
613 _mesa_reference_buffer_object(ctx, &ctx->Array.ArrayBufferObj,
614 ctx->Shared->NullBufferObj);
615
616 _mesa_reference_buffer_object(ctx, &ctx->CopyReadBuffer,
617 ctx->Shared->NullBufferObj);
618 _mesa_reference_buffer_object(ctx, &ctx->CopyWriteBuffer,
619 ctx->Shared->NullBufferObj);
620
621 ctx->UniformBufferBindings = calloc(ctx->Const.MaxUniformBufferBindings,
622 sizeof(*ctx->UniformBufferBindings));
623
624 _mesa_reference_buffer_object(ctx, &ctx->UniformBuffer,
625 ctx->Shared->NullBufferObj);
626
627 for (i = 0; i < ctx->Const.MaxUniformBufferBindings; i++) {
628 _mesa_reference_buffer_object(ctx,
629 &ctx->UniformBufferBindings[i].BufferObject,
630 ctx->Shared->NullBufferObj);
631 ctx->UniformBufferBindings[i].Offset = -1;
632 ctx->UniformBufferBindings[i].Size = -1;
633 }
634 }
635
636
637 void
638 _mesa_free_buffer_objects( struct gl_context *ctx )
639 {
640 GLuint i;
641
642 _mesa_reference_buffer_object(ctx, &ctx->Array.ArrayBufferObj, NULL);
643
644 _mesa_reference_buffer_object(ctx, &ctx->CopyReadBuffer, NULL);
645 _mesa_reference_buffer_object(ctx, &ctx->CopyWriteBuffer, NULL);
646
647 _mesa_reference_buffer_object(ctx, &ctx->UniformBuffer, NULL);
648
649 for (i = 0; i < ctx->Const.MaxUniformBufferBindings; i++) {
650 _mesa_reference_buffer_object(ctx,
651 &ctx->UniformBufferBindings[i].BufferObject,
652 NULL);
653 }
654
655 free(ctx->UniformBufferBindings);
656 ctx->UniformBufferBindings = NULL;
657 }
658
659
660 /**
661 * Bind the specified target to buffer for the specified context.
662 * Called by glBindBuffer() and other functions.
663 */
664 static void
665 bind_buffer_object(struct gl_context *ctx, GLenum target, GLuint buffer)
666 {
667 struct gl_buffer_object *oldBufObj;
668 struct gl_buffer_object *newBufObj = NULL;
669 struct gl_buffer_object **bindTarget = NULL;
670
671 bindTarget = get_buffer_target(ctx, target);
672 if (!bindTarget) {
673 _mesa_error(ctx, GL_INVALID_ENUM, "glBindBufferARB(target 0x%x)", target);
674 return;
675 }
676
677 /* Get pointer to old buffer object (to be unbound) */
678 oldBufObj = *bindTarget;
679 if (oldBufObj && oldBufObj->Name == buffer && !oldBufObj->DeletePending)
680 return; /* rebinding the same buffer object- no change */
681
682 /*
683 * Get pointer to new buffer object (newBufObj)
684 */
685 if (buffer == 0) {
686 /* The spec says there's not a buffer object named 0, but we use
687 * one internally because it simplifies things.
688 */
689 newBufObj = ctx->Shared->NullBufferObj;
690 }
691 else {
692 /* non-default buffer object */
693 newBufObj = _mesa_lookup_bufferobj(ctx, buffer);
694 if (!newBufObj || newBufObj == &DummyBufferObject) {
695 /* If this is a new buffer object id, or one which was generated but
696 * never used before, allocate a buffer object now.
697 */
698 ASSERT(ctx->Driver.NewBufferObject);
699 newBufObj = ctx->Driver.NewBufferObject(ctx, buffer, target);
700 if (!newBufObj) {
701 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindBufferARB");
702 return;
703 }
704 _mesa_HashInsert(ctx->Shared->BufferObjects, buffer, newBufObj);
705 }
706 }
707
708 /* bind new buffer */
709 _mesa_reference_buffer_object(ctx, bindTarget, newBufObj);
710
711 /* Pass BindBuffer call to device driver */
712 if (ctx->Driver.BindBuffer)
713 ctx->Driver.BindBuffer( ctx, target, newBufObj );
714 }
715
716
717 /**
718 * Update the default buffer objects in the given context to reference those
719 * specified in the shared state and release those referencing the old
720 * shared state.
721 */
722 void
723 _mesa_update_default_objects_buffer_objects(struct gl_context *ctx)
724 {
725 /* Bind the NullBufferObj to remove references to those
726 * in the shared context hash table.
727 */
728 bind_buffer_object( ctx, GL_ARRAY_BUFFER_ARB, 0);
729 bind_buffer_object( ctx, GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
730 bind_buffer_object( ctx, GL_PIXEL_PACK_BUFFER_ARB, 0);
731 bind_buffer_object( ctx, GL_PIXEL_UNPACK_BUFFER_ARB, 0);
732 }
733
734
735
736 /**
737 * Return the gl_buffer_object for the given ID.
738 * Always return NULL for ID 0.
739 */
740 struct gl_buffer_object *
741 _mesa_lookup_bufferobj(struct gl_context *ctx, GLuint buffer)
742 {
743 if (buffer == 0)
744 return NULL;
745 else
746 return (struct gl_buffer_object *)
747 _mesa_HashLookup(ctx->Shared->BufferObjects, buffer);
748 }
749
750
751 /**
752 * If *ptr points to obj, set ptr = the Null/default buffer object.
753 * This is a helper for buffer object deletion.
754 * The GL spec says that deleting a buffer object causes it to get
755 * unbound from all arrays in the current context.
756 */
757 static void
758 unbind(struct gl_context *ctx,
759 struct gl_buffer_object **ptr,
760 struct gl_buffer_object *obj)
761 {
762 if (*ptr == obj) {
763 _mesa_reference_buffer_object(ctx, ptr, ctx->Shared->NullBufferObj);
764 }
765 }
766
767
768 /**
769 * Plug default/fallback buffer object functions into the device
770 * driver hooks.
771 */
772 void
773 _mesa_init_buffer_object_functions(struct dd_function_table *driver)
774 {
775 /* GL_ARB_vertex/pixel_buffer_object */
776 driver->NewBufferObject = _mesa_new_buffer_object;
777 driver->DeleteBuffer = _mesa_delete_buffer_object;
778 driver->BindBuffer = NULL;
779 driver->BufferData = _mesa_buffer_data;
780 driver->BufferSubData = _mesa_buffer_subdata;
781 driver->GetBufferSubData = _mesa_buffer_get_subdata;
782 driver->UnmapBuffer = _mesa_buffer_unmap;
783
784 /* GL_ARB_map_buffer_range */
785 driver->MapBufferRange = _mesa_buffer_map_range;
786 driver->FlushMappedBufferRange = _mesa_buffer_flush_mapped_range;
787
788 /* GL_ARB_copy_buffer */
789 driver->CopyBufferSubData = _mesa_copy_buffer_subdata;
790 }
791
792
793
794 /**********************************************************************/
795 /* API Functions */
796 /**********************************************************************/
797
798 void GLAPIENTRY
799 _mesa_BindBufferARB(GLenum target, GLuint buffer)
800 {
801 GET_CURRENT_CONTEXT(ctx);
802 ASSERT_OUTSIDE_BEGIN_END(ctx);
803
804 if (MESA_VERBOSE & VERBOSE_API)
805 _mesa_debug(ctx, "glBindBuffer(%s, %u)\n",
806 _mesa_lookup_enum_by_nr(target), buffer);
807
808 bind_buffer_object(ctx, target, buffer);
809 }
810
811
812 /**
813 * Delete a set of buffer objects.
814 *
815 * \param n Number of buffer objects to delete.
816 * \param ids Array of \c n buffer object IDs.
817 */
818 void GLAPIENTRY
819 _mesa_DeleteBuffersARB(GLsizei n, const GLuint *ids)
820 {
821 GET_CURRENT_CONTEXT(ctx);
822 GLsizei i;
823 ASSERT_OUTSIDE_BEGIN_END(ctx);
824 FLUSH_VERTICES(ctx, 0);
825
826 if (n < 0) {
827 _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteBuffersARB(n)");
828 return;
829 }
830
831 _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
832
833 for (i = 0; i < n; i++) {
834 struct gl_buffer_object *bufObj = _mesa_lookup_bufferobj(ctx, ids[i]);
835 if (bufObj) {
836 struct gl_array_object *arrayObj = ctx->Array.ArrayObj;
837 GLuint j;
838
839 ASSERT(bufObj->Name == ids[i] || bufObj == &DummyBufferObject);
840
841 if (_mesa_bufferobj_mapped(bufObj)) {
842 /* if mapped, unmap it now */
843 ctx->Driver.UnmapBuffer(ctx, bufObj);
844 bufObj->AccessFlags = default_access_mode(ctx);
845 bufObj->Pointer = NULL;
846 }
847
848 /* unbind any vertex pointers bound to this buffer */
849 for (j = 0; j < Elements(arrayObj->VertexAttrib); j++) {
850 unbind(ctx, &arrayObj->VertexAttrib[j].BufferObj, bufObj);
851 }
852
853 if (ctx->Array.ArrayBufferObj == bufObj) {
854 _mesa_BindBufferARB( GL_ARRAY_BUFFER_ARB, 0 );
855 }
856 if (arrayObj->ElementArrayBufferObj == bufObj) {
857 _mesa_BindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, 0 );
858 }
859
860 /* unbind ARB_copy_buffer binding points */
861 if (ctx->CopyReadBuffer == bufObj) {
862 _mesa_BindBufferARB( GL_COPY_READ_BUFFER, 0 );
863 }
864 if (ctx->CopyWriteBuffer == bufObj) {
865 _mesa_BindBufferARB( GL_COPY_WRITE_BUFFER, 0 );
866 }
867
868 /* unbind transform feedback binding points */
869 if (ctx->TransformFeedback.CurrentBuffer == bufObj) {
870 _mesa_BindBufferARB( GL_TRANSFORM_FEEDBACK_BUFFER, 0 );
871 }
872 for (j = 0; j < MAX_FEEDBACK_ATTRIBS; j++) {
873 if (ctx->TransformFeedback.CurrentObject->Buffers[j] == bufObj) {
874 _mesa_BindBufferBase( GL_TRANSFORM_FEEDBACK_BUFFER, j, 0 );
875 }
876 }
877
878 if (ctx->UniformBuffer == bufObj) {
879 _mesa_BindBufferARB( GL_UNIFORM_BUFFER, 0 );
880 }
881
882 /* unbind any pixel pack/unpack pointers bound to this buffer */
883 if (ctx->Pack.BufferObj == bufObj) {
884 _mesa_BindBufferARB( GL_PIXEL_PACK_BUFFER_EXT, 0 );
885 }
886 if (ctx->Unpack.BufferObj == bufObj) {
887 _mesa_BindBufferARB( GL_PIXEL_UNPACK_BUFFER_EXT, 0 );
888 }
889
890 if (ctx->Texture.BufferObject == bufObj) {
891 _mesa_BindBufferARB( GL_TEXTURE_BUFFER, 0 );
892 }
893
894 /* The ID is immediately freed for re-use */
895 _mesa_HashRemove(ctx->Shared->BufferObjects, ids[i]);
896 /* Make sure we do not run into the classic ABA problem on bind.
897 * We don't want to allow re-binding a buffer object that's been
898 * "deleted" by glDeleteBuffers().
899 *
900 * The explicit rebinding to the default object in the current context
901 * prevents the above in the current context, but another context
902 * sharing the same objects might suffer from this problem.
903 * The alternative would be to do the hash lookup in any case on bind
904 * which would introduce more runtime overhead than this.
905 */
906 bufObj->DeletePending = GL_TRUE;
907 _mesa_reference_buffer_object(ctx, &bufObj, NULL);
908 }
909 }
910
911 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
912 }
913
914
915 /**
916 * Generate a set of unique buffer object IDs and store them in \c buffer.
917 *
918 * \param n Number of IDs to generate.
919 * \param buffer Array of \c n locations to store the IDs.
920 */
921 void GLAPIENTRY
922 _mesa_GenBuffersARB(GLsizei n, GLuint *buffer)
923 {
924 GET_CURRENT_CONTEXT(ctx);
925 GLuint first;
926 GLint i;
927 ASSERT_OUTSIDE_BEGIN_END(ctx);
928
929 if (MESA_VERBOSE & VERBOSE_API)
930 _mesa_debug(ctx, "glGenBuffers(%d)\n", n);
931
932 if (n < 0) {
933 _mesa_error(ctx, GL_INVALID_VALUE, "glGenBuffersARB");
934 return;
935 }
936
937 if (!buffer) {
938 return;
939 }
940
941 /*
942 * This must be atomic (generation and allocation of buffer object IDs)
943 */
944 _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
945
946 first = _mesa_HashFindFreeKeyBlock(ctx->Shared->BufferObjects, n);
947
948 /* Insert the ID and pointer to dummy buffer object into hash table */
949 for (i = 0; i < n; i++) {
950 _mesa_HashInsert(ctx->Shared->BufferObjects, first + i,
951 &DummyBufferObject);
952 buffer[i] = first + i;
953 }
954
955 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
956 }
957
958
959 /**
960 * Determine if ID is the name of a buffer object.
961 *
962 * \param id ID of the potential buffer object.
963 * \return \c GL_TRUE if \c id is the name of a buffer object,
964 * \c GL_FALSE otherwise.
965 */
966 GLboolean GLAPIENTRY
967 _mesa_IsBufferARB(GLuint id)
968 {
969 struct gl_buffer_object *bufObj;
970 GET_CURRENT_CONTEXT(ctx);
971 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
972
973 _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
974 bufObj = _mesa_lookup_bufferobj(ctx, id);
975 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
976
977 return bufObj && bufObj != &DummyBufferObject;
978 }
979
980
981 void GLAPIENTRY
982 _mesa_BufferDataARB(GLenum target, GLsizeiptrARB size,
983 const GLvoid * data, GLenum usage)
984 {
985 GET_CURRENT_CONTEXT(ctx);
986 struct gl_buffer_object *bufObj;
987 ASSERT_OUTSIDE_BEGIN_END(ctx);
988
989 if (MESA_VERBOSE & VERBOSE_API)
990 _mesa_debug(ctx, "glBufferData(%s, %ld, %p, %s)\n",
991 _mesa_lookup_enum_by_nr(target),
992 (long int) size, data,
993 _mesa_lookup_enum_by_nr(usage));
994
995 if (size < 0) {
996 _mesa_error(ctx, GL_INVALID_VALUE, "glBufferDataARB(size < 0)");
997 return;
998 }
999
1000 switch (usage) {
1001 case GL_STREAM_DRAW_ARB:
1002 case GL_STREAM_READ_ARB:
1003 case GL_STREAM_COPY_ARB:
1004 case GL_STATIC_DRAW_ARB:
1005 case GL_STATIC_READ_ARB:
1006 case GL_STATIC_COPY_ARB:
1007 case GL_DYNAMIC_DRAW_ARB:
1008 case GL_DYNAMIC_READ_ARB:
1009 case GL_DYNAMIC_COPY_ARB:
1010 /* OK */
1011 break;
1012 default:
1013 _mesa_error(ctx, GL_INVALID_ENUM, "glBufferDataARB(usage)");
1014 return;
1015 }
1016
1017 bufObj = get_buffer(ctx, "glBufferDataARB", target);
1018 if (!bufObj)
1019 return;
1020
1021 if (_mesa_bufferobj_mapped(bufObj)) {
1022 /* Unmap the existing buffer. We'll replace it now. Not an error. */
1023 ctx->Driver.UnmapBuffer(ctx, bufObj);
1024 bufObj->AccessFlags = default_access_mode(ctx);
1025 ASSERT(bufObj->Pointer == NULL);
1026 }
1027
1028 FLUSH_VERTICES(ctx, _NEW_BUFFER_OBJECT);
1029
1030 bufObj->Written = GL_TRUE;
1031
1032 #ifdef VBO_DEBUG
1033 printf("glBufferDataARB(%u, sz %ld, from %p, usage 0x%x)\n",
1034 bufObj->Name, size, data, usage);
1035 #endif
1036
1037 #ifdef BOUNDS_CHECK
1038 size += 100;
1039 #endif
1040
1041 ASSERT(ctx->Driver.BufferData);
1042 if (!ctx->Driver.BufferData( ctx, target, size, data, usage, bufObj )) {
1043 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBufferDataARB()");
1044 }
1045 }
1046
1047
1048 void GLAPIENTRY
1049 _mesa_BufferSubDataARB(GLenum target, GLintptrARB offset,
1050 GLsizeiptrARB size, const GLvoid * data)
1051 {
1052 GET_CURRENT_CONTEXT(ctx);
1053 struct gl_buffer_object *bufObj;
1054 ASSERT_OUTSIDE_BEGIN_END(ctx);
1055
1056 bufObj = buffer_object_subdata_range_good( ctx, target, offset, size,
1057 "glBufferSubDataARB" );
1058 if (!bufObj) {
1059 /* error already recorded */
1060 return;
1061 }
1062
1063 if (size == 0)
1064 return;
1065
1066 bufObj->Written = GL_TRUE;
1067
1068 ASSERT(ctx->Driver.BufferSubData);
1069 ctx->Driver.BufferSubData( ctx, offset, size, data, bufObj );
1070 }
1071
1072
1073 void GLAPIENTRY
1074 _mesa_GetBufferSubDataARB(GLenum target, GLintptrARB offset,
1075 GLsizeiptrARB size, void * data)
1076 {
1077 GET_CURRENT_CONTEXT(ctx);
1078 struct gl_buffer_object *bufObj;
1079 ASSERT_OUTSIDE_BEGIN_END(ctx);
1080
1081 bufObj = buffer_object_subdata_range_good( ctx, target, offset, size,
1082 "glGetBufferSubDataARB" );
1083 if (!bufObj) {
1084 /* error already recorded */
1085 return;
1086 }
1087
1088 ASSERT(ctx->Driver.GetBufferSubData);
1089 ctx->Driver.GetBufferSubData( ctx, offset, size, data, bufObj );
1090 }
1091
1092
1093 void * GLAPIENTRY
1094 _mesa_MapBufferARB(GLenum target, GLenum access)
1095 {
1096 GET_CURRENT_CONTEXT(ctx);
1097 struct gl_buffer_object * bufObj;
1098 GLbitfield accessFlags;
1099 void *map;
1100
1101 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, NULL);
1102
1103 switch (access) {
1104 case GL_READ_ONLY_ARB:
1105 accessFlags = GL_MAP_READ_BIT;
1106 break;
1107 case GL_WRITE_ONLY_ARB:
1108 accessFlags = GL_MAP_WRITE_BIT;
1109 break;
1110 case GL_READ_WRITE_ARB:
1111 accessFlags = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT;
1112 break;
1113 default:
1114 _mesa_error(ctx, GL_INVALID_ENUM, "glMapBufferARB(access)");
1115 return NULL;
1116 }
1117
1118 bufObj = get_buffer(ctx, "glMapBufferARB", target);
1119 if (!bufObj)
1120 return NULL;
1121
1122 if (_mesa_bufferobj_mapped(bufObj)) {
1123 _mesa_error(ctx, GL_INVALID_OPERATION, "glMapBufferARB(already mapped)");
1124 return NULL;
1125 }
1126
1127 if (!bufObj->Size) {
1128 _mesa_error(ctx, GL_OUT_OF_MEMORY,
1129 "glMapBuffer(buffer size = 0)");
1130 return NULL;
1131 }
1132
1133 ASSERT(ctx->Driver.MapBufferRange);
1134 map = ctx->Driver.MapBufferRange(ctx, 0, bufObj->Size, accessFlags, bufObj);
1135 if (!map) {
1136 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glMapBufferARB(map failed)");
1137 return NULL;
1138 }
1139 else {
1140 /* The driver callback should have set these fields.
1141 * This is important because other modules (like VBO) might call
1142 * the driver function directly.
1143 */
1144 ASSERT(bufObj->Pointer == map);
1145 ASSERT(bufObj->Length == bufObj->Size);
1146 ASSERT(bufObj->Offset == 0);
1147 bufObj->AccessFlags = accessFlags;
1148 }
1149
1150 if (access == GL_WRITE_ONLY_ARB || access == GL_READ_WRITE_ARB)
1151 bufObj->Written = GL_TRUE;
1152
1153 #ifdef VBO_DEBUG
1154 printf("glMapBufferARB(%u, sz %ld, access 0x%x)\n",
1155 bufObj->Name, bufObj->Size, access);
1156 if (access == GL_WRITE_ONLY_ARB) {
1157 GLuint i;
1158 GLubyte *b = (GLubyte *) bufObj->Pointer;
1159 for (i = 0; i < bufObj->Size; i++)
1160 b[i] = i & 0xff;
1161 }
1162 #endif
1163
1164 #ifdef BOUNDS_CHECK
1165 {
1166 GLubyte *buf = (GLubyte *) bufObj->Pointer;
1167 GLuint i;
1168 /* buffer is 100 bytes larger than requested, fill with magic value */
1169 for (i = 0; i < 100; i++) {
1170 buf[bufObj->Size - i - 1] = 123;
1171 }
1172 }
1173 #endif
1174
1175 return bufObj->Pointer;
1176 }
1177
1178
1179 GLboolean GLAPIENTRY
1180 _mesa_UnmapBufferARB(GLenum target)
1181 {
1182 GET_CURRENT_CONTEXT(ctx);
1183 struct gl_buffer_object *bufObj;
1184 GLboolean status = GL_TRUE;
1185 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
1186
1187 bufObj = get_buffer(ctx, "glUnmapBufferARB", target);
1188 if (!bufObj)
1189 return GL_FALSE;
1190
1191 if (!_mesa_bufferobj_mapped(bufObj)) {
1192 _mesa_error(ctx, GL_INVALID_OPERATION, "glUnmapBufferARB");
1193 return GL_FALSE;
1194 }
1195
1196 #ifdef BOUNDS_CHECK
1197 if (bufObj->Access != GL_READ_ONLY_ARB) {
1198 GLubyte *buf = (GLubyte *) bufObj->Pointer;
1199 GLuint i;
1200 /* check that last 100 bytes are still = magic value */
1201 for (i = 0; i < 100; i++) {
1202 GLuint pos = bufObj->Size - i - 1;
1203 if (buf[pos] != 123) {
1204 _mesa_warning(ctx, "Out of bounds buffer object write detected"
1205 " at position %d (value = %u)\n",
1206 pos, buf[pos]);
1207 }
1208 }
1209 }
1210 #endif
1211
1212 #ifdef VBO_DEBUG
1213 if (bufObj->AccessFlags & GL_MAP_WRITE_BIT) {
1214 GLuint i, unchanged = 0;
1215 GLubyte *b = (GLubyte *) bufObj->Pointer;
1216 GLint pos = -1;
1217 /* check which bytes changed */
1218 for (i = 0; i < bufObj->Size - 1; i++) {
1219 if (b[i] == (i & 0xff) && b[i+1] == ((i+1) & 0xff)) {
1220 unchanged++;
1221 if (pos == -1)
1222 pos = i;
1223 }
1224 }
1225 if (unchanged) {
1226 printf("glUnmapBufferARB(%u): %u of %ld unchanged, starting at %d\n",
1227 bufObj->Name, unchanged, bufObj->Size, pos);
1228 }
1229 }
1230 #endif
1231
1232 status = ctx->Driver.UnmapBuffer( ctx, bufObj );
1233 bufObj->AccessFlags = default_access_mode(ctx);
1234 ASSERT(bufObj->Pointer == NULL);
1235 ASSERT(bufObj->Offset == 0);
1236 ASSERT(bufObj->Length == 0);
1237
1238 return status;
1239 }
1240
1241
1242 void GLAPIENTRY
1243 _mesa_GetBufferParameterivARB(GLenum target, GLenum pname, GLint *params)
1244 {
1245 GET_CURRENT_CONTEXT(ctx);
1246 struct gl_buffer_object *bufObj;
1247 ASSERT_OUTSIDE_BEGIN_END(ctx);
1248
1249 bufObj = get_buffer(ctx, "glGetBufferParameterivARB", target);
1250 if (!bufObj)
1251 return;
1252
1253 switch (pname) {
1254 case GL_BUFFER_SIZE_ARB:
1255 *params = (GLint) bufObj->Size;
1256 return;
1257 case GL_BUFFER_USAGE_ARB:
1258 *params = bufObj->Usage;
1259 return;
1260 case GL_BUFFER_ACCESS_ARB:
1261 *params = simplified_access_mode(bufObj->AccessFlags);
1262 return;
1263 case GL_BUFFER_MAPPED_ARB:
1264 *params = _mesa_bufferobj_mapped(bufObj);
1265 return;
1266 case GL_BUFFER_ACCESS_FLAGS:
1267 if (!ctx->Extensions.ARB_map_buffer_range)
1268 goto invalid_pname;
1269 *params = bufObj->AccessFlags;
1270 return;
1271 case GL_BUFFER_MAP_OFFSET:
1272 if (!ctx->Extensions.ARB_map_buffer_range)
1273 goto invalid_pname;
1274 *params = (GLint) bufObj->Offset;
1275 return;
1276 case GL_BUFFER_MAP_LENGTH:
1277 if (!ctx->Extensions.ARB_map_buffer_range)
1278 goto invalid_pname;
1279 *params = (GLint) bufObj->Length;
1280 return;
1281 default:
1282 ; /* fall-through */
1283 }
1284
1285 invalid_pname:
1286 _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferParameterivARB(pname=%s)",
1287 _mesa_lookup_enum_by_nr(pname));
1288 }
1289
1290
1291 /**
1292 * New in GL 3.2
1293 * This is pretty much a duplicate of GetBufferParameteriv() but the
1294 * GL_BUFFER_SIZE_ARB attribute will be 64-bits on a 64-bit system.
1295 */
1296 void GLAPIENTRY
1297 _mesa_GetBufferParameteri64v(GLenum target, GLenum pname, GLint64 *params)
1298 {
1299 GET_CURRENT_CONTEXT(ctx);
1300 struct gl_buffer_object *bufObj;
1301 ASSERT_OUTSIDE_BEGIN_END(ctx);
1302
1303 bufObj = get_buffer(ctx, "glGetBufferParameteri64v", target);
1304 if (!bufObj)
1305 return;
1306
1307 switch (pname) {
1308 case GL_BUFFER_SIZE_ARB:
1309 *params = bufObj->Size;
1310 return;
1311 case GL_BUFFER_USAGE_ARB:
1312 *params = bufObj->Usage;
1313 return;
1314 case GL_BUFFER_ACCESS_ARB:
1315 *params = simplified_access_mode(bufObj->AccessFlags);
1316 return;
1317 case GL_BUFFER_ACCESS_FLAGS:
1318 if (!ctx->Extensions.ARB_map_buffer_range)
1319 goto invalid_pname;
1320 *params = bufObj->AccessFlags;
1321 return;
1322 case GL_BUFFER_MAPPED_ARB:
1323 *params = _mesa_bufferobj_mapped(bufObj);
1324 return;
1325 case GL_BUFFER_MAP_OFFSET:
1326 if (!ctx->Extensions.ARB_map_buffer_range)
1327 goto invalid_pname;
1328 *params = bufObj->Offset;
1329 return;
1330 case GL_BUFFER_MAP_LENGTH:
1331 if (!ctx->Extensions.ARB_map_buffer_range)
1332 goto invalid_pname;
1333 *params = bufObj->Length;
1334 return;
1335 default:
1336 ; /* fall-through */
1337 }
1338
1339 invalid_pname:
1340 _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferParameteri64v(pname=%s)",
1341 _mesa_lookup_enum_by_nr(pname));
1342 }
1343
1344
1345 void GLAPIENTRY
1346 _mesa_GetBufferPointervARB(GLenum target, GLenum pname, GLvoid **params)
1347 {
1348 GET_CURRENT_CONTEXT(ctx);
1349 struct gl_buffer_object * bufObj;
1350 ASSERT_OUTSIDE_BEGIN_END(ctx);
1351
1352 if (pname != GL_BUFFER_MAP_POINTER_ARB) {
1353 _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferPointervARB(pname)");
1354 return;
1355 }
1356
1357 bufObj = get_buffer(ctx, "glGetBufferPointervARB", target);
1358 if (!bufObj)
1359 return;
1360
1361 *params = bufObj->Pointer;
1362 }
1363
1364
1365 void GLAPIENTRY
1366 _mesa_CopyBufferSubData(GLenum readTarget, GLenum writeTarget,
1367 GLintptr readOffset, GLintptr writeOffset,
1368 GLsizeiptr size)
1369 {
1370 GET_CURRENT_CONTEXT(ctx);
1371 struct gl_buffer_object *src, *dst;
1372 ASSERT_OUTSIDE_BEGIN_END(ctx);
1373
1374 src = get_buffer(ctx, "glCopyBufferSubData", readTarget);
1375 if (!src)
1376 return;
1377
1378 dst = get_buffer(ctx, "glCopyBufferSubData", writeTarget);
1379 if (!dst)
1380 return;
1381
1382 if (_mesa_bufferobj_mapped(src)) {
1383 _mesa_error(ctx, GL_INVALID_OPERATION,
1384 "glCopyBufferSubData(readBuffer is mapped)");
1385 return;
1386 }
1387
1388 if (_mesa_bufferobj_mapped(dst)) {
1389 _mesa_error(ctx, GL_INVALID_OPERATION,
1390 "glCopyBufferSubData(writeBuffer is mapped)");
1391 return;
1392 }
1393
1394 if (readOffset < 0) {
1395 _mesa_error(ctx, GL_INVALID_VALUE,
1396 "glCopyBufferSubData(readOffset = %d)", (int) readOffset);
1397 return;
1398 }
1399
1400 if (writeOffset < 0) {
1401 _mesa_error(ctx, GL_INVALID_VALUE,
1402 "glCopyBufferSubData(writeOffset = %d)", (int) writeOffset);
1403 return;
1404 }
1405
1406 if (size < 0) {
1407 _mesa_error(ctx, GL_INVALID_VALUE,
1408 "glCopyBufferSubData(writeOffset = %d)", (int) size);
1409 return;
1410 }
1411
1412 if (readOffset + size > src->Size) {
1413 _mesa_error(ctx, GL_INVALID_VALUE,
1414 "glCopyBufferSubData(readOffset + size = %d)",
1415 (int) (readOffset + size));
1416 return;
1417 }
1418
1419 if (writeOffset + size > dst->Size) {
1420 _mesa_error(ctx, GL_INVALID_VALUE,
1421 "glCopyBufferSubData(writeOffset + size = %d)",
1422 (int) (writeOffset + size));
1423 return;
1424 }
1425
1426 if (src == dst) {
1427 if (readOffset + size <= writeOffset) {
1428 /* OK */
1429 }
1430 else if (writeOffset + size <= readOffset) {
1431 /* OK */
1432 }
1433 else {
1434 /* overlapping src/dst is illegal */
1435 _mesa_error(ctx, GL_INVALID_VALUE,
1436 "glCopyBufferSubData(overlapping src/dst)");
1437 return;
1438 }
1439 }
1440
1441 ctx->Driver.CopyBufferSubData(ctx, src, dst, readOffset, writeOffset, size);
1442 }
1443
1444
1445 /**
1446 * See GL_ARB_map_buffer_range spec
1447 */
1448 void * GLAPIENTRY
1449 _mesa_MapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length,
1450 GLbitfield access)
1451 {
1452 GET_CURRENT_CONTEXT(ctx);
1453 struct gl_buffer_object *bufObj;
1454 void *map;
1455
1456 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, NULL);
1457
1458 if (!ctx->Extensions.ARB_map_buffer_range) {
1459 _mesa_error(ctx, GL_INVALID_OPERATION,
1460 "glMapBufferRange(extension not supported)");
1461 return NULL;
1462 }
1463
1464 if (offset < 0) {
1465 _mesa_error(ctx, GL_INVALID_VALUE,
1466 "glMapBufferRange(offset = %ld)", (long)offset);
1467 return NULL;
1468 }
1469
1470 if (length < 0) {
1471 _mesa_error(ctx, GL_INVALID_VALUE,
1472 "glMapBufferRange(length = %ld)", (long)length);
1473 return NULL;
1474 }
1475
1476 if (access & ~(GL_MAP_READ_BIT |
1477 GL_MAP_WRITE_BIT |
1478 GL_MAP_INVALIDATE_RANGE_BIT |
1479 GL_MAP_INVALIDATE_BUFFER_BIT |
1480 GL_MAP_FLUSH_EXPLICIT_BIT |
1481 GL_MAP_UNSYNCHRONIZED_BIT)) {
1482 /* generate an error if any undefind bit is set */
1483 _mesa_error(ctx, GL_INVALID_VALUE, "glMapBufferRange(access)");
1484 return NULL;
1485 }
1486
1487 if ((access & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)) == 0) {
1488 _mesa_error(ctx, GL_INVALID_OPERATION,
1489 "glMapBufferRange(access indicates neither read or write)");
1490 return NULL;
1491 }
1492
1493 if ((access & GL_MAP_READ_BIT) &&
1494 (access & (GL_MAP_INVALIDATE_RANGE_BIT |
1495 GL_MAP_INVALIDATE_BUFFER_BIT |
1496 GL_MAP_UNSYNCHRONIZED_BIT))) {
1497 _mesa_error(ctx, GL_INVALID_OPERATION,
1498 "glMapBufferRange(invalid access flags)");
1499 return NULL;
1500 }
1501
1502 if ((access & GL_MAP_FLUSH_EXPLICIT_BIT) &&
1503 ((access & GL_MAP_WRITE_BIT) == 0)) {
1504 _mesa_error(ctx, GL_INVALID_OPERATION,
1505 "glMapBufferRange(invalid access flags)");
1506 return NULL;
1507 }
1508
1509 bufObj = get_buffer(ctx, "glMapBufferRange", target);
1510 if (!bufObj)
1511 return NULL;
1512
1513 if (offset + length > bufObj->Size) {
1514 _mesa_error(ctx, GL_INVALID_VALUE,
1515 "glMapBufferRange(offset + length > size)");
1516 return NULL;
1517 }
1518
1519 if (_mesa_bufferobj_mapped(bufObj)) {
1520 _mesa_error(ctx, GL_INVALID_OPERATION,
1521 "glMapBufferRange(buffer already mapped)");
1522 return NULL;
1523 }
1524
1525 if (!bufObj->Size) {
1526 _mesa_error(ctx, GL_OUT_OF_MEMORY,
1527 "glMapBufferRange(buffer size = 0)");
1528 return NULL;
1529 }
1530
1531 /* Mapping zero bytes should return a non-null pointer. */
1532 if (!length) {
1533 static long dummy = 0;
1534 bufObj->Pointer = &dummy;
1535 bufObj->Length = length;
1536 bufObj->Offset = offset;
1537 bufObj->AccessFlags = access;
1538 return bufObj->Pointer;
1539 }
1540
1541 ASSERT(ctx->Driver.MapBufferRange);
1542 map = ctx->Driver.MapBufferRange(ctx, offset, length, access, bufObj);
1543 if (!map) {
1544 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glMapBufferARB(map failed)");
1545 }
1546 else {
1547 /* The driver callback should have set all these fields.
1548 * This is important because other modules (like VBO) might call
1549 * the driver function directly.
1550 */
1551 ASSERT(bufObj->Pointer == map);
1552 ASSERT(bufObj->Length == length);
1553 ASSERT(bufObj->Offset == offset);
1554 ASSERT(bufObj->AccessFlags == access);
1555 }
1556
1557 return map;
1558 }
1559
1560
1561 /**
1562 * See GL_ARB_map_buffer_range spec
1563 */
1564 void GLAPIENTRY
1565 _mesa_FlushMappedBufferRange(GLenum target, GLintptr offset, GLsizeiptr length)
1566 {
1567 GET_CURRENT_CONTEXT(ctx);
1568 struct gl_buffer_object *bufObj;
1569 ASSERT_OUTSIDE_BEGIN_END(ctx);
1570
1571 if (!ctx->Extensions.ARB_map_buffer_range) {
1572 _mesa_error(ctx, GL_INVALID_OPERATION,
1573 "glFlushMappedBufferRange(extension not supported)");
1574 return;
1575 }
1576
1577 if (offset < 0) {
1578 _mesa_error(ctx, GL_INVALID_VALUE,
1579 "glFlushMappedBufferRange(offset = %ld)", (long)offset);
1580 return;
1581 }
1582
1583 if (length < 0) {
1584 _mesa_error(ctx, GL_INVALID_VALUE,
1585 "glFlushMappedBufferRange(length = %ld)", (long)length);
1586 return;
1587 }
1588
1589 bufObj = get_buffer(ctx, "glFlushMappedBufferRange", target);
1590 if (!bufObj)
1591 return;
1592
1593 if (!_mesa_bufferobj_mapped(bufObj)) {
1594 /* buffer is not mapped */
1595 _mesa_error(ctx, GL_INVALID_OPERATION,
1596 "glFlushMappedBufferRange(buffer is not mapped)");
1597 return;
1598 }
1599
1600 if ((bufObj->AccessFlags & GL_MAP_FLUSH_EXPLICIT_BIT) == 0) {
1601 _mesa_error(ctx, GL_INVALID_OPERATION,
1602 "glFlushMappedBufferRange(GL_MAP_FLUSH_EXPLICIT_BIT not set)");
1603 return;
1604 }
1605
1606 if (offset + length > bufObj->Length) {
1607 _mesa_error(ctx, GL_INVALID_VALUE,
1608 "glFlushMappedBufferRange(offset %ld + length %ld > mapped length %ld)",
1609 (long)offset, (long)length, (long)bufObj->Length);
1610 return;
1611 }
1612
1613 ASSERT(bufObj->AccessFlags & GL_MAP_WRITE_BIT);
1614
1615 if (ctx->Driver.FlushMappedBufferRange)
1616 ctx->Driver.FlushMappedBufferRange(ctx, offset, length, bufObj);
1617 }
1618
1619
1620 #if FEATURE_APPLE_object_purgeable
1621 static GLenum
1622 buffer_object_purgeable(struct gl_context *ctx, GLuint name, GLenum option)
1623 {
1624 struct gl_buffer_object *bufObj;
1625 GLenum retval;
1626
1627 bufObj = _mesa_lookup_bufferobj(ctx, name);
1628 if (!bufObj) {
1629 _mesa_error(ctx, GL_INVALID_VALUE,
1630 "glObjectPurgeable(name = 0x%x)", name);
1631 return 0;
1632 }
1633 if (!_mesa_is_bufferobj(bufObj)) {
1634 _mesa_error(ctx, GL_INVALID_OPERATION, "glObjectPurgeable(buffer 0)" );
1635 return 0;
1636 }
1637
1638 if (bufObj->Purgeable) {
1639 _mesa_error(ctx, GL_INVALID_OPERATION,
1640 "glObjectPurgeable(name = 0x%x) is already purgeable", name);
1641 return GL_VOLATILE_APPLE;
1642 }
1643
1644 bufObj->Purgeable = GL_TRUE;
1645
1646 retval = GL_VOLATILE_APPLE;
1647 if (ctx->Driver.BufferObjectPurgeable)
1648 retval = ctx->Driver.BufferObjectPurgeable(ctx, bufObj, option);
1649
1650 return retval;
1651 }
1652
1653
1654 static GLenum
1655 renderbuffer_purgeable(struct gl_context *ctx, GLuint name, GLenum option)
1656 {
1657 struct gl_renderbuffer *bufObj;
1658 GLenum retval;
1659
1660 bufObj = _mesa_lookup_renderbuffer(ctx, name);
1661 if (!bufObj) {
1662 _mesa_error(ctx, GL_INVALID_VALUE,
1663 "glObjectUnpurgeable(name = 0x%x)", name);
1664 return 0;
1665 }
1666
1667 if (bufObj->Purgeable) {
1668 _mesa_error(ctx, GL_INVALID_OPERATION,
1669 "glObjectPurgeable(name = 0x%x) is already purgeable", name);
1670 return GL_VOLATILE_APPLE;
1671 }
1672
1673 bufObj->Purgeable = GL_TRUE;
1674
1675 retval = GL_VOLATILE_APPLE;
1676 if (ctx->Driver.RenderObjectPurgeable)
1677 retval = ctx->Driver.RenderObjectPurgeable(ctx, bufObj, option);
1678
1679 return retval;
1680 }
1681
1682
1683 static GLenum
1684 texture_object_purgeable(struct gl_context *ctx, GLuint name, GLenum option)
1685 {
1686 struct gl_texture_object *bufObj;
1687 GLenum retval;
1688
1689 bufObj = _mesa_lookup_texture(ctx, name);
1690 if (!bufObj) {
1691 _mesa_error(ctx, GL_INVALID_VALUE,
1692 "glObjectPurgeable(name = 0x%x)", name);
1693 return 0;
1694 }
1695
1696 if (bufObj->Purgeable) {
1697 _mesa_error(ctx, GL_INVALID_OPERATION,
1698 "glObjectPurgeable(name = 0x%x) is already purgeable", name);
1699 return GL_VOLATILE_APPLE;
1700 }
1701
1702 bufObj->Purgeable = GL_TRUE;
1703
1704 retval = GL_VOLATILE_APPLE;
1705 if (ctx->Driver.TextureObjectPurgeable)
1706 retval = ctx->Driver.TextureObjectPurgeable(ctx, bufObj, option);
1707
1708 return retval;
1709 }
1710
1711
1712 GLenum GLAPIENTRY
1713 _mesa_ObjectPurgeableAPPLE(GLenum objectType, GLuint name, GLenum option)
1714 {
1715 GLenum retval;
1716
1717 GET_CURRENT_CONTEXT(ctx);
1718 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0);
1719
1720 if (name == 0) {
1721 _mesa_error(ctx, GL_INVALID_VALUE,
1722 "glObjectPurgeable(name = 0x%x)", name);
1723 return 0;
1724 }
1725
1726 switch (option) {
1727 case GL_VOLATILE_APPLE:
1728 case GL_RELEASED_APPLE:
1729 /* legal */
1730 break;
1731 default:
1732 _mesa_error(ctx, GL_INVALID_ENUM,
1733 "glObjectPurgeable(name = 0x%x) invalid option: %d",
1734 name, option);
1735 return 0;
1736 }
1737
1738 switch (objectType) {
1739 case GL_TEXTURE:
1740 retval = texture_object_purgeable(ctx, name, option);
1741 break;
1742 case GL_RENDERBUFFER_EXT:
1743 retval = renderbuffer_purgeable(ctx, name, option);
1744 break;
1745 case GL_BUFFER_OBJECT_APPLE:
1746 retval = buffer_object_purgeable(ctx, name, option);
1747 break;
1748 default:
1749 _mesa_error(ctx, GL_INVALID_ENUM,
1750 "glObjectPurgeable(name = 0x%x) invalid type: %d",
1751 name, objectType);
1752 return 0;
1753 }
1754
1755 /* In strict conformance to the spec, we must only return VOLATILE when
1756 * when passed the VOLATILE option. Madness.
1757 *
1758 * XXX First fix the spec, then fix me.
1759 */
1760 return option == GL_VOLATILE_APPLE ? GL_VOLATILE_APPLE : retval;
1761 }
1762
1763
1764 static GLenum
1765 buffer_object_unpurgeable(struct gl_context *ctx, GLuint name, GLenum option)
1766 {
1767 struct gl_buffer_object *bufObj;
1768 GLenum retval;
1769
1770 bufObj = _mesa_lookup_bufferobj(ctx, name);
1771 if (!bufObj) {
1772 _mesa_error(ctx, GL_INVALID_VALUE,
1773 "glObjectUnpurgeable(name = 0x%x)", name);
1774 return 0;
1775 }
1776
1777 if (! bufObj->Purgeable) {
1778 _mesa_error(ctx, GL_INVALID_OPERATION,
1779 "glObjectUnpurgeable(name = 0x%x) object is "
1780 " already \"unpurged\"", name);
1781 return 0;
1782 }
1783
1784 bufObj->Purgeable = GL_FALSE;
1785
1786 retval = option;
1787 if (ctx->Driver.BufferObjectUnpurgeable)
1788 retval = ctx->Driver.BufferObjectUnpurgeable(ctx, bufObj, option);
1789
1790 return retval;
1791 }
1792
1793
1794 static GLenum
1795 renderbuffer_unpurgeable(struct gl_context *ctx, GLuint name, GLenum option)
1796 {
1797 struct gl_renderbuffer *bufObj;
1798 GLenum retval;
1799
1800 bufObj = _mesa_lookup_renderbuffer(ctx, name);
1801 if (!bufObj) {
1802 _mesa_error(ctx, GL_INVALID_VALUE,
1803 "glObjectUnpurgeable(name = 0x%x)", name);
1804 return 0;
1805 }
1806
1807 if (! bufObj->Purgeable) {
1808 _mesa_error(ctx, GL_INVALID_OPERATION,
1809 "glObjectUnpurgeable(name = 0x%x) object is "
1810 " already \"unpurged\"", name);
1811 return 0;
1812 }
1813
1814 bufObj->Purgeable = GL_FALSE;
1815
1816 retval = option;
1817 if (ctx->Driver.RenderObjectUnpurgeable)
1818 retval = ctx->Driver.RenderObjectUnpurgeable(ctx, bufObj, option);
1819
1820 return retval;
1821 }
1822
1823
1824 static GLenum
1825 texture_object_unpurgeable(struct gl_context *ctx, GLuint name, GLenum option)
1826 {
1827 struct gl_texture_object *bufObj;
1828 GLenum retval;
1829
1830 bufObj = _mesa_lookup_texture(ctx, name);
1831 if (!bufObj) {
1832 _mesa_error(ctx, GL_INVALID_VALUE,
1833 "glObjectUnpurgeable(name = 0x%x)", name);
1834 return 0;
1835 }
1836
1837 if (! bufObj->Purgeable) {
1838 _mesa_error(ctx, GL_INVALID_OPERATION,
1839 "glObjectUnpurgeable(name = 0x%x) object is"
1840 " already \"unpurged\"", name);
1841 return 0;
1842 }
1843
1844 bufObj->Purgeable = GL_FALSE;
1845
1846 retval = option;
1847 if (ctx->Driver.TextureObjectUnpurgeable)
1848 retval = ctx->Driver.TextureObjectUnpurgeable(ctx, bufObj, option);
1849
1850 return retval;
1851 }
1852
1853
1854 GLenum GLAPIENTRY
1855 _mesa_ObjectUnpurgeableAPPLE(GLenum objectType, GLuint name, GLenum option)
1856 {
1857 GET_CURRENT_CONTEXT(ctx);
1858 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0);
1859
1860 if (name == 0) {
1861 _mesa_error(ctx, GL_INVALID_VALUE,
1862 "glObjectUnpurgeable(name = 0x%x)", name);
1863 return 0;
1864 }
1865
1866 switch (option) {
1867 case GL_RETAINED_APPLE:
1868 case GL_UNDEFINED_APPLE:
1869 /* legal */
1870 break;
1871 default:
1872 _mesa_error(ctx, GL_INVALID_ENUM,
1873 "glObjectUnpurgeable(name = 0x%x) invalid option: %d",
1874 name, option);
1875 return 0;
1876 }
1877
1878 switch (objectType) {
1879 case GL_BUFFER_OBJECT_APPLE:
1880 return buffer_object_unpurgeable(ctx, name, option);
1881 case GL_TEXTURE:
1882 return texture_object_unpurgeable(ctx, name, option);
1883 case GL_RENDERBUFFER_EXT:
1884 return renderbuffer_unpurgeable(ctx, name, option);
1885 default:
1886 _mesa_error(ctx, GL_INVALID_ENUM,
1887 "glObjectUnpurgeable(name = 0x%x) invalid type: %d",
1888 name, objectType);
1889 return 0;
1890 }
1891 }
1892
1893
1894 static void
1895 get_buffer_object_parameteriv(struct gl_context *ctx, GLuint name,
1896 GLenum pname, GLint *params)
1897 {
1898 struct gl_buffer_object *bufObj = _mesa_lookup_bufferobj(ctx, name);
1899 if (!bufObj) {
1900 _mesa_error(ctx, GL_INVALID_VALUE,
1901 "glGetObjectParameteriv(name = 0x%x) invalid object", name);
1902 return;
1903 }
1904
1905 switch (pname) {
1906 case GL_PURGEABLE_APPLE:
1907 *params = bufObj->Purgeable;
1908 break;
1909 default:
1910 _mesa_error(ctx, GL_INVALID_ENUM,
1911 "glGetObjectParameteriv(name = 0x%x) invalid enum: %d",
1912 name, pname);
1913 break;
1914 }
1915 }
1916
1917
1918 static void
1919 get_renderbuffer_parameteriv(struct gl_context *ctx, GLuint name,
1920 GLenum pname, GLint *params)
1921 {
1922 struct gl_renderbuffer *rb = _mesa_lookup_renderbuffer(ctx, name);
1923 if (!rb) {
1924 _mesa_error(ctx, GL_INVALID_VALUE,
1925 "glObjectUnpurgeable(name = 0x%x)", name);
1926 return;
1927 }
1928
1929 switch (pname) {
1930 case GL_PURGEABLE_APPLE:
1931 *params = rb->Purgeable;
1932 break;
1933 default:
1934 _mesa_error(ctx, GL_INVALID_ENUM,
1935 "glGetObjectParameteriv(name = 0x%x) invalid enum: %d",
1936 name, pname);
1937 break;
1938 }
1939 }
1940
1941
1942 static void
1943 get_texture_object_parameteriv(struct gl_context *ctx, GLuint name,
1944 GLenum pname, GLint *params)
1945 {
1946 struct gl_texture_object *texObj = _mesa_lookup_texture(ctx, name);
1947 if (!texObj) {
1948 _mesa_error(ctx, GL_INVALID_VALUE,
1949 "glObjectUnpurgeable(name = 0x%x)", name);
1950 return;
1951 }
1952
1953 switch (pname) {
1954 case GL_PURGEABLE_APPLE:
1955 *params = texObj->Purgeable;
1956 break;
1957 default:
1958 _mesa_error(ctx, GL_INVALID_ENUM,
1959 "glGetObjectParameteriv(name = 0x%x) invalid enum: %d",
1960 name, pname);
1961 break;
1962 }
1963 }
1964
1965
1966 void GLAPIENTRY
1967 _mesa_GetObjectParameterivAPPLE(GLenum objectType, GLuint name, GLenum pname,
1968 GLint *params)
1969 {
1970 GET_CURRENT_CONTEXT(ctx);
1971
1972 if (name == 0) {
1973 _mesa_error(ctx, GL_INVALID_VALUE,
1974 "glGetObjectParameteriv(name = 0x%x)", name);
1975 return;
1976 }
1977
1978 switch (objectType) {
1979 case GL_TEXTURE:
1980 get_texture_object_parameteriv(ctx, name, pname, params);
1981 break;
1982 case GL_BUFFER_OBJECT_APPLE:
1983 get_buffer_object_parameteriv(ctx, name, pname, params);
1984 break;
1985 case GL_RENDERBUFFER_EXT:
1986 get_renderbuffer_parameteriv(ctx, name, pname, params);
1987 break;
1988 default:
1989 _mesa_error(ctx, GL_INVALID_ENUM,
1990 "glGetObjectParameteriv(name = 0x%x) invalid type: %d",
1991 name, objectType);
1992 }
1993 }
1994
1995 #endif /* FEATURE_APPLE_object_purgeable */
1996
1997 void
1998 _mesa_init_bufferobj_dispatch(struct _glapi_table *disp)
1999 {
2000 SET_BindBufferARB(disp, _mesa_BindBufferARB);
2001 SET_BufferDataARB(disp, _mesa_BufferDataARB);
2002 SET_BufferSubDataARB(disp, _mesa_BufferSubDataARB);
2003 SET_DeleteBuffersARB(disp, _mesa_DeleteBuffersARB);
2004 SET_GenBuffersARB(disp, _mesa_GenBuffersARB);
2005 SET_GetBufferParameterivARB(disp, _mesa_GetBufferParameterivARB);
2006 SET_GetBufferPointervARB(disp, _mesa_GetBufferPointervARB);
2007 SET_GetBufferSubDataARB(disp, _mesa_GetBufferSubDataARB);
2008 SET_IsBufferARB(disp, _mesa_IsBufferARB);
2009 SET_MapBufferARB(disp, _mesa_MapBufferARB);
2010 SET_UnmapBufferARB(disp, _mesa_UnmapBufferARB);
2011 }