From 98c0fe934bde09be57d373b4395f27ff894aeca8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Wed, 20 Nov 2019 14:58:02 +0100 Subject: [PATCH] cogl: Remove CoglVertexBuffer It was deprecated, relied on deprecated API (implicit framebuffers, mateiarls etc), and was unused. Lets remove it. https://gitlab.gnome.org/GNOME/mutter/merge_requests/935 --- cogl/cogl/cogl-primitives.h | 3 +- cogl/cogl/cogl.h | 1 - cogl/cogl/deprecated/cogl-auto-texture.h | 3 +- .../deprecated/cogl-vertex-buffer-private.h | 165 -- cogl/cogl/deprecated/cogl-vertex-buffer.c | 1792 ----------------- cogl/cogl/deprecated/cogl-vertex-buffer.h | 425 ---- cogl/cogl/driver/gl/cogl-pipeline-opengl.c | 2 +- cogl/cogl/meson.build | 3 - cogl/tests/conform/meson.build | 2 - .../conform/test-vertex-buffer-contiguous.c | 259 --- .../conform/test-vertex-buffer-interleved.c | 164 -- cogl/tests/conform/test-wrap-modes.c | 46 - src/tests/clutter/interactive/meson.build | 1 - .../interactive/test-cogl-point-sprites.c | 17 - .../interactive/test-cogl-vertex-buffer.c | 398 ---- 15 files changed, 3 insertions(+), 3278 deletions(-) delete mode 100644 cogl/cogl/deprecated/cogl-vertex-buffer-private.h delete mode 100644 cogl/cogl/deprecated/cogl-vertex-buffer.c delete mode 100644 cogl/cogl/deprecated/cogl-vertex-buffer.h delete mode 100644 cogl/tests/conform/test-vertex-buffer-contiguous.c delete mode 100644 cogl/tests/conform/test-vertex-buffer-interleved.c delete mode 100644 src/tests/clutter/interactive/test-cogl-vertex-buffer.c diff --git a/cogl/cogl/cogl-primitives.h b/cogl/cogl/cogl-primitives.h index a24dc5990..60e0f4c68 100644 --- a/cogl/cogl/cogl-primitives.h +++ b/cogl/cogl/cogl-primitives.h @@ -40,8 +40,7 @@ G_BEGIN_DECLS * @short_description: Functions that draw various primitive 3D shapes * * The primitives API provides utilities for drawing some - * common 3D shapes in a more convenient way than the CoglVertexBuffer - * API provides. + * common 3D shapes. */ /** diff --git a/cogl/cogl/cogl.h b/cogl/cogl/cogl.h index c9c5ffcbf..29601cc58 100644 --- a/cogl/cogl/cogl.h +++ b/cogl/cogl/cogl.h @@ -88,7 +88,6 @@ #include #include #include -#include #ifdef COGL_ENABLE_MUTTER_API #include diff --git a/cogl/cogl/deprecated/cogl-auto-texture.h b/cogl/cogl/deprecated/cogl-auto-texture.h index b184ee364..df2b1da29 100644 --- a/cogl/cogl/deprecated/cogl-auto-texture.h +++ b/cogl/cogl/deprecated/cogl-auto-texture.h @@ -160,8 +160,7 @@ cogl_texture_new_from_bitmap (CoglBitmap *bitmap, * data is actually allocated. * * Sub textures have undefined behaviour texture coordinates outside - * of the range [0,1] are used. They also do not work with - * CoglVertexBuffers. + * of the range [0,1] are used. * * The sub texture will keep a reference to the full texture so you do * not need to keep one separately if you only want to use the sub diff --git a/cogl/cogl/deprecated/cogl-vertex-buffer-private.h b/cogl/cogl/deprecated/cogl-vertex-buffer-private.h deleted file mode 100644 index 69af36ebf..000000000 --- a/cogl/cogl/deprecated/cogl-vertex-buffer-private.h +++ /dev/null @@ -1,165 +0,0 @@ -/* - * Cogl - * - * A Low Level GPU Graphics and Utilities API - * - * Copyright (C) 2008,2009 Intel Corporation. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * - * - * Authors: - * Robert Bragg - */ - -#ifndef __COGL_VERTEX_BUFFER_H -#define __COGL_VERTEX_BUFFER_H - -#include "cogl-object-private.h" - -#include "cogl-primitive.h" - -#include - -/* Note we put quite a bit into the flags here to help keep - * the down size of the CoglVertexBufferAttrib struct below. */ -typedef enum _CoglVertexBufferAttribFlags -{ - /* Types */ - /* NB: update the _TYPE_MASK below if these are changed */ - COGL_VERTEX_BUFFER_ATTRIB_FLAG_COLOR_ARRAY = 1<<0, - COGL_VERTEX_BUFFER_ATTRIB_FLAG_NORMAL_ARRAY = 1<<1, - COGL_VERTEX_BUFFER_ATTRIB_FLAG_TEXTURE_COORD_ARRAY = 1<<2, - COGL_VERTEX_BUFFER_ATTRIB_FLAG_VERTEX_ARRAY = 1<<3, - COGL_VERTEX_BUFFER_ATTRIB_FLAG_CUSTOM_ARRAY = 1<<4, - COGL_VERTEX_BUFFER_ATTRIB_FLAG_INVALID = 1<<5, - - COGL_VERTEX_BUFFER_ATTRIB_FLAG_NORMALIZED = 1<<6, - COGL_VERTEX_BUFFER_ATTRIB_FLAG_ENABLED = 1<<7, - - /* Usage hints */ - /* FIXME - flatten into one flag, since its used as a boolean */ - COGL_VERTEX_BUFFER_ATTRIB_FLAG_INFREQUENT_RESUBMIT = 1<<8, - COGL_VERTEX_BUFFER_ATTRIB_FLAG_FREQUENT_RESUBMIT = 1<<9, - - /* GL Data types */ - /* NB: Update the _GL_TYPE_MASK below if these are changed */ - COGL_VERTEX_BUFFER_ATTRIB_FLAG_GL_TYPE_BYTE = 1<<10, - COGL_VERTEX_BUFFER_ATTRIB_FLAG_GL_TYPE_UNSIGNED_BYTE = 1<<11, - COGL_VERTEX_BUFFER_ATTRIB_FLAG_GL_TYPE_SHORT = 1<<12, - COGL_VERTEX_BUFFER_ATTRIB_FLAG_GL_TYPE_UNSIGNED_SHORT = 1<<13, - COGL_VERTEX_BUFFER_ATTRIB_FLAG_GL_TYPE_INT = 1<<14, - COGL_VERTEX_BUFFER_ATTRIB_FLAG_GL_TYPE_UNSIGNED_INT = 1<<15, - COGL_VERTEX_BUFFER_ATTRIB_FLAG_GL_TYPE_FLOAT = 1<<16, - COGL_VERTEX_BUFFER_ATTRIB_FLAG_GL_TYPE_DOUBLE = 1<<17, - - COGL_VERTEX_BUFFER_ATTRIB_FLAG_SUBMITTED = 1<<18, - COGL_VERTEX_BUFFER_ATTRIB_FLAG_UNUSED = 1<<19 - - /* XXX NB: If we need > 24 bits then look at changing the layout - * of struct _CoglVertexBufferAttrib below */ -} CoglVertexBufferAttribFlags; - -#define COGL_VERTEX_BUFFER_ATTRIB_FLAG_TYPE_MASK \ - (COGL_VERTEX_BUFFER_ATTRIB_FLAG_COLOR_ARRAY \ - | COGL_VERTEX_BUFFER_ATTRIB_FLAG_NORMAL_ARRAY \ - | COGL_VERTEX_BUFFER_ATTRIB_FLAG_TEXTURE_COORD_ARRAY \ - | COGL_VERTEX_BUFFER_ATTRIB_FLAG_VERTEX_ARRAY \ - | COGL_VERTEX_BUFFER_ATTRIB_FLAG_CUSTOM_ARRAY \ - | COGL_VERTEX_BUFFER_ATTRIB_FLAG_INVALID) - -typedef struct _CoglVertexBufferAttrib -{ - /* TODO: look at breaking up the flags into seperate - * bitfields and seperate enums */ - CoglVertexBufferAttribFlags flags:24; - uint8_t id; - GQuark name; - char *name_without_detail; - union _u - { - const void *pointer; - size_t vbo_offset; - } u; - CoglAttributeType type; - size_t span_bytes; - uint16_t stride; - uint8_t n_components; - uint8_t texture_unit; - - int attribute_first; - CoglAttribute *attribute; - -} CoglVertexBufferAttrib; - -typedef enum _CoglVertexBufferVBOFlags -{ - COGL_VERTEX_BUFFER_VBO_FLAG_STRIDED = 1<<0, - COGL_VERTEX_BUFFER_VBO_FLAG_MULTIPACK = 1<<1, - - /* FIXME - flatten into one flag, since its used as a boolean */ - COGL_VERTEX_BUFFER_VBO_FLAG_INFREQUENT_RESUBMIT = 1<<3, - COGL_VERTEX_BUFFER_VBO_FLAG_FREQUENT_RESUBMIT = 1<<4, - - COGL_VERTEX_BUFFER_VBO_FLAG_SUBMITTED = 1<<5 -} CoglVertexBufferVBOFlags; - -/* - * A CoglVertexBufferVBO represents one or more attributes in a single - * buffer object - */ -typedef struct _CoglVertexBufferVBO -{ - CoglVertexBufferVBOFlags flags; - - CoglAttributeBuffer *attribute_buffer; - size_t buffer_bytes; - - GList *attributes; -} CoglVertexBufferVBO; - -typedef struct _CoglVertexBufferIndices -{ - CoglHandleObject _parent; - - CoglIndices *indices; -} CoglVertexBufferIndices; - -typedef struct _CoglVertexBuffer -{ - CoglHandleObject _parent; - - int n_vertices; /*!< The number of vertices in the buffer */ - GList *submitted_vbos; /* The VBOs currently submitted to the GPU */ - - /* Note: new_attributes is normally NULL and only valid while - * modifying a buffer. */ - GList *new_attributes; /*!< attributes pending submission */ - - gboolean dirty_attributes; - - CoglPrimitive *primitive; - -} CoglVertexBuffer; - -#endif /* __COGL_VERTEX_BUFFER_H */ - diff --git a/cogl/cogl/deprecated/cogl-vertex-buffer.c b/cogl/cogl/deprecated/cogl-vertex-buffer.c deleted file mode 100644 index e1ce7dd3d..000000000 --- a/cogl/cogl/deprecated/cogl-vertex-buffer.c +++ /dev/null @@ -1,1792 +0,0 @@ -/* - * Cogl - * - * A Low Level GPU Graphics and Utilities API - * - * Copyright (C) 2008,2009,2010 Intel Corporation. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * - * - * Authors: - * Robert Bragg - */ - -/* XXX: For an overview of the functionality implemented here, please - * see cogl-vertex-buffer.h, which contains the gtk-doc section overview - * for the Vertex Buffers API. - */ - -/* - * TODO: We need to do a better job of minimizing when we call glVertexPointer - * and pals in enable_state_for_drawing_buffer - * - * We should have an internal 2-tuple cache of (VBO, offset) for each of them - * so we can avoid some GL calls. We could have cogl wrappers for the - * gl*Pointer funcs that look like this: - * - * cogl_vertex_pointer (n_components, gl_type, stride, vbo, offset); - * cogl_color_pointer (n_components, gl_type, stride, vbo, offset); - * - * They would also accept NULL for the VBO handle to support old style vertex - * arrays. - * - * TODO: - * Actually hook this up to the cogl shaders infrastructure. The vertex - * buffer API has been designed to allow adding of arbitrary attributes for use - * with shaders, but this has yet to be actually plumbed together and tested. - * The bits we are missing: - * - cogl_program_use doesn't currently record within ctx-> which program - * is currently in use so a.t.m only Clutter knows the current shader. - * - We don't query the current shader program for the generic vertex indices - * (using glGetAttribLocation) so that we can call glEnableVertexAttribArray - * with those indices. - * (currently we just make up consecutive indices) - * - some dirty flag mechanims to know when the shader program has changed - * so we don't need to re-query it each time we draw a buffer. - * - * TODO - * Expose API that lets developers get back a buffer handle for a particular - * polygon so they may add custom attributes to them. - * - It should be possible to query/modify attributes efficiently, in place, - * avoiding copies. It would not be acceptable to simply require that - * developers must query back the n_vertices of a buffer and then the - * n_components, type and stride etc of each attribute since there - * would be too many combinations to realistically handle. - * - * - In practice, some cases might be best solved with a higher level - * EditableMesh API, (see futher below) but for many cases I think an - * API like this might be appropriate: - * - * cogl_vertex_buffer_foreach_vertex (buffer_handle, - * (AttributesBufferIteratorFunc)callback, - * "gl_Vertex", "gl_Color", NULL); - * static void callback (CoglVertexBufferVertex *vert) - * { - * GLfloat *pos = vert->attrib[0]; - * GLubyte *color = vert->attrib[1]; - * GLfloat *new_attrib = buf[vert->index]; - * - * new_attrib = pos*color; - * } - * - * TODO - * Think about a higher level Mesh API for building/modifying attribute buffers - * - E.g. look at Blender for inspiration here. They can build a mesh from - * "MVert", "MFace" and "MEdge" primitives. - */ - -#include "cogl-config.h" - -#include -#include -#include - -#include "cogl-util.h" -#include "cogl-context-private.h" -#include "cogl-object-private.h" -#include "cogl-texture-private.h" -#include "cogl-pipeline.h" -#include "cogl-pipeline-private.h" -#include "cogl-primitives.h" -#include "cogl-framebuffer-private.h" -#include "cogl-primitive-private.h" -#include "cogl-journal-private.h" -#include "cogl1-context.h" -#include "cogl-vertex-buffer.h" -#include "deprecated/cogl-vertex-buffer-private.h" - -#define PAD_FOR_ALIGNMENT(VAR, TYPE_SIZE) \ - (VAR = TYPE_SIZE + ((VAR - 1) & ~(TYPE_SIZE - 1))) - -static void _cogl_vertex_buffer_free (CoglVertexBuffer *buffer); -static void _cogl_vertex_buffer_indices_free (CoglVertexBufferIndices *buffer_indices); -static CoglUserDataKey _cogl_vertex_buffer_pipeline_priv_key; - -COGL_HANDLE_DEFINE (VertexBuffer, vertex_buffer); -COGL_HANDLE_DEFINE (VertexBufferIndices, vertex_buffer_indices); - -CoglHandle -cogl_vertex_buffer_new (unsigned int n_vertices) -{ - CoglVertexBuffer *buffer = g_slice_alloc (sizeof (CoglVertexBuffer)); - - buffer->n_vertices = n_vertices; - - buffer->submitted_vbos = NULL; - buffer->new_attributes = NULL; - buffer->primitive = cogl_primitive_new (COGL_VERTICES_MODE_TRIANGLES, - n_vertices, NULL); - - /* return NULL; */ - return _cogl_vertex_buffer_handle_new (buffer); -} - -unsigned int -cogl_vertex_buffer_get_n_vertices (CoglHandle handle) -{ - CoglVertexBuffer *buffer; - - if (!cogl_is_vertex_buffer (handle)) - return 0; - - buffer = handle; - - return buffer->n_vertices; -} - -/* There are a number of standard OpenGL attributes that we deal with - * specially. These attributes are all namespaced with a "gl_" prefix - * so we should catch any typos instead of silently adding a custom - * attribute. - */ -static CoglVertexBufferAttribFlags -validate_gl_attribute (const char *gl_attribute, - uint8_t n_components, - uint8_t *texture_unit) -{ - CoglVertexBufferAttribFlags type; - char *detail_seperator = NULL; - int name_len; - - detail_seperator = strstr (gl_attribute, "::"); - if (detail_seperator) - name_len = detail_seperator - gl_attribute; - else - name_len = strlen (gl_attribute); - - if (strncmp (gl_attribute, "Vertex", name_len) == 0) - { - if (G_UNLIKELY (n_components == 1)) - g_critical ("glVertexPointer doesn't allow 1 component vertex " - "positions so we currently only support \"gl_Vertex\" " - "attributes where n_components == 2, 3 or 4"); - type = COGL_VERTEX_BUFFER_ATTRIB_FLAG_VERTEX_ARRAY; - } - else if (strncmp (gl_attribute, "Color", name_len) == 0) - { - if (G_UNLIKELY (n_components != 3 && n_components != 4)) - g_critical ("glColorPointer expects 3 or 4 component colors so we " - "currently only support \"gl_Color\" attributes where " - "n_components == 3 or 4"); - type = COGL_VERTEX_BUFFER_ATTRIB_FLAG_COLOR_ARRAY; - } - else if (strncmp (gl_attribute, - "MultiTexCoord", - strlen ("MultiTexCoord")) == 0) - { - unsigned int unit; - - if (sscanf (gl_attribute, "MultiTexCoord%u", &unit) != 1) - { - g_warning ("gl_MultiTexCoord attributes should include a\n" - "texture unit number, E.g. gl_MultiTexCoord0\n"); - unit = 0; - } - /* FIXME: validate any '::' delimiter for this case */ - *texture_unit = unit; - type = COGL_VERTEX_BUFFER_ATTRIB_FLAG_TEXTURE_COORD_ARRAY; - } - else if (strncmp (gl_attribute, "Normal", name_len) == 0) - { - if (G_UNLIKELY (n_components != 3)) - g_critical ("glNormalPointer expects 3 component normals so we " - "currently only support \"gl_Normal\" attributes where " - "n_components == 3"); - type = COGL_VERTEX_BUFFER_ATTRIB_FLAG_NORMAL_ARRAY; - } - else - { - g_warning ("Unknown gl_* attribute name gl_%s\n", gl_attribute); - type = COGL_VERTEX_BUFFER_ATTRIB_FLAG_INVALID; - } - - return type; -} - -/* There are a number of standard OpenGL attributes that we deal with - * specially. These attributes are all namespaced with a "gl_" prefix - * so we should catch any typos instead of silently adding a custom - * attribute. - */ -static CoglVertexBufferAttribFlags -validate_cogl_attribute (const char *cogl_attribute, - uint8_t n_components, - uint8_t *texture_unit) -{ - CoglVertexBufferAttribFlags type; - char *detail_seperator = NULL; - int name_len; - - detail_seperator = strstr (cogl_attribute, "::"); - if (detail_seperator) - name_len = detail_seperator - cogl_attribute; - else - name_len = strlen (cogl_attribute); - - if (strncmp (cogl_attribute, "position_in", name_len) == 0) - { - if (G_UNLIKELY (n_components == 1)) - g_critical ("glVertexPointer doesn't allow 1 component vertex " - "positions so we currently only support " - "\"cogl_position_in\" attributes where " - "n_components == 2, 3 or 4"); - type = COGL_VERTEX_BUFFER_ATTRIB_FLAG_VERTEX_ARRAY; - } - else if (strncmp (cogl_attribute, "color_in", name_len) == 0) - { - if (G_UNLIKELY (n_components != 3 && n_components != 4)) - g_critical ("glColorPointer expects 3 or 4 component colors so we " - "currently only support \"cogl_color_in\" attributes " - "where n_components == 3 or 4"); - type = COGL_VERTEX_BUFFER_ATTRIB_FLAG_COLOR_ARRAY; - } - else if (strncmp (cogl_attribute, - "cogl_tex_coord", - strlen ("cogl_tex_coord")) == 0) - { - unsigned int unit; - - if (strcmp (cogl_attribute, "cogl_tex_coord_in") == 0) - unit = 0; - else if (sscanf (cogl_attribute, "cogl_tex_coord%u_in", &unit) != 1) - { - g_warning ("texture coordinate attributes should either be " - "referenced as \"cogl_tex_coord_in\" or with a" - "texture unit number like \"cogl_tex_coord1_in\""); - unit = 0; - } - /* FIXME: validate any '::' delimiter for this case */ - *texture_unit = unit; - type = COGL_VERTEX_BUFFER_ATTRIB_FLAG_TEXTURE_COORD_ARRAY; - } - else if (strncmp (cogl_attribute, "normal_in", name_len) == 0) - { - if (G_UNLIKELY (n_components != 3)) - g_critical ("glNormalPointer expects 3 component normals so we " - "currently only support \"cogl_normal_in\" attributes " - "where n_components == 3"); - type = COGL_VERTEX_BUFFER_ATTRIB_FLAG_NORMAL_ARRAY; - } - else - { - g_warning ("Unknown cogl_* attribute name cogl_%s\n", cogl_attribute); - type = COGL_VERTEX_BUFFER_ATTRIB_FLAG_INVALID; - } - - return type; -} - -/* This validates that a custom attribute name is a valid GLSL variable name - * - * NB: attribute names may have a detail component delimited using '::' E.g. - * custom_attrib::foo or custom_attrib::bar - * - * maybe I should hang a compiled regex somewhere to handle this - */ -static gboolean -validate_custom_attribute_name (const char *attribute_name) -{ - char *detail_seperator = NULL; - int name_len; - int i; - - detail_seperator = strstr (attribute_name, "::"); - if (detail_seperator) - name_len = detail_seperator - attribute_name; - else - name_len = strlen (attribute_name); - - if (name_len == 0 - || !g_ascii_isalpha (attribute_name[0]) - || attribute_name[0] != '_') - return FALSE; - - for (i = 1; i < name_len; i++) - if (!g_ascii_isalnum (attribute_name[i]) || attribute_name[i] != '_') - return FALSE; - - return TRUE; -} - -/* Iterates the CoglVertexBufferVBOs of a buffer and creates a flat list - * of all the submitted attributes - * - * Note: The CoglVertexBufferAttrib structs are deep copied, except the - * internal CoglAttribute pointer is set to NULL. - */ -static GList * -copy_submitted_attributes_list (CoglVertexBuffer *buffer) -{ - GList *tmp; - GList *submitted_attributes = NULL; - - for (tmp = buffer->submitted_vbos; tmp != NULL; tmp = tmp->next) - { - CoglVertexBufferVBO *cogl_vbo = tmp->data; - GList *tmp2; - - for (tmp2 = cogl_vbo->attributes; tmp2 != NULL; tmp2 = tmp2->next) - { - CoglVertexBufferAttrib *attribute = tmp2->data; - CoglVertexBufferAttrib *copy = - g_slice_alloc (sizeof (CoglVertexBufferAttrib)); - *copy = *attribute; - copy->name_without_detail = - g_strdup (attribute->name_without_detail); - copy->attribute = NULL; - submitted_attributes = g_list_prepend (submitted_attributes, copy); - } - } - return submitted_attributes; -} - -static size_t -sizeof_attribute_type (CoglAttributeType type) -{ - switch (type) - { - case COGL_ATTRIBUTE_TYPE_BYTE: - return 1; - case COGL_ATTRIBUTE_TYPE_UNSIGNED_BYTE: - return 1; - case COGL_ATTRIBUTE_TYPE_SHORT: - return 2; - case COGL_ATTRIBUTE_TYPE_UNSIGNED_SHORT: - return 2; - case COGL_ATTRIBUTE_TYPE_FLOAT: - return 4; - } - g_return_val_if_reached (0); -} - -static size_t -strideof (CoglAttributeType type, int n_components) -{ - return sizeof_attribute_type (type) * n_components; -} - -static char * -canonize_attribute_name (const char *attribute_name) -{ - const char *detail_seperator = NULL; - int name_len; - - if (strncmp (attribute_name, "gl_", 3) != 0) - return g_strdup (attribute_name); - - /* skip past the "gl_" */ - attribute_name += 3; - - detail_seperator = strstr (attribute_name, "::"); - if (detail_seperator) - name_len = detail_seperator - attribute_name; - else - { - name_len = strlen (attribute_name); - detail_seperator = ""; - } - - if (strncmp (attribute_name, "Vertex", name_len) == 0) - return g_strconcat ("cogl_position_in", detail_seperator, NULL); - else if (strncmp (attribute_name, "Color", name_len) == 0) - return g_strconcat ("cogl_color_in", detail_seperator, NULL); - else if (strncmp (attribute_name, - "MultiTexCoord", - strlen ("MultiTexCoord")) == 0) - { - unsigned int unit; - - if (sscanf (attribute_name, "MultiTexCoord%u", &unit) != 1) - { - g_warning ("gl_MultiTexCoord attributes should include a\n" - "texture unit number, E.g. gl_MultiTexCoord0\n"); - unit = 0; - } - return g_strdup_printf ("cogl_tex_coord%u_in%s", - unit, detail_seperator); - } - else if (strncmp (attribute_name, "Normal", name_len) == 0) - return g_strconcat ("cogl_normal_in", detail_seperator, NULL); - else - { - g_warning ("Unknown gl_* attribute name gl_%s\n", attribute_name); - return g_strdup (attribute_name); - } -} - -void -cogl_vertex_buffer_add (CoglHandle handle, - const char *attribute_name, - uint8_t n_components, - CoglAttributeType type, - gboolean normalized, - uint16_t stride, - const void *pointer) -{ - CoglVertexBuffer *buffer; - char *cogl_attribute_name; - GQuark name_quark; - gboolean modifying_an_attrib = FALSE; - CoglVertexBufferAttrib *attribute; - CoglVertexBufferAttribFlags flags = 0; - uint8_t texture_unit = 0; - GList *tmp; - char *detail; - - if (!cogl_is_vertex_buffer (handle)) - return; - - buffer = handle; - buffer->dirty_attributes = TRUE; - - cogl_attribute_name = canonize_attribute_name (attribute_name); - name_quark = g_quark_from_string (cogl_attribute_name); - - /* The submit function works by diffing between submitted_attributes - * and new_attributes to minimize the upload bandwidth + cost of - * allocating new VBOs, so if there isn't already a list of new_attributes - * we create one: */ - if (!buffer->new_attributes) - buffer->new_attributes = copy_submitted_attributes_list (buffer); - - /* Note: we first look for an existing attribute that we are modifying - * so we may skip needing to validate the name */ - for (tmp = buffer->new_attributes; tmp != NULL; tmp = tmp->next) - { - CoglVertexBufferAttrib *submitted_attribute = tmp->data; - if (submitted_attribute->name == name_quark) - { - modifying_an_attrib = TRUE; - - attribute = submitted_attribute; - - /* since we will skip validate_gl/cogl_attribute in this case, we - * need to pluck out the attribute type before overwriting the - * flags: */ - flags |= - attribute->flags & COGL_VERTEX_BUFFER_ATTRIB_FLAG_TYPE_MASK; - break; - } - } - - if (!modifying_an_attrib) - { - /* Validate the attribute name, is suitable as a variable name */ - if (strncmp (attribute_name, "gl_", 3) == 0) - { - /* Note: we pass the original attribute name here so that - * any warning messages correspond to the users original - * attribute name... */ - flags |= validate_gl_attribute (attribute_name + 3, - n_components, - &texture_unit); - if (flags & COGL_VERTEX_BUFFER_ATTRIB_FLAG_INVALID) - return; - } - else if (strncmp (attribute_name, "cogl_", 5) == 0) - { - flags |= validate_cogl_attribute (attribute_name + 5, - n_components, - &texture_unit); - if (flags & COGL_VERTEX_BUFFER_ATTRIB_FLAG_INVALID) - return; - } - else - { - flags |= COGL_VERTEX_BUFFER_ATTRIB_FLAG_CUSTOM_ARRAY; - if (validate_custom_attribute_name (attribute_name)) - return; - } - - attribute = g_slice_alloc0 (sizeof (CoglVertexBufferAttrib)); - } - - attribute->name = name_quark; - detail = strstr (cogl_attribute_name, "::"); - if (detail) - attribute->name_without_detail = g_strndup (cogl_attribute_name, - detail - cogl_attribute_name); - else - attribute->name_without_detail = g_strdup (cogl_attribute_name); - attribute->type = type; - attribute->n_components = n_components; - if (stride == 0) - stride = strideof (type, n_components); - attribute->stride = stride; - attribute->u.pointer = pointer; - attribute->texture_unit = texture_unit; - attribute->attribute = NULL; - - flags |= COGL_VERTEX_BUFFER_ATTRIB_FLAG_ENABLED; - - /* Note: We currently just assume, if an attribute is *ever* updated - * then it should be taged as frequently changing. */ - if (modifying_an_attrib) - flags |= COGL_VERTEX_BUFFER_ATTRIB_FLAG_FREQUENT_RESUBMIT; - else - flags |= COGL_VERTEX_BUFFER_ATTRIB_FLAG_INFREQUENT_RESUBMIT; - - if (normalized) - flags |= COGL_VERTEX_BUFFER_ATTRIB_FLAG_NORMALIZED; - attribute->flags = flags; - - attribute->span_bytes = buffer->n_vertices * attribute->stride; - - if (!modifying_an_attrib) - buffer->new_attributes = - g_list_prepend (buffer->new_attributes, attribute); - - g_free (cogl_attribute_name); -} - -static void -_cogl_vertex_buffer_attrib_free (CoglVertexBufferAttrib *attribute) -{ - if (attribute->attribute) - cogl_object_unref (attribute->attribute); - g_free (attribute->name_without_detail); - g_slice_free (CoglVertexBufferAttrib, attribute); -} - -void -cogl_vertex_buffer_delete (CoglHandle handle, - const char *attribute_name) -{ - CoglVertexBuffer *buffer; - char *cogl_attribute_name = canonize_attribute_name (attribute_name); - GQuark name = g_quark_from_string (cogl_attribute_name); - GList *tmp; - - g_free (cogl_attribute_name); - - if (!cogl_is_vertex_buffer (handle)) - return; - - buffer = handle; - buffer->dirty_attributes = TRUE; - - /* The submit function works by diffing between submitted_attributes - * and new_attributes to minimize the upload bandwidth + cost of - * allocating new VBOs, so if there isn't already a list of new_attributes - * we create one: */ - if (!buffer->new_attributes) - buffer->new_attributes = copy_submitted_attributes_list (buffer); - - for (tmp = buffer->new_attributes; tmp != NULL; tmp = tmp->next) - { - CoglVertexBufferAttrib *submitted_attribute = tmp->data; - if (submitted_attribute->name == name) - { - buffer->new_attributes = - g_list_delete_link (buffer->new_attributes, tmp); - _cogl_vertex_buffer_attrib_free (submitted_attribute); - return; - } - } - - g_warning ("Failed to find an attribute named %s to delete\n", - attribute_name); -} - -static void -set_attribute_enable (CoglHandle handle, - const char *attribute_name, - gboolean state) -{ - CoglVertexBuffer *buffer; - char *cogl_attribute_name = canonize_attribute_name (attribute_name); - GQuark name_quark = g_quark_from_string (cogl_attribute_name); - GList *tmp; - - g_free (cogl_attribute_name); - - if (!cogl_is_vertex_buffer (handle)) - return; - - buffer = handle; - buffer->dirty_attributes = TRUE; - - /* NB: If a buffer is currently being edited, then there can be two seperate - * lists of attributes; those that are currently submitted and a new list yet - * to be submitted, we need to modify both. */ - - for (tmp = buffer->new_attributes; tmp != NULL; tmp = tmp->next) - { - CoglVertexBufferAttrib *attribute = tmp->data; - if (attribute->name == name_quark) - { - if (state) - attribute->flags |= COGL_VERTEX_BUFFER_ATTRIB_FLAG_ENABLED; - else - attribute->flags &= ~COGL_VERTEX_BUFFER_ATTRIB_FLAG_ENABLED; - break; - } - } - - for (tmp = buffer->submitted_vbos; tmp != NULL; tmp = tmp->next) - { - CoglVertexBufferVBO *cogl_vbo = tmp->data; - GList *tmp2; - - for (tmp2 = cogl_vbo->attributes; tmp2 != NULL; tmp2 = tmp2->next) - { - CoglVertexBufferAttrib *attribute = tmp2->data; - if (attribute->name == name_quark) - { - if (state) - attribute->flags |= COGL_VERTEX_BUFFER_ATTRIB_FLAG_ENABLED; - else - attribute->flags &= ~COGL_VERTEX_BUFFER_ATTRIB_FLAG_ENABLED; - return; - } - } - } - - g_warning ("Failed to %s attribute named %s/%s\n", - state == TRUE ? "enable" : "disable", - attribute_name, cogl_attribute_name); -} - -void -cogl_vertex_buffer_enable (CoglHandle handle, - const char *attribute_name) -{ - set_attribute_enable (handle, attribute_name, TRUE); -} - -void -cogl_vertex_buffer_disable (CoglHandle handle, - const char *attribute_name) -{ - set_attribute_enable (handle, attribute_name, FALSE); -} - -/* Given an attribute that we know has already been submitted before, this - * function looks for the existing VBO that contains it. - * - * Note: It will free redundant attribute struct once the corresponding - * VBO has been found. - */ -static void -filter_already_submitted_attribute (CoglVertexBufferAttrib *attribute, - GList **reuse_vbos, - GList **submitted_vbos) -{ - GList *tmp; - - /* First check the cogl_vbos we already know are being reused since we - * are more likley to get a match here */ - for (tmp = *reuse_vbos; tmp != NULL; tmp = tmp->next) - { - CoglVertexBufferVBO *cogl_vbo = tmp->data; - GList *tmp2; - - for (tmp2 = cogl_vbo->attributes; tmp2 != NULL; tmp2 = tmp2->next) - { - CoglVertexBufferAttrib *vbo_attribute = tmp2->data; - - if (vbo_attribute->name == attribute->name) - { - vbo_attribute->flags &= - ~COGL_VERTEX_BUFFER_ATTRIB_FLAG_UNUSED; - /* Note: we don't free the redundant attribute here, since it - * will be freed after all filtering in - * cogl_vertex_buffer_submit */ - return; - } - } - } - - for (tmp = *submitted_vbos; tmp != NULL; tmp = tmp->next) - { - CoglVertexBufferVBO *cogl_vbo = tmp->data; - CoglVertexBufferAttrib *reuse_attribute = NULL; - GList *tmp2; - - for (tmp2 = cogl_vbo->attributes; tmp2 != NULL; tmp2 = tmp2->next) - { - CoglVertexBufferAttrib *vbo_attribute = tmp2->data; - if (vbo_attribute->name == attribute->name) - { - reuse_attribute = vbo_attribute; - /* Note: we don't free the redundant attribute here, since it - * will be freed after all filtering in - * cogl_vertex_buffer_submit */ - - *submitted_vbos = g_list_remove_link (*submitted_vbos, tmp); - tmp->next = *reuse_vbos; - *reuse_vbos = tmp; - break; - } - } - - if (!reuse_attribute) - continue; - - /* Mark all but the matched attribute as UNUSED, so that when we - * finish filtering all our attributes any attrributes still - * marked as UNUSED can be removed from their cogl_vbo */ - for (tmp2 = cogl_vbo->attributes; tmp2 != NULL; tmp2 = tmp2->next) - { - CoglVertexBufferAttrib *vbo_attribute = tmp2->data; - if (vbo_attribute != reuse_attribute) - vbo_attribute->flags |= COGL_VERTEX_BUFFER_ATTRIB_FLAG_UNUSED; - } - - return; - } - - g_critical ("Failed to find the cogl vbo that corresponds to an\n" - "attribute that had apparently already been submitted!"); -} - -/* When we first mark a CoglVertexBufferVBO to be reused, we mark the - * attributes as unsed, so that when filtering of attributes into VBOs is done - * we can then prune the now unsed attributes. */ -static void -remove_unused_attributes (CoglVertexBufferVBO *cogl_vbo) -{ - GList *tmp; - GList *next; - - for (tmp = cogl_vbo->attributes; tmp != NULL; tmp = next) - { - CoglVertexBufferAttrib *attribute = tmp->data; - next = tmp->next; - - if (attribute->flags & COGL_VERTEX_BUFFER_ATTRIB_FLAG_UNUSED) - { - cogl_vbo->attributes = - g_list_delete_link (cogl_vbo->attributes, tmp); - g_slice_free (CoglVertexBufferAttrib, attribute); - } - } -} - -/* Give a newly added, strided, attribute, this function looks for a - * CoglVertexBufferVBO that the attribute is interleved with. If it can't - * find one then a new CoglVertexBufferVBO is allocated and added to the - * list of new_strided_vbos. - */ -static void -filter_strided_attribute (CoglVertexBufferAttrib *attribute, - GList **new_vbos) -{ - GList *tmp; - CoglVertexBufferVBO *new_cogl_vbo; - - for (tmp = *new_vbos; tmp != NULL; tmp = tmp->next) - { - CoglVertexBufferVBO *cogl_vbo = tmp->data; - GList *tmp2; - - if (!(cogl_vbo->flags & COGL_VERTEX_BUFFER_VBO_FLAG_STRIDED)) - continue; - - for (tmp2 = cogl_vbo->attributes; tmp2 != NULL; tmp2 = tmp2->next) - { - CoglVertexBufferAttrib *vbo_attribute = tmp2->data; - const char *attribute_start = attribute->u.pointer; - const char *vbo_attribute_start = vbo_attribute->u.pointer; - - /* NB: All attributes have buffer->n_vertices values which - * simplifies determining which attributes are interleved - * since we assume they will start no farther than +- a - * stride away from each other: - */ - if (attribute_start <= (vbo_attribute_start - vbo_attribute->stride) - || attribute_start - >= (vbo_attribute_start + vbo_attribute->stride)) - continue; /* Not interleved */ - - cogl_vbo->attributes = - g_list_prepend (cogl_vbo->attributes, attribute); - - if (attribute->flags & - COGL_VERTEX_BUFFER_ATTRIB_FLAG_FREQUENT_RESUBMIT) - { - cogl_vbo->flags &= - ~COGL_VERTEX_BUFFER_VBO_FLAG_INFREQUENT_RESUBMIT; - cogl_vbo->flags |= - COGL_VERTEX_BUFFER_VBO_FLAG_FREQUENT_RESUBMIT; - } - return; - } - } - new_cogl_vbo = g_slice_alloc (sizeof (CoglVertexBufferVBO)); - new_cogl_vbo->attributes = NULL; - new_cogl_vbo->attributes = - g_list_prepend (new_cogl_vbo->attributes, attribute); - /* Any one of the interleved attributes will have the same span_bytes */ - new_cogl_vbo->attribute_buffer = NULL; - new_cogl_vbo->buffer_bytes = attribute->span_bytes; - new_cogl_vbo->flags = COGL_VERTEX_BUFFER_VBO_FLAG_STRIDED; - - if (attribute->flags & COGL_VERTEX_BUFFER_ATTRIB_FLAG_INFREQUENT_RESUBMIT) - new_cogl_vbo->flags |= COGL_VERTEX_BUFFER_VBO_FLAG_INFREQUENT_RESUBMIT; - else - new_cogl_vbo->flags |= COGL_VERTEX_BUFFER_VBO_FLAG_FREQUENT_RESUBMIT; - - *new_vbos = g_list_prepend (*new_vbos, new_cogl_vbo); - return; -} - -/* This iterates through the list of submitted VBOs looking for one that - * contains attribute. If found the list *link* is removed and returned */ -static GList * -unlink_submitted_vbo_containing_attribute (GList **submitted_vbos, - CoglVertexBufferAttrib *attribute) -{ - GList *tmp; - GList *next = NULL; - - for (tmp = *submitted_vbos; tmp != NULL; tmp = next) - { - CoglVertexBufferVBO *submitted_vbo = tmp->data; - GList *tmp2; - - next = tmp->next; - - for (tmp2 = submitted_vbo->attributes; tmp2 != NULL; tmp2 = tmp2->next) - { - CoglVertexBufferAttrib *submitted_attribute = tmp2->data; - - if (submitted_attribute->name == attribute->name) - { - *submitted_vbos = g_list_remove_link (*submitted_vbos, tmp); - return tmp; - } - } - } - - return NULL; -} - -/* Unlinks all the submitted VBOs that conflict with the new cogl_vbo and - * returns them as a list. */ -static GList * -get_submitted_vbo_conflicts (GList **submitted_vbos, - CoglVertexBufferVBO *cogl_vbo) -{ - GList *tmp; - GList *conflicts = NULL; - - for (tmp = cogl_vbo->attributes; tmp != NULL; tmp = tmp->next) - { - GList *link = - unlink_submitted_vbo_containing_attribute (submitted_vbos, - tmp->data); - if (link) - { - /* prepend the link to the list of conflicts: */ - link->next = conflicts; - conflicts = link; - } - } - return conflicts; -} - -/* Any attributes in cogl_vbo gets removed from conflict_vbo */ -static void -disassociate_conflicting_attributes (CoglVertexBufferVBO *conflict_vbo, - CoglVertexBufferVBO *cogl_vbo) -{ - GList *tmp; - - /* NB: The attributes list in conflict_vbo will be shrinking so - * we iterate those in the inner loop. */ - - for (tmp = cogl_vbo->attributes; tmp != NULL; tmp = tmp->next) - { - CoglVertexBufferAttrib *attribute = tmp->data; - GList *tmp2; - for (tmp2 = conflict_vbo->attributes; tmp2 != NULL; tmp2 = tmp2->next) - { - CoglVertexBufferAttrib *conflict_attribute = tmp2->data; - - if (conflict_attribute->name == attribute->name) - { - _cogl_vertex_buffer_attrib_free (conflict_attribute); - conflict_vbo->attributes = - g_list_delete_link (conflict_vbo->attributes, tmp2); - break; - } - } - } -} - -static void -cogl_vertex_buffer_vbo_free (CoglVertexBufferVBO *cogl_vbo) -{ - GList *tmp; - - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - - for (tmp = cogl_vbo->attributes; tmp != NULL; tmp = tmp->next) - _cogl_vertex_buffer_attrib_free (tmp->data); - g_list_free (cogl_vbo->attributes); - - if (cogl_vbo->flags & COGL_VERTEX_BUFFER_VBO_FLAG_SUBMITTED) - cogl_object_unref (cogl_vbo->attribute_buffer); - - g_slice_free (CoglVertexBufferVBO, cogl_vbo); -} - -/* This figures out the lowest attribute client pointer. (This pointer is used - * to upload all the interleved attributes). - * - * In the process it also replaces the client pointer with the attributes - * offset, and marks the attribute as submitted. - */ -static const void * -prep_strided_vbo_for_upload (CoglVertexBufferVBO *cogl_vbo) -{ - GList *tmp; - const char *lowest_pointer = NULL; - - for (tmp = cogl_vbo->attributes; tmp != NULL; tmp = tmp->next) - { - CoglVertexBufferAttrib *attribute = tmp->data; - const char *client_pointer = attribute->u.pointer; - - if (!lowest_pointer || client_pointer < lowest_pointer) - lowest_pointer = client_pointer; - } - - for (tmp = cogl_vbo->attributes; tmp != NULL; tmp = tmp->next) - { - CoglVertexBufferAttrib *attribute = tmp->data; - const char *client_pointer = attribute->u.pointer; - attribute->u.vbo_offset = client_pointer - lowest_pointer; - attribute->flags |= COGL_VERTEX_BUFFER_ATTRIB_FLAG_SUBMITTED; - } - - return lowest_pointer; -} - -static gboolean -upload_multipack_vbo_via_map_buffer (CoglVertexBufferVBO *cogl_vbo) -{ - GList *tmp; - unsigned int offset = 0; - uint8_t *buf; - - _COGL_GET_CONTEXT (ctx, FALSE); - - buf = cogl_buffer_map (COGL_BUFFER (cogl_vbo->attribute_buffer), - COGL_BUFFER_ACCESS_WRITE, - COGL_BUFFER_MAP_HINT_DISCARD); - if (!buf) - return FALSE; - - for (tmp = cogl_vbo->attributes; tmp != NULL; tmp = tmp->next) - { - CoglVertexBufferAttrib *attribute = tmp->data; - gsize attribute_size = attribute->span_bytes; - gsize type_size = sizeof_attribute_type (attribute->type); - - PAD_FOR_ALIGNMENT (offset, type_size); - - memcpy (buf + offset, attribute->u.pointer, attribute_size); - - attribute->u.vbo_offset = offset; - attribute->flags |= COGL_VERTEX_BUFFER_ATTRIB_FLAG_SUBMITTED; - offset += attribute_size; - } - - cogl_buffer_unmap (COGL_BUFFER (cogl_vbo->attribute_buffer)); - - return TRUE; -} - -static void -upload_multipack_vbo_via_buffer_sub_data (CoglVertexBufferVBO *cogl_vbo) -{ - GList *l; - unsigned int offset = 0; - - for (l = cogl_vbo->attributes; l != NULL; l = l->next) - { - CoglVertexBufferAttrib *attribute = l->data; - gsize attribute_size = attribute->span_bytes; - gsize type_size = sizeof_attribute_type (attribute->type); - - PAD_FOR_ALIGNMENT (offset, type_size); - - cogl_buffer_set_data (COGL_BUFFER (cogl_vbo->attribute_buffer), - offset, - attribute->u.pointer, - attribute_size); - - attribute->u.vbo_offset = offset; - attribute->flags |= COGL_VERTEX_BUFFER_ATTRIB_FLAG_SUBMITTED; - offset += attribute_size; - } -} - -static void -upload_attributes (CoglVertexBufferVBO *cogl_vbo) -{ - CoglBufferUpdateHint usage; - - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - - if (cogl_vbo->flags & COGL_VERTEX_BUFFER_VBO_FLAG_FREQUENT_RESUBMIT) - usage = COGL_BUFFER_UPDATE_HINT_DYNAMIC; - else - usage = COGL_BUFFER_UPDATE_HINT_STATIC; - cogl_buffer_set_update_hint (COGL_BUFFER (cogl_vbo->attribute_buffer), usage); - - if (cogl_vbo->flags & COGL_VERTEX_BUFFER_VBO_FLAG_STRIDED) - { - const void *pointer = prep_strided_vbo_for_upload (cogl_vbo); - cogl_buffer_set_data (COGL_BUFFER (cogl_vbo->attribute_buffer), - 0, /* offset */ - pointer, - cogl_vbo->buffer_bytes); - } - else /* MULTIPACK */ - { - /* 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 - * thread about this topic here: - * http://www.mail-archive.com/dri-devel@lists.sourceforge.net/msg35004.html - * For now I have gone with glMapBuffer, but the jury is still out. - */ - - if (!upload_multipack_vbo_via_map_buffer (cogl_vbo)) - upload_multipack_vbo_via_buffer_sub_data (cogl_vbo); - } - - cogl_vbo->flags |= COGL_VERTEX_BUFFER_VBO_FLAG_SUBMITTED; -} - -/* Note: although there ends up being quite a few inner loops involved with - * resolving buffers, the number of attributes will be low so I don't expect - * them to cause a problem. */ -static void -cogl_vertex_buffer_vbo_resolve (CoglVertexBuffer *buffer, - CoglVertexBufferVBO *new_cogl_vbo, - GList **final_vbos) -{ - GList *conflicts; - GList *tmp; - GList *next; - gboolean found_target_vbo = FALSE; - - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - - conflicts = - get_submitted_vbo_conflicts (&buffer->submitted_vbos, new_cogl_vbo); - - for (tmp = conflicts; tmp != NULL; tmp = next) - { - CoglVertexBufferVBO *conflict_vbo = tmp->data; - - next = tmp->next; - - disassociate_conflicting_attributes (conflict_vbo, new_cogl_vbo); - - if (!conflict_vbo->attributes) - { - /* See if we can re-use this now empty VBO: */ - - if (!found_target_vbo - && conflict_vbo->buffer_bytes == new_cogl_vbo->buffer_bytes) - { - found_target_vbo = TRUE; - new_cogl_vbo->attribute_buffer = - cogl_object_ref (conflict_vbo->attribute_buffer); - cogl_vertex_buffer_vbo_free (conflict_vbo); - - upload_attributes (new_cogl_vbo); - - *final_vbos = g_list_prepend (*final_vbos, new_cogl_vbo); - } - else - cogl_vertex_buffer_vbo_free (conflict_vbo); - } - else - { - /* Relink the VBO back into buffer->submitted_vbos since it may - * be involved in other conflicts later */ - tmp->next = buffer->submitted_vbos; - tmp->prev = NULL; - buffer->submitted_vbos = tmp; - } - } - - if (!found_target_vbo) - { - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - - new_cogl_vbo->attribute_buffer = - cogl_attribute_buffer_new (ctx, new_cogl_vbo->buffer_bytes, NULL); - - upload_attributes (new_cogl_vbo); - *final_vbos = g_list_prepend (*final_vbos, new_cogl_vbo); - } -} - -static void -update_primitive_attributes (CoglVertexBuffer *buffer) -{ - GList *l; - int n_attributes = 0; - CoglAttribute **attributes; - int i; - - if (!buffer->dirty_attributes) - return; - - buffer->dirty_attributes = FALSE; - - for (l = buffer->submitted_vbos; l; l = l->next) - { - CoglVertexBufferVBO *cogl_vbo = l->data; - GList *l2; - - for (l2 = cogl_vbo->attributes; l2; l2 = l2->next, n_attributes++) - ; - } - - g_return_if_fail (n_attributes > 0); - - attributes = g_alloca (sizeof (CoglAttribute *) * n_attributes); - - i = 0; - for (l = buffer->submitted_vbos; l; l = l->next) - { - CoglVertexBufferVBO *cogl_vbo = l->data; - GList *l2; - - for (l2 = cogl_vbo->attributes; l2; l2 = l2->next) - { - CoglVertexBufferAttrib *attribute = l2->data; - if (G_LIKELY (attribute->flags & - COGL_VERTEX_BUFFER_ATTRIB_FLAG_ENABLED)) - { - if (G_UNLIKELY (!attribute->attribute)) - { - attribute->attribute = - cogl_attribute_new (cogl_vbo->attribute_buffer, - attribute->name_without_detail, - attribute->stride, - attribute->u.vbo_offset, - attribute->n_components, - attribute->type); - } - - attributes[i++] = attribute->attribute; - } - } - } - - cogl_primitive_set_attributes (buffer->primitive, attributes, i); -} - -static void -cogl_vertex_buffer_submit_real (CoglVertexBuffer *buffer) -{ - GList *tmp; - CoglVertexBufferVBO *new_multipack_vbo; - GList *new_multipack_vbo_link; - GList *new_vbos = NULL; - GList *reuse_vbos = NULL; - GList *final_vbos = NULL; - - if (!buffer->new_attributes) - goto done; - - /* The objective now is to copy the attribute data supplied by the client - * into buffer objects, but it's important to minimize the number of - * redundant data uploads. - * - * We obviously aim to group together the attributes that are interleved so - * that they can be delivered in one go to the driver. - * All BOs for interleved data are created as STATIC_DRAW_ARB. - * - * Non interleved attributes tagged as INFREQUENT_RESUBMIT will be grouped - * together back to back in a single BO created as STATIC_DRAW_ARB - * - * Non interleved attributes tagged as FREQUENT_RESUBMIT will be copied into - * individual buffer objects, and the BO itself created DYNAMIC_DRAW_ARB - * - * If we are modifying a previously submitted CoglVertexBuffer then we are - * carefull not to needlesly delete OpenGL buffer objects and replace with - * new ones, instead we upload new data to the existing buffers. - */ - - /* NB: We must forget attribute->pointer after submitting since the user - * is free to re-use that memory for other purposes now. */ - - /* Pseudo code: - * - * Broadly speaking we start with a list of unsorted attributes, and filter - * those into 'new' and 're-use' CoglVertexBufferVBO (CBO) lists. We then - * take the list of new CBO structs and compare with the CBOs that have - * already been submitted to the GPU (but ignoring those we already know will - * be re-used) to determine what other CBOs can be re-used, due to being - * superseded, and what new GL VBOs need to be created. - * - * We have two kinds of CBOs: - * - Multi Pack CBOs - * These contain multiple attributes tightly packed back to back) - * - Strided CBOs - * These typically contain multiple interleved sets of attributes, - * though they can contain just one attribute with a stride - * - * First create a new-CBOs entry "new-multipack-CBO" - * Tag "new-multipack-CBO" as MULTIPACK + INFREQUENT_RESUBMIT - * For each unsorted attrib: - * if already marked as submitted: - * iterate reuse-CBOs: - * if we find one that contains this attribute: - * free redundant unsorted attrib struct - * remove the UNUSED flag from the attrib found in the reuse-CBO - * continue to next unsorted attrib - * iterate submitted VBOs: - * if we find one that contains this attribute: - * free redundant unsorted attrib struct - * unlink the vbo and move it to the list of reuse-CBOs - * mark all attributes except the one just matched as UNUSED - * assert (found) - * continue to next unsorted attrib - * if strided: - * iterate the new, strided, CBOs, to see if the attribute is - * interleved with one of them, if found: - * add to the matched CBO - * else if not found: - * create a new-CBOs entry tagged STRIDED + INFREQUENT_RESUBMIT - * else if unstrided && tagged with FREQUENT_RESUBMIT: - * create a new-CBOs entry tagged MULTIPACK + FREQUENT_RESUBMIT - * else - * add to the new-multipack-CBO - * free list of unsorted-attribs - * - * Next compare the new list of CBOs with the submitted set and try to - * minimize the memory bandwidth required to upload the attributes and the - * overhead of creating new GL-BOs. - * - * We deal with four sets of CBOs: - * - The "new" CBOs - * (as determined above during filtering) - * - The "re-use" CBOs - * (as determined above during filtering) - * - The "submitted" CBOs - * (I.e. ones currently submitted to the GPU) - * - The "final" CBOs - * (The result of resolving the differences between the above sets) - * - * The re-use CBOs are dealt with first, and we simply delete any remaining - * attributes in these that are still marked as UNUSED, and move them - * to the list of final CBOs. - * - * Next we iterate through the "new" CBOs, searching for conflicts - * with the "submitted" CBOs and commit our decision to the "final" CBOs - * - * When searching for submitted entries we always unlink items from the - * submitted list once we make matches (before we make descisions - * based on the matches). If the CBO node is superseded it is freed, - * if it is modified but may be needed for more descisions later it is - * relinked back into the submitted list and if it's identical to a new - * CBO it will be linked into the final list. - * - * At the end the list of submitted CBOs represents the attributes that were - * deleted from the buffer. - * - * Iterate re-use-CBOs: - * Iterate attribs for each: - * if attrib UNUSED: - * remove the attrib from the CBO + free - * |Note: we could potentially mark this as a re-useable gap - * |if needs be later. - * add re-use CBO to the final-CBOs - * Iterate new-CBOs: - * List submitted CBOs conflicting with the this CBO (Unlinked items) - * found-target-BO=FALSE - * Iterate conflicting CBOs: - * Disassociate conflicting attribs from conflicting CBO struct - * If no attribs remain: - * If found-target-BO!=TRUE - * _AND_ If the total size of the conflicting CBO is compatible: - * |Note: We don't currently consider re-using oversized buffers - * found-target-BO=TRUE - * upload replacement data - * free submitted CBO struct - * add new CBO struct to final-CBOs - * else: - * delete conflict GL-BO - * delete conflict CBO struct - * else: - * relink CBO back into submitted-CBOs - * - * if found-target-BO == FALSE: - * create a new GL-BO - * upload data - * add new CBO struct to final-BOs - * - * Iterate through the remaining "submitted" CBOs: - * delete the submitted GL-BO - * free the submitted CBO struct - */ - - new_multipack_vbo = g_slice_alloc (sizeof (CoglVertexBufferVBO)); - new_multipack_vbo->attribute_buffer = NULL; - new_multipack_vbo->buffer_bytes = 0; - new_multipack_vbo->flags = - COGL_VERTEX_BUFFER_VBO_FLAG_MULTIPACK - | COGL_VERTEX_BUFFER_VBO_FLAG_INFREQUENT_RESUBMIT; - new_multipack_vbo->attributes = NULL; - new_vbos = g_list_prepend (new_vbos, new_multipack_vbo); - /* We save the link pointer here, just so we can do a fast removal later if - * no attributes get added to this vbo. */ - new_multipack_vbo_link = new_vbos; - - /* Start with a list of unsorted attributes, and filter those into - * potential new Cogl BO structs - */ - for (tmp = buffer->new_attributes; tmp != NULL; tmp = tmp->next) - { - CoglVertexBufferAttrib *attribute = tmp->data; - - if (attribute->flags & COGL_VERTEX_BUFFER_ATTRIB_FLAG_SUBMITTED) - { - /* If the attribute is already marked as submitted, then we need - * to find the existing VBO that contains it so we dont delete it. - * - * NB: this also frees the attribute struct since it's implicitly - * redundant in this case. - */ - filter_already_submitted_attribute (attribute, - &reuse_vbos, - &buffer->submitted_vbos); - } - else if (attribute->stride) - { - /* look for a CoglVertexBufferVBO that the attribute is - * interleved with. If one can't be found then a new - * CoglVertexBufferVBO is allocated and added to the list of - * new_vbos: */ - filter_strided_attribute (attribute, &new_vbos); - } - else if (attribute->flags & - COGL_VERTEX_BUFFER_ATTRIB_FLAG_FREQUENT_RESUBMIT) - { - CoglVertexBufferVBO *cogl_vbo = - g_slice_alloc (sizeof (CoglVertexBufferVBO)); - - /* attributes we expect will be frequently resubmitted are placed - * in their own VBO so that updates don't impact other attributes - */ - - cogl_vbo->flags = - COGL_VERTEX_BUFFER_VBO_FLAG_MULTIPACK - | COGL_VERTEX_BUFFER_VBO_FLAG_FREQUENT_RESUBMIT; - cogl_vbo->attributes = NULL; - cogl_vbo->attributes = g_list_prepend (cogl_vbo->attributes, - attribute); - cogl_vbo->attribute_buffer = NULL; - cogl_vbo->buffer_bytes = attribute->span_bytes; - new_vbos = g_list_prepend (new_vbos, cogl_vbo); - } - else - { - gsize type_size = sizeof_attribute_type (attribute->flags); - - /* Infrequently updated attributes just get packed back to back - * in a single VBO: */ - new_multipack_vbo->attributes = - g_list_prepend (new_multipack_vbo->attributes, - attribute); - - /* Note: we have to ensure that each run of attributes is - * naturally aligned according to its data type, which may - * require some padding bytes: */ - - /* XXX: We also have to be sure that the attributes aren't - * reorderd before being uploaded because the alignment padding - * is based on the adjacent attribute. - */ - - PAD_FOR_ALIGNMENT (new_multipack_vbo->buffer_bytes, type_size); - - new_multipack_vbo->buffer_bytes += attribute->span_bytes; - } - } - - /* At this point all buffer->new_attributes have been filtered into - * CoglVertexBufferVBOs... */ - g_list_free (buffer->new_attributes); - buffer->new_attributes = NULL; - - /* If the multipack vbo wasn't needed: */ - if (new_multipack_vbo->attributes == NULL) - { - new_vbos = g_list_delete_link (new_vbos, new_multipack_vbo_link); - g_slice_free (CoglVertexBufferVBO, new_multipack_vbo); - } - - for (tmp = reuse_vbos; tmp != NULL; tmp = tmp->next) - remove_unused_attributes (tmp->data); - final_vbos = g_list_concat (final_vbos, reuse_vbos); - - for (tmp = new_vbos; tmp != NULL; tmp = tmp->next) - cogl_vertex_buffer_vbo_resolve (buffer, tmp->data, &final_vbos); - - /* Anything left corresponds to deleted attributes: */ - for (tmp = buffer->submitted_vbos; tmp != NULL; tmp = tmp->next) - cogl_vertex_buffer_vbo_free (tmp->data); - g_list_free (buffer->submitted_vbos); - g_list_free (new_vbos); - - buffer->submitted_vbos = final_vbos; - -done: - update_primitive_attributes (buffer); -} - -void -cogl_vertex_buffer_submit (CoglHandle handle) -{ - CoglVertexBuffer *buffer; - - if (!cogl_is_vertex_buffer (handle)) - return; - - buffer = handle; - - cogl_vertex_buffer_submit_real (buffer); -} - -typedef struct -{ - /* We have a ref-count on this private structure because we need to - refer to it both from the private data on a pipeline and any weak - pipelines that we create from it. If we didn't have the ref count - then we would depend on the order of destruction of a - CoglPipeline and the weak materials to avoid a crash */ - unsigned int ref_count; - - CoglPipeline *real_source; -} VertexBufferMaterialPrivate; - -static void -unref_pipeline_priv (VertexBufferMaterialPrivate *priv) -{ - if (--priv->ref_count < 1) - g_slice_free (VertexBufferMaterialPrivate, priv); -} - -static void -weak_override_source_destroyed_cb (CoglPipeline *pipeline, - void *user_data) -{ - VertexBufferMaterialPrivate *pipeline_priv = user_data; - /* Unref the weak pipeline copy since it is no longer valid - probably because - * one of its ancestors has been changed. */ - cogl_object_unref (pipeline_priv->real_source); - pipeline_priv->real_source = NULL; - /* A reference was added when we copied the weak material so we need - to unref it here */ - unref_pipeline_priv (pipeline_priv); -} - -static gboolean -validate_layer_cb (CoglPipeline *pipeline, - int layer_index, - void *user_data) -{ - VertexBufferMaterialPrivate *pipeline_priv = user_data; - CoglPipeline *source = pipeline_priv->real_source; - - if (!cogl_pipeline_get_layer_point_sprite_coords_enabled (source, - layer_index)) - { - CoglPipelineWrapMode wrap_s; - CoglPipelineWrapMode wrap_t; - CoglPipelineWrapMode wrap_p; - gboolean need_override_source = FALSE; - - /* By default COGL_PIPELINE_WRAP_MODE_AUTOMATIC becomes - * GL_CLAMP_TO_EDGE but we want GL_REPEAT to maintain - * compatibility with older versions of Cogl so we'll override - * it. We don't want to do this for point sprites because in - * that case the whole texture is drawn so you would usually - * want clamp-to-edge. - */ - wrap_s = cogl_pipeline_get_layer_wrap_mode_s (source, layer_index); - if (wrap_s == COGL_PIPELINE_WRAP_MODE_AUTOMATIC) - { - need_override_source = TRUE; - wrap_s = COGL_PIPELINE_WRAP_MODE_REPEAT; - } - wrap_t = cogl_pipeline_get_layer_wrap_mode_t (source, layer_index); - if (wrap_t == COGL_PIPELINE_WRAP_MODE_AUTOMATIC) - { - need_override_source = TRUE; - wrap_t = COGL_PIPELINE_WRAP_MODE_REPEAT; - } - wrap_p = cogl_pipeline_get_layer_wrap_mode_p (source, layer_index); - if (wrap_p == COGL_PIPELINE_WRAP_MODE_AUTOMATIC) - { - need_override_source = TRUE; - wrap_p = COGL_PIPELINE_WRAP_MODE_REPEAT; - } - - if (need_override_source) - { - if (pipeline_priv->real_source == pipeline) - { - pipeline_priv->ref_count++; - pipeline_priv->real_source = source = - _cogl_pipeline_weak_copy (pipeline, - weak_override_source_destroyed_cb, - pipeline_priv); - } - - cogl_pipeline_set_layer_wrap_mode_s (source, layer_index, wrap_s); - cogl_pipeline_set_layer_wrap_mode_t (source, layer_index, wrap_t); - cogl_pipeline_set_layer_wrap_mode_p (source, layer_index, wrap_p); - } - } - - return TRUE; -} - -static void -destroy_pipeline_priv_cb (void *user_data) -{ - unref_pipeline_priv (user_data); -} - -static void -update_primitive_and_draw (CoglVertexBuffer *buffer, - CoglVerticesMode mode, - int first, - int count, - CoglVertexBufferIndices *buffer_indices) -{ - VertexBufferMaterialPrivate *pipeline_priv; - CoglPipeline *users_source; - - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - - cogl_primitive_set_mode (buffer->primitive, mode); - cogl_primitive_set_first_vertex (buffer->primitive, first); - cogl_primitive_set_n_vertices (buffer->primitive, count); - - if (buffer_indices) - cogl_primitive_set_indices (buffer->primitive, buffer_indices->indices, count); - else - cogl_primitive_set_indices (buffer->primitive, NULL, count); - - cogl_vertex_buffer_submit_real (buffer); - - users_source = cogl_get_source (); - pipeline_priv = - cogl_object_get_user_data (COGL_OBJECT (users_source), - &_cogl_vertex_buffer_pipeline_priv_key); - if (G_UNLIKELY (!pipeline_priv)) - { - pipeline_priv = g_slice_new0 (VertexBufferMaterialPrivate); - pipeline_priv->ref_count = 1; - cogl_object_set_user_data (COGL_OBJECT (users_source), - &_cogl_vertex_buffer_pipeline_priv_key, - pipeline_priv, - destroy_pipeline_priv_cb); - } - - if (G_UNLIKELY (!pipeline_priv->real_source)) - { - pipeline_priv->real_source = users_source; - cogl_pipeline_foreach_layer (pipeline_priv->real_source, - validate_layer_cb, - pipeline_priv); - } - - /* XXX: although this may seem redundant, we need to do this since - * CoglVertexBuffers can be used with legacy state and its the source stack - * which track whether legacy state is enabled. - * - * (We only have a CoglDrawFlag to disable legacy state not one - * to enable it) */ - cogl_push_source (pipeline_priv->real_source); - - _cogl_primitive_draw (buffer->primitive, - cogl_get_draw_framebuffer (), - pipeline_priv->real_source, - 0 /* no draw flags */); - - cogl_pop_source (); -} - -void -cogl_vertex_buffer_draw (CoglHandle handle, - CoglVerticesMode mode, - int first, - int count) -{ - CoglVertexBuffer *buffer; - - if (!cogl_is_vertex_buffer (handle)) - return; - - buffer = handle; - - update_primitive_and_draw (buffer, mode, first, count, NULL); -} - -static CoglHandle -_cogl_vertex_buffer_indices_new_real (CoglIndices *indices) -{ - CoglVertexBufferIndices *buffer_indices = - g_slice_alloc (sizeof (CoglVertexBufferIndices)); - buffer_indices->indices = indices; - - return _cogl_vertex_buffer_indices_handle_new (buffer_indices); -} - -CoglHandle -cogl_vertex_buffer_indices_new (CoglIndicesType indices_type, - const void *indices_array, - int indices_len) -{ - CoglIndices *indices; - - _COGL_GET_CONTEXT (ctx, NULL); - - indices = cogl_indices_new (ctx, indices_type, indices_array, indices_len); - return _cogl_vertex_buffer_indices_new_real (indices); -} - -CoglIndicesType -cogl_vertex_buffer_indices_get_type (CoglHandle indices_handle) -{ - CoglVertexBufferIndices *buffer_indices = NULL; - - if (!cogl_is_vertex_buffer_indices (indices_handle)) - return COGL_INDICES_TYPE_UNSIGNED_SHORT; - - buffer_indices = indices_handle; - - return cogl_indices_get_type (buffer_indices->indices); -} - -void -_cogl_vertex_buffer_indices_free (CoglVertexBufferIndices *buffer_indices) -{ - cogl_object_unref (buffer_indices->indices); - g_slice_free (CoglVertexBufferIndices, buffer_indices); -} - -void -cogl_vertex_buffer_draw_elements (CoglHandle handle, - CoglVerticesMode mode, - CoglHandle indices_handle, - int min_index, - int max_index, - int indices_offset, - int count) -{ - CoglVertexBuffer *buffer; - CoglVertexBufferIndices *buffer_indices; - - if (!cogl_is_vertex_buffer (handle)) - return; - - buffer = handle; - - if (!cogl_is_vertex_buffer_indices (indices_handle)) - return; - - buffer_indices = indices_handle; - - update_primitive_and_draw (buffer, mode, indices_offset, count, - buffer_indices); -} - -static void -_cogl_vertex_buffer_free (CoglVertexBuffer *buffer) -{ - GList *tmp; - - for (tmp = buffer->submitted_vbos; tmp != NULL; tmp = tmp->next) - cogl_vertex_buffer_vbo_free (tmp->data); - g_list_free (buffer->submitted_vbos); - - for (tmp = buffer->new_attributes; tmp != NULL; tmp = tmp->next) - _cogl_vertex_buffer_attrib_free (tmp->data); - g_list_free (buffer->new_attributes); - - if (buffer->primitive) - cogl_object_unref (buffer->primitive); - - g_slice_free (CoglVertexBuffer, buffer); -} - -CoglHandle -cogl_vertex_buffer_indices_get_for_quads (unsigned int n_indices) -{ - _COGL_GET_CONTEXT (ctx, NULL); - - if (n_indices <= 256 / 4 * 6) - { - if (ctx->quad_buffer_indices_byte == NULL) - { - /* NB: cogl_get_quad_indices takes n_quads not n_indices... */ - CoglIndices *indices = cogl_get_rectangle_indices (ctx, 256 / 4); - cogl_object_ref (indices); - ctx->quad_buffer_indices_byte = - _cogl_vertex_buffer_indices_new_real (indices); - } - - return ctx->quad_buffer_indices_byte; - } - else - { - if (ctx->quad_buffer_indices && - ctx->quad_buffer_indices_len < n_indices) - { - cogl_object_unref (ctx->quad_buffer_indices); - ctx->quad_buffer_indices = NULL; - } - - if (ctx->quad_buffer_indices == NULL) - { - /* NB: cogl_get_quad_indices takes n_quads not n_indices... */ - CoglIndices *indices = - cogl_get_rectangle_indices (ctx, n_indices / 6); - cogl_object_ref (indices); - ctx->quad_buffer_indices = - _cogl_vertex_buffer_indices_new_real (indices); - } - - ctx->quad_buffer_indices_len = n_indices; - - return ctx->quad_buffer_indices; - } - - g_return_val_if_reached (NULL); -} - diff --git a/cogl/cogl/deprecated/cogl-vertex-buffer.h b/cogl/cogl/deprecated/cogl-vertex-buffer.h deleted file mode 100644 index cf440cb1a..000000000 --- a/cogl/cogl/deprecated/cogl-vertex-buffer.h +++ /dev/null @@ -1,425 +0,0 @@ -/* - * Cogl - * - * A Low Level GPU Graphics and Utilities API - * - * Copyright (C) 2008,2009 Intel Corporation. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * - * - * Authors: - * Robert Bragg - */ - -#if !defined(__COGL_H_INSIDE__) && !defined(COGL_COMPILATION) -#error "Only can be included directly." -#endif - -#ifndef __COGL_VERTEX_BUFFER_H__ -#define __COGL_VERTEX_BUFFER_H__ - -#include -#include -#include -#include - -G_BEGIN_DECLS - -/** - * SECTION:cogl-vertex-buffer - * @short_description: An API for submitting extensible arrays of vertex - * attributes to be mapped into the GPU for fast drawing. - * - * For example to describe a textured triangle, you could create a new cogl - * vertex buffer with 3 vertices, and then you might add 2 attributes for each - * vertex: - * - * - * a "gl_Position" describing the (x,y,z) position for each vertex. - * - * - * a "gl_MultiTexCoord0" describing the (tx,ty) texture coordinates for each - * vertex. - * - * - * - * The Vertex Buffer API is designed to be a fairly raw mechanism for - * developers to be able to submit geometry to Cogl in a format that can be - * directly consumed by an OpenGL driver and mapped into your GPU for fast - * re-use. It is designed to avoid repeated validation of the attributes by the - * driver; to minimize transport costs (e.g. considering indirect GLX - * use-cases) and to potentially avoid repeated format conversions when - * attributes are supplied in a format that is not natively supported by the - * GPU. - * - * Although this API does allow you to modify attributes after they have been - * submitted to the GPU you should be aware that modification is not that - * cheap, since it implies validating the new data and potentially the - * OpenGL driver will need to reformat it for the GPU. - * - * If at all possible think of tricks that let you re-use static attributes, - * and if you do need to repeatedly update attributes (e.g. for some kind of - * morphing geometry) then only update and re-submit the specific attributes - * that have changed. - */ - -/** - * cogl_vertex_buffer_new: - * @n_vertices: The number of vertices that your attributes will correspond to. - * - * Creates a new vertex buffer that you can use to add attributes. - * - * Return value: a new #CoglHandle - * Deprecated: 1.16: Use the #CoglPrimitive api instead - */ -COGL_DEPRECATED_FOR (cogl_primitive_API) -CoglHandle -cogl_vertex_buffer_new (unsigned int n_vertices); - -/** - * cogl_vertex_buffer_get_n_vertices: - * @handle: A vertex buffer handle - * - * Retrieves the number of vertices that @handle represents - * - * Return value: the number of vertices - * Deprecated: 1.16: Use the #CoglPrimitive api instead - */ -COGL_DEPRECATED_FOR (cogl_primitive_API) -unsigned int -cogl_vertex_buffer_get_n_vertices (CoglHandle handle); - -/** - * cogl_vertex_buffer_add: - * @handle: A vertex buffer handle - * @attribute_name: The name of your attribute. It should be a valid GLSL - * variable name and standard attribute types must use one of following - * built-in names: (Note: they correspond to the built-in names of GLSL) - * - * "gl_Color" - * "gl_Normal" - * "gl_MultiTexCoord0, gl_MultiTexCoord1, ..." - * "gl_Vertex" - * - * To support adding multiple variations of the same attribute the name - * can have a detail component, E.g. "gl_Color::active" or - * "gl_Color::inactive" - * @n_components: The number of components per attribute and must be 1, 2, - * 3 or 4 - * @type: a #CoglAttributeType specifying the data type of each component. - * @normalized: If %TRUE, this specifies that values stored in an integer - * format should be mapped into the range [-1.0, 1.0] or [0.0, 1.0] - * for unsigned values. If %FALSE they are converted to floats - * directly. - * @stride: This specifies the number of bytes from the start of one attribute - * value to the start of the next value (for the same attribute). So, for - * example, with a position interleved with color like this: - * XYRGBAXYRGBAXYRGBA, then if each letter represents a byte, the - * stride for both attributes is 6. The special value 0 means the - * values are stored sequentially in memory. - * @pointer: This addresses the first attribute in the vertex array. This - * must remain valid until you either call cogl_vertex_buffer_submit() or - * issue a draw call. - * - * Adds an attribute to a buffer, or replaces a previously added - * attribute with the same name. - * - * You either can use one of the built-in names such as "gl_Vertex", or - * "gl_MultiTexCoord0" to add standard attributes, like positions, colors - * and normals, or you can add custom attributes for use in shaders. - * - * The number of vertices declared when calling cogl_vertex_buffer_new() - * determines how many attribute values will be read from the supplied - * @pointer. - * - * The data for your attribute isn't copied anywhere until you call - * cogl_vertex_buffer_submit(), or issue a draw call which automatically - * submits pending attribute changes. so the supplied pointer must remain - * valid until then. If you are updating an existing attribute (done by - * re-adding it) then you still need to re-call cogl_vertex_buffer_submit() - * to commit the changes to the GPU. Be carefull to minimize the number - * of calls to cogl_vertex_buffer_submit(), though. - * - * If you are interleving attributes it is assumed that each interleaved - * attribute starts no farther than +- stride bytes from the other attributes - * it is interleved with. I.e. this is ok: - * - * |-0-0-0-0-0-0-0-0-0-0| - * - * This is not ok: - * - * |- - - - -0-0-0-0-0-0 0 0 0 0| - * - * (Though you can have multiple groups of interleved attributes) - * - * Deprecated: 1.16: Use the #CoglPrimitive api instead - */ -COGL_DEPRECATED_FOR (cogl_primitive_API) -void -cogl_vertex_buffer_add (CoglHandle handle, - const char *attribute_name, - uint8_t n_components, - CoglAttributeType type, - gboolean normalized, - uint16_t stride, - const void *pointer); - -/** - * cogl_vertex_buffer_delete: - * @handle: A vertex buffer handle - * @attribute_name: The name of a previously added attribute - * - * Deletes an attribute from a buffer. You will need to call - * cogl_vertex_buffer_submit() or issue a draw call to commit this - * change to the GPU. - * - * Deprecated: 1.16: Use the #CoglPrimitive api instead - */ -COGL_DEPRECATED_FOR (cogl_primitive_API) -void -cogl_vertex_buffer_delete (CoglHandle handle, - const char *attribute_name); - -/** - * cogl_vertex_buffer_submit: - * @handle: A vertex buffer handle - * - * Submits all the user added attributes to the GPU; once submitted, the - * attributes can be used for drawing. - * - * You should aim to minimize calls to this function since it implies - * validating your data; it potentially incurs a transport cost (especially if - * you are using GLX indirect rendering) and potentially a format conversion - * cost if the GPU doesn't natively support any of the given attribute formats. - * - * Deprecated: 1.16: Use the #CoglPrimitive api instead - */ -COGL_DEPRECATED_FOR (cogl_primitive_API) -void -cogl_vertex_buffer_submit (CoglHandle handle); - -/** - * cogl_vertex_buffer_disable: - * @handle: A vertex buffer handle - * @attribute_name: The name of the attribute you want to disable - * - * Disables a previosuly added attribute. - * - * Since it can be costly to add and remove new attributes to buffers; to make - * individual buffers more reuseable it is possible to enable and disable - * attributes before using a buffer for drawing. - * - * You don't need to call cogl_vertex_buffer_submit() after using this - * function. - * - * Deprecated: 1.16: Use the #CoglPrimitive api instead - */ -COGL_DEPRECATED_FOR (cogl_primitive_API) -void -cogl_vertex_buffer_disable (CoglHandle handle, - const char *attribute_name); - -/** - * cogl_vertex_buffer_enable: - * @handle: A vertex buffer handle - * @attribute_name: The name of the attribute you want to enable - * - * Enables a previosuly disabled attribute. - * - * Since it can be costly to add and remove new attributes to buffers; to make - * individual buffers more reuseable it is possible to enable and disable - * attributes before using a buffer for drawing. - * - * You don't need to call cogl_vertex_buffer_submit() after using this function - * - * Deprecated: 1.16: Use the #CoglPrimitive api instead - */ -COGL_DEPRECATED_FOR (cogl_primitive_API) -void -cogl_vertex_buffer_enable (CoglHandle handle, - const char *attribute_name); - -/** - * cogl_vertex_buffer_draw: - * @handle: A vertex buffer handle - * @mode: A #CoglVerticesMode specifying how the vertices should be - * interpreted. - * @first: Specifies the index of the first vertex you want to draw with - * @count: Specifies the number of vertices you want to draw. - * - * Allows you to draw geometry using all or a subset of the - * vertices in a vertex buffer. - * - * Any un-submitted attribute changes are automatically submitted before - * drawing. - * - * Deprecated: 1.16: Use the #CoglPrimitive api instead - */ -COGL_DEPRECATED_FOR (cogl_primitive_API) -void -cogl_vertex_buffer_draw (CoglHandle handle, - CoglVerticesMode mode, - int first, - int count); - -/** - * cogl_vertex_buffer_indices_new: (skip) - * @indices_type: a #CoglIndicesType specifying the data type used for - * the indices. - * @indices_array: (array length=indices_len): 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. - * - * Return value: A CoglHandle for the indices which you can pass to - * cogl_vertex_buffer_draw_elements(). - * - * Deprecated: 1.16: Use the #CoglPrimitive api instead - */ -COGL_DEPRECATED_FOR (cogl_primitive_API) -CoglHandle -cogl_vertex_buffer_indices_new (CoglIndicesType indices_type, - const void *indices_array, - int indices_len); - -/** - * cogl_vertex_buffer_indices_get_type: - * @indices: An indices handle - * - * Queries back the data type used for the given indices - * - * Returns: The CoglIndicesType used - * - * Deprecated: 1.16: Use the #CoglPrimitive api instead - */ -COGL_DEPRECATED_FOR (cogl_primitive_API) -CoglIndicesType -cogl_vertex_buffer_indices_get_type (CoglHandle indices); - -/** - * cogl_vertex_buffer_draw_elements: - * @handle: A vertex buffer handle - * @mode: A #CoglVerticesMode specifying how the vertices should be - * interpreted. - * @indices: A CoglHandle for a set of indices allocated via - * cogl_vertex_buffer_indices_new () - * @min_index: Specifies the minimum vertex index contained in indices - * @max_index: Specifies the maximum vertex index contained in 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. - * - * This function lets you use an array of indices to specify the vertices - * within your vertex buffer that you want to draw. The indices themselves - * are created by calling cogl_vertex_buffer_indices_new () - * - * Any un-submitted attribute changes are automatically submitted before - * drawing. - * Deprecated: 1.16: Use the #CoglPrimitive api instead - */ -COGL_DEPRECATED_FOR (cogl_primitive_API) -void -cogl_vertex_buffer_draw_elements (CoglHandle handle, - CoglVerticesMode mode, - CoglHandle indices, - int min_index, - int max_index, - int indices_offset, - int count); - -/** - * 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 like that shown - * in then you can request 6 - * indices to render two triangles like those shown in . - * - *
- * Example of vertices submitted to form a quad - * - *
- * - *
- * Illustration of the triangle indices that will be generated - * - *
- * - * Returns: A %CoglHandle containing the indices. The handled is - * owned by Cogl and should not be modified or unref'd. - * - * Deprecated: 1.16: Use the #CoglPrimitive api instead - */ -COGL_DEPRECATED_FOR (cogl_primitive_API) -CoglHandle -cogl_vertex_buffer_indices_get_for_quads (unsigned int n_indices); - -/** - * cogl_is_vertex_buffer: - * @handle: a #CoglHandle for a vertex buffer object - * - * Checks whether @handle is a Vertex Buffer Object - * - * Return value: %TRUE if the handle is a VBO, and %FALSE - * otherwise - * - * Since: 1.0 - * Deprecated: 1.16: Use the #CoglPrimitive api instead - */ -COGL_DEPRECATED_FOR (cogl_primitive_API) -gboolean -cogl_is_vertex_buffer (CoglHandle handle); - -/** - * cogl_is_vertex_buffer_indices: - * @handle: a #CoglHandle - * - * Checks whether @handle is a handle to the indices for a vertex - * buffer object - * - * Return value: %TRUE if the handle is indices, and %FALSE - * otherwise - * - * Since: 1.4 - * Deprecated: 1.16: Use the #CoglPrimitive api instead - */ -COGL_DEPRECATED_FOR (cogl_primitive_API) -gboolean -cogl_is_vertex_buffer_indices (CoglHandle handle); -G_END_DECLS - -#endif /* __COGL_VERTEX_BUFFER_H__ */ diff --git a/cogl/cogl/driver/gl/cogl-pipeline-opengl.c b/cogl/cogl/driver/gl/cogl-pipeline-opengl.c index 89696b966..ebdb0981c 100644 --- a/cogl/cogl/driver/gl/cogl-pipeline-opengl.c +++ b/cogl/cogl/driver/gl/cogl-pipeline-opengl.c @@ -985,7 +985,7 @@ fragend_add_layer_cb (CoglPipelineLayer *layer, * * Currently for textured rectangles we manually calculate the texture * coords for each slice based on the users given coords, but this solution - * isn't ideal, and can't be used with CoglVertexBuffers. + * isn't ideal. */ void _cogl_pipeline_flush_gl_state (CoglContext *ctx, diff --git a/cogl/cogl/meson.build b/cogl/cogl/meson.build index f6f8c0163..f9d5c5ef4 100644 --- a/cogl/cogl/meson.build +++ b/cogl/cogl/meson.build @@ -65,7 +65,6 @@ built_headers += [cogl_gl_header_h] cogl_deprecated_headers = [ 'deprecated/cogl-material-compat.h', - 'deprecated/cogl-vertex-buffer.h', 'deprecated/cogl-shader.h', 'deprecated/cogl-clutter.h', 'deprecated/cogl-type-casts.h', @@ -352,8 +351,6 @@ cogl_sources = [ 'cogl-closure-list.c', 'cogl-fence.c', 'cogl-fence-private.h', - 'deprecated/cogl-vertex-buffer-private.h', - 'deprecated/cogl-vertex-buffer.c', 'deprecated/cogl-material-compat.c', 'deprecated/cogl-program.c', 'deprecated/cogl-program-private.h', diff --git a/cogl/tests/conform/meson.build b/cogl/tests/conform/meson.build index b36467593..2a7917aaa 100644 --- a/cogl/tests/conform/meson.build +++ b/cogl/tests/conform/meson.build @@ -54,8 +54,6 @@ cogl_test_conformance_sources = [ # "test-readpixels.c", # "test-texture-mipmaps.c", # "test-texture-pixmap-x11.c",", -# "test-vertex-buffer-contiguous.c", -# "test-vertex-buffer-interleved.c", #] cogl_test_conformance_includes = [ diff --git a/cogl/tests/conform/test-vertex-buffer-contiguous.c b/cogl/tests/conform/test-vertex-buffer-contiguous.c deleted file mode 100644 index f74e3ac7a..000000000 --- a/cogl/tests/conform/test-vertex-buffer-contiguous.c +++ /dev/null @@ -1,259 +0,0 @@ - -#include -#include - -#include "test-conform-common.h" - -/* This test verifies that the simplest usage of the vertex buffer API, - * where we add contiguous (x,y) GLfloat vertices, and RGBA GLubyte color - * attributes to a buffer, submit, and draw. - * - * It also tries to verify that the enable/disable attribute APIs are working - * too. - * - * If you want visual feedback of what this test paints for debugging purposes, - * then remove the call to clutter_main_quit() in validate_result. - */ - -typedef struct _TestState -{ - CoglHandle buffer; - CoglHandle texture; - CoglHandle material; - ClutterGeometry stage_geom; -} TestState; - -static void -validate_result (TestState *state) -{ - GLubyte pixel[4]; - GLint y_off = 90; - - if (cogl_test_verbose ()) - g_print ("y_off = %d\n", y_off); - - /* NB: We ignore the alpha, since we don't know if our render target is - * RGB or RGBA */ - -#define RED 0 -#define GREEN 1 -#define BLUE 2 - - /* Should see a blue pixel */ - cogl_read_pixels (10, y_off, 1, 1, - COGL_READ_PIXELS_COLOR_BUFFER, - COGL_PIXEL_FORMAT_RGBA_8888_PRE, - pixel); - if (cogl_test_verbose ()) - g_print ("pixel 0 = %x, %x, %x\n", pixel[RED], pixel[GREEN], pixel[BLUE]); - g_assert (pixel[RED] == 0 && pixel[GREEN] == 0 && pixel[BLUE] != 0); - - /* Should see a red pixel */ - cogl_read_pixels (110, y_off, 1, 1, - COGL_READ_PIXELS_COLOR_BUFFER, - COGL_PIXEL_FORMAT_RGBA_8888_PRE, - pixel); - if (cogl_test_verbose ()) - g_print ("pixel 1 = %x, %x, %x\n", pixel[RED], pixel[GREEN], pixel[BLUE]); - g_assert (pixel[RED] != 0 && pixel[GREEN] == 0 && pixel[BLUE] == 0); - - /* Should see a blue pixel */ - cogl_read_pixels (210, y_off, 1, 1, - COGL_READ_PIXELS_COLOR_BUFFER, - COGL_PIXEL_FORMAT_RGBA_8888_PRE, - pixel); - if (cogl_test_verbose ()) - g_print ("pixel 2 = %x, %x, %x\n", pixel[RED], pixel[GREEN], pixel[BLUE]); - g_assert (pixel[RED] == 0 && pixel[GREEN] == 0 && pixel[BLUE] != 0); - - /* Should see a green pixel, at bottom of 4th triangle */ - cogl_read_pixels (310, y_off, 1, 1, - COGL_READ_PIXELS_COLOR_BUFFER, - COGL_PIXEL_FORMAT_RGBA_8888_PRE, - pixel); - if (cogl_test_verbose ()) - g_print ("pixel 3 = %x, %x, %x\n", pixel[RED], pixel[GREEN], pixel[BLUE]); - g_assert (pixel[GREEN] > pixel[RED] && pixel[GREEN] > pixel[BLUE]); - - /* Should see a red pixel, at top of 4th triangle */ - cogl_read_pixels (310, y_off - 70, 1, 1, - COGL_READ_PIXELS_COLOR_BUFFER, - COGL_PIXEL_FORMAT_RGBA_8888_PRE, - pixel); - if (cogl_test_verbose ()) - g_print ("pixel 4 = %x, %x, %x\n", pixel[RED], pixel[GREEN], pixel[BLUE]); - g_assert (pixel[RED] > pixel[GREEN] && pixel[RED] > pixel[BLUE]); - - -#undef RED -#undef GREEN -#undef BLUE - - /* Comment this out if you want visual feedback of what this test - * paints. - */ - clutter_main_quit (); -} - -static void -on_paint (ClutterActor *actor, - ClutterPaintContext *paint_context, - TestState *state) -{ - /* Draw a faded blue triangle */ - cogl_vertex_buffer_enable (state->buffer, "gl_Color::blue"); - cogl_set_source_color4ub (0xff, 0x00, 0x00, 0xff); - cogl_vertex_buffer_draw (state->buffer, - GL_TRIANGLE_STRIP, /* mode */ - 0, /* first */ - 3); /* count */ - - /* Draw a red triangle */ - /* Here we are testing that the disable attribute works; if it doesn't - * the triangle will remain faded blue */ - cogl_translate (100, 0, 0); - cogl_vertex_buffer_disable (state->buffer, "gl_Color::blue"); - cogl_set_source_color4ub (0xff, 0x00, 0x00, 0xff); - cogl_vertex_buffer_draw (state->buffer, - GL_TRIANGLE_STRIP, /* mode */ - 0, /* first */ - 3); /* count */ - - /* Draw a faded blue triangle */ - /* Here we are testing that the re-enable works; if it doesn't - * the triangle will remain red */ - cogl_translate (100, 0, 0); - cogl_vertex_buffer_enable (state->buffer, "gl_Color::blue"); - cogl_set_source_color4ub (0xff, 0x00, 0x00, 0xff); - cogl_vertex_buffer_draw (state->buffer, - GL_TRIANGLE_STRIP, /* mode */ - 0, /* first */ - 3); /* count */ - - /* Draw a textured triangle */ - cogl_translate (100, 0, 0); - cogl_vertex_buffer_disable (state->buffer, "gl_Color::blue"); - cogl_set_source (state->material); - cogl_material_set_color4ub (state->material, 0xff, 0xff, 0xff, 0xff); - cogl_vertex_buffer_draw (state->buffer, - GL_TRIANGLE_STRIP, /* mode */ - 0, /* first */ - 3); /* count */ - - validate_result (state); -} - -static gboolean -queue_redraw (gpointer stage) -{ - clutter_actor_queue_redraw (CLUTTER_ACTOR (stage)); - - return TRUE; -} - - - -void -test_vertex_buffer_contiguous (TestUtilsGTestFixture *fixture, - void *data) -{ - TestState state; - ClutterActor *stage; - ClutterColor stage_clr = {0x0, 0x0, 0x0, 0xff}; - ClutterActor *group; - unsigned int idle_source; - guchar tex_data[] = { - 0xff, 0x00, 0x00, 0xff, - 0xff, 0x00, 0x00, 0xff, - 0x00, 0xff, 0x00, 0xff, - 0x00, 0xff, 0x00, 0xff - }; - - stage = clutter_stage_get_default (); - - clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_clr); - clutter_actor_get_geometry (stage, &state.stage_geom); - - group = clutter_group_new (); - clutter_actor_set_size (group, - state.stage_geom.width, - state.stage_geom.height); - clutter_container_add_actor (CLUTTER_CONTAINER (stage), group); - - /* We force continuous redrawing incase someone comments out the - * clutter_main_quit and wants visual feedback for the test since we - * wont be doing anything else that will trigger redrawing. */ - idle_source = g_idle_add (queue_redraw, stage); - - g_signal_connect (group, "paint", G_CALLBACK (on_paint), &state); - - state.texture = cogl_texture_new_from_data (2, 2, - COGL_TEXTURE_NO_SLICING, - COGL_PIXEL_FORMAT_RGBA_8888, - COGL_PIXEL_FORMAT_ANY, - 0, /* auto calc row stride */ - tex_data); - - state.material = cogl_material_new (); - cogl_material_set_color4ub (state.material, 0x00, 0xff, 0x00, 0xff); - cogl_material_set_layer (state.material, 0, state.texture); - - { - GLfloat triangle_verts[3][2] = - { - {0.0, 0.0}, - {100.0, 100.0}, - {0.0, 100.0} - }; - GLbyte triangle_colors[3][4] = - { - {0x00, 0x00, 0xff, 0xff}, /* blue */ - {0x00, 0x00, 0xff, 0x00}, /* transparent blue */ - {0x00, 0x00, 0xff, 0x00} /* transparent blue */ - }; - GLfloat triangle_tex_coords[3][2] = - { - {0.0, 0.0}, - {1.0, 1.0}, - {0.0, 1.0} - }; - state.buffer = cogl_vertex_buffer_new (3 /* n vertices */); - cogl_vertex_buffer_add (state.buffer, - "gl_Vertex", - 2, /* n components */ - GL_FLOAT, - FALSE, /* normalized */ - 0, /* stride */ - triangle_verts); - cogl_vertex_buffer_add (state.buffer, - "gl_Color::blue", - 4, /* n components */ - GL_UNSIGNED_BYTE, - FALSE, /* normalized */ - 0, /* stride */ - triangle_colors); - cogl_vertex_buffer_add (state.buffer, - "gl_MultiTexCoord0", - 2, /* n components */ - GL_FLOAT, - FALSE, /* normalized */ - 0, /* stride */ - triangle_tex_coords); - - cogl_vertex_buffer_submit (state.buffer); - } - - clutter_actor_show_all (stage); - - clutter_main (); - - cogl_object_unref (state.buffer); - cogl_object_unref (state.material); - cogl_object_unref (state.texture); - - g_clear_handle_id (&idle_source, g_source_remove); - - if (cogl_test_verbose ()) - g_print ("OK\n"); -} - diff --git a/cogl/tests/conform/test-vertex-buffer-interleved.c b/cogl/tests/conform/test-vertex-buffer-interleved.c deleted file mode 100644 index 057adc94a..000000000 --- a/cogl/tests/conform/test-vertex-buffer-interleved.c +++ /dev/null @@ -1,164 +0,0 @@ - -#include -#include - -#include "test-conform-common.h" - -/* This test verifies that interleved attributes work with the vertex buffer - * API. We add (x,y) GLfloat vertices, interleved with RGBA GLubyte color - * attributes to a buffer, submit and draw. - * - * If you want visual feedback of what this test paints for debugging purposes, - * then remove the call to clutter_main_quit() in validate_result. - */ - -typedef struct _TestState -{ - CoglHandle buffer; - ClutterGeometry stage_geom; -} TestState; - -typedef struct _InterlevedVertex -{ - GLfloat x; - GLfloat y; - - GLubyte r; - GLubyte g; - GLubyte b; - GLubyte a; -} InterlevedVertex; - - -static void -validate_result (TestState *state) -{ - GLubyte pixel[4]; - GLint y_off = 90; - - /* NB: We ignore the alpha, since we don't know if our render target is - * RGB or RGBA */ - -#define RED 0 -#define GREEN 1 -#define BLUE 2 - - /* Should see a blue pixel */ - cogl_read_pixels (10, y_off, 1, 1, - COGL_READ_PIXELS_COLOR_BUFFER, - COGL_PIXEL_FORMAT_RGBA_8888_PRE, - pixel); - if (cogl_test_verbose ()) - g_print ("pixel 0 = %x, %x, %x\n", pixel[RED], pixel[GREEN], pixel[BLUE]); - g_assert (pixel[RED] == 0 && pixel[GREEN] == 0 && pixel[BLUE] != 0); - -#undef RED -#undef GREEN -#undef BLUE - - /* Comment this out if you want visual feedback of what this test - * paints. - */ - clutter_main_quit (); -} - -static void -on_paint (ClutterActor *actor, - ClutterPaintContext *paint_context, - TestState *state) -{ - /* Draw a faded blue triangle */ - cogl_vertex_buffer_draw (state->buffer, - GL_TRIANGLE_STRIP, /* mode */ - 0, /* first */ - 3); /* count */ - - validate_result (state); -} - -static gboolean -queue_redraw (gpointer stage) -{ - clutter_actor_queue_redraw (CLUTTER_ACTOR (stage)); - - return TRUE; -} - -void -test_vertex_buffer_interleved (TestUtilsGTestFixture *fixture, - void *data) -{ - TestState state; - ClutterActor *stage; - ClutterColor stage_clr = {0x0, 0x0, 0x0, 0xff}; - ClutterActor *group; - unsigned int idle_source; - - stage = clutter_stage_get_default (); - - clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_clr); - clutter_actor_get_geometry (stage, &state.stage_geom); - - group = clutter_group_new (); - clutter_actor_set_size (group, - state.stage_geom.width, - state.stage_geom.height); - clutter_container_add_actor (CLUTTER_CONTAINER (stage), group); - - /* We force continuous redrawing incase someone comments out the - * clutter_main_quit and wants visual feedback for the test since we - * wont be doing anything else that will trigger redrawing. */ - idle_source = g_idle_add (queue_redraw, stage); - - g_signal_connect (group, "paint", G_CALLBACK (on_paint), &state); - - { - InterlevedVertex verts[3] = - { - { /* .x = */ 0.0, /* .y = */ 0.0, - /* blue */ - /* .r = */ 0x00, /* .g = */ 0x00, /* .b = */ 0xff, /* .a = */ 0xff }, - - { /* .x = */ 100.0, /* .y = */ 100.0, - /* transparent blue */ - /* .r = */ 0x00, /* .g = */ 0x00, /* .b = */ 0xff, /* .a = */ 0x00 }, - - { /* .x = */ 0.0, /* .y = */ 100.0, - /* transparent blue */ - /* .r = */ 0x00, /* .g = */ 0x00, /* .b = */ 0xff, /* .a = */ 0x00 }, - }; - - /* We assume the compiler is doing no funny struct padding for this test: - */ - g_assert (sizeof (InterlevedVertex) == 12); - - state.buffer = cogl_vertex_buffer_new (3 /* n vertices */); - cogl_vertex_buffer_add (state.buffer, - "gl_Vertex", - 2, /* n components */ - GL_FLOAT, - FALSE, /* normalized */ - 12, /* stride */ - &verts[0].x); - cogl_vertex_buffer_add (state.buffer, - "gl_Color", - 4, /* n components */ - GL_UNSIGNED_BYTE, - FALSE, /* normalized */ - 12, /* stride */ - &verts[0].r); - cogl_vertex_buffer_submit (state.buffer); - } - - clutter_actor_show_all (stage); - - clutter_main (); - - cogl_object_unref (state.buffer); - - g_clear_handle_id (&idle_source, g_source_remove); - - if (cogl_test_verbose ()) - g_print ("OK\n"); -} - diff --git a/cogl/tests/conform/test-wrap-modes.c b/cogl/tests/conform/test-wrap-modes.c index 92a609ec3..1c524f295 100644 --- a/cogl/tests/conform/test-wrap-modes.c +++ b/cogl/tests/conform/test-wrap-modes.c @@ -139,43 +139,6 @@ draw_tests_polygon (TestState *state) } } -static void -draw_tests_vbo (TestState *state) -{ - CoglHandle vbo; - int i; - - vbo = cogl_vertex_buffer_new (4); - cogl_vertex_buffer_add (vbo, "gl_Vertex", 3, - COGL_ATTRIBUTE_TYPE_FLOAT, FALSE, - sizeof (vertices[0]), - &vertices[0].x); - cogl_vertex_buffer_add (vbo, "gl_MultiTexCoord0", 2, - COGL_ATTRIBUTE_TYPE_FLOAT, FALSE, - sizeof (vertices[0]), - &vertices[0].tx); - cogl_vertex_buffer_submit (vbo); - - for (i = 0; i < G_N_ELEMENTS (wrap_modes); i += 2) - { - CoglPipelineWrapMode wrap_mode_s, wrap_mode_t; - CoglPipeline *pipeline; - - wrap_mode_s = wrap_modes[i]; - wrap_mode_t = wrap_modes[i + 1]; - pipeline = create_pipeline (state, wrap_mode_s, wrap_mode_t); - cogl_set_source (pipeline); - cogl_object_unref (pipeline); - cogl_push_matrix (); - cogl_translate (TEX_SIZE * i, 0.0f, 0.0f); - /* Render the pipeline at four times the size of the texture */ - cogl_vertex_buffer_draw (vbo, COGL_VERTICES_MODE_TRIANGLE_FAN, 0, 4); - cogl_pop_matrix (); - } - - cogl_object_unref (vbo); -} - static void validate_set (TestState *state, int offset) { @@ -232,7 +195,6 @@ validate_result (TestState *state) validate_set (state, 1); /* atlased rectangle */ #endif validate_set (state, 2); /* cogl_polygon */ - validate_set (state, 3); /* vertex buffer */ } static void @@ -260,14 +222,6 @@ paint (TestState *state) cogl_pop_matrix (); cogl_object_unref (state->texture); - /* Draw the tests using a vertex buffer */ - state->texture = create_texture (TEST_UTILS_TEXTURE_NO_ATLAS); - cogl_push_matrix (); - cogl_translate (0.0f, TEX_SIZE * 6.0f, 0.0f); - draw_tests_vbo (state); - cogl_pop_matrix (); - cogl_object_unref (state->texture); - validate_result (state); } diff --git a/src/tests/clutter/interactive/meson.build b/src/tests/clutter/interactive/meson.build index 7a12d8ae2..12274768e 100644 --- a/src/tests/clutter/interactive/meson.build +++ b/src/tests/clutter/interactive/meson.build @@ -36,7 +36,6 @@ clutter_tests_interactive_test_sources = [ 'test-text-field.c', 'test-cairo-clock.c', 'test-cairo-flowers.c', - 'test-cogl-vertex-buffer.c', 'test-stage-sizing.c', 'test-scrolling.c', 'test-swipe-action.c', diff --git a/src/tests/clutter/interactive/test-cogl-point-sprites.c b/src/tests/clutter/interactive/test-cogl-point-sprites.c index 453d6fffe..30b2567bc 100644 --- a/src/tests/clutter/interactive/test-cogl-point-sprites.c +++ b/src/tests/clutter/interactive/test-cogl-point-sprites.c @@ -102,7 +102,6 @@ paint_cb (ClutterActor *stage, CoglMatrix old_matrix, new_matrix; int i; float diff_time; - CoglHandle vbo; cogl_get_projection_matrix (&old_matrix); /* Use an orthogonal projection from -1 -> 1 in both axes */ @@ -197,22 +196,6 @@ paint_cb (ClutterActor *stage, g_timer_reset (data->last_spark_time); } - vbo = cogl_vertex_buffer_new (N_SPARKS); - cogl_vertex_buffer_add (vbo, "gl_Vertex", 2, - COGL_ATTRIBUTE_TYPE_FLOAT, FALSE, - sizeof (Spark), - &data->sparks[0].x); - cogl_vertex_buffer_add (vbo, "gl_Color", 4, - COGL_ATTRIBUTE_TYPE_UNSIGNED_BYTE, TRUE, - sizeof (Spark), - &data->sparks[0].color.red); - cogl_vertex_buffer_submit (vbo); - - cogl_set_source (data->material); - cogl_vertex_buffer_draw (vbo, COGL_VERTICES_MODE_POINTS, 0, N_SPARKS); - - cogl_object_unref (vbo); - cogl_set_projection_matrix (&old_matrix); cogl_pop_matrix (); } diff --git a/src/tests/clutter/interactive/test-cogl-vertex-buffer.c b/src/tests/clutter/interactive/test-cogl-vertex-buffer.c deleted file mode 100644 index 33dbbc3e1..000000000 --- a/src/tests/clutter/interactive/test-cogl-vertex-buffer.c +++ /dev/null @@ -1,398 +0,0 @@ -#include -#include -#include -#include -#include -#include - -/* Defines the size and resolution of the quad mesh we morph: - */ -#define MESH_WIDTH 100.0 /* number of quads along x axis */ -#define MESH_HEIGHT 100.0 /* number of quads along y axis */ -#define QUAD_WIDTH 5.0 /* width in pixels of a single quad */ -#define QUAD_HEIGHT 5.0 /* height in pixels of a single quad */ - -/* Defines a sine wave that sweeps across the mesh: - */ -#define WAVE_DEPTH ((MESH_WIDTH * QUAD_WIDTH) / 16.0) /* peak amplitude */ -#define WAVE_PERIODS 4.0 -#define WAVE_SPEED 10.0 - -/* Defines a rippling sine wave emitted from a point: - */ -#define RIPPLE_CENTER_X ((MESH_WIDTH / 2.0) * QUAD_WIDTH) -#define RIPPLE_CENTER_Y ((MESH_HEIGHT / 2.0) * QUAD_HEIGHT) -#define RIPPLE_RADIUS (MESH_WIDTH * QUAD_WIDTH) -#define RIPPLE_DEPTH ((MESH_WIDTH * QUAD_WIDTH) / 16.0) /* peak amplitude */ -#define RIPPLE_PERIODS 4.0 -#define RIPPLE_SPEED -10.0 - -/* Defines the width of the gaussian bell used to fade out the alpha - * towards the edges of the mesh (starting from the ripple center): - */ -#define GAUSSIAN_RADIUS ((MESH_WIDTH * QUAD_WIDTH) / 6.0) - -/* Our hues lie in the range [0, 1], and this defines how we map amplitude - * to hues (before scaling by {WAVE,RIPPLE}_DEPTH) - * As we are interferring two sine waves together; amplitudes lie in the - * range [-2, 2] - */ -#define HSL_OFFSET 0.5 /* the hue that we map an amplitude of 0 too */ -#define HSL_SCALE 0.25 - -typedef struct _TestState -{ - ClutterActor *dummy; - CoglHandle buffer; - float *quad_mesh_verts; - guint8 *quad_mesh_colors; - guint16 *static_indices; - guint n_static_indices; - CoglHandle indices; - ClutterTimeline *timeline; - guint frame_id; -} TestState; - -int -test_cogl_vertex_buffer_main (int argc, char *argv[]); - -const char * -test_cogl_vertex_buffer_describe (void); - -static void -frame_cb (ClutterTimeline *timeline, - gint elapsed_msecs, - TestState *state) -{ - guint x, y; - float period_progress = clutter_timeline_get_progress (timeline); - float period_progress_sin = sinf (period_progress); - float wave_shift = period_progress * WAVE_SPEED; - float ripple_shift = period_progress * RIPPLE_SPEED; - - for (y = 0; y <= MESH_HEIGHT; y++) - for (x = 0; x <= MESH_WIDTH; x++) - { - guint vert_index = (MESH_WIDTH + 1) * y + x; - float *vert = &state->quad_mesh_verts[3 * vert_index]; - - float real_x = x * QUAD_WIDTH; - float real_y = y * QUAD_HEIGHT; - - float wave_offset = (float)x / (MESH_WIDTH + 1); - float wave_angle = - (WAVE_PERIODS * 2 * G_PI * wave_offset) + wave_shift; - float wave_sin = sinf (wave_angle); - - float a_sqr = (RIPPLE_CENTER_X - real_x) * (RIPPLE_CENTER_X - real_x); - float b_sqr = (RIPPLE_CENTER_Y - real_y) * (RIPPLE_CENTER_Y - real_y); - float ripple_offset = sqrtf (a_sqr + b_sqr) / RIPPLE_RADIUS; - float ripple_angle = - (RIPPLE_PERIODS * 2 * G_PI * ripple_offset) + ripple_shift; - float ripple_sin = sinf (ripple_angle); - - float h, s, l; - guint8 *color; - - vert[2] = (wave_sin * WAVE_DEPTH) + (ripple_sin * RIPPLE_DEPTH); - - /* Burn some CPU time picking a pretty color... */ - h = (HSL_OFFSET - + wave_sin - + ripple_sin - + period_progress_sin) * HSL_SCALE; - s = 0.5; - l = 0.25 + (period_progress_sin + 1.0) / 4.0; - color = &state->quad_mesh_colors[4 * vert_index]; - /* A bit of a sneaky cast, but it seems safe to assume the ClutterColor - * typedef is set in stone... */ - clutter_color_from_hls ((ClutterColor *)color, h * 360.0, l, s); - - color[0] = (color[0] * color[3] + 128) / 255; - color[1] = (color[1] * color[3] + 128) / 255; - color[2] = (color[2] * color[3] + 128) / 255; - } - - cogl_vertex_buffer_add (state->buffer, - "gl_Vertex", - 3, /* n components */ - COGL_ATTRIBUTE_TYPE_FLOAT, - FALSE, /* normalized */ - 0, /* stride */ - state->quad_mesh_verts); - cogl_vertex_buffer_add (state->buffer, - "gl_Color", - 4, /* n components */ - COGL_ATTRIBUTE_TYPE_UNSIGNED_BYTE, - FALSE, /* normalized */ - 0, /* stride */ - state->quad_mesh_colors); - - cogl_vertex_buffer_submit (state->buffer); - - clutter_actor_set_rotation (state->dummy, - CLUTTER_Z_AXIS, - 360 * period_progress, - (MESH_WIDTH * QUAD_WIDTH) / 2, - (MESH_HEIGHT * QUAD_HEIGHT) / 2, - 0); - clutter_actor_set_rotation (state->dummy, - CLUTTER_X_AXIS, - 360 * period_progress, - (MESH_WIDTH * QUAD_WIDTH) / 2, - (MESH_HEIGHT * QUAD_HEIGHT) / 2, - 0); -} - -static void -on_paint (ClutterActor *actor, - ClutterPaintContext *paint_context, - TestState *state) -{ - cogl_set_source_color4ub (0xff, 0x00, 0x00, 0xff); - cogl_vertex_buffer_draw_elements (state->buffer, - COGL_VERTICES_MODE_TRIANGLE_STRIP, - state->indices, - 0, /* min index */ - (MESH_WIDTH + 1) * - (MESH_HEIGHT + 1) - 1, /* max index */ - 0, /* indices offset */ - state->n_static_indices); -} - -static void -init_static_index_arrays (TestState *state) -{ - guint n_indices; - int x, y; - guint16 *i; - guint dir; - - /* - Each row takes (2 + 2 * MESH_WIDTH indices) - * - Thats 2 to start the triangle strip then 2 indices to add 2 triangles - * per mesh quad. - * - We have MESH_HEIGHT rows - * - It takes one extra index for linking between rows (MESH_HEIGHT - 1) - * - A 2 x 3 mesh == 20 indices... */ - n_indices = (2 + 2 * MESH_WIDTH) * MESH_HEIGHT + (MESH_HEIGHT - 1); - state->static_indices = g_malloc (sizeof (guint16) * n_indices); - state->n_static_indices = n_indices; - -#define MESH_INDEX(X, Y) (Y) * (MESH_WIDTH + 1) + (X) - - i = state->static_indices; - - /* NB: front facing == anti-clockwise winding */ - - i[0] = MESH_INDEX (0, 0); - i[1] = MESH_INDEX (0, 1); - i += 2; - -#define LEFT 0 -#define RIGHT 1 - - dir = RIGHT; - - for (y = 0; y < MESH_HEIGHT; y++) - { - for (x = 0; x < MESH_WIDTH; x++) - { - /* Add 2 triangles per mesh quad... */ - if (dir == RIGHT) - { - i[0] = MESH_INDEX (x + 1, y); - i[1] = MESH_INDEX (x + 1, y + 1); - } - else - { - i[0] = MESH_INDEX (MESH_WIDTH - x - 1, y); - i[1] = MESH_INDEX (MESH_WIDTH - x - 1, y + 1); - } - i += 2; - } - - /* Link rows... */ - - if (y == (MESH_HEIGHT - 1)) - break; - - if (dir == RIGHT) - { - i[0] = MESH_INDEX (MESH_WIDTH, y + 1); - i[1] = MESH_INDEX (MESH_WIDTH, y + 1); - i[2] = MESH_INDEX (MESH_WIDTH, y + 2); - } - else - { - i[0] = MESH_INDEX (0, y + 1); - i[1] = MESH_INDEX (0, y + 1); - i[2] = MESH_INDEX (0, y + 2); - } - i += 3; - dir = !dir; - } - -#undef MESH_INDEX - - state->indices = - cogl_vertex_buffer_indices_new (COGL_INDICES_TYPE_UNSIGNED_SHORT, - state->static_indices, - state->n_static_indices); -} - -static float -gaussian (float x, float y) -{ - /* Bell width */ - float c = GAUSSIAN_RADIUS; - - /* Peak amplitude */ - float a = 1.0; - /* float a = 1.0 / (c * sqrtf (2.0 * G_PI)); */ - - /* Center offset */ - float b = 0.0; - - float dist; - x = x - RIPPLE_CENTER_X; - y = y - RIPPLE_CENTER_Y; - dist = sqrtf (x*x + y*y); - - return a * exp ((- ((dist - b) * (dist - b))) / (2.0 * c * c)); -} - -static void -init_quad_mesh (TestState *state) -{ - int x, y; - float *vert; - guint8 *color; - - /* Note: we maintain the minimum number of vertices possible. This minimizes - * the work required when we come to morph the geometry. - * - * We use static indices into our mesh so that we can treat the data like a - * single triangle list and drawing can be done in one operation (Note: We - * are using degenerate triangles at the edges to link to the next row) - */ - state->quad_mesh_verts = - g_malloc0 (sizeof (float) * 3 * (MESH_WIDTH + 1) * (MESH_HEIGHT + 1)); - - state->quad_mesh_colors = - g_malloc0 (sizeof (guint8) * 4 * (MESH_WIDTH + 1) * (MESH_HEIGHT + 1)); - - vert = state->quad_mesh_verts; - color = state->quad_mesh_colors; - for (y = 0; y <= MESH_HEIGHT; y++) - for (x = 0; x <= MESH_WIDTH; x++) - { - vert[0] = x * QUAD_WIDTH; - vert[1] = y * QUAD_HEIGHT; - vert += 3; - - color[3] = gaussian (x * QUAD_WIDTH, - y * QUAD_HEIGHT) * 255.0; - color += 4; - } - - state->buffer = cogl_vertex_buffer_new ((MESH_WIDTH + 1)*(MESH_HEIGHT + 1)); - cogl_vertex_buffer_add (state->buffer, - "gl_Vertex", - 3, /* n components */ - COGL_ATTRIBUTE_TYPE_FLOAT, - FALSE, /* normalized */ - 0, /* stride */ - state->quad_mesh_verts); - - cogl_vertex_buffer_add (state->buffer, - "gl_Color", - 4, /* n components */ - COGL_ATTRIBUTE_TYPE_UNSIGNED_BYTE, - FALSE, /* normalized */ - 0, /* stride */ - state->quad_mesh_colors); - - cogl_vertex_buffer_submit (state->buffer); - - init_static_index_arrays (state); -} - -/* This creates an actor that has a specific size but that does not result - * in any drawing so we can do our own drawing using Cogl... */ -static ClutterActor * -create_dummy_actor (guint width, guint height) -{ - ClutterActor *group, *rect; - ClutterColor clr = { 0xff, 0xff, 0xff, 0xff}; - - group = clutter_group_new (); - rect = clutter_rectangle_new_with_color (&clr); - clutter_actor_set_size (rect, width, height); - clutter_actor_hide (rect); - clutter_container_add_actor (CLUTTER_CONTAINER (group), rect); - return group; -} - -static void -stop_and_quit (ClutterActor *actor, - TestState *state) -{ - clutter_timeline_stop (state->timeline); - clutter_main_quit (); -} - -G_MODULE_EXPORT int -test_cogl_vertex_buffer_main (int argc, char *argv[]) -{ - TestState state; - ClutterActor *stage; - gfloat stage_w, stage_h; - gint dummy_width, dummy_height; - - if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS) - return 1; - - stage = clutter_stage_new (); - - clutter_stage_set_title (CLUTTER_STAGE (stage), "Cogl Vertex Buffers"); - clutter_stage_set_color (CLUTTER_STAGE (stage), CLUTTER_COLOR_Black); - g_signal_connect (stage, "destroy", G_CALLBACK (stop_and_quit), &state); - clutter_actor_get_size (stage, &stage_w, &stage_h); - - dummy_width = MESH_WIDTH * QUAD_WIDTH; - dummy_height = MESH_HEIGHT * QUAD_HEIGHT; - state.dummy = create_dummy_actor (dummy_width, dummy_height); - clutter_container_add_actor (CLUTTER_CONTAINER (stage), state.dummy); - clutter_actor_set_position (state.dummy, - (stage_w / 2.0) - (dummy_width / 2.0), - (stage_h / 2.0) - (dummy_height / 2.0)); - - state.timeline = clutter_timeline_new (1000); - clutter_timeline_set_loop (state.timeline, TRUE); - - state.frame_id = g_signal_connect (state.timeline, - "new-frame", - G_CALLBACK (frame_cb), - &state); - - g_signal_connect (state.dummy, "paint", G_CALLBACK (on_paint), &state); - - init_quad_mesh (&state); - - clutter_actor_show_all (stage); - - clutter_timeline_start (state.timeline); - - clutter_main (); - - cogl_object_unref (state.buffer); - cogl_object_unref (state.indices); - - return 0; -} - -G_MODULE_EXPORT const char * -test_cogl_vertex_buffer_describe (void) -{ - return "Vertex buffers support in Cogl."; -}