[cogl-vertex-buffers] Support putting index arrays into VBOS

It's now possible to add arrays of indices to a Cogl vertex buffer and
they will be put into an OpenGL vertex buffer object. Since it's quite
common for index arrays to be static it saves the OpenGL driver from
having to validate them repeatedly.

This changes the cogl_vertex_buffer_draw_elements API: It's no longer
possible to provide a pointer to an index array at draw time. So
cogl_vertex_buffer_draw_elements now takes an indices identifier that
should correspond to an idendifier returned when calling
cogl_vertex_buffer_add_indices ()
This commit is contained in:
Robert Bragg
2009-05-24 04:04:38 +01:00
parent 02faadae8b
commit 58b89eabdf
4 changed files with 232 additions and 43 deletions

View File

@ -214,6 +214,8 @@ cogl_vertex_buffer_new (guint n_vertices)
buffer->submitted_vbos = NULL;
buffer->new_attributes = NULL;
buffer->indices = NULL;
/* return COGL_INVALID_HANDLE; */
return _cogl_vertex_buffer_handle_new (buffer);
}
@ -1727,13 +1729,11 @@ cogl_vertex_buffer_draw (CoglHandle handle,
if (!cogl_is_vertex_buffer (handle))
return;
cogl_clip_ensure ();
buffer = _cogl_vertex_buffer_pointer_from_handle (handle);
enable_state_for_drawing_buffer (buffer);
cogl_clip_ensure ();
_cogl_current_matrix_state_flush ();
enable_state_for_drawing_buffer (buffer);
/* FIXME: flush cogl cache */
GE (glDrawArrays (mode, first, count));
@ -1741,35 +1741,158 @@ cogl_vertex_buffer_draw (CoglHandle handle,
disable_state_for_drawing_buffer (buffer);
}
static void
free_vertex_buffer_indices (CoglVertexBufferIndices *indices)
{
gboolean fallback =
(cogl_get_features () & COGL_FEATURE_VBOS) ? FALSE : TRUE;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
if (fallback)
g_free (indices->vbo_name);
else
GE (glDeleteBuffers (1, (GLuint *)&indices->vbo_name));
g_slice_free (CoglVertexBufferIndices, indices);
}
static int
get_indices_type_size (GLuint indices_type)
{
if (indices_type == GL_UNSIGNED_BYTE)
return sizeof (GLubyte);
if (indices_type == GL_UNSIGNED_SHORT)
return sizeof (GLushort);
else
{
g_critical ("Unknown indices type %d\n", indices_type);
return 0;
}
}
void
cogl_vertex_buffer_draw_elements (CoglHandle handle,
GLenum mode,
GLuint min_index,
GLuint max_index,
GLsizei count,
GLenum indices_type,
const GLvoid *indices)
cogl_vertex_buffer_add_indices (CoglHandle handle,
int id,
unsigned int min_index,
unsigned int max_index,
CoglIndicesType indices_type,
const void *indices_array,
size_t indices_len)
{
CoglVertexBuffer *buffer;
GList *l;
gboolean fallback =
(cogl_get_features () & COGL_FEATURE_VBOS) ? FALSE : TRUE;
size_t indices_bytes;
CoglVertexBufferIndices *indices;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
if (!cogl_is_vertex_buffer (handle))
return;
cogl_clip_ensure ();
buffer = _cogl_vertex_buffer_pointer_from_handle (handle);
for (l = buffer->indices; l; l = l->next)
{
CoglVertexBufferIndices *current_indices = l->data;
if (current_indices->id == id)
{
free_vertex_buffer_indices (l->data);
buffer->indices = g_list_delete_link (buffer->indices, l);
break;
}
}
indices = g_slice_alloc (sizeof (CoglVertexBufferIndices));
indices->id = id;
indices->min_index = min_index;
indices->max_index = max_index;
if (indices_type == COGL_INDICES_TYPE_UNSIGNED_BYTE)
indices->type = GL_UNSIGNED_BYTE;
else if (indices_type == COGL_INDICES_TYPE_UNSIGNED_SHORT)
indices->type = GL_UNSIGNED_SHORT;
else
{
g_critical ("unknown indices type %d", indices_type);
g_slice_free (CoglVertexBufferIndices, indices);
return;
}
indices_bytes = get_indices_type_size (indices->type) * indices_len;
if (fallback)
{
indices->vbo_name = g_malloc (indices_len);
memcpy (indices->vbo_name, indices_array, indices_bytes);
}
else
{
GE (glGenBuffers (1, (GLuint *)&indices->vbo_name));
GE (glBindBuffer (GL_ELEMENT_ARRAY_BUFFER,
GPOINTER_TO_UINT (indices->vbo_name)));
GE (glBufferData (GL_ELEMENT_ARRAY_BUFFER,
indices_bytes,
indices_array,
GL_STATIC_DRAW));
GE (glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, 0));
}
buffer->indices = g_list_prepend (buffer->indices, indices);
}
void
cogl_vertex_buffer_draw_elements (CoglHandle handle,
GLenum mode,
int indices_id,
unsigned int indices_offset,
unsigned int count)
{
CoglVertexBuffer *buffer;
gboolean fallback =
(cogl_get_features () & COGL_FEATURE_VBOS) ? FALSE : TRUE;
size_t byte_offset;
GList *l;
CoglVertexBufferIndices *indices = NULL;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
if (!cogl_is_vertex_buffer (handle))
return;
buffer = _cogl_vertex_buffer_pointer_from_handle (handle);
cogl_clip_ensure ();
_cogl_current_matrix_state_flush ();
enable_state_for_drawing_buffer (buffer);
_cogl_current_matrix_state_flush ();
for (l = buffer->indices; l; l = l->next)
{
CoglVertexBufferIndices *current_indices = l->data;
if (current_indices->id == indices_id)
{
indices = current_indices;
break;
}
}
if (!indices)
return;
byte_offset = indices_offset * get_indices_type_size (indices->type);
if (fallback)
byte_offset = (size_t)(((char *)indices->vbo_name) + byte_offset);
else
GE (glBindBuffer (GL_ELEMENT_ARRAY_BUFFER,
GPOINTER_TO_UINT (indices->vbo_name)));
/* FIXME: flush cogl cache */
GE (glDrawRangeElements (mode, min_index, max_index,
count, indices_type, indices));
GE (glDrawRangeElements (mode, indices->min_index, indices->max_index,
count, indices->type, (void *)byte_offset));
disable_state_for_drawing_buffer (buffer);
GE (glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, 0));
}
static void
@ -1779,8 +1902,16 @@ _cogl_vertex_buffer_free (CoglVertexBuffer *buffer)
for (tmp = buffer->submitted_vbos; tmp != NULL; tmp = tmp->next)
cogl_vertex_buffer_vbo_free (tmp->data, TRUE);
g_list_free (buffer->submitted_vbos);
for (tmp = buffer->new_attributes; tmp != NULL; tmp = tmp->next)
cogl_vertex_buffer_attribute_free (tmp->data);
g_list_free (buffer->new_attributes);
for (tmp = buffer->indices; tmp != NULL; tmp = tmp->next)
free_vertex_buffer_indices (tmp->data);
g_list_free (buffer->indices);
g_slice_free (CoglVertexBuffer, buffer);
}