bufferobj.c revision c1f859d4
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 */
50static INLINE struct gl_buffer_object *
51get_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 */
96static struct gl_buffer_object *
97buffer_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 */
143struct 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 */
162void
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 */
182void
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 */
248void
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 */
281void
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 */
321void
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 */
355void
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 */
384void *
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 */
411GLboolean
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 */
427void
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 */
445static void
446bind_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 */
513void
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 */
545GLboolean
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 */
593const 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 */
623void
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 */
637const 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 */
666void
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 */
682void *
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 */
711void
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 */
726struct 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 */
743static void
744unbind(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
759void 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 */
775void 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         if (bufObj->Pointer) {
798            /* if mapped, unmap it now */
799            ctx->Driver.UnmapBuffer(ctx, 0, bufObj);
800            bufObj->Access = GL_READ_WRITE_ARB;
801            bufObj->Pointer = NULL;
802         }
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 */
848void 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 */
898GLboolean 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
913void 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      /* Unmap the existing buffer.  We'll replace it now.  Not an error. */
955      ctx->Driver.UnmapBuffer(ctx, target, bufObj);
956      bufObj->Access = GL_READ_WRITE_ARB;
957      bufObj->Pointer = NULL;
958   }
959
960   ASSERT(ctx->Driver.BufferData);
961
962   /* Give the buffer object to the driver!  <data> may be null! */
963   ctx->Driver.BufferData( ctx, target, size, data, usage, bufObj );
964}
965
966
967void GLAPIENTRY
968_mesa_BufferSubDataARB(GLenum target, GLintptrARB offset,
969                       GLsizeiptrARB size, const GLvoid * data)
970{
971   GET_CURRENT_CONTEXT(ctx);
972   struct gl_buffer_object *bufObj;
973   ASSERT_OUTSIDE_BEGIN_END(ctx);
974
975   bufObj = buffer_object_subdata_range_good( ctx, target, offset, size,
976                                              "glBufferSubDataARB" );
977   if (!bufObj) {
978      /* error already recorded */
979      return;
980   }
981
982   ASSERT(ctx->Driver.BufferSubData);
983   ctx->Driver.BufferSubData( ctx, target, offset, size, data, bufObj );
984}
985
986
987void GLAPIENTRY
988_mesa_GetBufferSubDataARB(GLenum target, GLintptrARB offset,
989                          GLsizeiptrARB size, void * data)
990{
991   GET_CURRENT_CONTEXT(ctx);
992   struct gl_buffer_object *bufObj;
993   ASSERT_OUTSIDE_BEGIN_END(ctx);
994
995   bufObj = buffer_object_subdata_range_good( ctx, target, offset, size,
996                                              "glGetBufferSubDataARB" );
997   if (!bufObj) {
998      /* error already recorded */
999      return;
1000   }
1001
1002   ASSERT(ctx->Driver.GetBufferSubData);
1003   ctx->Driver.GetBufferSubData( ctx, target, offset, size, data, bufObj );
1004}
1005
1006
1007void * GLAPIENTRY
1008_mesa_MapBufferARB(GLenum target, GLenum access)
1009{
1010   GET_CURRENT_CONTEXT(ctx);
1011   struct gl_buffer_object * bufObj;
1012   ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, NULL);
1013
1014   switch (access) {
1015      case GL_READ_ONLY_ARB:
1016      case GL_WRITE_ONLY_ARB:
1017      case GL_READ_WRITE_ARB:
1018         /* OK */
1019         break;
1020      default:
1021         _mesa_error(ctx, GL_INVALID_ENUM, "glMapBufferARB(access)");
1022         return NULL;
1023   }
1024
1025   bufObj = get_buffer(ctx, target);
1026   if (!bufObj) {
1027      _mesa_error(ctx, GL_INVALID_ENUM, "glMapBufferARB(target)" );
1028      return NULL;
1029   }
1030   if (bufObj->Name == 0) {
1031      _mesa_error(ctx, GL_INVALID_OPERATION, "glMapBufferARB" );
1032      return NULL;
1033   }
1034   if (bufObj->Pointer) {
1035      _mesa_error(ctx, GL_INVALID_OPERATION, "glMapBufferARB(already mapped)");
1036      return NULL;
1037   }
1038
1039   ASSERT(ctx->Driver.MapBuffer);
1040   bufObj->Pointer = ctx->Driver.MapBuffer( ctx, target, access, bufObj );
1041   if (!bufObj->Pointer) {
1042      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glMapBufferARB(access)");
1043   }
1044
1045   bufObj->Access = access;
1046
1047   return bufObj->Pointer;
1048}
1049
1050
1051GLboolean GLAPIENTRY
1052_mesa_UnmapBufferARB(GLenum target)
1053{
1054   GET_CURRENT_CONTEXT(ctx);
1055   struct gl_buffer_object *bufObj;
1056   GLboolean status = GL_TRUE;
1057   ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
1058
1059   bufObj = get_buffer(ctx, target);
1060   if (!bufObj) {
1061      _mesa_error(ctx, GL_INVALID_ENUM, "glUnmapBufferARB(target)" );
1062      return GL_FALSE;
1063   }
1064   if (bufObj->Name == 0) {
1065      _mesa_error(ctx, GL_INVALID_OPERATION, "glUnmapBufferARB" );
1066      return GL_FALSE;
1067   }
1068   if (!bufObj->Pointer) {
1069      _mesa_error(ctx, GL_INVALID_OPERATION, "glUnmapBufferARB");
1070      return GL_FALSE;
1071   }
1072
1073   status = ctx->Driver.UnmapBuffer( ctx, target, bufObj );
1074   bufObj->Access = GL_READ_WRITE_ARB;
1075   bufObj->Pointer = NULL;
1076
1077   return status;
1078}
1079
1080
1081void GLAPIENTRY
1082_mesa_GetBufferParameterivARB(GLenum target, GLenum pname, GLint *params)
1083{
1084   GET_CURRENT_CONTEXT(ctx);
1085   struct gl_buffer_object *bufObj;
1086   ASSERT_OUTSIDE_BEGIN_END(ctx);
1087
1088   bufObj = get_buffer(ctx, target);
1089   if (!bufObj) {
1090      _mesa_error(ctx, GL_INVALID_ENUM, "GetBufferParameterivARB(target)" );
1091      return;
1092   }
1093   if (bufObj->Name == 0) {
1094      _mesa_error(ctx, GL_INVALID_OPERATION, "GetBufferParameterivARB" );
1095      return;
1096   }
1097
1098   switch (pname) {
1099      case GL_BUFFER_SIZE_ARB:
1100         *params = (GLint) bufObj->Size;
1101         break;
1102      case GL_BUFFER_USAGE_ARB:
1103         *params = bufObj->Usage;
1104         break;
1105      case GL_BUFFER_ACCESS_ARB:
1106         *params = bufObj->Access;
1107         break;
1108      case GL_BUFFER_MAPPED_ARB:
1109         *params = (bufObj->Pointer != NULL);
1110         break;
1111      default:
1112         _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferParameterivARB(pname)");
1113         return;
1114   }
1115}
1116
1117
1118void GLAPIENTRY
1119_mesa_GetBufferPointervARB(GLenum target, GLenum pname, GLvoid **params)
1120{
1121   GET_CURRENT_CONTEXT(ctx);
1122   struct gl_buffer_object * bufObj;
1123   ASSERT_OUTSIDE_BEGIN_END(ctx);
1124
1125   if (pname != GL_BUFFER_MAP_POINTER_ARB) {
1126      _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferPointervARB(pname)");
1127      return;
1128   }
1129
1130   bufObj = get_buffer(ctx, target);
1131   if (!bufObj) {
1132      _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferPointervARB(target)" );
1133      return;
1134   }
1135   if (bufObj->Name == 0) {
1136      _mesa_error(ctx, GL_INVALID_OPERATION, "glGetBufferPointervARB" );
1137      return;
1138   }
1139
1140   *params = bufObj->Pointer;
1141}
1142