mesa: implement GL_ARB_map_buffer_range
authorBrian Paul <brianp@vmware.com>
Mon, 8 Jun 2009 23:02:36 +0000 (17:02 -0600)
committerBrian Paul <brianp@vmware.com>
Mon, 8 Jun 2009 23:02:36 +0000 (17:02 -0600)
Only enabled for software drivers at this point.

Note that the gl_buffer_object::Access enum field has been replaced by
a gl_buffer_object::AccessFlags bitfield.  The new field is a mask of
the GL_MAP_x_BIT flags which is a superset of the old GL_READ_ONLY,
GL_WRITE_ONLY and GL_READ_WRITE modes.  When we query GL_BUFFER_ACCESS_ARB
we translate the bitfield into the conventional enum values.

src/mesa/drivers/common/driverfuncs.c
src/mesa/main/api_exec.c
src/mesa/main/bufferobj.c
src/mesa/main/bufferobj.h
src/mesa/main/dlist.c
src/mesa/main/extensions.c
src/mesa/main/mfeatures.h
src/mesa/main/mtypes.h

index 56abdbdfcb4f56e25036e064180d0bd37d084ec0..624ace058aa4ef75681673ba696d0a21b68f7c36 100644 (file)
@@ -213,6 +213,11 @@ _mesa_init_driver_functions(struct dd_function_table *driver)
    driver->UnmapBuffer = _mesa_buffer_unmap;
 #endif
 
+#if FEATURE_ARB_map_buffer_range
+   driver->MapBufferRange = _mesa_buffer_map_range;
+   driver->FlushMappedBufferRange = _mesa_buffer_flush_mapped_range;
+#endif
+
 #if FEATURE_EXT_framebuffer_object
    driver->NewFramebuffer = _mesa_new_framebuffer;
    driver->NewRenderbuffer = _mesa_new_soft_renderbuffer;
index c714d177a2a407d6ae52bbd983cd5eda4fdb9afd..2cc9a4323b20639deceb58b5b2b7693472e66387 100644 (file)
@@ -895,7 +895,11 @@ _mesa_init_exec_table(struct _glapi_table *exec)
    SET_RenderbufferStorageMultisample(exec, _mesa_RenderbufferStorageMultisample);
 #endif
 
+#if FEATURE_ARB_map_buffer_range
+   SET_MapBufferRange(exec, _mesa_MapBufferRange);
+   SET_FlushMappedBufferRange(exec, _mesa_FlushMappedBufferRange);
+#endif
+
    /* GL_ARB_copy_buffer */
    SET_CopyBufferSubData(exec, _mesa_CopyBufferSubData);
 }
-
index 3e011ef5b238eeccf5dcfc1a3c9f27db48622183..6b22881072020b74873deb0517acb6d5dfd63206 100644 (file)
@@ -40,9 +40,9 @@
 
 
 #ifdef FEATURE_OES_mapbuffer
-#define DEFAULT_ACCESS GL_WRITE_ONLY;
+#define DEFAULT_ACCESS GL_MAP_WRITE_BIT
 #else
-#define DEFAULT_ACCESS GL_READ_WRITE;
+#define DEFAULT_ACCESS (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)
 #endif
 
 
@@ -95,6 +95,24 @@ get_buffer(GLcontext *ctx, GLenum target)
 }
 
 
+/**
+ * Convert a GLbitfield describing the mapped buffer access flags
+ * into one of GL_READ_WRITE, GL_READ_ONLY, or GL_WRITE_ONLY.
+ */
+static GLenum
+simplified_access_mode(GLbitfield access)
+{
+   const GLbitfield rwFlags = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT;
+   if ((access & rwFlags) == rwFlags)
+      return GL_READ_WRITE;
+   if ((access & GL_MAP_READ_BIT) == GL_MAP_READ_BIT)
+      return GL_READ_ONLY;
+   if ((access & GL_MAP_WRITE_BIT) == GL_MAP_WRITE_BIT)
+      return GL_WRITE_ONLY;
+   return GL_READ_WRITE; /* this should never happen, but no big deal */
+}
+
+
 /**
  * Tests the subdata range parameters and sets the GL error code for
  * \c glBufferSubDataARB and \c glGetBufferSubDataARB.
@@ -271,7 +289,7 @@ _mesa_initialize_buffer_object( struct gl_buffer_object *obj,
    obj->RefCount = 1;
    obj->Name = name;
    obj->Usage = GL_STATIC_DRAW_ARB;
-   obj->Access = DEFAULT_ACCESS;
+   obj->AccessFlags = DEFAULT_ACCESS;
 }
 
 
@@ -409,6 +427,43 @@ _mesa_buffer_map( GLcontext *ctx, GLenum target, GLenum access,
 }
 
 
+/**
+ * Default fallback for \c dd_function_table::MapBufferRange().
+ * Called via glMapBufferRange().
+ */
+void *
+_mesa_buffer_map_range( GLcontext *ctx, GLenum target, GLintptr offset,
+                        GLsizeiptr length, GLbitfield access,
+                        struct gl_buffer_object *bufObj )
+{
+   (void) ctx;
+   (void) target;
+   (void) access;
+   (void) length;
+   assert(!bufObj->Pointer);
+   /* Just return a direct pointer to the data */
+   return bufObj->Data + offset;
+}
+
+
+/**
+ * Default fallback for \c dd_function_table::FlushMappedBufferRange().
+ * Called via glFlushMappedBufferRange().
+ */
+void
+_mesa_buffer_flush_mapped_range( GLcontext *ctx, GLenum target, 
+                                 GLintptr offset, GLsizeiptr length,
+                                 struct gl_buffer_object *obj )
+{
+   (void) ctx;
+   (void) target;
+   (void) offset;
+   (void) length;
+   (void) obj;
+   /* no-op */
+}
+
+
 /**
  * Default callback for \c dd_function_table::MapBuffer().
  *
@@ -845,7 +900,7 @@ _mesa_DeleteBuffersARB(GLsizei n, const GLuint *ids)
          if (bufObj->Pointer) {
             /* if mapped, unmap it now */
             ctx->Driver.UnmapBuffer(ctx, 0, bufObj);
-            bufObj->Access = DEFAULT_ACCESS;
+            bufObj->AccessFlags = DEFAULT_ACCESS;
             bufObj->Pointer = NULL;
          }
 
@@ -1004,7 +1059,7 @@ _mesa_BufferDataARB(GLenum target, GLsizeiptrARB size,
    if (bufObj->Pointer) {
       /* Unmap the existing buffer.  We'll replace it now.  Not an error. */
       ctx->Driver.UnmapBuffer(ctx, target, bufObj);
-      bufObj->Access = DEFAULT_ACCESS;
+      bufObj->AccessFlags = DEFAULT_ACCESS;
       bufObj->Pointer = NULL;
    }  
 
@@ -1071,13 +1126,18 @@ _mesa_MapBufferARB(GLenum target, GLenum access)
 {
    GET_CURRENT_CONTEXT(ctx);
    struct gl_buffer_object * bufObj;
+   GLbitfield accessFlags;
    ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, NULL);
 
    switch (access) {
       case GL_READ_ONLY_ARB:
+         accessFlags = GL_MAP_READ_BIT;
+         break;
       case GL_WRITE_ONLY_ARB:
+         accessFlags = GL_MAP_WRITE_BIT;
+         break;
       case GL_READ_WRITE_ARB:
-         /* OK */
+         accessFlags = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT;
          break;
       default:
          _mesa_error(ctx, GL_INVALID_ENUM, "glMapBufferARB(access)");
@@ -1104,7 +1164,10 @@ _mesa_MapBufferARB(GLenum target, GLenum access)
       _mesa_error(ctx, GL_OUT_OF_MEMORY, "glMapBufferARB(access)");
    }
 
-   bufObj->Access = access;
+   bufObj->AccessFlags = accessFlags;
+   bufObj->Offset = 0;
+   bufObj->Length = bufObj->Size;
+
    if (access == GL_WRITE_ONLY_ARB || access == GL_READ_WRITE_ARB)
       bufObj->Written = GL_TRUE;
 
@@ -1146,7 +1209,7 @@ _mesa_UnmapBufferARB(GLenum target)
    }
 
 #ifdef VBO_DEBUG
-   if (bufObj->Access == GL_WRITE_ONLY_ARB) {
+   if (bufObj->AccessFlags & GL_MAP_WRITE_BIT) {
       GLuint i, unchanged = 0;
       GLubyte *b = (GLubyte *) bufObj->Pointer;
       GLint pos = -1;
@@ -1166,8 +1229,10 @@ _mesa_UnmapBufferARB(GLenum target)
 #endif
 
    status = ctx->Driver.UnmapBuffer( ctx, target, bufObj );
-   bufObj->Access = DEFAULT_ACCESS;
+   bufObj->AccessFlags = DEFAULT_ACCESS;
    bufObj->Pointer = NULL;
+   bufObj->Offset = 0;
+   bufObj->Length = 0;
 
    return status;
 }
@@ -1198,7 +1263,7 @@ _mesa_GetBufferParameterivARB(GLenum target, GLenum pname, GLint *params)
          *params = bufObj->Usage;
          break;
       case GL_BUFFER_ACCESS_ARB:
-         *params = bufObj->Access;
+         *params = simplified_access_mode(bufObj->AccessFlags);
          break;
       case GL_BUFFER_MAPPED_ARB:
          *params = (bufObj->Pointer != NULL);
@@ -1315,3 +1380,153 @@ _mesa_CopyBufferSubData(GLenum readTarget, GLenum writeTarget,
    ctx->Driver.CopyBufferSubData(ctx, src, dst, readOffset, writeOffset, size);
 }
 
+
+/**
+ * See GL_ARB_map_buffer_range spec
+ */
+void * GLAPIENTRY
+_mesa_MapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length,
+                     GLbitfield access)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   struct gl_buffer_object *bufObj;
+   ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, NULL);
+
+   if (!ctx->Extensions.ARB_map_buffer_range) {
+      _mesa_error(ctx, GL_INVALID_OPERATION,
+                  "glMapBufferRange(extension not supported)");
+      return NULL;
+   }
+
+   if (offset < 0) {
+      _mesa_error(ctx, GL_INVALID_VALUE,
+                  "glMapBufferRange(offset = %ld)", offset);
+      return NULL;
+   }
+
+   if (length < 0) {
+      _mesa_error(ctx, GL_INVALID_VALUE,
+                  "glMapBufferRange(length = %ld)", length);
+      return NULL;
+   }
+
+   if ((access & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)) == 0) {
+      _mesa_error(ctx, GL_INVALID_OPERATION,
+                  "glMapBufferRange(access indicates neither read or write)");
+      return NULL;
+   }
+
+   if (access & GL_MAP_READ_BIT) {
+      if ((access & GL_MAP_INVALIDATE_RANGE_BIT) ||
+          (access & GL_MAP_INVALIDATE_BUFFER_BIT) ||
+          (access & GL_MAP_UNSYNCHRONIZED_BIT)) {
+         _mesa_error(ctx, GL_INVALID_OPERATION,
+                     "glMapBufferRange(invalid access flags)");
+         return NULL;
+      }
+   }
+
+   if ((access & GL_MAP_FLUSH_EXPLICIT_BIT) &&
+       ((access & GL_MAP_WRITE_BIT) == 0)) {
+      _mesa_error(ctx, GL_INVALID_OPERATION,
+                  "glMapBufferRange(invalid access flags)");
+      return NULL;
+   }
+
+   bufObj = get_buffer(ctx, target);
+   if (!bufObj || bufObj->Name == 0) {
+      _mesa_error(ctx, GL_INVALID_ENUM,
+                  "glMapBufferRange(target = 0x%x)", target);
+      return NULL;
+   }
+
+   if (offset + length > bufObj->Size) {
+      _mesa_error(ctx, GL_INVALID_VALUE,
+                  "glMapBufferRange(offset + length > size)");
+      return NULL;
+   }
+
+   if (bufObj->Pointer) {
+      _mesa_error(ctx, GL_INVALID_OPERATION,
+                  "glMapBufferRange(buffer already mapped)");
+      return NULL;
+   }
+      
+   ASSERT(ctx->Driver.MapBufferRange);
+   bufObj->Pointer = ctx->Driver.MapBufferRange(ctx, target, offset, length,
+                                                access, bufObj);
+
+   bufObj->Offset = offset;
+   bufObj->Length = length;
+   bufObj->AccessFlags = access;
+
+   return bufObj->Pointer;
+}
+
+
+/**
+ * See GL_ARB_map_buffer_range spec
+ */
+void GLAPIENTRY
+_mesa_FlushMappedBufferRange(GLenum target, GLintptr offset, GLsizeiptr length)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   struct gl_buffer_object *bufObj;
+   ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+   if (!ctx->Extensions.ARB_map_buffer_range) {
+      _mesa_error(ctx, GL_INVALID_OPERATION,
+                  "glMapBufferRange(extension not supported)");
+      return;
+   }
+
+   if (offset < 0) {
+      _mesa_error(ctx, GL_INVALID_VALUE,
+                  "glMapBufferRange(offset = %ld)", offset);
+      return;
+   }
+
+   if (length < 0) {
+      _mesa_error(ctx, GL_INVALID_VALUE,
+                  "glMapBufferRange(length = %ld)", length);
+      return;
+   }
+
+   bufObj = get_buffer(ctx, target);
+   if (!bufObj) {
+      _mesa_error(ctx, GL_INVALID_ENUM,
+                  "glMapBufferRange(target = 0x%x)", target);
+      return;
+   }
+
+   if (bufObj->Name == 0) {
+      _mesa_error(ctx, GL_INVALID_OPERATION,
+                  "glMapBufferRange(current buffer is 0)");
+      return;
+   }
+
+   if (!bufObj->Pointer) {
+      /* buffer is not mapped */
+      _mesa_error(ctx, GL_INVALID_OPERATION,
+                  "glMapBufferRange(buffer is not mapped)");
+      return;
+   }
+
+   if ((bufObj->AccessFlags & GL_MAP_FLUSH_EXPLICIT_BIT) == 0) {
+      _mesa_error(ctx, GL_INVALID_OPERATION,
+                  "glMapBufferRange(GL_MAP_FLUSH_EXPLICIT_BIT not set)");
+      return;
+   }
+
+   if (offset + length > bufObj->Length) {
+      _mesa_error(ctx, GL_INVALID_VALUE,
+             "glMapBufferRange(offset %ld + length %ld > mapped length %ld)",
+             offset, length, bufObj->Length);
+      return;
+   }
+
+   ASSERT(bufObj->AccessFlags & GL_MAP_WRITE_BIT);
+
+   if (ctx->Driver.FlushMappedBufferRange)
+      ctx->Driver.FlushMappedBufferRange(ctx, target, offset, length, bufObj);
+}
index 79c027aa4d48321d7fb768967451866c54ae5618..a8e2dcef933b9e55e574efbd7cfadc46611e887c 100644 (file)
@@ -79,6 +79,16 @@ extern void *
 _mesa_buffer_map( GLcontext *ctx, GLenum target, GLenum access,
                  struct gl_buffer_object * bufObj );
 
+extern void *
+_mesa_buffer_map_range( GLcontext *ctx, GLenum target, GLintptr offset,
+                        GLsizeiptr length, GLbitfield access,
+                        struct gl_buffer_object *bufObj );
+
+extern void
+_mesa_buffer_flush_mapped_range( GLcontext *ctx, GLenum target, 
+                                 GLintptr offset, GLsizeiptr length,
+                                 struct gl_buffer_object *obj );
+
 extern GLboolean
 _mesa_buffer_unmap( GLcontext *ctx, GLenum target,
                     struct gl_buffer_object * bufObj );
@@ -167,4 +177,11 @@ _mesa_CopyBufferSubData(GLenum readTarget, GLenum writeTarget,
                         GLintptr readOffset, GLintptr writeOffset,
                         GLsizeiptr size);
 
+extern void * GLAPIENTRY
+_mesa_MapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length,
+                     GLbitfield access);
+
+extern void GLAPIENTRY
+_mesa_FlushMappedBufferRange(GLenum target, GLintptr offset, GLsizeiptr length);
+
 #endif
index d3c1717a50644d0e88df3b7ff45d3a2975c6c673..a9c2c306ec3f2f6695b41d29735c2f2c0c74f824 100644 (file)
@@ -8239,6 +8239,12 @@ _mesa_init_dlist_table(struct _glapi_table *table)
    SET_ProgramLocalParameters4fvEXT(table, save_ProgramLocalParameters4fvEXT);
 #endif
 
+   /* ARB 50. GL_ARB_map_buffer_range */
+#if FEATURE_ARB_map_buffer_range
+   SET_MapBufferRange(table, _mesa_MapBufferRange); /* no dlist save */
+   SET_FlushMappedBufferRange(table, _mesa_FlushMappedBufferRange); /* no dl */
+#endif
+
    /* ARB 59. GL_ARB_copy_buffer */
    SET_CopyBufferSubData(table, _mesa_CopyBufferSubData); /* no dlist save */
 }
index 490110a6d245089850516e005d817aacff6f7156..0d708fc246c0d0bf2ae3a712a93f6b4087264f00 100644 (file)
@@ -1,8 +1,9 @@
 /*
  * Mesa 3-D graphics library
- * Version:  7.3
+ * Version:  7.6
  *
  * Copyright (C) 1999-2008  Brian Paul   All Rights Reserved.
+ * Copyright (C) 2009  VMware, Inc.  All Rights Reserved.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -53,6 +54,7 @@ static const struct {
    { OFF, "GL_ARB_framebuffer_object",         F(ARB_framebuffer_object) },
    { OFF, "GL_ARB_half_float_pixel",           F(ARB_half_float_pixel) },
    { OFF, "GL_ARB_imaging",                    F(ARB_imaging) },
+   { OFF, "GL_ARB_map_buffer_range",           F(ARB_map_buffer_range) },
    { ON,  "GL_ARB_multisample",                F(ARB_multisample) },
    { OFF, "GL_ARB_multitexture",               F(ARB_multitexture) },
    { OFF, "GL_ARB_occlusion_query",            F(ARB_occlusion_query) },
@@ -199,6 +201,7 @@ _mesa_enable_sw_extensions(GLcontext *ctx)
 #endif
    ctx->Extensions.ARB_half_float_pixel = GL_TRUE;
    ctx->Extensions.ARB_imaging = GL_TRUE;
+   ctx->Extensions.ARB_map_buffer_range = GL_TRUE;
    ctx->Extensions.ARB_multitexture = GL_TRUE;
 #if FEATURE_ARB_occlusion_query
    ctx->Extensions.ARB_occlusion_query = GL_TRUE;
index 62c3ead3e1bb3eeecdec673b8dfbd0e3abeffe86..ef973314e35d265c11147fc741cc756ebd510289 100644 (file)
@@ -61,6 +61,7 @@
 #define FEATURE_ARB_occlusion_query  _HAVE_FULL_GL
 #define FEATURE_ARB_fragment_program  _HAVE_FULL_GL
 #define FEATURE_ARB_framebuffer_object  _HAVE_FULL_GL
+#define FEATURE_ARB_map_buffer_range  _HAVE_FULL_GL
 #define FEATURE_ARB_pixel_buffer_object  _HAVE_FULL_GL
 #define FEATURE_ARB_vertex_buffer_object  _HAVE_FULL_GL
 #define FEATURE_ARB_vertex_program  _HAVE_FULL_GL
index 46020eb210e7190200731800679d7e148e60422f..71a85a9db817363fd542570bafe51c7be8035e48 100644 (file)
@@ -1503,7 +1503,7 @@ struct gl_buffer_object
    GLubyte *Data;       /**< Location of storage either in RAM or VRAM. */
    /** Fields describing a mapped buffer */
    /*@{*/
-   GLenum Access;       /**< GL_READ_ONLY_ARB, GL_WRITE_ONLY_ARB, etc. */
+   GLbitfield AccessFlags; /**< Mask of GL_MAP_x_BIT flags */
    GLvoid *Pointer;     /**< User-space address of mapping */
    GLintptr Offset;     /**< Mapped offset */
    GLsizeiptr Length;   /**< Mapped length */
@@ -2443,6 +2443,7 @@ struct gl_extensions
    GLboolean ARB_framebuffer_object;
    GLboolean ARB_half_float_pixel;
    GLboolean ARB_imaging;
+   GLboolean ARB_map_buffer_range;
    GLboolean ARB_multisample;
    GLboolean ARB_multitexture;
    GLboolean ARB_occlusion_query;