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