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