From 39cb36ba0110a65696cff9461caf52227762be34 Mon Sep 17 00:00:00 2001 From: Neil Roberts Date: Thu, 28 May 2009 13:47:18 +0100 Subject: [PATCH] [cogl-vertex-buffer] Add cogl_vertex_buffer_indices_get_for_quads This function can be used as an efficient way of drawing groups of quads without using GL_QUADS. It generates a VBO containing the indices needed to render using pairs of GL_TRIANGLES. The VBO is globally cached so that it only needs to be uploaded whenever more indices are requested than ever before. --- cogl-vertex-buffer.h | 40 ++++++++++++++ common/cogl-vertex-buffer.c | 80 ++++++++++++++++++++++++++++ doc/reference/cogl/cogl-sections.txt | 1 + gl/cogl-context.c | 9 ++++ gl/cogl-context.h | 6 +++ gles/cogl-context.c | 9 ++++ gles/cogl-context.h | 7 ++- 7 files changed, 151 insertions(+), 1 deletion(-) diff --git a/cogl-vertex-buffer.h b/cogl-vertex-buffer.h index ab37dbced..f01b5d3dd 100644 --- a/cogl-vertex-buffer.h +++ b/cogl-vertex-buffer.h @@ -394,6 +394,46 @@ cogl_vertex_buffer_ref (CoglHandle handle); void cogl_vertex_buffer_unref (CoglHandle handle); +/** + * cogl_vertex_buffer_indices_get_for_quads: + * @n_indices: the number of indices in the vertex buffer. + * + * Creates a vertex buffer containing the indices needed to draw pairs + * of triangles from a list of vertices grouped as quads. There will + * be at least @n_indices entries in the buffer (but there may be + * more). + * + * The indices will follow this pattern: + * + * 0, 1, 2, 0, 2, 3, 4, 5, 6, 4, 6, 7 ... etc + * + * For example, if you submit vertices for a quad like this: + * + * |[ + * 0 3 + * ######## + * # # + * # # + * ######## + * 1 2 + * ]| + * + * Then you can request 6 indices to render two triangles like this: + * + * |[ + * 0 0 3 + * ## ######## + * # ## ## # + * # ## ## # + * ######## ## + * 1 2 2 + * ]| + * + * Returns: A %CoglHandle containing the indices. The handled is + * owned by Cogl and should not be modified or unref'd. + */ +CoglHandle +cogl_vertex_buffer_indices_get_for_quads (guint n_indices); G_END_DECLS diff --git a/common/cogl-vertex-buffer.c b/common/cogl-vertex-buffer.c index b3c36f0ec..a36bb1cec 100644 --- a/common/cogl-vertex-buffer.c +++ b/common/cogl-vertex-buffer.c @@ -1880,3 +1880,83 @@ _cogl_vertex_buffer_free (CoglVertexBuffer *buffer) g_slice_free (CoglVertexBuffer, buffer); } +CoglHandle +cogl_vertex_buffer_indices_get_for_quads (guint n_indices) +{ + _COGL_GET_CONTEXT (ctx, COGL_INVALID_HANDLE); + + /* Check if the indices would fit in a byte array */ + if (n_indices <= 256 / 4 * 6) + { + /* Generate the byte array if we haven't already */ + if (ctx->quad_indices_byte == COGL_INVALID_HANDLE) + { + guint8 *byte_array = g_malloc (256 / 4 * 6 * sizeof (guint8)); + guint8 *p = byte_array; + int i, vert_num = 0; + + for (i = 0; i < 256 / 4; i++) + { + *(p++) = vert_num + 0; + *(p++) = vert_num + 1; + *(p++) = vert_num + 2; + *(p++) = vert_num + 0; + *(p++) = vert_num + 2; + *(p++) = vert_num + 3; + vert_num += 4; + } + + ctx->quad_indices_byte + = cogl_vertex_buffer_indices_new (COGL_INDICES_TYPE_UNSIGNED_BYTE, + byte_array, + 256 / 4 * 6); + + g_free (byte_array); + } + + return ctx->quad_indices_byte; + } + else + { + if (ctx->quad_indices_short_len < n_indices) + { + guint16 *short_array; + guint16 *p; + int i, vert_num = 0; + + if (ctx->quad_indices_short != COGL_INVALID_HANDLE) + cogl_handle_unref (ctx->quad_indices_short); + /* Pick a power of two >= MAX (512, n_indices) */ + if (ctx->quad_indices_short_len == 0) + ctx->quad_indices_short_len = 512; + while (ctx->quad_indices_short_len < n_indices) + ctx->quad_indices_short_len *= 2; + + /* Over-allocate to generate a whole number of quads */ + p = short_array = g_malloc ((ctx->quad_indices_short_len + + 5) / 6 * 6 + * sizeof (guint16)); + + /* Fill in the complete quads */ + for (i = 0; i < ctx->quad_indices_short_len; i += 6) + { + *(p++) = vert_num + 0; + *(p++) = vert_num + 1; + *(p++) = vert_num + 2; + *(p++) = vert_num + 0; + *(p++) = vert_num + 2; + *(p++) = vert_num + 3; + vert_num += 4; + } + + ctx->quad_indices_short + = cogl_vertex_buffer_indices_new (COGL_INDICES_TYPE_UNSIGNED_SHORT, + short_array, + ctx->quad_indices_short_len); + + g_free (short_array); + } + + return ctx->quad_indices_short; + } +} diff --git a/doc/reference/cogl/cogl-sections.txt b/doc/reference/cogl/cogl-sections.txt index 9d49ea53f..f596ee042 100644 --- a/doc/reference/cogl/cogl-sections.txt +++ b/doc/reference/cogl/cogl-sections.txt @@ -313,6 +313,7 @@ CoglIndicesType cogl_vertex_buffer_add_indices cogl_vertex_buffer_delete_indices cogl_vertex_buffer_draw_elements +cogl_vertex_buffer_indices_get_for_quads CoglVertexBufferAttribFlags COGL_VERTEX_BUFFER_ATTRIB_FLAG_GL_TYPE_MASK diff --git a/gl/cogl-context.c b/gl/cogl-context.c index 39415a02a..16fcb3e12 100644 --- a/gl/cogl-context.c +++ b/gl/cogl-context.c @@ -171,6 +171,10 @@ cogl_create_context () _cogl_material_get_cogl_enable_flags (_context->source_material); cogl_enable (enable_flags); + _context->quad_indices_byte = COGL_INVALID_HANDLE; + _context->quad_indices_short = COGL_INVALID_HANDLE; + _context->quad_indices_short_len = 0; + return TRUE; } @@ -207,6 +211,11 @@ _cogl_destroy_context () if (_context->current_layers) g_array_free (_context->current_layers, TRUE); + if (_context->quad_indices_byte) + cogl_handle_unref (_context->quad_indices_byte); + if (_context->quad_indices_short) + cogl_handle_unref (_context->quad_indices_short); + g_free (_context); } diff --git a/gl/cogl-context.h b/gl/cogl-context.h index f490d39ac..f5ca54cb2 100644 --- a/gl/cogl-context.h +++ b/gl/cogl-context.h @@ -102,6 +102,12 @@ typedef struct floatVec2 path_nodes_max; CoglHandle stencil_material; + /* Pre-generated VBOs containing indices to generate GL_TRIANGLES + out of a vertex array of quads */ + CoglHandle quad_indices_byte; + guint quad_indices_short_len; + CoglHandle quad_indices_short; + /* Relying on glext.h to define these */ COGL_PFNGLGENRENDERBUFFERSEXTPROC pf_glGenRenderbuffersEXT; COGL_PFNGLDELETERENDERBUFFERSEXTPROC pf_glDeleteRenderbuffersEXT; diff --git a/gles/cogl-context.c b/gles/cogl-context.c index 5b6ce7c1b..d3ec31c5d 100644 --- a/gles/cogl-context.c +++ b/gles/cogl-context.c @@ -129,6 +129,10 @@ cogl_create_context () _cogl_material_get_cogl_enable_flags (_context->source_material); cogl_enable (enable_flags); + _context->quad_indices_byte = COGL_INVALID_HANDLE; + _context->quad_indices_short = COGL_INVALID_HANDLE; + _context->quad_indices_short_len = 0; + return TRUE; } @@ -165,6 +169,11 @@ _cogl_destroy_context () if (_context->current_layers) g_array_free (_context->current_layers, TRUE); + if (_context->quad_indices_byte) + cogl_handle_unref (_context->quad_indices_byte); + if (_context->quad_indices_short) + cogl_handle_unref (_context->quad_indices_short); + g_free (_context); } diff --git a/gles/cogl-context.h b/gles/cogl-context.h index 3542e038d..9c1d44fbe 100644 --- a/gles/cogl-context.h +++ b/gles/cogl-context.h @@ -104,6 +104,12 @@ typedef struct floatVec2 path_nodes_max; CoglHandle stencil_material; + /* Pre-generated VBOs containing indices to generate GL_TRIANGLES + out of a vertex array of quads */ + CoglHandle quad_indices_byte; + guint quad_indices_short_len; + CoglHandle quad_indices_short; + #ifdef HAVE_COGL_GLES2 CoglGles2Wrapper gles2; @@ -111,7 +117,6 @@ typedef struct supported */ GLint viewport_store[4]; #endif - } CoglContext; CoglContext *