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