mesa: fix typo (s/feadback/feedback/). Fixes broken selection/feedback.
[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 /**
42 * Get the buffer object bound to the specified target in a GL context.
43 *
44 * \param ctx GL context
45 * \param target Buffer object target to be retrieved. Currently this must
46 * be either \c GL_ARRAY_BUFFER or \c GL_ELEMENT_ARRAY_BUFFER.
47 * \return A pointer to the buffer object bound to \c target in the
48 * specified context or \c NULL if \c target is invalid.
49 */
50 static INLINE struct gl_buffer_object *
51 get_buffer(GLcontext *ctx, GLenum target)
52 {
53 struct gl_buffer_object * bufObj = NULL;
54
55 switch (target) {
56 case GL_ARRAY_BUFFER_ARB:
57 bufObj = ctx->Array.ArrayBufferObj;
58 break;
59 case GL_ELEMENT_ARRAY_BUFFER_ARB:
60 bufObj = ctx->Array.ElementArrayBufferObj;
61 break;
62 case GL_PIXEL_PACK_BUFFER_EXT:
63 bufObj = ctx->Pack.BufferObj;
64 break;
65 case GL_PIXEL_UNPACK_BUFFER_EXT:
66 bufObj = ctx->Unpack.BufferObj;
67 break;
68 default:
69 /* error must be recorded by caller */
70 return NULL;
71 }
72
73 /* bufObj should point to NullBufferObj or a user-created buffer object */
74 ASSERT(bufObj);
75
76 return bufObj;
77 }
78
79
80 /**
81 * Tests the subdata range parameters and sets the GL error code for
82 * \c glBufferSubDataARB and \c glGetBufferSubDataARB.
83 *
84 * \param ctx GL context.
85 * \param target Buffer object target on which to operate.
86 * \param offset Offset of the first byte of the subdata range.
87 * \param size Size, in bytes, of the subdata range.
88 * \param caller Name of calling function for recording errors.
89 * \return A pointer to the buffer object bound to \c target in the
90 * specified context or \c NULL if any of the parameter or state
91 * conditions for \c glBufferSubDataARB or \c glGetBufferSubDataARB
92 * are invalid.
93 *
94 * \sa glBufferSubDataARB, glGetBufferSubDataARB
95 */
96 static struct gl_buffer_object *
97 buffer_object_subdata_range_good( GLcontext * ctx, GLenum target,
98 GLintptrARB offset, GLsizeiptrARB size,
99 const char *caller )
100 {
101 struct gl_buffer_object *bufObj;
102
103 if (size < 0) {
104 _mesa_error(ctx, GL_INVALID_VALUE, "%s(size < 0)", caller);
105 return NULL;
106 }
107
108 if (offset < 0) {
109 _mesa_error(ctx, GL_INVALID_VALUE, "%s(offset < 0)", caller);
110 return NULL;
111 }
112
113 bufObj = get_buffer(ctx, target);
114 if (!bufObj) {
115 _mesa_error(ctx, GL_INVALID_ENUM, "%s(target)", caller);
116 return NULL;
117 }
118 if (bufObj->Name == 0) {
119 _mesa_error(ctx, GL_INVALID_OPERATION, "%s", caller);
120 return NULL;
121 }
122 if (offset + size > bufObj->Size) {
123 _mesa_error(ctx, GL_INVALID_VALUE,
124 "%s(size + offset > buffer size)", caller);
125 return NULL;
126 }
127 if (bufObj->Pointer) {
128 /* Buffer is currently mapped */
129 _mesa_error(ctx, GL_INVALID_OPERATION, "%s", caller);
130 return NULL;
131 }
132
133 return bufObj;
134 }
135
136
137 /**
138 * Allocate and initialize a new buffer object.
139 *
140 * This function is intended to be called via
141 * \c dd_function_table::NewBufferObject.
142 */
143 struct gl_buffer_object *
144 _mesa_new_buffer_object( GLcontext *ctx, GLuint name, GLenum target )
145 {
146 struct gl_buffer_object *obj;
147
148 (void) ctx;
149
150 obj = MALLOC_STRUCT(gl_buffer_object);
151 _mesa_initialize_buffer_object(obj, name, target);
152 return obj;
153 }
154
155
156 /**
157 * Delete a buffer object.
158 *
159 * This function is intended to be called via
160 * \c dd_function_table::DeleteBuffer.
161 */
162 void
163 _mesa_delete_buffer_object( GLcontext *ctx, struct gl_buffer_object *bufObj )
164 {
165 (void) ctx;
166
167 if (bufObj->Data)
168 _mesa_free(bufObj->Data);
169
170 /* assign strange values here to help w/ debugging */
171 bufObj->RefCount = -1000;
172 bufObj->Name = ~0;
173
174 _mesa_free(bufObj);
175 }
176
177
178
179 /**
180 * Set ptr to bufObj w/ reference counting.
181 */
182 void
183 _mesa_reference_buffer_object(GLcontext *ctx,
184 struct gl_buffer_object **ptr,
185 struct gl_buffer_object *bufObj)
186 {
187 if (*ptr == bufObj)
188 return;
189
190 if (*ptr) {
191 /* Unreference the old texture */
192 GLboolean deleteFlag = GL_FALSE;
193 struct gl_buffer_object *oldObj = *ptr;
194
195 /*_glthread_LOCK_MUTEX(oldObj->Mutex);*/
196 ASSERT(oldObj->RefCount > 0);
197 oldObj->RefCount--;
198 #if 0
199 printf("BufferObj %p %d DECR to %d\n",
200 (void *) oldObj, oldObj->Name, oldObj->RefCount);
201 #endif
202 deleteFlag = (oldObj->RefCount == 0);
203 /*_glthread_UNLOCK_MUTEX(oldObj->Mutex);*/
204
205 if (deleteFlag) {
206
207 /* some sanity checking: don't delete a buffer still in use */
208 #if 0
209 /* unfortunately, these tests are invalid during context tear-down */
210 ASSERT(ctx->Array.ArrayBufferObj != bufObj);
211 ASSERT(ctx->Array.ElementArrayBufferObj != bufObj);
212 ASSERT(ctx->Array.ArrayObj->Vertex.BufferObj != bufObj);
213 #endif
214
215 ASSERT(ctx->Driver.DeleteBuffer);
216 ctx->Driver.DeleteBuffer(ctx, oldObj);
217 }
218
219 *ptr = NULL;
220 }
221 ASSERT(!*ptr);
222
223 if (bufObj) {
224 /* reference new texture */
225 /*_glthread_LOCK_MUTEX(tex->Mutex);*/
226 if (bufObj->RefCount == 0) {
227 /* this buffer's being deleted (look just above) */
228 /* Not sure this can every really happen. Warn if it does. */
229 _mesa_problem(NULL, "referencing deleted buffer object");
230 *ptr = NULL;
231 }
232 else {
233 bufObj->RefCount++;
234 #if 0
235 printf("BufferObj %p %d INCR to %d\n",
236 (void *) bufObj, bufObj->Name, bufObj->RefCount);
237 #endif
238 *ptr = bufObj;
239 }
240 /*_glthread_UNLOCK_MUTEX(tex->Mutex);*/
241 }
242 }
243
244
245 /**
246 * Initialize a buffer object to default values.
247 */
248 void
249 _mesa_initialize_buffer_object( struct gl_buffer_object *obj,
250 GLuint name, GLenum target )
251 {
252 (void) target;
253
254 _mesa_bzero(obj, sizeof(struct gl_buffer_object));
255 obj->RefCount = 1;
256 obj->Name = name;
257 obj->Usage = GL_STATIC_DRAW_ARB;
258 obj->Access = GL_READ_WRITE_ARB;
259 }
260
261
262 /**
263 * Allocate space for and store data in a buffer object. Any data that was
264 * previously stored in the buffer object is lost. If \c data is \c NULL,
265 * memory will be allocated, but no copy will occur.
266 *
267 * This function is intended to be called via
268 * \c dd_function_table::BufferData. This function need not set GL error
269 * codes. The input parameters will have been tested before calling.
270 *
271 * \param ctx GL context.
272 * \param target Buffer object target on which to operate.
273 * \param size Size, in bytes, of the new data store.
274 * \param data Pointer to the data to store in the buffer object. This
275 * pointer may be \c NULL.
276 * \param usage Hints about how the data will be used.
277 * \param bufObj Object to be used.
278 *
279 * \sa glBufferDataARB, dd_function_table::BufferData.
280 */
281 void
282 _mesa_buffer_data( GLcontext *ctx, GLenum target, GLsizeiptrARB size,
283 const GLvoid * data, GLenum usage,
284 struct gl_buffer_object * bufObj )
285 {
286 void * new_data;
287
288 (void) ctx; (void) target;
289
290 new_data = _mesa_realloc( bufObj->Data, bufObj->Size, size );
291 if (new_data) {
292 bufObj->Data = (GLubyte *) new_data;
293 bufObj->Size = size;
294 bufObj->Usage = usage;
295
296 if (data) {
297 _mesa_memcpy( bufObj->Data, data, size );
298 }
299 }
300 }
301
302
303 /**
304 * Replace data in a subrange of buffer object. If the data range
305 * specified by \c size + \c offset extends beyond the end of the buffer or
306 * if \c data is \c NULL, no copy is performed.
307 *
308 * This function is intended to be called by
309 * \c dd_function_table::BufferSubData. This function need not set GL error
310 * codes. The input parameters will have been tested before calling.
311 *
312 * \param ctx GL context.
313 * \param target Buffer object target on which to operate.
314 * \param offset Offset of the first byte to be modified.
315 * \param size Size, in bytes, of the data range.
316 * \param data Pointer to the data to store in the buffer object.
317 * \param bufObj Object to be used.
318 *
319 * \sa glBufferSubDataARB, dd_function_table::BufferSubData.
320 */
321 void
322 _mesa_buffer_subdata( GLcontext *ctx, GLenum target, GLintptrARB offset,
323 GLsizeiptrARB size, const GLvoid * data,
324 struct gl_buffer_object * bufObj )
325 {
326 (void) ctx; (void) target;
327
328 /* this should have been caught in _mesa_BufferSubData() */
329 ASSERT(size + offset <= bufObj->Size);
330
331 if (bufObj->Data) {
332 _mesa_memcpy( (GLubyte *) bufObj->Data + offset, data, size );
333 }
334 }
335
336
337 /**
338 * Retrieve data from a subrange of buffer object. If the data range
339 * specified by \c size + \c offset extends beyond the end of the buffer or
340 * if \c data is \c NULL, no copy is performed.
341 *
342 * This function is intended to be called by
343 * \c dd_function_table::BufferGetSubData. This function need not set GL error
344 * codes. The input parameters will have been tested before calling.
345 *
346 * \param ctx GL context.
347 * \param target Buffer object target on which to operate.
348 * \param offset Offset of the first byte to be modified.
349 * \param size Size, in bytes, of the data range.
350 * \param data Pointer to the data to store in the buffer object.
351 * \param bufObj Object to be used.
352 *
353 * \sa glBufferGetSubDataARB, dd_function_table::GetBufferSubData.
354 */
355 void
356 _mesa_buffer_get_subdata( GLcontext *ctx, GLenum target, GLintptrARB offset,
357 GLsizeiptrARB size, GLvoid * data,
358 struct gl_buffer_object * bufObj )
359 {
360 (void) ctx; (void) target;
361
362 if (bufObj->Data && ((GLsizeiptrARB) (size + offset) <= bufObj->Size)) {
363 _mesa_memcpy( data, (GLubyte *) bufObj->Data + offset, size );
364 }
365 }
366
367
368 /**
369 * Fallback function called via ctx->Driver.MapBuffer().
370 * Hardware drivers that really implement buffer objects should never use
371 * this function.
372 *
373 * The function parameters will have been already tested for errors.
374 *
375 * \param ctx GL context.
376 * \param target Buffer object target on which to operate.
377 * \param access Information about how the buffer will be accessed.
378 * \param bufObj Object to be mapped.
379 * \return A pointer to the object's internal data store that can be accessed
380 * by the processor
381 *
382 * \sa glMapBufferARB, dd_function_table::MapBuffer
383 */
384 void *
385 _mesa_buffer_map( GLcontext *ctx, GLenum target, GLenum access,
386 struct gl_buffer_object *bufObj )
387 {
388 (void) ctx;
389 (void) target;
390 (void) access;
391 ASSERT(!bufObj->OnCard);
392 /* Just return a direct pointer to the data */
393 if (bufObj->Pointer) {
394 /* already mapped! */
395 return NULL;
396 }
397 bufObj->Pointer = bufObj->Data;
398 return bufObj->Pointer;
399 }
400
401
402 /**
403 * Fallback function called via ctx->Driver.MapBuffer().
404 * Hardware drivers that really implement buffer objects should never use
405 * function.
406 *
407 * The input parameters will have been already tested for errors.
408 *
409 * \sa glUnmapBufferARB, dd_function_table::UnmapBuffer
410 */
411 GLboolean
412 _mesa_buffer_unmap( GLcontext *ctx, GLenum target,
413 struct gl_buffer_object *bufObj )
414 {
415 (void) ctx;
416 (void) target;
417 ASSERT(!bufObj->OnCard);
418 /* XXX we might assert here that bufObj->Pointer is non-null */
419 bufObj->Pointer = NULL;
420 return GL_TRUE;
421 }
422
423
424 /**
425 * Initialize the state associated with buffer objects
426 */
427 void
428 _mesa_init_buffer_objects( GLcontext *ctx )
429 {
430 /* Allocate the default buffer object and set refcount so high that
431 * it never gets deleted.
432 * XXX with recent/improved refcounting this may not longer be needed.
433 */
434 ctx->Array.NullBufferObj = _mesa_new_buffer_object(ctx, 0, 0);
435 if (ctx->Array.NullBufferObj)
436 ctx->Array.NullBufferObj->RefCount = 1000;
437
438 ctx->Array.ArrayBufferObj = ctx->Array.NullBufferObj;
439 ctx->Array.ElementArrayBufferObj = ctx->Array.NullBufferObj;
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_drapix_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 /* unbind any vertex pointers bound to this buffer */
793 GLuint j;
794
795 ASSERT(bufObj->Name == ids[i]);
796
797 unbind(ctx, &ctx->Array.ArrayObj->Vertex.BufferObj, bufObj);
798 unbind(ctx, &ctx->Array.ArrayObj->Normal.BufferObj, bufObj);
799 unbind(ctx, &ctx->Array.ArrayObj->Color.BufferObj, bufObj);
800 unbind(ctx, &ctx->Array.ArrayObj->SecondaryColor.BufferObj, bufObj);
801 unbind(ctx, &ctx->Array.ArrayObj->FogCoord.BufferObj, bufObj);
802 unbind(ctx, &ctx->Array.ArrayObj->Index.BufferObj, bufObj);
803 unbind(ctx, &ctx->Array.ArrayObj->EdgeFlag.BufferObj, bufObj);
804 for (j = 0; j < MAX_TEXTURE_UNITS; j++) {
805 unbind(ctx, &ctx->Array.ArrayObj->TexCoord[j].BufferObj, bufObj);
806 }
807 for (j = 0; j < VERT_ATTRIB_MAX; j++) {
808 unbind(ctx, &ctx->Array.ArrayObj->VertexAttrib[j].BufferObj, bufObj);
809 }
810
811 if (ctx->Array.ArrayBufferObj == bufObj) {
812 _mesa_BindBufferARB( GL_ARRAY_BUFFER_ARB, 0 );
813 }
814 if (ctx->Array.ElementArrayBufferObj == bufObj) {
815 _mesa_BindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, 0 );
816 }
817
818 if (ctx->Pack.BufferObj == bufObj) {
819 _mesa_BindBufferARB( GL_PIXEL_PACK_BUFFER_EXT, 0 );
820 }
821 if (ctx->Unpack.BufferObj == bufObj) {
822 _mesa_BindBufferARB( GL_PIXEL_UNPACK_BUFFER_EXT, 0 );
823 }
824
825 /* The ID is immediately freed for re-use */
826 _mesa_HashRemove(ctx->Shared->BufferObjects, bufObj->Name);
827 _mesa_reference_buffer_object(ctx, &bufObj, NULL);
828 }
829 }
830
831 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
832 }
833
834
835 /**
836 * Generate a set of unique buffer object IDs and store them in \c buffer.
837 *
838 * \param n Number of IDs to generate.
839 * \param buffer Array of \c n locations to store the IDs.
840 */
841 void GLAPIENTRY
842 _mesa_GenBuffersARB(GLsizei n, GLuint *buffer)
843 {
844 GET_CURRENT_CONTEXT(ctx);
845 GLuint first;
846 GLint i;
847 ASSERT_OUTSIDE_BEGIN_END(ctx);
848
849 if (n < 0) {
850 _mesa_error(ctx, GL_INVALID_VALUE, "glGenBuffersARB");
851 return;
852 }
853
854 if (!buffer) {
855 return;
856 }
857
858 /*
859 * This must be atomic (generation and allocation of buffer object IDs)
860 */
861 _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
862
863 first = _mesa_HashFindFreeKeyBlock(ctx->Shared->BufferObjects, n);
864
865 /* Allocate new, empty buffer objects and return identifiers */
866 for (i = 0; i < n; i++) {
867 struct gl_buffer_object *bufObj;
868 GLuint name = first + i;
869 GLenum target = 0;
870 bufObj = ctx->Driver.NewBufferObject( ctx, name, target );
871 if (!bufObj) {
872 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
873 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenBuffersARB");
874 return;
875 }
876 _mesa_HashInsert(ctx->Shared->BufferObjects, first + i, bufObj);
877 buffer[i] = first + i;
878 }
879
880 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
881 }
882
883
884 /**
885 * Determine if ID is the name of a buffer object.
886 *
887 * \param id ID of the potential buffer object.
888 * \return \c GL_TRUE if \c id is the name of a buffer object,
889 * \c GL_FALSE otherwise.
890 */
891 GLboolean GLAPIENTRY
892 _mesa_IsBufferARB(GLuint id)
893 {
894 struct gl_buffer_object *bufObj;
895 GET_CURRENT_CONTEXT(ctx);
896 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
897
898 _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
899 bufObj = _mesa_lookup_bufferobj(ctx, id);
900 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
901
902 return bufObj ? GL_TRUE : GL_FALSE;
903 }
904
905
906 void GLAPIENTRY
907 _mesa_BufferDataARB(GLenum target, GLsizeiptrARB size,
908 const GLvoid * data, GLenum usage)
909 {
910 GET_CURRENT_CONTEXT(ctx);
911 struct gl_buffer_object *bufObj;
912 ASSERT_OUTSIDE_BEGIN_END(ctx);
913
914 if (size < 0) {
915 _mesa_error(ctx, GL_INVALID_VALUE, "glBufferDataARB(size < 0)");
916 return;
917 }
918
919 switch (usage) {
920 case GL_STREAM_DRAW_ARB:
921 case GL_STREAM_READ_ARB:
922 case GL_STREAM_COPY_ARB:
923 case GL_STATIC_DRAW_ARB:
924 case GL_STATIC_READ_ARB:
925 case GL_STATIC_COPY_ARB:
926 case GL_DYNAMIC_DRAW_ARB:
927 case GL_DYNAMIC_READ_ARB:
928 case GL_DYNAMIC_COPY_ARB:
929 /* OK */
930 break;
931 default:
932 _mesa_error(ctx, GL_INVALID_ENUM, "glBufferDataARB(usage)");
933 return;
934 }
935
936 bufObj = get_buffer(ctx, target);
937 if (!bufObj) {
938 _mesa_error(ctx, GL_INVALID_ENUM, "glBufferDataARB(target)" );
939 return;
940 }
941 if (bufObj->Name == 0) {
942 _mesa_error(ctx, GL_INVALID_OPERATION, "glBufferDataARB" );
943 return;
944 }
945
946 if (bufObj->Pointer) {
947 _mesa_error(ctx, GL_INVALID_OPERATION, "glBufferDataARB(buffer is mapped)" );
948 return;
949 }
950
951 ASSERT(ctx->Driver.BufferData);
952
953 /* Give the buffer object to the driver! <data> may be null! */
954 ctx->Driver.BufferData( ctx, target, size, data, usage, bufObj );
955 }
956
957
958 void GLAPIENTRY
959 _mesa_BufferSubDataARB(GLenum target, GLintptrARB offset,
960 GLsizeiptrARB size, const GLvoid * data)
961 {
962 GET_CURRENT_CONTEXT(ctx);
963 struct gl_buffer_object *bufObj;
964 ASSERT_OUTSIDE_BEGIN_END(ctx);
965
966 bufObj = buffer_object_subdata_range_good( ctx, target, offset, size,
967 "glBufferSubDataARB" );
968 if (!bufObj) {
969 /* error already recorded */
970 return;
971 }
972
973 ASSERT(ctx->Driver.BufferSubData);
974 ctx->Driver.BufferSubData( ctx, target, offset, size, data, bufObj );
975 }
976
977
978 void GLAPIENTRY
979 _mesa_GetBufferSubDataARB(GLenum target, GLintptrARB offset,
980 GLsizeiptrARB size, void * data)
981 {
982 GET_CURRENT_CONTEXT(ctx);
983 struct gl_buffer_object *bufObj;
984 ASSERT_OUTSIDE_BEGIN_END(ctx);
985
986 bufObj = buffer_object_subdata_range_good( ctx, target, offset, size,
987 "glGetBufferSubDataARB" );
988 if (!bufObj) {
989 /* error already recorded */
990 return;
991 }
992
993 ASSERT(ctx->Driver.GetBufferSubData);
994 ctx->Driver.GetBufferSubData( ctx, target, offset, size, data, bufObj );
995 }
996
997
998 void * GLAPIENTRY
999 _mesa_MapBufferARB(GLenum target, GLenum access)
1000 {
1001 GET_CURRENT_CONTEXT(ctx);
1002 struct gl_buffer_object * bufObj;
1003 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, NULL);
1004
1005 switch (access) {
1006 case GL_READ_ONLY_ARB:
1007 case GL_WRITE_ONLY_ARB:
1008 case GL_READ_WRITE_ARB:
1009 /* OK */
1010 break;
1011 default:
1012 _mesa_error(ctx, GL_INVALID_ENUM, "glMapBufferARB(access)");
1013 return NULL;
1014 }
1015
1016 bufObj = get_buffer(ctx, target);
1017 if (!bufObj) {
1018 _mesa_error(ctx, GL_INVALID_ENUM, "glMapBufferARB(target)" );
1019 return NULL;
1020 }
1021 if (bufObj->Name == 0) {
1022 _mesa_error(ctx, GL_INVALID_OPERATION, "glMapBufferARB" );
1023 return NULL;
1024 }
1025 if (bufObj->Pointer) {
1026 _mesa_error(ctx, GL_INVALID_OPERATION, "glMapBufferARB(already mapped)");
1027 return NULL;
1028 }
1029
1030 ASSERT(ctx->Driver.MapBuffer);
1031 bufObj->Pointer = ctx->Driver.MapBuffer( ctx, target, access, bufObj );
1032 if (!bufObj->Pointer) {
1033 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glMapBufferARB(access)");
1034 }
1035
1036 bufObj->Access = access;
1037
1038 return bufObj->Pointer;
1039 }
1040
1041
1042 GLboolean GLAPIENTRY
1043 _mesa_UnmapBufferARB(GLenum target)
1044 {
1045 GET_CURRENT_CONTEXT(ctx);
1046 struct gl_buffer_object *bufObj;
1047 GLboolean status = GL_TRUE;
1048 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
1049
1050 bufObj = get_buffer(ctx, target);
1051 if (!bufObj) {
1052 _mesa_error(ctx, GL_INVALID_ENUM, "glUnmapBufferARB(target)" );
1053 return GL_FALSE;
1054 }
1055 if (bufObj->Name == 0) {
1056 _mesa_error(ctx, GL_INVALID_OPERATION, "glUnmapBufferARB" );
1057 return GL_FALSE;
1058 }
1059 if (!bufObj->Pointer) {
1060 _mesa_error(ctx, GL_INVALID_OPERATION, "glUnmapBufferARB");
1061 return GL_FALSE;
1062 }
1063
1064 if (ctx->Driver.UnmapBuffer) {
1065 status = ctx->Driver.UnmapBuffer( ctx, target, bufObj );
1066 }
1067
1068 bufObj->Access = GL_READ_WRITE_ARB; /* initial value, OK? */
1069 bufObj->Pointer = NULL;
1070
1071 return status;
1072 }
1073
1074
1075 void GLAPIENTRY
1076 _mesa_GetBufferParameterivARB(GLenum target, GLenum pname, GLint *params)
1077 {
1078 GET_CURRENT_CONTEXT(ctx);
1079 struct gl_buffer_object *bufObj;
1080 ASSERT_OUTSIDE_BEGIN_END(ctx);
1081
1082 bufObj = get_buffer(ctx, target);
1083 if (!bufObj) {
1084 _mesa_error(ctx, GL_INVALID_ENUM, "GetBufferParameterivARB(target)" );
1085 return;
1086 }
1087 if (bufObj->Name == 0) {
1088 _mesa_error(ctx, GL_INVALID_OPERATION, "GetBufferParameterivARB" );
1089 return;
1090 }
1091
1092 switch (pname) {
1093 case GL_BUFFER_SIZE_ARB:
1094 *params = (GLint) bufObj->Size;
1095 break;
1096 case GL_BUFFER_USAGE_ARB:
1097 *params = bufObj->Usage;
1098 break;
1099 case GL_BUFFER_ACCESS_ARB:
1100 *params = bufObj->Access;
1101 break;
1102 case GL_BUFFER_MAPPED_ARB:
1103 *params = (bufObj->Pointer != NULL);
1104 break;
1105 default:
1106 _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferParameterivARB(pname)");
1107 return;
1108 }
1109 }
1110
1111
1112 void GLAPIENTRY
1113 _mesa_GetBufferPointervARB(GLenum target, GLenum pname, GLvoid **params)
1114 {
1115 GET_CURRENT_CONTEXT(ctx);
1116 struct gl_buffer_object * bufObj;
1117 ASSERT_OUTSIDE_BEGIN_END(ctx);
1118
1119 if (pname != GL_BUFFER_MAP_POINTER_ARB) {
1120 _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferPointervARB(pname)");
1121 return;
1122 }
1123
1124 bufObj = get_buffer(ctx, target);
1125 if (!bufObj) {
1126 _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferPointervARB(target)" );
1127 return;
1128 }
1129 if (bufObj->Name == 0) {
1130 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetBufferPointervARB" );
1131 return;
1132 }
1133
1134 *params = bufObj->Pointer;
1135 }