mesa: rename functions to follow Mesa conventions
[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.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 default:
97 return NULL;
98 }
99 return NULL;
100 }
101
102
103 /**
104 * Get the buffer object bound to the specified target in a GL context.
105 * \param ctx the GL context
106 * \param target the buffer object target to be retrieved.
107 * \return pointer to the buffer object bound to \c target in the
108 * specified context or \c NULL if \c target is invalid.
109 */
110 static INLINE struct gl_buffer_object *
111 get_buffer(struct gl_context *ctx, GLenum target)
112 {
113 struct gl_buffer_object **bufObj = get_buffer_target(ctx, target);
114 if (bufObj)
115 return *bufObj;
116 return NULL;
117 }
118
119
120 /**
121 * Convert a GLbitfield describing the mapped buffer access flags
122 * into one of GL_READ_WRITE, GL_READ_ONLY, or GL_WRITE_ONLY.
123 */
124 static GLenum
125 simplified_access_mode(GLbitfield access)
126 {
127 const GLbitfield rwFlags = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT;
128 if ((access & rwFlags) == rwFlags)
129 return GL_READ_WRITE;
130 if ((access & GL_MAP_READ_BIT) == GL_MAP_READ_BIT)
131 return GL_READ_ONLY;
132 if ((access & GL_MAP_WRITE_BIT) == GL_MAP_WRITE_BIT)
133 return GL_WRITE_ONLY;
134 return GL_READ_WRITE; /* this should never happen, but no big deal */
135 }
136
137
138 /**
139 * Tests the subdata range parameters and sets the GL error code for
140 * \c glBufferSubDataARB and \c glGetBufferSubDataARB.
141 *
142 * \param ctx GL context.
143 * \param target Buffer object target on which to operate.
144 * \param offset Offset of the first byte of the subdata range.
145 * \param size Size, in bytes, of the subdata range.
146 * \param caller Name of calling function for recording errors.
147 * \return A pointer to the buffer object bound to \c target in the
148 * specified context or \c NULL if any of the parameter or state
149 * conditions for \c glBufferSubDataARB or \c glGetBufferSubDataARB
150 * are invalid.
151 *
152 * \sa glBufferSubDataARB, glGetBufferSubDataARB
153 */
154 static struct gl_buffer_object *
155 buffer_object_subdata_range_good( struct gl_context * ctx, GLenum target,
156 GLintptrARB offset, GLsizeiptrARB size,
157 const char *caller )
158 {
159 struct gl_buffer_object *bufObj;
160
161 if (size < 0) {
162 _mesa_error(ctx, GL_INVALID_VALUE, "%s(size < 0)", caller);
163 return NULL;
164 }
165
166 if (offset < 0) {
167 _mesa_error(ctx, GL_INVALID_VALUE, "%s(offset < 0)", caller);
168 return NULL;
169 }
170
171 bufObj = get_buffer(ctx, target);
172 if (!bufObj) {
173 _mesa_error(ctx, GL_INVALID_ENUM, "%s(target)", caller);
174 return NULL;
175 }
176 if (!_mesa_is_bufferobj(bufObj)) {
177 _mesa_error(ctx, GL_INVALID_OPERATION, "%s", caller);
178 return NULL;
179 }
180 if (offset + size > bufObj->Size) {
181 _mesa_error(ctx, GL_INVALID_VALUE,
182 "%s(size + offset > buffer size)", caller);
183 return NULL;
184 }
185 if (_mesa_bufferobj_mapped(bufObj)) {
186 /* Buffer is currently mapped */
187 _mesa_error(ctx, GL_INVALID_OPERATION, "%s", caller);
188 return NULL;
189 }
190
191 return bufObj;
192 }
193
194
195 /**
196 * Allocate and initialize a new buffer object.
197 *
198 * Default callback for the \c dd_function_table::NewBufferObject() hook.
199 */
200 static struct gl_buffer_object *
201 _mesa_new_buffer_object( struct gl_context *ctx, GLuint name, GLenum target )
202 {
203 struct gl_buffer_object *obj;
204
205 (void) ctx;
206
207 obj = MALLOC_STRUCT(gl_buffer_object);
208 _mesa_initialize_buffer_object(obj, name, target);
209 return obj;
210 }
211
212
213 /**
214 * Delete a buffer object.
215 *
216 * Default callback for the \c dd_function_table::DeleteBuffer() hook.
217 */
218 static void
219 _mesa_delete_buffer_object(struct gl_context *ctx,
220 struct gl_buffer_object *bufObj)
221 {
222 (void) ctx;
223
224 if (bufObj->Data)
225 free(bufObj->Data);
226
227 /* assign strange values here to help w/ debugging */
228 bufObj->RefCount = -1000;
229 bufObj->Name = ~0;
230
231 _glthread_DESTROY_MUTEX(bufObj->Mutex);
232 free(bufObj);
233 }
234
235
236
237 /**
238 * Set ptr to bufObj w/ reference counting.
239 */
240 void
241 _mesa_reference_buffer_object(struct gl_context *ctx,
242 struct gl_buffer_object **ptr,
243 struct gl_buffer_object *bufObj)
244 {
245 if (*ptr == bufObj)
246 return;
247
248 if (*ptr) {
249 /* Unreference the old buffer */
250 GLboolean deleteFlag = GL_FALSE;
251 struct gl_buffer_object *oldObj = *ptr;
252
253 _glthread_LOCK_MUTEX(oldObj->Mutex);
254 ASSERT(oldObj->RefCount > 0);
255 oldObj->RefCount--;
256 #if 0
257 printf("BufferObj %p %d DECR to %d\n",
258 (void *) oldObj, oldObj->Name, oldObj->RefCount);
259 #endif
260 deleteFlag = (oldObj->RefCount == 0);
261 _glthread_UNLOCK_MUTEX(oldObj->Mutex);
262
263 if (deleteFlag) {
264
265 /* some sanity checking: don't delete a buffer still in use */
266 #if 0
267 /* unfortunately, these tests are invalid during context tear-down */
268 ASSERT(ctx->Array.ArrayBufferObj != bufObj);
269 ASSERT(ctx->Array.ElementArrayBufferObj != bufObj);
270 ASSERT(ctx->Array.ArrayObj->Vertex.BufferObj != bufObj);
271 #endif
272
273 ASSERT(ctx->Driver.DeleteBuffer);
274 ctx->Driver.DeleteBuffer(ctx, oldObj);
275 }
276
277 *ptr = NULL;
278 }
279 ASSERT(!*ptr);
280
281 if (bufObj) {
282 /* reference new buffer */
283 _glthread_LOCK_MUTEX(bufObj->Mutex);
284 if (bufObj->RefCount == 0) {
285 /* this buffer's being deleted (look just above) */
286 /* Not sure this can every really happen. Warn if it does. */
287 _mesa_problem(NULL, "referencing deleted buffer object");
288 *ptr = NULL;
289 }
290 else {
291 bufObj->RefCount++;
292 #if 0
293 printf("BufferObj %p %d INCR to %d\n",
294 (void *) bufObj, bufObj->Name, bufObj->RefCount);
295 #endif
296 *ptr = bufObj;
297 }
298 _glthread_UNLOCK_MUTEX(bufObj->Mutex);
299 }
300 }
301
302
303 /**
304 * Initialize a buffer object to default values.
305 */
306 void
307 _mesa_initialize_buffer_object( struct gl_buffer_object *obj,
308 GLuint name, GLenum target )
309 {
310 (void) target;
311
312 memset(obj, 0, sizeof(struct gl_buffer_object));
313 _glthread_INIT_MUTEX(obj->Mutex);
314 obj->RefCount = 1;
315 obj->Name = name;
316 obj->Usage = GL_STATIC_DRAW_ARB;
317 obj->AccessFlags = DEFAULT_ACCESS;
318 }
319
320
321 /**
322 * Allocate space for and store data in a buffer object. Any data that was
323 * previously stored in the buffer object is lost. If \c data is \c NULL,
324 * memory will be allocated, but no copy will occur.
325 *
326 * This is the default callback for \c dd_function_table::BufferData()
327 * Note that all GL error checking will have been done already.
328 *
329 * \param ctx GL context.
330 * \param target Buffer object target on which to operate.
331 * \param size Size, in bytes, of the new data store.
332 * \param data Pointer to the data to store in the buffer object. This
333 * pointer may be \c NULL.
334 * \param usage Hints about how the data will be used.
335 * \param bufObj Object to be used.
336 *
337 * \return GL_TRUE for success, GL_FALSE for failure
338 * \sa glBufferDataARB, dd_function_table::BufferData.
339 */
340 static GLboolean
341 _mesa_buffer_data( struct gl_context *ctx, GLenum target, GLsizeiptrARB size,
342 const GLvoid * data, GLenum usage,
343 struct gl_buffer_object * bufObj )
344 {
345 void * new_data;
346
347 (void) ctx; (void) target;
348
349 new_data = _mesa_realloc( bufObj->Data, bufObj->Size, size );
350 if (new_data) {
351 bufObj->Data = (GLubyte *) new_data;
352 bufObj->Size = size;
353 bufObj->Usage = usage;
354
355 if (data) {
356 memcpy( bufObj->Data, data, size );
357 }
358
359 return GL_TRUE;
360 }
361 else {
362 return GL_FALSE;
363 }
364 }
365
366
367 /**
368 * Replace data in a subrange of buffer object. If the data range
369 * specified by \c size + \c offset extends beyond the end of the buffer or
370 * if \c data is \c NULL, no copy is performed.
371 *
372 * This is the default callback for \c dd_function_table::BufferSubData()
373 * Note that all GL error checking will have been done already.
374 *
375 * \param ctx GL context.
376 * \param target Buffer object target on which to operate.
377 * \param offset Offset of the first byte to be modified.
378 * \param size Size, in bytes, of the data range.
379 * \param data Pointer to the data to store in the buffer object.
380 * \param bufObj Object to be used.
381 *
382 * \sa glBufferSubDataARB, dd_function_table::BufferSubData.
383 */
384 static void
385 _mesa_buffer_subdata( struct gl_context *ctx, GLenum target, GLintptrARB offset,
386 GLsizeiptrARB size, const GLvoid * data,
387 struct gl_buffer_object * bufObj )
388 {
389 (void) ctx; (void) target;
390
391 /* this should have been caught in _mesa_BufferSubData() */
392 ASSERT(size + offset <= bufObj->Size);
393
394 if (bufObj->Data) {
395 memcpy( (GLubyte *) bufObj->Data + offset, data, size );
396 }
397 }
398
399
400 /**
401 * Retrieve data from a subrange of buffer object. If the data range
402 * specified by \c size + \c offset extends beyond the end of the buffer or
403 * if \c data is \c NULL, no copy is performed.
404 *
405 * This is the default callback for \c dd_function_table::GetBufferSubData()
406 * Note that all GL error checking will have been done already.
407 *
408 * \param ctx GL context.
409 * \param target Buffer object target on which to operate.
410 * \param offset Offset of the first byte to be fetched.
411 * \param size Size, in bytes, of the data range.
412 * \param data Destination for data
413 * \param bufObj Object to be used.
414 *
415 * \sa glBufferGetSubDataARB, dd_function_table::GetBufferSubData.
416 */
417 static void
418 _mesa_buffer_get_subdata( struct gl_context *ctx,
419 GLenum target, GLintptrARB offset,
420 GLsizeiptrARB size, GLvoid * data,
421 struct gl_buffer_object * bufObj )
422 {
423 (void) ctx; (void) target;
424
425 if (bufObj->Data && ((GLsizeiptrARB) (size + offset) <= bufObj->Size)) {
426 memcpy( data, (GLubyte *) bufObj->Data + offset, size );
427 }
428 }
429
430
431 /**
432 * Default callback for \c dd_function_tabel::MapBuffer().
433 *
434 * The function parameters will have been already tested for errors.
435 *
436 * \param ctx GL context.
437 * \param target Buffer object target on which to operate.
438 * \param access Information about how the buffer will be accessed.
439 * \param bufObj Object to be mapped.
440 * \return A pointer to the object's internal data store that can be accessed
441 * by the processor
442 *
443 * \sa glMapBufferARB, dd_function_table::MapBuffer
444 */
445 static void *
446 _mesa_buffer_map( struct gl_context *ctx, GLenum target, GLenum access,
447 struct gl_buffer_object *bufObj )
448 {
449 (void) ctx;
450 (void) target;
451 (void) access;
452 /* Just return a direct pointer to the data */
453 if (_mesa_bufferobj_mapped(bufObj)) {
454 /* already mapped! */
455 return NULL;
456 }
457 bufObj->Pointer = bufObj->Data;
458 bufObj->Length = bufObj->Size;
459 bufObj->Offset = 0;
460 return bufObj->Pointer;
461 }
462
463
464 /**
465 * Default fallback for \c dd_function_table::MapBufferRange().
466 * Called via glMapBufferRange().
467 */
468 static void *
469 _mesa_buffer_map_range( struct gl_context *ctx, GLenum target, GLintptr offset,
470 GLsizeiptr length, GLbitfield access,
471 struct gl_buffer_object *bufObj )
472 {
473 (void) ctx;
474 (void) target;
475 assert(!_mesa_bufferobj_mapped(bufObj));
476 /* Just return a direct pointer to the data */
477 bufObj->Pointer = bufObj->Data + offset;
478 bufObj->Length = length;
479 bufObj->Offset = offset;
480 bufObj->AccessFlags = access;
481 return bufObj->Pointer;
482 }
483
484
485 /**
486 * Default fallback for \c dd_function_table::FlushMappedBufferRange().
487 * Called via glFlushMappedBufferRange().
488 */
489 static void
490 _mesa_buffer_flush_mapped_range( struct gl_context *ctx, GLenum target,
491 GLintptr offset, GLsizeiptr length,
492 struct gl_buffer_object *obj )
493 {
494 (void) ctx;
495 (void) target;
496 (void) offset;
497 (void) length;
498 (void) obj;
499 /* no-op */
500 }
501
502
503 /**
504 * Default callback for \c dd_function_table::MapBuffer().
505 *
506 * The input parameters will have been already tested for errors.
507 *
508 * \sa glUnmapBufferARB, dd_function_table::UnmapBuffer
509 */
510 static GLboolean
511 _mesa_buffer_unmap( struct gl_context *ctx, GLenum target,
512 struct gl_buffer_object *bufObj )
513 {
514 (void) ctx;
515 (void) target;
516 /* XXX we might assert here that bufObj->Pointer is non-null */
517 bufObj->Pointer = NULL;
518 bufObj->Length = 0;
519 bufObj->Offset = 0;
520 bufObj->AccessFlags = 0x0;
521 return GL_TRUE;
522 }
523
524
525 /**
526 * Default fallback for \c dd_function_table::CopyBufferSubData().
527 * Called via glCopyBuffserSubData().
528 */
529 static void
530 _mesa_copy_buffer_subdata(struct gl_context *ctx,
531 struct gl_buffer_object *src,
532 struct gl_buffer_object *dst,
533 GLintptr readOffset, GLintptr writeOffset,
534 GLsizeiptr size)
535 {
536 GLubyte *srcPtr, *dstPtr;
537
538 /* buffer should not already be mapped */
539 assert(!_mesa_bufferobj_mapped(src));
540 assert(!_mesa_bufferobj_mapped(dst));
541
542 srcPtr = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_COPY_READ_BUFFER,
543 GL_READ_ONLY, src);
544 dstPtr = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_COPY_WRITE_BUFFER,
545 GL_WRITE_ONLY, dst);
546
547 if (srcPtr && dstPtr)
548 memcpy(dstPtr + writeOffset, srcPtr + readOffset, size);
549
550 ctx->Driver.UnmapBuffer(ctx, GL_COPY_READ_BUFFER, src);
551 ctx->Driver.UnmapBuffer(ctx, GL_COPY_WRITE_BUFFER, dst);
552 }
553
554
555
556 /**
557 * Initialize the state associated with buffer objects
558 */
559 void
560 _mesa_init_buffer_objects( struct gl_context *ctx )
561 {
562 memset(&DummyBufferObject, 0, sizeof(DummyBufferObject));
563 _glthread_INIT_MUTEX(DummyBufferObject.Mutex);
564 DummyBufferObject.RefCount = 1000*1000*1000; /* never delete */
565
566 _mesa_reference_buffer_object(ctx, &ctx->Array.ArrayBufferObj,
567 ctx->Shared->NullBufferObj);
568 _mesa_reference_buffer_object(ctx, &ctx->Array.ElementArrayBufferObj,
569 ctx->Shared->NullBufferObj);
570
571 _mesa_reference_buffer_object(ctx, &ctx->CopyReadBuffer,
572 ctx->Shared->NullBufferObj);
573 _mesa_reference_buffer_object(ctx, &ctx->CopyWriteBuffer,
574 ctx->Shared->NullBufferObj);
575 }
576
577
578 void
579 _mesa_free_buffer_objects( struct gl_context *ctx )
580 {
581 _mesa_reference_buffer_object(ctx, &ctx->Array.ArrayBufferObj, NULL);
582 _mesa_reference_buffer_object(ctx, &ctx->Array.ElementArrayBufferObj, NULL);
583
584 _mesa_reference_buffer_object(ctx, &ctx->CopyReadBuffer, NULL);
585 _mesa_reference_buffer_object(ctx, &ctx->CopyWriteBuffer, NULL);
586 }
587
588
589 /**
590 * Bind the specified target to buffer for the specified context.
591 * Called by glBindBuffer() and other functions.
592 */
593 static void
594 bind_buffer_object(struct gl_context *ctx, GLenum target, GLuint buffer)
595 {
596 struct gl_buffer_object *oldBufObj;
597 struct gl_buffer_object *newBufObj = NULL;
598 struct gl_buffer_object **bindTarget = NULL;
599
600 bindTarget = get_buffer_target(ctx, target);
601 if (!bindTarget) {
602 _mesa_error(ctx, GL_INVALID_ENUM, "glBindBufferARB(target 0x%x)", target);
603 return;
604 }
605
606 /* Get pointer to old buffer object (to be unbound) */
607 oldBufObj = *bindTarget;
608 if (oldBufObj && oldBufObj->Name == buffer)
609 return; /* rebinding the same buffer object- no change */
610
611 /*
612 * Get pointer to new buffer object (newBufObj)
613 */
614 if (buffer == 0) {
615 /* The spec says there's not a buffer object named 0, but we use
616 * one internally because it simplifies things.
617 */
618 newBufObj = ctx->Shared->NullBufferObj;
619 }
620 else {
621 /* non-default buffer object */
622 newBufObj = _mesa_lookup_bufferobj(ctx, buffer);
623 if (!newBufObj || newBufObj == &DummyBufferObject) {
624 /* If this is a new buffer object id, or one which was generated but
625 * never used before, allocate a buffer object now.
626 */
627 ASSERT(ctx->Driver.NewBufferObject);
628 newBufObj = ctx->Driver.NewBufferObject(ctx, buffer, target);
629 if (!newBufObj) {
630 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindBufferARB");
631 return;
632 }
633 _mesa_HashInsert(ctx->Shared->BufferObjects, buffer, newBufObj);
634 }
635 }
636
637 /* bind new buffer */
638 _mesa_reference_buffer_object(ctx, bindTarget, newBufObj);
639
640 /* Pass BindBuffer call to device driver */
641 if (ctx->Driver.BindBuffer)
642 ctx->Driver.BindBuffer( ctx, target, newBufObj );
643 }
644
645
646 /**
647 * Update the default buffer objects in the given context to reference those
648 * specified in the shared state and release those referencing the old
649 * shared state.
650 */
651 void
652 _mesa_update_default_objects_buffer_objects(struct gl_context *ctx)
653 {
654 /* Bind the NullBufferObj to remove references to those
655 * in the shared context hash table.
656 */
657 bind_buffer_object( ctx, GL_ARRAY_BUFFER_ARB, 0);
658 bind_buffer_object( ctx, GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
659 bind_buffer_object( ctx, GL_PIXEL_PACK_BUFFER_ARB, 0);
660 bind_buffer_object( ctx, GL_PIXEL_UNPACK_BUFFER_ARB, 0);
661 }
662
663
664
665 /**
666 * Return the gl_buffer_object for the given ID.
667 * Always return NULL for ID 0.
668 */
669 struct gl_buffer_object *
670 _mesa_lookup_bufferobj(struct gl_context *ctx, GLuint buffer)
671 {
672 if (buffer == 0)
673 return NULL;
674 else
675 return (struct gl_buffer_object *)
676 _mesa_HashLookup(ctx->Shared->BufferObjects, buffer);
677 }
678
679
680 /**
681 * If *ptr points to obj, set ptr = the Null/default buffer object.
682 * This is a helper for buffer object deletion.
683 * The GL spec says that deleting a buffer object causes it to get
684 * unbound from all arrays in the current context.
685 */
686 static void
687 unbind(struct gl_context *ctx,
688 struct gl_buffer_object **ptr,
689 struct gl_buffer_object *obj)
690 {
691 if (*ptr == obj) {
692 _mesa_reference_buffer_object(ctx, ptr, ctx->Shared->NullBufferObj);
693 }
694 }
695
696
697 /**
698 * Plug default/fallback buffer object functions into the device
699 * driver hooks.
700 */
701 void
702 _mesa_init_buffer_object_functions(struct dd_function_table *driver)
703 {
704 /* GL_ARB_vertex/pixel_buffer_object */
705 driver->NewBufferObject = _mesa_new_buffer_object;
706 driver->DeleteBuffer = _mesa_delete_buffer_object;
707 driver->BindBuffer = NULL;
708 driver->BufferData = _mesa_buffer_data;
709 driver->BufferSubData = _mesa_buffer_subdata;
710 driver->GetBufferSubData = _mesa_buffer_get_subdata;
711 driver->MapBuffer = _mesa_buffer_map;
712 driver->UnmapBuffer = _mesa_buffer_unmap;
713
714 /* GL_ARB_map_buffer_range */
715 driver->MapBufferRange = _mesa_buffer_map_range;
716 driver->FlushMappedBufferRange = _mesa_buffer_flush_mapped_range;
717
718 /* GL_ARB_copy_buffer */
719 driver->CopyBufferSubData = _mesa_copy_buffer_subdata;
720 }
721
722
723
724 /**********************************************************************/
725 /* API Functions */
726 /**********************************************************************/
727
728 void GLAPIENTRY
729 _mesa_BindBufferARB(GLenum target, GLuint buffer)
730 {
731 GET_CURRENT_CONTEXT(ctx);
732 ASSERT_OUTSIDE_BEGIN_END(ctx);
733
734 if (MESA_VERBOSE & VERBOSE_API)
735 _mesa_debug(ctx, "glBindBuffer(%s, %u)\n",
736 _mesa_lookup_enum_by_nr(target), buffer);
737
738 bind_buffer_object(ctx, target, buffer);
739 }
740
741
742 /**
743 * Delete a set of buffer objects.
744 *
745 * \param n Number of buffer objects to delete.
746 * \param ids Array of \c n buffer object IDs.
747 */
748 void GLAPIENTRY
749 _mesa_DeleteBuffersARB(GLsizei n, const GLuint *ids)
750 {
751 GET_CURRENT_CONTEXT(ctx);
752 GLsizei i;
753 ASSERT_OUTSIDE_BEGIN_END(ctx);
754 FLUSH_VERTICES(ctx, 0);
755
756 if (n < 0) {
757 _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteBuffersARB(n)");
758 return;
759 }
760
761 _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
762
763 for (i = 0; i < n; i++) {
764 struct gl_buffer_object *bufObj = _mesa_lookup_bufferobj(ctx, ids[i]);
765 if (bufObj) {
766 struct gl_array_object *arrayObj = ctx->Array.ArrayObj;
767 GLuint j;
768
769 ASSERT(bufObj->Name == ids[i] || bufObj == &DummyBufferObject);
770
771 if (_mesa_bufferobj_mapped(bufObj)) {
772 /* if mapped, unmap it now */
773 ctx->Driver.UnmapBuffer(ctx, 0, bufObj);
774 bufObj->AccessFlags = DEFAULT_ACCESS;
775 bufObj->Pointer = NULL;
776 }
777
778 /* unbind any vertex pointers bound to this buffer */
779 unbind(ctx, &arrayObj->Vertex.BufferObj, bufObj);
780 unbind(ctx, &arrayObj->Weight.BufferObj, bufObj);
781 unbind(ctx, &arrayObj->Normal.BufferObj, bufObj);
782 unbind(ctx, &arrayObj->Color.BufferObj, bufObj);
783 unbind(ctx, &arrayObj->SecondaryColor.BufferObj, bufObj);
784 unbind(ctx, &arrayObj->FogCoord.BufferObj, bufObj);
785 unbind(ctx, &arrayObj->Index.BufferObj, bufObj);
786 unbind(ctx, &arrayObj->EdgeFlag.BufferObj, bufObj);
787 for (j = 0; j < Elements(arrayObj->TexCoord); j++) {
788 unbind(ctx, &arrayObj->TexCoord[j].BufferObj, bufObj);
789 }
790 for (j = 0; j < Elements(arrayObj->VertexAttrib); j++) {
791 unbind(ctx, &arrayObj->VertexAttrib[j].BufferObj, bufObj);
792 }
793
794 if (ctx->Array.ArrayBufferObj == bufObj) {
795 _mesa_BindBufferARB( GL_ARRAY_BUFFER_ARB, 0 );
796 }
797 if (ctx->Array.ElementArrayBufferObj == bufObj) {
798 _mesa_BindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, 0 );
799 }
800
801 /* unbind any pixel pack/unpack pointers bound to this buffer */
802 if (ctx->Pack.BufferObj == bufObj) {
803 _mesa_BindBufferARB( GL_PIXEL_PACK_BUFFER_EXT, 0 );
804 }
805 if (ctx->Unpack.BufferObj == bufObj) {
806 _mesa_BindBufferARB( GL_PIXEL_UNPACK_BUFFER_EXT, 0 );
807 }
808
809 /* The ID is immediately freed for re-use */
810 _mesa_HashRemove(ctx->Shared->BufferObjects, ids[i]);
811 _mesa_reference_buffer_object(ctx, &bufObj, NULL);
812 }
813 }
814
815 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
816 }
817
818
819 /**
820 * Generate a set of unique buffer object IDs and store them in \c buffer.
821 *
822 * \param n Number of IDs to generate.
823 * \param buffer Array of \c n locations to store the IDs.
824 */
825 void GLAPIENTRY
826 _mesa_GenBuffersARB(GLsizei n, GLuint *buffer)
827 {
828 GET_CURRENT_CONTEXT(ctx);
829 GLuint first;
830 GLint i;
831 ASSERT_OUTSIDE_BEGIN_END(ctx);
832
833 if (MESA_VERBOSE & VERBOSE_API)
834 _mesa_debug(ctx, "glGenBuffers(%d)\n", n);
835
836 if (n < 0) {
837 _mesa_error(ctx, GL_INVALID_VALUE, "glGenBuffersARB");
838 return;
839 }
840
841 if (!buffer) {
842 return;
843 }
844
845 /*
846 * This must be atomic (generation and allocation of buffer object IDs)
847 */
848 _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
849
850 first = _mesa_HashFindFreeKeyBlock(ctx->Shared->BufferObjects, n);
851
852 /* Insert the ID and pointer to dummy buffer object into hash table */
853 for (i = 0; i < n; i++) {
854 _mesa_HashInsert(ctx->Shared->BufferObjects, first + i,
855 &DummyBufferObject);
856 buffer[i] = first + i;
857 }
858
859 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
860 }
861
862
863 /**
864 * Determine if ID is the name of a buffer object.
865 *
866 * \param id ID of the potential buffer object.
867 * \return \c GL_TRUE if \c id is the name of a buffer object,
868 * \c GL_FALSE otherwise.
869 */
870 GLboolean GLAPIENTRY
871 _mesa_IsBufferARB(GLuint id)
872 {
873 struct gl_buffer_object *bufObj;
874 GET_CURRENT_CONTEXT(ctx);
875 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
876
877 _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
878 bufObj = _mesa_lookup_bufferobj(ctx, id);
879 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
880
881 return bufObj && bufObj != &DummyBufferObject;
882 }
883
884
885 void GLAPIENTRY
886 _mesa_BufferDataARB(GLenum target, GLsizeiptrARB size,
887 const GLvoid * data, GLenum usage)
888 {
889 GET_CURRENT_CONTEXT(ctx);
890 struct gl_buffer_object *bufObj;
891 ASSERT_OUTSIDE_BEGIN_END(ctx);
892
893 if (MESA_VERBOSE & VERBOSE_API)
894 _mesa_debug(ctx, "glBufferData(%s, %ld, %p, %s)\n",
895 _mesa_lookup_enum_by_nr(target),
896 (long int) size, data,
897 _mesa_lookup_enum_by_nr(usage));
898
899 if (size < 0) {
900 _mesa_error(ctx, GL_INVALID_VALUE, "glBufferDataARB(size < 0)");
901 return;
902 }
903
904 switch (usage) {
905 case GL_STREAM_DRAW_ARB:
906 case GL_STREAM_READ_ARB:
907 case GL_STREAM_COPY_ARB:
908 case GL_STATIC_DRAW_ARB:
909 case GL_STATIC_READ_ARB:
910 case GL_STATIC_COPY_ARB:
911 case GL_DYNAMIC_DRAW_ARB:
912 case GL_DYNAMIC_READ_ARB:
913 case GL_DYNAMIC_COPY_ARB:
914 /* OK */
915 break;
916 default:
917 _mesa_error(ctx, GL_INVALID_ENUM, "glBufferDataARB(usage)");
918 return;
919 }
920
921 bufObj = get_buffer(ctx, target);
922 if (!bufObj) {
923 _mesa_error(ctx, GL_INVALID_ENUM, "glBufferDataARB(target)" );
924 return;
925 }
926 if (!_mesa_is_bufferobj(bufObj)) {
927 _mesa_error(ctx, GL_INVALID_OPERATION, "glBufferDataARB(buffer 0)" );
928 return;
929 }
930
931 if (_mesa_bufferobj_mapped(bufObj)) {
932 /* Unmap the existing buffer. We'll replace it now. Not an error. */
933 ctx->Driver.UnmapBuffer(ctx, target, bufObj);
934 bufObj->AccessFlags = DEFAULT_ACCESS;
935 ASSERT(bufObj->Pointer == NULL);
936 }
937
938 FLUSH_VERTICES(ctx, _NEW_BUFFER_OBJECT);
939
940 bufObj->Written = GL_TRUE;
941
942 #ifdef VBO_DEBUG
943 printf("glBufferDataARB(%u, sz %ld, from %p, usage 0x%x)\n",
944 bufObj->Name, size, data, usage);
945 #endif
946
947 #ifdef BOUNDS_CHECK
948 size += 100;
949 #endif
950
951 ASSERT(ctx->Driver.BufferData);
952 if (!ctx->Driver.BufferData( ctx, target, size, data, usage, bufObj )) {
953 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBufferDataARB()");
954 }
955 }
956
957
958 void GLAPIENTRY
959 _mesa_BufferSubDataARB(GLenum target, GLintptrARB offset,
960 GLsizeiptrARB size, const GLvoid * data)
961 {
962 GET_CURRENT_CONTEXT(ctx);
963 struct gl_buffer_object *bufObj;
964 ASSERT_OUTSIDE_BEGIN_END(ctx);
965
966 bufObj = buffer_object_subdata_range_good( ctx, target, offset, size,
967 "glBufferSubDataARB" );
968 if (!bufObj) {
969 /* error already recorded */
970 return;
971 }
972
973 if (size == 0)
974 return;
975
976 bufObj->Written = GL_TRUE;
977
978 ASSERT(ctx->Driver.BufferSubData);
979 ctx->Driver.BufferSubData( ctx, target, offset, size, data, bufObj );
980 }
981
982
983 void GLAPIENTRY
984 _mesa_GetBufferSubDataARB(GLenum target, GLintptrARB offset,
985 GLsizeiptrARB size, void * data)
986 {
987 GET_CURRENT_CONTEXT(ctx);
988 struct gl_buffer_object *bufObj;
989 ASSERT_OUTSIDE_BEGIN_END(ctx);
990
991 bufObj = buffer_object_subdata_range_good( ctx, target, offset, size,
992 "glGetBufferSubDataARB" );
993 if (!bufObj) {
994 /* error already recorded */
995 return;
996 }
997
998 ASSERT(ctx->Driver.GetBufferSubData);
999 ctx->Driver.GetBufferSubData( ctx, target, offset, size, data, bufObj );
1000 }
1001
1002
1003 void * GLAPIENTRY
1004 _mesa_MapBufferARB(GLenum target, GLenum access)
1005 {
1006 GET_CURRENT_CONTEXT(ctx);
1007 struct gl_buffer_object * bufObj;
1008 GLbitfield accessFlags;
1009 void *map;
1010
1011 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, NULL);
1012
1013 switch (access) {
1014 case GL_READ_ONLY_ARB:
1015 accessFlags = GL_MAP_READ_BIT;
1016 break;
1017 case GL_WRITE_ONLY_ARB:
1018 accessFlags = GL_MAP_WRITE_BIT;
1019 break;
1020 case GL_READ_WRITE_ARB:
1021 accessFlags = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT;
1022 break;
1023 default:
1024 _mesa_error(ctx, GL_INVALID_ENUM, "glMapBufferARB(access)");
1025 return NULL;
1026 }
1027
1028 bufObj = get_buffer(ctx, target);
1029 if (!bufObj) {
1030 _mesa_error(ctx, GL_INVALID_ENUM, "glMapBufferARB(target)" );
1031 return NULL;
1032 }
1033 if (!_mesa_is_bufferobj(bufObj)) {
1034 _mesa_error(ctx, GL_INVALID_OPERATION, "glMapBufferARB(buffer 0)" );
1035 return NULL;
1036 }
1037 if (_mesa_bufferobj_mapped(bufObj)) {
1038 _mesa_error(ctx, GL_INVALID_OPERATION, "glMapBufferARB(already mapped)");
1039 return NULL;
1040 }
1041
1042 ASSERT(ctx->Driver.MapBuffer);
1043 map = ctx->Driver.MapBuffer( ctx, target, access, bufObj );
1044 if (!map) {
1045 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glMapBufferARB(map failed)");
1046 return NULL;
1047 }
1048 else {
1049 /* The driver callback should have set these fields.
1050 * This is important because other modules (like VBO) might call
1051 * the driver function directly.
1052 */
1053 ASSERT(bufObj->Pointer == map);
1054 ASSERT(bufObj->Length == bufObj->Size);
1055 ASSERT(bufObj->Offset == 0);
1056 bufObj->AccessFlags = accessFlags;
1057 }
1058
1059 if (access == GL_WRITE_ONLY_ARB || access == GL_READ_WRITE_ARB)
1060 bufObj->Written = GL_TRUE;
1061
1062 #ifdef VBO_DEBUG
1063 printf("glMapBufferARB(%u, sz %ld, access 0x%x)\n",
1064 bufObj->Name, bufObj->Size, access);
1065 if (access == GL_WRITE_ONLY_ARB) {
1066 GLuint i;
1067 GLubyte *b = (GLubyte *) bufObj->Pointer;
1068 for (i = 0; i < bufObj->Size; i++)
1069 b[i] = i & 0xff;
1070 }
1071 #endif
1072
1073 #ifdef BOUNDS_CHECK
1074 {
1075 GLubyte *buf = (GLubyte *) bufObj->Pointer;
1076 GLuint i;
1077 /* buffer is 100 bytes larger than requested, fill with magic value */
1078 for (i = 0; i < 100; i++) {
1079 buf[bufObj->Size - i - 1] = 123;
1080 }
1081 }
1082 #endif
1083
1084 return bufObj->Pointer;
1085 }
1086
1087
1088 GLboolean GLAPIENTRY
1089 _mesa_UnmapBufferARB(GLenum target)
1090 {
1091 GET_CURRENT_CONTEXT(ctx);
1092 struct gl_buffer_object *bufObj;
1093 GLboolean status = GL_TRUE;
1094 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
1095
1096 bufObj = get_buffer(ctx, target);
1097 if (!bufObj) {
1098 _mesa_error(ctx, GL_INVALID_ENUM, "glUnmapBufferARB(target)" );
1099 return GL_FALSE;
1100 }
1101 if (!_mesa_is_bufferobj(bufObj)) {
1102 _mesa_error(ctx, GL_INVALID_OPERATION, "glUnmapBufferARB" );
1103 return GL_FALSE;
1104 }
1105 if (!_mesa_bufferobj_mapped(bufObj)) {
1106 _mesa_error(ctx, GL_INVALID_OPERATION, "glUnmapBufferARB");
1107 return GL_FALSE;
1108 }
1109
1110 #ifdef BOUNDS_CHECK
1111 if (bufObj->Access != GL_READ_ONLY_ARB) {
1112 GLubyte *buf = (GLubyte *) bufObj->Pointer;
1113 GLuint i;
1114 /* check that last 100 bytes are still = magic value */
1115 for (i = 0; i < 100; i++) {
1116 GLuint pos = bufObj->Size - i - 1;
1117 if (buf[pos] != 123) {
1118 _mesa_warning(ctx, "Out of bounds buffer object write detected"
1119 " at position %d (value = %u)\n",
1120 pos, buf[pos]);
1121 }
1122 }
1123 }
1124 #endif
1125
1126 #ifdef VBO_DEBUG
1127 if (bufObj->AccessFlags & GL_MAP_WRITE_BIT) {
1128 GLuint i, unchanged = 0;
1129 GLubyte *b = (GLubyte *) bufObj->Pointer;
1130 GLint pos = -1;
1131 /* check which bytes changed */
1132 for (i = 0; i < bufObj->Size - 1; i++) {
1133 if (b[i] == (i & 0xff) && b[i+1] == ((i+1) & 0xff)) {
1134 unchanged++;
1135 if (pos == -1)
1136 pos = i;
1137 }
1138 }
1139 if (unchanged) {
1140 printf("glUnmapBufferARB(%u): %u of %ld unchanged, starting at %d\n",
1141 bufObj->Name, unchanged, bufObj->Size, pos);
1142 }
1143 }
1144 #endif
1145
1146 status = ctx->Driver.UnmapBuffer( ctx, target, bufObj );
1147 bufObj->AccessFlags = DEFAULT_ACCESS;
1148 ASSERT(bufObj->Pointer == NULL);
1149 ASSERT(bufObj->Offset == 0);
1150 ASSERT(bufObj->Length == 0);
1151
1152 return status;
1153 }
1154
1155
1156 void GLAPIENTRY
1157 _mesa_GetBufferParameterivARB(GLenum target, GLenum pname, GLint *params)
1158 {
1159 GET_CURRENT_CONTEXT(ctx);
1160 struct gl_buffer_object *bufObj;
1161 ASSERT_OUTSIDE_BEGIN_END(ctx);
1162
1163 bufObj = get_buffer(ctx, target);
1164 if (!bufObj) {
1165 _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferParameterivARB(target)" );
1166 return;
1167 }
1168 if (!_mesa_is_bufferobj(bufObj)) {
1169 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetBufferParameterivARB" );
1170 return;
1171 }
1172
1173 switch (pname) {
1174 case GL_BUFFER_SIZE_ARB:
1175 *params = (GLint) bufObj->Size;
1176 return;
1177 case GL_BUFFER_USAGE_ARB:
1178 *params = bufObj->Usage;
1179 return;
1180 case GL_BUFFER_ACCESS_ARB:
1181 *params = simplified_access_mode(bufObj->AccessFlags);
1182 return;
1183 case GL_BUFFER_MAPPED_ARB:
1184 *params = _mesa_bufferobj_mapped(bufObj);
1185 return;
1186 case GL_BUFFER_ACCESS_FLAGS:
1187 if (ctx->VersionMajor < 3)
1188 goto invalid_pname;
1189 *params = bufObj->AccessFlags;
1190 return;
1191 case GL_BUFFER_MAP_OFFSET:
1192 if (ctx->VersionMajor < 3)
1193 goto invalid_pname;
1194 *params = (GLint) bufObj->Offset;
1195 return;
1196 case GL_BUFFER_MAP_LENGTH:
1197 if (ctx->VersionMajor < 3)
1198 goto invalid_pname;
1199 *params = (GLint) bufObj->Length;
1200 return;
1201 default:
1202 ; /* fall-through */
1203 }
1204
1205 invalid_pname:
1206 _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferParameterivARB(pname=%s)",
1207 _mesa_lookup_enum_by_nr(pname));
1208 }
1209
1210
1211 /**
1212 * New in GL 3.2
1213 * This is pretty much a duplicate of GetBufferParameteriv() but the
1214 * GL_BUFFER_SIZE_ARB attribute will be 64-bits on a 64-bit system.
1215 */
1216 void GLAPIENTRY
1217 _mesa_GetBufferParameteri64v(GLenum target, GLenum pname, GLint64 *params)
1218 {
1219 GET_CURRENT_CONTEXT(ctx);
1220 struct gl_buffer_object *bufObj;
1221 ASSERT_OUTSIDE_BEGIN_END(ctx);
1222
1223 bufObj = get_buffer(ctx, target);
1224 if (!bufObj) {
1225 _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferParameteri64v(target)" );
1226 return;
1227 }
1228 if (!_mesa_is_bufferobj(bufObj)) {
1229 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetBufferParameteri64v" );
1230 return;
1231 }
1232
1233 switch (pname) {
1234 case GL_BUFFER_SIZE_ARB:
1235 *params = bufObj->Size;
1236 return;
1237 case GL_BUFFER_USAGE_ARB:
1238 *params = bufObj->Usage;
1239 return;
1240 case GL_BUFFER_ACCESS_ARB:
1241 *params = simplified_access_mode(bufObj->AccessFlags);
1242 return;
1243 case GL_BUFFER_ACCESS_FLAGS:
1244 if (ctx->VersionMajor < 3)
1245 goto invalid_pname;
1246 *params = bufObj->AccessFlags;
1247 return;
1248 case GL_BUFFER_MAPPED_ARB:
1249 *params = _mesa_bufferobj_mapped(bufObj);
1250 return;
1251 case GL_BUFFER_MAP_OFFSET:
1252 if (ctx->VersionMajor < 3)
1253 goto invalid_pname;
1254 *params = bufObj->Offset;
1255 return;
1256 case GL_BUFFER_MAP_LENGTH:
1257 if (ctx->VersionMajor < 3)
1258 goto invalid_pname;
1259 *params = bufObj->Length;
1260 return;
1261 default:
1262 ; /* fall-through */
1263 }
1264
1265 invalid_pname:
1266 _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferParameteri64v(pname=%s)",
1267 _mesa_lookup_enum_by_nr(pname));
1268 }
1269
1270
1271 void GLAPIENTRY
1272 _mesa_GetBufferPointervARB(GLenum target, GLenum pname, GLvoid **params)
1273 {
1274 GET_CURRENT_CONTEXT(ctx);
1275 struct gl_buffer_object * bufObj;
1276 ASSERT_OUTSIDE_BEGIN_END(ctx);
1277
1278 if (pname != GL_BUFFER_MAP_POINTER_ARB) {
1279 _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferPointervARB(pname)");
1280 return;
1281 }
1282
1283 bufObj = get_buffer(ctx, target);
1284 if (!bufObj) {
1285 _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferPointervARB(target)" );
1286 return;
1287 }
1288 if (!_mesa_is_bufferobj(bufObj)) {
1289 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetBufferPointervARB" );
1290 return;
1291 }
1292
1293 *params = bufObj->Pointer;
1294 }
1295
1296
1297 void GLAPIENTRY
1298 _mesa_CopyBufferSubData(GLenum readTarget, GLenum writeTarget,
1299 GLintptr readOffset, GLintptr writeOffset,
1300 GLsizeiptr size)
1301 {
1302 GET_CURRENT_CONTEXT(ctx);
1303 struct gl_buffer_object *src, *dst;
1304 ASSERT_OUTSIDE_BEGIN_END(ctx);
1305
1306 src = get_buffer(ctx, readTarget);
1307 if (!src || !_mesa_is_bufferobj(src)) {
1308 _mesa_error(ctx, GL_INVALID_ENUM,
1309 "glCopyBuffserSubData(readTarget = 0x%x)", readTarget);
1310 return;
1311 }
1312
1313 dst = get_buffer(ctx, writeTarget);
1314 if (!dst || !_mesa_is_bufferobj(dst)) {
1315 _mesa_error(ctx, GL_INVALID_ENUM,
1316 "glCopyBuffserSubData(writeTarget = 0x%x)", writeTarget);
1317 return;
1318 }
1319
1320 if (_mesa_bufferobj_mapped(src)) {
1321 _mesa_error(ctx, GL_INVALID_OPERATION,
1322 "glCopyBuffserSubData(readBuffer is mapped)");
1323 return;
1324 }
1325
1326 if (_mesa_bufferobj_mapped(dst)) {
1327 _mesa_error(ctx, GL_INVALID_OPERATION,
1328 "glCopyBuffserSubData(writeBuffer is mapped)");
1329 return;
1330 }
1331
1332 if (readOffset < 0) {
1333 _mesa_error(ctx, GL_INVALID_VALUE,
1334 "glCopyBuffserSubData(readOffset = %d)", (int) readOffset);
1335 return;
1336 }
1337
1338 if (writeOffset < 0) {
1339 _mesa_error(ctx, GL_INVALID_VALUE,
1340 "glCopyBuffserSubData(writeOffset = %d)", (int) writeOffset);
1341 return;
1342 }
1343
1344 if (readOffset + size > src->Size) {
1345 _mesa_error(ctx, GL_INVALID_VALUE,
1346 "glCopyBuffserSubData(readOffset + size = %d)",
1347 (int) (readOffset + size));
1348 return;
1349 }
1350
1351 if (writeOffset + size > dst->Size) {
1352 _mesa_error(ctx, GL_INVALID_VALUE,
1353 "glCopyBuffserSubData(writeOffset + size = %d)",
1354 (int) (writeOffset + size));
1355 return;
1356 }
1357
1358 if (src == dst) {
1359 if (readOffset + size <= writeOffset) {
1360 /* OK */
1361 }
1362 else if (writeOffset + size <= readOffset) {
1363 /* OK */
1364 }
1365 else {
1366 /* overlapping src/dst is illegal */
1367 _mesa_error(ctx, GL_INVALID_VALUE,
1368 "glCopyBuffserSubData(overlapping src/dst)");
1369 return;
1370 }
1371 }
1372
1373 ctx->Driver.CopyBufferSubData(ctx, src, dst, readOffset, writeOffset, size);
1374 }
1375
1376
1377 /**
1378 * See GL_ARB_map_buffer_range spec
1379 */
1380 void * GLAPIENTRY
1381 _mesa_MapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length,
1382 GLbitfield access)
1383 {
1384 GET_CURRENT_CONTEXT(ctx);
1385 struct gl_buffer_object *bufObj;
1386 void *map;
1387
1388 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, NULL);
1389
1390 if (!ctx->Extensions.ARB_map_buffer_range) {
1391 _mesa_error(ctx, GL_INVALID_OPERATION,
1392 "glMapBufferRange(extension not supported)");
1393 return NULL;
1394 }
1395
1396 if (offset < 0) {
1397 _mesa_error(ctx, GL_INVALID_VALUE,
1398 "glMapBufferRange(offset = %ld)", (long)offset);
1399 return NULL;
1400 }
1401
1402 if (length < 0) {
1403 _mesa_error(ctx, GL_INVALID_VALUE,
1404 "glMapBufferRange(length = %ld)", (long)length);
1405 return NULL;
1406 }
1407
1408 if ((access & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)) == 0) {
1409 _mesa_error(ctx, GL_INVALID_OPERATION,
1410 "glMapBufferRange(access indicates neither read or write)");
1411 return NULL;
1412 }
1413
1414 if (access & GL_MAP_READ_BIT) {
1415 if ((access & GL_MAP_INVALIDATE_RANGE_BIT) ||
1416 (access & GL_MAP_INVALIDATE_BUFFER_BIT) ||
1417 (access & GL_MAP_UNSYNCHRONIZED_BIT)) {
1418 _mesa_error(ctx, GL_INVALID_OPERATION,
1419 "glMapBufferRange(invalid access flags)");
1420 return NULL;
1421 }
1422 }
1423
1424 if ((access & GL_MAP_FLUSH_EXPLICIT_BIT) &&
1425 ((access & GL_MAP_WRITE_BIT) == 0)) {
1426 _mesa_error(ctx, GL_INVALID_OPERATION,
1427 "glMapBufferRange(invalid access flags)");
1428 return NULL;
1429 }
1430
1431 bufObj = get_buffer(ctx, target);
1432 if (!bufObj || !_mesa_is_bufferobj(bufObj)) {
1433 _mesa_error(ctx, GL_INVALID_ENUM,
1434 "glMapBufferRange(target = 0x%x)", target);
1435 return NULL;
1436 }
1437
1438 if (offset + length > bufObj->Size) {
1439 _mesa_error(ctx, GL_INVALID_VALUE,
1440 "glMapBufferRange(offset + length > size)");
1441 return NULL;
1442 }
1443
1444 if (_mesa_bufferobj_mapped(bufObj)) {
1445 _mesa_error(ctx, GL_INVALID_OPERATION,
1446 "glMapBufferRange(buffer already mapped)");
1447 return NULL;
1448 }
1449
1450 ASSERT(ctx->Driver.MapBufferRange);
1451 map = ctx->Driver.MapBufferRange(ctx, target, offset, length,
1452 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, target, 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 */