summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNeil Roberts <neil@linux.intel.com>2012-10-17 21:28:45 +0100
committerNeil Roberts <neil@linux.intel.com>2012-10-17 21:47:42 +0100
commit55ca02b5ca9cafc750251ec974e0d6a536cb80b8 (patch)
treea8d3c202b83427195dfdde349c6bc943f1b4b4bb
parentf2038121bdc89ce9b832674deb52dba033416a79 (diff)
downloadcogl-55ca02b5ca9cafc750251ec974e0d6a536cb80b8.tar.gz
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>
-rw-r--r--cogl/cogl-buffer-private.h8
-rw-r--r--cogl/cogl-buffer.c33
-rw-r--r--cogl/cogl-buffer.h52
-rw-r--r--cogl/cogl-driver.h8
-rw-r--r--cogl/driver/gl/cogl-buffer-gl-private.h8
-rw-r--r--cogl/driver/gl/cogl-buffer-gl.c75
-rw-r--r--cogl/driver/gl/gl/cogl-driver-gl.c2
-rw-r--r--cogl/driver/gl/gles/cogl-driver-gles.c2
-rw-r--r--cogl/gl-prototypes/cogl-all-functions.h11
-rw-r--r--doc/reference/cogl2/cogl2-sections.txt1
10 files changed, 168 insertions, 32 deletions
diff --git a/cogl/cogl-buffer-private.h b/cogl/cogl-buffer-private.h
index 59794cd2..cf2d9b92 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 573db0fe..7a1a0846 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 5ad24b96..217de11b 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 f9221110..36f4c7ad 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 570e36cc..583e0c11 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 94f69363..673dbf1a 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 4b961b79..142260f8 100644
--- a/cogl/driver/gl/gl/cogl-driver-gl.c
+++ b/cogl/driver/gl/gl/cogl-driver-gl.c
@@ -585,7 +585,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 c38f090a..0e2b4651 100644
--- a/cogl/driver/gl/gles/cogl-driver-gles.c
+++ b/cogl/driver/gl/gles/cogl-driver-gles.c
@@ -364,7 +364,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 eeef4e7d..870722e4 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/cogl2/cogl2-sections.txt b/doc/reference/cogl2/cogl2-sections.txt
index e5cb2fd2..c02b87bd 100644
--- a/doc/reference/cogl2/cogl2-sections.txt
+++ b/doc/reference/cogl2/cogl2-sections.txt
@@ -669,6 +669,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