cogl-buffer: Move malloc fallback logic into CoglBuffer

Since we'll want to share the fallback logic with CoglVertexArray this
moves the malloc based fallback (for when OpenGL doesn't support vertex
or pixel buffer objects) into cogl-buffer.c.
This commit is contained in:
Robert Bragg 2010-07-06 01:21:43 +01:00
parent 2353aa56ea
commit 2e0d2cf055
3 changed files with 188 additions and 217 deletions

View File

@ -87,7 +87,7 @@ typedef enum {
struct _CoglBuffer struct _CoglBuffer
{ {
CoglObject _parent; CoglObject _parent;
const CoglBufferVtable *vtable; CoglBufferVtable vtable;
CoglBufferBindTarget last_target; CoglBufferBindTarget last_target;
@ -118,6 +118,7 @@ _cogl_buffer_register_buffer_type (GQuark type);
void void
_cogl_buffer_initialize (CoglBuffer *buffer, _cogl_buffer_initialize (CoglBuffer *buffer,
unsigned int size, unsigned int size,
gboolean use_malloc,
CoglBufferBindTarget default_target, CoglBufferBindTarget default_target,
CoglBufferUsageHint usage_hint, CoglBufferUsageHint usage_hint,
CoglBufferUpdateHint update_hint); CoglBufferUpdateHint update_hint);
@ -135,12 +136,6 @@ _cogl_buffer_unbind (CoglBuffer *buffer);
CoglBufferUsageHint CoglBufferUsageHint
_cogl_buffer_get_usage_hint (CoglBuffer *buffer); _cogl_buffer_get_usage_hint (CoglBuffer *buffer);
GLenum
_cogl_buffer_get_last_gl_target (CoglBuffer *buffer);
CoglBufferBindTarget
_cogl_buffer_get_last_bind_target (CoglBuffer *buffer);
GLenum GLenum
_cogl_buffer_access_to_gl_enum (CoglBufferAccess access); _cogl_buffer_access_to_gl_enum (CoglBufferAccess access);

View File

@ -112,33 +112,10 @@ cogl_is_buffer (const void *object)
return FALSE; return FALSE;
} }
void static GLenum
_cogl_buffer_initialize (CoglBuffer *buffer, convert_bind_target_to_gl_target (CoglBufferBindTarget target)
unsigned int size,
CoglBufferBindTarget default_target,
CoglBufferUsageHint usage_hint,
CoglBufferUpdateHint update_hint)
{ {
_COGL_GET_CONTEXT (ctx, NO_RETVAL); switch (target)
buffer->flags = COGL_BUFFER_FLAG_NONE;
buffer->size = size;
buffer->last_target = default_target;
buffer->usage_hint = usage_hint;
buffer->update_hint = update_hint;
buffer->data = NULL;
}
void
_cogl_buffer_fini (CoglBuffer *buffer)
{
g_return_if_fail (!COGL_BUFFER_FLAG_IS_SET (buffer, MAPPED));
}
GLenum
_cogl_buffer_get_last_gl_target (CoglBuffer *buffer)
{
switch (buffer->last_target)
{ {
case COGL_BUFFER_BIND_TARGET_PIXEL_PACK: case COGL_BUFFER_BIND_TARGET_PIXEL_PACK:
return GL_PIXEL_PACK_BUFFER; return GL_PIXEL_PACK_BUFFER;
@ -153,10 +130,178 @@ _cogl_buffer_get_last_gl_target (CoglBuffer *buffer)
} }
} }
CoglBufferBindTarget static guint8 *
_cogl_buffer_get_last_bind_target (CoglBuffer *buffer) bo_map (CoglBuffer *buffer,
CoglBufferAccess access,
CoglBufferMapHint hints)
{ {
return buffer->last_target; #ifndef COGL_HAS_GLES
CoglPixelArray *pixel_array = COGL_PIXEL_ARRAY (buffer);
guint8 *data;
CoglBufferBindTarget target;
GLenum gl_target;
_COGL_GET_CONTEXT (ctx, NULL);
target = buffer->last_target;
_cogl_buffer_bind (buffer, target);
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 (!COGL_PIXEL_ARRAY_FLAG_IS_SET (pixel_array, STORE_CREATED) ||
(hints & COGL_BUFFER_MAP_HINT_DISCARD))
{
GE( glBufferData (gl_target,
buffer->size,
NULL,
_cogl_buffer_hints_to_gl_enum (buffer->usage_hint,
buffer->update_hint)) );
COGL_PIXEL_ARRAY_SET_FLAG (pixel_array, STORE_CREATED);
}
GE_RET( data, glMapBuffer (gl_target,
_cogl_buffer_access_to_gl_enum (access)) );
if (data)
COGL_BUFFER_SET_FLAG (buffer, MAPPED);
_cogl_buffer_unbind (buffer);
return data;
#else /* COGL_HAS_GLES */
return NULL;
#endif /* COGL_HAS_GLES */
}
static void
bo_unmap (CoglBuffer *buffer)
{
#ifndef COGL_HAS_GLES
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
_cogl_buffer_bind (buffer, buffer->last_target);
GE( glUnmapBuffer (convert_bind_target_to_gl_target (buffer->last_target)) );
COGL_BUFFER_CLEAR_FLAG (buffer, MAPPED);
_cogl_buffer_unbind (buffer);
#else
g_return_if_reached ();
#endif
}
static gboolean
bo_set_data (CoglBuffer *buffer,
unsigned int offset,
const guint8 *data,
unsigned int size)
{
CoglPixelArray *pixel_array = COGL_PIXEL_ARRAY (buffer);
CoglBufferBindTarget target;
GLenum gl_target;
_COGL_GET_CONTEXT (ctx, FALSE);
target = buffer->last_target;
_cogl_buffer_bind (buffer, target);
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 (!COGL_PIXEL_ARRAY_FLAG_IS_SET (pixel_array, STORE_CREATED))
{
GE( glBufferData (gl_target,
buffer->size,
NULL,
_cogl_buffer_hints_to_gl_enum (buffer->usage_hint,
buffer->update_hint)) );
COGL_PIXEL_ARRAY_SET_FLAG (pixel_array, STORE_CREATED);
}
GE( glBufferSubData (gl_target, offset, size, data) );
_cogl_buffer_unbind (buffer);
return TRUE;
}
/*
* Fallback path, buffer->data points to a malloc'ed buffer.
*/
static guint8 *
malloc_map (CoglBuffer *buffer,
CoglBufferAccess access,
CoglBufferMapHint hints)
{
COGL_BUFFER_SET_FLAG (buffer, MAPPED);
return buffer->data;
}
static void
malloc_unmap (CoglBuffer *buffer)
{
COGL_BUFFER_CLEAR_FLAG (buffer, MAPPED);
}
static gboolean
malloc_set_data (CoglBuffer *buffer,
unsigned int offset,
const guint8 *data,
unsigned int size)
{
memcpy (buffer->data + offset, data, size);
return TRUE;
}
void
_cogl_buffer_initialize (CoglBuffer *buffer,
unsigned int size,
gboolean use_malloc,
CoglBufferBindTarget default_target,
CoglBufferUsageHint usage_hint,
CoglBufferUpdateHint update_hint)
{
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
buffer->flags = COGL_BUFFER_FLAG_NONE;
buffer->size = size;
buffer->last_target = default_target;
buffer->usage_hint = usage_hint;
buffer->update_hint = update_hint;
buffer->data = NULL;
if (use_malloc)
{
buffer->vtable.map = malloc_map;
buffer->vtable.unmap = malloc_unmap;
buffer->vtable.set_data = malloc_set_data;
buffer->data = g_malloc (size);
}
else
{
buffer->vtable.map = bo_map;
buffer->vtable.unmap = bo_unmap;
buffer->vtable.set_data = bo_set_data;
GE( glGenBuffers (1, &buffer->gl_handle) );
COGL_BUFFER_SET_FLAG (buffer, BUFFER_OBJECT);
}
}
void
_cogl_buffer_fini (CoglBuffer *buffer)
{
g_return_if_fail (!COGL_BUFFER_FLAG_IS_SET (buffer, MAPPED));
} }
/* OpenGL ES 1.1 and 2 have a GL_OES_mapbuffer extension that is able to map /* OpenGL ES 1.1 and 2 have a GL_OES_mapbuffer extension that is able to map
@ -226,7 +371,7 @@ _cogl_buffer_bind (CoglBuffer *buffer, CoglBufferBindTarget target)
if (COGL_BUFFER_FLAG_IS_SET (buffer, BUFFER_OBJECT)) if (COGL_BUFFER_FLAG_IS_SET (buffer, BUFFER_OBJECT))
{ {
GLenum gl_target = _cogl_buffer_get_last_gl_target (buffer); GLenum gl_target = convert_bind_target_to_gl_target (buffer->last_target);
GE( glBindBuffer (gl_target, buffer->gl_handle) ); GE( glBindBuffer (gl_target, buffer->gl_handle) );
} }
@ -245,7 +390,7 @@ _cogl_buffer_unbind (CoglBuffer *buffer)
if (COGL_BUFFER_FLAG_IS_SET (buffer, BUFFER_OBJECT)) if (COGL_BUFFER_FLAG_IS_SET (buffer, BUFFER_OBJECT))
{ {
GLenum gl_target = _cogl_buffer_get_last_gl_target (buffer); GLenum gl_target = convert_bind_target_to_gl_target (buffer->last_target);
GE( glBindBuffer (gl_target, 0) ); GE( glBindBuffer (gl_target, 0) );
} }
@ -294,7 +439,7 @@ cogl_buffer_map (CoglBuffer *buffer,
if (COGL_BUFFER_FLAG_IS_SET (buffer, MAPPED)) if (COGL_BUFFER_FLAG_IS_SET (buffer, MAPPED))
return buffer->data; return buffer->data;
buffer->data = buffer->vtable->map (buffer, access, hints); buffer->data = buffer->vtable.map (buffer, access, hints);
return buffer->data; return buffer->data;
} }
@ -307,7 +452,7 @@ cogl_buffer_unmap (CoglBuffer *buffer)
if (!COGL_BUFFER_FLAG_IS_SET (buffer, MAPPED)) if (!COGL_BUFFER_FLAG_IS_SET (buffer, MAPPED))
return; return;
buffer->vtable->unmap (buffer); buffer->vtable.unmap (buffer);
} }
gboolean gboolean
@ -322,5 +467,5 @@ cogl_buffer_set_data (CoglBuffer *buffer,
if (G_UNLIKELY((offset + size) > buffer->size)) if (G_UNLIKELY((offset + size) > buffer->size))
return FALSE; return FALSE;
return buffer->vtable->set_data (buffer, offset, data, size); return buffer->vtable.set_data (buffer, offset, data, size);
} }

View File

@ -92,37 +92,23 @@ _cogl_pixel_array_new (unsigned int size)
{ {
CoglPixelArray *pixel_array = g_slice_new0 (CoglPixelArray); CoglPixelArray *pixel_array = g_slice_new0 (CoglPixelArray);
CoglBuffer *buffer = COGL_BUFFER (pixel_array); CoglBuffer *buffer = COGL_BUFFER (pixel_array);
gboolean use_malloc;
_COGL_GET_CONTEXT (ctx, COGL_INVALID_HANDLE); _COGL_GET_CONTEXT (ctx, COGL_INVALID_HANDLE);
if (!cogl_features_available (COGL_FEATURE_PBOS))
use_malloc = TRUE;
else
use_malloc = FALSE;
/* parent's constructor */ /* parent's constructor */
_cogl_buffer_initialize (buffer, _cogl_buffer_initialize (buffer,
size, size,
use_malloc,
COGL_BUFFER_BIND_TARGET_PIXEL_UNPACK, COGL_BUFFER_BIND_TARGET_PIXEL_UNPACK,
COGL_BUFFER_USAGE_HINT_TEXTURE, COGL_BUFFER_USAGE_HINT_TEXTURE,
COGL_BUFFER_UPDATE_HINT_STATIC); COGL_BUFFER_UPDATE_HINT_STATIC);
/* malloc version only for GLES */
#if !defined (COGL_HAS_GLES)
if (cogl_features_available (COGL_FEATURE_PBOS))
{
/* PBOS */
buffer->vtable = &cogl_pixel_array_vtable;
GE( glGenBuffers (1, &buffer->gl_handle) );
COGL_BUFFER_SET_FLAG (buffer, BUFFER_OBJECT);
}
else
#endif
{
/* malloc fallback subclass */
buffer->vtable = &cogl_malloc_pixel_array_vtable;
/* create the buffer here as there's no point for a lazy allocation in
* the malloc case */
buffer->data = g_malloc (size);
}
pixel_array->flags = COGL_PIXEL_ARRAY_FLAG_NONE; pixel_array->flags = COGL_PIXEL_ARRAY_FLAG_NONE;
/* return COGL_INVALID_HANDLE; */ /* return COGL_INVALID_HANDLE; */
@ -175,158 +161,3 @@ _cogl_pixel_array_free (CoglPixelArray *buffer)
g_slice_free (CoglPixelArray, buffer); g_slice_free (CoglPixelArray, buffer);
} }
#if !defined (COGL_HAS_GLES)
static guint8 *
_cogl_pixel_array_map (CoglBuffer *buffer,
CoglBufferAccess access,
CoglBufferMapHint hints)
{
CoglPixelArray *pixel_array = COGL_PIXEL_ARRAY (buffer);
guint8 *data;
CoglBufferBindTarget target;
GLenum gl_target;
_COGL_GET_CONTEXT (ctx, NULL);
target = _cogl_buffer_get_last_bind_target (buffer);
_cogl_buffer_bind (buffer, target);
gl_target = _cogl_buffer_get_last_gl_target (buffer);
/* 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 (!COGL_PIXEL_ARRAY_FLAG_IS_SET (pixel_array, STORE_CREATED) ||
(hints & COGL_BUFFER_MAP_HINT_DISCARD))
{
GE( glBufferData (gl_target,
buffer->size,
NULL,
_cogl_buffer_hints_to_gl_enum (buffer->usage_hint,
buffer->update_hint)) );
COGL_PIXEL_ARRAY_SET_FLAG (pixel_array, STORE_CREATED);
}
GE_RET( data, glMapBuffer (gl_target,
_cogl_buffer_access_to_gl_enum (access)) );
if (data)
COGL_BUFFER_SET_FLAG (buffer, MAPPED);
_cogl_buffer_unbind (buffer);
return data;
}
static void
_cogl_pixel_array_unmap (CoglBuffer *buffer)
{
CoglBufferBindTarget target;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
target = _cogl_buffer_get_last_bind_target (buffer);
_cogl_buffer_bind (buffer, target);
GE( glUnmapBuffer (_cogl_buffer_get_last_gl_target (buffer)) );
COGL_BUFFER_CLEAR_FLAG (buffer, MAPPED);
_cogl_buffer_unbind (buffer);
}
static gboolean
_cogl_pixel_array_set_data (CoglBuffer *buffer,
unsigned int offset,
const guint8 *data,
unsigned int size)
{
CoglPixelArray *pixel_array = COGL_PIXEL_ARRAY (buffer);
CoglBufferBindTarget target;
GLenum gl_target;
_COGL_GET_CONTEXT (ctx, FALSE);
target = _cogl_buffer_get_last_bind_target (buffer);
_cogl_buffer_bind (buffer, target);
gl_target = _cogl_buffer_get_last_gl_target (buffer);
/* 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 (!COGL_PIXEL_ARRAY_FLAG_IS_SET (pixel_array, STORE_CREATED))
{
GE( glBufferData (gl_target,
buffer->size,
NULL,
_cogl_buffer_hints_to_gl_enum (buffer->usage_hint,
buffer->update_hint)) );
COGL_PIXEL_ARRAY_SET_FLAG (pixel_array, STORE_CREATED);
}
GE( glBufferSubData (gl_target, offset, size, data) );
_cogl_buffer_unbind (buffer);
return TRUE;
}
#if 0
gboolean
cogl_pixel_array_set_region (CoglPixelArray *buffer,
guint8 *data,
unsigned int src_width,
unsigned int src_height,
unsigned int src_rowstride,
unsigned int dst_x,
unsigned int dst_y)
{
if (!cogl_is_pixel_array (buffer))
return FALSE;
return TRUE;
}
#endif
static const CoglBufferVtable cogl_pixel_array_vtable =
{
_cogl_pixel_array_map,
_cogl_pixel_array_unmap,
_cogl_pixel_array_set_data,
};
#endif
/*
* Fallback path, buffer->data points to a malloc'ed buffer.
*/
static guint8 *
_cogl_malloc_pixel_array_map (CoglBuffer *buffer,
CoglBufferAccess access,
CoglBufferMapHint hints)
{
COGL_BUFFER_SET_FLAG (buffer, MAPPED);
return buffer->data;
}
static void
_cogl_malloc_pixel_array_unmap (CoglBuffer *buffer)
{
COGL_BUFFER_CLEAR_FLAG (buffer, MAPPED);
}
static gboolean
_cogl_malloc_pixel_array_set_data (CoglBuffer *buffer,
unsigned int offset,
const guint8 *data,
unsigned int size)
{
memcpy (buffer->data + offset, data, size);
return TRUE;
}
static const CoglBufferVtable cogl_malloc_pixel_array_vtable =
{
_cogl_malloc_pixel_array_map,
_cogl_malloc_pixel_array_unmap,
_cogl_malloc_pixel_array_set_data,
};