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