mesa: added a simple bounds checker to glMap/UnmapBuffer() (disabled)
[mesa.git] / src / mesa / main / bufferobj.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 7.6
4 *
5 * Copyright (C) 1999-2008 Brian Paul All Rights Reserved.
6 * Copyright (C) 2009 VMware, Inc. All Rights Reserved.
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the "Software"),
10 * to deal in the Software without restriction, including without limitation
11 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 * and/or sell copies of the Software, and to permit persons to whom the
13 * Software is furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included
16 * in all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
22 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 */
25
26
27 /**
28 * \file bufferobj.c
29 * \brief Functions for the GL_ARB_vertex/pixel_buffer_object extensions.
30 * \author Brian Paul, Ian Romanick
31 */
32
33
34 #include "glheader.h"
35 #include "hash.h"
36 #include "imports.h"
37 #include "image.h"
38 #include "context.h"
39 #include "bufferobj.h"
40
41
42 /* Debug flags */
43 /*#define VBO_DEBUG*/
44 /*#define BOUNDS_CHECK*/
45
46
47 #ifdef FEATURE_OES_mapbuffer
48 #define DEFAULT_ACCESS GL_WRITE_ONLY;
49 #else
50 #define DEFAULT_ACCESS GL_READ_WRITE;
51 #endif
52
53
54 /**
55 * Get the buffer object bound to the specified target in a GL context.
56 *
57 * \param ctx GL context
58 * \param target Buffer object target to be retrieved. Currently this must
59 * be either \c GL_ARRAY_BUFFER or \c GL_ELEMENT_ARRAY_BUFFER.
60 * \return A pointer to the buffer object bound to \c target in the
61 * specified context or \c NULL if \c target is invalid.
62 */
63 static INLINE struct gl_buffer_object *
64 get_buffer(GLcontext *ctx, GLenum target)
65 {
66 struct gl_buffer_object * bufObj = NULL;
67
68 switch (target) {
69 case GL_ARRAY_BUFFER_ARB:
70 bufObj = ctx->Array.ArrayBufferObj;
71 break;
72 case GL_ELEMENT_ARRAY_BUFFER_ARB:
73 bufObj = ctx->Array.ElementArrayBufferObj;
74 break;
75 case GL_PIXEL_PACK_BUFFER_EXT:
76 bufObj = ctx->Pack.BufferObj;
77 break;
78 case GL_PIXEL_UNPACK_BUFFER_EXT:
79 bufObj = ctx->Unpack.BufferObj;
80 break;
81 case GL_COPY_READ_BUFFER:
82 if (ctx->Extensions.ARB_copy_buffer) {
83 bufObj = ctx->CopyReadBuffer;
84 }
85 break;
86 case GL_COPY_WRITE_BUFFER:
87 if (ctx->Extensions.ARB_copy_buffer) {
88 bufObj = ctx->CopyWriteBuffer;
89 }
90 break;
91 default:
92 /* error must be recorded by caller */
93 return NULL;
94 }
95
96 /* bufObj should point to NullBufferObj or a user-created buffer object */
97 ASSERT(bufObj);
98
99 return bufObj;
100 }
101
102
103 /**
104 * Tests the subdata range parameters and sets the GL error code for
105 * \c glBufferSubDataARB and \c glGetBufferSubDataARB.
106 *
107 * \param ctx GL context.
108 * \param target Buffer object target on which to operate.
109 * \param offset Offset of the first byte of the subdata range.
110 * \param size Size, in bytes, of the subdata range.
111 * \param caller Name of calling function for recording errors.
112 * \return A pointer to the buffer object bound to \c target in the
113 * specified context or \c NULL if any of the parameter or state
114 * conditions for \c glBufferSubDataARB or \c glGetBufferSubDataARB
115 * are invalid.
116 *
117 * \sa glBufferSubDataARB, glGetBufferSubDataARB
118 */
119 static struct gl_buffer_object *
120 buffer_object_subdata_range_good( GLcontext * ctx, GLenum target,
121 GLintptrARB offset, GLsizeiptrARB size,
122 const char *caller )
123 {
124 struct gl_buffer_object *bufObj;
125
126 if (size < 0) {
127 _mesa_error(ctx, GL_INVALID_VALUE, "%s(size < 0)", caller);
128 return NULL;
129 }
130
131 if (offset < 0) {
132 _mesa_error(ctx, GL_INVALID_VALUE, "%s(offset < 0)", caller);
133 return NULL;
134 }
135
136 bufObj = get_buffer(ctx, target);
137 if (!bufObj) {
138 _mesa_error(ctx, GL_INVALID_ENUM, "%s(target)", caller);
139 return NULL;
140 }
141 if (bufObj->Name == 0) {
142 _mesa_error(ctx, GL_INVALID_OPERATION, "%s", caller);
143 return NULL;
144 }
145 if (offset + size > bufObj->Size) {
146 _mesa_error(ctx, GL_INVALID_VALUE,
147 "%s(size + offset > buffer size)", caller);
148 return NULL;
149 }
150 if (bufObj->Pointer) {
151 /* Buffer is currently mapped */
152 _mesa_error(ctx, GL_INVALID_OPERATION, "%s", caller);
153 return NULL;
154 }
155
156 return bufObj;
157 }
158
159
160 /**
161 * Allocate and initialize a new buffer object.
162 *
163 * Default callback for the \c dd_function_table::NewBufferObject() hook.
164 */
165 struct gl_buffer_object *
166 _mesa_new_buffer_object( GLcontext *ctx, GLuint name, GLenum target )
167 {
168 struct gl_buffer_object *obj;
169
170 (void) ctx;
171
172 obj = MALLOC_STRUCT(gl_buffer_object);
173 _mesa_initialize_buffer_object(obj, name, target);
174 return obj;
175 }
176
177
178 /**
179 * Delete a buffer object.
180 *
181 * Default callback for the \c dd_function_table::DeleteBuffer() hook.
182 */
183 void
184 _mesa_delete_buffer_object( GLcontext *ctx, struct gl_buffer_object *bufObj )
185 {
186 (void) ctx;
187
188 if (bufObj->Data)
189 _mesa_free(bufObj->Data);
190
191 /* assign strange values here to help w/ debugging */
192 bufObj->RefCount = -1000;
193 bufObj->Name = ~0;
194
195 _mesa_free(bufObj);
196 }
197
198
199
200 /**
201 * Set ptr to bufObj w/ reference counting.
202 */
203 void
204 _mesa_reference_buffer_object(GLcontext *ctx,
205 struct gl_buffer_object **ptr,
206 struct gl_buffer_object *bufObj)
207 {
208 if (*ptr == bufObj)
209 return;
210
211 if (*ptr) {
212 /* Unreference the old buffer */
213 GLboolean deleteFlag = GL_FALSE;
214 struct gl_buffer_object *oldObj = *ptr;
215
216 /*_glthread_LOCK_MUTEX(oldObj->Mutex);*/
217 ASSERT(oldObj->RefCount > 0);
218 oldObj->RefCount--;
219 #if 0
220 printf("BufferObj %p %d DECR to %d\n",
221 (void *) oldObj, oldObj->Name, oldObj->RefCount);
222 #endif
223 deleteFlag = (oldObj->RefCount == 0);
224 /*_glthread_UNLOCK_MUTEX(oldObj->Mutex);*/
225
226 if (deleteFlag) {
227
228 /* some sanity checking: don't delete a buffer still in use */
229 #if 0
230 /* unfortunately, these tests are invalid during context tear-down */
231 ASSERT(ctx->Array.ArrayBufferObj != bufObj);
232 ASSERT(ctx->Array.ElementArrayBufferObj != bufObj);
233 ASSERT(ctx->Array.ArrayObj->Vertex.BufferObj != bufObj);
234 #endif
235
236 ASSERT(ctx->Driver.DeleteBuffer);
237 ctx->Driver.DeleteBuffer(ctx, oldObj);
238 }
239
240 *ptr = NULL;
241 }
242 ASSERT(!*ptr);
243
244 if (bufObj) {
245 /* reference new buffer */
246 /*_glthread_LOCK_MUTEX(tex->Mutex);*/
247 if (bufObj->RefCount == 0) {
248 /* this buffer's being deleted (look just above) */
249 /* Not sure this can every really happen. Warn if it does. */
250 _mesa_problem(NULL, "referencing deleted buffer object");
251 *ptr = NULL;
252 }
253 else {
254 bufObj->RefCount++;
255 #if 0
256 printf("BufferObj %p %d INCR to %d\n",
257 (void *) bufObj, bufObj->Name, bufObj->RefCount);
258 #endif
259 *ptr = bufObj;
260 }
261 /*_glthread_UNLOCK_MUTEX(tex->Mutex);*/
262 }
263 }
264
265
266 /**
267 * Initialize a buffer object to default values.
268 */
269 void
270 _mesa_initialize_buffer_object( struct gl_buffer_object *obj,
271 GLuint name, GLenum target )
272 {
273 (void) target;
274
275 _mesa_bzero(obj, sizeof(struct gl_buffer_object));
276 obj->RefCount = 1;
277 obj->Name = name;
278 obj->Usage = GL_STATIC_DRAW_ARB;
279 obj->Access = DEFAULT_ACCESS;
280 }
281
282
283 /**
284 * Allocate space for and store data in a buffer object. Any data that was
285 * previously stored in the buffer object is lost. If \c data is \c NULL,
286 * memory will be allocated, but no copy will occur.
287 *
288 * This is the default callback for \c dd_function_table::BufferData()
289 * Note that all GL error checking will have been done already.
290 *
291 * \param ctx GL context.
292 * \param target Buffer object target on which to operate.
293 * \param size Size, in bytes, of the new data store.
294 * \param data Pointer to the data to store in the buffer object. This
295 * pointer may be \c NULL.
296 * \param usage Hints about how the data will be used.
297 * \param bufObj Object to be used.
298 *
299 * \sa glBufferDataARB, dd_function_table::BufferData.
300 */
301 void
302 _mesa_buffer_data( GLcontext *ctx, GLenum target, GLsizeiptrARB size,
303 const GLvoid * data, GLenum usage,
304 struct gl_buffer_object * bufObj )
305 {
306 void * new_data;
307
308 (void) ctx; (void) target;
309
310 new_data = _mesa_realloc( bufObj->Data, bufObj->Size, size );
311 if (new_data) {
312 bufObj->Data = (GLubyte *) new_data;
313 bufObj->Size = size;
314 bufObj->Usage = usage;
315
316 if (data) {
317 _mesa_memcpy( bufObj->Data, data, size );
318 }
319 }
320 }
321
322
323 /**
324 * Replace data in a subrange of buffer object. If the data range
325 * specified by \c size + \c offset extends beyond the end of the buffer or
326 * if \c data is \c NULL, no copy is performed.
327 *
328 * This is the default callback for \c dd_function_table::BufferSubData()
329 * Note that all GL error checking will have been done already.
330 *
331 * \param ctx GL context.
332 * \param target Buffer object target on which to operate.
333 * \param offset Offset of the first byte to be modified.
334 * \param size Size, in bytes, of the data range.
335 * \param data Pointer to the data to store in the buffer object.
336 * \param bufObj Object to be used.
337 *
338 * \sa glBufferSubDataARB, dd_function_table::BufferSubData.
339 */
340 void
341 _mesa_buffer_subdata( GLcontext *ctx, GLenum target, GLintptrARB offset,
342 GLsizeiptrARB size, const GLvoid * data,
343 struct gl_buffer_object * bufObj )
344 {
345 (void) ctx; (void) target;
346
347 /* this should have been caught in _mesa_BufferSubData() */
348 ASSERT(size + offset <= bufObj->Size);
349
350 if (bufObj->Data) {
351 _mesa_memcpy( (GLubyte *) bufObj->Data + offset, data, size );
352 }
353 }
354
355
356 /**
357 * Retrieve data from a subrange of buffer object. If the data range
358 * specified by \c size + \c offset extends beyond the end of the buffer or
359 * if \c data is \c NULL, no copy is performed.
360 *
361 * This is the default callback for \c dd_function_table::GetBufferSubData()
362 * Note that all GL error checking will have been done already.
363 *
364 * \param ctx GL context.
365 * \param target Buffer object target on which to operate.
366 * \param offset Offset of the first byte to be fetched.
367 * \param size Size, in bytes, of the data range.
368 * \param data Destination for data
369 * \param bufObj Object to be used.
370 *
371 * \sa glBufferGetSubDataARB, dd_function_table::GetBufferSubData.
372 */
373 void
374 _mesa_buffer_get_subdata( GLcontext *ctx, GLenum target, GLintptrARB offset,
375 GLsizeiptrARB size, GLvoid * data,
376 struct gl_buffer_object * bufObj )
377 {
378 (void) ctx; (void) target;
379
380 if (bufObj->Data && ((GLsizeiptrARB) (size + offset) <= bufObj->Size)) {
381 _mesa_memcpy( data, (GLubyte *) bufObj->Data + offset, size );
382 }
383 }
384
385
386 /**
387 * Default callback for \c dd_function_tabel::MapBuffer().
388 *
389 * The function parameters will have been already tested for errors.
390 *
391 * \param ctx GL context.
392 * \param target Buffer object target on which to operate.
393 * \param access Information about how the buffer will be accessed.
394 * \param bufObj Object to be mapped.
395 * \return A pointer to the object's internal data store that can be accessed
396 * by the processor
397 *
398 * \sa glMapBufferARB, dd_function_table::MapBuffer
399 */
400 void *
401 _mesa_buffer_map( GLcontext *ctx, GLenum target, GLenum access,
402 struct gl_buffer_object *bufObj )
403 {
404 (void) ctx;
405 (void) target;
406 (void) access;
407 /* Just return a direct pointer to the data */
408 if (bufObj->Pointer) {
409 /* already mapped! */
410 return NULL;
411 }
412 bufObj->Pointer = bufObj->Data;
413 return bufObj->Pointer;
414 }
415
416
417 /**
418 * Default callback for \c dd_function_table::MapBuffer().
419 *
420 * The input parameters will have been already tested for errors.
421 *
422 * \sa glUnmapBufferARB, dd_function_table::UnmapBuffer
423 */
424 GLboolean
425 _mesa_buffer_unmap( GLcontext *ctx, GLenum target,
426 struct gl_buffer_object *bufObj )
427 {
428 (void) ctx;
429 (void) target;
430 /* XXX we might assert here that bufObj->Pointer is non-null */
431 bufObj->Pointer = NULL;
432 return GL_TRUE;
433 }
434
435
436 /**
437 * Default fallback for \c dd_function_table::CopyBufferSubData().
438 * Called via glCopyBuffserSubData().
439 */
440 void
441 _mesa_copy_buffer_subdata(GLcontext *ctx,
442 struct gl_buffer_object *src,
443 struct gl_buffer_object *dst,
444 GLintptr readOffset, GLintptr writeOffset,
445 GLsizeiptr size)
446 {
447 GLubyte *srcPtr, *dstPtr;
448
449 /* buffer should not already be mapped */
450 assert(!src->Pointer);
451 assert(!dst->Pointer);
452
453 srcPtr = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_COPY_READ_BUFFER,
454 GL_READ_ONLY, src);
455 dstPtr = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_COPY_WRITE_BUFFER,
456 GL_WRITE_ONLY, dst);
457
458 if (srcPtr && dstPtr)
459 _mesa_memcpy(dstPtr + writeOffset, srcPtr + readOffset, size);
460
461 ctx->Driver.UnmapBuffer(ctx, GL_COPY_READ_BUFFER, src);
462 ctx->Driver.UnmapBuffer(ctx, GL_COPY_WRITE_BUFFER, dst);
463 }
464
465
466
467 /**
468 * Initialize the state associated with buffer objects
469 */
470 void
471 _mesa_init_buffer_objects( GLcontext *ctx )
472 {
473 ctx->Array.ArrayBufferObj = ctx->Shared->NullBufferObj;
474 ctx->Array.ElementArrayBufferObj = ctx->Shared->NullBufferObj;
475
476 ctx->CopyReadBuffer = ctx->Shared->NullBufferObj;
477 ctx->CopyWriteBuffer = ctx->Shared->NullBufferObj;
478 }
479
480
481 /**
482 * Bind the specified target to buffer for the specified context.
483 */
484 static void
485 bind_buffer_object(GLcontext *ctx, GLenum target, GLuint buffer)
486 {
487 struct gl_buffer_object *oldBufObj;
488 struct gl_buffer_object *newBufObj = NULL;
489 struct gl_buffer_object **bindTarget = NULL;
490
491 switch (target) {
492 case GL_ARRAY_BUFFER_ARB:
493 bindTarget = &ctx->Array.ArrayBufferObj;
494 break;
495 case GL_ELEMENT_ARRAY_BUFFER_ARB:
496 bindTarget = &ctx->Array.ElementArrayBufferObj;
497 break;
498 case GL_PIXEL_PACK_BUFFER_EXT:
499 bindTarget = &ctx->Pack.BufferObj;
500 break;
501 case GL_PIXEL_UNPACK_BUFFER_EXT:
502 bindTarget = &ctx->Unpack.BufferObj;
503 break;
504 case GL_COPY_READ_BUFFER:
505 if (ctx->Extensions.ARB_copy_buffer) {
506 bindTarget = &ctx->CopyReadBuffer;
507 }
508 break;
509 case GL_COPY_WRITE_BUFFER:
510 if (ctx->Extensions.ARB_copy_buffer) {
511 bindTarget = &ctx->CopyWriteBuffer;
512 }
513 break;
514 default:
515 ; /* no-op / we'll hit the follow error test next */
516 }
517
518 if (!bindTarget) {
519 _mesa_error(ctx, GL_INVALID_ENUM, "glBindBufferARB(target 0x%x)");
520 return;
521 }
522
523 /* Get pointer to old buffer object (to be unbound) */
524 oldBufObj = get_buffer(ctx, target);
525 if (oldBufObj && oldBufObj->Name == buffer)
526 return; /* rebinding the same buffer object- no change */
527
528 /*
529 * Get pointer to new buffer object (newBufObj)
530 */
531 if (buffer == 0) {
532 /* The spec says there's not a buffer object named 0, but we use
533 * one internally because it simplifies things.
534 */
535 newBufObj = ctx->Shared->NullBufferObj;
536 }
537 else {
538 /* non-default buffer object */
539 newBufObj = _mesa_lookup_bufferobj(ctx, buffer);
540 if (!newBufObj) {
541 /* if this is a new buffer object id, allocate a buffer object now */
542 ASSERT(ctx->Driver.NewBufferObject);
543 newBufObj = ctx->Driver.NewBufferObject(ctx, buffer, target);
544 if (!newBufObj) {
545 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindBufferARB");
546 return;
547 }
548 _mesa_HashInsert(ctx->Shared->BufferObjects, buffer, newBufObj);
549 }
550 }
551
552 /* bind new buffer */
553 _mesa_reference_buffer_object(ctx, bindTarget, newBufObj);
554
555 /* Pass BindBuffer call to device driver */
556 if (ctx->Driver.BindBuffer)
557 ctx->Driver.BindBuffer( ctx, target, newBufObj );
558 }
559
560
561 /**
562 * Update the default buffer objects in the given context to reference those
563 * specified in the shared state and release those referencing the old
564 * shared state.
565 */
566 void
567 _mesa_update_default_objects_buffer_objects(GLcontext *ctx)
568 {
569 /* Bind the NullBufferObj to remove references to those
570 * in the shared context hash table.
571 */
572 bind_buffer_object( ctx, GL_ARRAY_BUFFER_ARB, 0);
573 bind_buffer_object( ctx, GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
574 bind_buffer_object( ctx, GL_PIXEL_PACK_BUFFER_ARB, 0);
575 bind_buffer_object( ctx, GL_PIXEL_UNPACK_BUFFER_ARB, 0);
576 }
577
578
579 /**
580 * When we're about to read pixel data out of a PBO (via glDrawPixels,
581 * glTexImage, etc) or write data into a PBO (via glReadPixels,
582 * glGetTexImage, etc) we call this function to check that we're not
583 * going to read out of bounds.
584 *
585 * XXX This would also be a convenient time to check that the PBO isn't
586 * currently mapped. Whoever calls this function should check for that.
587 * Remember, we can't use a PBO when it's mapped!
588 *
589 * \param width width of image to read/write
590 * \param height height of image to read/write
591 * \param depth depth of image to read/write
592 * \param format format of image to read/write
593 * \param type datatype of image to read/write
594 * \param ptr the user-provided pointer/offset
595 * \return GL_TRUE if the PBO access is OK, GL_FALSE if the access would
596 * go out of bounds.
597 */
598 GLboolean
599 _mesa_validate_pbo_access(GLuint dimensions,
600 const struct gl_pixelstore_attrib *pack,
601 GLsizei width, GLsizei height, GLsizei depth,
602 GLenum format, GLenum type, const GLvoid *ptr)
603 {
604 GLvoid *start, *end;
605 const GLubyte *sizeAddr; /* buffer size, cast to a pointer */
606
607 ASSERT(pack->BufferObj->Name != 0);
608
609 if (pack->BufferObj->Size == 0)
610 /* no buffer! */
611 return GL_FALSE;
612
613 /* get address of first pixel we'll read */
614 start = _mesa_image_address(dimensions, pack, ptr, width, height,
615 format, type, 0, 0, 0);
616
617 /* get address just past the last pixel we'll read */
618 end = _mesa_image_address(dimensions, pack, ptr, width, height,
619 format, type, depth-1, height-1, width);
620
621
622 sizeAddr = ((const GLubyte *) 0) + pack->BufferObj->Size;
623
624 if ((const GLubyte *) start > sizeAddr) {
625 /* This will catch negative values / wrap-around */
626 return GL_FALSE;
627 }
628 if ((const GLubyte *) end > sizeAddr) {
629 /* Image read goes beyond end of buffer */
630 return GL_FALSE;
631 }
632
633 /* OK! */
634 return GL_TRUE;
635 }
636
637
638 /**
639 * If the source of glBitmap data is a PBO, check that we won't read out
640 * of buffer bounds, then map the buffer.
641 * If not sourcing from a PBO, just return the bitmap pointer.
642 * This is a helper function for (some) drivers.
643 * Return NULL if error.
644 * If non-null return, must call _mesa_unmap_bitmap_pbo() when done.
645 */
646 const GLubyte *
647 _mesa_map_bitmap_pbo(GLcontext *ctx,
648 const struct gl_pixelstore_attrib *unpack,
649 const GLubyte *bitmap)
650 {
651 const GLubyte *buf;
652
653 if (unpack->BufferObj->Name) {
654 /* unpack from PBO */
655 buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
656 GL_READ_ONLY_ARB,
657 unpack->BufferObj);
658 if (!buf)
659 return NULL;
660
661 buf = ADD_POINTERS(buf, bitmap);
662 }
663 else {
664 /* unpack from normal memory */
665 buf = bitmap;
666 }
667
668 return buf;
669 }
670
671
672 /**
673 * Counterpart to _mesa_map_bitmap_pbo()
674 * This is a helper function for (some) drivers.
675 */
676 void
677 _mesa_unmap_bitmap_pbo(GLcontext *ctx,
678 const struct gl_pixelstore_attrib *unpack)
679 {
680 if (unpack->BufferObj->Name) {
681 ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
682 unpack->BufferObj);
683 }
684 }
685
686
687 /**
688 * \sa _mesa_map_bitmap_pbo
689 */
690 const GLvoid *
691 _mesa_map_drawpix_pbo(GLcontext *ctx,
692 const struct gl_pixelstore_attrib *unpack,
693 const GLvoid *pixels)
694 {
695 const GLvoid *buf;
696
697 if (unpack->BufferObj->Name) {
698 /* unpack from PBO */
699 buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
700 GL_READ_ONLY_ARB,
701 unpack->BufferObj);
702 if (!buf)
703 return NULL;
704
705 buf = ADD_POINTERS(buf, pixels);
706 }
707 else {
708 /* unpack from normal memory */
709 buf = pixels;
710 }
711
712 return buf;
713 }
714
715
716 /**
717 * \sa _mesa_unmap_bitmap_pbo
718 */
719 void
720 _mesa_unmap_drawpix_pbo(GLcontext *ctx,
721 const struct gl_pixelstore_attrib *unpack)
722 {
723 if (unpack->BufferObj->Name) {
724 ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
725 unpack->BufferObj);
726 }
727 }
728
729
730 /**
731 * If PBO is bound, map the buffer, return dest pointer in mapped buffer.
732 * Call _mesa_unmap_readpix_pbo() when finished
733 * \return NULL if error
734 */
735 void *
736 _mesa_map_readpix_pbo(GLcontext *ctx,
737 const struct gl_pixelstore_attrib *pack,
738 GLvoid *dest)
739 {
740 void *buf;
741
742 if (pack->BufferObj->Name) {
743 /* pack into PBO */
744 buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT,
745 GL_WRITE_ONLY_ARB,
746 pack->BufferObj);
747 if (!buf)
748 return NULL;
749
750 buf = ADD_POINTERS(buf, dest);
751 }
752 else {
753 /* pack to normal memory */
754 buf = dest;
755 }
756
757 return buf;
758 }
759
760
761 /**
762 * Counterpart to _mesa_map_readpix_pbo()
763 */
764 void
765 _mesa_unmap_readpix_pbo(GLcontext *ctx,
766 const struct gl_pixelstore_attrib *pack)
767 {
768 if (pack->BufferObj->Name) {
769 ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT, pack->BufferObj);
770 }
771 }
772
773
774
775 /**
776 * Return the gl_buffer_object for the given ID.
777 * Always return NULL for ID 0.
778 */
779 struct gl_buffer_object *
780 _mesa_lookup_bufferobj(GLcontext *ctx, GLuint buffer)
781 {
782 if (buffer == 0)
783 return NULL;
784 else
785 return (struct gl_buffer_object *)
786 _mesa_HashLookup(ctx->Shared->BufferObjects, buffer);
787 }
788
789
790 /**
791 * If *ptr points to obj, set ptr = the Null/default buffer object.
792 * This is a helper for buffer object deletion.
793 * The GL spec says that deleting a buffer object causes it to get
794 * unbound from all arrays in the current context.
795 */
796 static void
797 unbind(GLcontext *ctx,
798 struct gl_buffer_object **ptr,
799 struct gl_buffer_object *obj)
800 {
801 if (*ptr == obj) {
802 _mesa_reference_buffer_object(ctx, ptr, ctx->Shared->NullBufferObj);
803 }
804 }
805
806
807
808 /**********************************************************************/
809 /* API Functions */
810 /**********************************************************************/
811
812 void GLAPIENTRY
813 _mesa_BindBufferARB(GLenum target, GLuint buffer)
814 {
815 GET_CURRENT_CONTEXT(ctx);
816 ASSERT_OUTSIDE_BEGIN_END(ctx);
817
818 bind_buffer_object(ctx, target, buffer);
819 }
820
821
822 /**
823 * Delete a set of buffer objects.
824 *
825 * \param n Number of buffer objects to delete.
826 * \param ids Array of \c n buffer object IDs.
827 */
828 void GLAPIENTRY
829 _mesa_DeleteBuffersARB(GLsizei n, const GLuint *ids)
830 {
831 GET_CURRENT_CONTEXT(ctx);
832 GLsizei i;
833 ASSERT_OUTSIDE_BEGIN_END(ctx);
834
835 if (n < 0) {
836 _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteBuffersARB(n)");
837 return;
838 }
839
840 _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
841
842 for (i = 0; i < n; i++) {
843 struct gl_buffer_object *bufObj = _mesa_lookup_bufferobj(ctx, ids[i]);
844 if (bufObj) {
845 struct gl_array_object *arrayObj = ctx->Array.ArrayObj;
846 GLuint j;
847
848 ASSERT(bufObj->Name == ids[i]);
849
850 if (bufObj->Pointer) {
851 /* if mapped, unmap it now */
852 ctx->Driver.UnmapBuffer(ctx, 0, bufObj);
853 bufObj->Access = DEFAULT_ACCESS;
854 bufObj->Pointer = NULL;
855 }
856
857 /* unbind any vertex pointers bound to this buffer */
858 unbind(ctx, &arrayObj->Vertex.BufferObj, bufObj);
859 unbind(ctx, &arrayObj->Weight.BufferObj, bufObj);
860 unbind(ctx, &arrayObj->Normal.BufferObj, bufObj);
861 unbind(ctx, &arrayObj->Color.BufferObj, bufObj);
862 unbind(ctx, &arrayObj->SecondaryColor.BufferObj, bufObj);
863 unbind(ctx, &arrayObj->FogCoord.BufferObj, bufObj);
864 unbind(ctx, &arrayObj->Index.BufferObj, bufObj);
865 unbind(ctx, &arrayObj->EdgeFlag.BufferObj, bufObj);
866 for (j = 0; j < Elements(arrayObj->TexCoord); j++) {
867 unbind(ctx, &arrayObj->TexCoord[j].BufferObj, bufObj);
868 }
869 for (j = 0; j < Elements(arrayObj->VertexAttrib); j++) {
870 unbind(ctx, &arrayObj->VertexAttrib[j].BufferObj, bufObj);
871 }
872
873 if (ctx->Array.ArrayBufferObj == bufObj) {
874 _mesa_BindBufferARB( GL_ARRAY_BUFFER_ARB, 0 );
875 }
876 if (ctx->Array.ElementArrayBufferObj == bufObj) {
877 _mesa_BindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, 0 );
878 }
879
880 /* unbind any pixel pack/unpack pointers bound to this buffer */
881 if (ctx->Pack.BufferObj == bufObj) {
882 _mesa_BindBufferARB( GL_PIXEL_PACK_BUFFER_EXT, 0 );
883 }
884 if (ctx->Unpack.BufferObj == bufObj) {
885 _mesa_BindBufferARB( GL_PIXEL_UNPACK_BUFFER_EXT, 0 );
886 }
887
888 /* The ID is immediately freed for re-use */
889 _mesa_HashRemove(ctx->Shared->BufferObjects, bufObj->Name);
890 _mesa_reference_buffer_object(ctx, &bufObj, NULL);
891 }
892 }
893
894 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
895 }
896
897
898 /**
899 * Generate a set of unique buffer object IDs and store them in \c buffer.
900 *
901 * \param n Number of IDs to generate.
902 * \param buffer Array of \c n locations to store the IDs.
903 */
904 void GLAPIENTRY
905 _mesa_GenBuffersARB(GLsizei n, GLuint *buffer)
906 {
907 GET_CURRENT_CONTEXT(ctx);
908 GLuint first;
909 GLint i;
910 ASSERT_OUTSIDE_BEGIN_END(ctx);
911
912 if (n < 0) {
913 _mesa_error(ctx, GL_INVALID_VALUE, "glGenBuffersARB");
914 return;
915 }
916
917 if (!buffer) {
918 return;
919 }
920
921 /*
922 * This must be atomic (generation and allocation of buffer object IDs)
923 */
924 _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
925
926 first = _mesa_HashFindFreeKeyBlock(ctx->Shared->BufferObjects, n);
927
928 /* Allocate new, empty buffer objects and return identifiers */
929 for (i = 0; i < n; i++) {
930 struct gl_buffer_object *bufObj;
931 GLuint name = first + i;
932 GLenum target = 0;
933 bufObj = ctx->Driver.NewBufferObject( ctx, name, target );
934 if (!bufObj) {
935 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
936 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenBuffersARB");
937 return;
938 }
939 _mesa_HashInsert(ctx->Shared->BufferObjects, first + i, bufObj);
940 buffer[i] = first + i;
941 }
942
943 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
944 }
945
946
947 /**
948 * Determine if ID is the name of a buffer object.
949 *
950 * \param id ID of the potential buffer object.
951 * \return \c GL_TRUE if \c id is the name of a buffer object,
952 * \c GL_FALSE otherwise.
953 */
954 GLboolean GLAPIENTRY
955 _mesa_IsBufferARB(GLuint id)
956 {
957 struct gl_buffer_object *bufObj;
958 GET_CURRENT_CONTEXT(ctx);
959 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
960
961 _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
962 bufObj = _mesa_lookup_bufferobj(ctx, id);
963 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
964
965 return bufObj ? GL_TRUE : GL_FALSE;
966 }
967
968
969 void GLAPIENTRY
970 _mesa_BufferDataARB(GLenum target, GLsizeiptrARB size,
971 const GLvoid * data, GLenum usage)
972 {
973 GET_CURRENT_CONTEXT(ctx);
974 struct gl_buffer_object *bufObj;
975 ASSERT_OUTSIDE_BEGIN_END(ctx);
976
977 if (size < 0) {
978 _mesa_error(ctx, GL_INVALID_VALUE, "glBufferDataARB(size < 0)");
979 return;
980 }
981
982 switch (usage) {
983 case GL_STREAM_DRAW_ARB:
984 case GL_STREAM_READ_ARB:
985 case GL_STREAM_COPY_ARB:
986 case GL_STATIC_DRAW_ARB:
987 case GL_STATIC_READ_ARB:
988 case GL_STATIC_COPY_ARB:
989 case GL_DYNAMIC_DRAW_ARB:
990 case GL_DYNAMIC_READ_ARB:
991 case GL_DYNAMIC_COPY_ARB:
992 /* OK */
993 break;
994 default:
995 _mesa_error(ctx, GL_INVALID_ENUM, "glBufferDataARB(usage)");
996 return;
997 }
998
999 bufObj = get_buffer(ctx, target);
1000 if (!bufObj) {
1001 _mesa_error(ctx, GL_INVALID_ENUM, "glBufferDataARB(target)" );
1002 return;
1003 }
1004 if (bufObj->Name == 0) {
1005 _mesa_error(ctx, GL_INVALID_OPERATION, "glBufferDataARB(buffer 0)" );
1006 return;
1007 }
1008
1009 if (bufObj->Pointer) {
1010 /* Unmap the existing buffer. We'll replace it now. Not an error. */
1011 ctx->Driver.UnmapBuffer(ctx, target, bufObj);
1012 bufObj->Access = DEFAULT_ACCESS;
1013 bufObj->Pointer = NULL;
1014 }
1015
1016 FLUSH_VERTICES(ctx, _NEW_BUFFER_OBJECT);
1017
1018 ASSERT(ctx->Driver.BufferData);
1019
1020 bufObj->Written = GL_TRUE;
1021
1022 #ifdef VBO_DEBUG
1023 _mesa_printf("glBufferDataARB(%u, sz %ld, from %p, usage 0x%x)\n",
1024 bufObj->Name, size, data, usage);
1025 #endif
1026
1027 #ifdef BOUNDS_CHECK
1028 size += 100;
1029 #endif
1030 /* Give the buffer object to the driver! <data> may be null! */
1031 ctx->Driver.BufferData( ctx, target, size, data, usage, bufObj );
1032 }
1033
1034
1035 void GLAPIENTRY
1036 _mesa_BufferSubDataARB(GLenum target, GLintptrARB offset,
1037 GLsizeiptrARB size, const GLvoid * data)
1038 {
1039 GET_CURRENT_CONTEXT(ctx);
1040 struct gl_buffer_object *bufObj;
1041 ASSERT_OUTSIDE_BEGIN_END(ctx);
1042
1043 bufObj = buffer_object_subdata_range_good( ctx, target, offset, size,
1044 "glBufferSubDataARB" );
1045 if (!bufObj) {
1046 /* error already recorded */
1047 return;
1048 }
1049
1050 bufObj->Written = GL_TRUE;
1051
1052 ASSERT(ctx->Driver.BufferSubData);
1053 ctx->Driver.BufferSubData( ctx, target, offset, size, data, bufObj );
1054 }
1055
1056
1057 void GLAPIENTRY
1058 _mesa_GetBufferSubDataARB(GLenum target, GLintptrARB offset,
1059 GLsizeiptrARB size, void * data)
1060 {
1061 GET_CURRENT_CONTEXT(ctx);
1062 struct gl_buffer_object *bufObj;
1063 ASSERT_OUTSIDE_BEGIN_END(ctx);
1064
1065 bufObj = buffer_object_subdata_range_good( ctx, target, offset, size,
1066 "glGetBufferSubDataARB" );
1067 if (!bufObj) {
1068 /* error already recorded */
1069 return;
1070 }
1071
1072 ASSERT(ctx->Driver.GetBufferSubData);
1073 ctx->Driver.GetBufferSubData( ctx, target, offset, size, data, bufObj );
1074 }
1075
1076
1077 void * GLAPIENTRY
1078 _mesa_MapBufferARB(GLenum target, GLenum access)
1079 {
1080 GET_CURRENT_CONTEXT(ctx);
1081 struct gl_buffer_object * bufObj;
1082 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, NULL);
1083
1084 switch (access) {
1085 case GL_READ_ONLY_ARB:
1086 case GL_WRITE_ONLY_ARB:
1087 case GL_READ_WRITE_ARB:
1088 /* OK */
1089 break;
1090 default:
1091 _mesa_error(ctx, GL_INVALID_ENUM, "glMapBufferARB(access)");
1092 return NULL;
1093 }
1094
1095 bufObj = get_buffer(ctx, target);
1096 if (!bufObj) {
1097 _mesa_error(ctx, GL_INVALID_ENUM, "glMapBufferARB(target)" );
1098 return NULL;
1099 }
1100 if (bufObj->Name == 0) {
1101 _mesa_error(ctx, GL_INVALID_OPERATION, "glMapBufferARB(buffer 0)" );
1102 return NULL;
1103 }
1104 if (bufObj->Pointer) {
1105 _mesa_error(ctx, GL_INVALID_OPERATION, "glMapBufferARB(already mapped)");
1106 return NULL;
1107 }
1108
1109 ASSERT(ctx->Driver.MapBuffer);
1110 bufObj->Pointer = ctx->Driver.MapBuffer( ctx, target, access, bufObj );
1111 if (!bufObj->Pointer) {
1112 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glMapBufferARB(access)");
1113 }
1114
1115 bufObj->Access = access;
1116 if (access == GL_WRITE_ONLY_ARB || access == GL_READ_WRITE_ARB)
1117 bufObj->Written = GL_TRUE;
1118
1119 #ifdef VBO_DEBUG
1120 _mesa_printf("glMapBufferARB(%u, sz %ld, access 0x%x)\n",
1121 bufObj->Name, bufObj->Size, access);
1122 if (access == GL_WRITE_ONLY_ARB) {
1123 GLuint i;
1124 GLubyte *b = (GLubyte *) bufObj->Pointer;
1125 for (i = 0; i < bufObj->Size; i++)
1126 b[i] = i & 0xff;
1127 }
1128 #endif
1129
1130 #ifdef BOUNDS_CHECK
1131 {
1132 GLubyte *buf = (GLubyte *) bufObj->Pointer;
1133 GLuint i;
1134 /* buffer is 100 bytes larger than requested, fill with magic value */
1135 for (i = 0; i < 100; i++) {
1136 buf[bufObj->Size - i - 1] = 123;
1137 }
1138 }
1139 #endif
1140
1141 return bufObj->Pointer;
1142 }
1143
1144
1145 GLboolean GLAPIENTRY
1146 _mesa_UnmapBufferARB(GLenum target)
1147 {
1148 GET_CURRENT_CONTEXT(ctx);
1149 struct gl_buffer_object *bufObj;
1150 GLboolean status = GL_TRUE;
1151 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
1152
1153 bufObj = get_buffer(ctx, target);
1154 if (!bufObj) {
1155 _mesa_error(ctx, GL_INVALID_ENUM, "glUnmapBufferARB(target)" );
1156 return GL_FALSE;
1157 }
1158 if (bufObj->Name == 0) {
1159 _mesa_error(ctx, GL_INVALID_OPERATION, "glUnmapBufferARB" );
1160 return GL_FALSE;
1161 }
1162 if (!bufObj->Pointer) {
1163 _mesa_error(ctx, GL_INVALID_OPERATION, "glUnmapBufferARB");
1164 return GL_FALSE;
1165 }
1166
1167 #ifdef BOUNDS_CHECK
1168 if (bufObj->Access != GL_READ_ONLY_ARB) {
1169 GLubyte *buf = (GLubyte *) bufObj->Pointer;
1170 GLuint i;
1171 /* check that last 100 bytes are still = magic value */
1172 for (i = 0; i < 100; i++) {
1173 GLuint pos = bufObj->Size - i - 1;
1174 if (buf[pos] != 123) {
1175 _mesa_warning(ctx, "Out of bounds buffer object write detected"
1176 " at position %d (value = %u)\n",
1177 pos, buf[pos]);
1178 }
1179 }
1180 }
1181 #endif
1182
1183 #ifdef VBO_DEBUG
1184 if (bufObj->Access == GL_WRITE_ONLY_ARB) {
1185 GLuint i, unchanged = 0;
1186 GLubyte *b = (GLubyte *) bufObj->Pointer;
1187 GLint pos = -1;
1188 /* check which bytes changed */
1189 for (i = 0; i < bufObj->Size - 1; i++) {
1190 if (b[i] == (i & 0xff) && b[i+1] == ((i+1) & 0xff)) {
1191 unchanged++;
1192 if (pos == -1)
1193 pos = i;
1194 }
1195 }
1196 if (unchanged) {
1197 _mesa_printf("glUnmapBufferARB(%u): %u of %ld unchanged, starting at %d\n",
1198 bufObj->Name, unchanged, bufObj->Size, pos);
1199 }
1200 }
1201 #endif
1202
1203 status = ctx->Driver.UnmapBuffer( ctx, target, bufObj );
1204 bufObj->Access = DEFAULT_ACCESS;
1205 bufObj->Pointer = NULL;
1206
1207 return status;
1208 }
1209
1210
1211 void GLAPIENTRY
1212 _mesa_GetBufferParameterivARB(GLenum target, GLenum pname, GLint *params)
1213 {
1214 GET_CURRENT_CONTEXT(ctx);
1215 struct gl_buffer_object *bufObj;
1216 ASSERT_OUTSIDE_BEGIN_END(ctx);
1217
1218 bufObj = get_buffer(ctx, target);
1219 if (!bufObj) {
1220 _mesa_error(ctx, GL_INVALID_ENUM, "GetBufferParameterivARB(target)" );
1221 return;
1222 }
1223 if (bufObj->Name == 0) {
1224 _mesa_error(ctx, GL_INVALID_OPERATION, "GetBufferParameterivARB" );
1225 return;
1226 }
1227
1228 switch (pname) {
1229 case GL_BUFFER_SIZE_ARB:
1230 *params = (GLint) bufObj->Size;
1231 break;
1232 case GL_BUFFER_USAGE_ARB:
1233 *params = bufObj->Usage;
1234 break;
1235 case GL_BUFFER_ACCESS_ARB:
1236 *params = bufObj->Access;
1237 break;
1238 case GL_BUFFER_MAPPED_ARB:
1239 *params = (bufObj->Pointer != NULL);
1240 break;
1241 default:
1242 _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferParameterivARB(pname)");
1243 return;
1244 }
1245 }
1246
1247
1248 void GLAPIENTRY
1249 _mesa_GetBufferPointervARB(GLenum target, GLenum pname, GLvoid **params)
1250 {
1251 GET_CURRENT_CONTEXT(ctx);
1252 struct gl_buffer_object * bufObj;
1253 ASSERT_OUTSIDE_BEGIN_END(ctx);
1254
1255 if (pname != GL_BUFFER_MAP_POINTER_ARB) {
1256 _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferPointervARB(pname)");
1257 return;
1258 }
1259
1260 bufObj = get_buffer(ctx, target);
1261 if (!bufObj) {
1262 _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferPointervARB(target)" );
1263 return;
1264 }
1265 if (bufObj->Name == 0) {
1266 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetBufferPointervARB" );
1267 return;
1268 }
1269
1270 *params = bufObj->Pointer;
1271 }
1272
1273
1274 void GLAPIENTRY
1275 _mesa_CopyBufferSubData(GLenum readTarget, GLenum writeTarget,
1276 GLintptr readOffset, GLintptr writeOffset,
1277 GLsizeiptr size)
1278 {
1279 GET_CURRENT_CONTEXT(ctx);
1280 struct gl_buffer_object *src, *dst;
1281 ASSERT_OUTSIDE_BEGIN_END(ctx);
1282
1283 src = get_buffer(ctx, readTarget);
1284 if (!src || src->Name == 0) {
1285 _mesa_error(ctx, GL_INVALID_ENUM,
1286 "glCopyBuffserSubData(readTarget = 0x%x)", readTarget);
1287 return;
1288 }
1289
1290 dst = get_buffer(ctx, writeTarget);
1291 if (!dst || dst->Name == 0) {
1292 _mesa_error(ctx, GL_INVALID_ENUM,
1293 "glCopyBuffserSubData(writeTarget = 0x%x)", writeTarget);
1294 return;
1295 }
1296
1297 if (src->Pointer) {
1298 _mesa_error(ctx, GL_INVALID_OPERATION,
1299 "glCopyBuffserSubData(readBuffer is mapped)");
1300 return;
1301 }
1302
1303 if (dst->Pointer) {
1304 _mesa_error(ctx, GL_INVALID_OPERATION,
1305 "glCopyBuffserSubData(writeBuffer is mapped)");
1306 return;
1307 }
1308
1309 if (readOffset < 0) {
1310 _mesa_error(ctx, GL_INVALID_VALUE,
1311 "glCopyBuffserSubData(readOffset = %d)", readOffset);
1312 return;
1313 }
1314
1315 if (writeOffset < 0) {
1316 _mesa_error(ctx, GL_INVALID_VALUE,
1317 "glCopyBuffserSubData(writeOffset = %d)", writeOffset);
1318 return;
1319 }
1320
1321 if (readOffset + size > src->Size) {
1322 _mesa_error(ctx, GL_INVALID_VALUE,
1323 "glCopyBuffserSubData(readOffset + size = %d)",
1324 readOffset, size);
1325 return;
1326 }
1327
1328 if (writeOffset + size > dst->Size) {
1329 _mesa_error(ctx, GL_INVALID_VALUE,
1330 "glCopyBuffserSubData(writeOffset + size = %d)",
1331 writeOffset, size);
1332 return;
1333 }
1334
1335 if (src == dst) {
1336 if (readOffset + size <= writeOffset) {
1337 /* OK */
1338 }
1339 else if (writeOffset + size <= readOffset) {
1340 /* OK */
1341 }
1342 else {
1343 /* overlapping src/dst is illegal */
1344 _mesa_error(ctx, GL_INVALID_VALUE,
1345 "glCopyBuffserSubData(overlapping src/dst)");
1346 return;
1347 }
1348 }
1349
1350 ctx->Driver.CopyBufferSubData(ctx, src, dst, readOffset, writeOffset, size);
1351 }
1352