Merge branch 'llvm-cliptest-viewport'
[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 bufObj->Written = GL_TRUE;
1193
1194 ASSERT(ctx->Driver.BufferSubData);
1195 ctx->Driver.BufferSubData( ctx, target, offset, size, data, bufObj );
1196 }
1197
1198
1199 void GLAPIENTRY
1200 _mesa_GetBufferSubDataARB(GLenum target, GLintptrARB offset,
1201 GLsizeiptrARB size, void * data)
1202 {
1203 GET_CURRENT_CONTEXT(ctx);
1204 struct gl_buffer_object *bufObj;
1205 ASSERT_OUTSIDE_BEGIN_END(ctx);
1206
1207 bufObj = buffer_object_subdata_range_good( ctx, target, offset, size,
1208 "glGetBufferSubDataARB" );
1209 if (!bufObj) {
1210 /* error already recorded */
1211 return;
1212 }
1213
1214 ASSERT(ctx->Driver.GetBufferSubData);
1215 ctx->Driver.GetBufferSubData( ctx, target, offset, size, data, bufObj );
1216 }
1217
1218
1219 void * GLAPIENTRY
1220 _mesa_MapBufferARB(GLenum target, GLenum access)
1221 {
1222 GET_CURRENT_CONTEXT(ctx);
1223 struct gl_buffer_object * bufObj;
1224 GLbitfield accessFlags;
1225 void *map;
1226
1227 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, NULL);
1228
1229 switch (access) {
1230 case GL_READ_ONLY_ARB:
1231 accessFlags = GL_MAP_READ_BIT;
1232 break;
1233 case GL_WRITE_ONLY_ARB:
1234 accessFlags = GL_MAP_WRITE_BIT;
1235 break;
1236 case GL_READ_WRITE_ARB:
1237 accessFlags = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT;
1238 break;
1239 default:
1240 _mesa_error(ctx, GL_INVALID_ENUM, "glMapBufferARB(access)");
1241 return NULL;
1242 }
1243
1244 bufObj = get_buffer(ctx, target);
1245 if (!bufObj) {
1246 _mesa_error(ctx, GL_INVALID_ENUM, "glMapBufferARB(target)" );
1247 return NULL;
1248 }
1249 if (!_mesa_is_bufferobj(bufObj)) {
1250 _mesa_error(ctx, GL_INVALID_OPERATION, "glMapBufferARB(buffer 0)" );
1251 return NULL;
1252 }
1253 if (_mesa_bufferobj_mapped(bufObj)) {
1254 _mesa_error(ctx, GL_INVALID_OPERATION, "glMapBufferARB(already mapped)");
1255 return NULL;
1256 }
1257
1258 ASSERT(ctx->Driver.MapBuffer);
1259 map = ctx->Driver.MapBuffer( ctx, target, access, bufObj );
1260 if (!map) {
1261 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glMapBufferARB(map failed)");
1262 return NULL;
1263 }
1264 else {
1265 /* The driver callback should have set these fields.
1266 * This is important because other modules (like VBO) might call
1267 * the driver function directly.
1268 */
1269 ASSERT(bufObj->Pointer == map);
1270 ASSERT(bufObj->Length == bufObj->Size);
1271 ASSERT(bufObj->Offset == 0);
1272 bufObj->AccessFlags = accessFlags;
1273 }
1274
1275 if (access == GL_WRITE_ONLY_ARB || access == GL_READ_WRITE_ARB)
1276 bufObj->Written = GL_TRUE;
1277
1278 #ifdef VBO_DEBUG
1279 printf("glMapBufferARB(%u, sz %ld, access 0x%x)\n",
1280 bufObj->Name, bufObj->Size, access);
1281 if (access == GL_WRITE_ONLY_ARB) {
1282 GLuint i;
1283 GLubyte *b = (GLubyte *) bufObj->Pointer;
1284 for (i = 0; i < bufObj->Size; i++)
1285 b[i] = i & 0xff;
1286 }
1287 #endif
1288
1289 #ifdef BOUNDS_CHECK
1290 {
1291 GLubyte *buf = (GLubyte *) bufObj->Pointer;
1292 GLuint i;
1293 /* buffer is 100 bytes larger than requested, fill with magic value */
1294 for (i = 0; i < 100; i++) {
1295 buf[bufObj->Size - i - 1] = 123;
1296 }
1297 }
1298 #endif
1299
1300 return bufObj->Pointer;
1301 }
1302
1303
1304 GLboolean GLAPIENTRY
1305 _mesa_UnmapBufferARB(GLenum target)
1306 {
1307 GET_CURRENT_CONTEXT(ctx);
1308 struct gl_buffer_object *bufObj;
1309 GLboolean status = GL_TRUE;
1310 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
1311
1312 bufObj = get_buffer(ctx, target);
1313 if (!bufObj) {
1314 _mesa_error(ctx, GL_INVALID_ENUM, "glUnmapBufferARB(target)" );
1315 return GL_FALSE;
1316 }
1317 if (!_mesa_is_bufferobj(bufObj)) {
1318 _mesa_error(ctx, GL_INVALID_OPERATION, "glUnmapBufferARB" );
1319 return GL_FALSE;
1320 }
1321 if (!_mesa_bufferobj_mapped(bufObj)) {
1322 _mesa_error(ctx, GL_INVALID_OPERATION, "glUnmapBufferARB");
1323 return GL_FALSE;
1324 }
1325
1326 #ifdef BOUNDS_CHECK
1327 if (bufObj->Access != GL_READ_ONLY_ARB) {
1328 GLubyte *buf = (GLubyte *) bufObj->Pointer;
1329 GLuint i;
1330 /* check that last 100 bytes are still = magic value */
1331 for (i = 0; i < 100; i++) {
1332 GLuint pos = bufObj->Size - i - 1;
1333 if (buf[pos] != 123) {
1334 _mesa_warning(ctx, "Out of bounds buffer object write detected"
1335 " at position %d (value = %u)\n",
1336 pos, buf[pos]);
1337 }
1338 }
1339 }
1340 #endif
1341
1342 #ifdef VBO_DEBUG
1343 if (bufObj->AccessFlags & GL_MAP_WRITE_BIT) {
1344 GLuint i, unchanged = 0;
1345 GLubyte *b = (GLubyte *) bufObj->Pointer;
1346 GLint pos = -1;
1347 /* check which bytes changed */
1348 for (i = 0; i < bufObj->Size - 1; i++) {
1349 if (b[i] == (i & 0xff) && b[i+1] == ((i+1) & 0xff)) {
1350 unchanged++;
1351 if (pos == -1)
1352 pos = i;
1353 }
1354 }
1355 if (unchanged) {
1356 printf("glUnmapBufferARB(%u): %u of %ld unchanged, starting at %d\n",
1357 bufObj->Name, unchanged, bufObj->Size, pos);
1358 }
1359 }
1360 #endif
1361
1362 status = ctx->Driver.UnmapBuffer( ctx, target, bufObj );
1363 bufObj->AccessFlags = DEFAULT_ACCESS;
1364 ASSERT(bufObj->Pointer == NULL);
1365 ASSERT(bufObj->Offset == 0);
1366 ASSERT(bufObj->Length == 0);
1367
1368 return status;
1369 }
1370
1371
1372 void GLAPIENTRY
1373 _mesa_GetBufferParameterivARB(GLenum target, GLenum pname, GLint *params)
1374 {
1375 GET_CURRENT_CONTEXT(ctx);
1376 struct gl_buffer_object *bufObj;
1377 ASSERT_OUTSIDE_BEGIN_END(ctx);
1378
1379 bufObj = get_buffer(ctx, target);
1380 if (!bufObj) {
1381 _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferParameterivARB(target)" );
1382 return;
1383 }
1384 if (!_mesa_is_bufferobj(bufObj)) {
1385 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetBufferParameterivARB" );
1386 return;
1387 }
1388
1389 switch (pname) {
1390 case GL_BUFFER_SIZE_ARB:
1391 *params = (GLint) bufObj->Size;
1392 return;
1393 case GL_BUFFER_USAGE_ARB:
1394 *params = bufObj->Usage;
1395 return;
1396 case GL_BUFFER_ACCESS_ARB:
1397 *params = simplified_access_mode(bufObj->AccessFlags);
1398 return;
1399 case GL_BUFFER_MAPPED_ARB:
1400 *params = _mesa_bufferobj_mapped(bufObj);
1401 return;
1402 case GL_BUFFER_ACCESS_FLAGS:
1403 if (ctx->VersionMajor < 3)
1404 goto invalid_pname;
1405 *params = bufObj->AccessFlags;
1406 return;
1407 case GL_BUFFER_MAP_OFFSET:
1408 if (ctx->VersionMajor < 3)
1409 goto invalid_pname;
1410 *params = (GLint) bufObj->Offset;
1411 return;
1412 case GL_BUFFER_MAP_LENGTH:
1413 if (ctx->VersionMajor < 3)
1414 goto invalid_pname;
1415 *params = (GLint) bufObj->Length;
1416 return;
1417 default:
1418 ; /* fall-through */
1419 }
1420
1421 invalid_pname:
1422 _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferParameterivARB(pname=%s)",
1423 _mesa_lookup_enum_by_nr(pname));
1424 }
1425
1426
1427 /**
1428 * New in GL 3.2
1429 * This is pretty much a duplicate of GetBufferParameteriv() but the
1430 * GL_BUFFER_SIZE_ARB attribute will be 64-bits on a 64-bit system.
1431 */
1432 void GLAPIENTRY
1433 _mesa_GetBufferParameteri64v(GLenum target, GLenum pname, GLint64 *params)
1434 {
1435 GET_CURRENT_CONTEXT(ctx);
1436 struct gl_buffer_object *bufObj;
1437 ASSERT_OUTSIDE_BEGIN_END(ctx);
1438
1439 bufObj = get_buffer(ctx, target);
1440 if (!bufObj) {
1441 _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferParameteri64v(target)" );
1442 return;
1443 }
1444 if (!_mesa_is_bufferobj(bufObj)) {
1445 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetBufferParameteri64v" );
1446 return;
1447 }
1448
1449 switch (pname) {
1450 case GL_BUFFER_SIZE_ARB:
1451 *params = bufObj->Size;
1452 return;
1453 case GL_BUFFER_USAGE_ARB:
1454 *params = bufObj->Usage;
1455 return;
1456 case GL_BUFFER_ACCESS_ARB:
1457 *params = simplified_access_mode(bufObj->AccessFlags);
1458 return;
1459 case GL_BUFFER_ACCESS_FLAGS:
1460 if (ctx->VersionMajor < 3)
1461 goto invalid_pname;
1462 *params = bufObj->AccessFlags;
1463 return;
1464 case GL_BUFFER_MAPPED_ARB:
1465 *params = _mesa_bufferobj_mapped(bufObj);
1466 return;
1467 case GL_BUFFER_MAP_OFFSET:
1468 if (ctx->VersionMajor < 3)
1469 goto invalid_pname;
1470 *params = bufObj->Offset;
1471 return;
1472 case GL_BUFFER_MAP_LENGTH:
1473 if (ctx->VersionMajor < 3)
1474 goto invalid_pname;
1475 *params = bufObj->Length;
1476 return;
1477 default:
1478 ; /* fall-through */
1479 }
1480
1481 invalid_pname:
1482 _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferParameteri64v(pname=%s)",
1483 _mesa_lookup_enum_by_nr(pname));
1484 }
1485
1486
1487 void GLAPIENTRY
1488 _mesa_GetBufferPointervARB(GLenum target, GLenum pname, GLvoid **params)
1489 {
1490 GET_CURRENT_CONTEXT(ctx);
1491 struct gl_buffer_object * bufObj;
1492 ASSERT_OUTSIDE_BEGIN_END(ctx);
1493
1494 if (pname != GL_BUFFER_MAP_POINTER_ARB) {
1495 _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferPointervARB(pname)");
1496 return;
1497 }
1498
1499 bufObj = get_buffer(ctx, target);
1500 if (!bufObj) {
1501 _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferPointervARB(target)" );
1502 return;
1503 }
1504 if (!_mesa_is_bufferobj(bufObj)) {
1505 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetBufferPointervARB" );
1506 return;
1507 }
1508
1509 *params = bufObj->Pointer;
1510 }
1511
1512
1513 void GLAPIENTRY
1514 _mesa_CopyBufferSubData(GLenum readTarget, GLenum writeTarget,
1515 GLintptr readOffset, GLintptr writeOffset,
1516 GLsizeiptr size)
1517 {
1518 GET_CURRENT_CONTEXT(ctx);
1519 struct gl_buffer_object *src, *dst;
1520 ASSERT_OUTSIDE_BEGIN_END(ctx);
1521
1522 src = get_buffer(ctx, readTarget);
1523 if (!src || !_mesa_is_bufferobj(src)) {
1524 _mesa_error(ctx, GL_INVALID_ENUM,
1525 "glCopyBuffserSubData(readTarget = 0x%x)", readTarget);
1526 return;
1527 }
1528
1529 dst = get_buffer(ctx, writeTarget);
1530 if (!dst || !_mesa_is_bufferobj(dst)) {
1531 _mesa_error(ctx, GL_INVALID_ENUM,
1532 "glCopyBuffserSubData(writeTarget = 0x%x)", writeTarget);
1533 return;
1534 }
1535
1536 if (_mesa_bufferobj_mapped(src)) {
1537 _mesa_error(ctx, GL_INVALID_OPERATION,
1538 "glCopyBuffserSubData(readBuffer is mapped)");
1539 return;
1540 }
1541
1542 if (_mesa_bufferobj_mapped(dst)) {
1543 _mesa_error(ctx, GL_INVALID_OPERATION,
1544 "glCopyBuffserSubData(writeBuffer is mapped)");
1545 return;
1546 }
1547
1548 if (readOffset < 0) {
1549 _mesa_error(ctx, GL_INVALID_VALUE,
1550 "glCopyBuffserSubData(readOffset = %d)", (int) readOffset);
1551 return;
1552 }
1553
1554 if (writeOffset < 0) {
1555 _mesa_error(ctx, GL_INVALID_VALUE,
1556 "glCopyBuffserSubData(writeOffset = %d)", (int) writeOffset);
1557 return;
1558 }
1559
1560 if (readOffset + size > src->Size) {
1561 _mesa_error(ctx, GL_INVALID_VALUE,
1562 "glCopyBuffserSubData(readOffset + size = %d)",
1563 (int) (readOffset + size));
1564 return;
1565 }
1566
1567 if (writeOffset + size > dst->Size) {
1568 _mesa_error(ctx, GL_INVALID_VALUE,
1569 "glCopyBuffserSubData(writeOffset + size = %d)",
1570 (int) (writeOffset + size));
1571 return;
1572 }
1573
1574 if (src == dst) {
1575 if (readOffset + size <= writeOffset) {
1576 /* OK */
1577 }
1578 else if (writeOffset + size <= readOffset) {
1579 /* OK */
1580 }
1581 else {
1582 /* overlapping src/dst is illegal */
1583 _mesa_error(ctx, GL_INVALID_VALUE,
1584 "glCopyBuffserSubData(overlapping src/dst)");
1585 return;
1586 }
1587 }
1588
1589 ctx->Driver.CopyBufferSubData(ctx, src, dst, readOffset, writeOffset, size);
1590 }
1591
1592
1593 /**
1594 * See GL_ARB_map_buffer_range spec
1595 */
1596 void * GLAPIENTRY
1597 _mesa_MapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length,
1598 GLbitfield access)
1599 {
1600 GET_CURRENT_CONTEXT(ctx);
1601 struct gl_buffer_object *bufObj;
1602 void *map;
1603
1604 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, NULL);
1605
1606 if (!ctx->Extensions.ARB_map_buffer_range) {
1607 _mesa_error(ctx, GL_INVALID_OPERATION,
1608 "glMapBufferRange(extension not supported)");
1609 return NULL;
1610 }
1611
1612 if (offset < 0) {
1613 _mesa_error(ctx, GL_INVALID_VALUE,
1614 "glMapBufferRange(offset = %ld)", (long)offset);
1615 return NULL;
1616 }
1617
1618 if (length < 0) {
1619 _mesa_error(ctx, GL_INVALID_VALUE,
1620 "glMapBufferRange(length = %ld)", (long)length);
1621 return NULL;
1622 }
1623
1624 if ((access & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)) == 0) {
1625 _mesa_error(ctx, GL_INVALID_OPERATION,
1626 "glMapBufferRange(access indicates neither read or write)");
1627 return NULL;
1628 }
1629
1630 if (access & GL_MAP_READ_BIT) {
1631 if ((access & GL_MAP_INVALIDATE_RANGE_BIT) ||
1632 (access & GL_MAP_INVALIDATE_BUFFER_BIT) ||
1633 (access & GL_MAP_UNSYNCHRONIZED_BIT)) {
1634 _mesa_error(ctx, GL_INVALID_OPERATION,
1635 "glMapBufferRange(invalid access flags)");
1636 return NULL;
1637 }
1638 }
1639
1640 if ((access & GL_MAP_FLUSH_EXPLICIT_BIT) &&
1641 ((access & GL_MAP_WRITE_BIT) == 0)) {
1642 _mesa_error(ctx, GL_INVALID_OPERATION,
1643 "glMapBufferRange(invalid access flags)");
1644 return NULL;
1645 }
1646
1647 bufObj = get_buffer(ctx, target);
1648 if (!bufObj || !_mesa_is_bufferobj(bufObj)) {
1649 _mesa_error(ctx, GL_INVALID_ENUM,
1650 "glMapBufferRange(target = 0x%x)", target);
1651 return NULL;
1652 }
1653
1654 if (offset + length > bufObj->Size) {
1655 _mesa_error(ctx, GL_INVALID_VALUE,
1656 "glMapBufferRange(offset + length > size)");
1657 return NULL;
1658 }
1659
1660 if (_mesa_bufferobj_mapped(bufObj)) {
1661 _mesa_error(ctx, GL_INVALID_OPERATION,
1662 "glMapBufferRange(buffer already mapped)");
1663 return NULL;
1664 }
1665
1666 ASSERT(ctx->Driver.MapBufferRange);
1667 map = ctx->Driver.MapBufferRange(ctx, target, offset, length,
1668 access, bufObj);
1669 if (!map) {
1670 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glMapBufferARB(map failed)");
1671 }
1672 else {
1673 /* The driver callback should have set all these fields.
1674 * This is important because other modules (like VBO) might call
1675 * the driver function directly.
1676 */
1677 ASSERT(bufObj->Pointer == map);
1678 ASSERT(bufObj->Length == length);
1679 ASSERT(bufObj->Offset == offset);
1680 ASSERT(bufObj->AccessFlags == access);
1681 }
1682
1683 return map;
1684 }
1685
1686
1687 /**
1688 * See GL_ARB_map_buffer_range spec
1689 */
1690 void GLAPIENTRY
1691 _mesa_FlushMappedBufferRange(GLenum target, GLintptr offset, GLsizeiptr length)
1692 {
1693 GET_CURRENT_CONTEXT(ctx);
1694 struct gl_buffer_object *bufObj;
1695 ASSERT_OUTSIDE_BEGIN_END(ctx);
1696
1697 if (!ctx->Extensions.ARB_map_buffer_range) {
1698 _mesa_error(ctx, GL_INVALID_OPERATION,
1699 "glMapBufferRange(extension not supported)");
1700 return;
1701 }
1702
1703 if (offset < 0) {
1704 _mesa_error(ctx, GL_INVALID_VALUE,
1705 "glMapBufferRange(offset = %ld)", (long)offset);
1706 return;
1707 }
1708
1709 if (length < 0) {
1710 _mesa_error(ctx, GL_INVALID_VALUE,
1711 "glMapBufferRange(length = %ld)", (long)length);
1712 return;
1713 }
1714
1715 bufObj = get_buffer(ctx, target);
1716 if (!bufObj) {
1717 _mesa_error(ctx, GL_INVALID_ENUM,
1718 "glMapBufferRange(target = 0x%x)", target);
1719 return;
1720 }
1721
1722 if (!_mesa_is_bufferobj(bufObj)) {
1723 _mesa_error(ctx, GL_INVALID_OPERATION,
1724 "glMapBufferRange(current buffer is 0)");
1725 return;
1726 }
1727
1728 if (!_mesa_bufferobj_mapped(bufObj)) {
1729 /* buffer is not mapped */
1730 _mesa_error(ctx, GL_INVALID_OPERATION,
1731 "glMapBufferRange(buffer is not mapped)");
1732 return;
1733 }
1734
1735 if ((bufObj->AccessFlags & GL_MAP_FLUSH_EXPLICIT_BIT) == 0) {
1736 _mesa_error(ctx, GL_INVALID_OPERATION,
1737 "glMapBufferRange(GL_MAP_FLUSH_EXPLICIT_BIT not set)");
1738 return;
1739 }
1740
1741 if (offset + length > bufObj->Length) {
1742 _mesa_error(ctx, GL_INVALID_VALUE,
1743 "glMapBufferRange(offset %ld + length %ld > mapped length %ld)",
1744 (long)offset, (long)length, (long)bufObj->Length);
1745 return;
1746 }
1747
1748 ASSERT(bufObj->AccessFlags & GL_MAP_WRITE_BIT);
1749
1750 if (ctx->Driver.FlushMappedBufferRange)
1751 ctx->Driver.FlushMappedBufferRange(ctx, target, offset, length, bufObj);
1752 }
1753
1754
1755 #if FEATURE_APPLE_object_purgeable
1756 static GLenum
1757 _mesa_BufferObjectPurgeable(struct gl_context *ctx, GLuint name, GLenum option)
1758 {
1759 struct gl_buffer_object *bufObj;
1760 GLenum retval;
1761
1762 bufObj = _mesa_lookup_bufferobj(ctx, name);
1763 if (!bufObj) {
1764 _mesa_error(ctx, GL_INVALID_VALUE,
1765 "glObjectPurgeable(name = 0x%x)", name);
1766 return 0;
1767 }
1768 if (!_mesa_is_bufferobj(bufObj)) {
1769 _mesa_error(ctx, GL_INVALID_OPERATION, "glObjectPurgeable(buffer 0)" );
1770 return 0;
1771 }
1772
1773 if (bufObj->Purgeable) {
1774 _mesa_error(ctx, GL_INVALID_OPERATION,
1775 "glObjectPurgeable(name = 0x%x) is already purgeable", name);
1776 return GL_VOLATILE_APPLE;
1777 }
1778
1779 bufObj->Purgeable = GL_TRUE;
1780
1781 retval = GL_VOLATILE_APPLE;
1782 if (ctx->Driver.BufferObjectPurgeable)
1783 retval = ctx->Driver.BufferObjectPurgeable(ctx, bufObj, option);
1784
1785 return retval;
1786 }
1787
1788
1789 static GLenum
1790 _mesa_RenderObjectPurgeable(struct gl_context *ctx, GLuint name, GLenum option)
1791 {
1792 struct gl_renderbuffer *bufObj;
1793 GLenum retval;
1794
1795 bufObj = _mesa_lookup_renderbuffer(ctx, name);
1796 if (!bufObj) {
1797 _mesa_error(ctx, GL_INVALID_VALUE,
1798 "glObjectUnpurgeable(name = 0x%x)", name);
1799 return 0;
1800 }
1801
1802 if (bufObj->Purgeable) {
1803 _mesa_error(ctx, GL_INVALID_OPERATION,
1804 "glObjectPurgeable(name = 0x%x) is already purgeable", name);
1805 return GL_VOLATILE_APPLE;
1806 }
1807
1808 bufObj->Purgeable = GL_TRUE;
1809
1810 retval = GL_VOLATILE_APPLE;
1811 if (ctx->Driver.RenderObjectPurgeable)
1812 retval = ctx->Driver.RenderObjectPurgeable(ctx, bufObj, option);
1813
1814 return retval;
1815 }
1816
1817
1818 static GLenum
1819 _mesa_TextureObjectPurgeable(struct gl_context *ctx, GLuint name, GLenum option)
1820 {
1821 struct gl_texture_object *bufObj;
1822 GLenum retval;
1823
1824 bufObj = _mesa_lookup_texture(ctx, name);
1825 if (!bufObj) {
1826 _mesa_error(ctx, GL_INVALID_VALUE,
1827 "glObjectPurgeable(name = 0x%x)", name);
1828 return 0;
1829 }
1830
1831 if (bufObj->Purgeable) {
1832 _mesa_error(ctx, GL_INVALID_OPERATION,
1833 "glObjectPurgeable(name = 0x%x) is already purgeable", name);
1834 return GL_VOLATILE_APPLE;
1835 }
1836
1837 bufObj->Purgeable = GL_TRUE;
1838
1839 retval = GL_VOLATILE_APPLE;
1840 if (ctx->Driver.TextureObjectPurgeable)
1841 retval = ctx->Driver.TextureObjectPurgeable(ctx, bufObj, option);
1842
1843 return retval;
1844 }
1845
1846
1847 GLenum GLAPIENTRY
1848 _mesa_ObjectPurgeableAPPLE(GLenum objectType, GLuint name, GLenum option)
1849 {
1850 GLenum retval;
1851
1852 GET_CURRENT_CONTEXT(ctx);
1853 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0);
1854
1855 if (name == 0) {
1856 _mesa_error(ctx, GL_INVALID_VALUE,
1857 "glObjectPurgeable(name = 0x%x)", name);
1858 return 0;
1859 }
1860
1861 switch (option) {
1862 case GL_VOLATILE_APPLE:
1863 case GL_RELEASED_APPLE:
1864 /* legal */
1865 break;
1866 default:
1867 _mesa_error(ctx, GL_INVALID_ENUM,
1868 "glObjectPurgeable(name = 0x%x) invalid option: %d",
1869 name, option);
1870 return 0;
1871 }
1872
1873 switch (objectType) {
1874 case GL_TEXTURE:
1875 retval = _mesa_TextureObjectPurgeable (ctx, name, option);
1876 break;
1877 case GL_RENDERBUFFER_EXT:
1878 retval = _mesa_RenderObjectPurgeable (ctx, name, option);
1879 break;
1880 case GL_BUFFER_OBJECT_APPLE:
1881 retval = _mesa_BufferObjectPurgeable (ctx, name, option);
1882 break;
1883 default:
1884 _mesa_error(ctx, GL_INVALID_ENUM,
1885 "glObjectPurgeable(name = 0x%x) invalid type: %d",
1886 name, objectType);
1887 return 0;
1888 }
1889
1890 /* In strict conformance to the spec, we must only return VOLATILE when
1891 * when passed the VOLATILE option. Madness.
1892 *
1893 * XXX First fix the spec, then fix me.
1894 */
1895 return option == GL_VOLATILE_APPLE ? GL_VOLATILE_APPLE : retval;
1896 }
1897
1898
1899 static GLenum
1900 _mesa_BufferObjectUnpurgeable(struct gl_context *ctx, GLuint name, GLenum option)
1901 {
1902 struct gl_buffer_object *bufObj;
1903 GLenum retval;
1904
1905 bufObj = _mesa_lookup_bufferobj(ctx, name);
1906 if (!bufObj) {
1907 _mesa_error(ctx, GL_INVALID_VALUE,
1908 "glObjectUnpurgeable(name = 0x%x)", name);
1909 return 0;
1910 }
1911
1912 if (! bufObj->Purgeable) {
1913 _mesa_error(ctx, GL_INVALID_OPERATION,
1914 "glObjectUnpurgeable(name = 0x%x) object is "
1915 " already \"unpurged\"", name);
1916 return 0;
1917 }
1918
1919 bufObj->Purgeable = GL_FALSE;
1920
1921 retval = option;
1922 if (ctx->Driver.BufferObjectUnpurgeable)
1923 retval = ctx->Driver.BufferObjectUnpurgeable(ctx, bufObj, option);
1924
1925 return retval;
1926 }
1927
1928
1929 static GLenum
1930 _mesa_RenderObjectUnpurgeable(struct gl_context *ctx, GLuint name, GLenum option)
1931 {
1932 struct gl_renderbuffer *bufObj;
1933 GLenum retval;
1934
1935 bufObj = _mesa_lookup_renderbuffer(ctx, name);
1936 if (!bufObj) {
1937 _mesa_error(ctx, GL_INVALID_VALUE,
1938 "glObjectUnpurgeable(name = 0x%x)", name);
1939 return 0;
1940 }
1941
1942 if (! bufObj->Purgeable) {
1943 _mesa_error(ctx, GL_INVALID_OPERATION,
1944 "glObjectUnpurgeable(name = 0x%x) object is "
1945 " already \"unpurged\"", name);
1946 return 0;
1947 }
1948
1949 bufObj->Purgeable = GL_FALSE;
1950
1951 retval = option;
1952 if (ctx->Driver.RenderObjectUnpurgeable)
1953 retval = ctx->Driver.RenderObjectUnpurgeable(ctx, bufObj, option);
1954
1955 return retval;
1956 }
1957
1958
1959 static GLenum
1960 _mesa_TextureObjectUnpurgeable(struct gl_context *ctx, GLuint name, GLenum option)
1961 {
1962 struct gl_texture_object *bufObj;
1963 GLenum retval;
1964
1965 bufObj = _mesa_lookup_texture(ctx, name);
1966 if (!bufObj) {
1967 _mesa_error(ctx, GL_INVALID_VALUE,
1968 "glObjectUnpurgeable(name = 0x%x)", name);
1969 return 0;
1970 }
1971
1972 if (! bufObj->Purgeable) {
1973 _mesa_error(ctx, GL_INVALID_OPERATION,
1974 "glObjectUnpurgeable(name = 0x%x) object is"
1975 " already \"unpurged\"", name);
1976 return 0;
1977 }
1978
1979 bufObj->Purgeable = GL_FALSE;
1980
1981 retval = option;
1982 if (ctx->Driver.TextureObjectUnpurgeable)
1983 retval = ctx->Driver.TextureObjectUnpurgeable(ctx, bufObj, option);
1984
1985 return retval;
1986 }
1987
1988
1989 GLenum GLAPIENTRY
1990 _mesa_ObjectUnpurgeableAPPLE(GLenum objectType, GLuint name, GLenum option)
1991 {
1992 GET_CURRENT_CONTEXT(ctx);
1993 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0);
1994
1995 if (name == 0) {
1996 _mesa_error(ctx, GL_INVALID_VALUE,
1997 "glObjectUnpurgeable(name = 0x%x)", name);
1998 return 0;
1999 }
2000
2001 switch (option) {
2002 case GL_RETAINED_APPLE:
2003 case GL_UNDEFINED_APPLE:
2004 /* legal */
2005 break;
2006 default:
2007 _mesa_error(ctx, GL_INVALID_ENUM,
2008 "glObjectUnpurgeable(name = 0x%x) invalid option: %d",
2009 name, option);
2010 return 0;
2011 }
2012
2013 switch (objectType) {
2014 case GL_BUFFER_OBJECT_APPLE:
2015 return _mesa_BufferObjectUnpurgeable(ctx, name, option);
2016 case GL_TEXTURE:
2017 return _mesa_TextureObjectUnpurgeable(ctx, name, option);
2018 case GL_RENDERBUFFER_EXT:
2019 return _mesa_RenderObjectUnpurgeable(ctx, name, option);
2020 default:
2021 _mesa_error(ctx, GL_INVALID_ENUM,
2022 "glObjectUnpurgeable(name = 0x%x) invalid type: %d",
2023 name, objectType);
2024 return 0;
2025 }
2026 }
2027
2028
2029 static void
2030 _mesa_GetBufferObjectParameterivAPPLE(struct gl_context *ctx, GLuint name,
2031 GLenum pname, GLint* params)
2032 {
2033 struct gl_buffer_object *bufObj;
2034
2035 bufObj = _mesa_lookup_bufferobj(ctx, name);
2036 if (!bufObj) {
2037 _mesa_error(ctx, GL_INVALID_VALUE,
2038 "glGetObjectParameteriv(name = 0x%x) invalid object", name);
2039 return;
2040 }
2041
2042 switch (pname) {
2043 case GL_PURGEABLE_APPLE:
2044 *params = bufObj->Purgeable;
2045 break;
2046 default:
2047 _mesa_error(ctx, GL_INVALID_ENUM,
2048 "glGetObjectParameteriv(name = 0x%x) invalid enum: %d",
2049 name, pname);
2050 break;
2051 }
2052 }
2053
2054
2055 static void
2056 _mesa_GetRenderObjectParameterivAPPLE(struct gl_context *ctx, GLuint name,
2057 GLenum pname, GLint* params)
2058 {
2059 struct gl_renderbuffer *bufObj;
2060
2061 bufObj = _mesa_lookup_renderbuffer(ctx, name);
2062 if (!bufObj) {
2063 _mesa_error(ctx, GL_INVALID_VALUE,
2064 "glObjectUnpurgeable(name = 0x%x)", name);
2065 return;
2066 }
2067
2068 switch (pname) {
2069 case GL_PURGEABLE_APPLE:
2070 *params = bufObj->Purgeable;
2071 break;
2072 default:
2073 _mesa_error(ctx, GL_INVALID_ENUM,
2074 "glGetObjectParameteriv(name = 0x%x) invalid enum: %d",
2075 name, pname);
2076 break;
2077 }
2078 }
2079
2080
2081 static void
2082 _mesa_GetTextureObjectParameterivAPPLE(struct gl_context *ctx, GLuint name,
2083 GLenum pname, GLint* params)
2084 {
2085 struct gl_texture_object *bufObj;
2086
2087 bufObj = _mesa_lookup_texture(ctx, name);
2088 if (!bufObj) {
2089 _mesa_error(ctx, GL_INVALID_VALUE,
2090 "glObjectUnpurgeable(name = 0x%x)", name);
2091 return;
2092 }
2093
2094 switch (pname) {
2095 case GL_PURGEABLE_APPLE:
2096 *params = bufObj->Purgeable;
2097 break;
2098 default:
2099 _mesa_error(ctx, GL_INVALID_ENUM,
2100 "glGetObjectParameteriv(name = 0x%x) invalid enum: %d",
2101 name, pname);
2102 break;
2103 }
2104 }
2105
2106
2107 void GLAPIENTRY
2108 _mesa_GetObjectParameterivAPPLE(GLenum objectType, GLuint name, GLenum pname,
2109 GLint* params)
2110 {
2111 GET_CURRENT_CONTEXT(ctx);
2112
2113 if (name == 0) {
2114 _mesa_error(ctx, GL_INVALID_VALUE,
2115 "glGetObjectParameteriv(name = 0x%x)", name);
2116 return;
2117 }
2118
2119 switch (objectType) {
2120 case GL_TEXTURE:
2121 _mesa_GetTextureObjectParameterivAPPLE (ctx, name, pname, params);
2122 break;
2123 case GL_BUFFER_OBJECT_APPLE:
2124 _mesa_GetBufferObjectParameterivAPPLE (ctx, name, pname, params);
2125 break;
2126 case GL_RENDERBUFFER_EXT:
2127 _mesa_GetRenderObjectParameterivAPPLE (ctx, name, pname, params);
2128 break;
2129 default:
2130 _mesa_error(ctx, GL_INVALID_ENUM,
2131 "glGetObjectParameteriv(name = 0x%x) invalid type: %d",
2132 name, objectType);
2133 }
2134 }
2135
2136 #endif /* FEATURE_APPLE_object_purgeable */