[cogl/wip/cogl-1.14: 59/177] Add cogl_buffer_map_range()



commit b7c7e7a60b0cb380a1e1d0d4088198807e972cb3
Author: Neil Roberts <neil linux intel com>
Date:   Wed Oct 17 21:28:45 2012 +0100

    Add cogl_buffer_map_range()
    
    This adds a buffer method to map a subregion of the buffer. This works
    using the GL_ARB_map_buffer_range extension. If the extension is not
    available then it will fallback to using glMapBuffer to map the entire
    buffer and then just add the offset to the returned pointer.
    
    cogl_buffer_map() is now just a wrapper which maps the entire range of
    the buffer. The driver backend functions have been renamed to
    map_range and they now all take the offset and size arguments.
    
    When the COGL_BUFFER_MAP_HINT_DISCARD hint is used and the map range
    extension is available instead of using glBufferData to invalidate the
    buffer it will instead pass the new GL_MAP_HINT_INVALIDATE_BUFFER
    flag. There is now additionally a COGL_BUFFER_MAP_HINT_DISCARD_REGION
    hint which can be used if the application only wants to discard the
    small region that is mapped. glMapBufferRange is always used if it is
    available even if the entire buffer is being mapped because it seems
    more robust to pass those flags then to call glBufferData.
    
    Reviewed-by: Robert Bragg <robert linux intel com>
    
    (cherry picked from commit 55ca02b5ca9cafc750251ec974e0d6a536cb80b8)

 cogl/cogl-buffer-private.h                         |    8 ++-
 cogl/cogl-buffer.c                                 |   33 +++++++--
 cogl/cogl-buffer.h                                 |   52 +++++++++++++-
 cogl/cogl-driver.h                                 |    8 ++-
 cogl/driver/gl/cogl-buffer-gl-private.h            |    8 ++-
 cogl/driver/gl/cogl-buffer-gl.c                    |   75 +++++++++++++++++---
 cogl/driver/gl/gl/cogl-driver-gl.c                 |    2 +-
 cogl/driver/gl/gles/cogl-driver-gles.c             |    2 +-
 cogl/gl-prototypes/cogl-all-functions.h            |   11 +++
 .../cogl-2.0-experimental-sections.txt             |    1 +
 10 files changed, 168 insertions(+), 32 deletions(-)
---
diff --git a/cogl/cogl-buffer-private.h b/cogl/cogl-buffer-private.h
index 59794cd..cf2d9b9 100644
--- a/cogl/cogl-buffer-private.h
+++ b/cogl/cogl-buffer-private.h
@@ -41,9 +41,11 @@ typedef struct _CoglBufferVtable CoglBufferVtable;
 
 struct _CoglBufferVtable
 {
-  void * (* map) (CoglBuffer       *buffer,
-                  CoglBufferAccess  access,
-                  CoglBufferMapHint hints);
+  void * (* map_range) (CoglBuffer *buffer,
+                        size_t offset,
+                        size_t size,
+                        CoglBufferAccess access,
+                        CoglBufferMapHint hints);
 
   void (* unmap) (CoglBuffer *buffer);
 
diff --git a/cogl/cogl-buffer.c b/cogl/cogl-buffer.c
index 573db0f..7a1a084 100644
--- a/cogl/cogl-buffer.c
+++ b/cogl/cogl-buffer.c
@@ -79,12 +79,14 @@ cogl_is_buffer (void *object)
  */
 
 static void *
-malloc_map (CoglBuffer       *buffer,
-            CoglBufferAccess  access,
-            CoglBufferMapHint hints)
+malloc_map_range (CoglBuffer *buffer,
+                  size_t offset,
+                  size_t size,
+                  CoglBufferAccess access,
+                  CoglBufferMapHint hints)
 {
   buffer->flags |= COGL_BUFFER_FLAG_MAPPED;
-  return buffer->data;
+  return buffer->data + offset;
 }
 
 static void
@@ -138,7 +140,7 @@ _cogl_buffer_initialize (CoglBuffer *buffer,
 
   if (use_malloc)
     {
-      buffer->vtable.map = malloc_map;
+      buffer->vtable.map_range = malloc_map_range;
       buffer->vtable.unmap = malloc_unmap;
       buffer->vtable.set_data = malloc_set_data;
 
@@ -146,7 +148,7 @@ _cogl_buffer_initialize (CoglBuffer *buffer,
     }
   else
     {
-      buffer->vtable.map = ctx->driver_vtable->buffer_map;
+      buffer->vtable.map_range = ctx->driver_vtable->buffer_map_range;
       buffer->vtable.unmap = ctx->driver_vtable->buffer_unmap;
       buffer->vtable.set_data = ctx->driver_vtable->buffer_set_data;
 
@@ -218,13 +220,30 @@ cogl_buffer_map (CoglBuffer        *buffer,
 {
   _COGL_RETURN_VAL_IF_FAIL (cogl_is_buffer (buffer), NULL);
 
+  return cogl_buffer_map_range (buffer, 0, buffer->size, access, hints);
+}
+
+void *
+cogl_buffer_map_range (CoglBuffer *buffer,
+                       size_t offset,
+                       size_t size,
+                       CoglBufferAccess access,
+                       CoglBufferMapHint hints)
+{
+  _COGL_RETURN_VAL_IF_FAIL (cogl_is_buffer (buffer), NULL);
+
   if (G_UNLIKELY (buffer->immutable_ref))
     warn_about_midscene_changes ();
 
   if (buffer->flags & COGL_BUFFER_FLAG_MAPPED)
     return buffer->data;
 
-  buffer->data = buffer->vtable.map (buffer, access, hints);
+  buffer->data = buffer->vtable.map_range (buffer,
+                                           offset,
+                                           size,
+                                           access,
+                                           hints);
+
   return buffer->data;
 }
 
diff --git a/cogl/cogl-buffer.h b/cogl/cogl-buffer.h
index 5ad24b9..217de11 100644
--- a/cogl/cogl-buffer.h
+++ b/cogl/cogl-buffer.h
@@ -161,7 +161,13 @@ typedef enum { /*< prefix=COGL_BUFFER_ACCESS >*/
 /**
  * CoglBufferMapHint:
  * @COGL_BUFFER_MAP_HINT_DISCARD: Tells Cogl that you plan to replace
- *    all the buffer's contents.
+ *    all the buffer's contents. When this flag is used to map a
+ *    buffer, the entire contents of the buffer become undefined, even
+ *    if only a subregion of the buffer is mapped.
+ * @COGL_BUFFER_MAP_HINT_DISCARD_RANGE: Tells Cogl that you plan to
+ *    replace all the contents of the mapped region. The contents of
+ *    the region specified are undefined after this flag is used to
+ *    map a buffer.
  *
  * Hints to Cogl about how you are planning to modify the data once it
  * is mapped.
@@ -170,7 +176,8 @@ typedef enum { /*< prefix=COGL_BUFFER_ACCESS >*/
  * Stability: unstable
  */
 typedef enum { /*< prefix=COGL_BUFFER_MAP_HINT >*/
-  COGL_BUFFER_MAP_HINT_DISCARD = 1 << 0
+  COGL_BUFFER_MAP_HINT_DISCARD = 1 << 0,
+  COGL_BUFFER_MAP_HINT_DISCARD_RANGE = 1 << 1
 } CoglBufferMapHint;
 
 /**
@@ -180,7 +187,9 @@ typedef enum { /*< prefix=COGL_BUFFER_MAP_HINT >*/
  * @hints: A mask of #CoglBufferMapHint<!-- -->s that tell Cogl how
  *   the data will be modified once mapped.
  *
- * Maps the buffer into the application address space for direct access.
+ * Maps the buffer into the application address space for direct
+ * access. This is equivalent to calling cogl_buffer_map_range() with
+ * zero as the offset and the size of the entire buffer as the size.
  *
  * It is strongly recommended that you pass
  * %COGL_BUFFER_MAP_HINT_DISCARD as a hint if you are going to replace
@@ -204,6 +213,43 @@ cogl_buffer_map (CoglBuffer        *buffer,
                  CoglBufferMapHint  hints);
 
 /**
+ * cogl_buffer_map_range:
+ * @buffer: a buffer object
+ * @offset: Offset within the buffer to start the mapping
+ * @size: The size of data to map
+ * @access: how the mapped buffer will be used by the application
+ * @hints: A mask of #CoglBufferMapHint<!-- -->s that tell Cogl how
+ *   the data will be modified once mapped.
+ *
+ * Maps a sub-region of the buffer into the application's address space
+ * for direct access.
+ *
+ * It is strongly recommended that you pass
+ * %COGL_BUFFER_MAP_HINT_DISCARD as a hint if you are going to replace
+ * all the buffer's data. This way if the buffer is currently being
+ * used by the GPU then the driver won't have to stall the CPU and
+ * wait for the hardware to finish because it can instead allocate a
+ * new buffer to map. You can pass
+ * %COGL_BUFFER_MAP_HINT_DISCARD_REGION instead if you want the
+ * regions outside of the mapping to be retained.
+ *
+ * The behaviour is undefined if you access the buffer in a way
+ * conflicting with the @access mask you pass. It is also an error to
+ * release your last reference while the buffer is mapped.
+ *
+ * Return value: A pointer to the mapped memory or %NULL is the call fails
+ *
+ * Since: 2.0
+ * Stability: unstable
+ */
+void *
+cogl_buffer_map_range (CoglBuffer *buffer,
+                       size_t offset,
+                       size_t size,
+                       CoglBufferAccess access,
+                       CoglBufferMapHint hints);
+
+/**
  * cogl_buffer_unmap:
  * @buffer: a buffer object
  *
diff --git a/cogl/cogl-driver.h b/cogl/cogl-driver.h
index f922111..36f4c7a 100644
--- a/cogl/cogl-driver.h
+++ b/cogl/cogl-driver.h
@@ -240,9 +240,11 @@ struct _CoglDriverVtable
 
   /* Maps a buffer into the CPU */
   void *
-  (* buffer_map) (CoglBuffer *buffer,
-                  CoglBufferAccess  access,
-                  CoglBufferMapHint hints);
+  (* buffer_map_range) (CoglBuffer *buffer,
+                        size_t offset,
+                        size_t size,
+                        CoglBufferAccess access,
+                        CoglBufferMapHint hints);
 
   /* Unmaps a buffer */
   void
diff --git a/cogl/driver/gl/cogl-buffer-gl-private.h b/cogl/driver/gl/cogl-buffer-gl-private.h
index 570e36c..583e0c1 100644
--- a/cogl/driver/gl/cogl-buffer-gl-private.h
+++ b/cogl/driver/gl/cogl-buffer-gl-private.h
@@ -40,9 +40,11 @@ void
 _cogl_buffer_gl_destroy (CoglBuffer *buffer);
 
 void *
-_cogl_buffer_gl_map (CoglBuffer *buffer,
-                     CoglBufferAccess  access,
-                     CoglBufferMapHint hints);
+_cogl_buffer_gl_map_range (CoglBuffer *buffer,
+                           size_t offset,
+                           size_t size,
+                           CoglBufferAccess access,
+                           CoglBufferMapHint hints);
 
 void
 _cogl_buffer_gl_unmap (CoglBuffer *buffer);
diff --git a/cogl/driver/gl/cogl-buffer-gl.c b/cogl/driver/gl/cogl-buffer-gl.c
index 94f6936..673dbf1 100644
--- a/cogl/driver/gl/cogl-buffer-gl.c
+++ b/cogl/driver/gl/cogl-buffer-gl.c
@@ -57,7 +57,18 @@
 #ifndef GL_READ_WRITE
 #define GL_READ_WRITE 0x88BA
 #endif
-
+#ifndef GL_MAP_READ_BIT
+#define GL_MAP_READ_BIT 0x0001
+#endif
+#ifndef GL_MAP_WRITE_BIT
+#define GL_MAP_WRITE_BIT 0x0002
+#endif
+#ifndef GL_MAP_INVALIDATE_RANGE_BIT
+#define GL_MAP_INVALIDATE_RANGE_BIT 0x0004
+#endif
+#ifndef GL_MAP_INVALIDATE_BUFFER_BIT
+#define GL_MAP_INVALIDATE_BUFFER_BIT 0x0008
+#endif
 
 void
 _cogl_buffer_gl_create (CoglBuffer *buffer)
@@ -173,9 +184,11 @@ _cogl_buffer_bind_no_create (CoglBuffer *buffer,
 }
 
 void *
-_cogl_buffer_gl_map (CoglBuffer *buffer,
-                     CoglBufferAccess  access,
-                     CoglBufferMapHint hints)
+_cogl_buffer_gl_map_range (CoglBuffer *buffer,
+                           size_t offset,
+                           size_t size,
+                           CoglBufferAccess access,
+                           CoglBufferMapHint hints)
 {
   uint8_t *data;
   CoglBufferBindTarget target;
@@ -194,14 +207,54 @@ _cogl_buffer_gl_map (CoglBuffer *buffer,
 
   gl_target = convert_bind_target_to_gl_target (target);
 
-  /* create an empty store if we don't have one yet. creating the store
-   * lazily allows the user of the CoglBuffer to set a hint before the
-   * store is created. */
-  if (!buffer->store_created || (hints & COGL_BUFFER_MAP_HINT_DISCARD))
-    recreate_store (buffer);
+  /* If the map buffer range extension is supported then we will
+   * always use it even if we are mapping the full range because the
+   * normal mapping function doesn't support passing the discard
+   * hints */
+  if (ctx->glMapBufferRange)
+    {
+      GLbitfield gl_access = 0;
+
+      if ((access & COGL_BUFFER_ACCESS_READ))
+        gl_access |= GL_MAP_READ_BIT;
+      if ((access & COGL_BUFFER_ACCESS_WRITE))
+        gl_access |= GL_MAP_WRITE_BIT;
+
+      if ((hints & COGL_BUFFER_MAP_HINT_DISCARD))
+        gl_access |= GL_MAP_INVALIDATE_BUFFER_BIT;
+      if ((hints & COGL_BUFFER_MAP_HINT_DISCARD_RANGE))
+        gl_access |= GL_MAP_INVALIDATE_RANGE_BIT;
+
+      if (!buffer->store_created)
+        recreate_store (buffer);
+
+      GE_RET( data,
+              ctx,
+              glMapBufferRange (gl_target,
+                                offset,
+                                size,
+                                gl_access) );
+    }
+  else
+    {
+      /* create an empty store if we don't have one yet. creating the store
+       * lazily allows the user of the CoglBuffer to set a hint before the
+       * store is created. */
+      if (!buffer->store_created ||
+          (hints & COGL_BUFFER_MAP_HINT_DISCARD) ||
+          ((hints & COGL_BUFFER_MAP_HINT_DISCARD_RANGE) &&
+           offset == 0 && size >= buffer->size))
+        recreate_store (buffer);
+
+      GE_RET( data,
+              ctx,
+              glMapBuffer (gl_target,
+                           _cogl_buffer_access_to_gl_enum (access)) );
+
+      if (data)
+        data += offset;
+    }
 
-  GE_RET( data, ctx, glMapBuffer (gl_target,
-                                  _cogl_buffer_access_to_gl_enum (access)) );
   if (data)
     buffer->flags |= COGL_BUFFER_FLAG_MAPPED;
 
diff --git a/cogl/driver/gl/gl/cogl-driver-gl.c b/cogl/driver/gl/gl/cogl-driver-gl.c
index 7600db2..2597161 100644
--- a/cogl/driver/gl/gl/cogl-driver-gl.c
+++ b/cogl/driver/gl/gl/cogl-driver-gl.c
@@ -618,7 +618,7 @@ _cogl_driver_gl =
     _cogl_clip_stack_gl_flush,
     _cogl_buffer_gl_create,
     _cogl_buffer_gl_destroy,
-    _cogl_buffer_gl_map,
+    _cogl_buffer_gl_map_range,
     _cogl_buffer_gl_unmap,
     _cogl_buffer_gl_set_data,
   };
diff --git a/cogl/driver/gl/gles/cogl-driver-gles.c b/cogl/driver/gl/gles/cogl-driver-gles.c
index dd4955b..ddd9b53 100644
--- a/cogl/driver/gl/gles/cogl-driver-gles.c
+++ b/cogl/driver/gl/gles/cogl-driver-gles.c
@@ -392,7 +392,7 @@ _cogl_driver_gles =
     _cogl_clip_stack_gl_flush,
     _cogl_buffer_gl_create,
     _cogl_buffer_gl_destroy,
-    _cogl_buffer_gl_map,
+    _cogl_buffer_gl_map_range,
     _cogl_buffer_gl_unmap,
     _cogl_buffer_gl_set_data,
   };
diff --git a/cogl/gl-prototypes/cogl-all-functions.h b/cogl/gl-prototypes/cogl-all-functions.h
index eeef4e7..870722e 100644
--- a/cogl/gl-prototypes/cogl-all-functions.h
+++ b/cogl/gl-prototypes/cogl-all-functions.h
@@ -286,3 +286,14 @@ COGL_EXT_FUNCTION (void, glGenVertexArrays,
                    (GLsizei n,
                     GLuint *arrays))
 COGL_EXT_END ()
+
+COGL_EXT_BEGIN (map_region, 3, 0,
+                0, /* not in either GLES */
+                "ARB\0",
+                "map_buffer_range\0")
+COGL_EXT_FUNCTION (GLvoid *, glMapBufferRange,
+                   (GLenum target,
+                    GLintptr offset,
+                    GLsizeiptr length,
+                    GLbitfield access))
+COGL_EXT_END ()
diff --git a/doc/reference/cogl-2.0-experimental/cogl-2.0-experimental-sections.txt b/doc/reference/cogl-2.0-experimental/cogl-2.0-experimental-sections.txt
index 5f6f959..1944951 100644
--- a/doc/reference/cogl-2.0-experimental/cogl-2.0-experimental-sections.txt
+++ b/doc/reference/cogl-2.0-experimental/cogl-2.0-experimental-sections.txt
@@ -731,6 +731,7 @@ cogl_buffer_set_update_hint
 cogl_buffer_get_update_hint
 CoglBufferAccess
 cogl_buffer_map
+cogl_buffer_map_range
 cogl_buffer_unmap
 cogl_buffer_set_data
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]