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