Tizen 2.0 Release
[profile/ivi/osmesa.git] / src / mesa / main / bufferobj.c
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 "enums.h"
36 #include "hash.h"
37 #include "imports.h"
38 #include "image.h"
39 #include "context.h"
40 #include "bufferobj.h"
41 #include "fbobject.h"
42 #include "mfeatures.h"
43 #include "mtypes.h"
44 #include "texobj.h"
45
46
47 /* Debug flags */
48 /*#define VBO_DEBUG*/
49 /*#define BOUNDS_CHECK*/
50
51
52 #if FEATURE_OES_mapbuffer
53 #define DEFAULT_ACCESS GL_MAP_WRITE_BIT
54 #else
55 #define DEFAULT_ACCESS (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)
56 #endif
57
58
59 /**
60  * Used as a placeholder for buffer objects between glGenBuffers() and
61  * glBindBuffer() so that glIsBuffer() can work correctly.
62  */
63 static struct gl_buffer_object DummyBufferObject;
64
65
66 /**
67  * Return pointer to address of a buffer object target.
68  * \param ctx  the GL context
69  * \param target  the buffer object target to be retrieved.
70  * \return   pointer to pointer to the buffer object bound to \c target in the
71  *           specified context or \c NULL if \c target is invalid.
72  */
73 static INLINE struct gl_buffer_object **
74 get_buffer_target(struct gl_context *ctx, GLenum target)
75 {
76    switch (target) {
77    case GL_ARRAY_BUFFER_ARB:
78       return &ctx->Array.ArrayBufferObj;
79    case GL_ELEMENT_ARRAY_BUFFER_ARB:
80       return &ctx->Array.ElementArrayBufferObj;
81    case GL_PIXEL_PACK_BUFFER_EXT:
82       return &ctx->Pack.BufferObj;
83    case GL_PIXEL_UNPACK_BUFFER_EXT:
84       return &ctx->Unpack.BufferObj;
85    case GL_COPY_READ_BUFFER:
86       return &ctx->CopyReadBuffer;
87    case GL_COPY_WRITE_BUFFER:
88       return &ctx->CopyWriteBuffer;
89 #if FEATURE_EXT_transform_feedback
90    case GL_TRANSFORM_FEEDBACK_BUFFER:
91       if (ctx->Extensions.EXT_transform_feedback) {
92          return &ctx->TransformFeedback.CurrentBuffer;
93       }
94       break;
95 #endif
96    case GL_TEXTURE_BUFFER:
97       if (ctx->Extensions.ARB_texture_buffer_object) {
98          return &ctx->Texture.BufferObject;
99       }
100       break;
101    default:
102       return NULL;
103    }
104    return NULL;
105 }
106
107
108 /**
109  * Get the buffer object bound to the specified target in a GL context.
110  * \param ctx  the GL context
111  * \param target  the buffer object target to be retrieved.
112  * \return   pointer to the buffer object bound to \c target in the
113  *           specified context or \c NULL if \c target is invalid.
114  */
115 static INLINE struct gl_buffer_object *
116 get_buffer(struct gl_context *ctx, GLenum target)
117 {
118    struct gl_buffer_object **bufObj = get_buffer_target(ctx, target);
119    if (bufObj)
120       return *bufObj;
121    return NULL;
122 }
123
124
125 /**
126  * Convert a GLbitfield describing the mapped buffer access flags
127  * into one of GL_READ_WRITE, GL_READ_ONLY, or GL_WRITE_ONLY.
128  */
129 static GLenum
130 simplified_access_mode(GLbitfield access)
131 {
132    const GLbitfield rwFlags = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT;
133    if ((access & rwFlags) == rwFlags)
134       return GL_READ_WRITE;
135    if ((access & GL_MAP_READ_BIT) == GL_MAP_READ_BIT)
136       return GL_READ_ONLY;
137    if ((access & GL_MAP_WRITE_BIT) == GL_MAP_WRITE_BIT)
138       return GL_WRITE_ONLY;
139    return GL_READ_WRITE; /* this should never happen, but no big deal */
140 }
141
142
143 /**
144  * Tests the subdata range parameters and sets the GL error code for
145  * \c glBufferSubDataARB and \c glGetBufferSubDataARB.
146  *
147  * \param ctx     GL context.
148  * \param target  Buffer object target on which to operate.
149  * \param offset  Offset of the first byte of the subdata range.
150  * \param size    Size, in bytes, of the subdata range.
151  * \param caller  Name of calling function for recording errors.
152  * \return   A pointer to the buffer object bound to \c target in the
153  *           specified context or \c NULL if any of the parameter or state
154  *           conditions for \c glBufferSubDataARB or \c glGetBufferSubDataARB
155  *           are invalid.
156  *
157  * \sa glBufferSubDataARB, glGetBufferSubDataARB
158  */
159 static struct gl_buffer_object *
160 buffer_object_subdata_range_good( struct gl_context * ctx, GLenum target, 
161                                   GLintptrARB offset, GLsizeiptrARB size,
162                                   const char *caller )
163 {
164    struct gl_buffer_object *bufObj;
165
166    if (size < 0) {
167       _mesa_error(ctx, GL_INVALID_VALUE, "%s(size < 0)", caller);
168       return NULL;
169    }
170
171    if (offset < 0) {
172       _mesa_error(ctx, GL_INVALID_VALUE, "%s(offset < 0)", caller);
173       return NULL;
174    }
175
176    bufObj = get_buffer(ctx, target);
177    if (!bufObj) {
178       _mesa_error(ctx, GL_INVALID_ENUM, "%s(target)", caller);
179       return NULL;
180    }
181    if (!_mesa_is_bufferobj(bufObj)) {
182       _mesa_error(ctx, GL_INVALID_OPERATION, "%s", caller);
183       return NULL;
184    }
185    if (offset + size > bufObj->Size) {
186       _mesa_error(ctx, GL_INVALID_VALUE,
187                   "%s(size + offset > buffer size)", caller);
188       return NULL;
189    }
190    if (_mesa_bufferobj_mapped(bufObj)) {
191       /* Buffer is currently mapped */
192       _mesa_error(ctx, GL_INVALID_OPERATION, "%s", caller);
193       return NULL;
194    }
195
196    return bufObj;
197 }
198
199
200 /**
201  * Allocate and initialize a new buffer object.
202  * 
203  * Default callback for the \c dd_function_table::NewBufferObject() hook.
204  */
205 static struct gl_buffer_object *
206 _mesa_new_buffer_object( struct gl_context *ctx, GLuint name, GLenum target )
207 {
208    struct gl_buffer_object *obj;
209
210    (void) ctx;
211
212    obj = MALLOC_STRUCT(gl_buffer_object);
213    _mesa_initialize_buffer_object(obj, name, target);
214    return obj;
215 }
216
217
218 /**
219  * Delete a buffer object.
220  * 
221  * Default callback for the \c dd_function_table::DeleteBuffer() hook.
222  */
223 static void
224 _mesa_delete_buffer_object(struct gl_context *ctx,
225                            struct gl_buffer_object *bufObj)
226 {
227    (void) ctx;
228
229    if (bufObj->Data)
230       free(bufObj->Data);
231
232    /* assign strange values here to help w/ debugging */
233    bufObj->RefCount = -1000;
234    bufObj->Name = ~0;
235
236    _glthread_DESTROY_MUTEX(bufObj->Mutex);
237    free(bufObj);
238 }
239
240
241
242 /**
243  * Set ptr to bufObj w/ reference counting.
244  */
245 void
246 _mesa_reference_buffer_object(struct gl_context *ctx,
247                               struct gl_buffer_object **ptr,
248                               struct gl_buffer_object *bufObj)
249 {
250    if (*ptr == bufObj)
251       return;
252
253    if (*ptr) {
254       /* Unreference the old buffer */
255       GLboolean deleteFlag = GL_FALSE;
256       struct gl_buffer_object *oldObj = *ptr;
257
258       _glthread_LOCK_MUTEX(oldObj->Mutex);
259       ASSERT(oldObj->RefCount > 0);
260       oldObj->RefCount--;
261 #if 0
262       printf("BufferObj %p %d DECR to %d\n",
263              (void *) oldObj, oldObj->Name, oldObj->RefCount);
264 #endif
265       deleteFlag = (oldObj->RefCount == 0);
266       _glthread_UNLOCK_MUTEX(oldObj->Mutex);
267
268       if (deleteFlag) {
269
270          /* some sanity checking: don't delete a buffer still in use */
271 #if 0
272          /* unfortunately, these tests are invalid during context tear-down */
273          ASSERT(ctx->Array.ArrayBufferObj != bufObj);
274          ASSERT(ctx->Array.ElementArrayBufferObj != bufObj);
275          ASSERT(ctx->Array.ArrayObj->Vertex.BufferObj != bufObj);
276 #endif
277
278          ASSERT(ctx->Driver.DeleteBuffer);
279          ctx->Driver.DeleteBuffer(ctx, oldObj);
280       }
281
282       *ptr = NULL;
283    }
284    ASSERT(!*ptr);
285
286    if (bufObj) {
287       /* reference new buffer */
288       _glthread_LOCK_MUTEX(bufObj->Mutex);
289       if (bufObj->RefCount == 0) {
290          /* this buffer's being deleted (look just above) */
291          /* Not sure this can every really happen.  Warn if it does. */
292          _mesa_problem(NULL, "referencing deleted buffer object");
293          *ptr = NULL;
294       }
295       else {
296          bufObj->RefCount++;
297 #if 0
298          printf("BufferObj %p %d INCR to %d\n",
299                 (void *) bufObj, bufObj->Name, bufObj->RefCount);
300 #endif
301          *ptr = bufObj;
302       }
303       _glthread_UNLOCK_MUTEX(bufObj->Mutex);
304    }
305 }
306
307
308 /**
309  * Initialize a buffer object to default values.
310  */
311 void
312 _mesa_initialize_buffer_object( struct gl_buffer_object *obj,
313                                 GLuint name, GLenum target )
314 {
315    (void) target;
316
317    memset(obj, 0, sizeof(struct gl_buffer_object));
318    _glthread_INIT_MUTEX(obj->Mutex);
319    obj->RefCount = 1;
320    obj->Name = name;
321    obj->Usage = GL_STATIC_DRAW_ARB;
322    obj->AccessFlags = DEFAULT_ACCESS;
323 }
324
325
326 /**
327  * Allocate space for and store data in a buffer object.  Any data that was
328  * previously stored in the buffer object is lost.  If \c data is \c NULL,
329  * memory will be allocated, but no copy will occur.
330  *
331  * This is the default callback for \c dd_function_table::BufferData()
332  * Note that all GL error checking will have been done already.
333  *
334  * \param ctx     GL context.
335  * \param target  Buffer object target on which to operate.
336  * \param size    Size, in bytes, of the new data store.
337  * \param data    Pointer to the data to store in the buffer object.  This
338  *                pointer may be \c NULL.
339  * \param usage   Hints about how the data will be used.
340  * \param bufObj  Object to be used.
341  *
342  * \return GL_TRUE for success, GL_FALSE for failure
343  * \sa glBufferDataARB, dd_function_table::BufferData.
344  */
345 static GLboolean
346 _mesa_buffer_data( struct gl_context *ctx, GLenum target, GLsizeiptrARB size,
347                    const GLvoid * data, GLenum usage,
348                    struct gl_buffer_object * bufObj )
349 {
350    void * new_data;
351
352    (void) ctx; (void) target;
353
354    new_data = _mesa_realloc( bufObj->Data, bufObj->Size, size );
355    if (new_data) {
356       bufObj->Data = (GLubyte *) new_data;
357       bufObj->Size = size;
358       bufObj->Usage = usage;
359
360       if (data) {
361          memcpy( bufObj->Data, data, size );
362       }
363
364       return GL_TRUE;
365    }
366    else {
367       return GL_FALSE;
368    }
369 }
370
371
372 /**
373  * Replace data in a subrange of buffer object.  If the data range
374  * specified by \c size + \c offset extends beyond the end of the buffer or
375  * if \c data is \c NULL, no copy is performed.
376  *
377  * This is the default callback for \c dd_function_table::BufferSubData()
378  * Note that all GL error checking will have been done already.
379  *
380  * \param ctx     GL context.
381  * \param target  Buffer object target on which to operate.
382  * \param offset  Offset of the first byte to be modified.
383  * \param size    Size, in bytes, of the data range.
384  * \param data    Pointer to the data to store in the buffer object.
385  * \param bufObj  Object to be used.
386  *
387  * \sa glBufferSubDataARB, dd_function_table::BufferSubData.
388  */
389 static void
390 _mesa_buffer_subdata( struct gl_context *ctx, GLenum target, GLintptrARB offset,
391                       GLsizeiptrARB size, const GLvoid * data,
392                       struct gl_buffer_object * bufObj )
393 {
394    (void) ctx; (void) target;
395
396    /* this should have been caught in _mesa_BufferSubData() */
397    ASSERT(size + offset <= bufObj->Size);
398
399    if (bufObj->Data) {
400       memcpy( (GLubyte *) bufObj->Data + offset, data, size );
401    }
402 }
403
404
405 /**
406  * Retrieve data from a subrange of buffer object.  If the data range
407  * specified by \c size + \c offset extends beyond the end of the buffer or
408  * if \c data is \c NULL, no copy is performed.
409  *
410  * This is the default callback for \c dd_function_table::GetBufferSubData()
411  * Note that all GL error checking will have been done already.
412  *
413  * \param ctx     GL context.
414  * \param target  Buffer object target on which to operate.
415  * \param offset  Offset of the first byte to be fetched.
416  * \param size    Size, in bytes, of the data range.
417  * \param data    Destination for data
418  * \param bufObj  Object to be used.
419  *
420  * \sa glBufferGetSubDataARB, dd_function_table::GetBufferSubData.
421  */
422 static void
423 _mesa_buffer_get_subdata( struct gl_context *ctx,
424                           GLenum target, GLintptrARB offset,
425                           GLsizeiptrARB size, GLvoid * data,
426                           struct gl_buffer_object * bufObj )
427 {
428    (void) ctx; (void) target;
429
430    if (bufObj->Data && ((GLsizeiptrARB) (size + offset) <= bufObj->Size)) {
431       memcpy( data, (GLubyte *) bufObj->Data + offset, size );
432    }
433 }
434
435
436 /**
437  * Default callback for \c dd_function_tabel::MapBuffer().
438  *
439  * The function parameters will have been already tested for errors.
440  *
441  * \param ctx     GL context.
442  * \param target  Buffer object target on which to operate.
443  * \param access  Information about how the buffer will be accessed.
444  * \param bufObj  Object to be mapped.
445  * \return  A pointer to the object's internal data store that can be accessed
446  *          by the processor
447  *
448  * \sa glMapBufferARB, dd_function_table::MapBuffer
449  */
450 static void *
451 _mesa_buffer_map( struct gl_context *ctx, GLenum target, GLenum access,
452                   struct gl_buffer_object *bufObj )
453 {
454    (void) ctx;
455    (void) target;
456    (void) access;
457    /* Just return a direct pointer to the data */
458    if (_mesa_bufferobj_mapped(bufObj)) {
459       /* already mapped! */
460       return NULL;
461    }
462    bufObj->Pointer = bufObj->Data;
463    bufObj->Length = bufObj->Size;
464    bufObj->Offset = 0;
465    return bufObj->Pointer;
466 }
467
468
469 /**
470  * Default fallback for \c dd_function_table::MapBufferRange().
471  * Called via glMapBufferRange().
472  */
473 static void *
474 _mesa_buffer_map_range( struct gl_context *ctx, GLenum target, GLintptr offset,
475                         GLsizeiptr length, GLbitfield access,
476                         struct gl_buffer_object *bufObj )
477 {
478    (void) ctx;
479    (void) target;
480    assert(!_mesa_bufferobj_mapped(bufObj));
481    /* Just return a direct pointer to the data */
482    bufObj->Pointer = bufObj->Data + offset;
483    bufObj->Length = length;
484    bufObj->Offset = offset;
485    bufObj->AccessFlags = access;
486    return bufObj->Pointer;
487 }
488
489
490 /**
491  * Default fallback for \c dd_function_table::FlushMappedBufferRange().
492  * Called via glFlushMappedBufferRange().
493  */
494 static void
495 _mesa_buffer_flush_mapped_range( struct gl_context *ctx, GLenum target, 
496                                  GLintptr offset, GLsizeiptr length,
497                                  struct gl_buffer_object *obj )
498 {
499    (void) ctx;
500    (void) target;
501    (void) offset;
502    (void) length;
503    (void) obj;
504    /* no-op */
505 }
506
507
508 /**
509  * Default callback for \c dd_function_table::MapBuffer().
510  *
511  * The input parameters will have been already tested for errors.
512  *
513  * \sa glUnmapBufferARB, dd_function_table::UnmapBuffer
514  */
515 static GLboolean
516 _mesa_buffer_unmap( struct gl_context *ctx, GLenum target,
517                     struct gl_buffer_object *bufObj )
518 {
519    (void) ctx;
520    (void) target;
521    /* XXX we might assert here that bufObj->Pointer is non-null */
522    bufObj->Pointer = NULL;
523    bufObj->Length = 0;
524    bufObj->Offset = 0;
525    bufObj->AccessFlags = 0x0;
526    return GL_TRUE;
527 }
528
529
530 /**
531  * Default fallback for \c dd_function_table::CopyBufferSubData().
532  * Called via glCopyBuffserSubData().
533  */
534 static void
535 _mesa_copy_buffer_subdata(struct gl_context *ctx,
536                           struct gl_buffer_object *src,
537                           struct gl_buffer_object *dst,
538                           GLintptr readOffset, GLintptr writeOffset,
539                           GLsizeiptr size)
540 {
541    GLubyte *srcPtr, *dstPtr;
542
543    /* buffer should not already be mapped */
544    assert(!_mesa_bufferobj_mapped(src));
545    assert(!_mesa_bufferobj_mapped(dst));
546
547    srcPtr = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_COPY_READ_BUFFER,
548                                               GL_READ_ONLY, src);
549    dstPtr = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_COPY_WRITE_BUFFER,
550                                               GL_WRITE_ONLY, dst);
551
552    if (srcPtr && dstPtr)
553       memcpy(dstPtr + writeOffset, srcPtr + readOffset, size);
554
555    ctx->Driver.UnmapBuffer(ctx, GL_COPY_READ_BUFFER, src);
556    ctx->Driver.UnmapBuffer(ctx, GL_COPY_WRITE_BUFFER, dst);
557 }
558
559
560
561 /**
562  * Initialize the state associated with buffer objects
563  */
564 void
565 _mesa_init_buffer_objects( struct gl_context *ctx )
566 {
567    memset(&DummyBufferObject, 0, sizeof(DummyBufferObject));
568    _glthread_INIT_MUTEX(DummyBufferObject.Mutex);
569    DummyBufferObject.RefCount = 1000*1000*1000; /* never delete */
570
571    _mesa_reference_buffer_object(ctx, &ctx->Array.ArrayBufferObj,
572                                  ctx->Shared->NullBufferObj);
573    _mesa_reference_buffer_object(ctx, &ctx->Array.ElementArrayBufferObj,
574                                  ctx->Shared->NullBufferObj);
575
576    _mesa_reference_buffer_object(ctx, &ctx->CopyReadBuffer,
577                                  ctx->Shared->NullBufferObj);
578    _mesa_reference_buffer_object(ctx, &ctx->CopyWriteBuffer,
579                                  ctx->Shared->NullBufferObj);
580 }
581
582
583 void
584 _mesa_free_buffer_objects( struct gl_context *ctx )
585 {
586    _mesa_reference_buffer_object(ctx, &ctx->Array.ArrayBufferObj, NULL);
587    _mesa_reference_buffer_object(ctx, &ctx->Array.ElementArrayBufferObj, NULL);
588
589    _mesa_reference_buffer_object(ctx, &ctx->CopyReadBuffer, NULL);
590    _mesa_reference_buffer_object(ctx, &ctx->CopyWriteBuffer, NULL);
591 }
592
593
594 /**
595  * Bind the specified target to buffer for the specified context.
596  * Called by glBindBuffer() and other functions.
597  */
598 static void
599 bind_buffer_object(struct gl_context *ctx, GLenum target, GLuint buffer)
600 {
601    struct gl_buffer_object *oldBufObj;
602    struct gl_buffer_object *newBufObj = NULL;
603    struct gl_buffer_object **bindTarget = NULL;
604
605    bindTarget = get_buffer_target(ctx, target);
606    if (!bindTarget) {
607       _mesa_error(ctx, GL_INVALID_ENUM, "glBindBufferARB(target 0x%x)", target);
608       return;
609    }
610
611    /* Get pointer to old buffer object (to be unbound) */
612    oldBufObj = *bindTarget;
613    if (oldBufObj && oldBufObj->Name == buffer)
614       return;   /* rebinding the same buffer object- no change */
615
616    /*
617     * Get pointer to new buffer object (newBufObj)
618     */
619    if (buffer == 0) {
620       /* The spec says there's not a buffer object named 0, but we use
621        * one internally because it simplifies things.
622        */
623       newBufObj = ctx->Shared->NullBufferObj;
624    }
625    else {
626       /* non-default buffer object */
627       newBufObj = _mesa_lookup_bufferobj(ctx, buffer);
628       if (!newBufObj || newBufObj == &DummyBufferObject) {
629          /* If this is a new buffer object id, or one which was generated but
630           * never used before, allocate a buffer object now.
631           */
632          ASSERT(ctx->Driver.NewBufferObject);
633          newBufObj = ctx->Driver.NewBufferObject(ctx, buffer, target);
634          if (!newBufObj) {
635             _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindBufferARB");
636             return;
637          }
638          _mesa_HashInsert(ctx->Shared->BufferObjects, buffer, newBufObj);
639       }
640    }
641    
642    /* bind new buffer */
643    _mesa_reference_buffer_object(ctx, bindTarget, newBufObj);
644
645    /* Pass BindBuffer call to device driver */
646    if (ctx->Driver.BindBuffer)
647       ctx->Driver.BindBuffer( ctx, target, newBufObj );
648 }
649
650
651 /**
652  * Update the default buffer objects in the given context to reference those
653  * specified in the shared state and release those referencing the old 
654  * shared state.
655  */
656 void
657 _mesa_update_default_objects_buffer_objects(struct gl_context *ctx)
658 {
659    /* Bind the NullBufferObj to remove references to those
660     * in the shared context hash table.
661     */
662    bind_buffer_object( ctx, GL_ARRAY_BUFFER_ARB, 0);
663    bind_buffer_object( ctx, GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
664    bind_buffer_object( ctx, GL_PIXEL_PACK_BUFFER_ARB, 0);
665    bind_buffer_object( ctx, GL_PIXEL_UNPACK_BUFFER_ARB, 0);
666 }
667
668
669
670 /**
671  * Return the gl_buffer_object for the given ID.
672  * Always return NULL for ID 0.
673  */
674 struct gl_buffer_object *
675 _mesa_lookup_bufferobj(struct gl_context *ctx, GLuint buffer)
676 {
677    if (buffer == 0)
678       return NULL;
679    else
680       return (struct gl_buffer_object *)
681          _mesa_HashLookup(ctx->Shared->BufferObjects, buffer);
682 }
683
684
685 /**
686  * If *ptr points to obj, set ptr = the Null/default buffer object.
687  * This is a helper for buffer object deletion.
688  * The GL spec says that deleting a buffer object causes it to get
689  * unbound from all arrays in the current context.
690  */
691 static void
692 unbind(struct gl_context *ctx,
693        struct gl_buffer_object **ptr,
694        struct gl_buffer_object *obj)
695 {
696    if (*ptr == obj) {
697       _mesa_reference_buffer_object(ctx, ptr, ctx->Shared->NullBufferObj);
698    }
699 }
700
701
702 /**
703  * Plug default/fallback buffer object functions into the device
704  * driver hooks.
705  */
706 void
707 _mesa_init_buffer_object_functions(struct dd_function_table *driver)
708 {
709    /* GL_ARB_vertex/pixel_buffer_object */
710    driver->NewBufferObject = _mesa_new_buffer_object;
711    driver->DeleteBuffer = _mesa_delete_buffer_object;
712    driver->BindBuffer = NULL;
713    driver->BufferData = _mesa_buffer_data;
714    driver->BufferSubData = _mesa_buffer_subdata;
715    driver->GetBufferSubData = _mesa_buffer_get_subdata;
716    driver->MapBuffer = _mesa_buffer_map;
717    driver->UnmapBuffer = _mesa_buffer_unmap;
718
719    /* GL_ARB_map_buffer_range */
720    driver->MapBufferRange = _mesa_buffer_map_range;
721    driver->FlushMappedBufferRange = _mesa_buffer_flush_mapped_range;
722
723    /* GL_ARB_copy_buffer */
724    driver->CopyBufferSubData = _mesa_copy_buffer_subdata;
725 }
726
727
728
729 /**********************************************************************/
730 /* API Functions                                                      */
731 /**********************************************************************/
732
733 void GLAPIENTRY
734 _mesa_BindBufferARB(GLenum target, GLuint buffer)
735 {
736    GET_CURRENT_CONTEXT(ctx);
737    ASSERT_OUTSIDE_BEGIN_END(ctx);
738
739    if (MESA_VERBOSE & VERBOSE_API)
740       _mesa_debug(ctx, "glBindBuffer(%s, %u)\n",
741                   _mesa_lookup_enum_by_nr(target), buffer);
742
743    bind_buffer_object(ctx, target, buffer);
744 }
745
746
747 /**
748  * Delete a set of buffer objects.
749  * 
750  * \param n      Number of buffer objects to delete.
751  * \param ids    Array of \c n buffer object IDs.
752  */
753 void GLAPIENTRY
754 _mesa_DeleteBuffersARB(GLsizei n, const GLuint *ids)
755 {
756    GET_CURRENT_CONTEXT(ctx);
757    GLsizei i;
758    ASSERT_OUTSIDE_BEGIN_END(ctx);
759    FLUSH_VERTICES(ctx, 0);
760
761    if (n < 0) {
762       _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteBuffersARB(n)");
763       return;
764    }
765
766    _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
767
768    for (i = 0; i < n; i++) {
769       struct gl_buffer_object *bufObj = _mesa_lookup_bufferobj(ctx, ids[i]);
770       if (bufObj) {
771          struct gl_array_object *arrayObj = ctx->Array.ArrayObj;
772          GLuint j;
773
774          ASSERT(bufObj->Name == ids[i] || bufObj == &DummyBufferObject);
775
776          if (_mesa_bufferobj_mapped(bufObj)) {
777             /* if mapped, unmap it now */
778             ctx->Driver.UnmapBuffer(ctx, 0, bufObj);
779             bufObj->AccessFlags = DEFAULT_ACCESS;
780             bufObj->Pointer = NULL;
781          }
782
783          /* unbind any vertex pointers bound to this buffer */
784          unbind(ctx, &arrayObj->Vertex.BufferObj, bufObj);
785          unbind(ctx, &arrayObj->Weight.BufferObj, bufObj);
786          unbind(ctx, &arrayObj->Normal.BufferObj, bufObj);
787          unbind(ctx, &arrayObj->Color.BufferObj, bufObj);
788          unbind(ctx, &arrayObj->SecondaryColor.BufferObj, bufObj);
789          unbind(ctx, &arrayObj->FogCoord.BufferObj, bufObj);
790          unbind(ctx, &arrayObj->Index.BufferObj, bufObj);
791          unbind(ctx, &arrayObj->EdgeFlag.BufferObj, bufObj);
792          for (j = 0; j < Elements(arrayObj->TexCoord); j++) {
793             unbind(ctx, &arrayObj->TexCoord[j].BufferObj, bufObj);
794          }
795          for (j = 0; j < Elements(arrayObj->VertexAttrib); j++) {
796             unbind(ctx, &arrayObj->VertexAttrib[j].BufferObj, bufObj);
797          }
798
799          if (ctx->Array.ArrayBufferObj == bufObj) {
800             _mesa_BindBufferARB( GL_ARRAY_BUFFER_ARB, 0 );
801          }
802          if (ctx->Array.ElementArrayBufferObj == bufObj) {
803             _mesa_BindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, 0 );
804          }
805
806          /* unbind any pixel pack/unpack pointers bound to this buffer */
807          if (ctx->Pack.BufferObj == bufObj) {
808             _mesa_BindBufferARB( GL_PIXEL_PACK_BUFFER_EXT, 0 );
809          }
810          if (ctx->Unpack.BufferObj == bufObj) {
811             _mesa_BindBufferARB( GL_PIXEL_UNPACK_BUFFER_EXT, 0 );
812          }
813
814          /* The ID is immediately freed for re-use */
815          _mesa_HashRemove(ctx->Shared->BufferObjects, ids[i]);
816          _mesa_reference_buffer_object(ctx, &bufObj, NULL);
817       }
818    }
819
820    _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
821 }
822
823
824 /**
825  * Generate a set of unique buffer object IDs and store them in \c buffer.
826  * 
827  * \param n       Number of IDs to generate.
828  * \param buffer  Array of \c n locations to store the IDs.
829  */
830 void GLAPIENTRY
831 _mesa_GenBuffersARB(GLsizei n, GLuint *buffer)
832 {
833    GET_CURRENT_CONTEXT(ctx);
834    GLuint first;
835    GLint i;
836    ASSERT_OUTSIDE_BEGIN_END(ctx);
837
838    if (MESA_VERBOSE & VERBOSE_API)
839       _mesa_debug(ctx, "glGenBuffers(%d)\n", n);
840
841    if (n < 0) {
842       _mesa_error(ctx, GL_INVALID_VALUE, "glGenBuffersARB");
843       return;
844    }
845
846    if (!buffer) {
847       return;
848    }
849
850    /*
851     * This must be atomic (generation and allocation of buffer object IDs)
852     */
853    _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
854
855    first = _mesa_HashFindFreeKeyBlock(ctx->Shared->BufferObjects, n);
856
857    /* Insert the ID and pointer to dummy buffer object into hash table */
858    for (i = 0; i < n; i++) {
859       _mesa_HashInsert(ctx->Shared->BufferObjects, first + i,
860                        &DummyBufferObject);
861       buffer[i] = first + i;
862    }
863
864    _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
865 }
866
867
868 /**
869  * Determine if ID is the name of a buffer object.
870  * 
871  * \param id  ID of the potential buffer object.
872  * \return  \c GL_TRUE if \c id is the name of a buffer object, 
873  *          \c GL_FALSE otherwise.
874  */
875 GLboolean GLAPIENTRY
876 _mesa_IsBufferARB(GLuint id)
877 {
878    struct gl_buffer_object *bufObj;
879    GET_CURRENT_CONTEXT(ctx);
880    ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
881
882    _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
883    bufObj = _mesa_lookup_bufferobj(ctx, id);
884    _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
885
886    return bufObj && bufObj != &DummyBufferObject;
887 }
888
889
890 void GLAPIENTRY
891 _mesa_BufferDataARB(GLenum target, GLsizeiptrARB size,
892                     const GLvoid * data, GLenum usage)
893 {
894    GET_CURRENT_CONTEXT(ctx);
895    struct gl_buffer_object *bufObj;
896    ASSERT_OUTSIDE_BEGIN_END(ctx);
897
898    if (MESA_VERBOSE & VERBOSE_API)
899       _mesa_debug(ctx, "glBufferData(%s, %ld, %p, %s)\n",
900                   _mesa_lookup_enum_by_nr(target),
901                   (long int) size, data,
902                   _mesa_lookup_enum_by_nr(usage));
903
904    if (size < 0) {
905       _mesa_error(ctx, GL_INVALID_VALUE, "glBufferDataARB(size < 0)");
906       return;
907    }
908
909    switch (usage) {
910    case GL_STREAM_DRAW_ARB:
911    case GL_STREAM_READ_ARB:
912    case GL_STREAM_COPY_ARB:
913    case GL_STATIC_DRAW_ARB:
914    case GL_STATIC_READ_ARB:
915    case GL_STATIC_COPY_ARB:
916    case GL_DYNAMIC_DRAW_ARB:
917    case GL_DYNAMIC_READ_ARB:
918    case GL_DYNAMIC_COPY_ARB:
919       /* OK */
920       break;
921    default:
922       _mesa_error(ctx, GL_INVALID_ENUM, "glBufferDataARB(usage)");
923       return;
924    }
925
926    bufObj = get_buffer(ctx, target);
927    if (!bufObj) {
928       _mesa_error(ctx, GL_INVALID_ENUM, "glBufferDataARB(target)" );
929       return;
930    }
931    if (!_mesa_is_bufferobj(bufObj)) {
932       _mesa_error(ctx, GL_INVALID_OPERATION, "glBufferDataARB(buffer 0)" );
933       return;
934    }
935    
936    if (_mesa_bufferobj_mapped(bufObj)) {
937       /* Unmap the existing buffer.  We'll replace it now.  Not an error. */
938       ctx->Driver.UnmapBuffer(ctx, target, bufObj);
939       bufObj->AccessFlags = DEFAULT_ACCESS;
940       ASSERT(bufObj->Pointer == NULL);
941    }  
942
943    FLUSH_VERTICES(ctx, _NEW_BUFFER_OBJECT);
944
945    bufObj->Written = GL_TRUE;
946
947 #ifdef VBO_DEBUG
948    printf("glBufferDataARB(%u, sz %ld, from %p, usage 0x%x)\n",
949                 bufObj->Name, size, data, usage);
950 #endif
951
952 #ifdef BOUNDS_CHECK
953    size += 100;
954 #endif
955
956    ASSERT(ctx->Driver.BufferData);
957    if (!ctx->Driver.BufferData( ctx, target, size, data, usage, bufObj )) {
958       _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBufferDataARB()");
959    }
960 }
961
962
963 void GLAPIENTRY
964 _mesa_BufferSubDataARB(GLenum target, GLintptrARB offset,
965                        GLsizeiptrARB size, const GLvoid * data)
966 {
967    GET_CURRENT_CONTEXT(ctx);
968    struct gl_buffer_object *bufObj;
969    ASSERT_OUTSIDE_BEGIN_END(ctx);
970
971    bufObj = buffer_object_subdata_range_good( ctx, target, offset, size,
972                                               "glBufferSubDataARB" );
973    if (!bufObj) {
974       /* error already recorded */
975       return;
976    }
977
978    if (size == 0)
979       return;
980
981    bufObj->Written = GL_TRUE;
982
983    ASSERT(ctx->Driver.BufferSubData);
984    ctx->Driver.BufferSubData( ctx, target, offset, size, data, bufObj );
985 }
986
987
988 void GLAPIENTRY
989 _mesa_GetBufferSubDataARB(GLenum target, GLintptrARB offset,
990                           GLsizeiptrARB size, void * data)
991 {
992    GET_CURRENT_CONTEXT(ctx);
993    struct gl_buffer_object *bufObj;
994    ASSERT_OUTSIDE_BEGIN_END(ctx);
995
996    bufObj = buffer_object_subdata_range_good( ctx, target, offset, size,
997                                               "glGetBufferSubDataARB" );
998    if (!bufObj) {
999       /* error already recorded */
1000       return;
1001    }
1002
1003    ASSERT(ctx->Driver.GetBufferSubData);
1004    ctx->Driver.GetBufferSubData( ctx, target, offset, size, data, bufObj );
1005 }
1006
1007
1008 void * GLAPIENTRY
1009 _mesa_MapBufferARB(GLenum target, GLenum access)
1010 {
1011    GET_CURRENT_CONTEXT(ctx);
1012    struct gl_buffer_object * bufObj;
1013    GLbitfield accessFlags;
1014    void *map;
1015
1016    ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, NULL);
1017
1018    switch (access) {
1019    case GL_READ_ONLY_ARB:
1020       accessFlags = GL_MAP_READ_BIT;
1021       break;
1022    case GL_WRITE_ONLY_ARB:
1023       accessFlags = GL_MAP_WRITE_BIT;
1024       break;
1025    case GL_READ_WRITE_ARB:
1026       accessFlags = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT;
1027       break;
1028    default:
1029       _mesa_error(ctx, GL_INVALID_ENUM, "glMapBufferARB(access)");
1030       return NULL;
1031    }
1032
1033    bufObj = get_buffer(ctx, target);
1034    if (!bufObj) {
1035       _mesa_error(ctx, GL_INVALID_ENUM, "glMapBufferARB(target)" );
1036       return NULL;
1037    }
1038    if (!_mesa_is_bufferobj(bufObj)) {
1039       _mesa_error(ctx, GL_INVALID_OPERATION, "glMapBufferARB(buffer 0)" );
1040       return NULL;
1041    }
1042    if (_mesa_bufferobj_mapped(bufObj)) {
1043       _mesa_error(ctx, GL_INVALID_OPERATION, "glMapBufferARB(already mapped)");
1044       return NULL;
1045    }
1046
1047    ASSERT(ctx->Driver.MapBuffer);
1048    map = ctx->Driver.MapBuffer( ctx, target, access, bufObj );
1049    if (!map) {
1050       _mesa_error(ctx, GL_OUT_OF_MEMORY, "glMapBufferARB(map failed)");
1051       return NULL;
1052    }
1053    else {
1054       /* The driver callback should have set these fields.
1055        * This is important because other modules (like VBO) might call
1056        * the driver function directly.
1057        */
1058       ASSERT(bufObj->Pointer == map);
1059       ASSERT(bufObj->Length == bufObj->Size);
1060       ASSERT(bufObj->Offset == 0);
1061       bufObj->AccessFlags = accessFlags;
1062    }
1063
1064    if (access == GL_WRITE_ONLY_ARB || access == GL_READ_WRITE_ARB)
1065       bufObj->Written = GL_TRUE;
1066
1067 #ifdef VBO_DEBUG
1068    printf("glMapBufferARB(%u, sz %ld, access 0x%x)\n",
1069           bufObj->Name, bufObj->Size, access);
1070    if (access == GL_WRITE_ONLY_ARB) {
1071       GLuint i;
1072       GLubyte *b = (GLubyte *) bufObj->Pointer;
1073       for (i = 0; i < bufObj->Size; i++)
1074          b[i] = i & 0xff;
1075    }
1076 #endif
1077
1078 #ifdef BOUNDS_CHECK
1079    {
1080       GLubyte *buf = (GLubyte *) bufObj->Pointer;
1081       GLuint i;
1082       /* buffer is 100 bytes larger than requested, fill with magic value */
1083       for (i = 0; i < 100; i++) {
1084          buf[bufObj->Size - i - 1] = 123;
1085       }
1086    }
1087 #endif
1088
1089    return bufObj->Pointer;
1090 }
1091
1092
1093 GLboolean GLAPIENTRY
1094 _mesa_UnmapBufferARB(GLenum target)
1095 {
1096    GET_CURRENT_CONTEXT(ctx);
1097    struct gl_buffer_object *bufObj;
1098    GLboolean status = GL_TRUE;
1099    ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
1100
1101    bufObj = get_buffer(ctx, target);
1102    if (!bufObj) {
1103       _mesa_error(ctx, GL_INVALID_ENUM, "glUnmapBufferARB(target)" );
1104       return GL_FALSE;
1105    }
1106    if (!_mesa_is_bufferobj(bufObj)) {
1107       _mesa_error(ctx, GL_INVALID_OPERATION, "glUnmapBufferARB" );
1108       return GL_FALSE;
1109    }
1110    if (!_mesa_bufferobj_mapped(bufObj)) {
1111       _mesa_error(ctx, GL_INVALID_OPERATION, "glUnmapBufferARB");
1112       return GL_FALSE;
1113    }
1114
1115 #ifdef BOUNDS_CHECK
1116    if (bufObj->Access != GL_READ_ONLY_ARB) {
1117       GLubyte *buf = (GLubyte *) bufObj->Pointer;
1118       GLuint i;
1119       /* check that last 100 bytes are still = magic value */
1120       for (i = 0; i < 100; i++) {
1121          GLuint pos = bufObj->Size - i - 1;
1122          if (buf[pos] != 123) {
1123             _mesa_warning(ctx, "Out of bounds buffer object write detected"
1124                           " at position %d (value = %u)\n",
1125                           pos, buf[pos]);
1126          }
1127       }
1128    }
1129 #endif
1130
1131 #ifdef VBO_DEBUG
1132    if (bufObj->AccessFlags & GL_MAP_WRITE_BIT) {
1133       GLuint i, unchanged = 0;
1134       GLubyte *b = (GLubyte *) bufObj->Pointer;
1135       GLint pos = -1;
1136       /* check which bytes changed */
1137       for (i = 0; i < bufObj->Size - 1; i++) {
1138          if (b[i] == (i & 0xff) && b[i+1] == ((i+1) & 0xff)) {
1139             unchanged++;
1140             if (pos == -1)
1141                pos = i;
1142          }
1143       }
1144       if (unchanged) {
1145          printf("glUnmapBufferARB(%u): %u of %ld unchanged, starting at %d\n",
1146                       bufObj->Name, unchanged, bufObj->Size, pos);
1147       }
1148    }
1149 #endif
1150
1151    status = ctx->Driver.UnmapBuffer( ctx, target, bufObj );
1152    bufObj->AccessFlags = DEFAULT_ACCESS;
1153    ASSERT(bufObj->Pointer == NULL);
1154    ASSERT(bufObj->Offset == 0);
1155    ASSERT(bufObj->Length == 0);
1156
1157    return status;
1158 }
1159
1160
1161 void GLAPIENTRY
1162 _mesa_GetBufferParameterivARB(GLenum target, GLenum pname, GLint *params)
1163 {
1164    GET_CURRENT_CONTEXT(ctx);
1165    struct gl_buffer_object *bufObj;
1166    ASSERT_OUTSIDE_BEGIN_END(ctx);
1167
1168    bufObj = get_buffer(ctx, target);
1169    if (!bufObj) {
1170       _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferParameterivARB(target)" );
1171       return;
1172    }
1173    if (!_mesa_is_bufferobj(bufObj)) {
1174       _mesa_error(ctx, GL_INVALID_OPERATION, "glGetBufferParameterivARB" );
1175       return;
1176    }
1177
1178    switch (pname) {
1179    case GL_BUFFER_SIZE_ARB:
1180       *params = (GLint) bufObj->Size;
1181       return;
1182    case GL_BUFFER_USAGE_ARB:
1183       *params = bufObj->Usage;
1184       return;
1185    case GL_BUFFER_ACCESS_ARB:
1186       *params = simplified_access_mode(bufObj->AccessFlags);
1187       return;
1188    case GL_BUFFER_MAPPED_ARB:
1189       *params = _mesa_bufferobj_mapped(bufObj);
1190       return;
1191    case GL_BUFFER_ACCESS_FLAGS:
1192       if (ctx->VersionMajor < 3)
1193          goto invalid_pname;
1194       *params = bufObj->AccessFlags;
1195       return;
1196    case GL_BUFFER_MAP_OFFSET:
1197       if (ctx->VersionMajor < 3)
1198          goto invalid_pname;
1199       *params = (GLint) bufObj->Offset;
1200       return;
1201    case GL_BUFFER_MAP_LENGTH:
1202       if (ctx->VersionMajor < 3)
1203          goto invalid_pname;
1204       *params = (GLint) bufObj->Length;
1205       return;
1206    default:
1207       ; /* fall-through */
1208    }
1209
1210 invalid_pname:
1211    _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferParameterivARB(pname=%s)",
1212                _mesa_lookup_enum_by_nr(pname));
1213 }
1214
1215
1216 /**
1217  * New in GL 3.2
1218  * This is pretty much a duplicate of GetBufferParameteriv() but the
1219  * GL_BUFFER_SIZE_ARB attribute will be 64-bits on a 64-bit system.
1220  */
1221 void GLAPIENTRY
1222 _mesa_GetBufferParameteri64v(GLenum target, GLenum pname, GLint64 *params)
1223 {
1224    GET_CURRENT_CONTEXT(ctx);
1225    struct gl_buffer_object *bufObj;
1226    ASSERT_OUTSIDE_BEGIN_END(ctx);
1227
1228    bufObj = get_buffer(ctx, target);
1229    if (!bufObj) {
1230       _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferParameteri64v(target)" );
1231       return;
1232    }
1233    if (!_mesa_is_bufferobj(bufObj)) {
1234       _mesa_error(ctx, GL_INVALID_OPERATION, "glGetBufferParameteri64v" );
1235       return;
1236    }
1237
1238    switch (pname) {
1239    case GL_BUFFER_SIZE_ARB:
1240       *params = bufObj->Size;
1241       return;
1242    case GL_BUFFER_USAGE_ARB:
1243       *params = bufObj->Usage;
1244       return;
1245    case GL_BUFFER_ACCESS_ARB:
1246       *params = simplified_access_mode(bufObj->AccessFlags);
1247       return;
1248    case GL_BUFFER_ACCESS_FLAGS:
1249       if (ctx->VersionMajor < 3)
1250          goto invalid_pname;
1251       *params = bufObj->AccessFlags;
1252       return;
1253    case GL_BUFFER_MAPPED_ARB:
1254       *params = _mesa_bufferobj_mapped(bufObj);
1255       return;
1256    case GL_BUFFER_MAP_OFFSET:
1257       if (ctx->VersionMajor < 3)
1258          goto invalid_pname;
1259       *params = bufObj->Offset;
1260       return;
1261    case GL_BUFFER_MAP_LENGTH:
1262       if (ctx->VersionMajor < 3)
1263          goto invalid_pname;
1264       *params = bufObj->Length;
1265       return;
1266    default:
1267       ; /* fall-through */
1268    }
1269
1270 invalid_pname:
1271    _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferParameteri64v(pname=%s)",
1272                _mesa_lookup_enum_by_nr(pname));
1273 }
1274
1275
1276 void GLAPIENTRY
1277 _mesa_GetBufferPointervARB(GLenum target, GLenum pname, GLvoid **params)
1278 {
1279    GET_CURRENT_CONTEXT(ctx);
1280    struct gl_buffer_object * bufObj;
1281    ASSERT_OUTSIDE_BEGIN_END(ctx);
1282
1283    if (pname != GL_BUFFER_MAP_POINTER_ARB) {
1284       _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferPointervARB(pname)");
1285       return;
1286    }
1287
1288    bufObj = get_buffer(ctx, target);
1289    if (!bufObj) {
1290       _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferPointervARB(target)" );
1291       return;
1292    }
1293    if (!_mesa_is_bufferobj(bufObj)) {
1294       _mesa_error(ctx, GL_INVALID_OPERATION, "glGetBufferPointervARB" );
1295       return;
1296    }
1297
1298    *params = bufObj->Pointer;
1299 }
1300
1301
1302 void GLAPIENTRY
1303 _mesa_CopyBufferSubData(GLenum readTarget, GLenum writeTarget,
1304                         GLintptr readOffset, GLintptr writeOffset,
1305                         GLsizeiptr size)
1306 {
1307    GET_CURRENT_CONTEXT(ctx);
1308    struct gl_buffer_object *src, *dst;
1309    ASSERT_OUTSIDE_BEGIN_END(ctx);
1310
1311    src = get_buffer(ctx, readTarget);
1312    if (!src || !_mesa_is_bufferobj(src)) {
1313       _mesa_error(ctx, GL_INVALID_ENUM,
1314                   "glCopyBuffserSubData(readTarget = 0x%x)", readTarget);
1315       return;
1316    }
1317
1318    dst = get_buffer(ctx, writeTarget);
1319    if (!dst || !_mesa_is_bufferobj(dst)) {
1320       _mesa_error(ctx, GL_INVALID_ENUM,
1321                   "glCopyBuffserSubData(writeTarget = 0x%x)", writeTarget);
1322       return;
1323    }
1324
1325    if (_mesa_bufferobj_mapped(src)) {
1326       _mesa_error(ctx, GL_INVALID_OPERATION,
1327                   "glCopyBuffserSubData(readBuffer is mapped)");
1328       return;
1329    }
1330
1331    if (_mesa_bufferobj_mapped(dst)) {
1332       _mesa_error(ctx, GL_INVALID_OPERATION,
1333                   "glCopyBuffserSubData(writeBuffer is mapped)");
1334       return;
1335    }
1336
1337    if (readOffset < 0) {
1338       _mesa_error(ctx, GL_INVALID_VALUE,
1339                   "glCopyBuffserSubData(readOffset = %d)", (int) readOffset);
1340       return;
1341    }
1342
1343    if (writeOffset < 0) {
1344       _mesa_error(ctx, GL_INVALID_VALUE,
1345                   "glCopyBuffserSubData(writeOffset = %d)", (int) writeOffset);
1346       return;
1347    }
1348
1349    if (readOffset + size > src->Size) {
1350       _mesa_error(ctx, GL_INVALID_VALUE,
1351                   "glCopyBuffserSubData(readOffset + size = %d)",
1352                   (int) (readOffset + size));
1353       return;
1354    }
1355
1356    if (writeOffset + size > dst->Size) {
1357       _mesa_error(ctx, GL_INVALID_VALUE,
1358                   "glCopyBuffserSubData(writeOffset + size = %d)",
1359                   (int) (writeOffset + size));
1360       return;
1361    }
1362
1363    if (src == dst) {
1364       if (readOffset + size <= writeOffset) {
1365          /* OK */
1366       }
1367       else if (writeOffset + size <= readOffset) {
1368          /* OK */
1369       }
1370       else {
1371          /* overlapping src/dst is illegal */
1372          _mesa_error(ctx, GL_INVALID_VALUE,
1373                      "glCopyBuffserSubData(overlapping src/dst)");
1374          return;
1375       }
1376    }
1377
1378    ctx->Driver.CopyBufferSubData(ctx, src, dst, readOffset, writeOffset, size);
1379 }
1380
1381
1382 /**
1383  * See GL_ARB_map_buffer_range spec
1384  */
1385 void * GLAPIENTRY
1386 _mesa_MapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length,
1387                      GLbitfield access)
1388 {
1389    GET_CURRENT_CONTEXT(ctx);
1390    struct gl_buffer_object *bufObj;
1391    void *map;
1392
1393    ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, NULL);
1394
1395    if (!ctx->Extensions.ARB_map_buffer_range) {
1396       _mesa_error(ctx, GL_INVALID_OPERATION,
1397                   "glMapBufferRange(extension not supported)");
1398       return NULL;
1399    }
1400
1401    if (offset < 0) {
1402       _mesa_error(ctx, GL_INVALID_VALUE,
1403                   "glMapBufferRange(offset = %ld)", (long)offset);
1404       return NULL;
1405    }
1406
1407    if (length < 0) {
1408       _mesa_error(ctx, GL_INVALID_VALUE,
1409                   "glMapBufferRange(length = %ld)", (long)length);
1410       return NULL;
1411    }
1412
1413    if (access & ~(GL_MAP_READ_BIT |
1414                   GL_MAP_WRITE_BIT |
1415                   GL_MAP_INVALIDATE_RANGE_BIT |
1416                   GL_MAP_INVALIDATE_BUFFER_BIT |
1417                   GL_MAP_FLUSH_EXPLICIT_BIT |
1418                   GL_MAP_UNSYNCHRONIZED_BIT)) {
1419       /* generate an error if any undefind bit is set */
1420       _mesa_error(ctx, GL_INVALID_VALUE, "glMapBufferRange(access)");
1421       return NULL;
1422    }
1423
1424    if ((access & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)) == 0) {
1425       _mesa_error(ctx, GL_INVALID_OPERATION,
1426                   "glMapBufferRange(access indicates neither read or write)");
1427       return NULL;
1428    }
1429
1430    if ((access & GL_MAP_READ_BIT) &&
1431        (access & (GL_MAP_INVALIDATE_RANGE_BIT |
1432                   GL_MAP_INVALIDATE_BUFFER_BIT |
1433                   GL_MAP_UNSYNCHRONIZED_BIT))) {
1434       _mesa_error(ctx, GL_INVALID_OPERATION,
1435                   "glMapBufferRange(invalid access flags)");
1436       return NULL;
1437    }
1438
1439    if ((access & GL_MAP_FLUSH_EXPLICIT_BIT) &&
1440        ((access & GL_MAP_WRITE_BIT) == 0)) {
1441       _mesa_error(ctx, GL_INVALID_OPERATION,
1442                   "glMapBufferRange(invalid access flags)");
1443       return NULL;
1444    }
1445
1446    bufObj = get_buffer(ctx, target);
1447    if (!bufObj || !_mesa_is_bufferobj(bufObj)) {
1448       _mesa_error(ctx, GL_INVALID_ENUM,
1449                   "glMapBufferRange(target = 0x%x)", target);
1450       return NULL;
1451    }
1452
1453    if (offset + length > bufObj->Size) {
1454       _mesa_error(ctx, GL_INVALID_VALUE,
1455                   "glMapBufferRange(offset + length > size)");
1456       return NULL;
1457    }
1458
1459    if (_mesa_bufferobj_mapped(bufObj)) {
1460       _mesa_error(ctx, GL_INVALID_OPERATION,
1461                   "glMapBufferRange(buffer already mapped)");
1462       return NULL;
1463    }
1464       
1465    ASSERT(ctx->Driver.MapBufferRange);
1466    map = ctx->Driver.MapBufferRange(ctx, target, offset, length,
1467                                     access, bufObj);
1468    if (!map) {
1469       _mesa_error(ctx, GL_OUT_OF_MEMORY, "glMapBufferARB(map failed)");
1470    }
1471    else {
1472       /* The driver callback should have set all these fields.
1473        * This is important because other modules (like VBO) might call
1474        * the driver function directly.
1475        */
1476       ASSERT(bufObj->Pointer == map);
1477       ASSERT(bufObj->Length == length);
1478       ASSERT(bufObj->Offset == offset);
1479       ASSERT(bufObj->AccessFlags == access);
1480    }
1481
1482    return map;
1483 }
1484
1485
1486 /**
1487  * See GL_ARB_map_buffer_range spec
1488  */
1489 void GLAPIENTRY
1490 _mesa_FlushMappedBufferRange(GLenum target, GLintptr offset, GLsizeiptr length)
1491 {
1492    GET_CURRENT_CONTEXT(ctx);
1493    struct gl_buffer_object *bufObj;
1494    ASSERT_OUTSIDE_BEGIN_END(ctx);
1495
1496    if (!ctx->Extensions.ARB_map_buffer_range) {
1497       _mesa_error(ctx, GL_INVALID_OPERATION,
1498                   "glMapBufferRange(extension not supported)");
1499       return;
1500    }
1501
1502    if (offset < 0) {
1503       _mesa_error(ctx, GL_INVALID_VALUE,
1504                   "glMapBufferRange(offset = %ld)", (long)offset);
1505       return;
1506    }
1507
1508    if (length < 0) {
1509       _mesa_error(ctx, GL_INVALID_VALUE,
1510                   "glMapBufferRange(length = %ld)", (long)length);
1511       return;
1512    }
1513
1514    bufObj = get_buffer(ctx, target);
1515    if (!bufObj) {
1516       _mesa_error(ctx, GL_INVALID_ENUM,
1517                   "glMapBufferRange(target = 0x%x)", target);
1518       return;
1519    }
1520
1521    if (!_mesa_is_bufferobj(bufObj)) {
1522       _mesa_error(ctx, GL_INVALID_OPERATION,
1523                   "glMapBufferRange(current buffer is 0)");
1524       return;
1525    }
1526
1527    if (!_mesa_bufferobj_mapped(bufObj)) {
1528       /* buffer is not mapped */
1529       _mesa_error(ctx, GL_INVALID_OPERATION,
1530                   "glMapBufferRange(buffer is not mapped)");
1531       return;
1532    }
1533
1534    if ((bufObj->AccessFlags & GL_MAP_FLUSH_EXPLICIT_BIT) == 0) {
1535       _mesa_error(ctx, GL_INVALID_OPERATION,
1536                   "glMapBufferRange(GL_MAP_FLUSH_EXPLICIT_BIT not set)");
1537       return;
1538    }
1539
1540    if (offset + length > bufObj->Length) {
1541       _mesa_error(ctx, GL_INVALID_VALUE,
1542                   "glMapBufferRange(offset %ld + length %ld > mapped length %ld)",
1543                   (long)offset, (long)length, (long)bufObj->Length);
1544       return;
1545    }
1546
1547    ASSERT(bufObj->AccessFlags & GL_MAP_WRITE_BIT);
1548
1549    if (ctx->Driver.FlushMappedBufferRange)
1550       ctx->Driver.FlushMappedBufferRange(ctx, target, offset, length, bufObj);
1551 }
1552
1553
1554 #if FEATURE_APPLE_object_purgeable
1555 static GLenum
1556 buffer_object_purgeable(struct gl_context *ctx, GLuint name, GLenum option)
1557 {
1558    struct gl_buffer_object *bufObj;
1559    GLenum retval;
1560
1561    bufObj = _mesa_lookup_bufferobj(ctx, name);
1562    if (!bufObj) {
1563       _mesa_error(ctx, GL_INVALID_VALUE,
1564                   "glObjectPurgeable(name = 0x%x)", name);
1565       return 0;
1566    }
1567    if (!_mesa_is_bufferobj(bufObj)) {
1568       _mesa_error(ctx, GL_INVALID_OPERATION, "glObjectPurgeable(buffer 0)" );
1569       return 0;
1570    }
1571
1572    if (bufObj->Purgeable) {
1573       _mesa_error(ctx, GL_INVALID_OPERATION,
1574                   "glObjectPurgeable(name = 0x%x) is already purgeable", name);
1575       return GL_VOLATILE_APPLE;
1576    }
1577
1578    bufObj->Purgeable = GL_TRUE;
1579
1580    retval = GL_VOLATILE_APPLE;
1581    if (ctx->Driver.BufferObjectPurgeable)
1582       retval = ctx->Driver.BufferObjectPurgeable(ctx, bufObj, option);
1583
1584    return retval;
1585 }
1586
1587
1588 static GLenum
1589 renderbuffer_purgeable(struct gl_context *ctx, GLuint name, GLenum option)
1590 {
1591    struct gl_renderbuffer *bufObj;
1592    GLenum retval;
1593
1594    bufObj = _mesa_lookup_renderbuffer(ctx, name);
1595    if (!bufObj) {
1596       _mesa_error(ctx, GL_INVALID_VALUE,
1597                   "glObjectUnpurgeable(name = 0x%x)", name);
1598       return 0;
1599    }
1600
1601    if (bufObj->Purgeable) {
1602       _mesa_error(ctx, GL_INVALID_OPERATION,
1603                   "glObjectPurgeable(name = 0x%x) is already purgeable", name);
1604       return GL_VOLATILE_APPLE;
1605    }
1606
1607    bufObj->Purgeable = GL_TRUE;
1608
1609    retval = GL_VOLATILE_APPLE;
1610    if (ctx->Driver.RenderObjectPurgeable)
1611       retval = ctx->Driver.RenderObjectPurgeable(ctx, bufObj, option);
1612
1613    return retval;
1614 }
1615
1616
1617 static GLenum
1618 texture_object_purgeable(struct gl_context *ctx, GLuint name, GLenum option)
1619 {
1620    struct gl_texture_object *bufObj;
1621    GLenum retval;
1622
1623    bufObj = _mesa_lookup_texture(ctx, name);
1624    if (!bufObj) {
1625       _mesa_error(ctx, GL_INVALID_VALUE,
1626                   "glObjectPurgeable(name = 0x%x)", name);
1627       return 0;
1628    }
1629
1630    if (bufObj->Purgeable) {
1631       _mesa_error(ctx, GL_INVALID_OPERATION,
1632                   "glObjectPurgeable(name = 0x%x) is already purgeable", name);
1633       return GL_VOLATILE_APPLE;
1634    }
1635
1636    bufObj->Purgeable = GL_TRUE;
1637
1638    retval = GL_VOLATILE_APPLE;
1639    if (ctx->Driver.TextureObjectPurgeable)
1640       retval = ctx->Driver.TextureObjectPurgeable(ctx, bufObj, option);
1641
1642    return retval;
1643 }
1644
1645
1646 GLenum GLAPIENTRY
1647 _mesa_ObjectPurgeableAPPLE(GLenum objectType, GLuint name, GLenum option)
1648 {
1649    GLenum retval;
1650
1651    GET_CURRENT_CONTEXT(ctx);
1652    ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0);
1653
1654    if (name == 0) {
1655       _mesa_error(ctx, GL_INVALID_VALUE,
1656                   "glObjectPurgeable(name = 0x%x)", name);
1657       return 0;
1658    }
1659
1660    switch (option) {
1661    case GL_VOLATILE_APPLE:
1662    case GL_RELEASED_APPLE:
1663       /* legal */
1664       break;
1665    default:
1666       _mesa_error(ctx, GL_INVALID_ENUM,
1667                   "glObjectPurgeable(name = 0x%x) invalid option: %d",
1668                   name, option);
1669       return 0;
1670    }
1671
1672    switch (objectType) {
1673    case GL_TEXTURE:
1674       retval = texture_object_purgeable(ctx, name, option);
1675       break;
1676    case GL_RENDERBUFFER_EXT:
1677       retval = renderbuffer_purgeable(ctx, name, option);
1678       break;
1679    case GL_BUFFER_OBJECT_APPLE:
1680       retval = buffer_object_purgeable(ctx, name, option);
1681       break;
1682    default:
1683       _mesa_error(ctx, GL_INVALID_ENUM,
1684                   "glObjectPurgeable(name = 0x%x) invalid type: %d",
1685                   name, objectType);
1686       return 0;
1687    }
1688
1689    /* In strict conformance to the spec, we must only return VOLATILE when
1690     * when passed the VOLATILE option. Madness.
1691     *
1692     * XXX First fix the spec, then fix me.
1693     */
1694    return option == GL_VOLATILE_APPLE ? GL_VOLATILE_APPLE : retval;
1695 }
1696
1697
1698 static GLenum
1699 buffer_object_unpurgeable(struct gl_context *ctx, GLuint name, GLenum option)
1700 {
1701    struct gl_buffer_object *bufObj;
1702    GLenum retval;
1703
1704    bufObj = _mesa_lookup_bufferobj(ctx, name);
1705    if (!bufObj) {
1706       _mesa_error(ctx, GL_INVALID_VALUE,
1707                   "glObjectUnpurgeable(name = 0x%x)", name);
1708       return 0;
1709    }
1710
1711    if (! bufObj->Purgeable) {
1712       _mesa_error(ctx, GL_INVALID_OPERATION,
1713                   "glObjectUnpurgeable(name = 0x%x) object is "
1714                   " already \"unpurged\"", name);
1715       return 0;
1716    }
1717
1718    bufObj->Purgeable = GL_FALSE;
1719
1720    retval = option;
1721    if (ctx->Driver.BufferObjectUnpurgeable)
1722       retval = ctx->Driver.BufferObjectUnpurgeable(ctx, bufObj, option);
1723
1724    return retval;
1725 }
1726
1727
1728 static GLenum
1729 renderbuffer_unpurgeable(struct gl_context *ctx, GLuint name, GLenum option)
1730 {
1731    struct gl_renderbuffer *bufObj;
1732    GLenum retval;
1733
1734    bufObj = _mesa_lookup_renderbuffer(ctx, name);
1735    if (!bufObj) {
1736       _mesa_error(ctx, GL_INVALID_VALUE,
1737                   "glObjectUnpurgeable(name = 0x%x)", name);
1738       return 0;
1739    }
1740
1741    if (! bufObj->Purgeable) {
1742       _mesa_error(ctx, GL_INVALID_OPERATION,
1743                   "glObjectUnpurgeable(name = 0x%x) object is "
1744                   " already \"unpurged\"", name);
1745       return 0;
1746    }
1747
1748    bufObj->Purgeable = GL_FALSE;
1749
1750    retval = option;
1751    if (ctx->Driver.RenderObjectUnpurgeable)
1752       retval = ctx->Driver.RenderObjectUnpurgeable(ctx, bufObj, option);
1753
1754    return retval;
1755 }
1756
1757
1758 static GLenum
1759 texture_object_unpurgeable(struct gl_context *ctx, GLuint name, GLenum option)
1760 {
1761    struct gl_texture_object *bufObj;
1762    GLenum retval;
1763
1764    bufObj = _mesa_lookup_texture(ctx, name);
1765    if (!bufObj) {
1766       _mesa_error(ctx, GL_INVALID_VALUE,
1767                   "glObjectUnpurgeable(name = 0x%x)", name);
1768       return 0;
1769    }
1770
1771    if (! bufObj->Purgeable) {
1772       _mesa_error(ctx, GL_INVALID_OPERATION,
1773                   "glObjectUnpurgeable(name = 0x%x) object is"
1774                   " already \"unpurged\"", name);
1775       return 0;
1776    }
1777
1778    bufObj->Purgeable = GL_FALSE;
1779
1780    retval = option;
1781    if (ctx->Driver.TextureObjectUnpurgeable)
1782       retval = ctx->Driver.TextureObjectUnpurgeable(ctx, bufObj, option);
1783
1784    return retval;
1785 }
1786
1787
1788 GLenum GLAPIENTRY
1789 _mesa_ObjectUnpurgeableAPPLE(GLenum objectType, GLuint name, GLenum option)
1790 {
1791    GET_CURRENT_CONTEXT(ctx);
1792    ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0);
1793
1794    if (name == 0) {
1795       _mesa_error(ctx, GL_INVALID_VALUE,
1796                   "glObjectUnpurgeable(name = 0x%x)", name);
1797       return 0;
1798    }
1799
1800    switch (option) {
1801    case GL_RETAINED_APPLE:
1802    case GL_UNDEFINED_APPLE:
1803       /* legal */
1804       break;
1805    default:
1806       _mesa_error(ctx, GL_INVALID_ENUM,
1807                   "glObjectUnpurgeable(name = 0x%x) invalid option: %d",
1808                   name, option);
1809       return 0;
1810    }
1811
1812    switch (objectType) {
1813    case GL_BUFFER_OBJECT_APPLE:
1814       return buffer_object_unpurgeable(ctx, name, option);
1815    case GL_TEXTURE:
1816       return texture_object_unpurgeable(ctx, name, option);
1817    case GL_RENDERBUFFER_EXT:
1818       return renderbuffer_unpurgeable(ctx, name, option);
1819    default:
1820       _mesa_error(ctx, GL_INVALID_ENUM,
1821                   "glObjectUnpurgeable(name = 0x%x) invalid type: %d",
1822                   name, objectType);
1823       return 0;
1824    }
1825 }
1826
1827
1828 static void
1829 get_buffer_object_parameteriv(struct gl_context *ctx, GLuint name,
1830                               GLenum pname, GLint *params)
1831 {
1832    struct gl_buffer_object *bufObj = _mesa_lookup_bufferobj(ctx, name);
1833    if (!bufObj) {
1834       _mesa_error(ctx, GL_INVALID_VALUE,
1835                   "glGetObjectParameteriv(name = 0x%x) invalid object", name);
1836       return;
1837    }
1838
1839    switch (pname) {
1840    case GL_PURGEABLE_APPLE:
1841       *params = bufObj->Purgeable;
1842       break;
1843    default:
1844       _mesa_error(ctx, GL_INVALID_ENUM,
1845                   "glGetObjectParameteriv(name = 0x%x) invalid enum: %d",
1846                   name, pname);
1847       break;
1848    }
1849 }
1850
1851
1852 static void
1853 get_renderbuffer_parameteriv(struct gl_context *ctx, GLuint name,
1854                              GLenum pname, GLint *params)
1855 {
1856    struct gl_renderbuffer *rb = _mesa_lookup_renderbuffer(ctx, name);
1857    if (!rb) {
1858       _mesa_error(ctx, GL_INVALID_VALUE,
1859                   "glObjectUnpurgeable(name = 0x%x)", name);
1860       return;
1861    }
1862
1863    switch (pname) {
1864    case GL_PURGEABLE_APPLE:
1865       *params = rb->Purgeable;
1866       break;
1867    default:
1868       _mesa_error(ctx, GL_INVALID_ENUM,
1869                   "glGetObjectParameteriv(name = 0x%x) invalid enum: %d",
1870                   name, pname);
1871       break;
1872    }
1873 }
1874
1875
1876 static void
1877 get_texture_object_parameteriv(struct gl_context *ctx, GLuint name,
1878                                GLenum pname, GLint *params)
1879 {
1880    struct gl_texture_object *texObj = _mesa_lookup_texture(ctx, name);
1881    if (!texObj) {
1882       _mesa_error(ctx, GL_INVALID_VALUE,
1883                   "glObjectUnpurgeable(name = 0x%x)", name);
1884       return;
1885    }
1886
1887    switch (pname) {
1888    case GL_PURGEABLE_APPLE:
1889       *params = texObj->Purgeable;
1890       break;
1891    default:
1892       _mesa_error(ctx, GL_INVALID_ENUM,
1893                   "glGetObjectParameteriv(name = 0x%x) invalid enum: %d",
1894                   name, pname);
1895       break;
1896    }
1897 }
1898
1899
1900 void GLAPIENTRY
1901 _mesa_GetObjectParameterivAPPLE(GLenum objectType, GLuint name, GLenum pname,
1902                                 GLint *params)
1903 {
1904    GET_CURRENT_CONTEXT(ctx);
1905
1906    if (name == 0) {
1907       _mesa_error(ctx, GL_INVALID_VALUE,
1908                   "glGetObjectParameteriv(name = 0x%x)", name);
1909       return;
1910    }
1911
1912    switch (objectType) {
1913    case GL_TEXTURE:
1914       get_texture_object_parameteriv(ctx, name, pname, params);
1915       break;
1916    case GL_BUFFER_OBJECT_APPLE:
1917       get_buffer_object_parameteriv(ctx, name, pname, params);
1918       break;
1919    case GL_RENDERBUFFER_EXT:
1920       get_renderbuffer_parameteriv(ctx, name, pname, params);
1921       break;
1922    default:
1923       _mesa_error(ctx, GL_INVALID_ENUM,
1924                   "glGetObjectParameteriv(name = 0x%x) invalid type: %d",
1925                   name, objectType);
1926    }
1927 }
1928
1929 #endif /* FEATURE_APPLE_object_purgeable */