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