mirror of
https://github.com/brl/mutter.git
synced 2024-11-26 18:11:05 -05:00
[cogl vertex buffers] Adds fallbacks for drivers without VBO support
Buffer objects aren't currently available for glx indirect contexts, so we now have a fallback that simply allocates fake client side vbos to store the attributes.
This commit is contained in:
parent
bf4a0fa03f
commit
c1afd0de69
@ -125,7 +125,10 @@ typedef enum _CoglVertexBufferVBOFlags
|
|||||||
typedef struct _CoglVertexBufferVBO
|
typedef struct _CoglVertexBufferVBO
|
||||||
{
|
{
|
||||||
CoglVertexBufferVBOFlags flags;
|
CoglVertexBufferVBOFlags flags;
|
||||||
GLuint vbo_name; /*!< The name of the corresponding buffer object */
|
|
||||||
|
/* Note: this is a pointer to handle fallbacks, and normally holds
|
||||||
|
* a GLuint value */
|
||||||
|
gpointer vbo_name; /*!< The name of the corresponding buffer object */
|
||||||
gsize vbo_bytes; /*!< The lengh of the allocated buffer object in bytes */
|
gsize vbo_bytes; /*!< The lengh of the allocated buffer object in bytes */
|
||||||
GList *attributes;
|
GList *attributes;
|
||||||
} CoglVertexBufferVBO;
|
} CoglVertexBufferVBO;
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
*
|
*
|
||||||
* Vertex Buffer API: Handle extensible arrays of vertex attributes
|
* Vertex Buffer API: Handle extensible arrays of vertex attributes
|
||||||
*
|
*
|
||||||
* Copyright (C) 2008 Intel Corporation.
|
* Copyright (C) 2008, 2009 Intel Corporation.
|
||||||
*
|
*
|
||||||
* Authored by: Robert Bragg <robert@linux.intel.com>
|
* Authored by: Robert Bragg <robert@linux.intel.com>
|
||||||
*
|
*
|
||||||
@ -893,7 +893,12 @@ cogl_vertex_buffer_vbo_free (CoglVertexBufferVBO *cogl_vbo,
|
|||||||
|
|
||||||
if (delete_gl_vbo && cogl_vbo->flags &
|
if (delete_gl_vbo && cogl_vbo->flags &
|
||||||
COGL_VERTEX_BUFFER_VBO_FLAG_SUBMITTED)
|
COGL_VERTEX_BUFFER_VBO_FLAG_SUBMITTED)
|
||||||
GE (glDeleteBuffers (1, &cogl_vbo->vbo_name));
|
{
|
||||||
|
if (cogl_get_features () & COGL_FEATURE_VBOS)
|
||||||
|
GE (glDeleteBuffers (1, (GLuint *)&cogl_vbo->vbo_name));
|
||||||
|
else
|
||||||
|
g_free (cogl_vbo->vbo_name);
|
||||||
|
}
|
||||||
|
|
||||||
g_slice_free (CoglVertexBufferVBO, cogl_vbo);
|
g_slice_free (CoglVertexBufferVBO, cogl_vbo);
|
||||||
}
|
}
|
||||||
@ -937,11 +942,19 @@ upload_multipack_vbo_via_map_buffer (CoglVertexBufferVBO *cogl_vbo)
|
|||||||
GList *tmp;
|
GList *tmp;
|
||||||
guint offset = 0;
|
guint offset = 0;
|
||||||
char *buf;
|
char *buf;
|
||||||
|
gboolean fallback =
|
||||||
|
(cogl_get_features () & COGL_FEATURE_VBOS) ? FALSE : TRUE;
|
||||||
|
|
||||||
_COGL_GET_CONTEXT (ctx, FALSE);
|
_COGL_GET_CONTEXT (ctx, FALSE);
|
||||||
|
|
||||||
buf = glMapBuffer (GL_ARRAY_BUFFER, GL_WRITE_ONLY);
|
if (!fallback)
|
||||||
glGetError();
|
{
|
||||||
|
buf = glMapBuffer (GL_ARRAY_BUFFER, GL_WRITE_ONLY);
|
||||||
|
glGetError();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
buf = cogl_vbo->vbo_name;
|
||||||
|
|
||||||
if (!buf)
|
if (!buf)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
@ -959,7 +972,9 @@ upload_multipack_vbo_via_map_buffer (CoglVertexBufferVBO *cogl_vbo)
|
|||||||
attribute->flags |= COGL_VERTEX_BUFFER_ATTRIB_FLAG_SUBMITTED;
|
attribute->flags |= COGL_VERTEX_BUFFER_ATTRIB_FLAG_SUBMITTED;
|
||||||
offset += attribute_size;
|
offset += attribute_size;
|
||||||
}
|
}
|
||||||
glUnmapBuffer (GL_ARRAY_BUFFER);
|
|
||||||
|
if (!fallback)
|
||||||
|
glUnmapBuffer (GL_ARRAY_BUFFER);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
#else
|
#else
|
||||||
@ -972,6 +987,8 @@ upload_multipack_vbo_via_buffer_sub_data (CoglVertexBufferVBO *cogl_vbo)
|
|||||||
{
|
{
|
||||||
GList *tmp;
|
GList *tmp;
|
||||||
guint offset = 0;
|
guint offset = 0;
|
||||||
|
gboolean fallback =
|
||||||
|
(cogl_get_features () & COGL_FEATURE_VBOS) ? FALSE : TRUE;
|
||||||
|
|
||||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||||
|
|
||||||
@ -983,10 +1000,19 @@ upload_multipack_vbo_via_buffer_sub_data (CoglVertexBufferVBO *cogl_vbo)
|
|||||||
|
|
||||||
PAD_FOR_ALIGNMENT (offset, gl_type_size);
|
PAD_FOR_ALIGNMENT (offset, gl_type_size);
|
||||||
|
|
||||||
GE (glBufferSubData (GL_ARRAY_BUFFER,
|
if (!fallback)
|
||||||
offset,
|
{
|
||||||
attribute_size,
|
GE (glBufferSubData (GL_ARRAY_BUFFER,
|
||||||
attribute->u.pointer));
|
offset,
|
||||||
|
attribute_size,
|
||||||
|
attribute->u.pointer));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
char *dest = (char *)cogl_vbo->vbo_name + offset;
|
||||||
|
memcpy (dest, attribute->u.pointer, attribute_size);
|
||||||
|
}
|
||||||
|
|
||||||
attribute->u.vbo_offset = offset;
|
attribute->u.vbo_offset = offset;
|
||||||
attribute->flags |= COGL_VERTEX_BUFFER_ATTRIB_FLAG_SUBMITTED;
|
attribute->flags |= COGL_VERTEX_BUFFER_ATTRIB_FLAG_SUBMITTED;
|
||||||
offset += attribute_size;
|
offset += attribute_size;
|
||||||
@ -997,36 +1023,58 @@ static void
|
|||||||
upload_gl_vbo (CoglVertexBufferVBO *cogl_vbo)
|
upload_gl_vbo (CoglVertexBufferVBO *cogl_vbo)
|
||||||
{
|
{
|
||||||
GLenum usage;
|
GLenum usage;
|
||||||
|
gboolean fallback =
|
||||||
|
(cogl_get_features () & COGL_FEATURE_VBOS) ? FALSE : TRUE;
|
||||||
|
|
||||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||||
|
|
||||||
g_return_if_fail (cogl_vbo->vbo_name != 0);
|
|
||||||
|
|
||||||
if (cogl_vbo->flags & COGL_VERTEX_BUFFER_VBO_FLAG_FREQUENT_RESUBMIT)
|
if (cogl_vbo->flags & COGL_VERTEX_BUFFER_VBO_FLAG_FREQUENT_RESUBMIT)
|
||||||
usage = GL_DYNAMIC_DRAW;
|
usage = GL_DYNAMIC_DRAW;
|
||||||
else
|
else
|
||||||
usage = GL_STATIC_DRAW;
|
usage = GL_STATIC_DRAW;
|
||||||
|
|
||||||
GE (glBindBuffer (GL_ARRAY_BUFFER, cogl_vbo->vbo_name));
|
if (!fallback)
|
||||||
|
{
|
||||||
|
g_return_if_fail (cogl_vbo->vbo_name != 0);
|
||||||
|
|
||||||
|
GE (glBindBuffer (GL_ARRAY_BUFFER,
|
||||||
|
GPOINTER_TO_UINT (cogl_vbo->vbo_name)));
|
||||||
|
}
|
||||||
|
else if (cogl_vbo->vbo_name == NULL)
|
||||||
|
{
|
||||||
|
/* If the driver doesn't support VBOs then we simply allocate
|
||||||
|
* a client side fake vbo buffer. Unlike VBOs we can't allocate
|
||||||
|
* without specifying a size which is why we defer allocation
|
||||||
|
* until here. */
|
||||||
|
cogl_vbo->vbo_name = g_malloc (cogl_vbo->vbo_bytes);
|
||||||
|
}
|
||||||
|
|
||||||
if (cogl_vbo->flags & COGL_VERTEX_BUFFER_VBO_FLAG_STRIDED)
|
if (cogl_vbo->flags & COGL_VERTEX_BUFFER_VBO_FLAG_STRIDED)
|
||||||
{
|
{
|
||||||
const void *pointer =
|
const void *pointer =
|
||||||
prep_strided_vbo_for_upload (cogl_vbo);
|
prep_strided_vbo_for_upload (cogl_vbo);
|
||||||
GE (glBufferData (GL_ARRAY_BUFFER,
|
if (!fallback)
|
||||||
cogl_vbo->vbo_bytes,
|
{
|
||||||
pointer,
|
GE (glBufferData (GL_ARRAY_BUFFER,
|
||||||
usage));
|
cogl_vbo->vbo_bytes,
|
||||||
|
pointer,
|
||||||
|
usage));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
memcpy (cogl_vbo->vbo_name, pointer, cogl_vbo->vbo_bytes);
|
||||||
}
|
}
|
||||||
else if (cogl_vbo->flags & COGL_VERTEX_BUFFER_VBO_FLAG_MULTIPACK)
|
else if (cogl_vbo->flags & COGL_VERTEX_BUFFER_VBO_FLAG_MULTIPACK)
|
||||||
{
|
{
|
||||||
/* First we make it obvious to the driver that we want to update the
|
/* First we make it obvious to the driver that we want to update the
|
||||||
* whole buffer (without this, the driver is more likley to block
|
* whole buffer (without this, the driver is more likley to block
|
||||||
* if the GPU is busy using the buffer) */
|
* if the GPU is busy using the buffer) */
|
||||||
GE (glBufferData (GL_ARRAY_BUFFER,
|
if (!fallback)
|
||||||
cogl_vbo->vbo_bytes,
|
{
|
||||||
NULL,
|
GE (glBufferData (GL_ARRAY_BUFFER,
|
||||||
usage));
|
cogl_vbo->vbo_bytes,
|
||||||
|
NULL,
|
||||||
|
usage));
|
||||||
|
}
|
||||||
|
|
||||||
/* I think it might depend on the specific driver/HW whether its better
|
/* I think it might depend on the specific driver/HW whether its better
|
||||||
* to use glMapBuffer here or glBufferSubData here. There is even a good
|
* to use glMapBuffer here or glBufferSubData here. There is even a good
|
||||||
@ -1041,10 +1089,16 @@ upload_gl_vbo (CoglVertexBufferVBO *cogl_vbo)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
CoglVertexBufferAttrib *attribute = cogl_vbo->attributes->data;
|
CoglVertexBufferAttrib *attribute = cogl_vbo->attributes->data;
|
||||||
GE (glBufferData (GL_ARRAY_BUFFER,
|
if (!fallback)
|
||||||
cogl_vbo->vbo_bytes,
|
{
|
||||||
attribute->u.pointer,
|
GE (glBufferData (GL_ARRAY_BUFFER,
|
||||||
usage));
|
cogl_vbo->vbo_bytes,
|
||||||
|
attribute->u.pointer,
|
||||||
|
usage));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
memcpy (cogl_vbo->vbo_name, attribute->u.pointer, cogl_vbo->vbo_bytes);
|
||||||
|
|
||||||
/* We forget this pointer now since the client will be free
|
/* We forget this pointer now since the client will be free
|
||||||
* to re-use this memory */
|
* to re-use this memory */
|
||||||
attribute->u.pointer = NULL;
|
attribute->u.pointer = NULL;
|
||||||
@ -1053,7 +1107,8 @@ upload_gl_vbo (CoglVertexBufferVBO *cogl_vbo)
|
|||||||
|
|
||||||
cogl_vbo->flags |= COGL_VERTEX_BUFFER_VBO_FLAG_SUBMITTED;
|
cogl_vbo->flags |= COGL_VERTEX_BUFFER_VBO_FLAG_SUBMITTED;
|
||||||
|
|
||||||
GE (glBindBuffer (GL_ARRAY_BUFFER, 0));
|
if (!fallback)
|
||||||
|
GE (glBindBuffer (GL_ARRAY_BUFFER, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Note: although there ends up being quite a few inner loops involved with
|
/* Note: although there ends up being quite a few inner loops involved with
|
||||||
@ -1112,7 +1167,11 @@ cogl_vertex_buffer_vbo_resolve (CoglVertexBuffer *buffer,
|
|||||||
|
|
||||||
if (!found_target_vbo)
|
if (!found_target_vbo)
|
||||||
{
|
{
|
||||||
GE (glGenBuffers (1, &new_cogl_vbo->vbo_name));
|
if (cogl_get_features () & COGL_FEATURE_VBOS)
|
||||||
|
GE (glGenBuffers (1, (GLuint *)&new_cogl_vbo->vbo_name));
|
||||||
|
else
|
||||||
|
new_cogl_vbo->vbo_name = NULL;
|
||||||
|
/* this will be allocated at upload time */
|
||||||
|
|
||||||
upload_gl_vbo (new_cogl_vbo);
|
upload_gl_vbo (new_cogl_vbo);
|
||||||
*final_vbos = g_list_prepend (*final_vbos, new_cogl_vbo);
|
*final_vbos = g_list_prepend (*final_vbos, new_cogl_vbo);
|
||||||
@ -1449,8 +1508,25 @@ enable_state_for_drawing_buffer (CoglVertexBuffer *buffer)
|
|||||||
{
|
{
|
||||||
CoglVertexBufferVBO *cogl_vbo = tmp->data;
|
CoglVertexBufferVBO *cogl_vbo = tmp->data;
|
||||||
GList *tmp2;
|
GList *tmp2;
|
||||||
|
char *base;
|
||||||
|
const GLvoid *pointer;
|
||||||
|
|
||||||
GE (glBindBuffer (GL_ARRAY_BUFFER, cogl_vbo->vbo_name));
|
if (cogl_get_features () & COGL_FEATURE_VBOS)
|
||||||
|
{
|
||||||
|
GE (glBindBuffer (GL_ARRAY_BUFFER,
|
||||||
|
GPOINTER_TO_UINT (cogl_vbo->vbo_name)));
|
||||||
|
base = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
base = cogl_vbo->vbo_name;
|
||||||
|
|
||||||
|
/* When GL VBOs are bing used then the "pointer" we pass to
|
||||||
|
* glColorPointer glVertexAttribPointer etc is actually an offset into
|
||||||
|
* the currently bound VBO.
|
||||||
|
*
|
||||||
|
* If we don't have VBO support though, then we must point into
|
||||||
|
* our fake client side VBO.
|
||||||
|
*/
|
||||||
|
|
||||||
for (tmp2 = cogl_vbo->attributes; tmp2 != NULL; tmp2 = tmp2->next)
|
for (tmp2 = cogl_vbo->attributes; tmp2 != NULL; tmp2 = tmp2->next)
|
||||||
{
|
{
|
||||||
@ -1467,26 +1543,29 @@ enable_state_for_drawing_buffer (CoglVertexBuffer *buffer)
|
|||||||
case COGL_VERTEX_BUFFER_ATTRIB_FLAG_COLOR_ARRAY:
|
case COGL_VERTEX_BUFFER_ATTRIB_FLAG_COLOR_ARRAY:
|
||||||
enable_flags |= COGL_ENABLE_COLOR_ARRAY | COGL_ENABLE_BLEND;
|
enable_flags |= COGL_ENABLE_COLOR_ARRAY | COGL_ENABLE_BLEND;
|
||||||
/* GE (glEnableClientState (GL_COLOR_ARRAY)); */
|
/* GE (glEnableClientState (GL_COLOR_ARRAY)); */
|
||||||
|
pointer = (const GLvoid *)(base + attribute->u.vbo_offset);
|
||||||
GE (glColorPointer (attribute->n_components,
|
GE (glColorPointer (attribute->n_components,
|
||||||
gl_type,
|
gl_type,
|
||||||
attribute->stride,
|
attribute->stride,
|
||||||
(const GLvoid *)attribute->u.vbo_offset));
|
pointer));
|
||||||
break;
|
break;
|
||||||
case COGL_VERTEX_BUFFER_ATTRIB_FLAG_NORMAL_ARRAY:
|
case COGL_VERTEX_BUFFER_ATTRIB_FLAG_NORMAL_ARRAY:
|
||||||
/* FIXME: go through cogl cache to enable normal array */
|
/* FIXME: go through cogl cache to enable normal array */
|
||||||
GE (glEnableClientState (GL_NORMAL_ARRAY));
|
GE (glEnableClientState (GL_NORMAL_ARRAY));
|
||||||
|
pointer = (const GLvoid *)(base + attribute->u.vbo_offset);
|
||||||
GE (glNormalPointer (gl_type,
|
GE (glNormalPointer (gl_type,
|
||||||
attribute->stride,
|
attribute->stride,
|
||||||
(const GLvoid *)attribute->u.vbo_offset));
|
pointer));
|
||||||
break;
|
break;
|
||||||
case COGL_VERTEX_BUFFER_ATTRIB_FLAG_TEXTURE_COORD_ARRAY:
|
case COGL_VERTEX_BUFFER_ATTRIB_FLAG_TEXTURE_COORD_ARRAY:
|
||||||
GE (glClientActiveTexture (GL_TEXTURE0 +
|
GE (glClientActiveTexture (GL_TEXTURE0 +
|
||||||
attribute->texture_unit));
|
attribute->texture_unit));
|
||||||
GE (glEnableClientState (GL_TEXTURE_COORD_ARRAY));
|
GE (glEnableClientState (GL_TEXTURE_COORD_ARRAY));
|
||||||
|
pointer = (const GLvoid *)(base + attribute->u.vbo_offset);
|
||||||
GE (glTexCoordPointer (attribute->n_components,
|
GE (glTexCoordPointer (attribute->n_components,
|
||||||
gl_type,
|
gl_type,
|
||||||
attribute->stride,
|
attribute->stride,
|
||||||
(const GLvoid *)attribute->u.vbo_offset));
|
pointer));
|
||||||
if (attribute->texture_unit > max_texcoord_attrib_unit)
|
if (attribute->texture_unit > max_texcoord_attrib_unit)
|
||||||
max_texcoord_attrib_unit = attribute->texture_unit;
|
max_texcoord_attrib_unit = attribute->texture_unit;
|
||||||
disable_mask &= ~(1 << attribute->texture_unit);
|
disable_mask &= ~(1 << attribute->texture_unit);
|
||||||
@ -1494,10 +1573,11 @@ enable_state_for_drawing_buffer (CoglVertexBuffer *buffer)
|
|||||||
case COGL_VERTEX_BUFFER_ATTRIB_FLAG_VERTEX_ARRAY:
|
case COGL_VERTEX_BUFFER_ATTRIB_FLAG_VERTEX_ARRAY:
|
||||||
enable_flags |= COGL_ENABLE_VERTEX_ARRAY;
|
enable_flags |= COGL_ENABLE_VERTEX_ARRAY;
|
||||||
/* GE (glEnableClientState (GL_VERTEX_ARRAY)); */
|
/* GE (glEnableClientState (GL_VERTEX_ARRAY)); */
|
||||||
|
pointer = (const GLvoid *)(base + attribute->u.vbo_offset);
|
||||||
GE (glVertexPointer (attribute->n_components,
|
GE (glVertexPointer (attribute->n_components,
|
||||||
gl_type,
|
gl_type,
|
||||||
attribute->stride,
|
attribute->stride,
|
||||||
(const GLvoid *)attribute->u.vbo_offset));
|
pointer));
|
||||||
break;
|
break;
|
||||||
case COGL_VERTEX_BUFFER_ATTRIB_FLAG_CUSTOM_ARRAY:
|
case COGL_VERTEX_BUFFER_ATTRIB_FLAG_CUSTOM_ARRAY:
|
||||||
{
|
{
|
||||||
@ -1508,13 +1588,13 @@ enable_state_for_drawing_buffer (CoglVertexBuffer *buffer)
|
|||||||
normalized = GL_TRUE;
|
normalized = GL_TRUE;
|
||||||
/* FIXME: go through cogl cache to enable generic array */
|
/* FIXME: go through cogl cache to enable generic array */
|
||||||
GE (glEnableVertexAttribArray (generic_index++));
|
GE (glEnableVertexAttribArray (generic_index++));
|
||||||
|
pointer = (const GLvoid *)(base + attribute->u.vbo_offset);
|
||||||
GE (glVertexAttribPointer (generic_index,
|
GE (glVertexAttribPointer (generic_index,
|
||||||
attribute->n_components,
|
attribute->n_components,
|
||||||
gl_type,
|
gl_type,
|
||||||
normalized,
|
normalized,
|
||||||
attribute->stride,
|
attribute->stride,
|
||||||
(const GLvoid *)
|
pointer));
|
||||||
attribute->u.vbo_offset));
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -1583,7 +1663,8 @@ disable_state_for_drawing_buffer (CoglVertexBuffer *buffer)
|
|||||||
/* Disable all the client state that cogl doesn't currently know
|
/* Disable all the client state that cogl doesn't currently know
|
||||||
* about:
|
* about:
|
||||||
*/
|
*/
|
||||||
GE (glBindBuffer (GL_ARRAY_BUFFER, 0));
|
if (cogl_get_features () & COGL_FEATURE_VBOS)
|
||||||
|
GE (glBindBuffer (GL_ARRAY_BUFFER, 0));
|
||||||
|
|
||||||
for (tmp = buffer->submitted_vbos; tmp != NULL; tmp = tmp->next)
|
for (tmp = buffer->submitted_vbos; tmp != NULL; tmp = tmp->next)
|
||||||
{
|
{
|
||||||
|
@ -65,6 +65,8 @@ _cogl_features_init (void)
|
|||||||
flags |= COGL_FEATURE_SHADERS_GLSL | COGL_FEATURE_OFFSCREEN;
|
flags |= COGL_FEATURE_SHADERS_GLSL | COGL_FEATURE_OFFSCREEN;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
flags |= COGL_FEATURE_VBOS;
|
||||||
|
|
||||||
/* Cache features */
|
/* Cache features */
|
||||||
ctx->feature_flags = flags;
|
ctx->feature_flags = flags;
|
||||||
ctx->features_cached = TRUE;
|
ctx->features_cached = TRUE;
|
||||||
|
Loading…
Reference in New Issue
Block a user