bufferobj.c revision 4a49301e
1/*
2 * Mesa 3-D graphics library
3 * Version:  7.6
4 *
5 * Copyright (C) 1999-2008  Brian Paul   All Rights Reserved.
6 * Copyright (C) 2009  VMware, Inc.  All Rights Reserved.
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the "Software"),
10 * to deal in the Software without restriction, including without limitation
11 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 * and/or sell copies of the Software, and to permit persons to whom the
13 * Software is furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included
16 * in all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
21 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
22 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 */
25
26
27/**
28 * \file bufferobj.c
29 * \brief Functions for the GL_ARB_vertex/pixel_buffer_object extensions.
30 * \author Brian Paul, Ian Romanick
31 */
32
33
34#include "glheader.h"
35#include "hash.h"
36#include "imports.h"
37#include "image.h"
38#include "context.h"
39#include "bufferobj.h"
40
41
42/* Debug flags */
43/*#define VBO_DEBUG*/
44/*#define BOUNDS_CHECK*/
45
46
47#ifdef FEATURE_OES_mapbuffer
48#define DEFAULT_ACCESS GL_MAP_WRITE_BIT
49#else
50#define DEFAULT_ACCESS (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)
51#endif
52
53
54/**
55 * Return pointer to address of a buffer object target.
56 * \param ctx  the GL context
57 * \param target  the buffer object target to be retrieved.
58 * \return   pointer to pointer to the buffer object bound to \c target in the
59 *           specified context or \c NULL if \c target is invalid.
60 */
61static INLINE struct gl_buffer_object **
62get_buffer_target(GLcontext *ctx, GLenum target)
63{
64   switch (target) {
65   case GL_ARRAY_BUFFER_ARB:
66      return &ctx->Array.ArrayBufferObj;
67   case GL_ELEMENT_ARRAY_BUFFER_ARB:
68      return &ctx->Array.ElementArrayBufferObj;
69   case GL_PIXEL_PACK_BUFFER_EXT:
70      return &ctx->Pack.BufferObj;
71   case GL_PIXEL_UNPACK_BUFFER_EXT:
72      return &ctx->Unpack.BufferObj;
73   case GL_COPY_READ_BUFFER:
74      if (ctx->Extensions.ARB_copy_buffer) {
75         return &ctx->CopyReadBuffer;
76      }
77      break;
78   case GL_COPY_WRITE_BUFFER:
79      if (ctx->Extensions.ARB_copy_buffer) {
80         return &ctx->CopyWriteBuffer;
81      }
82      break;
83   default:
84      return NULL;
85   }
86   return NULL;
87}
88
89
90/**
91 * Get the buffer object bound to the specified target in a GL context.
92 * \param ctx  the GL context
93 * \param target  the buffer object target to be retrieved.
94 * \return   pointer to the buffer object bound to \c target in the
95 *           specified context or \c NULL if \c target is invalid.
96 */
97static INLINE struct gl_buffer_object *
98get_buffer(GLcontext *ctx, GLenum target)
99{
100   struct gl_buffer_object **bufObj = get_buffer_target(ctx, target);
101   if (bufObj)
102      return *bufObj;
103   return NULL;
104}
105
106
107/**
108 * Convert a GLbitfield describing the mapped buffer access flags
109 * into one of GL_READ_WRITE, GL_READ_ONLY, or GL_WRITE_ONLY.
110 */
111static GLenum
112simplified_access_mode(GLbitfield access)
113{
114   const GLbitfield rwFlags = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT;
115   if ((access & rwFlags) == rwFlags)
116      return GL_READ_WRITE;
117   if ((access & GL_MAP_READ_BIT) == GL_MAP_READ_BIT)
118      return GL_READ_ONLY;
119   if ((access & GL_MAP_WRITE_BIT) == GL_MAP_WRITE_BIT)
120      return GL_WRITE_ONLY;
121   return GL_READ_WRITE; /* this should never happen, but no big deal */
122}
123
124
125/**
126 * Tests the subdata range parameters and sets the GL error code for
127 * \c glBufferSubDataARB and \c glGetBufferSubDataARB.
128 *
129 * \param ctx     GL context.
130 * \param target  Buffer object target on which to operate.
131 * \param offset  Offset of the first byte of the subdata range.
132 * \param size    Size, in bytes, of the subdata range.
133 * \param caller  Name of calling function for recording errors.
134 * \return   A pointer to the buffer object bound to \c target in the
135 *           specified context or \c NULL if any of the parameter or state
136 *           conditions for \c glBufferSubDataARB or \c glGetBufferSubDataARB
137 *           are invalid.
138 *
139 * \sa glBufferSubDataARB, glGetBufferSubDataARB
140 */
141static struct gl_buffer_object *
142buffer_object_subdata_range_good( GLcontext * ctx, GLenum target,
143                                  GLintptrARB offset, GLsizeiptrARB size,
144                                  const char *caller )
145{
146   struct gl_buffer_object *bufObj;
147
148   if (size < 0) {
149      _mesa_error(ctx, GL_INVALID_VALUE, "%s(size < 0)", caller);
150      return NULL;
151   }
152
153   if (offset < 0) {
154      _mesa_error(ctx, GL_INVALID_VALUE, "%s(offset < 0)", caller);
155      return NULL;
156   }
157
158   bufObj = get_buffer(ctx, target);
159   if (!bufObj) {
160      _mesa_error(ctx, GL_INVALID_ENUM, "%s(target)", caller);
161      return NULL;
162   }
163   if (!_mesa_is_bufferobj(bufObj)) {
164      _mesa_error(ctx, GL_INVALID_OPERATION, "%s", caller);
165      return NULL;
166   }
167   if (offset + size > bufObj->Size) {
168      _mesa_error(ctx, GL_INVALID_VALUE,
169		  "%s(size + offset > buffer size)", caller);
170      return NULL;
171   }
172   if (_mesa_bufferobj_mapped(bufObj)) {
173      /* Buffer is currently mapped */
174      _mesa_error(ctx, GL_INVALID_OPERATION, "%s", caller);
175      return NULL;
176   }
177
178   return bufObj;
179}
180
181
182/**
183 * Allocate and initialize a new buffer object.
184 *
185 * Default callback for the \c dd_function_table::NewBufferObject() hook.
186 */
187static struct gl_buffer_object *
188_mesa_new_buffer_object( GLcontext *ctx, GLuint name, GLenum target )
189{
190   struct gl_buffer_object *obj;
191
192   (void) ctx;
193
194   obj = MALLOC_STRUCT(gl_buffer_object);
195   _mesa_initialize_buffer_object(obj, name, target);
196   return obj;
197}
198
199
200/**
201 * Delete a buffer object.
202 *
203 * Default callback for the \c dd_function_table::DeleteBuffer() hook.
204 */
205static void
206_mesa_delete_buffer_object( GLcontext *ctx, struct gl_buffer_object *bufObj )
207{
208   (void) ctx;
209
210   if (bufObj->Data)
211      _mesa_free(bufObj->Data);
212
213   /* assign strange values here to help w/ debugging */
214   bufObj->RefCount = -1000;
215   bufObj->Name = ~0;
216
217   _glthread_DESTROY_MUTEX(bufObj->Mutex);
218   _mesa_free(bufObj);
219}
220
221
222
223/**
224 * Set ptr to bufObj w/ reference counting.
225 */
226void
227_mesa_reference_buffer_object(GLcontext *ctx,
228                              struct gl_buffer_object **ptr,
229                              struct gl_buffer_object *bufObj)
230{
231   if (*ptr == bufObj)
232      return;
233
234   if (*ptr) {
235      /* Unreference the old buffer */
236      GLboolean deleteFlag = GL_FALSE;
237      struct gl_buffer_object *oldObj = *ptr;
238
239      _glthread_LOCK_MUTEX(oldObj->Mutex);
240      ASSERT(oldObj->RefCount > 0);
241      oldObj->RefCount--;
242#if 0
243      printf("BufferObj %p %d DECR to %d\n",
244             (void *) oldObj, oldObj->Name, oldObj->RefCount);
245#endif
246      deleteFlag = (oldObj->RefCount == 0);
247      _glthread_UNLOCK_MUTEX(oldObj->Mutex);
248
249      if (deleteFlag) {
250
251         /* some sanity checking: don't delete a buffer still in use */
252#if 0
253         /* unfortunately, these tests are invalid during context tear-down */
254	 ASSERT(ctx->Array.ArrayBufferObj != bufObj);
255	 ASSERT(ctx->Array.ElementArrayBufferObj != bufObj);
256	 ASSERT(ctx->Array.ArrayObj->Vertex.BufferObj != bufObj);
257#endif
258
259	 ASSERT(ctx->Driver.DeleteBuffer);
260         ctx->Driver.DeleteBuffer(ctx, oldObj);
261      }
262
263      *ptr = NULL;
264   }
265   ASSERT(!*ptr);
266
267   if (bufObj) {
268      /* reference new buffer */
269      _glthread_LOCK_MUTEX(bufObj->Mutex);
270      if (bufObj->RefCount == 0) {
271         /* this buffer's being deleted (look just above) */
272         /* Not sure this can every really happen.  Warn if it does. */
273         _mesa_problem(NULL, "referencing deleted buffer object");
274         *ptr = NULL;
275      }
276      else {
277         bufObj->RefCount++;
278#if 0
279         printf("BufferObj %p %d INCR to %d\n",
280                (void *) bufObj, bufObj->Name, bufObj->RefCount);
281#endif
282         *ptr = bufObj;
283      }
284      _glthread_UNLOCK_MUTEX(bufObj->Mutex);
285   }
286}
287
288
289/**
290 * Initialize a buffer object to default values.
291 */
292void
293_mesa_initialize_buffer_object( struct gl_buffer_object *obj,
294				GLuint name, GLenum target )
295{
296   (void) target;
297
298   _mesa_bzero(obj, sizeof(struct gl_buffer_object));
299   _glthread_INIT_MUTEX(obj->Mutex);
300   obj->RefCount = 1;
301   obj->Name = name;
302   obj->Usage = GL_STATIC_DRAW_ARB;
303   obj->AccessFlags = DEFAULT_ACCESS;
304}
305
306
307/**
308 * Allocate space for and store data in a buffer object.  Any data that was
309 * previously stored in the buffer object is lost.  If \c data is \c NULL,
310 * memory will be allocated, but no copy will occur.
311 *
312 * This is the default callback for \c dd_function_table::BufferData()
313 * Note that all GL error checking will have been done already.
314 *
315 * \param ctx     GL context.
316 * \param target  Buffer object target on which to operate.
317 * \param size    Size, in bytes, of the new data store.
318 * \param data    Pointer to the data to store in the buffer object.  This
319 *                pointer may be \c NULL.
320 * \param usage   Hints about how the data will be used.
321 * \param bufObj  Object to be used.
322 *
323 * \return GL_TRUE for success, GL_FALSE for failure
324 * \sa glBufferDataARB, dd_function_table::BufferData.
325 */
326static GLboolean
327_mesa_buffer_data( GLcontext *ctx, GLenum target, GLsizeiptrARB size,
328		   const GLvoid * data, GLenum usage,
329		   struct gl_buffer_object * bufObj )
330{
331   void * new_data;
332
333   (void) ctx; (void) target;
334
335   new_data = _mesa_realloc( bufObj->Data, bufObj->Size, size );
336   if (new_data) {
337      bufObj->Data = (GLubyte *) new_data;
338      bufObj->Size = size;
339      bufObj->Usage = usage;
340
341      if (data) {
342	 _mesa_memcpy( bufObj->Data, data, size );
343      }
344
345      return GL_TRUE;
346   }
347   else {
348      return GL_FALSE;
349   }
350}
351
352
353/**
354 * Replace data in a subrange of buffer object.  If the data range
355 * specified by \c size + \c offset extends beyond the end of the buffer or
356 * if \c data is \c NULL, no copy is performed.
357 *
358 * This is the default callback for \c dd_function_table::BufferSubData()
359 * Note that all GL error checking will have been done already.
360 *
361 * \param ctx     GL context.
362 * \param target  Buffer object target on which to operate.
363 * \param offset  Offset of the first byte to be modified.
364 * \param size    Size, in bytes, of the data range.
365 * \param data    Pointer to the data to store in the buffer object.
366 * \param bufObj  Object to be used.
367 *
368 * \sa glBufferSubDataARB, dd_function_table::BufferSubData.
369 */
370static void
371_mesa_buffer_subdata( GLcontext *ctx, GLenum target, GLintptrARB offset,
372		      GLsizeiptrARB size, const GLvoid * data,
373		      struct gl_buffer_object * bufObj )
374{
375   (void) ctx; (void) target;
376
377   /* this should have been caught in _mesa_BufferSubData() */
378   ASSERT(size + offset <= bufObj->Size);
379
380   if (bufObj->Data) {
381      _mesa_memcpy( (GLubyte *) bufObj->Data + offset, data, size );
382   }
383}
384
385
386/**
387 * Retrieve data from a subrange of buffer object.  If the data range
388 * specified by \c size + \c offset extends beyond the end of the buffer or
389 * if \c data is \c NULL, no copy is performed.
390 *
391 * This is the default callback for \c dd_function_table::GetBufferSubData()
392 * Note that all GL error checking will have been done already.
393 *
394 * \param ctx     GL context.
395 * \param target  Buffer object target on which to operate.
396 * \param offset  Offset of the first byte to be fetched.
397 * \param size    Size, in bytes, of the data range.
398 * \param data    Destination for data
399 * \param bufObj  Object to be used.
400 *
401 * \sa glBufferGetSubDataARB, dd_function_table::GetBufferSubData.
402 */
403static void
404_mesa_buffer_get_subdata( GLcontext *ctx, GLenum target, GLintptrARB offset,
405			  GLsizeiptrARB size, GLvoid * data,
406			  struct gl_buffer_object * bufObj )
407{
408   (void) ctx; (void) target;
409
410   if (bufObj->Data && ((GLsizeiptrARB) (size + offset) <= bufObj->Size)) {
411      _mesa_memcpy( data, (GLubyte *) bufObj->Data + offset, size );
412   }
413}
414
415
416/**
417 * Default callback for \c dd_function_tabel::MapBuffer().
418 *
419 * The function parameters will have been already tested for errors.
420 *
421 * \param ctx     GL context.
422 * \param target  Buffer object target on which to operate.
423 * \param access  Information about how the buffer will be accessed.
424 * \param bufObj  Object to be mapped.
425 * \return  A pointer to the object's internal data store that can be accessed
426 *          by the processor
427 *
428 * \sa glMapBufferARB, dd_function_table::MapBuffer
429 */
430static void *
431_mesa_buffer_map( GLcontext *ctx, GLenum target, GLenum access,
432		  struct gl_buffer_object *bufObj )
433{
434   (void) ctx;
435   (void) target;
436   (void) access;
437   /* Just return a direct pointer to the data */
438   if (_mesa_bufferobj_mapped(bufObj)) {
439      /* already mapped! */
440      return NULL;
441   }
442   bufObj->Pointer = bufObj->Data;
443   bufObj->Length = bufObj->Size;
444   bufObj->Offset = 0;
445   return bufObj->Pointer;
446}
447
448
449/**
450 * Default fallback for \c dd_function_table::MapBufferRange().
451 * Called via glMapBufferRange().
452 */
453static void *
454_mesa_buffer_map_range( GLcontext *ctx, GLenum target, GLintptr offset,
455                        GLsizeiptr length, GLbitfield access,
456                        struct gl_buffer_object *bufObj )
457{
458   (void) ctx;
459   (void) target;
460   assert(!_mesa_bufferobj_mapped(bufObj));
461   /* Just return a direct pointer to the data */
462   bufObj->Pointer = bufObj->Data + offset;
463   bufObj->Length = length;
464   bufObj->Offset = offset;
465   bufObj->AccessFlags = access;
466   return bufObj->Pointer;
467}
468
469
470/**
471 * Default fallback for \c dd_function_table::FlushMappedBufferRange().
472 * Called via glFlushMappedBufferRange().
473 */
474static void
475_mesa_buffer_flush_mapped_range( GLcontext *ctx, GLenum target,
476                                 GLintptr offset, GLsizeiptr length,
477                                 struct gl_buffer_object *obj )
478{
479   (void) ctx;
480   (void) target;
481   (void) offset;
482   (void) length;
483   (void) obj;
484   /* no-op */
485}
486
487
488/**
489 * Default callback for \c dd_function_table::MapBuffer().
490 *
491 * The input parameters will have been already tested for errors.
492 *
493 * \sa glUnmapBufferARB, dd_function_table::UnmapBuffer
494 */
495static GLboolean
496_mesa_buffer_unmap( GLcontext *ctx, GLenum target,
497                    struct gl_buffer_object *bufObj )
498{
499   (void) ctx;
500   (void) target;
501   /* XXX we might assert here that bufObj->Pointer is non-null */
502   bufObj->Pointer = NULL;
503   bufObj->Length = 0;
504   bufObj->Offset = 0;
505   bufObj->AccessFlags = 0x0;
506   return GL_TRUE;
507}
508
509
510/**
511 * Default fallback for \c dd_function_table::CopyBufferSubData().
512 * Called via glCopyBuffserSubData().
513 */
514static void
515_mesa_copy_buffer_subdata(GLcontext *ctx,
516                          struct gl_buffer_object *src,
517                          struct gl_buffer_object *dst,
518                          GLintptr readOffset, GLintptr writeOffset,
519                          GLsizeiptr size)
520{
521   GLubyte *srcPtr, *dstPtr;
522
523   /* buffer should not already be mapped */
524   assert(!_mesa_bufferobj_mapped(src));
525   assert(!_mesa_bufferobj_mapped(dst));
526
527   srcPtr = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_COPY_READ_BUFFER,
528                                              GL_READ_ONLY, src);
529   dstPtr = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_COPY_WRITE_BUFFER,
530                                              GL_WRITE_ONLY, dst);
531
532   if (srcPtr && dstPtr)
533      _mesa_memcpy(dstPtr + writeOffset, srcPtr + readOffset, size);
534
535   ctx->Driver.UnmapBuffer(ctx, GL_COPY_READ_BUFFER, src);
536   ctx->Driver.UnmapBuffer(ctx, GL_COPY_WRITE_BUFFER, dst);
537}
538
539
540
541/**
542 * Initialize the state associated with buffer objects
543 */
544void
545_mesa_init_buffer_objects( GLcontext *ctx )
546{
547   _mesa_reference_buffer_object(ctx, &ctx->Array.ArrayBufferObj,
548                                 ctx->Shared->NullBufferObj);
549   _mesa_reference_buffer_object(ctx, &ctx->Array.ElementArrayBufferObj,
550                                 ctx->Shared->NullBufferObj);
551
552   _mesa_reference_buffer_object(ctx, &ctx->CopyReadBuffer,
553                                 ctx->Shared->NullBufferObj);
554   _mesa_reference_buffer_object(ctx, &ctx->CopyWriteBuffer,
555                                 ctx->Shared->NullBufferObj);
556}
557
558
559void
560_mesa_free_buffer_objects( GLcontext *ctx )
561{
562   _mesa_reference_buffer_object(ctx, &ctx->Array.ArrayBufferObj, NULL);
563   _mesa_reference_buffer_object(ctx, &ctx->Array.ElementArrayBufferObj, NULL);
564
565   _mesa_reference_buffer_object(ctx, &ctx->CopyReadBuffer, NULL);
566   _mesa_reference_buffer_object(ctx, &ctx->CopyWriteBuffer, NULL);
567}
568
569
570/**
571 * Bind the specified target to buffer for the specified context.
572 * Called by glBindBuffer() and other functions.
573 */
574static void
575bind_buffer_object(GLcontext *ctx, GLenum target, GLuint buffer)
576{
577   struct gl_buffer_object *oldBufObj;
578   struct gl_buffer_object *newBufObj = NULL;
579   struct gl_buffer_object **bindTarget = NULL;
580
581   bindTarget = get_buffer_target(ctx, target);
582   if (!bindTarget) {
583      _mesa_error(ctx, GL_INVALID_ENUM, "glBindBufferARB(target 0x%x)");
584      return;
585   }
586
587   /* Get pointer to old buffer object (to be unbound) */
588   oldBufObj = *bindTarget;
589   if (oldBufObj && oldBufObj->Name == buffer)
590      return;   /* rebinding the same buffer object- no change */
591
592   /*
593    * Get pointer to new buffer object (newBufObj)
594    */
595   if (buffer == 0) {
596      /* The spec says there's not a buffer object named 0, but we use
597       * one internally because it simplifies things.
598       */
599      newBufObj = ctx->Shared->NullBufferObj;
600   }
601   else {
602      /* non-default buffer object */
603      newBufObj = _mesa_lookup_bufferobj(ctx, buffer);
604      if (!newBufObj) {
605         /* if this is a new buffer object id, allocate a buffer object now */
606         ASSERT(ctx->Driver.NewBufferObject);
607         newBufObj = ctx->Driver.NewBufferObject(ctx, buffer, target);
608         if (!newBufObj) {
609            _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindBufferARB");
610            return;
611         }
612         _mesa_HashInsert(ctx->Shared->BufferObjects, buffer, newBufObj);
613      }
614   }
615
616   /* bind new buffer */
617   _mesa_reference_buffer_object(ctx, bindTarget, newBufObj);
618
619   /* Pass BindBuffer call to device driver */
620   if (ctx->Driver.BindBuffer)
621      ctx->Driver.BindBuffer( ctx, target, newBufObj );
622}
623
624
625/**
626 * Update the default buffer objects in the given context to reference those
627 * specified in the shared state and release those referencing the old
628 * shared state.
629 */
630void
631_mesa_update_default_objects_buffer_objects(GLcontext *ctx)
632{
633   /* Bind the NullBufferObj to remove references to those
634    * in the shared context hash table.
635    */
636   bind_buffer_object( ctx, GL_ARRAY_BUFFER_ARB, 0);
637   bind_buffer_object( ctx, GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
638   bind_buffer_object( ctx, GL_PIXEL_PACK_BUFFER_ARB, 0);
639   bind_buffer_object( ctx, GL_PIXEL_UNPACK_BUFFER_ARB, 0);
640}
641
642
643/**
644 * When we're about to read pixel data out of a PBO (via glDrawPixels,
645 * glTexImage, etc) or write data into a PBO (via glReadPixels,
646 * glGetTexImage, etc) we call this function to check that we're not
647 * going to read out of bounds.
648 *
649 * XXX This would also be a convenient time to check that the PBO isn't
650 * currently mapped.  Whoever calls this function should check for that.
651 * Remember, we can't use a PBO when it's mapped!
652 *
653 * If we're not using a PBO, this is a no-op.
654 *
655 * \param width  width of image to read/write
656 * \param height  height of image to read/write
657 * \param depth  depth of image to read/write
658 * \param format  format of image to read/write
659 * \param type  datatype of image to read/write
660 * \param ptr  the user-provided pointer/offset
661 * \return GL_TRUE if the PBO access is OK, GL_FALSE if the access would
662 *         go out of bounds.
663 */
664GLboolean
665_mesa_validate_pbo_access(GLuint dimensions,
666                          const struct gl_pixelstore_attrib *pack,
667                          GLsizei width, GLsizei height, GLsizei depth,
668                          GLenum format, GLenum type, const GLvoid *ptr)
669{
670   GLvoid *start, *end;
671   const GLubyte *sizeAddr; /* buffer size, cast to a pointer */
672
673   if (!_mesa_is_bufferobj(pack->BufferObj))
674      return GL_TRUE;  /* no PBO, OK */
675
676   if (pack->BufferObj->Size == 0)
677      /* no buffer! */
678      return GL_FALSE;
679
680   /* get address of first pixel we'll read */
681   start = _mesa_image_address(dimensions, pack, ptr, width, height,
682                               format, type, 0, 0, 0);
683
684   /* get address just past the last pixel we'll read */
685   end =  _mesa_image_address(dimensions, pack, ptr, width, height,
686                              format, type, depth-1, height-1, width);
687
688
689   sizeAddr = ((const GLubyte *) 0) + pack->BufferObj->Size;
690
691   if ((const GLubyte *) start > sizeAddr) {
692      /* This will catch negative values / wrap-around */
693      return GL_FALSE;
694   }
695   if ((const GLubyte *) end > sizeAddr) {
696      /* Image read goes beyond end of buffer */
697      return GL_FALSE;
698   }
699
700   /* OK! */
701   return GL_TRUE;
702}
703
704
705/**
706 * For commands that read from a PBO (glDrawPixels, glTexImage,
707 * glPolygonStipple, etc), if we're reading from a PBO, map it read-only
708 * and return the pointer into the PBO.  If we're not reading from a
709 * PBO, return \p src as-is.
710 * If non-null return, must call _mesa_unmap_pbo_source() when done.
711 *
712 * \return NULL if error, else pointer to start of data
713 */
714const GLvoid *
715_mesa_map_pbo_source(GLcontext *ctx,
716                     const struct gl_pixelstore_attrib *unpack,
717                     const GLvoid *src)
718{
719   const GLubyte *buf;
720
721   if (_mesa_is_bufferobj(unpack->BufferObj)) {
722      /* unpack from PBO */
723      buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
724                                              GL_READ_ONLY_ARB,
725                                              unpack->BufferObj);
726      if (!buf)
727         return NULL;
728
729      buf = ADD_POINTERS(buf, src);
730   }
731   else {
732      /* unpack from normal memory */
733      buf = src;
734   }
735
736   return buf;
737}
738
739
740/**
741 * Combine PBO-read validation and mapping.
742 * If any GL errors are detected, they'll be recorded and NULL returned.
743 * \sa _mesa_validate_pbo_access
744 * \sa _mesa_map_pbo_source
745 * A call to this function should have a matching call to
746 * _mesa_unmap_pbo_source().
747 */
748const GLvoid *
749_mesa_map_validate_pbo_source(GLcontext *ctx,
750                              GLuint dimensions,
751                              const struct gl_pixelstore_attrib *unpack,
752                              GLsizei width, GLsizei height, GLsizei depth,
753                              GLenum format, GLenum type, const GLvoid *ptr,
754                              const char *where)
755{
756   ASSERT(dimensions == 1 || dimensions == 2 || dimensions == 3);
757
758   if (!_mesa_is_bufferobj(unpack->BufferObj)) {
759      /* non-PBO access: no validation to be done */
760      return ptr;
761   }
762
763   if (!_mesa_validate_pbo_access(dimensions, unpack,
764                                  width, height, depth, format, type, ptr)) {
765      _mesa_error(ctx, GL_INVALID_OPERATION,
766                  "%s(out of bounds PBO access)", where);
767      return NULL;
768   }
769
770   if (_mesa_bufferobj_mapped(unpack->BufferObj)) {
771      /* buffer is already mapped - that's an error */
772      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(PBO is mapped)", where);
773      return NULL;
774   }
775
776   ptr = _mesa_map_pbo_source(ctx, unpack, ptr);
777   return ptr;
778}
779
780
781/**
782 * Counterpart to _mesa_map_pbo_source()
783 */
784void
785_mesa_unmap_pbo_source(GLcontext *ctx,
786                       const struct gl_pixelstore_attrib *unpack)
787{
788   ASSERT(unpack != &ctx->Pack); /* catch pack/unpack mismatch */
789   if (_mesa_is_bufferobj(unpack->BufferObj)) {
790      ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
791                              unpack->BufferObj);
792   }
793}
794
795
796/**
797 * For commands that write to a PBO (glReadPixels, glGetColorTable, etc),
798 * if we're writing to a PBO, map it write-only and return the pointer
799 * into the PBO.  If we're not writing to a PBO, return \p dst as-is.
800 * If non-null return, must call _mesa_unmap_pbo_dest() when done.
801 *
802 * \return NULL if error, else pointer to start of data
803 */
804void *
805_mesa_map_pbo_dest(GLcontext *ctx,
806                   const struct gl_pixelstore_attrib *pack,
807                   GLvoid *dest)
808{
809   void *buf;
810
811   if (_mesa_is_bufferobj(pack->BufferObj)) {
812      /* pack into PBO */
813      buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT,
814                                              GL_WRITE_ONLY_ARB,
815                                              pack->BufferObj);
816      if (!buf)
817         return NULL;
818
819      buf = ADD_POINTERS(buf, dest);
820   }
821   else {
822      /* pack to normal memory */
823      buf = dest;
824   }
825
826   return buf;
827}
828
829
830/**
831 * Combine PBO-write validation and mapping.
832 * If any GL errors are detected, they'll be recorded and NULL returned.
833 * \sa _mesa_validate_pbo_access
834 * \sa _mesa_map_pbo_dest
835 * A call to this function should have a matching call to
836 * _mesa_unmap_pbo_dest().
837 */
838GLvoid *
839_mesa_map_validate_pbo_dest(GLcontext *ctx,
840                            GLuint dimensions,
841                            const struct gl_pixelstore_attrib *unpack,
842                            GLsizei width, GLsizei height, GLsizei depth,
843                            GLenum format, GLenum type, GLvoid *ptr,
844                            const char *where)
845{
846   ASSERT(dimensions == 1 || dimensions == 2 || dimensions == 3);
847
848   if (!_mesa_is_bufferobj(unpack->BufferObj)) {
849      /* non-PBO access: no validation to be done */
850      return ptr;
851   }
852
853   if (!_mesa_validate_pbo_access(dimensions, unpack,
854                                  width, height, depth, format, type, ptr)) {
855      _mesa_error(ctx, GL_INVALID_OPERATION,
856                  "%s(out of bounds PBO access)", where);
857      return NULL;
858   }
859
860   if (_mesa_bufferobj_mapped(unpack->BufferObj)) {
861      /* buffer is already mapped - that's an error */
862      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(PBO is mapped)", where);
863      return NULL;
864   }
865
866   ptr = _mesa_map_pbo_dest(ctx, unpack, ptr);
867   return ptr;
868}
869
870
871/**
872 * Counterpart to _mesa_map_pbo_dest()
873 */
874void
875_mesa_unmap_pbo_dest(GLcontext *ctx,
876                     const struct gl_pixelstore_attrib *pack)
877{
878   ASSERT(pack != &ctx->Unpack); /* catch pack/unpack mismatch */
879   if (_mesa_is_bufferobj(pack->BufferObj)) {
880      ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT, pack->BufferObj);
881   }
882}
883
884
885
886/**
887 * Return the gl_buffer_object for the given ID.
888 * Always return NULL for ID 0.
889 */
890struct gl_buffer_object *
891_mesa_lookup_bufferobj(GLcontext *ctx, GLuint buffer)
892{
893   if (buffer == 0)
894      return NULL;
895   else
896      return (struct gl_buffer_object *)
897         _mesa_HashLookup(ctx->Shared->BufferObjects, buffer);
898}
899
900
901/**
902 * If *ptr points to obj, set ptr = the Null/default buffer object.
903 * This is a helper for buffer object deletion.
904 * The GL spec says that deleting a buffer object causes it to get
905 * unbound from all arrays in the current context.
906 */
907static void
908unbind(GLcontext *ctx,
909       struct gl_buffer_object **ptr,
910       struct gl_buffer_object *obj)
911{
912   if (*ptr == obj) {
913      _mesa_reference_buffer_object(ctx, ptr, ctx->Shared->NullBufferObj);
914   }
915}
916
917
918/**
919 * Plug default/fallback buffer object functions into the device
920 * driver hooks.
921 */
922void
923_mesa_init_buffer_object_functions(struct dd_function_table *driver)
924{
925   /* GL_ARB_vertex/pixel_buffer_object */
926   driver->NewBufferObject = _mesa_new_buffer_object;
927   driver->DeleteBuffer = _mesa_delete_buffer_object;
928   driver->BindBuffer = NULL;
929   driver->BufferData = _mesa_buffer_data;
930   driver->BufferSubData = _mesa_buffer_subdata;
931   driver->GetBufferSubData = _mesa_buffer_get_subdata;
932   driver->MapBuffer = _mesa_buffer_map;
933   driver->UnmapBuffer = _mesa_buffer_unmap;
934
935   /* GL_ARB_map_buffer_range */
936   driver->MapBufferRange = _mesa_buffer_map_range;
937   driver->FlushMappedBufferRange = _mesa_buffer_flush_mapped_range;
938
939   /* GL_ARB_copy_buffer */
940   driver->CopyBufferSubData = _mesa_copy_buffer_subdata;
941}
942
943
944
945/**********************************************************************/
946/* API Functions                                                      */
947/**********************************************************************/
948
949void GLAPIENTRY
950_mesa_BindBufferARB(GLenum target, GLuint buffer)
951{
952   GET_CURRENT_CONTEXT(ctx);
953   ASSERT_OUTSIDE_BEGIN_END(ctx);
954
955   bind_buffer_object(ctx, target, buffer);
956}
957
958
959/**
960 * Delete a set of buffer objects.
961 *
962 * \param n      Number of buffer objects to delete.
963 * \param ids    Array of \c n buffer object IDs.
964 */
965void GLAPIENTRY
966_mesa_DeleteBuffersARB(GLsizei n, const GLuint *ids)
967{
968   GET_CURRENT_CONTEXT(ctx);
969   GLsizei i;
970   ASSERT_OUTSIDE_BEGIN_END(ctx);
971
972   if (n < 0) {
973      _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteBuffersARB(n)");
974      return;
975   }
976
977   _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
978
979   for (i = 0; i < n; i++) {
980      struct gl_buffer_object *bufObj = _mesa_lookup_bufferobj(ctx, ids[i]);
981      if (bufObj) {
982         struct gl_array_object *arrayObj = ctx->Array.ArrayObj;
983         GLuint j;
984
985         ASSERT(bufObj->Name == ids[i]);
986
987         if (_mesa_bufferobj_mapped(bufObj)) {
988            /* if mapped, unmap it now */
989            ctx->Driver.UnmapBuffer(ctx, 0, bufObj);
990            bufObj->AccessFlags = DEFAULT_ACCESS;
991            bufObj->Pointer = NULL;
992         }
993
994         /* unbind any vertex pointers bound to this buffer */
995         unbind(ctx, &arrayObj->Vertex.BufferObj, bufObj);
996         unbind(ctx, &arrayObj->Weight.BufferObj, bufObj);
997         unbind(ctx, &arrayObj->Normal.BufferObj, bufObj);
998         unbind(ctx, &arrayObj->Color.BufferObj, bufObj);
999         unbind(ctx, &arrayObj->SecondaryColor.BufferObj, bufObj);
1000         unbind(ctx, &arrayObj->FogCoord.BufferObj, bufObj);
1001         unbind(ctx, &arrayObj->Index.BufferObj, bufObj);
1002         unbind(ctx, &arrayObj->EdgeFlag.BufferObj, bufObj);
1003         for (j = 0; j < Elements(arrayObj->TexCoord); j++) {
1004            unbind(ctx, &arrayObj->TexCoord[j].BufferObj, bufObj);
1005         }
1006         for (j = 0; j < Elements(arrayObj->VertexAttrib); j++) {
1007            unbind(ctx, &arrayObj->VertexAttrib[j].BufferObj, bufObj);
1008         }
1009
1010         if (ctx->Array.ArrayBufferObj == bufObj) {
1011            _mesa_BindBufferARB( GL_ARRAY_BUFFER_ARB, 0 );
1012         }
1013         if (ctx->Array.ElementArrayBufferObj == bufObj) {
1014            _mesa_BindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, 0 );
1015         }
1016
1017         /* unbind any pixel pack/unpack pointers bound to this buffer */
1018         if (ctx->Pack.BufferObj == bufObj) {
1019            _mesa_BindBufferARB( GL_PIXEL_PACK_BUFFER_EXT, 0 );
1020         }
1021         if (ctx->Unpack.BufferObj == bufObj) {
1022            _mesa_BindBufferARB( GL_PIXEL_UNPACK_BUFFER_EXT, 0 );
1023         }
1024
1025         /* The ID is immediately freed for re-use */
1026         _mesa_HashRemove(ctx->Shared->BufferObjects, bufObj->Name);
1027         _mesa_reference_buffer_object(ctx, &bufObj, NULL);
1028      }
1029   }
1030
1031   _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
1032}
1033
1034
1035/**
1036 * Generate a set of unique buffer object IDs and store them in \c buffer.
1037 *
1038 * \param n       Number of IDs to generate.
1039 * \param buffer  Array of \c n locations to store the IDs.
1040 */
1041void GLAPIENTRY
1042_mesa_GenBuffersARB(GLsizei n, GLuint *buffer)
1043{
1044   GET_CURRENT_CONTEXT(ctx);
1045   GLuint first;
1046   GLint i;
1047   ASSERT_OUTSIDE_BEGIN_END(ctx);
1048
1049   if (n < 0) {
1050      _mesa_error(ctx, GL_INVALID_VALUE, "glGenBuffersARB");
1051      return;
1052   }
1053
1054   if (!buffer) {
1055      return;
1056   }
1057
1058   /*
1059    * This must be atomic (generation and allocation of buffer object IDs)
1060    */
1061   _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
1062
1063   first = _mesa_HashFindFreeKeyBlock(ctx->Shared->BufferObjects, n);
1064
1065   /* Allocate new, empty buffer objects and return identifiers */
1066   for (i = 0; i < n; i++) {
1067      struct gl_buffer_object *bufObj;
1068      GLuint name = first + i;
1069      GLenum target = 0;
1070      bufObj = ctx->Driver.NewBufferObject( ctx, name, target );
1071      if (!bufObj) {
1072         _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
1073         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenBuffersARB");
1074         return;
1075      }
1076      _mesa_HashInsert(ctx->Shared->BufferObjects, first + i, bufObj);
1077      buffer[i] = first + i;
1078   }
1079
1080   _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
1081}
1082
1083
1084/**
1085 * Determine if ID is the name of a buffer object.
1086 *
1087 * \param id  ID of the potential buffer object.
1088 * \return  \c GL_TRUE if \c id is the name of a buffer object,
1089 *          \c GL_FALSE otherwise.
1090 */
1091GLboolean GLAPIENTRY
1092_mesa_IsBufferARB(GLuint id)
1093{
1094   struct gl_buffer_object *bufObj;
1095   GET_CURRENT_CONTEXT(ctx);
1096   ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
1097
1098   _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
1099   bufObj = _mesa_lookup_bufferobj(ctx, id);
1100   _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
1101
1102   return bufObj ? GL_TRUE : GL_FALSE;
1103}
1104
1105
1106void GLAPIENTRY
1107_mesa_BufferDataARB(GLenum target, GLsizeiptrARB size,
1108                    const GLvoid * data, GLenum usage)
1109{
1110   GET_CURRENT_CONTEXT(ctx);
1111   struct gl_buffer_object *bufObj;
1112   ASSERT_OUTSIDE_BEGIN_END(ctx);
1113
1114   if (size < 0) {
1115      _mesa_error(ctx, GL_INVALID_VALUE, "glBufferDataARB(size < 0)");
1116      return;
1117   }
1118
1119   switch (usage) {
1120      case GL_STREAM_DRAW_ARB:
1121      case GL_STREAM_READ_ARB:
1122      case GL_STREAM_COPY_ARB:
1123      case GL_STATIC_DRAW_ARB:
1124      case GL_STATIC_READ_ARB:
1125      case GL_STATIC_COPY_ARB:
1126      case GL_DYNAMIC_DRAW_ARB:
1127      case GL_DYNAMIC_READ_ARB:
1128      case GL_DYNAMIC_COPY_ARB:
1129         /* OK */
1130         break;
1131      default:
1132         _mesa_error(ctx, GL_INVALID_ENUM, "glBufferDataARB(usage)");
1133         return;
1134   }
1135
1136   bufObj = get_buffer(ctx, target);
1137   if (!bufObj) {
1138      _mesa_error(ctx, GL_INVALID_ENUM, "glBufferDataARB(target)" );
1139      return;
1140   }
1141   if (!_mesa_is_bufferobj(bufObj)) {
1142      _mesa_error(ctx, GL_INVALID_OPERATION, "glBufferDataARB(buffer 0)" );
1143      return;
1144   }
1145
1146   if (_mesa_bufferobj_mapped(bufObj)) {
1147      /* Unmap the existing buffer.  We'll replace it now.  Not an error. */
1148      ctx->Driver.UnmapBuffer(ctx, target, bufObj);
1149      bufObj->AccessFlags = DEFAULT_ACCESS;
1150      ASSERT(bufObj->Pointer == NULL);
1151   }
1152
1153   FLUSH_VERTICES(ctx, _NEW_BUFFER_OBJECT);
1154
1155   bufObj->Written = GL_TRUE;
1156
1157#ifdef VBO_DEBUG
1158   _mesa_printf("glBufferDataARB(%u, sz %ld, from %p, usage 0x%x)\n",
1159                bufObj->Name, size, data, usage);
1160#endif
1161
1162#ifdef BOUNDS_CHECK
1163   size += 100;
1164#endif
1165
1166   ASSERT(ctx->Driver.BufferData);
1167   if (!ctx->Driver.BufferData( ctx, target, size, data, usage, bufObj )) {
1168      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBufferDataARB()");
1169   }
1170}
1171
1172
1173void GLAPIENTRY
1174_mesa_BufferSubDataARB(GLenum target, GLintptrARB offset,
1175                       GLsizeiptrARB size, const GLvoid * data)
1176{
1177   GET_CURRENT_CONTEXT(ctx);
1178   struct gl_buffer_object *bufObj;
1179   ASSERT_OUTSIDE_BEGIN_END(ctx);
1180
1181   bufObj = buffer_object_subdata_range_good( ctx, target, offset, size,
1182                                              "glBufferSubDataARB" );
1183   if (!bufObj) {
1184      /* error already recorded */
1185      return;
1186   }
1187
1188   bufObj->Written = GL_TRUE;
1189
1190   ASSERT(ctx->Driver.BufferSubData);
1191   ctx->Driver.BufferSubData( ctx, target, offset, size, data, bufObj );
1192}
1193
1194
1195void GLAPIENTRY
1196_mesa_GetBufferSubDataARB(GLenum target, GLintptrARB offset,
1197                          GLsizeiptrARB size, void * data)
1198{
1199   GET_CURRENT_CONTEXT(ctx);
1200   struct gl_buffer_object *bufObj;
1201   ASSERT_OUTSIDE_BEGIN_END(ctx);
1202
1203   bufObj = buffer_object_subdata_range_good( ctx, target, offset, size,
1204                                              "glGetBufferSubDataARB" );
1205   if (!bufObj) {
1206      /* error already recorded */
1207      return;
1208   }
1209
1210   ASSERT(ctx->Driver.GetBufferSubData);
1211   ctx->Driver.GetBufferSubData( ctx, target, offset, size, data, bufObj );
1212}
1213
1214
1215void * GLAPIENTRY
1216_mesa_MapBufferARB(GLenum target, GLenum access)
1217{
1218   GET_CURRENT_CONTEXT(ctx);
1219   struct gl_buffer_object * bufObj;
1220   GLbitfield accessFlags;
1221   void *map;
1222
1223   ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, NULL);
1224
1225   switch (access) {
1226      case GL_READ_ONLY_ARB:
1227         accessFlags = GL_MAP_READ_BIT;
1228         break;
1229      case GL_WRITE_ONLY_ARB:
1230         accessFlags = GL_MAP_WRITE_BIT;
1231         break;
1232      case GL_READ_WRITE_ARB:
1233         accessFlags = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT;
1234         break;
1235      default:
1236         _mesa_error(ctx, GL_INVALID_ENUM, "glMapBufferARB(access)");
1237         return NULL;
1238   }
1239
1240   bufObj = get_buffer(ctx, target);
1241   if (!bufObj) {
1242      _mesa_error(ctx, GL_INVALID_ENUM, "glMapBufferARB(target)" );
1243      return NULL;
1244   }
1245   if (!_mesa_is_bufferobj(bufObj)) {
1246      _mesa_error(ctx, GL_INVALID_OPERATION, "glMapBufferARB(buffer 0)" );
1247      return NULL;
1248   }
1249   if (_mesa_bufferobj_mapped(bufObj)) {
1250      _mesa_error(ctx, GL_INVALID_OPERATION, "glMapBufferARB(already mapped)");
1251      return NULL;
1252   }
1253
1254   ASSERT(ctx->Driver.MapBuffer);
1255   map = ctx->Driver.MapBuffer( ctx, target, access, bufObj );
1256   if (!map) {
1257      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glMapBufferARB(map failed)");
1258      return NULL;
1259   }
1260   else {
1261      /* The driver callback should have set these fields.
1262       * This is important because other modules (like VBO) might call
1263       * the driver function directly.
1264       */
1265      ASSERT(bufObj->Pointer == map);
1266      ASSERT(bufObj->Length == bufObj->Size);
1267      ASSERT(bufObj->Offset == 0);
1268      bufObj->AccessFlags = accessFlags;
1269   }
1270
1271   if (access == GL_WRITE_ONLY_ARB || access == GL_READ_WRITE_ARB)
1272      bufObj->Written = GL_TRUE;
1273
1274#ifdef VBO_DEBUG
1275   _mesa_printf("glMapBufferARB(%u, sz %ld, access 0x%x)\n",
1276                bufObj->Name, bufObj->Size, access);
1277   if (access == GL_WRITE_ONLY_ARB) {
1278      GLuint i;
1279      GLubyte *b = (GLubyte *) bufObj->Pointer;
1280      for (i = 0; i < bufObj->Size; i++)
1281         b[i] = i & 0xff;
1282   }
1283#endif
1284
1285#ifdef BOUNDS_CHECK
1286   {
1287      GLubyte *buf = (GLubyte *) bufObj->Pointer;
1288      GLuint i;
1289      /* buffer is 100 bytes larger than requested, fill with magic value */
1290      for (i = 0; i < 100; i++) {
1291         buf[bufObj->Size - i - 1] = 123;
1292      }
1293   }
1294#endif
1295
1296   return bufObj->Pointer;
1297}
1298
1299
1300GLboolean GLAPIENTRY
1301_mesa_UnmapBufferARB(GLenum target)
1302{
1303   GET_CURRENT_CONTEXT(ctx);
1304   struct gl_buffer_object *bufObj;
1305   GLboolean status = GL_TRUE;
1306   ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
1307
1308   bufObj = get_buffer(ctx, target);
1309   if (!bufObj) {
1310      _mesa_error(ctx, GL_INVALID_ENUM, "glUnmapBufferARB(target)" );
1311      return GL_FALSE;
1312   }
1313   if (!_mesa_is_bufferobj(bufObj)) {
1314      _mesa_error(ctx, GL_INVALID_OPERATION, "glUnmapBufferARB" );
1315      return GL_FALSE;
1316   }
1317   if (!_mesa_bufferobj_mapped(bufObj)) {
1318      _mesa_error(ctx, GL_INVALID_OPERATION, "glUnmapBufferARB");
1319      return GL_FALSE;
1320   }
1321
1322#ifdef BOUNDS_CHECK
1323   if (bufObj->Access != GL_READ_ONLY_ARB) {
1324      GLubyte *buf = (GLubyte *) bufObj->Pointer;
1325      GLuint i;
1326      /* check that last 100 bytes are still = magic value */
1327      for (i = 0; i < 100; i++) {
1328         GLuint pos = bufObj->Size - i - 1;
1329         if (buf[pos] != 123) {
1330            _mesa_warning(ctx, "Out of bounds buffer object write detected"
1331                          " at position %d (value = %u)\n",
1332                          pos, buf[pos]);
1333         }
1334      }
1335   }
1336#endif
1337
1338#ifdef VBO_DEBUG
1339   if (bufObj->AccessFlags & GL_MAP_WRITE_BIT) {
1340      GLuint i, unchanged = 0;
1341      GLubyte *b = (GLubyte *) bufObj->Pointer;
1342      GLint pos = -1;
1343      /* check which bytes changed */
1344      for (i = 0; i < bufObj->Size - 1; i++) {
1345         if (b[i] == (i & 0xff) && b[i+1] == ((i+1) & 0xff)) {
1346            unchanged++;
1347            if (pos == -1)
1348               pos = i;
1349         }
1350      }
1351      if (unchanged) {
1352         _mesa_printf("glUnmapBufferARB(%u): %u of %ld unchanged, starting at %d\n",
1353                      bufObj->Name, unchanged, bufObj->Size, pos);
1354      }
1355   }
1356#endif
1357
1358   status = ctx->Driver.UnmapBuffer( ctx, target, bufObj );
1359   bufObj->AccessFlags = DEFAULT_ACCESS;
1360   ASSERT(bufObj->Pointer == NULL);
1361   ASSERT(bufObj->Offset == 0);
1362   ASSERT(bufObj->Length == 0);
1363
1364   return status;
1365}
1366
1367
1368void GLAPIENTRY
1369_mesa_GetBufferParameterivARB(GLenum target, GLenum pname, GLint *params)
1370{
1371   GET_CURRENT_CONTEXT(ctx);
1372   struct gl_buffer_object *bufObj;
1373   ASSERT_OUTSIDE_BEGIN_END(ctx);
1374
1375   bufObj = get_buffer(ctx, target);
1376   if (!bufObj) {
1377      _mesa_error(ctx, GL_INVALID_ENUM, "GetBufferParameterivARB(target)" );
1378      return;
1379   }
1380   if (!_mesa_is_bufferobj(bufObj)) {
1381      _mesa_error(ctx, GL_INVALID_OPERATION, "GetBufferParameterivARB" );
1382      return;
1383   }
1384
1385   switch (pname) {
1386      case GL_BUFFER_SIZE_ARB:
1387         *params = (GLint) bufObj->Size;
1388         break;
1389      case GL_BUFFER_USAGE_ARB:
1390         *params = bufObj->Usage;
1391         break;
1392      case GL_BUFFER_ACCESS_ARB:
1393         *params = simplified_access_mode(bufObj->AccessFlags);
1394         break;
1395      case GL_BUFFER_MAPPED_ARB:
1396         *params = _mesa_bufferobj_mapped(bufObj);
1397         break;
1398      default:
1399         _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferParameterivARB(pname)");
1400         return;
1401   }
1402}
1403
1404
1405void GLAPIENTRY
1406_mesa_GetBufferPointervARB(GLenum target, GLenum pname, GLvoid **params)
1407{
1408   GET_CURRENT_CONTEXT(ctx);
1409   struct gl_buffer_object * bufObj;
1410   ASSERT_OUTSIDE_BEGIN_END(ctx);
1411
1412   if (pname != GL_BUFFER_MAP_POINTER_ARB) {
1413      _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferPointervARB(pname)");
1414      return;
1415   }
1416
1417   bufObj = get_buffer(ctx, target);
1418   if (!bufObj) {
1419      _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferPointervARB(target)" );
1420      return;
1421   }
1422   if (!_mesa_is_bufferobj(bufObj)) {
1423      _mesa_error(ctx, GL_INVALID_OPERATION, "glGetBufferPointervARB" );
1424      return;
1425   }
1426
1427   *params = bufObj->Pointer;
1428}
1429
1430
1431void GLAPIENTRY
1432_mesa_CopyBufferSubData(GLenum readTarget, GLenum writeTarget,
1433                        GLintptr readOffset, GLintptr writeOffset,
1434                        GLsizeiptr size)
1435{
1436   GET_CURRENT_CONTEXT(ctx);
1437   struct gl_buffer_object *src, *dst;
1438   ASSERT_OUTSIDE_BEGIN_END(ctx);
1439
1440   src = get_buffer(ctx, readTarget);
1441   if (!src || !_mesa_is_bufferobj(src)) {
1442      _mesa_error(ctx, GL_INVALID_ENUM,
1443                  "glCopyBuffserSubData(readTarget = 0x%x)", readTarget);
1444      return;
1445   }
1446
1447   dst = get_buffer(ctx, writeTarget);
1448   if (!dst || !_mesa_is_bufferobj(dst)) {
1449      _mesa_error(ctx, GL_INVALID_ENUM,
1450                  "glCopyBuffserSubData(writeTarget = 0x%x)", writeTarget);
1451      return;
1452   }
1453
1454   if (_mesa_bufferobj_mapped(src)) {
1455      _mesa_error(ctx, GL_INVALID_OPERATION,
1456                  "glCopyBuffserSubData(readBuffer is mapped)");
1457      return;
1458   }
1459
1460   if (_mesa_bufferobj_mapped(dst)) {
1461      _mesa_error(ctx, GL_INVALID_OPERATION,
1462                  "glCopyBuffserSubData(writeBuffer is mapped)");
1463      return;
1464   }
1465
1466   if (readOffset < 0) {
1467      _mesa_error(ctx, GL_INVALID_VALUE,
1468                  "glCopyBuffserSubData(readOffset = %d)", readOffset);
1469      return;
1470   }
1471
1472   if (writeOffset < 0) {
1473      _mesa_error(ctx, GL_INVALID_VALUE,
1474                  "glCopyBuffserSubData(writeOffset = %d)", writeOffset);
1475      return;
1476   }
1477
1478   if (readOffset + size > src->Size) {
1479      _mesa_error(ctx, GL_INVALID_VALUE,
1480                  "glCopyBuffserSubData(readOffset + size = %d)",
1481                  readOffset, size);
1482      return;
1483   }
1484
1485   if (writeOffset + size > dst->Size) {
1486      _mesa_error(ctx, GL_INVALID_VALUE,
1487                  "glCopyBuffserSubData(writeOffset + size = %d)",
1488                  writeOffset, size);
1489      return;
1490   }
1491
1492   if (src == dst) {
1493      if (readOffset + size <= writeOffset) {
1494         /* OK */
1495      }
1496      else if (writeOffset + size <= readOffset) {
1497         /* OK */
1498      }
1499      else {
1500         /* overlapping src/dst is illegal */
1501         _mesa_error(ctx, GL_INVALID_VALUE,
1502                     "glCopyBuffserSubData(overlapping src/dst)");
1503         return;
1504      }
1505   }
1506
1507   ctx->Driver.CopyBufferSubData(ctx, src, dst, readOffset, writeOffset, size);
1508}
1509
1510
1511/**
1512 * See GL_ARB_map_buffer_range spec
1513 */
1514void * GLAPIENTRY
1515_mesa_MapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length,
1516                     GLbitfield access)
1517{
1518   GET_CURRENT_CONTEXT(ctx);
1519   struct gl_buffer_object *bufObj;
1520   void *map;
1521
1522   ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, NULL);
1523
1524   if (!ctx->Extensions.ARB_map_buffer_range) {
1525      _mesa_error(ctx, GL_INVALID_OPERATION,
1526                  "glMapBufferRange(extension not supported)");
1527      return NULL;
1528   }
1529
1530   if (offset < 0) {
1531      _mesa_error(ctx, GL_INVALID_VALUE,
1532                  "glMapBufferRange(offset = %ld)", offset);
1533      return NULL;
1534   }
1535
1536   if (length < 0) {
1537      _mesa_error(ctx, GL_INVALID_VALUE,
1538                  "glMapBufferRange(length = %ld)", length);
1539      return NULL;
1540   }
1541
1542   if ((access & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)) == 0) {
1543      _mesa_error(ctx, GL_INVALID_OPERATION,
1544                  "glMapBufferRange(access indicates neither read or write)");
1545      return NULL;
1546   }
1547
1548   if (access & GL_MAP_READ_BIT) {
1549      if ((access & GL_MAP_INVALIDATE_RANGE_BIT) ||
1550          (access & GL_MAP_INVALIDATE_BUFFER_BIT) ||
1551          (access & GL_MAP_UNSYNCHRONIZED_BIT)) {
1552         _mesa_error(ctx, GL_INVALID_OPERATION,
1553                     "glMapBufferRange(invalid access flags)");
1554         return NULL;
1555      }
1556   }
1557
1558   if ((access & GL_MAP_FLUSH_EXPLICIT_BIT) &&
1559       ((access & GL_MAP_WRITE_BIT) == 0)) {
1560      _mesa_error(ctx, GL_INVALID_OPERATION,
1561                  "glMapBufferRange(invalid access flags)");
1562      return NULL;
1563   }
1564
1565   bufObj = get_buffer(ctx, target);
1566   if (!bufObj || !_mesa_is_bufferobj(bufObj)) {
1567      _mesa_error(ctx, GL_INVALID_ENUM,
1568                  "glMapBufferRange(target = 0x%x)", target);
1569      return NULL;
1570   }
1571
1572   if (offset + length > bufObj->Size) {
1573      _mesa_error(ctx, GL_INVALID_VALUE,
1574                  "glMapBufferRange(offset + length > size)");
1575      return NULL;
1576   }
1577
1578   if (_mesa_bufferobj_mapped(bufObj)) {
1579      _mesa_error(ctx, GL_INVALID_OPERATION,
1580                  "glMapBufferRange(buffer already mapped)");
1581      return NULL;
1582   }
1583
1584   ASSERT(ctx->Driver.MapBufferRange);
1585   map = ctx->Driver.MapBufferRange(ctx, target, offset, length,
1586                                    access, bufObj);
1587   if (!map) {
1588      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glMapBufferARB(map failed)");
1589   }
1590   else {
1591      /* The driver callback should have set all these fields.
1592       * This is important because other modules (like VBO) might call
1593       * the driver function directly.
1594       */
1595      ASSERT(bufObj->Pointer == map);
1596      ASSERT(bufObj->Length == length);
1597      ASSERT(bufObj->Offset == offset);
1598      ASSERT(bufObj->AccessFlags == access);
1599   }
1600
1601   return map;
1602}
1603
1604
1605/**
1606 * See GL_ARB_map_buffer_range spec
1607 */
1608void GLAPIENTRY
1609_mesa_FlushMappedBufferRange(GLenum target, GLintptr offset, GLsizeiptr length)
1610{
1611   GET_CURRENT_CONTEXT(ctx);
1612   struct gl_buffer_object *bufObj;
1613   ASSERT_OUTSIDE_BEGIN_END(ctx);
1614
1615   if (!ctx->Extensions.ARB_map_buffer_range) {
1616      _mesa_error(ctx, GL_INVALID_OPERATION,
1617                  "glMapBufferRange(extension not supported)");
1618      return;
1619   }
1620
1621   if (offset < 0) {
1622      _mesa_error(ctx, GL_INVALID_VALUE,
1623                  "glMapBufferRange(offset = %ld)", offset);
1624      return;
1625   }
1626
1627   if (length < 0) {
1628      _mesa_error(ctx, GL_INVALID_VALUE,
1629                  "glMapBufferRange(length = %ld)", length);
1630      return;
1631   }
1632
1633   bufObj = get_buffer(ctx, target);
1634   if (!bufObj) {
1635      _mesa_error(ctx, GL_INVALID_ENUM,
1636                  "glMapBufferRange(target = 0x%x)", target);
1637      return;
1638   }
1639
1640   if (!_mesa_is_bufferobj(bufObj)) {
1641      _mesa_error(ctx, GL_INVALID_OPERATION,
1642                  "glMapBufferRange(current buffer is 0)");
1643      return;
1644   }
1645
1646   if (!_mesa_bufferobj_mapped(bufObj)) {
1647      /* buffer is not mapped */
1648      _mesa_error(ctx, GL_INVALID_OPERATION,
1649                  "glMapBufferRange(buffer is not mapped)");
1650      return;
1651   }
1652
1653   if ((bufObj->AccessFlags & GL_MAP_FLUSH_EXPLICIT_BIT) == 0) {
1654      _mesa_error(ctx, GL_INVALID_OPERATION,
1655                  "glMapBufferRange(GL_MAP_FLUSH_EXPLICIT_BIT not set)");
1656      return;
1657   }
1658
1659   if (offset + length > bufObj->Length) {
1660      _mesa_error(ctx, GL_INVALID_VALUE,
1661             "glMapBufferRange(offset %ld + length %ld > mapped length %ld)",
1662             offset, length, bufObj->Length);
1663      return;
1664   }
1665
1666   ASSERT(bufObj->AccessFlags & GL_MAP_WRITE_BIT);
1667
1668   if (ctx->Driver.FlushMappedBufferRange)
1669      ctx->Driver.FlushMappedBufferRange(ctx, target, offset, length, bufObj);
1670}
1671