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