[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:
parent
02faadae8b
commit
58b89eabdf
@ -256,6 +256,54 @@ cogl_vertex_buffer_draw (CoglHandle handle,
|
|||||||
GLint first,
|
GLint first,
|
||||||
GLsizei count);
|
GLsizei count);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CoglIndicesType:
|
||||||
|
* @COGL_INDICES_TYPE_UNSIGNED_BYTE: Your indices are unsigned bytes
|
||||||
|
* @COGL_INDICES_TYPE_UNSIGNED_SHORT: Your indices are unsigned shorts
|
||||||
|
* @COGL_INDICES_TYPE_UNSIGNED_INT: You indices are unsigned integers
|
||||||
|
*
|
||||||
|
* You should aim to use the smallest data type that gives you enough
|
||||||
|
* range, since it reduces the size of your index array and can help
|
||||||
|
* reduce the demand on memory bandwidth.
|
||||||
|
*/
|
||||||
|
typedef enum _CoglIndicesType
|
||||||
|
{
|
||||||
|
COGL_INDICES_TYPE_UNSIGNED_BYTE,
|
||||||
|
COGL_INDICES_TYPE_UNSIGNED_SHORT,
|
||||||
|
COGL_INDICES_TYPE_UNSIGNED_INT
|
||||||
|
} CoglIndicesType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cogl_vertex_buffer_add_indices:
|
||||||
|
* @handle: A vertex buffer handle
|
||||||
|
* @id: Any unique number. It's used to identify the indices when you later
|
||||||
|
* call cogl_vertex_buffer_draw_elements()
|
||||||
|
* @min_index: Specifies the minimum vertex index contained in indices
|
||||||
|
* @max_index: Specifies the maximum vertex index contained in indices
|
||||||
|
* @indices_type: a #CoglIndicesType specifying the data type used for
|
||||||
|
* the indices.
|
||||||
|
* @indices_array: Specifies the address of your array of indices
|
||||||
|
* @indices_len: The number of indices in indices_array
|
||||||
|
*
|
||||||
|
* Depending on how much geometry you are submitting it can be worthwhile
|
||||||
|
* optimizing the number of redundant vertices you submit. Using an index
|
||||||
|
* array allows you to reference vertices multiple times, for example
|
||||||
|
* during triangle strips.
|
||||||
|
*
|
||||||
|
* You should aim to use the COGL_INDICES_TYPE_UNSIGNED_SHORT when possible
|
||||||
|
* and correctly reflect the range of index values in the {min,max}_index
|
||||||
|
* arguments. This allows Cogl to optimize the internal storage used for
|
||||||
|
* the indices and reduce the demand for memory bandwidth.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
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);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* cogl_vertex_buffer_draw_elements:
|
* cogl_vertex_buffer_draw_elements:
|
||||||
* @handle: A vertex buffer handle
|
* @handle: A vertex buffer handle
|
||||||
@ -270,33 +318,26 @@ cogl_vertex_buffer_draw (CoglHandle handle,
|
|||||||
* <listitem>GL_TRIANGLE_FAN</listitem>
|
* <listitem>GL_TRIANGLE_FAN</listitem>
|
||||||
* <listitem>GL_TRIANGLES</listitem>
|
* <listitem>GL_TRIANGLES</listitem>
|
||||||
* </itemizedlist>
|
* </itemizedlist>
|
||||||
* (Note: only types available in GLES are listed)
|
* @indices_id: The identifier for a an array of indices previously added to
|
||||||
* @min_index: Specifies the minimum vertex index contained in indices
|
* the given Cogl vertex buffer using
|
||||||
* @max_index: Specifies the maximum vertex index contained in indices
|
* cogl_vertex_buffer_add_indices().
|
||||||
|
* @indices_offset: An offset into named indices. The offset marks the first
|
||||||
|
* index to use for drawing.
|
||||||
* @count: Specifies the number of vertices you want to draw.
|
* @count: Specifies the number of vertices you want to draw.
|
||||||
* @indices_type: Specifies the data type used for the indices, and must be
|
|
||||||
* one of:
|
|
||||||
* <itemizedlist>
|
|
||||||
* <listitem>GL_UNSIGNED_BYTE</listitem>
|
|
||||||
* <listitem>GL_UNSIGNED_SHORT</listitem>
|
|
||||||
* <listitem>GL_UNSIGNED_INT</listitem>
|
|
||||||
* </itemizedlist>
|
|
||||||
* @indices: Specifies the address of your array of indices
|
|
||||||
*
|
*
|
||||||
* This function lets you use an array of indices to specify the vertices
|
* This function lets you use an array of indices to specify the vertices
|
||||||
* within your vertex buffer that you want to draw.
|
* within your vertex buffer that you want to draw. The indices themselves
|
||||||
|
* are given by calling cogl_vertex_buffer_add_indices ()
|
||||||
*
|
*
|
||||||
* Any un-submitted attribute changes are automatically submitted before
|
* Any un-submitted attribute changes are automatically submitted before
|
||||||
* drawing.
|
* drawing.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
cogl_vertex_buffer_draw_elements (CoglHandle handle,
|
cogl_vertex_buffer_draw_elements (CoglHandle handle,
|
||||||
GLenum mode,
|
GLenum mode,
|
||||||
GLuint min_index,
|
int indices_id,
|
||||||
GLuint max_index,
|
unsigned int indices_offset,
|
||||||
GLsizei count,
|
unsigned int count);
|
||||||
GLenum indices_type,
|
|
||||||
const GLvoid *indices);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* cogl_vertex_buffer_ref:
|
* cogl_vertex_buffer_ref:
|
||||||
|
@ -99,9 +99,9 @@ typedef struct _CoglVertexBufferAttrib
|
|||||||
union _u
|
union _u
|
||||||
{
|
{
|
||||||
const void *pointer;
|
const void *pointer;
|
||||||
gsize vbo_offset;
|
size_t vbo_offset;
|
||||||
} u;
|
} u;
|
||||||
gsize span_bytes;
|
size_t span_bytes;
|
||||||
guint16 stride;
|
guint16 stride;
|
||||||
guint8 n_components;
|
guint8 n_components;
|
||||||
guint8 texture_unit;
|
guint8 texture_unit;
|
||||||
@ -129,24 +129,39 @@ typedef struct _CoglVertexBufferVBO
|
|||||||
{
|
{
|
||||||
CoglVertexBufferVBOFlags flags;
|
CoglVertexBufferVBOFlags flags;
|
||||||
|
|
||||||
/* Note: this is a pointer to handle fallbacks, and normally holds
|
/* Note: this is a pointer to handle fallbacks. It normally holds
|
||||||
* a GLuint value */
|
* a GLuint VBO name, but when the driver doesn't support VBOs then
|
||||||
gpointer vbo_name; /*!< The name of the corresponding buffer object */
|
* this simply points to an malloc'd buffer. */
|
||||||
gsize vbo_bytes; /*!< The lengh of the allocated buffer object in bytes */
|
void *vbo_name; /*!< The name of the corresponding buffer object */
|
||||||
|
size_t vbo_bytes; /*!< The lengh of the allocated buffer object in bytes */
|
||||||
GList *attributes;
|
GList *attributes;
|
||||||
} CoglVertexBufferVBO;
|
} CoglVertexBufferVBO;
|
||||||
|
|
||||||
|
typedef struct _CoglVertexBufferIndices
|
||||||
|
{
|
||||||
|
int id;
|
||||||
|
/* Note: this is a pointer to handle fallbacks. It normally holds
|
||||||
|
* a GLuint VBO name, but when the driver doesn't support VBOs then
|
||||||
|
* this simply points to an malloc'd buffer. */
|
||||||
|
void *vbo_name;
|
||||||
|
GLenum type;
|
||||||
|
GLuint min_index;
|
||||||
|
GLuint max_index;
|
||||||
|
} CoglVertexBufferIndices;
|
||||||
|
|
||||||
typedef struct _CoglVertexBuffer
|
typedef struct _CoglVertexBuffer
|
||||||
{
|
{
|
||||||
CoglHandleObject _parent;
|
CoglHandleObject _parent;
|
||||||
|
|
||||||
guint n_vertices; /*!< The number of vertices in the buffer */
|
int n_vertices; /*!< The number of vertices in the buffer */
|
||||||
GList *submitted_vbos; /* The VBOs currently submitted to the GPU */
|
GList *submitted_vbos; /* The VBOs currently submitted to the GPU */
|
||||||
|
|
||||||
/* Note: new_attributes is normally NULL and only valid while
|
/* Note: new_attributes is normally NULL and only valid while
|
||||||
* modifying a buffer. */
|
* modifying a buffer. */
|
||||||
GList *new_attributes; /*!< attributes pending submission */
|
GList *new_attributes; /*!< attributes pending submission */
|
||||||
|
|
||||||
|
GList *indices; /*!< A list of associated index arrays */
|
||||||
|
|
||||||
} CoglVertexBuffer;
|
} CoglVertexBuffer;
|
||||||
|
|
||||||
#endif /* __COGL_VERTEX_BUFFER_H */
|
#endif /* __COGL_VERTEX_BUFFER_H */
|
||||||
|
@ -214,6 +214,8 @@ cogl_vertex_buffer_new (guint n_vertices)
|
|||||||
buffer->submitted_vbos = NULL;
|
buffer->submitted_vbos = NULL;
|
||||||
buffer->new_attributes = NULL;
|
buffer->new_attributes = NULL;
|
||||||
|
|
||||||
|
buffer->indices = NULL;
|
||||||
|
|
||||||
/* return COGL_INVALID_HANDLE; */
|
/* return COGL_INVALID_HANDLE; */
|
||||||
return _cogl_vertex_buffer_handle_new (buffer);
|
return _cogl_vertex_buffer_handle_new (buffer);
|
||||||
}
|
}
|
||||||
@ -1727,13 +1729,11 @@ cogl_vertex_buffer_draw (CoglHandle handle,
|
|||||||
if (!cogl_is_vertex_buffer (handle))
|
if (!cogl_is_vertex_buffer (handle))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
cogl_clip_ensure ();
|
|
||||||
|
|
||||||
buffer = _cogl_vertex_buffer_pointer_from_handle (handle);
|
buffer = _cogl_vertex_buffer_pointer_from_handle (handle);
|
||||||
|
|
||||||
enable_state_for_drawing_buffer (buffer);
|
cogl_clip_ensure ();
|
||||||
|
|
||||||
_cogl_current_matrix_state_flush ();
|
_cogl_current_matrix_state_flush ();
|
||||||
|
enable_state_for_drawing_buffer (buffer);
|
||||||
|
|
||||||
/* FIXME: flush cogl cache */
|
/* FIXME: flush cogl cache */
|
||||||
GE (glDrawArrays (mode, first, count));
|
GE (glDrawArrays (mode, first, count));
|
||||||
@ -1741,35 +1741,158 @@ cogl_vertex_buffer_draw (CoglHandle handle,
|
|||||||
disable_state_for_drawing_buffer (buffer);
|
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
|
void
|
||||||
cogl_vertex_buffer_draw_elements (CoglHandle handle,
|
cogl_vertex_buffer_add_indices (CoglHandle handle,
|
||||||
GLenum mode,
|
int id,
|
||||||
GLuint min_index,
|
unsigned int min_index,
|
||||||
GLuint max_index,
|
unsigned int max_index,
|
||||||
GLsizei count,
|
CoglIndicesType indices_type,
|
||||||
GLenum indices_type,
|
const void *indices_array,
|
||||||
const GLvoid *indices)
|
size_t indices_len)
|
||||||
{
|
{
|
||||||
CoglVertexBuffer *buffer;
|
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);
|
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||||
|
|
||||||
if (!cogl_is_vertex_buffer (handle))
|
if (!cogl_is_vertex_buffer (handle))
|
||||||
return;
|
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);
|
buffer = _cogl_vertex_buffer_pointer_from_handle (handle);
|
||||||
|
|
||||||
|
cogl_clip_ensure ();
|
||||||
|
_cogl_current_matrix_state_flush ();
|
||||||
enable_state_for_drawing_buffer (buffer);
|
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 */
|
/* FIXME: flush cogl cache */
|
||||||
GE (glDrawRangeElements (mode, min_index, max_index,
|
GE (glDrawRangeElements (mode, indices->min_index, indices->max_index,
|
||||||
count, indices_type, indices));
|
count, indices->type, (void *)byte_offset));
|
||||||
|
|
||||||
disable_state_for_drawing_buffer (buffer);
|
disable_state_for_drawing_buffer (buffer);
|
||||||
|
|
||||||
|
GE (glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -1779,8 +1902,16 @@ _cogl_vertex_buffer_free (CoglVertexBuffer *buffer)
|
|||||||
|
|
||||||
for (tmp = buffer->submitted_vbos; tmp != NULL; tmp = tmp->next)
|
for (tmp = buffer->submitted_vbos; tmp != NULL; tmp = tmp->next)
|
||||||
cogl_vertex_buffer_vbo_free (tmp->data, TRUE);
|
cogl_vertex_buffer_vbo_free (tmp->data, TRUE);
|
||||||
|
g_list_free (buffer->submitted_vbos);
|
||||||
|
|
||||||
for (tmp = buffer->new_attributes; tmp != NULL; tmp = tmp->next)
|
for (tmp = buffer->new_attributes; tmp != NULL; tmp = tmp->next)
|
||||||
cogl_vertex_buffer_attribute_free (tmp->data);
|
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);
|
g_slice_free (CoglVertexBuffer, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -307,6 +307,8 @@ cogl_vertex_buffer_submit
|
|||||||
cogl_vertex_buffer_disable
|
cogl_vertex_buffer_disable
|
||||||
cogl_vertex_buffer_enable
|
cogl_vertex_buffer_enable
|
||||||
cogl_vertex_buffer_draw
|
cogl_vertex_buffer_draw
|
||||||
|
CoglIndicesType
|
||||||
|
cogl_vertex_buffer_add_indices
|
||||||
cogl_vertex_buffer_draw_elements
|
cogl_vertex_buffer_draw_elements
|
||||||
<SUBSECTION Private>
|
<SUBSECTION Private>
|
||||||
CoglVertexBufferAttribFlags
|
CoglVertexBufferAttribFlags
|
||||||
|
Loading…
Reference in New Issue
Block a user