Some initial RGB and RGBA floating point texture formats.
[mesa.git] / src / mesa / main / bufferobj.c
index 344cf06ec4d812e8d6a6a76b424771ca0a109726..25457183431bd061d91f43c9317ab4dc5f28b816 100644 (file)
 #include "bufferobj.h"
 
 
-struct gl_buffer_object {
-   GLint RefCount;
-   GLuint Name;
-   GLenum Target;
-   
-   GLenum usage;
-   GLenum access;
-   GLvoid * pointer;
-   GLuint  size;
-
-   void * data;
-};
-
-
 /**
  * Get the buffer object bound to the specified target in a GL context.
  *
@@ -69,16 +55,19 @@ buffer_object_get_target( GLcontext *ctx, GLenum target, const char * str )
 
    switch (target) {
       case GL_ARRAY_BUFFER_ARB:
-         bufObj = ctx->ArrayBuffer;
+         bufObj = ctx->Array.ArrayBufferObj;
          break;
       case GL_ELEMENT_ARRAY_BUFFER_ARB:
-         bufObj = ctx->ElementArrayBuffer;
+         bufObj = ctx->Array.ElementArrayBufferObj;
          break;
       default:
          _mesa_error(ctx, GL_INVALID_ENUM, "gl%s(target)", str);
-         break;
+         return NULL;
    }
-   
+
+   if (bufObj->Name == 0)
+      return NULL;
+
    return bufObj;
 }
 
@@ -107,12 +96,12 @@ buffer_object_subdata_range_good( GLcontext * ctx, GLenum target,
    struct gl_buffer_object *bufObj;
 
    if (size < 0) {
-      _mesa_error(ctx, GL_INVALID_VALUE, "gl%s(size < 0)", str);
+      _mesa_error(ctx, GL_INVALID_VALUE, "%s(size < 0)", str);
       return NULL;
    }
 
    if (offset < 0) {
-      _mesa_error(ctx, GL_INVALID_VALUE, "gl%s(offset < 0)", str);
+      _mesa_error(ctx, GL_INVALID_VALUE, "%s(offset < 0)", str);
       return NULL;
    }
 
@@ -121,14 +110,14 @@ buffer_object_subdata_range_good( GLcontext * ctx, GLenum target,
       return NULL;
    }
 
-   if ( (offset + size) > bufObj->size ) {
+   if ( (GLuint)(offset + size) > bufObj->Size ) {
       _mesa_error(ctx, GL_INVALID_VALUE,
-                 "gl%s(size + offset > buffer size)", str);
+                 "%s(size + offset > buffer size)", str);
       return NULL;
    }
 
-   if ( bufObj->pointer != NULL ) {
-      _mesa_error(ctx, GL_INVALID_OPERATION, "gl%s", str);
+   if ( bufObj->Pointer != NULL ) {
+      _mesa_error(ctx, GL_INVALID_OPERATION, "%s", str);
       return NULL;
    }
 
@@ -152,6 +141,21 @@ _mesa_new_buffer_object( GLcontext *ctx, GLuint name, GLenum target )
 }
 
 
+/**
+ * Delete a buffer object.
+ * 
+ * This function is intended to be called via
+ * \c dd_function_table::DeleteBufferObject.
+ */
+void
+_mesa_delete_buffer_object( GLcontext *ctx, struct gl_buffer_object *bufObj )
+{
+   if (bufObj->Data)
+      _mesa_free(bufObj->Data);
+   _mesa_free(bufObj);
+}
+
+
 /**
  * Initialize a buffer object to default values.
  */
@@ -220,14 +224,14 @@ _mesa_buffer_data( GLcontext *ctx, GLenum target, GLsizeiptrARB size,
 
    (void) target;
 
-   new_data = _mesa_realloc( bufObj->data, bufObj->size, size );
+   new_data = _mesa_realloc( bufObj->Data, bufObj->Size, size );
    if ( new_data != NULL ) {
-      bufObj->data = new_data;
-      bufObj->size = size;
-      bufObj->usage = usage;
+      bufObj->Data = (GLubyte *) new_data;
+      bufObj->Size = size;
+      bufObj->Usage = usage;
 
       if ( data != NULL ) {
-        _mesa_memcpy( bufObj->data, data, size );
+        _mesa_memcpy( bufObj->Data, data, size );
       }
    }
 }
@@ -256,9 +260,9 @@ _mesa_buffer_subdata( GLcontext *ctx, GLenum target, GLintptrARB offset,
                      GLsizeiptrARB size, const GLvoid * data,
                      struct gl_buffer_object * bufObj )
 {
-   if ( (bufObj->data != NULL)
-       && ((size + offset) <= bufObj->size) ) {
-      _mesa_memcpy( (GLubyte *) bufObj->data + offset, data, size );
+   if ( (bufObj->Data != NULL)
+       && ((GLuint)(size + offset) <= bufObj->Size) ) {
+      _mesa_memcpy( (GLubyte *) bufObj->Data + offset, data, size );
    }
 }
 
@@ -286,9 +290,9 @@ _mesa_buffer_get_subdata( GLcontext *ctx, GLenum target, GLintptrARB offset,
                          GLsizeiptrARB size, GLvoid * data,
                          struct gl_buffer_object * bufObj )
 {
-   if ( (bufObj->data != NULL)
-       && ((size + offset) <= bufObj->size) ) {
-      _mesa_memcpy( data, (GLubyte *) bufObj->data + offset, size );
+   if ( (bufObj->Data != NULL)
+       && ((GLuint)(size + offset) <= bufObj->Size) ) {
+      _mesa_memcpy( data, (GLubyte *) bufObj->Data + offset, size );
    }
 }
 
@@ -313,11 +317,45 @@ void *
 _mesa_buffer_map( GLcontext *ctx, GLenum target, GLenum access,
                  struct gl_buffer_object * bufObj )
 {
-   return bufObj->data;
+   return bufObj->Data;
 }
 
 
+/**
+ * Initialize the state associated with buffer objects
+ */
 void
+_mesa_init_buffer_objects( GLcontext *ctx )
+{
+   GLuint i;
+
+   ctx->Array.NullBufferObj = _mesa_new_buffer_object(ctx, 0, 0);
+   ctx->Array.ArrayBufferObj = ctx->Array.NullBufferObj;
+   ctx->Array.ElementArrayBufferObj = ctx->Array.NullBufferObj;
+
+   /* Vertex array buffers */
+   ctx->Array.Vertex.BufferObj = ctx->Array.NullBufferObj;
+   ctx->Array.Normal.BufferObj = ctx->Array.NullBufferObj;
+   ctx->Array.Color.BufferObj = ctx->Array.NullBufferObj;
+   ctx->Array.SecondaryColor.BufferObj = ctx->Array.NullBufferObj;
+   ctx->Array.FogCoord.BufferObj = ctx->Array.NullBufferObj;
+   ctx->Array.Index.BufferObj = ctx->Array.NullBufferObj;
+   for (i = 0; i < MAX_TEXTURE_UNITS; i++) {
+      ctx->Array.TexCoord[i].BufferObj = ctx->Array.NullBufferObj;
+   }
+   ctx->Array.EdgeFlag.BufferObj = ctx->Array.NullBufferObj;
+   for (i = 0; i < VERT_ATTRIB_MAX; i++) {
+      ctx->Array.VertexAttrib[i].BufferObj = ctx->Array.NullBufferObj;
+   }
+}
+
+
+
+/**********************************************************************/
+/* API Functions                                                      */
+/**********************************************************************/
+
+void GLAPIENTRY
 _mesa_BindBufferARB(GLenum target, GLuint buffer)
 {
    GET_CURRENT_CONTEXT(ctx);
@@ -333,22 +371,16 @@ _mesa_BindBufferARB(GLenum target, GLuint buffer)
     * Get pointer to new buffer object (newBufObj)
     */
    if ( buffer == 0 ) {
-      newBufObj = NULL;
+      /* The spec says there's not a buffer object named 0, but we use
+       * one internally because it simplifies things.
+       */
+      newBufObj = ctx->Array.NullBufferObj;
    }
    else {
       /* non-default buffer object */
       const struct _mesa_HashTable *hash = ctx->Shared->BufferObjects;
       newBufObj = (struct gl_buffer_object *) _mesa_HashLookup(hash, buffer);
-      if ( newBufObj != NULL ) {
-         /* error checking */
-         if (newBufObj->Target != 0 && newBufObj->Target != target) {
-            /* the named buffer object's target doesn't match the target */
-            _mesa_error( ctx, GL_INVALID_OPERATION,
-                         "glBindBufferARB(wrong target)" );
-            return;
-         }
-      }
-      else {
+      if (!newBufObj) {
          /* if this is a new buffer object id, allocate a buffer object now */
         newBufObj = (*ctx->Driver.NewBufferObject)(ctx, buffer, target);
          if (!newBufObj) {
@@ -357,16 +389,15 @@ _mesa_BindBufferARB(GLenum target, GLuint buffer)
          }
          _mesa_save_buffer_object(ctx, newBufObj);
       }
-      newBufObj->Target = target;
       newBufObj->RefCount++;
    }
    
    switch (target) {
       case GL_ARRAY_BUFFER_ARB:
-         ctx->ArrayBuffer = newBufObj;
+         ctx->Array.ArrayBufferObj = newBufObj;
          break;
       case GL_ELEMENT_ARRAY_BUFFER_ARB:
-         ctx->ElementArrayBuffer = newBufObj;
+         ctx->Array.ElementArrayBufferObj = newBufObj;
          break;
    }
 
@@ -393,11 +424,11 @@ _mesa_BindBufferARB(GLenum target, GLuint buffer)
  * \param n      Number of buffer objects to delete.
  * \param buffer Array of \c n buffer object IDs.
  */
-void
+void GLAPIENTRY
 _mesa_DeleteBuffersARB(GLsizei n, const GLuint *ids)
 {
    GET_CURRENT_CONTEXT(ctx);
-   unsigned i;
+   GLsizei i;
    ASSERT_OUTSIDE_BEGIN_END(ctx);
 
    if (n < 0) {
@@ -412,21 +443,44 @@ _mesa_DeleteBuffersARB(GLsizei n, const GLuint *ids)
          struct gl_buffer_object *bufObj = (struct gl_buffer_object *)
             _mesa_HashLookup(ctx->Shared->BufferObjects, ids[i]);
          if (bufObj) {
-            if ( (bufObj->Target == GL_ARRAY_BUFFER_ARB)
-                || (bufObj->Target == GL_ELEMENT_ARRAY_BUFFER_ARB) ) {
-              _mesa_BindBufferARB( bufObj->Target, 0 );
+            /* unbind any vertex pointers bound to this buffer */
+            GLuint j;
+
+            ASSERT(bufObj->Name != 0);
+
+            if (ctx->Array.Vertex.BufferObj == bufObj)
+               ctx->Array.Vertex.BufferObj = ctx->Array.NullBufferObj;
+            if (ctx->Array.Normal.BufferObj == bufObj)
+               ctx->Array.Normal.BufferObj = ctx->Array.NullBufferObj;
+            if (ctx->Array.Color.BufferObj == bufObj)
+               ctx->Array.Color.BufferObj = ctx->Array.NullBufferObj;
+            if (ctx->Array.SecondaryColor.BufferObj == bufObj)
+               ctx->Array.SecondaryColor.BufferObj = ctx->Array.NullBufferObj;
+            if (ctx->Array.FogCoord.BufferObj == bufObj)
+               ctx->Array.FogCoord.BufferObj = ctx->Array.NullBufferObj;
+            if (ctx->Array.Index.BufferObj == bufObj)
+               ctx->Array.Index.BufferObj = ctx->Array.NullBufferObj;
+            if (ctx->Array.EdgeFlag.BufferObj == bufObj)
+               ctx->Array.EdgeFlag.BufferObj = ctx->Array.NullBufferObj;
+            for (j = 0; j < MAX_TEXTURE_UNITS; j++) {
+               if (ctx->Array.TexCoord[j].BufferObj == bufObj)
+                  ctx->Array.TexCoord[j].BufferObj = ctx->Array.NullBufferObj;
+            }
+            for (j = 0; j < VERT_ATTRIB_MAX; j++) {
+               if (ctx->Array.VertexAttrib[j].BufferObj == bufObj)
+                  ctx->Array.VertexAttrib[j].BufferObj = ctx->Array.NullBufferObj;
             }
-           else if (bufObj->Target == 0) {
-              /* The buffer object is not bound.
-               */
-           }
-            else {
-               _mesa_problem(ctx, "bad target in glDeleteBufferARB");
-               return;
+
+            /* if deleting bound buffers, rebind to zero */
+            if (ctx->Array.ArrayBufferObj == bufObj) {
+              _mesa_BindBufferARB( GL_ARRAY_BUFFER_ARB, 0 );
             }
+            if (ctx->Array.ElementArrayBufferObj == bufObj) {
+              _mesa_BindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, 0 );
+            }
+
             bufObj->RefCount--;
             if (bufObj->RefCount <= 0) {
-               ASSERT(bufObj->Name != 0);
                _mesa_remove_buffer_object(ctx, bufObj);
                ASSERT(ctx->Driver.DeleteBuffer);
                (*ctx->Driver.DeleteBuffer)(ctx, bufObj);
@@ -445,7 +499,7 @@ _mesa_DeleteBuffersARB(GLsizei n, const GLuint *ids)
  * \param n       Number of IDs to generate.
  * \param buffer  Array of \c n locations to store the IDs.
  */
-void
+void GLAPIENTRY
 _mesa_GenBuffersARB(GLsizei n, GLuint *buffer)
 {
    GET_CURRENT_CONTEXT(ctx);
@@ -475,7 +529,7 @@ _mesa_GenBuffersARB(GLsizei n, GLuint *buffer)
       GLuint name = first + i;
       GLenum target = 0;
       bufObj = (*ctx->Driver.NewBufferObject)( ctx, name, target );
-      if ( bufObj != NULL ) {
+      if (!bufObj) {
          _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenBuffersARB");
          return;
       }
@@ -494,7 +548,7 @@ _mesa_GenBuffersARB(GLsizei n, GLuint *buffer)
  * \return  \c GL_TRUE if \c id is the name of a buffer object, 
  *          \c GL_FALSE otherwise.
  */
-GLboolean
+GLboolean GLAPIENTRY
 _mesa_IsBufferARB(GLuint id)
 {
    struct gl_buffer_object * bufObj;
@@ -512,7 +566,7 @@ _mesa_IsBufferARB(GLuint id)
 }
 
 
-void
+void GLAPIENTRY
 _mesa_BufferDataARB(GLenum target, GLsizeiptrARB size,
                     const GLvoid * data, GLenum usage)
 {
@@ -548,6 +602,11 @@ _mesa_BufferDataARB(GLenum target, GLsizeiptrARB size,
       return;
    }
    
+   if (bufObj->Pointer) {
+      _mesa_error(ctx, GL_INVALID_OPERATION, "glBufferDataARB(buffer is mapped)" );
+      return;
+   }  
+
    ASSERT(ctx->Driver.BufferData);
 
    /* Give the buffer object to the driver!  <data> may be null! */
@@ -555,7 +614,7 @@ _mesa_BufferDataARB(GLenum target, GLsizeiptrARB size,
 }
 
 
-void
+void GLAPIENTRY
 _mesa_BufferSubDataARB(GLenum target, GLintptrARB offset,
                        GLsizeiptrARB size, const GLvoid * data)
 {
@@ -564,18 +623,23 @@ _mesa_BufferSubDataARB(GLenum target, GLintptrARB offset,
    ASSERT_OUTSIDE_BEGIN_END(ctx);
 
    bufObj = buffer_object_subdata_range_good( ctx, target, offset, size,
-                                              "glBufferSubDataARB" );
+                                              "BufferSubDataARB" );
    if (!bufObj) {
       _mesa_error(ctx, GL_INVALID_OPERATION, "glBufferSubDataARB" );
       return;
    }
 
+   if (bufObj->Pointer) {
+      _mesa_error(ctx, GL_INVALID_OPERATION, "glBufferSubDataARB(buffer is mapped)" );
+      return;
+   }  
+
    ASSERT(ctx->Driver.BufferSubData);
    (*ctx->Driver.BufferSubData)( ctx, target, offset, size, data, bufObj );
 }
 
 
-void
+void GLAPIENTRY
 _mesa_GetBufferSubDataARB(GLenum target, GLintptrARB offset,
                           GLsizeiptrARB size, void * data)
 {
@@ -584,17 +648,23 @@ _mesa_GetBufferSubDataARB(GLenum target, GLintptrARB offset,
    ASSERT_OUTSIDE_BEGIN_END(ctx);
 
    bufObj = buffer_object_subdata_range_good( ctx, target, offset, size,
-                                              "glGetBufferSubDataARB" );
+                                              "GetBufferSubDataARB" );
    if (!bufObj) {
       _mesa_error(ctx, GL_INVALID_OPERATION, "glGetBufferSubDataARB" );
       return;
    }
+
+   if (bufObj->Pointer) {
+      _mesa_error(ctx, GL_INVALID_OPERATION, "glGetBufferSubDataARB(buffer is mapped)" );
+      return;
+   }  
+
    ASSERT(ctx->Driver.GetBufferSubData);
    (*ctx->Driver.GetBufferSubData)( ctx, target, offset, size, data, bufObj );
 }
 
 
-void *
+void * GLAPIENTRY
 _mesa_MapBufferARB(GLenum target, GLenum access)
 {
    GET_CURRENT_CONTEXT(ctx);
@@ -618,22 +688,24 @@ _mesa_MapBufferARB(GLenum target, GLenum access)
       return NULL;
    }
 
-   if ( bufObj->pointer != NULL ) {
-      _mesa_error(ctx, GL_INVALID_OPERATION, "glMapBufferARB");
+   if ( bufObj->Pointer != NULL ) {
+      _mesa_error(ctx, GL_INVALID_OPERATION, "glMapBufferARB(already mapped)");
       return NULL;
    }
 
    ASSERT(ctx->Driver.MapBuffer);
-   bufObj->pointer = (*ctx->Driver.MapBuffer)( ctx, target, access, bufObj );
-   if ( bufObj->pointer == NULL ) {
+   bufObj->Pointer = (*ctx->Driver.MapBuffer)( ctx, target, access, bufObj );
+   if ( bufObj->Pointer == NULL ) {
       _mesa_error(ctx, GL_OUT_OF_MEMORY, "glMapBufferARB(access)");
    }
 
-   return bufObj->pointer;
+   bufObj->Access = access;
+
+   return bufObj->Pointer;
 }
 
 
-GLboolean
+GLboolean GLAPIENTRY
 _mesa_UnmapBufferARB(GLenum target)
 {
    GET_CURRENT_CONTEXT(ctx);
@@ -641,14 +713,13 @@ _mesa_UnmapBufferARB(GLenum target)
    GLboolean status = GL_TRUE;
    ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
 
-
    bufObj = buffer_object_get_target( ctx, target, "UnmapBufferARB" );
    if ( bufObj == NULL ) {
-      _mesa_error(ctx, GL_INVALID_OPERATION, "glBufferSubDataARB" );
+      _mesa_error(ctx, GL_INVALID_OPERATION, "glUnmapBufferARB" );
       return GL_FALSE;
    }
 
-   if ( bufObj->pointer == NULL ) {
+   if ( bufObj->Pointer == NULL ) {
       _mesa_error(ctx, GL_INVALID_OPERATION, "glUnmapBufferARB");
       return GL_FALSE;
    }
@@ -657,13 +728,14 @@ _mesa_UnmapBufferARB(GLenum target)
       status = (*ctx->Driver.UnmapBuffer)( ctx, target, bufObj );
    }
 
-   bufObj->pointer = NULL;
+   bufObj->Access = GL_READ_WRITE_ARB; /* initial value, OK? */
+   bufObj->Pointer = NULL;
 
    return status;
 }
 
 
-void
+void GLAPIENTRY
 _mesa_GetBufferParameterivARB(GLenum target, GLenum pname, GLint *params)
 {
    GET_CURRENT_CONTEXT(ctx);
@@ -678,16 +750,16 @@ _mesa_GetBufferParameterivARB(GLenum target, GLenum pname, GLint *params)
 
    switch (pname) {
       case GL_BUFFER_SIZE_ARB:
-         *params = bufObj->size;
+         *params = bufObj->Size;
          break;
       case GL_BUFFER_USAGE_ARB:
-         *params = bufObj->usage;
+         *params = bufObj->Usage;
          break;
       case GL_BUFFER_ACCESS_ARB:
-         *params = bufObj->access;
+         *params = bufObj->Access;
          break;
       case GL_BUFFER_MAPPED_ARB:
-         *params = (bufObj->pointer != NULL);
+         *params = (bufObj->Pointer != NULL);
          break;
       default:
          _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferParameterivARB(pname)");
@@ -696,7 +768,7 @@ _mesa_GetBufferParameterivARB(GLenum target, GLenum pname, GLint *params)
 }
 
 
-void
+void GLAPIENTRY
 _mesa_GetBufferPointervARB(GLenum target, GLenum pname, GLvoid **params)
 {
    GET_CURRENT_CONTEXT(ctx);
@@ -714,5 +786,5 @@ _mesa_GetBufferPointervARB(GLenum target, GLenum pname, GLvoid **params)
       return;
    }
 
-   *params = bufObj->pointer;
+   *params = bufObj->Pointer;
 }