mesa: Unbind uniform buffer bindings on glDeleteBuffers().
[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 GLbitfield
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 _mesa_is_gles(ctx)
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 static void
660 handle_bind_buffer_gen(struct gl_context *ctx,
661 GLenum target,
662 GLuint buffer,
663 struct gl_buffer_object **buf_handle)
664 {
665 struct gl_buffer_object *buf = *buf_handle;
666
667 if (!buf || buf == &DummyBufferObject) {
668 /* If this is a new buffer object id, or one which was generated but
669 * never used before, allocate a buffer object now.
670 */
671 ASSERT(ctx->Driver.NewBufferObject);
672 buf = ctx->Driver.NewBufferObject(ctx, buffer, target);
673 if (!buf) {
674 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindBufferARB");
675 return;
676 }
677 _mesa_HashInsert(ctx->Shared->BufferObjects, buffer, buf);
678 *buf_handle = buf;
679 }
680 }
681
682 /**
683 * Bind the specified target to buffer for the specified context.
684 * Called by glBindBuffer() and other functions.
685 */
686 static void
687 bind_buffer_object(struct gl_context *ctx, GLenum target, GLuint buffer)
688 {
689 struct gl_buffer_object *oldBufObj;
690 struct gl_buffer_object *newBufObj = NULL;
691 struct gl_buffer_object **bindTarget = NULL;
692
693 bindTarget = get_buffer_target(ctx, target);
694 if (!bindTarget) {
695 _mesa_error(ctx, GL_INVALID_ENUM, "glBindBufferARB(target 0x%x)", target);
696 return;
697 }
698
699 /* Get pointer to old buffer object (to be unbound) */
700 oldBufObj = *bindTarget;
701 if (oldBufObj && oldBufObj->Name == buffer && !oldBufObj->DeletePending)
702 return; /* rebinding the same buffer object- no change */
703
704 /*
705 * Get pointer to new buffer object (newBufObj)
706 */
707 if (buffer == 0) {
708 /* The spec says there's not a buffer object named 0, but we use
709 * one internally because it simplifies things.
710 */
711 newBufObj = ctx->Shared->NullBufferObj;
712 }
713 else {
714 /* non-default buffer object */
715 newBufObj = _mesa_lookup_bufferobj(ctx, buffer);
716 handle_bind_buffer_gen(ctx, target, buffer, &newBufObj);
717 }
718
719 /* bind new buffer */
720 _mesa_reference_buffer_object(ctx, bindTarget, newBufObj);
721
722 /* Pass BindBuffer call to device driver */
723 if (ctx->Driver.BindBuffer)
724 ctx->Driver.BindBuffer( ctx, target, newBufObj );
725 }
726
727
728 /**
729 * Update the default buffer objects in the given context to reference those
730 * specified in the shared state and release those referencing the old
731 * shared state.
732 */
733 void
734 _mesa_update_default_objects_buffer_objects(struct gl_context *ctx)
735 {
736 /* Bind the NullBufferObj to remove references to those
737 * in the shared context hash table.
738 */
739 bind_buffer_object( ctx, GL_ARRAY_BUFFER_ARB, 0);
740 bind_buffer_object( ctx, GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
741 bind_buffer_object( ctx, GL_PIXEL_PACK_BUFFER_ARB, 0);
742 bind_buffer_object( ctx, GL_PIXEL_UNPACK_BUFFER_ARB, 0);
743 }
744
745
746
747 /**
748 * Return the gl_buffer_object for the given ID.
749 * Always return NULL for ID 0.
750 */
751 struct gl_buffer_object *
752 _mesa_lookup_bufferobj(struct gl_context *ctx, GLuint buffer)
753 {
754 if (buffer == 0)
755 return NULL;
756 else
757 return (struct gl_buffer_object *)
758 _mesa_HashLookup(ctx->Shared->BufferObjects, buffer);
759 }
760
761
762 /**
763 * If *ptr points to obj, set ptr = the Null/default buffer object.
764 * This is a helper for buffer object deletion.
765 * The GL spec says that deleting a buffer object causes it to get
766 * unbound from all arrays in the current context.
767 */
768 static void
769 unbind(struct gl_context *ctx,
770 struct gl_buffer_object **ptr,
771 struct gl_buffer_object *obj)
772 {
773 if (*ptr == obj) {
774 _mesa_reference_buffer_object(ctx, ptr, ctx->Shared->NullBufferObj);
775 }
776 }
777
778
779 /**
780 * Plug default/fallback buffer object functions into the device
781 * driver hooks.
782 */
783 void
784 _mesa_init_buffer_object_functions(struct dd_function_table *driver)
785 {
786 /* GL_ARB_vertex/pixel_buffer_object */
787 driver->NewBufferObject = _mesa_new_buffer_object;
788 driver->DeleteBuffer = _mesa_delete_buffer_object;
789 driver->BindBuffer = NULL;
790 driver->BufferData = _mesa_buffer_data;
791 driver->BufferSubData = _mesa_buffer_subdata;
792 driver->GetBufferSubData = _mesa_buffer_get_subdata;
793 driver->UnmapBuffer = _mesa_buffer_unmap;
794
795 /* GL_ARB_map_buffer_range */
796 driver->MapBufferRange = _mesa_buffer_map_range;
797 driver->FlushMappedBufferRange = _mesa_buffer_flush_mapped_range;
798
799 /* GL_ARB_copy_buffer */
800 driver->CopyBufferSubData = _mesa_copy_buffer_subdata;
801 }
802
803
804
805 /**********************************************************************/
806 /* API Functions */
807 /**********************************************************************/
808
809 void GLAPIENTRY
810 _mesa_BindBufferARB(GLenum target, GLuint buffer)
811 {
812 GET_CURRENT_CONTEXT(ctx);
813 ASSERT_OUTSIDE_BEGIN_END(ctx);
814
815 if (MESA_VERBOSE & VERBOSE_API)
816 _mesa_debug(ctx, "glBindBuffer(%s, %u)\n",
817 _mesa_lookup_enum_by_nr(target), buffer);
818
819 bind_buffer_object(ctx, target, buffer);
820 }
821
822
823 /**
824 * Delete a set of buffer objects.
825 *
826 * \param n Number of buffer objects to delete.
827 * \param ids Array of \c n buffer object IDs.
828 */
829 void GLAPIENTRY
830 _mesa_DeleteBuffersARB(GLsizei n, const GLuint *ids)
831 {
832 GET_CURRENT_CONTEXT(ctx);
833 GLsizei i;
834 ASSERT_OUTSIDE_BEGIN_END(ctx);
835 FLUSH_VERTICES(ctx, 0);
836
837 if (n < 0) {
838 _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteBuffersARB(n)");
839 return;
840 }
841
842 _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
843
844 for (i = 0; i < n; i++) {
845 struct gl_buffer_object *bufObj = _mesa_lookup_bufferobj(ctx, ids[i]);
846 if (bufObj) {
847 struct gl_array_object *arrayObj = ctx->Array.ArrayObj;
848 GLuint j;
849
850 ASSERT(bufObj->Name == ids[i] || bufObj == &DummyBufferObject);
851
852 if (_mesa_bufferobj_mapped(bufObj)) {
853 /* if mapped, unmap it now */
854 ctx->Driver.UnmapBuffer(ctx, bufObj);
855 bufObj->AccessFlags = default_access_mode(ctx);
856 bufObj->Pointer = NULL;
857 }
858
859 /* unbind any vertex pointers bound to this buffer */
860 for (j = 0; j < Elements(arrayObj->VertexAttrib); j++) {
861 unbind(ctx, &arrayObj->VertexAttrib[j].BufferObj, bufObj);
862 }
863
864 if (ctx->Array.ArrayBufferObj == bufObj) {
865 _mesa_BindBufferARB( GL_ARRAY_BUFFER_ARB, 0 );
866 }
867 if (arrayObj->ElementArrayBufferObj == bufObj) {
868 _mesa_BindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, 0 );
869 }
870
871 /* unbind ARB_copy_buffer binding points */
872 if (ctx->CopyReadBuffer == bufObj) {
873 _mesa_BindBufferARB( GL_COPY_READ_BUFFER, 0 );
874 }
875 if (ctx->CopyWriteBuffer == bufObj) {
876 _mesa_BindBufferARB( GL_COPY_WRITE_BUFFER, 0 );
877 }
878
879 /* unbind transform feedback binding points */
880 if (ctx->TransformFeedback.CurrentBuffer == bufObj) {
881 _mesa_BindBufferARB( GL_TRANSFORM_FEEDBACK_BUFFER, 0 );
882 }
883 for (j = 0; j < MAX_FEEDBACK_BUFFERS; j++) {
884 if (ctx->TransformFeedback.CurrentObject->Buffers[j] == bufObj) {
885 _mesa_BindBufferBase( GL_TRANSFORM_FEEDBACK_BUFFER, j, 0 );
886 }
887 }
888
889 /* unbind UBO binding points */
890 for (j = 0; j < ctx->Const.MaxUniformBufferBindings; j++) {
891 if (ctx->UniformBufferBindings[j].BufferObject == bufObj) {
892 _mesa_BindBufferBase( GL_UNIFORM_BUFFER, j, 0 );
893 }
894 }
895
896 if (ctx->UniformBuffer == bufObj) {
897 _mesa_BindBufferARB( GL_UNIFORM_BUFFER, 0 );
898 }
899
900 /* unbind any pixel pack/unpack pointers bound to this buffer */
901 if (ctx->Pack.BufferObj == bufObj) {
902 _mesa_BindBufferARB( GL_PIXEL_PACK_BUFFER_EXT, 0 );
903 }
904 if (ctx->Unpack.BufferObj == bufObj) {
905 _mesa_BindBufferARB( GL_PIXEL_UNPACK_BUFFER_EXT, 0 );
906 }
907
908 if (ctx->Texture.BufferObject == bufObj) {
909 _mesa_BindBufferARB( GL_TEXTURE_BUFFER, 0 );
910 }
911
912 /* The ID is immediately freed for re-use */
913 _mesa_HashRemove(ctx->Shared->BufferObjects, ids[i]);
914 /* Make sure we do not run into the classic ABA problem on bind.
915 * We don't want to allow re-binding a buffer object that's been
916 * "deleted" by glDeleteBuffers().
917 *
918 * The explicit rebinding to the default object in the current context
919 * prevents the above in the current context, but another context
920 * sharing the same objects might suffer from this problem.
921 * The alternative would be to do the hash lookup in any case on bind
922 * which would introduce more runtime overhead than this.
923 */
924 bufObj->DeletePending = GL_TRUE;
925 _mesa_reference_buffer_object(ctx, &bufObj, NULL);
926 }
927 }
928
929 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
930 }
931
932
933 /**
934 * Generate a set of unique buffer object IDs and store them in \c buffer.
935 *
936 * \param n Number of IDs to generate.
937 * \param buffer Array of \c n locations to store the IDs.
938 */
939 void GLAPIENTRY
940 _mesa_GenBuffersARB(GLsizei n, GLuint *buffer)
941 {
942 GET_CURRENT_CONTEXT(ctx);
943 GLuint first;
944 GLint i;
945 ASSERT_OUTSIDE_BEGIN_END(ctx);
946
947 if (MESA_VERBOSE & VERBOSE_API)
948 _mesa_debug(ctx, "glGenBuffers(%d)\n", n);
949
950 if (n < 0) {
951 _mesa_error(ctx, GL_INVALID_VALUE, "glGenBuffersARB");
952 return;
953 }
954
955 if (!buffer) {
956 return;
957 }
958
959 /*
960 * This must be atomic (generation and allocation of buffer object IDs)
961 */
962 _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
963
964 first = _mesa_HashFindFreeKeyBlock(ctx->Shared->BufferObjects, n);
965
966 /* Insert the ID and pointer to dummy buffer object into hash table */
967 for (i = 0; i < n; i++) {
968 _mesa_HashInsert(ctx->Shared->BufferObjects, first + i,
969 &DummyBufferObject);
970 buffer[i] = first + i;
971 }
972
973 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
974 }
975
976
977 /**
978 * Determine if ID is the name of a buffer object.
979 *
980 * \param id ID of the potential buffer object.
981 * \return \c GL_TRUE if \c id is the name of a buffer object,
982 * \c GL_FALSE otherwise.
983 */
984 GLboolean GLAPIENTRY
985 _mesa_IsBufferARB(GLuint id)
986 {
987 struct gl_buffer_object *bufObj;
988 GET_CURRENT_CONTEXT(ctx);
989 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
990
991 _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
992 bufObj = _mesa_lookup_bufferobj(ctx, id);
993 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
994
995 return bufObj && bufObj != &DummyBufferObject;
996 }
997
998
999 void GLAPIENTRY
1000 _mesa_BufferDataARB(GLenum target, GLsizeiptrARB size,
1001 const GLvoid * data, GLenum usage)
1002 {
1003 GET_CURRENT_CONTEXT(ctx);
1004 struct gl_buffer_object *bufObj;
1005 ASSERT_OUTSIDE_BEGIN_END(ctx);
1006
1007 if (MESA_VERBOSE & VERBOSE_API)
1008 _mesa_debug(ctx, "glBufferData(%s, %ld, %p, %s)\n",
1009 _mesa_lookup_enum_by_nr(target),
1010 (long int) size, data,
1011 _mesa_lookup_enum_by_nr(usage));
1012
1013 if (size < 0) {
1014 _mesa_error(ctx, GL_INVALID_VALUE, "glBufferDataARB(size < 0)");
1015 return;
1016 }
1017
1018 switch (usage) {
1019 case GL_STREAM_DRAW_ARB:
1020 case GL_STREAM_READ_ARB:
1021 case GL_STREAM_COPY_ARB:
1022 case GL_STATIC_DRAW_ARB:
1023 case GL_STATIC_READ_ARB:
1024 case GL_STATIC_COPY_ARB:
1025 case GL_DYNAMIC_DRAW_ARB:
1026 case GL_DYNAMIC_READ_ARB:
1027 case GL_DYNAMIC_COPY_ARB:
1028 /* OK */
1029 break;
1030 default:
1031 _mesa_error(ctx, GL_INVALID_ENUM, "glBufferDataARB(usage)");
1032 return;
1033 }
1034
1035 bufObj = get_buffer(ctx, "glBufferDataARB", target);
1036 if (!bufObj)
1037 return;
1038
1039 if (_mesa_bufferobj_mapped(bufObj)) {
1040 /* Unmap the existing buffer. We'll replace it now. Not an error. */
1041 ctx->Driver.UnmapBuffer(ctx, bufObj);
1042 bufObj->AccessFlags = default_access_mode(ctx);
1043 ASSERT(bufObj->Pointer == NULL);
1044 }
1045
1046 FLUSH_VERTICES(ctx, _NEW_BUFFER_OBJECT);
1047
1048 bufObj->Written = GL_TRUE;
1049
1050 #ifdef VBO_DEBUG
1051 printf("glBufferDataARB(%u, sz %ld, from %p, usage 0x%x)\n",
1052 bufObj->Name, size, data, usage);
1053 #endif
1054
1055 #ifdef BOUNDS_CHECK
1056 size += 100;
1057 #endif
1058
1059 ASSERT(ctx->Driver.BufferData);
1060 if (!ctx->Driver.BufferData( ctx, target, size, data, usage, bufObj )) {
1061 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBufferDataARB()");
1062 }
1063 }
1064
1065
1066 void GLAPIENTRY
1067 _mesa_BufferSubDataARB(GLenum target, GLintptrARB offset,
1068 GLsizeiptrARB size, const GLvoid * data)
1069 {
1070 GET_CURRENT_CONTEXT(ctx);
1071 struct gl_buffer_object *bufObj;
1072 ASSERT_OUTSIDE_BEGIN_END(ctx);
1073
1074 bufObj = buffer_object_subdata_range_good( ctx, target, offset, size,
1075 "glBufferSubDataARB" );
1076 if (!bufObj) {
1077 /* error already recorded */
1078 return;
1079 }
1080
1081 if (size == 0)
1082 return;
1083
1084 bufObj->Written = GL_TRUE;
1085
1086 ASSERT(ctx->Driver.BufferSubData);
1087 ctx->Driver.BufferSubData( ctx, offset, size, data, bufObj );
1088 }
1089
1090
1091 void GLAPIENTRY
1092 _mesa_GetBufferSubDataARB(GLenum target, GLintptrARB offset,
1093 GLsizeiptrARB size, void * data)
1094 {
1095 GET_CURRENT_CONTEXT(ctx);
1096 struct gl_buffer_object *bufObj;
1097 ASSERT_OUTSIDE_BEGIN_END(ctx);
1098
1099 bufObj = buffer_object_subdata_range_good( ctx, target, offset, size,
1100 "glGetBufferSubDataARB" );
1101 if (!bufObj) {
1102 /* error already recorded */
1103 return;
1104 }
1105
1106 ASSERT(ctx->Driver.GetBufferSubData);
1107 ctx->Driver.GetBufferSubData( ctx, offset, size, data, bufObj );
1108 }
1109
1110
1111 void * GLAPIENTRY
1112 _mesa_MapBufferARB(GLenum target, GLenum access)
1113 {
1114 GET_CURRENT_CONTEXT(ctx);
1115 struct gl_buffer_object * bufObj;
1116 GLbitfield accessFlags;
1117 void *map;
1118
1119 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, NULL);
1120
1121 switch (access) {
1122 case GL_READ_ONLY_ARB:
1123 accessFlags = GL_MAP_READ_BIT;
1124 break;
1125 case GL_WRITE_ONLY_ARB:
1126 accessFlags = GL_MAP_WRITE_BIT;
1127 break;
1128 case GL_READ_WRITE_ARB:
1129 accessFlags = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT;
1130 break;
1131 default:
1132 _mesa_error(ctx, GL_INVALID_ENUM, "glMapBufferARB(access)");
1133 return NULL;
1134 }
1135
1136 bufObj = get_buffer(ctx, "glMapBufferARB", target);
1137 if (!bufObj)
1138 return NULL;
1139
1140 if (_mesa_bufferobj_mapped(bufObj)) {
1141 _mesa_error(ctx, GL_INVALID_OPERATION, "glMapBufferARB(already mapped)");
1142 return NULL;
1143 }
1144
1145 if (!bufObj->Size) {
1146 _mesa_error(ctx, GL_OUT_OF_MEMORY,
1147 "glMapBuffer(buffer size = 0)");
1148 return NULL;
1149 }
1150
1151 ASSERT(ctx->Driver.MapBufferRange);
1152 map = ctx->Driver.MapBufferRange(ctx, 0, bufObj->Size, accessFlags, bufObj);
1153 if (!map) {
1154 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glMapBufferARB(map failed)");
1155 return NULL;
1156 }
1157 else {
1158 /* The driver callback should have set these fields.
1159 * This is important because other modules (like VBO) might call
1160 * the driver function directly.
1161 */
1162 ASSERT(bufObj->Pointer == map);
1163 ASSERT(bufObj->Length == bufObj->Size);
1164 ASSERT(bufObj->Offset == 0);
1165 bufObj->AccessFlags = accessFlags;
1166 }
1167
1168 if (access == GL_WRITE_ONLY_ARB || access == GL_READ_WRITE_ARB)
1169 bufObj->Written = GL_TRUE;
1170
1171 #ifdef VBO_DEBUG
1172 printf("glMapBufferARB(%u, sz %ld, access 0x%x)\n",
1173 bufObj->Name, bufObj->Size, access);
1174 if (access == GL_WRITE_ONLY_ARB) {
1175 GLuint i;
1176 GLubyte *b = (GLubyte *) bufObj->Pointer;
1177 for (i = 0; i < bufObj->Size; i++)
1178 b[i] = i & 0xff;
1179 }
1180 #endif
1181
1182 #ifdef BOUNDS_CHECK
1183 {
1184 GLubyte *buf = (GLubyte *) bufObj->Pointer;
1185 GLuint i;
1186 /* buffer is 100 bytes larger than requested, fill with magic value */
1187 for (i = 0; i < 100; i++) {
1188 buf[bufObj->Size - i - 1] = 123;
1189 }
1190 }
1191 #endif
1192
1193 return bufObj->Pointer;
1194 }
1195
1196
1197 GLboolean GLAPIENTRY
1198 _mesa_UnmapBufferARB(GLenum target)
1199 {
1200 GET_CURRENT_CONTEXT(ctx);
1201 struct gl_buffer_object *bufObj;
1202 GLboolean status = GL_TRUE;
1203 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
1204
1205 bufObj = get_buffer(ctx, "glUnmapBufferARB", target);
1206 if (!bufObj)
1207 return GL_FALSE;
1208
1209 if (!_mesa_bufferobj_mapped(bufObj)) {
1210 _mesa_error(ctx, GL_INVALID_OPERATION, "glUnmapBufferARB");
1211 return GL_FALSE;
1212 }
1213
1214 #ifdef BOUNDS_CHECK
1215 if (bufObj->Access != GL_READ_ONLY_ARB) {
1216 GLubyte *buf = (GLubyte *) bufObj->Pointer;
1217 GLuint i;
1218 /* check that last 100 bytes are still = magic value */
1219 for (i = 0; i < 100; i++) {
1220 GLuint pos = bufObj->Size - i - 1;
1221 if (buf[pos] != 123) {
1222 _mesa_warning(ctx, "Out of bounds buffer object write detected"
1223 " at position %d (value = %u)\n",
1224 pos, buf[pos]);
1225 }
1226 }
1227 }
1228 #endif
1229
1230 #ifdef VBO_DEBUG
1231 if (bufObj->AccessFlags & GL_MAP_WRITE_BIT) {
1232 GLuint i, unchanged = 0;
1233 GLubyte *b = (GLubyte *) bufObj->Pointer;
1234 GLint pos = -1;
1235 /* check which bytes changed */
1236 for (i = 0; i < bufObj->Size - 1; i++) {
1237 if (b[i] == (i & 0xff) && b[i+1] == ((i+1) & 0xff)) {
1238 unchanged++;
1239 if (pos == -1)
1240 pos = i;
1241 }
1242 }
1243 if (unchanged) {
1244 printf("glUnmapBufferARB(%u): %u of %ld unchanged, starting at %d\n",
1245 bufObj->Name, unchanged, bufObj->Size, pos);
1246 }
1247 }
1248 #endif
1249
1250 status = ctx->Driver.UnmapBuffer( ctx, bufObj );
1251 bufObj->AccessFlags = default_access_mode(ctx);
1252 ASSERT(bufObj->Pointer == NULL);
1253 ASSERT(bufObj->Offset == 0);
1254 ASSERT(bufObj->Length == 0);
1255
1256 return status;
1257 }
1258
1259
1260 void GLAPIENTRY
1261 _mesa_GetBufferParameterivARB(GLenum target, GLenum pname, GLint *params)
1262 {
1263 GET_CURRENT_CONTEXT(ctx);
1264 struct gl_buffer_object *bufObj;
1265 ASSERT_OUTSIDE_BEGIN_END(ctx);
1266
1267 bufObj = get_buffer(ctx, "glGetBufferParameterivARB", target);
1268 if (!bufObj)
1269 return;
1270
1271 switch (pname) {
1272 case GL_BUFFER_SIZE_ARB:
1273 *params = (GLint) bufObj->Size;
1274 return;
1275 case GL_BUFFER_USAGE_ARB:
1276 *params = bufObj->Usage;
1277 return;
1278 case GL_BUFFER_ACCESS_ARB:
1279 *params = simplified_access_mode(bufObj->AccessFlags);
1280 return;
1281 case GL_BUFFER_MAPPED_ARB:
1282 *params = _mesa_bufferobj_mapped(bufObj);
1283 return;
1284 case GL_BUFFER_ACCESS_FLAGS:
1285 if (!ctx->Extensions.ARB_map_buffer_range)
1286 goto invalid_pname;
1287 *params = bufObj->AccessFlags;
1288 return;
1289 case GL_BUFFER_MAP_OFFSET:
1290 if (!ctx->Extensions.ARB_map_buffer_range)
1291 goto invalid_pname;
1292 *params = (GLint) bufObj->Offset;
1293 return;
1294 case GL_BUFFER_MAP_LENGTH:
1295 if (!ctx->Extensions.ARB_map_buffer_range)
1296 goto invalid_pname;
1297 *params = (GLint) bufObj->Length;
1298 return;
1299 default:
1300 ; /* fall-through */
1301 }
1302
1303 invalid_pname:
1304 _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferParameterivARB(pname=%s)",
1305 _mesa_lookup_enum_by_nr(pname));
1306 }
1307
1308
1309 /**
1310 * New in GL 3.2
1311 * This is pretty much a duplicate of GetBufferParameteriv() but the
1312 * GL_BUFFER_SIZE_ARB attribute will be 64-bits on a 64-bit system.
1313 */
1314 void GLAPIENTRY
1315 _mesa_GetBufferParameteri64v(GLenum target, GLenum pname, GLint64 *params)
1316 {
1317 GET_CURRENT_CONTEXT(ctx);
1318 struct gl_buffer_object *bufObj;
1319 ASSERT_OUTSIDE_BEGIN_END(ctx);
1320
1321 bufObj = get_buffer(ctx, "glGetBufferParameteri64v", target);
1322 if (!bufObj)
1323 return;
1324
1325 switch (pname) {
1326 case GL_BUFFER_SIZE_ARB:
1327 *params = bufObj->Size;
1328 return;
1329 case GL_BUFFER_USAGE_ARB:
1330 *params = bufObj->Usage;
1331 return;
1332 case GL_BUFFER_ACCESS_ARB:
1333 *params = simplified_access_mode(bufObj->AccessFlags);
1334 return;
1335 case GL_BUFFER_ACCESS_FLAGS:
1336 if (!ctx->Extensions.ARB_map_buffer_range)
1337 goto invalid_pname;
1338 *params = bufObj->AccessFlags;
1339 return;
1340 case GL_BUFFER_MAPPED_ARB:
1341 *params = _mesa_bufferobj_mapped(bufObj);
1342 return;
1343 case GL_BUFFER_MAP_OFFSET:
1344 if (!ctx->Extensions.ARB_map_buffer_range)
1345 goto invalid_pname;
1346 *params = bufObj->Offset;
1347 return;
1348 case GL_BUFFER_MAP_LENGTH:
1349 if (!ctx->Extensions.ARB_map_buffer_range)
1350 goto invalid_pname;
1351 *params = bufObj->Length;
1352 return;
1353 default:
1354 ; /* fall-through */
1355 }
1356
1357 invalid_pname:
1358 _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferParameteri64v(pname=%s)",
1359 _mesa_lookup_enum_by_nr(pname));
1360 }
1361
1362
1363 void GLAPIENTRY
1364 _mesa_GetBufferPointervARB(GLenum target, GLenum pname, GLvoid **params)
1365 {
1366 GET_CURRENT_CONTEXT(ctx);
1367 struct gl_buffer_object * bufObj;
1368 ASSERT_OUTSIDE_BEGIN_END(ctx);
1369
1370 if (pname != GL_BUFFER_MAP_POINTER_ARB) {
1371 _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferPointervARB(pname)");
1372 return;
1373 }
1374
1375 bufObj = get_buffer(ctx, "glGetBufferPointervARB", target);
1376 if (!bufObj)
1377 return;
1378
1379 *params = bufObj->Pointer;
1380 }
1381
1382
1383 void GLAPIENTRY
1384 _mesa_CopyBufferSubData(GLenum readTarget, GLenum writeTarget,
1385 GLintptr readOffset, GLintptr writeOffset,
1386 GLsizeiptr size)
1387 {
1388 GET_CURRENT_CONTEXT(ctx);
1389 struct gl_buffer_object *src, *dst;
1390 ASSERT_OUTSIDE_BEGIN_END(ctx);
1391
1392 src = get_buffer(ctx, "glCopyBufferSubData", readTarget);
1393 if (!src)
1394 return;
1395
1396 dst = get_buffer(ctx, "glCopyBufferSubData", writeTarget);
1397 if (!dst)
1398 return;
1399
1400 if (_mesa_bufferobj_mapped(src)) {
1401 _mesa_error(ctx, GL_INVALID_OPERATION,
1402 "glCopyBufferSubData(readBuffer is mapped)");
1403 return;
1404 }
1405
1406 if (_mesa_bufferobj_mapped(dst)) {
1407 _mesa_error(ctx, GL_INVALID_OPERATION,
1408 "glCopyBufferSubData(writeBuffer is mapped)");
1409 return;
1410 }
1411
1412 if (readOffset < 0) {
1413 _mesa_error(ctx, GL_INVALID_VALUE,
1414 "glCopyBufferSubData(readOffset = %d)", (int) readOffset);
1415 return;
1416 }
1417
1418 if (writeOffset < 0) {
1419 _mesa_error(ctx, GL_INVALID_VALUE,
1420 "glCopyBufferSubData(writeOffset = %d)", (int) writeOffset);
1421 return;
1422 }
1423
1424 if (size < 0) {
1425 _mesa_error(ctx, GL_INVALID_VALUE,
1426 "glCopyBufferSubData(writeOffset = %d)", (int) size);
1427 return;
1428 }
1429
1430 if (readOffset + size > src->Size) {
1431 _mesa_error(ctx, GL_INVALID_VALUE,
1432 "glCopyBufferSubData(readOffset + size = %d)",
1433 (int) (readOffset + size));
1434 return;
1435 }
1436
1437 if (writeOffset + size > dst->Size) {
1438 _mesa_error(ctx, GL_INVALID_VALUE,
1439 "glCopyBufferSubData(writeOffset + size = %d)",
1440 (int) (writeOffset + size));
1441 return;
1442 }
1443
1444 if (src == dst) {
1445 if (readOffset + size <= writeOffset) {
1446 /* OK */
1447 }
1448 else if (writeOffset + size <= readOffset) {
1449 /* OK */
1450 }
1451 else {
1452 /* overlapping src/dst is illegal */
1453 _mesa_error(ctx, GL_INVALID_VALUE,
1454 "glCopyBufferSubData(overlapping src/dst)");
1455 return;
1456 }
1457 }
1458
1459 ctx->Driver.CopyBufferSubData(ctx, src, dst, readOffset, writeOffset, size);
1460 }
1461
1462
1463 /**
1464 * See GL_ARB_map_buffer_range spec
1465 */
1466 void * GLAPIENTRY
1467 _mesa_MapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length,
1468 GLbitfield access)
1469 {
1470 GET_CURRENT_CONTEXT(ctx);
1471 struct gl_buffer_object *bufObj;
1472 void *map;
1473
1474 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, NULL);
1475
1476 if (!ctx->Extensions.ARB_map_buffer_range) {
1477 _mesa_error(ctx, GL_INVALID_OPERATION,
1478 "glMapBufferRange(extension not supported)");
1479 return NULL;
1480 }
1481
1482 if (offset < 0) {
1483 _mesa_error(ctx, GL_INVALID_VALUE,
1484 "glMapBufferRange(offset = %ld)", (long)offset);
1485 return NULL;
1486 }
1487
1488 if (length < 0) {
1489 _mesa_error(ctx, GL_INVALID_VALUE,
1490 "glMapBufferRange(length = %ld)", (long)length);
1491 return NULL;
1492 }
1493
1494 if (access & ~(GL_MAP_READ_BIT |
1495 GL_MAP_WRITE_BIT |
1496 GL_MAP_INVALIDATE_RANGE_BIT |
1497 GL_MAP_INVALIDATE_BUFFER_BIT |
1498 GL_MAP_FLUSH_EXPLICIT_BIT |
1499 GL_MAP_UNSYNCHRONIZED_BIT)) {
1500 /* generate an error if any undefind bit is set */
1501 _mesa_error(ctx, GL_INVALID_VALUE, "glMapBufferRange(access)");
1502 return NULL;
1503 }
1504
1505 if ((access & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)) == 0) {
1506 _mesa_error(ctx, GL_INVALID_OPERATION,
1507 "glMapBufferRange(access indicates neither read or write)");
1508 return NULL;
1509 }
1510
1511 if ((access & GL_MAP_READ_BIT) &&
1512 (access & (GL_MAP_INVALIDATE_RANGE_BIT |
1513 GL_MAP_INVALIDATE_BUFFER_BIT |
1514 GL_MAP_UNSYNCHRONIZED_BIT))) {
1515 _mesa_error(ctx, GL_INVALID_OPERATION,
1516 "glMapBufferRange(invalid access flags)");
1517 return NULL;
1518 }
1519
1520 if ((access & GL_MAP_FLUSH_EXPLICIT_BIT) &&
1521 ((access & GL_MAP_WRITE_BIT) == 0)) {
1522 _mesa_error(ctx, GL_INVALID_OPERATION,
1523 "glMapBufferRange(invalid access flags)");
1524 return NULL;
1525 }
1526
1527 bufObj = get_buffer(ctx, "glMapBufferRange", target);
1528 if (!bufObj)
1529 return NULL;
1530
1531 if (offset + length > bufObj->Size) {
1532 _mesa_error(ctx, GL_INVALID_VALUE,
1533 "glMapBufferRange(offset + length > size)");
1534 return NULL;
1535 }
1536
1537 if (_mesa_bufferobj_mapped(bufObj)) {
1538 _mesa_error(ctx, GL_INVALID_OPERATION,
1539 "glMapBufferRange(buffer already mapped)");
1540 return NULL;
1541 }
1542
1543 if (!bufObj->Size) {
1544 _mesa_error(ctx, GL_OUT_OF_MEMORY,
1545 "glMapBufferRange(buffer size = 0)");
1546 return NULL;
1547 }
1548
1549 /* Mapping zero bytes should return a non-null pointer. */
1550 if (!length) {
1551 static long dummy = 0;
1552 bufObj->Pointer = &dummy;
1553 bufObj->Length = length;
1554 bufObj->Offset = offset;
1555 bufObj->AccessFlags = access;
1556 return bufObj->Pointer;
1557 }
1558
1559 ASSERT(ctx->Driver.MapBufferRange);
1560 map = ctx->Driver.MapBufferRange(ctx, offset, length, access, bufObj);
1561 if (!map) {
1562 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glMapBufferARB(map failed)");
1563 }
1564 else {
1565 /* The driver callback should have set all these fields.
1566 * This is important because other modules (like VBO) might call
1567 * the driver function directly.
1568 */
1569 ASSERT(bufObj->Pointer == map);
1570 ASSERT(bufObj->Length == length);
1571 ASSERT(bufObj->Offset == offset);
1572 ASSERT(bufObj->AccessFlags == access);
1573 }
1574
1575 return map;
1576 }
1577
1578
1579 /**
1580 * See GL_ARB_map_buffer_range spec
1581 */
1582 void GLAPIENTRY
1583 _mesa_FlushMappedBufferRange(GLenum target, GLintptr offset, GLsizeiptr length)
1584 {
1585 GET_CURRENT_CONTEXT(ctx);
1586 struct gl_buffer_object *bufObj;
1587 ASSERT_OUTSIDE_BEGIN_END(ctx);
1588
1589 if (!ctx->Extensions.ARB_map_buffer_range) {
1590 _mesa_error(ctx, GL_INVALID_OPERATION,
1591 "glFlushMappedBufferRange(extension not supported)");
1592 return;
1593 }
1594
1595 if (offset < 0) {
1596 _mesa_error(ctx, GL_INVALID_VALUE,
1597 "glFlushMappedBufferRange(offset = %ld)", (long)offset);
1598 return;
1599 }
1600
1601 if (length < 0) {
1602 _mesa_error(ctx, GL_INVALID_VALUE,
1603 "glFlushMappedBufferRange(length = %ld)", (long)length);
1604 return;
1605 }
1606
1607 bufObj = get_buffer(ctx, "glFlushMappedBufferRange", target);
1608 if (!bufObj)
1609 return;
1610
1611 if (!_mesa_bufferobj_mapped(bufObj)) {
1612 /* buffer is not mapped */
1613 _mesa_error(ctx, GL_INVALID_OPERATION,
1614 "glFlushMappedBufferRange(buffer is not mapped)");
1615 return;
1616 }
1617
1618 if ((bufObj->AccessFlags & GL_MAP_FLUSH_EXPLICIT_BIT) == 0) {
1619 _mesa_error(ctx, GL_INVALID_OPERATION,
1620 "glFlushMappedBufferRange(GL_MAP_FLUSH_EXPLICIT_BIT not set)");
1621 return;
1622 }
1623
1624 if (offset + length > bufObj->Length) {
1625 _mesa_error(ctx, GL_INVALID_VALUE,
1626 "glFlushMappedBufferRange(offset %ld + length %ld > mapped length %ld)",
1627 (long)offset, (long)length, (long)bufObj->Length);
1628 return;
1629 }
1630
1631 ASSERT(bufObj->AccessFlags & GL_MAP_WRITE_BIT);
1632
1633 if (ctx->Driver.FlushMappedBufferRange)
1634 ctx->Driver.FlushMappedBufferRange(ctx, offset, length, bufObj);
1635 }
1636
1637
1638 #if FEATURE_APPLE_object_purgeable
1639 static GLenum
1640 buffer_object_purgeable(struct gl_context *ctx, GLuint name, GLenum option)
1641 {
1642 struct gl_buffer_object *bufObj;
1643 GLenum retval;
1644
1645 bufObj = _mesa_lookup_bufferobj(ctx, name);
1646 if (!bufObj) {
1647 _mesa_error(ctx, GL_INVALID_VALUE,
1648 "glObjectPurgeable(name = 0x%x)", name);
1649 return 0;
1650 }
1651 if (!_mesa_is_bufferobj(bufObj)) {
1652 _mesa_error(ctx, GL_INVALID_OPERATION, "glObjectPurgeable(buffer 0)" );
1653 return 0;
1654 }
1655
1656 if (bufObj->Purgeable) {
1657 _mesa_error(ctx, GL_INVALID_OPERATION,
1658 "glObjectPurgeable(name = 0x%x) is already purgeable", name);
1659 return GL_VOLATILE_APPLE;
1660 }
1661
1662 bufObj->Purgeable = GL_TRUE;
1663
1664 retval = GL_VOLATILE_APPLE;
1665 if (ctx->Driver.BufferObjectPurgeable)
1666 retval = ctx->Driver.BufferObjectPurgeable(ctx, bufObj, option);
1667
1668 return retval;
1669 }
1670
1671
1672 static GLenum
1673 renderbuffer_purgeable(struct gl_context *ctx, GLuint name, GLenum option)
1674 {
1675 struct gl_renderbuffer *bufObj;
1676 GLenum retval;
1677
1678 bufObj = _mesa_lookup_renderbuffer(ctx, name);
1679 if (!bufObj) {
1680 _mesa_error(ctx, GL_INVALID_VALUE,
1681 "glObjectUnpurgeable(name = 0x%x)", name);
1682 return 0;
1683 }
1684
1685 if (bufObj->Purgeable) {
1686 _mesa_error(ctx, GL_INVALID_OPERATION,
1687 "glObjectPurgeable(name = 0x%x) is already purgeable", name);
1688 return GL_VOLATILE_APPLE;
1689 }
1690
1691 bufObj->Purgeable = GL_TRUE;
1692
1693 retval = GL_VOLATILE_APPLE;
1694 if (ctx->Driver.RenderObjectPurgeable)
1695 retval = ctx->Driver.RenderObjectPurgeable(ctx, bufObj, option);
1696
1697 return retval;
1698 }
1699
1700
1701 static GLenum
1702 texture_object_purgeable(struct gl_context *ctx, GLuint name, GLenum option)
1703 {
1704 struct gl_texture_object *bufObj;
1705 GLenum retval;
1706
1707 bufObj = _mesa_lookup_texture(ctx, name);
1708 if (!bufObj) {
1709 _mesa_error(ctx, GL_INVALID_VALUE,
1710 "glObjectPurgeable(name = 0x%x)", name);
1711 return 0;
1712 }
1713
1714 if (bufObj->Purgeable) {
1715 _mesa_error(ctx, GL_INVALID_OPERATION,
1716 "glObjectPurgeable(name = 0x%x) is already purgeable", name);
1717 return GL_VOLATILE_APPLE;
1718 }
1719
1720 bufObj->Purgeable = GL_TRUE;
1721
1722 retval = GL_VOLATILE_APPLE;
1723 if (ctx->Driver.TextureObjectPurgeable)
1724 retval = ctx->Driver.TextureObjectPurgeable(ctx, bufObj, option);
1725
1726 return retval;
1727 }
1728
1729
1730 GLenum GLAPIENTRY
1731 _mesa_ObjectPurgeableAPPLE(GLenum objectType, GLuint name, GLenum option)
1732 {
1733 GLenum retval;
1734
1735 GET_CURRENT_CONTEXT(ctx);
1736 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0);
1737
1738 if (name == 0) {
1739 _mesa_error(ctx, GL_INVALID_VALUE,
1740 "glObjectPurgeable(name = 0x%x)", name);
1741 return 0;
1742 }
1743
1744 switch (option) {
1745 case GL_VOLATILE_APPLE:
1746 case GL_RELEASED_APPLE:
1747 /* legal */
1748 break;
1749 default:
1750 _mesa_error(ctx, GL_INVALID_ENUM,
1751 "glObjectPurgeable(name = 0x%x) invalid option: %d",
1752 name, option);
1753 return 0;
1754 }
1755
1756 switch (objectType) {
1757 case GL_TEXTURE:
1758 retval = texture_object_purgeable(ctx, name, option);
1759 break;
1760 case GL_RENDERBUFFER_EXT:
1761 retval = renderbuffer_purgeable(ctx, name, option);
1762 break;
1763 case GL_BUFFER_OBJECT_APPLE:
1764 retval = buffer_object_purgeable(ctx, name, option);
1765 break;
1766 default:
1767 _mesa_error(ctx, GL_INVALID_ENUM,
1768 "glObjectPurgeable(name = 0x%x) invalid type: %d",
1769 name, objectType);
1770 return 0;
1771 }
1772
1773 /* In strict conformance to the spec, we must only return VOLATILE when
1774 * when passed the VOLATILE option. Madness.
1775 *
1776 * XXX First fix the spec, then fix me.
1777 */
1778 return option == GL_VOLATILE_APPLE ? GL_VOLATILE_APPLE : retval;
1779 }
1780
1781
1782 static GLenum
1783 buffer_object_unpurgeable(struct gl_context *ctx, GLuint name, GLenum option)
1784 {
1785 struct gl_buffer_object *bufObj;
1786 GLenum retval;
1787
1788 bufObj = _mesa_lookup_bufferobj(ctx, name);
1789 if (!bufObj) {
1790 _mesa_error(ctx, GL_INVALID_VALUE,
1791 "glObjectUnpurgeable(name = 0x%x)", name);
1792 return 0;
1793 }
1794
1795 if (! bufObj->Purgeable) {
1796 _mesa_error(ctx, GL_INVALID_OPERATION,
1797 "glObjectUnpurgeable(name = 0x%x) object is "
1798 " already \"unpurged\"", name);
1799 return 0;
1800 }
1801
1802 bufObj->Purgeable = GL_FALSE;
1803
1804 retval = option;
1805 if (ctx->Driver.BufferObjectUnpurgeable)
1806 retval = ctx->Driver.BufferObjectUnpurgeable(ctx, bufObj, option);
1807
1808 return retval;
1809 }
1810
1811
1812 static GLenum
1813 renderbuffer_unpurgeable(struct gl_context *ctx, GLuint name, GLenum option)
1814 {
1815 struct gl_renderbuffer *bufObj;
1816 GLenum retval;
1817
1818 bufObj = _mesa_lookup_renderbuffer(ctx, name);
1819 if (!bufObj) {
1820 _mesa_error(ctx, GL_INVALID_VALUE,
1821 "glObjectUnpurgeable(name = 0x%x)", name);
1822 return 0;
1823 }
1824
1825 if (! bufObj->Purgeable) {
1826 _mesa_error(ctx, GL_INVALID_OPERATION,
1827 "glObjectUnpurgeable(name = 0x%x) object is "
1828 " already \"unpurged\"", name);
1829 return 0;
1830 }
1831
1832 bufObj->Purgeable = GL_FALSE;
1833
1834 retval = option;
1835 if (ctx->Driver.RenderObjectUnpurgeable)
1836 retval = ctx->Driver.RenderObjectUnpurgeable(ctx, bufObj, option);
1837
1838 return retval;
1839 }
1840
1841
1842 static GLenum
1843 texture_object_unpurgeable(struct gl_context *ctx, GLuint name, GLenum option)
1844 {
1845 struct gl_texture_object *bufObj;
1846 GLenum retval;
1847
1848 bufObj = _mesa_lookup_texture(ctx, name);
1849 if (!bufObj) {
1850 _mesa_error(ctx, GL_INVALID_VALUE,
1851 "glObjectUnpurgeable(name = 0x%x)", name);
1852 return 0;
1853 }
1854
1855 if (! bufObj->Purgeable) {
1856 _mesa_error(ctx, GL_INVALID_OPERATION,
1857 "glObjectUnpurgeable(name = 0x%x) object is"
1858 " already \"unpurged\"", name);
1859 return 0;
1860 }
1861
1862 bufObj->Purgeable = GL_FALSE;
1863
1864 retval = option;
1865 if (ctx->Driver.TextureObjectUnpurgeable)
1866 retval = ctx->Driver.TextureObjectUnpurgeable(ctx, bufObj, option);
1867
1868 return retval;
1869 }
1870
1871
1872 GLenum GLAPIENTRY
1873 _mesa_ObjectUnpurgeableAPPLE(GLenum objectType, GLuint name, GLenum option)
1874 {
1875 GET_CURRENT_CONTEXT(ctx);
1876 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0);
1877
1878 if (name == 0) {
1879 _mesa_error(ctx, GL_INVALID_VALUE,
1880 "glObjectUnpurgeable(name = 0x%x)", name);
1881 return 0;
1882 }
1883
1884 switch (option) {
1885 case GL_RETAINED_APPLE:
1886 case GL_UNDEFINED_APPLE:
1887 /* legal */
1888 break;
1889 default:
1890 _mesa_error(ctx, GL_INVALID_ENUM,
1891 "glObjectUnpurgeable(name = 0x%x) invalid option: %d",
1892 name, option);
1893 return 0;
1894 }
1895
1896 switch (objectType) {
1897 case GL_BUFFER_OBJECT_APPLE:
1898 return buffer_object_unpurgeable(ctx, name, option);
1899 case GL_TEXTURE:
1900 return texture_object_unpurgeable(ctx, name, option);
1901 case GL_RENDERBUFFER_EXT:
1902 return renderbuffer_unpurgeable(ctx, name, option);
1903 default:
1904 _mesa_error(ctx, GL_INVALID_ENUM,
1905 "glObjectUnpurgeable(name = 0x%x) invalid type: %d",
1906 name, objectType);
1907 return 0;
1908 }
1909 }
1910
1911
1912 static void
1913 get_buffer_object_parameteriv(struct gl_context *ctx, GLuint name,
1914 GLenum pname, GLint *params)
1915 {
1916 struct gl_buffer_object *bufObj = _mesa_lookup_bufferobj(ctx, name);
1917 if (!bufObj) {
1918 _mesa_error(ctx, GL_INVALID_VALUE,
1919 "glGetObjectParameteriv(name = 0x%x) invalid object", name);
1920 return;
1921 }
1922
1923 switch (pname) {
1924 case GL_PURGEABLE_APPLE:
1925 *params = bufObj->Purgeable;
1926 break;
1927 default:
1928 _mesa_error(ctx, GL_INVALID_ENUM,
1929 "glGetObjectParameteriv(name = 0x%x) invalid enum: %d",
1930 name, pname);
1931 break;
1932 }
1933 }
1934
1935
1936 static void
1937 get_renderbuffer_parameteriv(struct gl_context *ctx, GLuint name,
1938 GLenum pname, GLint *params)
1939 {
1940 struct gl_renderbuffer *rb = _mesa_lookup_renderbuffer(ctx, name);
1941 if (!rb) {
1942 _mesa_error(ctx, GL_INVALID_VALUE,
1943 "glObjectUnpurgeable(name = 0x%x)", name);
1944 return;
1945 }
1946
1947 switch (pname) {
1948 case GL_PURGEABLE_APPLE:
1949 *params = rb->Purgeable;
1950 break;
1951 default:
1952 _mesa_error(ctx, GL_INVALID_ENUM,
1953 "glGetObjectParameteriv(name = 0x%x) invalid enum: %d",
1954 name, pname);
1955 break;
1956 }
1957 }
1958
1959
1960 static void
1961 get_texture_object_parameteriv(struct gl_context *ctx, GLuint name,
1962 GLenum pname, GLint *params)
1963 {
1964 struct gl_texture_object *texObj = _mesa_lookup_texture(ctx, name);
1965 if (!texObj) {
1966 _mesa_error(ctx, GL_INVALID_VALUE,
1967 "glObjectUnpurgeable(name = 0x%x)", name);
1968 return;
1969 }
1970
1971 switch (pname) {
1972 case GL_PURGEABLE_APPLE:
1973 *params = texObj->Purgeable;
1974 break;
1975 default:
1976 _mesa_error(ctx, GL_INVALID_ENUM,
1977 "glGetObjectParameteriv(name = 0x%x) invalid enum: %d",
1978 name, pname);
1979 break;
1980 }
1981 }
1982
1983
1984 void GLAPIENTRY
1985 _mesa_GetObjectParameterivAPPLE(GLenum objectType, GLuint name, GLenum pname,
1986 GLint *params)
1987 {
1988 GET_CURRENT_CONTEXT(ctx);
1989
1990 if (name == 0) {
1991 _mesa_error(ctx, GL_INVALID_VALUE,
1992 "glGetObjectParameteriv(name = 0x%x)", name);
1993 return;
1994 }
1995
1996 switch (objectType) {
1997 case GL_TEXTURE:
1998 get_texture_object_parameteriv(ctx, name, pname, params);
1999 break;
2000 case GL_BUFFER_OBJECT_APPLE:
2001 get_buffer_object_parameteriv(ctx, name, pname, params);
2002 break;
2003 case GL_RENDERBUFFER_EXT:
2004 get_renderbuffer_parameteriv(ctx, name, pname, params);
2005 break;
2006 default:
2007 _mesa_error(ctx, GL_INVALID_ENUM,
2008 "glGetObjectParameteriv(name = 0x%x) invalid type: %d",
2009 name, objectType);
2010 }
2011 }
2012
2013 #endif /* FEATURE_APPLE_object_purgeable */
2014
2015 static void
2016 set_ubo_binding(struct gl_context *ctx,
2017 int index,
2018 struct gl_buffer_object *bufObj,
2019 GLintptr offset,
2020 GLsizeiptr size,
2021 GLboolean autoSize)
2022 {
2023 struct gl_uniform_buffer_binding *binding;
2024
2025 binding = &ctx->UniformBufferBindings[index];
2026 if (binding->BufferObject == bufObj &&
2027 binding->Offset == offset &&
2028 binding->Size == size &&
2029 binding->AutomaticSize == autoSize) {
2030 return;
2031 }
2032
2033 FLUSH_VERTICES(ctx, _NEW_BUFFER_OBJECT);
2034
2035 _mesa_reference_buffer_object(ctx, &binding->BufferObject, bufObj);
2036 binding->Offset = offset;
2037 binding->Size = size;
2038 binding->AutomaticSize = autoSize;
2039 }
2040
2041 /**
2042 * Bind a region of a buffer object to a uniform block binding point.
2043 * \param index the uniform buffer binding point index
2044 * \param bufObj the buffer object
2045 * \param offset offset to the start of buffer object region
2046 * \param size size of the buffer object region
2047 */
2048 static void
2049 bind_buffer_range_uniform_buffer(struct gl_context *ctx,
2050 GLuint index,
2051 struct gl_buffer_object *bufObj,
2052 GLintptr offset,
2053 GLsizeiptr size)
2054 {
2055 if (index >= ctx->Const.MaxUniformBufferBindings) {
2056 _mesa_error(ctx, GL_INVALID_VALUE, "glBindBufferRange(index=%d)", index);
2057 return;
2058 }
2059
2060 if (offset & (ctx->Const.UniformBufferOffsetAlignment - 1)) {
2061 _mesa_error(ctx, GL_INVALID_VALUE,
2062 "glBindBufferRange(offset misalgned %d/%d)", (int) offset,
2063 ctx->Const.UniformBufferOffsetAlignment);
2064 return;
2065 }
2066
2067 if (bufObj == ctx->Shared->NullBufferObj) {
2068 offset = -1;
2069 size = -1;
2070 }
2071
2072 _mesa_reference_buffer_object(ctx, &ctx->UniformBuffer, bufObj);
2073 set_ubo_binding(ctx, index, bufObj, offset, size, GL_FALSE);
2074 }
2075
2076
2077 /**
2078 * Bind a buffer object to a uniform block binding point.
2079 * As above, but offset = 0.
2080 */
2081 static void
2082 bind_buffer_base_uniform_buffer(struct gl_context *ctx,
2083 GLuint index,
2084 struct gl_buffer_object *bufObj)
2085 {
2086 if (index >= ctx->Const.MaxUniformBufferBindings) {
2087 _mesa_error(ctx, GL_INVALID_VALUE, "glBindBufferBase(index=%d)", index);
2088 return;
2089 }
2090
2091 _mesa_reference_buffer_object(ctx, &ctx->UniformBuffer, bufObj);
2092 if (bufObj == ctx->Shared->NullBufferObj)
2093 set_ubo_binding(ctx, index, bufObj, -1, -1, GL_TRUE);
2094 else
2095 set_ubo_binding(ctx, index, bufObj, 0, 0, GL_TRUE);
2096 }
2097
2098 void GLAPIENTRY
2099 _mesa_BindBufferRange(GLenum target, GLuint index,
2100 GLuint buffer, GLintptr offset, GLsizeiptr size)
2101 {
2102 GET_CURRENT_CONTEXT(ctx);
2103 struct gl_buffer_object *bufObj;
2104
2105 if (buffer == 0) {
2106 bufObj = ctx->Shared->NullBufferObj;
2107 } else {
2108 bufObj = _mesa_lookup_bufferobj(ctx, buffer);
2109 }
2110 handle_bind_buffer_gen(ctx, target, buffer, &bufObj);
2111
2112 if (!bufObj) {
2113 _mesa_error(ctx, GL_INVALID_OPERATION,
2114 "glBindBufferRange(invalid buffer=%u)", buffer);
2115 return;
2116 }
2117
2118 if (size <= 0) {
2119 _mesa_error(ctx, GL_INVALID_VALUE, "glBindBufferRange(size=%d)",
2120 (int) size);
2121 return;
2122 }
2123
2124 if (offset + size > bufObj->Size) {
2125 _mesa_error(ctx, GL_INVALID_VALUE,
2126 "glBindBufferRange(offset + size %d > buffer size %d)",
2127 (int) (offset + size), (int) (bufObj->Size));
2128 return;
2129 }
2130
2131 switch (target) {
2132 case GL_TRANSFORM_FEEDBACK_BUFFER:
2133 _mesa_bind_buffer_range_transform_feedback(ctx, index, bufObj,
2134 offset, size);
2135 return;
2136 case GL_UNIFORM_BUFFER:
2137 bind_buffer_range_uniform_buffer(ctx, index, bufObj, offset, size);
2138 return;
2139 default:
2140 _mesa_error(ctx, GL_INVALID_ENUM, "glBindBufferRange(target)");
2141 return;
2142 }
2143 }
2144
2145 void GLAPIENTRY
2146 _mesa_BindBufferBase(GLenum target, GLuint index, GLuint buffer)
2147 {
2148 GET_CURRENT_CONTEXT(ctx);
2149 struct gl_buffer_object *bufObj;
2150
2151 if (buffer == 0) {
2152 bufObj = ctx->Shared->NullBufferObj;
2153 } else {
2154 bufObj = _mesa_lookup_bufferobj(ctx, buffer);
2155 }
2156 handle_bind_buffer_gen(ctx, target, buffer, &bufObj);
2157
2158 if (!bufObj) {
2159 _mesa_error(ctx, GL_INVALID_OPERATION,
2160 "glBindBufferBase(invalid buffer=%u)", buffer);
2161 return;
2162 }
2163
2164 /* Note that there's some oddness in the GL 3.1-GL 3.3 specifications with
2165 * regards to BindBufferBase. It says (GL 3.1 core spec, page 63):
2166 *
2167 * "BindBufferBase is equivalent to calling BindBufferRange with offset
2168 * zero and size equal to the size of buffer."
2169 *
2170 * but it says for glGetIntegeri_v (GL 3.1 core spec, page 230):
2171 *
2172 * "If the parameter (starting offset or size) was not specified when the
2173 * buffer object was bound, zero is returned."
2174 *
2175 * What happens if the size of the buffer changes? Does the size of the
2176 * buffer at the moment glBindBufferBase was called still play a role, like
2177 * the first quote would imply, or is the size meaningless in the
2178 * glBindBufferBase case like the second quote would suggest? The GL 4.1
2179 * core spec page 45 says:
2180 *
2181 * "It is equivalent to calling BindBufferRange with offset zero, while
2182 * size is determined by the size of the bound buffer at the time the
2183 * binding is used."
2184 *
2185 * My interpretation is that the GL 4.1 spec was a clarification of the
2186 * behavior, not a change. In particular, this choice will only make
2187 * rendering work in cases where it would have had undefined results.
2188 */
2189
2190 switch (target) {
2191 case GL_TRANSFORM_FEEDBACK_BUFFER:
2192 _mesa_bind_buffer_base_transform_feedback(ctx, index, bufObj);
2193 return;
2194 case GL_UNIFORM_BUFFER:
2195 bind_buffer_base_uniform_buffer(ctx, index, bufObj);
2196 return;
2197 default:
2198 _mesa_error(ctx, GL_INVALID_ENUM, "glBindBufferBase(target)");
2199 return;
2200 }
2201 }
2202
2203 void
2204 _mesa_init_bufferobj_dispatch(struct _glapi_table *disp)
2205 {
2206 SET_BindBufferARB(disp, _mesa_BindBufferARB);
2207 SET_BufferDataARB(disp, _mesa_BufferDataARB);
2208 SET_BufferSubDataARB(disp, _mesa_BufferSubDataARB);
2209 SET_DeleteBuffersARB(disp, _mesa_DeleteBuffersARB);
2210 SET_GenBuffersARB(disp, _mesa_GenBuffersARB);
2211 SET_GetBufferParameterivARB(disp, _mesa_GetBufferParameterivARB);
2212 SET_GetBufferPointervARB(disp, _mesa_GetBufferPointervARB);
2213 SET_GetBufferSubDataARB(disp, _mesa_GetBufferSubDataARB);
2214 SET_IsBufferARB(disp, _mesa_IsBufferARB);
2215 SET_MapBufferARB(disp, _mesa_MapBufferARB);
2216 SET_UnmapBufferARB(disp, _mesa_UnmapBufferARB);
2217 SET_BindBufferRangeEXT(disp, _mesa_BindBufferRange);
2218 SET_BindBufferBaseEXT(disp, _mesa_BindBufferBase);
2219 }