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