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