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