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)
This commit is contained in:
parent
8a3fb7a10d
commit
ec03357e88
@ -41,7 +41,9 @@ typedef struct _CoglBufferVtable CoglBufferVtable;
|
||||
|
||||
struct _CoglBufferVtable
|
||||
{
|
||||
void * (* map) (CoglBuffer *buffer,
|
||||
void * (* map_range) (CoglBuffer *buffer,
|
||||
size_t offset,
|
||||
size_t size,
|
||||
CoglBufferAccess access,
|
||||
CoglBufferMapHint hints);
|
||||
|
||||
|
@ -79,12 +79,14 @@ cogl_is_buffer (void *object)
|
||||
*/
|
||||
|
||||
static void *
|
||||
malloc_map (CoglBuffer *buffer,
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
@ -203,6 +212,43 @@ cogl_buffer_map (CoglBuffer *buffer,
|
||||
CoglBufferAccess access,
|
||||
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
|
||||
|
@ -240,7 +240,9 @@ struct _CoglDriverVtable
|
||||
|
||||
/* Maps a buffer into the CPU */
|
||||
void *
|
||||
(* buffer_map) (CoglBuffer *buffer,
|
||||
(* buffer_map_range) (CoglBuffer *buffer,
|
||||
size_t offset,
|
||||
size_t size,
|
||||
CoglBufferAccess access,
|
||||
CoglBufferMapHint hints);
|
||||
|
||||
|
@ -40,7 +40,9 @@ void
|
||||
_cogl_buffer_gl_destroy (CoglBuffer *buffer);
|
||||
|
||||
void *
|
||||
_cogl_buffer_gl_map (CoglBuffer *buffer,
|
||||
_cogl_buffer_gl_map_range (CoglBuffer *buffer,
|
||||
size_t offset,
|
||||
size_t size,
|
||||
CoglBufferAccess access,
|
||||
CoglBufferMapHint hints);
|
||||
|
||||
|
@ -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,7 +184,9 @@ _cogl_buffer_bind_no_create (CoglBuffer *buffer,
|
||||
}
|
||||
|
||||
void *
|
||||
_cogl_buffer_gl_map (CoglBuffer *buffer,
|
||||
_cogl_buffer_gl_map_range (CoglBuffer *buffer,
|
||||
size_t offset,
|
||||
size_t size,
|
||||
CoglBufferAccess access,
|
||||
CoglBufferMapHint hints)
|
||||
{
|
||||
@ -194,14 +207,54 @@ _cogl_buffer_gl_map (CoglBuffer *buffer,
|
||||
|
||||
gl_target = convert_bind_target_to_gl_target (target);
|
||||
|
||||
/* 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))
|
||||
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,
|
||||
GE_RET( data,
|
||||
ctx,
|
||||
glMapBuffer (gl_target,
|
||||
_cogl_buffer_access_to_gl_enum (access)) );
|
||||
|
||||
if (data)
|
||||
data += offset;
|
||||
}
|
||||
|
||||
if (data)
|
||||
buffer->flags |= COGL_BUFFER_FLAG_MAPPED;
|
||||
|
||||
|
@ -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,
|
||||
};
|
||||
|
@ -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,
|
||||
};
|
||||
|
@ -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 ()
|
||||
|
@ -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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user