2009-01-20 21:12:44 +00:00
|
|
|
/*
|
2009-04-27 14:48:12 +00:00
|
|
|
* Cogl
|
2009-01-20 21:12:44 +00:00
|
|
|
*
|
2009-04-27 14:48:12 +00:00
|
|
|
* An object oriented GL/GLES Abstraction/Utility Layer
|
2009-01-20 21:12:44 +00:00
|
|
|
*
|
2010-10-12 11:55:23 +00:00
|
|
|
* Copyright (C) 2008,2009,2010 Intel Corporation.
|
2008-11-10 18:53:14 +00:00
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
2010-03-01 12:56:10 +00:00
|
|
|
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*
|
|
|
|
*
|
2009-04-27 14:48:12 +00:00
|
|
|
*
|
|
|
|
* Authors:
|
|
|
|
* Robert Bragg <robert@linux.intel.com>
|
2008-11-10 18:53:14 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
/* XXX: For an overview of the functionality implemented here, please
|
2009-01-20 21:12:44 +00:00
|
|
|
* see cogl-vertex-buffer.h, which contains the gtk-doc section overview
|
|
|
|
* for the Vertex Buffers API.
|
2008-11-10 18:53:14 +00:00
|
|
|
*/
|
|
|
|
|
2009-01-20 21:12:44 +00:00
|
|
|
/*
|
2008-11-10 18:53:14 +00:00
|
|
|
* TODO: We need to do a better job of minimizing when we call glVertexPointer
|
2009-02-06 16:10:28 +00:00
|
|
|
* and pals in enable_state_for_drawing_buffer
|
2009-01-20 21:12:44 +00:00
|
|
|
*
|
2008-11-10 18:53:14 +00:00
|
|
|
* 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:
|
2009-01-20 21:12:44 +00:00
|
|
|
* 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.
|
2008-11-10 18:53:14 +00:00
|
|
|
* 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)
|
2009-01-20 21:12:44 +00:00
|
|
|
* - 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.
|
|
|
|
*
|
2008-11-10 18:53:14 +00:00
|
|
|
* TODO
|
2009-01-20 21:12:44 +00:00
|
|
|
* Expose API that lets developers get back a buffer handle for a particular
|
2008-11-10 18:53:14 +00:00
|
|
|
* polygon so they may add custom attributes to them.
|
2009-01-20 21:12:44 +00:00
|
|
|
* - It should be possible to query/modify attributes efficiently, in place,
|
2008-11-10 18:53:14 +00:00
|
|
|
* avoiding copies. It would not be acceptable to simply require that
|
2009-01-20 21:12:44 +00:00
|
|
|
* developers must query back the n_vertices of a buffer and then the
|
|
|
|
* n_components, type and stride etc of each attribute since there
|
2008-11-10 18:53:14 +00:00
|
|
|
* would be too many combinations to realistically handle.
|
2009-01-20 21:12:44 +00:00
|
|
|
*
|
2008-11-10 18:53:14 +00:00
|
|
|
* - 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:
|
|
|
|
*
|
2009-01-20 21:12:44 +00:00
|
|
|
* cogl_vertex_buffer_foreach_vertex (buffer_handle,
|
|
|
|
* (AttributesBufferIteratorFunc)callback,
|
|
|
|
* "gl_Vertex", "gl_Color", NULL);
|
|
|
|
* static void callback (CoglVertexBufferVertex *vert)
|
2008-11-10 18:53:14 +00:00
|
|
|
* {
|
|
|
|
* GLfloat *pos = vert->attrib[0];
|
|
|
|
* GLubyte *color = vert->attrib[1];
|
|
|
|
* GLfloat *new_attrib = buf[vert->index];
|
2009-01-20 21:12:44 +00:00
|
|
|
*
|
2008-11-10 18:53:14 +00:00
|
|
|
* new_attrib = pos*color;
|
|
|
|
* }
|
|
|
|
*
|
|
|
|
* TODO
|
2009-01-20 21:12:44 +00:00
|
|
|
* 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.
|
2008-11-10 18:53:14 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include "config.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
2009-05-20 14:15:25 +00:00
|
|
|
#include <glib.h>
|
2008-11-10 18:53:14 +00:00
|
|
|
|
|
|
|
#include "cogl.h"
|
|
|
|
#include "cogl-internal.h"
|
|
|
|
#include "cogl-util.h"
|
2010-11-04 22:25:52 +00:00
|
|
|
#include "cogl-context-private.h"
|
2008-11-10 18:53:14 +00:00
|
|
|
#include "cogl-handle.h"
|
2009-01-20 21:12:44 +00:00
|
|
|
#include "cogl-vertex-buffer-private.h"
|
Fully integrates CoglMaterial throughout the rest of Cogl
This glues CoglMaterial in as the fundamental way that Cogl describes how to
fill in geometry.
It adds cogl_set_source (), which is used to set the material which will be
used by all subsequent drawing functions
It adds cogl_set_source_texture as a convenience for setting up a default
material with a single texture layer, and cogl_set_source_color is now also
a convenience for setting up a material with a solid fill.
"drawing functions" include, cogl_rectangle, cogl_texture_rectangle,
cogl_texture_multiple_rectangles, cogl_texture_polygon (though the
cogl_texture_* funcs have been renamed; see below for details),
cogl_path_fill/stroke and cogl_vertex_buffer_draw*.
cogl_texture_rectangle, cogl_texture_multiple_rectangles and
cogl_texture_polygon no longer take a texture handle; instead the current
source material is referenced. The functions have also been renamed to:
cogl_rectangle_with_texture_coords, cogl_rectangles_with_texture_coords
and cogl_polygon respectivly.
Most code that previously did:
cogl_texture_rectangle (tex_handle, x, y,...);
needs to be changed to now do:
cogl_set_source_texture (tex_handle);
cogl_rectangle_with_texture_coords (x, y,....);
In the less likely case where you were blending your source texture with a color
like:
cogl_set_source_color4ub (r,g,b,a); /* where r,g,b,a isn't just white */
cogl_texture_rectangle (tex_handle, x, y,...);
you will need your own material to do that:
mat = cogl_material_new ();
cogl_material_set_color4ub (r,g,b,a);
cogl_material_set_layer (mat, 0, tex_handle));
cogl_set_source_material (mat);
Code that uses the texture coordinates, 0, 0, 1, 1 don't need to use
cog_rectangle_with_texure_coords since these are the coordinates that
cogl_rectangle will use.
For cogl_texture_polygon; as well as dropping the texture handle, the
n_vertices and vertices arguments were transposed for consistency. So
code previously written as:
cogl_texture_polygon (tex_handle, 3, verts, TRUE);
need to be written as:
cogl_set_source_texture (tex_handle);
cogl_polygon (verts, 3, TRUE);
All of the unit tests have been updated to now use the material API and
test-cogl-material has been renamed to test-cogl-multitexture since any
textured quad is now technically a test of CoglMaterial but this test
specifically creates a material with multiple texture layers.
Note: The GLES backend has not been updated yet; that will be done in a
following commit.
2009-01-23 16:15:40 +00:00
|
|
|
#include "cogl-texture-private.h"
|
2010-10-27 17:54:57 +00:00
|
|
|
#include "cogl-pipeline.h"
|
|
|
|
#include "cogl-pipeline-private.h"
|
[cogl] Improving Cogl journal to minimize driver overheads + GPU state changes
Previously the journal was always flushed at the end of
_cogl_rectangles_with_multitexture_coords, (i.e. the end of any
cogl_rectangle* calls) but now we have broadened the potential for batching
geometry. In ideal circumstances we will only flush once per scene.
In summary the journal works like this:
When you use any of the cogl_rectangle* APIs then nothing is emitted to the
GPU at this point, we just log one or more quads into the journal. A
journal entry consists of the quad coordinates, an associated material
reference, and a modelview matrix. Ideally the journal only gets flushed
once at the end of a scene, but in fact there are things to consider that
may cause unwanted flushing, including:
- modifying materials mid-scene
This is because each quad in the journal has an associated material
reference (i.e. not copy), so if you try and modify a material that is
already referenced in the journal we force a flush first)
NOTE: For now this means you should avoid using cogl_set_source_color()
since that currently uses a single shared material. Later we
should change it to use a pool of materials that is recycled
when the journal is flushed.
- modifying any state that isn't currently logged, such as depth, fog and
backface culling enables.
The first thing that happens when flushing, is to upload all the vertex data
associated with the journal into a single VBO.
We then go through a process of splitting up the journal into batches that
have compatible state so they can be emitted to the GPU together. This is
currently broken up into 3 levels so we can stagger the state changes:
1) we break the journal up according to changes in the number of material layers
associated with logged quads. The number of layers in a material determines
the stride of the associated vertices, so we have to update our vertex
array offsets at this level. (i.e. calling gl{Vertex,Color},Pointer etc)
2) we further split batches up according to material compatability. (e.g.
materials with different textures) We flush material state at this level.
3) Finally we split batches up according to modelview changes. At this level
we update the modelview matrix and actually emit the actual draw command.
This commit is largely about putting the initial design in-place; this will be
followed by other changes that take advantage of the extended batching.
2009-06-17 17:46:42 +00:00
|
|
|
#include "cogl-primitives.h"
|
2009-11-26 19:06:35 +00:00
|
|
|
#include "cogl-framebuffer-private.h"
|
2010-02-10 18:18:30 +00:00
|
|
|
#include "cogl-journal-private.h"
|
2008-11-10 18:53:14 +00:00
|
|
|
|
|
|
|
#define PAD_FOR_ALIGNMENT(VAR, TYPE_SIZE) \
|
|
|
|
(VAR = TYPE_SIZE + ((VAR - 1) & ~(TYPE_SIZE - 1)))
|
|
|
|
|
2009-01-20 21:12:44 +00:00
|
|
|
static void _cogl_vertex_buffer_free (CoglVertexBuffer *buffer);
|
2009-05-28 11:49:29 +00:00
|
|
|
static void _cogl_vertex_buffer_indices_free (CoglVertexBufferIndices *buffer_indices);
|
2010-10-27 17:54:57 +00:00
|
|
|
static CoglUserDataKey _cogl_vertex_buffer_pipeline_priv_key;
|
2008-11-10 18:53:14 +00:00
|
|
|
|
2009-04-01 16:16:44 +00:00
|
|
|
COGL_HANDLE_DEFINE (VertexBuffer, vertex_buffer);
|
2010-07-09 16:59:16 +00:00
|
|
|
COGL_OBJECT_DEFINE_DEPRECATED_REF_COUNTING (vertex_buffer);
|
2009-05-28 11:49:29 +00:00
|
|
|
COGL_HANDLE_DEFINE (VertexBufferIndices, vertex_buffer_indices);
|
2008-11-10 18:53:14 +00:00
|
|
|
|
|
|
|
CoglHandle
|
cogl: improves header and coding style consistency
We've had complaints that our Cogl code/headers are a bit "special" so
this is a first pass at tidying things up by giving them some
consistency. These changes are all consistent with how new code in Cogl
is being written, but the style isn't consistently applied across all
code yet.
There are two parts to this patch; but since each one required a large
amount of effort to maintain tidy indenting it made sense to combine the
changes to reduce the time spent re indenting the same lines.
The first change is to use a consistent style for declaring function
prototypes in headers. Cogl headers now consistently use this style for
prototypes:
return_type
cogl_function_name (CoglType arg0,
CoglType arg1);
Not everyone likes this style, but it seems that most of the currently
active Cogl developers agree on it.
The second change is to constrain the use of redundant glib data types
in Cogl. Uses of gint, guint, gfloat, glong, gulong and gchar have all
been replaced with int, unsigned int, float, long, unsigned long and char
respectively. When talking about pixel data; use of guchar has been
replaced with guint8, otherwise unsigned char can be used.
The glib types that we continue to use for portability are gboolean,
gint{8,16,32,64}, guint{8,16,32,64} and gsize.
The general intention is that Cogl should look palatable to the widest
range of C programmers including those outside the Gnome community so
- especially for the public API - we want to minimize the number of
foreign looking typedefs.
2010-02-10 01:57:32 +00:00
|
|
|
cogl_vertex_buffer_new (unsigned int n_vertices)
|
2008-11-10 18:53:14 +00:00
|
|
|
{
|
2009-01-20 21:12:44 +00:00
|
|
|
CoglVertexBuffer *buffer = g_slice_alloc (sizeof (CoglVertexBuffer));
|
|
|
|
|
|
|
|
buffer->n_vertices = n_vertices;
|
2008-11-10 18:53:14 +00:00
|
|
|
|
2009-01-20 21:12:44 +00:00
|
|
|
buffer->submitted_vbos = NULL;
|
|
|
|
buffer->new_attributes = NULL;
|
2010-10-12 11:55:23 +00:00
|
|
|
buffer->primitive = cogl_primitive_new (COGL_VERTICES_MODE_TRIANGLES,
|
|
|
|
n_vertices, NULL);
|
2008-11-10 18:53:14 +00:00
|
|
|
|
|
|
|
/* return COGL_INVALID_HANDLE; */
|
2009-01-20 21:12:44 +00:00
|
|
|
return _cogl_vertex_buffer_handle_new (buffer);
|
2008-11-10 18:53:14 +00:00
|
|
|
}
|
|
|
|
|
cogl: improves header and coding style consistency
We've had complaints that our Cogl code/headers are a bit "special" so
this is a first pass at tidying things up by giving them some
consistency. These changes are all consistent with how new code in Cogl
is being written, but the style isn't consistently applied across all
code yet.
There are two parts to this patch; but since each one required a large
amount of effort to maintain tidy indenting it made sense to combine the
changes to reduce the time spent re indenting the same lines.
The first change is to use a consistent style for declaring function
prototypes in headers. Cogl headers now consistently use this style for
prototypes:
return_type
cogl_function_name (CoglType arg0,
CoglType arg1);
Not everyone likes this style, but it seems that most of the currently
active Cogl developers agree on it.
The second change is to constrain the use of redundant glib data types
in Cogl. Uses of gint, guint, gfloat, glong, gulong and gchar have all
been replaced with int, unsigned int, float, long, unsigned long and char
respectively. When talking about pixel data; use of guchar has been
replaced with guint8, otherwise unsigned char can be used.
The glib types that we continue to use for portability are gboolean,
gint{8,16,32,64}, guint{8,16,32,64} and gsize.
The general intention is that Cogl should look palatable to the widest
range of C programmers including those outside the Gnome community so
- especially for the public API - we want to minimize the number of
foreign looking typedefs.
2010-02-10 01:57:32 +00:00
|
|
|
unsigned int
|
2009-02-28 17:39:38 +00:00
|
|
|
cogl_vertex_buffer_get_n_vertices (CoglHandle handle)
|
|
|
|
{
|
|
|
|
CoglVertexBuffer *buffer;
|
|
|
|
|
|
|
|
if (!cogl_is_vertex_buffer (handle))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
buffer = _cogl_vertex_buffer_pointer_from_handle (handle);
|
|
|
|
|
|
|
|
return buffer->n_vertices;
|
|
|
|
}
|
|
|
|
|
2008-11-10 18:53:14 +00:00
|
|
|
/* 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.
|
|
|
|
*/
|
2009-01-20 21:12:44 +00:00
|
|
|
static CoglVertexBufferAttribFlags
|
2008-11-10 18:53:14 +00:00
|
|
|
validate_gl_attribute (const char *gl_attribute,
|
2009-09-24 16:34:26 +00:00
|
|
|
guint8 n_components,
|
2008-11-10 18:53:14 +00:00
|
|
|
guint8 *texture_unit)
|
|
|
|
{
|
2009-01-20 21:12:44 +00:00
|
|
|
CoglVertexBufferAttribFlags type;
|
2008-11-10 18:53:14 +00:00
|
|
|
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)
|
|
|
|
{
|
2009-09-24 16:34:26 +00:00
|
|
|
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");
|
2009-01-20 21:12:44 +00:00
|
|
|
type = COGL_VERTEX_BUFFER_ATTRIB_FLAG_VERTEX_ARRAY;
|
2008-11-10 18:53:14 +00:00
|
|
|
}
|
|
|
|
else if (strncmp (gl_attribute, "Color", name_len) == 0)
|
|
|
|
{
|
2009-09-24 16:34:26 +00:00
|
|
|
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");
|
2009-01-20 21:12:44 +00:00
|
|
|
type = COGL_VERTEX_BUFFER_ATTRIB_FLAG_COLOR_ARRAY;
|
2008-11-10 18:53:14 +00:00
|
|
|
}
|
|
|
|
else if (strncmp (gl_attribute,
|
|
|
|
"MultiTexCoord",
|
|
|
|
strlen ("MultiTexCoord")) == 0)
|
|
|
|
{
|
|
|
|
unsigned int unit;
|
2009-01-20 21:12:44 +00:00
|
|
|
|
2008-11-10 18:53:14 +00:00
|
|
|
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;
|
2009-01-20 21:12:44 +00:00
|
|
|
type = COGL_VERTEX_BUFFER_ATTRIB_FLAG_TEXTURE_COORD_ARRAY;
|
2008-11-10 18:53:14 +00:00
|
|
|
}
|
|
|
|
else if (strncmp (gl_attribute, "Normal", name_len) == 0)
|
|
|
|
{
|
2009-09-24 16:34:26 +00:00
|
|
|
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");
|
2009-01-20 21:12:44 +00:00
|
|
|
type = COGL_VERTEX_BUFFER_ATTRIB_FLAG_NORMAL_ARRAY;
|
2008-11-10 18:53:14 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
g_warning ("Unknown gl_* attribute name gl_%s\n", gl_attribute);
|
2009-01-20 21:12:44 +00:00
|
|
|
type = COGL_VERTEX_BUFFER_ATTRIB_FLAG_INVALID;
|
2008-11-10 18:53:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return type;
|
|
|
|
}
|
|
|
|
|
2010-07-23 16:46:41 +00:00
|
|
|
/* 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,
|
|
|
|
guint8 n_components,
|
|
|
|
guint8 *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;
|
|
|
|
}
|
|
|
|
|
2008-11-10 18:53:14 +00:00
|
|
|
/* 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.
|
2009-01-20 21:12:44 +00:00
|
|
|
* custom_attrib::foo or custom_attrib::bar
|
2008-11-10 18:53:14 +00:00
|
|
|
*
|
|
|
|
* 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);
|
|
|
|
|
2008-11-18 16:24:31 +00:00
|
|
|
if (name_len == 0
|
|
|
|
|| !g_ascii_isalpha (attribute_name[0])
|
|
|
|
|| attribute_name[0] != '_')
|
2008-11-10 18:53:14 +00:00
|
|
|
return FALSE;
|
2009-01-20 21:12:44 +00:00
|
|
|
|
2008-11-10 18:53:14 +00:00
|
|
|
for (i = 1; i < name_len; i++)
|
2008-11-18 16:24:31 +00:00
|
|
|
if (!g_ascii_isalnum (attribute_name[i]) || attribute_name[i] != '_')
|
2008-11-10 18:53:14 +00:00
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2009-01-20 21:12:44 +00:00
|
|
|
/* Iterates the CoglVertexBufferVBOs of a buffer and creates a flat list
|
|
|
|
* of all the submitted attributes
|
2008-11-10 18:53:14 +00:00
|
|
|
*
|
2010-10-12 11:55:23 +00:00
|
|
|
* Note: The CoglVertexBufferAttrib structs are deep copied, except the
|
2011-01-20 19:31:53 +00:00
|
|
|
* internal CoglAttribute pointer is set to NULL.
|
2008-11-10 18:53:14 +00:00
|
|
|
*/
|
|
|
|
static GList *
|
2009-01-20 21:12:44 +00:00
|
|
|
copy_submitted_attributes_list (CoglVertexBuffer *buffer)
|
2008-11-10 18:53:14 +00:00
|
|
|
{
|
|
|
|
GList *tmp;
|
|
|
|
GList *submitted_attributes = NULL;
|
|
|
|
|
2009-01-20 21:12:44 +00:00
|
|
|
for (tmp = buffer->submitted_vbos; tmp != NULL; tmp = tmp->next)
|
2008-11-10 18:53:14 +00:00
|
|
|
{
|
2009-01-20 21:12:44 +00:00
|
|
|
CoglVertexBufferVBO *cogl_vbo = tmp->data;
|
2008-11-10 18:53:14 +00:00
|
|
|
GList *tmp2;
|
2009-01-20 21:12:44 +00:00
|
|
|
|
2008-11-10 18:53:14 +00:00
|
|
|
for (tmp2 = cogl_vbo->attributes; tmp2 != NULL; tmp2 = tmp2->next)
|
|
|
|
{
|
2009-01-20 21:12:44 +00:00
|
|
|
CoglVertexBufferAttrib *attribute = tmp2->data;
|
|
|
|
CoglVertexBufferAttrib *copy =
|
|
|
|
g_slice_alloc (sizeof (CoglVertexBufferAttrib));
|
2008-11-10 18:53:14 +00:00
|
|
|
*copy = *attribute;
|
2010-10-12 11:55:23 +00:00
|
|
|
copy->name_without_detail =
|
|
|
|
g_strdup (attribute->name_without_detail);
|
|
|
|
copy->attribute = NULL;
|
2008-11-10 18:53:14 +00:00
|
|
|
submitted_attributes = g_list_prepend (submitted_attributes, copy);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return submitted_attributes;
|
|
|
|
}
|
|
|
|
|
2010-10-12 11:55:23 +00:00
|
|
|
static size_t
|
|
|
|
sizeof_attribute_type (CoglAttributeType type)
|
2008-11-10 18:53:14 +00:00
|
|
|
{
|
2010-10-12 11:55:23 +00:00
|
|
|
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);
|
2008-11-10 18:53:14 +00:00
|
|
|
}
|
|
|
|
|
2010-10-12 11:55:23 +00:00
|
|
|
static size_t
|
|
|
|
strideof (CoglAttributeType type, int n_components)
|
2008-11-10 18:53:14 +00:00
|
|
|
{
|
2010-10-12 11:55:23 +00:00
|
|
|
return sizeof_attribute_type (type) * n_components;
|
|
|
|
}
|
2008-11-10 18:53:14 +00:00
|
|
|
|
2010-10-12 11:55:23 +00:00
|
|
|
static char *
|
|
|
|
canonize_attribute_name (const char *attribute_name)
|
|
|
|
{
|
|
|
|
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
|
2008-11-10 18:53:14 +00:00
|
|
|
{
|
2010-10-12 11:55:23 +00:00
|
|
|
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);
|
2008-11-10 18:53:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2009-05-24 10:33:29 +00:00
|
|
|
cogl_vertex_buffer_add (CoglHandle handle,
|
|
|
|
const char *attribute_name,
|
|
|
|
guint8 n_components,
|
|
|
|
CoglAttributeType type,
|
|
|
|
gboolean normalized,
|
|
|
|
guint16 stride,
|
|
|
|
const void *pointer)
|
2008-11-10 18:53:14 +00:00
|
|
|
{
|
2009-01-20 21:12:44 +00:00
|
|
|
CoglVertexBuffer *buffer;
|
2010-10-12 11:55:23 +00:00
|
|
|
char *cogl_attribute_name;
|
|
|
|
GQuark name_quark;
|
2008-11-10 18:53:14 +00:00
|
|
|
gboolean modifying_an_attrib = FALSE;
|
2009-01-20 21:12:44 +00:00
|
|
|
CoglVertexBufferAttrib *attribute;
|
|
|
|
CoglVertexBufferAttribFlags flags = 0;
|
2008-11-10 18:53:14 +00:00
|
|
|
guint8 texture_unit = 0;
|
|
|
|
GList *tmp;
|
2010-10-12 11:55:23 +00:00
|
|
|
char *detail;
|
2008-11-10 18:53:14 +00:00
|
|
|
|
2009-01-20 21:12:44 +00:00
|
|
|
if (!cogl_is_vertex_buffer (handle))
|
2008-11-10 18:53:14 +00:00
|
|
|
return;
|
|
|
|
|
2009-01-20 21:12:44 +00:00
|
|
|
buffer = _cogl_vertex_buffer_pointer_from_handle (handle);
|
2010-10-12 11:55:23 +00:00
|
|
|
buffer->dirty_attributes = TRUE;
|
|
|
|
|
|
|
|
cogl_attribute_name = canonize_attribute_name (attribute_name);
|
|
|
|
name_quark = g_quark_from_string (cogl_attribute_name);
|
2008-11-10 18:53:14 +00:00
|
|
|
|
|
|
|
/* 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: */
|
2009-01-20 21:12:44 +00:00
|
|
|
if (!buffer->new_attributes)
|
|
|
|
buffer->new_attributes = copy_submitted_attributes_list (buffer);
|
|
|
|
|
2008-11-10 18:53:14 +00:00
|
|
|
/* Note: we first look for an existing attribute that we are modifying
|
|
|
|
* so we may skip needing to validate the name */
|
2009-01-20 21:12:44 +00:00
|
|
|
for (tmp = buffer->new_attributes; tmp != NULL; tmp = tmp->next)
|
2008-11-10 18:53:14 +00:00
|
|
|
{
|
2009-01-20 21:12:44 +00:00
|
|
|
CoglVertexBufferAttrib *submitted_attribute = tmp->data;
|
2008-11-10 18:53:14 +00:00
|
|
|
if (submitted_attribute->name == name_quark)
|
|
|
|
{
|
|
|
|
modifying_an_attrib = TRUE;
|
|
|
|
|
|
|
|
attribute = submitted_attribute;
|
|
|
|
|
2010-07-23 16:46:41 +00:00
|
|
|
/* since we will skip validate_gl/cogl_attribute in this case, we
|
|
|
|
* need to pluck out the attribute type before overwriting the
|
|
|
|
* flags: */
|
2009-01-20 21:12:44 +00:00
|
|
|
flags |=
|
|
|
|
attribute->flags & COGL_VERTEX_BUFFER_ATTRIB_FLAG_TYPE_MASK;
|
2008-11-10 18:53:14 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!modifying_an_attrib)
|
|
|
|
{
|
|
|
|
/* Validate the attribute name, is suitable as a variable name */
|
|
|
|
if (strncmp (attribute_name, "gl_", 3) == 0)
|
|
|
|
{
|
2010-10-12 11:55:23 +00:00
|
|
|
/* Note: we pass the original attribute name here so that
|
|
|
|
* any warning messages correspond to the users original
|
|
|
|
* attribute name... */
|
2008-11-10 18:53:14 +00:00
|
|
|
flags |= validate_gl_attribute (attribute_name + 3,
|
2009-09-24 16:34:26 +00:00
|
|
|
n_components,
|
|
|
|
&texture_unit);
|
2009-01-20 21:12:44 +00:00
|
|
|
if (flags & COGL_VERTEX_BUFFER_ATTRIB_FLAG_INVALID)
|
2008-11-10 18:53:14 +00:00
|
|
|
return;
|
|
|
|
}
|
2010-07-23 16:46:41 +00:00
|
|
|
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;
|
|
|
|
}
|
2008-11-10 18:53:14 +00:00
|
|
|
else
|
|
|
|
{
|
2009-01-20 21:12:44 +00:00
|
|
|
flags |= COGL_VERTEX_BUFFER_ATTRIB_FLAG_CUSTOM_ARRAY;
|
2008-11-10 18:53:14 +00:00
|
|
|
if (validate_custom_attribute_name (attribute_name))
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-10-12 11:55:23 +00:00
|
|
|
attribute = g_slice_alloc0 (sizeof (CoglVertexBufferAttrib));
|
2008-11-10 18:53:14 +00:00
|
|
|
}
|
|
|
|
|
2010-10-12 11:55:23 +00:00
|
|
|
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;
|
2008-11-10 18:53:14 +00:00
|
|
|
attribute->n_components = n_components;
|
2010-10-12 11:55:23 +00:00
|
|
|
if (stride == 0)
|
|
|
|
stride = strideof (type, n_components);
|
|
|
|
attribute->stride = stride;
|
2008-11-10 18:53:14 +00:00
|
|
|
attribute->u.pointer = pointer;
|
|
|
|
attribute->texture_unit = texture_unit;
|
2010-10-12 11:55:23 +00:00
|
|
|
attribute->attribute = NULL;
|
2008-11-10 18:53:14 +00:00
|
|
|
|
2009-01-20 21:12:44 +00:00
|
|
|
flags |= COGL_VERTEX_BUFFER_ATTRIB_FLAG_ENABLED;
|
2008-11-10 18:53:14 +00:00
|
|
|
|
|
|
|
/* Note: We currently just assume, if an attribute is *ever* updated
|
|
|
|
* then it should be taged as frequently changing. */
|
|
|
|
if (modifying_an_attrib)
|
2009-01-20 21:12:44 +00:00
|
|
|
flags |= COGL_VERTEX_BUFFER_ATTRIB_FLAG_FREQUENT_RESUBMIT;
|
2008-11-10 18:53:14 +00:00
|
|
|
else
|
2009-01-20 21:12:44 +00:00
|
|
|
flags |= COGL_VERTEX_BUFFER_ATTRIB_FLAG_INFREQUENT_RESUBMIT;
|
2008-11-10 18:53:14 +00:00
|
|
|
|
|
|
|
if (normalized)
|
2009-01-20 21:12:44 +00:00
|
|
|
flags |= COGL_VERTEX_BUFFER_ATTRIB_FLAG_NORMALIZED;
|
2008-11-10 18:53:14 +00:00
|
|
|
attribute->flags = flags;
|
2009-01-20 21:12:44 +00:00
|
|
|
|
2010-10-12 11:55:23 +00:00
|
|
|
attribute->span_bytes = buffer->n_vertices * attribute->stride;
|
2008-11-10 18:53:14 +00:00
|
|
|
|
|
|
|
if (!modifying_an_attrib)
|
2009-01-20 21:12:44 +00:00
|
|
|
buffer->new_attributes =
|
|
|
|
g_list_prepend (buffer->new_attributes, attribute);
|
2010-10-12 11:55:23 +00:00
|
|
|
|
|
|
|
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);
|
2008-11-10 18:53:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2009-01-20 21:12:44 +00:00
|
|
|
cogl_vertex_buffer_delete (CoglHandle handle,
|
|
|
|
const char *attribute_name)
|
2008-11-10 18:53:14 +00:00
|
|
|
{
|
2009-01-20 21:12:44 +00:00
|
|
|
CoglVertexBuffer *buffer;
|
2010-10-12 11:55:23 +00:00
|
|
|
char *cogl_attribute_name = canonize_attribute_name (attribute_name);
|
|
|
|
GQuark name = g_quark_from_string (cogl_attribute_name);
|
2008-11-10 18:53:14 +00:00
|
|
|
GList *tmp;
|
|
|
|
|
2010-10-12 11:55:23 +00:00
|
|
|
g_free (cogl_attribute_name);
|
|
|
|
|
2009-01-20 21:12:44 +00:00
|
|
|
if (!cogl_is_vertex_buffer (handle))
|
2008-11-10 18:53:14 +00:00
|
|
|
return;
|
|
|
|
|
2009-01-20 21:12:44 +00:00
|
|
|
buffer = _cogl_vertex_buffer_pointer_from_handle (handle);
|
2010-10-12 11:55:23 +00:00
|
|
|
buffer->dirty_attributes = TRUE;
|
2008-11-10 18:53:14 +00:00
|
|
|
|
|
|
|
/* 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: */
|
2009-01-20 21:12:44 +00:00
|
|
|
if (!buffer->new_attributes)
|
|
|
|
buffer->new_attributes = copy_submitted_attributes_list (buffer);
|
|
|
|
|
|
|
|
for (tmp = buffer->new_attributes; tmp != NULL; tmp = tmp->next)
|
2008-11-10 18:53:14 +00:00
|
|
|
{
|
2009-01-20 21:12:44 +00:00
|
|
|
CoglVertexBufferAttrib *submitted_attribute = tmp->data;
|
2008-11-10 18:53:14 +00:00
|
|
|
if (submitted_attribute->name == name)
|
|
|
|
{
|
2009-01-20 21:12:44 +00:00
|
|
|
buffer->new_attributes =
|
|
|
|
g_list_delete_link (buffer->new_attributes, tmp);
|
2010-10-12 11:55:23 +00:00
|
|
|
_cogl_vertex_buffer_attrib_free (submitted_attribute);
|
2008-11-10 18:53:14 +00:00
|
|
|
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)
|
|
|
|
{
|
2009-01-20 21:12:44 +00:00
|
|
|
CoglVertexBuffer *buffer;
|
2010-10-12 11:55:23 +00:00
|
|
|
char *cogl_attribute_name = canonize_attribute_name (attribute_name);
|
|
|
|
GQuark name_quark = g_quark_from_string (cogl_attribute_name);
|
2008-11-10 18:53:14 +00:00
|
|
|
GList *tmp;
|
|
|
|
|
2010-10-12 11:55:23 +00:00
|
|
|
g_free (cogl_attribute_name);
|
|
|
|
|
2009-01-20 21:12:44 +00:00
|
|
|
if (!cogl_is_vertex_buffer (handle))
|
2008-11-10 18:53:14 +00:00
|
|
|
return;
|
|
|
|
|
2009-01-20 21:12:44 +00:00
|
|
|
buffer = _cogl_vertex_buffer_pointer_from_handle (handle);
|
2010-10-12 11:55:23 +00:00
|
|
|
buffer->dirty_attributes = TRUE;
|
2008-11-10 18:53:14 +00:00
|
|
|
|
2009-01-20 21:12:44 +00:00
|
|
|
/* 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)
|
2008-11-10 18:53:14 +00:00
|
|
|
{
|
2009-01-20 21:12:44 +00:00
|
|
|
CoglVertexBufferAttrib *attribute = tmp->data;
|
2008-11-10 18:53:14 +00:00
|
|
|
if (attribute->name == name_quark)
|
|
|
|
{
|
|
|
|
if (state)
|
2009-01-20 21:12:44 +00:00
|
|
|
attribute->flags |= COGL_VERTEX_BUFFER_ATTRIB_FLAG_ENABLED;
|
2008-11-10 18:53:14 +00:00
|
|
|
else
|
2009-01-20 21:12:44 +00:00
|
|
|
attribute->flags &= ~COGL_VERTEX_BUFFER_ATTRIB_FLAG_ENABLED;
|
2008-11-10 18:53:14 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2009-01-20 21:12:44 +00:00
|
|
|
|
|
|
|
for (tmp = buffer->submitted_vbos; tmp != NULL; tmp = tmp->next)
|
2008-11-10 18:53:14 +00:00
|
|
|
{
|
2009-01-20 21:12:44 +00:00
|
|
|
CoglVertexBufferVBO *cogl_vbo = tmp->data;
|
2008-11-10 18:53:14 +00:00
|
|
|
GList *tmp2;
|
|
|
|
|
|
|
|
for (tmp2 = cogl_vbo->attributes; tmp2 != NULL; tmp2 = tmp2->next)
|
|
|
|
{
|
2009-01-20 21:12:44 +00:00
|
|
|
CoglVertexBufferAttrib *attribute = tmp2->data;
|
2008-11-10 18:53:14 +00:00
|
|
|
if (attribute->name == name_quark)
|
|
|
|
{
|
|
|
|
if (state)
|
2009-01-20 21:12:44 +00:00
|
|
|
attribute->flags |= COGL_VERTEX_BUFFER_ATTRIB_FLAG_ENABLED;
|
2008-11-10 18:53:14 +00:00
|
|
|
else
|
2009-01-20 21:12:44 +00:00
|
|
|
attribute->flags &= ~COGL_VERTEX_BUFFER_ATTRIB_FLAG_ENABLED;
|
2008-11-10 18:53:14 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-10-12 11:55:23 +00:00
|
|
|
g_warning ("Failed to %s attribute named %s/%s\n",
|
|
|
|
state == TRUE ? "enable" : "disable",
|
|
|
|
attribute_name, cogl_attribute_name);
|
2008-11-10 18:53:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2009-01-20 21:12:44 +00:00
|
|
|
cogl_vertex_buffer_enable (CoglHandle handle,
|
|
|
|
const char *attribute_name)
|
2008-11-10 18:53:14 +00:00
|
|
|
{
|
|
|
|
set_attribute_enable (handle, attribute_name, TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2009-01-20 21:12:44 +00:00
|
|
|
cogl_vertex_buffer_disable (CoglHandle handle,
|
|
|
|
const char *attribute_name)
|
2008-11-10 18:53:14 +00:00
|
|
|
{
|
|
|
|
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
|
2009-01-20 21:12:44 +00:00
|
|
|
filter_already_submitted_attribute (CoglVertexBufferAttrib *attribute,
|
2008-11-10 18:53:14 +00:00
|
|
|
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)
|
|
|
|
{
|
2009-01-20 21:12:44 +00:00
|
|
|
CoglVertexBufferVBO *cogl_vbo = tmp->data;
|
2008-11-10 18:53:14 +00:00
|
|
|
GList *tmp2;
|
|
|
|
|
|
|
|
for (tmp2 = cogl_vbo->attributes; tmp2 != NULL; tmp2 = tmp2->next)
|
|
|
|
{
|
2009-01-20 21:12:44 +00:00
|
|
|
CoglVertexBufferAttrib *vbo_attribute = tmp2->data;
|
2008-11-10 18:53:14 +00:00
|
|
|
|
|
|
|
if (vbo_attribute->name == attribute->name)
|
|
|
|
{
|
2009-01-20 21:12:44 +00:00
|
|
|
vbo_attribute->flags &=
|
|
|
|
~COGL_VERTEX_BUFFER_ATTRIB_FLAG_UNUSED;
|
2008-11-10 18:53:14 +00:00
|
|
|
/* Note: we don't free the redundant attribute here, since it
|
2009-01-20 21:12:44 +00:00
|
|
|
* will be freed after all filtering in
|
|
|
|
* cogl_vertex_buffer_submit */
|
2008-11-10 18:53:14 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2009-01-20 21:12:44 +00:00
|
|
|
|
2008-11-10 18:53:14 +00:00
|
|
|
for (tmp = *submitted_vbos; tmp != NULL; tmp = tmp->next)
|
|
|
|
{
|
2009-01-20 21:12:44 +00:00
|
|
|
CoglVertexBufferVBO *cogl_vbo = tmp->data;
|
|
|
|
CoglVertexBufferAttrib *reuse_attribute = NULL;
|
2008-11-10 18:53:14 +00:00
|
|
|
GList *tmp2;
|
|
|
|
|
|
|
|
for (tmp2 = cogl_vbo->attributes; tmp2 != NULL; tmp2 = tmp2->next)
|
|
|
|
{
|
2009-01-20 21:12:44 +00:00
|
|
|
CoglVertexBufferAttrib *vbo_attribute = tmp2->data;
|
2008-11-10 18:53:14 +00:00
|
|
|
if (vbo_attribute->name == attribute->name)
|
|
|
|
{
|
|
|
|
reuse_attribute = vbo_attribute;
|
|
|
|
/* Note: we don't free the redundant attribute here, since it
|
2009-01-20 21:12:44 +00:00
|
|
|
* will be freed after all filtering in
|
|
|
|
* cogl_vertex_buffer_submit */
|
|
|
|
|
2008-11-10 18:53:14 +00:00
|
|
|
*submitted_vbos = g_list_remove_link (*submitted_vbos, tmp);
|
|
|
|
tmp->next = *reuse_vbos;
|
|
|
|
*reuse_vbos = tmp;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!reuse_attribute)
|
|
|
|
continue;
|
2009-01-20 21:12:44 +00:00
|
|
|
|
2008-11-10 18:53:14 +00:00
|
|
|
/* Mark all but the matched attribute as UNUSED, so that when we
|
|
|
|
* finish filtering all our attributes any attrributes still
|
2010-11-25 18:13:51 +00:00
|
|
|
* marked as UNUSED can be removed from their cogl_vbo */
|
2008-11-10 18:53:14 +00:00
|
|
|
for (tmp2 = cogl_vbo->attributes; tmp2 != NULL; tmp2 = tmp2->next)
|
|
|
|
{
|
2009-01-20 21:12:44 +00:00
|
|
|
CoglVertexBufferAttrib *vbo_attribute = tmp2->data;
|
|
|
|
if (vbo_attribute != reuse_attribute)
|
|
|
|
vbo_attribute->flags |= COGL_VERTEX_BUFFER_ATTRIB_FLAG_UNUSED;
|
2008-11-10 18:53:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_critical ("Failed to find the cogl vbo that corresponds to an\n"
|
|
|
|
"attribute that had apparently already been submitted!");
|
|
|
|
}
|
|
|
|
|
2009-01-20 21:12:44 +00:00
|
|
|
/* 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
|
2008-11-10 18:53:14 +00:00
|
|
|
* we can then prune the now unsed attributes. */
|
|
|
|
static void
|
2009-01-20 21:12:44 +00:00
|
|
|
remove_unused_attributes (CoglVertexBufferVBO *cogl_vbo)
|
2008-11-10 18:53:14 +00:00
|
|
|
{
|
|
|
|
GList *tmp;
|
|
|
|
GList *next;
|
|
|
|
|
|
|
|
for (tmp = cogl_vbo->attributes; tmp != NULL; tmp = next)
|
|
|
|
{
|
2009-01-20 21:12:44 +00:00
|
|
|
CoglVertexBufferAttrib *attribute = tmp->data;
|
2008-11-10 18:53:14 +00:00
|
|
|
next = tmp->next;
|
|
|
|
|
2009-01-20 21:12:44 +00:00
|
|
|
if (attribute->flags & COGL_VERTEX_BUFFER_ATTRIB_FLAG_UNUSED)
|
2008-11-10 18:53:14 +00:00
|
|
|
{
|
|
|
|
cogl_vbo->attributes =
|
|
|
|
g_list_delete_link (cogl_vbo->attributes, tmp);
|
2009-01-20 21:12:44 +00:00
|
|
|
g_slice_free (CoglVertexBufferAttrib, attribute);
|
2008-11-10 18:53:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Give a newly added, strided, attribute, this function looks for a
|
2009-01-20 21:12:44 +00:00
|
|
|
* 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.
|
2008-11-10 18:53:14 +00:00
|
|
|
*/
|
|
|
|
static void
|
2009-01-20 21:12:44 +00:00
|
|
|
filter_strided_attribute (CoglVertexBufferAttrib *attribute,
|
2008-11-10 18:53:14 +00:00
|
|
|
GList **new_vbos)
|
|
|
|
{
|
|
|
|
GList *tmp;
|
2009-01-20 21:12:44 +00:00
|
|
|
CoglVertexBufferVBO *new_cogl_vbo;
|
2008-11-10 18:53:14 +00:00
|
|
|
|
|
|
|
for (tmp = *new_vbos; tmp != NULL; tmp = tmp->next)
|
|
|
|
{
|
2009-01-20 21:12:44 +00:00
|
|
|
CoglVertexBufferVBO *cogl_vbo = tmp->data;
|
2008-11-10 18:53:14 +00:00
|
|
|
GList *tmp2;
|
2009-01-20 21:12:44 +00:00
|
|
|
|
2009-06-05 14:18:43 +00:00
|
|
|
if (!(cogl_vbo->flags & COGL_VERTEX_BUFFER_VBO_FLAG_STRIDED))
|
2008-11-10 18:53:14 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
for (tmp2 = cogl_vbo->attributes; tmp2 != NULL; tmp2 = tmp2->next)
|
|
|
|
{
|
2009-01-20 21:12:44 +00:00
|
|
|
CoglVertexBufferAttrib *vbo_attribute = tmp2->data;
|
2008-11-10 18:53:14 +00:00
|
|
|
const char *attribute_start = attribute->u.pointer;
|
|
|
|
const char *vbo_attribute_start = vbo_attribute->u.pointer;
|
|
|
|
|
2009-01-20 21:12:44 +00:00
|
|
|
/* NB: All attributes have buffer->n_vertices values which
|
2008-11-10 18:53:14 +00:00
|
|
|
* 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);
|
|
|
|
|
2009-01-20 21:12:44 +00:00
|
|
|
if (attribute->flags &
|
|
|
|
COGL_VERTEX_BUFFER_ATTRIB_FLAG_FREQUENT_RESUBMIT)
|
2008-11-10 18:53:14 +00:00
|
|
|
{
|
2009-01-20 21:12:44 +00:00
|
|
|
cogl_vbo->flags &=
|
|
|
|
~COGL_VERTEX_BUFFER_VBO_FLAG_INFREQUENT_RESUBMIT;
|
|
|
|
cogl_vbo->flags |=
|
|
|
|
COGL_VERTEX_BUFFER_VBO_FLAG_FREQUENT_RESUBMIT;
|
2008-11-10 18:53:14 +00:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2009-01-20 21:12:44 +00:00
|
|
|
new_cogl_vbo = g_slice_alloc (sizeof (CoglVertexBufferVBO));
|
2008-11-10 18:53:14 +00:00
|
|
|
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 */
|
2010-10-12 11:55:23 +00:00
|
|
|
new_cogl_vbo->array = NULL;
|
|
|
|
new_cogl_vbo->array_bytes = attribute->span_bytes;
|
2009-01-20 21:12:44 +00:00
|
|
|
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;
|
2008-11-10 18:53:14 +00:00
|
|
|
else
|
2009-01-20 21:12:44 +00:00
|
|
|
new_cogl_vbo->flags |= COGL_VERTEX_BUFFER_VBO_FLAG_FREQUENT_RESUBMIT;
|
2008-11-10 18:53:14 +00:00
|
|
|
|
|
|
|
*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,
|
2009-01-20 21:12:44 +00:00
|
|
|
CoglVertexBufferAttrib *attribute)
|
2008-11-10 18:53:14 +00:00
|
|
|
{
|
|
|
|
GList *tmp;
|
|
|
|
GList *next = NULL;
|
|
|
|
|
|
|
|
for (tmp = *submitted_vbos; tmp != NULL; tmp = next)
|
|
|
|
{
|
2009-01-20 21:12:44 +00:00
|
|
|
CoglVertexBufferVBO *submitted_vbo = tmp->data;
|
2008-11-10 18:53:14 +00:00
|
|
|
GList *tmp2;
|
|
|
|
|
|
|
|
next = tmp->next;
|
|
|
|
|
|
|
|
for (tmp2 = submitted_vbo->attributes; tmp2 != NULL; tmp2 = tmp2->next)
|
|
|
|
{
|
2009-01-20 21:12:44 +00:00
|
|
|
CoglVertexBufferAttrib *submitted_attribute = tmp2->data;
|
2008-11-10 18:53:14 +00:00
|
|
|
|
|
|
|
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 *
|
2009-01-20 21:12:44 +00:00
|
|
|
get_submitted_vbo_conflicts (GList **submitted_vbos,
|
|
|
|
CoglVertexBufferVBO *cogl_vbo)
|
2008-11-10 18:53:14 +00:00
|
|
|
{
|
|
|
|
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
|
2009-01-20 21:12:44 +00:00
|
|
|
disassociate_conflicting_attributes (CoglVertexBufferVBO *conflict_vbo,
|
|
|
|
CoglVertexBufferVBO *cogl_vbo)
|
2008-11-10 18:53:14 +00:00
|
|
|
{
|
|
|
|
GList *tmp;
|
2009-01-20 21:12:44 +00:00
|
|
|
|
2008-11-10 18:53:14 +00:00
|
|
|
/* 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)
|
|
|
|
{
|
2009-01-20 21:12:44 +00:00
|
|
|
CoglVertexBufferAttrib *attribute = tmp->data;
|
2008-11-10 18:53:14 +00:00
|
|
|
GList *tmp2;
|
|
|
|
for (tmp2 = conflict_vbo->attributes; tmp2 != NULL; tmp2 = tmp2->next)
|
|
|
|
{
|
2009-01-20 21:12:44 +00:00
|
|
|
CoglVertexBufferAttrib *conflict_attribute = tmp2->data;
|
2008-11-10 18:53:14 +00:00
|
|
|
|
|
|
|
if (conflict_attribute->name == attribute->name)
|
|
|
|
{
|
2010-10-12 11:55:23 +00:00
|
|
|
_cogl_vertex_buffer_attrib_free (conflict_attribute);
|
2008-11-10 18:53:14 +00:00
|
|
|
conflict_vbo->attributes =
|
|
|
|
g_list_delete_link (conflict_vbo->attributes, tmp2);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2010-10-12 11:55:23 +00:00
|
|
|
cogl_vertex_buffer_vbo_free (CoglVertexBufferVBO *cogl_vbo)
|
2008-11-10 18:53:14 +00:00
|
|
|
{
|
|
|
|
GList *tmp;
|
|
|
|
|
|
|
|
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
|
|
|
|
|
|
|
for (tmp = cogl_vbo->attributes; tmp != NULL; tmp = tmp->next)
|
2010-10-12 11:55:23 +00:00
|
|
|
_cogl_vertex_buffer_attrib_free (tmp->data);
|
2008-11-10 18:53:14 +00:00
|
|
|
g_list_free (cogl_vbo->attributes);
|
|
|
|
|
2010-10-12 11:55:23 +00:00
|
|
|
if (cogl_vbo->flags & COGL_VERTEX_BUFFER_VBO_FLAG_SUBMITTED)
|
|
|
|
cogl_object_unref (cogl_vbo->array);
|
2008-11-10 18:53:14 +00:00
|
|
|
|
2009-01-20 21:12:44 +00:00
|
|
|
g_slice_free (CoglVertexBufferVBO, cogl_vbo);
|
2008-11-10 18:53:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* 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 *
|
2009-01-20 21:12:44 +00:00
|
|
|
prep_strided_vbo_for_upload (CoglVertexBufferVBO *cogl_vbo)
|
2008-11-10 18:53:14 +00:00
|
|
|
{
|
|
|
|
GList *tmp;
|
|
|
|
const char *lowest_pointer = NULL;
|
|
|
|
|
|
|
|
for (tmp = cogl_vbo->attributes; tmp != NULL; tmp = tmp->next)
|
|
|
|
{
|
2009-01-20 21:12:44 +00:00
|
|
|
CoglVertexBufferAttrib *attribute = tmp->data;
|
2008-11-10 18:53:14 +00:00
|
|
|
const char *client_pointer = attribute->u.pointer;
|
|
|
|
|
|
|
|
if (!lowest_pointer || client_pointer < lowest_pointer)
|
|
|
|
lowest_pointer = client_pointer;
|
|
|
|
}
|
2009-01-20 21:12:44 +00:00
|
|
|
|
2008-11-10 18:53:14 +00:00
|
|
|
for (tmp = cogl_vbo->attributes; tmp != NULL; tmp = tmp->next)
|
|
|
|
{
|
2009-01-20 21:12:44 +00:00
|
|
|
CoglVertexBufferAttrib *attribute = tmp->data;
|
2008-11-10 18:53:14 +00:00
|
|
|
const char *client_pointer = attribute->u.pointer;
|
|
|
|
attribute->u.vbo_offset = client_pointer - lowest_pointer;
|
2009-01-20 21:12:44 +00:00
|
|
|
attribute->flags |= COGL_VERTEX_BUFFER_ATTRIB_FLAG_SUBMITTED;
|
2008-11-10 18:53:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return lowest_pointer;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
2009-01-20 21:12:44 +00:00
|
|
|
upload_multipack_vbo_via_map_buffer (CoglVertexBufferVBO *cogl_vbo)
|
2008-11-10 18:53:14 +00:00
|
|
|
{
|
|
|
|
GList *tmp;
|
cogl: improves header and coding style consistency
We've had complaints that our Cogl code/headers are a bit "special" so
this is a first pass at tidying things up by giving them some
consistency. These changes are all consistent with how new code in Cogl
is being written, but the style isn't consistently applied across all
code yet.
There are two parts to this patch; but since each one required a large
amount of effort to maintain tidy indenting it made sense to combine the
changes to reduce the time spent re indenting the same lines.
The first change is to use a consistent style for declaring function
prototypes in headers. Cogl headers now consistently use this style for
prototypes:
return_type
cogl_function_name (CoglType arg0,
CoglType arg1);
Not everyone likes this style, but it seems that most of the currently
active Cogl developers agree on it.
The second change is to constrain the use of redundant glib data types
in Cogl. Uses of gint, guint, gfloat, glong, gulong and gchar have all
been replaced with int, unsigned int, float, long, unsigned long and char
respectively. When talking about pixel data; use of guchar has been
replaced with guint8, otherwise unsigned char can be used.
The glib types that we continue to use for portability are gboolean,
gint{8,16,32,64}, guint{8,16,32,64} and gsize.
The general intention is that Cogl should look palatable to the widest
range of C programmers including those outside the Gnome community so
- especially for the public API - we want to minimize the number of
foreign looking typedefs.
2010-02-10 01:57:32 +00:00
|
|
|
unsigned int offset = 0;
|
2010-10-12 11:55:23 +00:00
|
|
|
guint8 *buf;
|
2008-11-10 18:53:14 +00:00
|
|
|
|
|
|
|
_COGL_GET_CONTEXT (ctx, FALSE);
|
|
|
|
|
2010-10-12 11:55:23 +00:00
|
|
|
buf = cogl_buffer_map (COGL_BUFFER (cogl_vbo->array),
|
|
|
|
COGL_BUFFER_ACCESS_WRITE,
|
|
|
|
COGL_BUFFER_MAP_HINT_DISCARD);
|
2008-11-10 18:53:14 +00:00
|
|
|
if (!buf)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
for (tmp = cogl_vbo->attributes; tmp != NULL; tmp = tmp->next)
|
|
|
|
{
|
2009-01-20 21:12:44 +00:00
|
|
|
CoglVertexBufferAttrib *attribute = tmp->data;
|
2008-11-10 18:53:14 +00:00
|
|
|
gsize attribute_size = attribute->span_bytes;
|
2010-10-12 11:55:23 +00:00
|
|
|
gsize type_size = sizeof_attribute_type (attribute->type);
|
2008-11-10 18:53:14 +00:00
|
|
|
|
2010-10-12 11:55:23 +00:00
|
|
|
PAD_FOR_ALIGNMENT (offset, type_size);
|
2008-11-10 18:53:14 +00:00
|
|
|
|
|
|
|
memcpy (buf + offset, attribute->u.pointer, attribute_size);
|
|
|
|
|
|
|
|
attribute->u.vbo_offset = offset;
|
2009-01-20 21:12:44 +00:00
|
|
|
attribute->flags |= COGL_VERTEX_BUFFER_ATTRIB_FLAG_SUBMITTED;
|
2008-11-10 18:53:14 +00:00
|
|
|
offset += attribute_size;
|
|
|
|
}
|
2009-04-15 18:25:55 +00:00
|
|
|
|
2010-10-12 11:55:23 +00:00
|
|
|
cogl_buffer_unmap (COGL_BUFFER (cogl_vbo->array));
|
2008-11-10 18:53:14 +00:00
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2009-01-20 21:12:44 +00:00
|
|
|
upload_multipack_vbo_via_buffer_sub_data (CoglVertexBufferVBO *cogl_vbo)
|
2008-11-10 18:53:14 +00:00
|
|
|
{
|
2010-10-12 11:55:23 +00:00
|
|
|
GList *l;
|
cogl: improves header and coding style consistency
We've had complaints that our Cogl code/headers are a bit "special" so
this is a first pass at tidying things up by giving them some
consistency. These changes are all consistent with how new code in Cogl
is being written, but the style isn't consistently applied across all
code yet.
There are two parts to this patch; but since each one required a large
amount of effort to maintain tidy indenting it made sense to combine the
changes to reduce the time spent re indenting the same lines.
The first change is to use a consistent style for declaring function
prototypes in headers. Cogl headers now consistently use this style for
prototypes:
return_type
cogl_function_name (CoglType arg0,
CoglType arg1);
Not everyone likes this style, but it seems that most of the currently
active Cogl developers agree on it.
The second change is to constrain the use of redundant glib data types
in Cogl. Uses of gint, guint, gfloat, glong, gulong and gchar have all
been replaced with int, unsigned int, float, long, unsigned long and char
respectively. When talking about pixel data; use of guchar has been
replaced with guint8, otherwise unsigned char can be used.
The glib types that we continue to use for portability are gboolean,
gint{8,16,32,64}, guint{8,16,32,64} and gsize.
The general intention is that Cogl should look palatable to the widest
range of C programmers including those outside the Gnome community so
- especially for the public API - we want to minimize the number of
foreign looking typedefs.
2010-02-10 01:57:32 +00:00
|
|
|
unsigned int offset = 0;
|
2008-11-10 18:53:14 +00:00
|
|
|
|
2010-10-12 11:55:23 +00:00
|
|
|
for (l = cogl_vbo->attributes; l != NULL; l = l->next)
|
2008-11-10 18:53:14 +00:00
|
|
|
{
|
2010-10-12 11:55:23 +00:00
|
|
|
CoglVertexBufferAttrib *attribute = l->data;
|
2008-11-10 18:53:14 +00:00
|
|
|
gsize attribute_size = attribute->span_bytes;
|
2010-10-12 11:55:23 +00:00
|
|
|
gsize type_size = sizeof_attribute_type (attribute->type);
|
2008-11-10 18:53:14 +00:00
|
|
|
|
2010-10-12 11:55:23 +00:00
|
|
|
PAD_FOR_ALIGNMENT (offset, type_size);
|
2008-11-10 18:53:14 +00:00
|
|
|
|
2010-10-12 11:55:23 +00:00
|
|
|
cogl_buffer_set_data (COGL_BUFFER (cogl_vbo->array),
|
|
|
|
offset,
|
|
|
|
attribute->u.pointer,
|
|
|
|
attribute_size);
|
2009-04-15 18:25:55 +00:00
|
|
|
|
2008-11-10 18:53:14 +00:00
|
|
|
attribute->u.vbo_offset = offset;
|
2009-01-20 21:12:44 +00:00
|
|
|
attribute->flags |= COGL_VERTEX_BUFFER_ATTRIB_FLAG_SUBMITTED;
|
2008-11-10 18:53:14 +00:00
|
|
|
offset += attribute_size;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2010-10-12 11:55:23 +00:00
|
|
|
upload_attributes (CoglVertexBufferVBO *cogl_vbo)
|
2008-11-10 18:53:14 +00:00
|
|
|
{
|
2010-10-12 11:55:23 +00:00
|
|
|
CoglBufferUpdateHint usage;
|
2008-11-10 18:53:14 +00:00
|
|
|
|
|
|
|
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
|
|
|
|
2009-01-20 21:12:44 +00:00
|
|
|
if (cogl_vbo->flags & COGL_VERTEX_BUFFER_VBO_FLAG_FREQUENT_RESUBMIT)
|
2010-10-12 11:55:23 +00:00
|
|
|
usage = COGL_BUFFER_UPDATE_HINT_DYNAMIC;
|
2008-11-10 18:53:14 +00:00
|
|
|
else
|
2010-10-12 11:55:23 +00:00
|
|
|
usage = COGL_BUFFER_UPDATE_HINT_STATIC;
|
|
|
|
cogl_buffer_set_update_hint (COGL_BUFFER (cogl_vbo->array), usage);
|
2009-01-20 21:12:44 +00:00
|
|
|
|
|
|
|
if (cogl_vbo->flags & COGL_VERTEX_BUFFER_VBO_FLAG_STRIDED)
|
2008-11-10 18:53:14 +00:00
|
|
|
{
|
2010-10-12 11:55:23 +00:00
|
|
|
const void *pointer = prep_strided_vbo_for_upload (cogl_vbo);
|
|
|
|
cogl_buffer_set_data (COGL_BUFFER (cogl_vbo->array),
|
|
|
|
0, /* offset */
|
|
|
|
pointer,
|
|
|
|
cogl_vbo->array_bytes);
|
2008-11-10 18:53:14 +00:00
|
|
|
}
|
2010-08-01 15:07:38 +00:00
|
|
|
else /* MULTIPACK */
|
2008-11-10 18:53:14 +00:00
|
|
|
{
|
2009-01-20 21:12:44 +00:00
|
|
|
/* 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
|
2008-11-10 18:53:14 +00:00
|
|
|
* 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);
|
|
|
|
}
|
|
|
|
|
2009-01-20 21:12:44 +00:00
|
|
|
cogl_vbo->flags |= COGL_VERTEX_BUFFER_VBO_FLAG_SUBMITTED;
|
2008-11-10 18:53:14 +00:00
|
|
|
}
|
|
|
|
|
2009-01-20 21:12:44 +00:00
|
|
|
/* 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. */
|
2008-11-10 18:53:14 +00:00
|
|
|
static void
|
2009-01-20 21:12:44 +00:00
|
|
|
cogl_vertex_buffer_vbo_resolve (CoglVertexBuffer *buffer,
|
|
|
|
CoglVertexBufferVBO *new_cogl_vbo,
|
|
|
|
GList **final_vbos)
|
2008-11-10 18:53:14 +00:00
|
|
|
{
|
|
|
|
GList *conflicts;
|
|
|
|
GList *tmp;
|
|
|
|
GList *next;
|
|
|
|
gboolean found_target_vbo = FALSE;
|
|
|
|
|
|
|
|
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
2009-01-20 21:12:44 +00:00
|
|
|
|
2008-11-10 18:53:14 +00:00
|
|
|
conflicts =
|
2009-01-20 21:12:44 +00:00
|
|
|
get_submitted_vbo_conflicts (&buffer->submitted_vbos, new_cogl_vbo);
|
2008-11-10 18:53:14 +00:00
|
|
|
|
|
|
|
for (tmp = conflicts; tmp != NULL; tmp = next)
|
|
|
|
{
|
2009-01-20 21:12:44 +00:00
|
|
|
CoglVertexBufferVBO *conflict_vbo = tmp->data;
|
2008-11-10 18:53:14 +00:00
|
|
|
|
|
|
|
next = tmp->next;
|
2009-01-20 21:12:44 +00:00
|
|
|
|
2008-11-10 18:53:14 +00:00
|
|
|
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
|
2010-10-12 11:55:23 +00:00
|
|
|
&& conflict_vbo->array_bytes == new_cogl_vbo->array_bytes)
|
2008-11-10 18:53:14 +00:00
|
|
|
{
|
|
|
|
found_target_vbo = TRUE;
|
2010-10-12 11:55:23 +00:00
|
|
|
new_cogl_vbo->array = cogl_object_ref (conflict_vbo->array);
|
|
|
|
cogl_vertex_buffer_vbo_free (conflict_vbo);
|
2009-01-20 21:12:44 +00:00
|
|
|
|
2010-10-12 11:55:23 +00:00
|
|
|
upload_attributes (new_cogl_vbo);
|
2008-11-10 18:53:14 +00:00
|
|
|
|
|
|
|
*final_vbos = g_list_prepend (*final_vbos, new_cogl_vbo);
|
|
|
|
}
|
|
|
|
else
|
2010-10-12 11:55:23 +00:00
|
|
|
cogl_vertex_buffer_vbo_free (conflict_vbo);
|
2008-11-10 18:53:14 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2009-01-20 21:12:44 +00:00
|
|
|
/* Relink the VBO back into buffer->submitted_vbos since it may
|
2008-11-10 18:53:14 +00:00
|
|
|
* be involved in other conflicts later */
|
2009-01-20 21:12:44 +00:00
|
|
|
tmp->next = buffer->submitted_vbos;
|
2008-11-10 18:53:14 +00:00
|
|
|
tmp->prev = NULL;
|
2009-01-20 21:12:44 +00:00
|
|
|
buffer->submitted_vbos = tmp;
|
2008-11-10 18:53:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!found_target_vbo)
|
|
|
|
{
|
2010-11-16 08:49:55 +00:00
|
|
|
new_cogl_vbo->array = cogl_vertex_array_new (new_cogl_vbo->array_bytes,
|
|
|
|
NULL);
|
2009-01-20 21:12:44 +00:00
|
|
|
|
2010-10-12 11:55:23 +00:00
|
|
|
upload_attributes (new_cogl_vbo);
|
2008-11-10 18:53:14 +00:00
|
|
|
*final_vbos = g_list_prepend (*final_vbos, new_cogl_vbo);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-10-12 11:55:23 +00:00
|
|
|
static void
|
|
|
|
update_primitive_attributes (CoglVertexBuffer *buffer)
|
|
|
|
{
|
|
|
|
GList *l;
|
|
|
|
int n_attributes = 0;
|
2011-01-20 19:31:53 +00:00
|
|
|
CoglAttribute **attributes;
|
2010-10-12 11:55:23 +00:00
|
|
|
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);
|
|
|
|
|
2011-01-20 19:31:53 +00:00
|
|
|
attributes = g_alloca (sizeof (CoglAttribute *) * n_attributes + 1);
|
2010-10-12 11:55:23 +00:00
|
|
|
|
|
|
|
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 =
|
2011-01-20 19:31:53 +00:00
|
|
|
cogl_attribute_new (cogl_vbo->array,
|
|
|
|
attribute->name_without_detail,
|
|
|
|
attribute->stride,
|
|
|
|
attribute->u.vbo_offset,
|
|
|
|
attribute->n_components,
|
|
|
|
attribute->type);
|
2010-10-12 11:55:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
attributes[i++] = attribute->attribute;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
attributes[i] = NULL;
|
|
|
|
|
|
|
|
cogl_primitive_set_attributes (buffer->primitive, attributes);
|
|
|
|
}
|
|
|
|
|
2009-02-28 17:36:25 +00:00
|
|
|
static void
|
|
|
|
cogl_vertex_buffer_submit_real (CoglVertexBuffer *buffer)
|
2008-11-10 18:53:14 +00:00
|
|
|
{
|
|
|
|
GList *tmp;
|
2009-01-20 21:12:44 +00:00
|
|
|
CoglVertexBufferVBO *new_multipack_vbo;
|
2008-11-10 18:53:14 +00:00
|
|
|
GList *new_multipack_vbo_link;
|
|
|
|
GList *new_vbos = NULL;
|
|
|
|
GList *reuse_vbos = NULL;
|
|
|
|
GList *final_vbos = NULL;
|
2009-01-20 21:12:44 +00:00
|
|
|
|
2009-02-28 17:36:25 +00:00
|
|
|
if (!buffer->new_attributes)
|
2010-10-12 11:55:23 +00:00
|
|
|
goto done;
|
2009-01-20 21:12:44 +00:00
|
|
|
|
2008-11-10 18:53:14 +00:00
|
|
|
/* The objective now is to copy the attribute data supplied by the client
|
2009-01-20 21:12:44 +00:00
|
|
|
* into buffer objects, but it's important to minimize the number of
|
|
|
|
* redundant data uploads.
|
2008-11-10 18:53:14 +00:00
|
|
|
*
|
2009-01-20 21:12:44 +00:00
|
|
|
* 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.
|
2008-11-10 18:53:14 +00:00
|
|
|
*
|
|
|
|
* 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
|
|
|
|
*
|
2009-01-20 21:12:44 +00:00
|
|
|
* 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.
|
2008-11-10 18:53:14 +00:00
|
|
|
*/
|
2009-01-20 21:12:44 +00:00
|
|
|
|
2008-11-10 18:53:14 +00:00
|
|
|
/* NB: We must forget attribute->pointer after submitting since the user
|
|
|
|
* is free to re-use that memory for other purposes now. */
|
|
|
|
|
|
|
|
/* Pseudo code:
|
2009-01-20 21:12:44 +00:00
|
|
|
*
|
2008-11-10 18:53:14 +00:00
|
|
|
* Broadly speaking we start with a list of unsorted attributes, and filter
|
2009-01-20 21:12:44 +00:00
|
|
|
* 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.
|
|
|
|
*
|
2010-08-01 15:07:38 +00:00
|
|
|
* We have two kinds of CBOs:
|
|
|
|
* - Multi Pack CBOs
|
|
|
|
* These contain multiple attributes tightly packed back to back)
|
2008-11-10 18:53:14 +00:00
|
|
|
* - 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:
|
2010-08-01 15:07:38 +00:00
|
|
|
* create a new-CBOs entry tagged MULTIPACK + FREQUENT_RESUBMIT
|
2008-11-10 18:53:14 +00:00
|
|
|
* else
|
|
|
|
* add to the new-multipack-CBO
|
|
|
|
* free list of unsorted-attribs
|
2009-01-20 21:12:44 +00:00
|
|
|
*
|
2008-11-10 18:53:14 +00:00
|
|
|
* 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)
|
2009-01-20 21:12:44 +00:00
|
|
|
*
|
2008-11-10 18:53:14 +00:00
|
|
|
* 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
|
2009-01-20 21:12:44 +00:00
|
|
|
* CBO it will be linked into the final list.
|
2008-11-10 18:53:14 +00:00
|
|
|
*
|
|
|
|
* At the end the list of submitted CBOs represents the attributes that were
|
2009-01-20 21:12:44 +00:00
|
|
|
* deleted from the buffer.
|
|
|
|
*
|
2008-11-10 18:53:14 +00:00
|
|
|
* 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
|
|
|
|
*/
|
2009-01-20 21:12:44 +00:00
|
|
|
|
|
|
|
new_multipack_vbo = g_slice_alloc (sizeof (CoglVertexBufferVBO));
|
2010-10-12 11:55:23 +00:00
|
|
|
new_multipack_vbo->array = NULL;
|
|
|
|
new_multipack_vbo->array_bytes = 0;
|
2009-01-20 21:12:44 +00:00
|
|
|
new_multipack_vbo->flags =
|
|
|
|
COGL_VERTEX_BUFFER_VBO_FLAG_MULTIPACK
|
|
|
|
| COGL_VERTEX_BUFFER_VBO_FLAG_INFREQUENT_RESUBMIT;
|
2008-11-10 18:53:14 +00:00
|
|
|
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
|
|
|
|
*/
|
2009-01-20 21:12:44 +00:00
|
|
|
for (tmp = buffer->new_attributes; tmp != NULL; tmp = tmp->next)
|
2008-11-10 18:53:14 +00:00
|
|
|
{
|
2009-01-20 21:12:44 +00:00
|
|
|
CoglVertexBufferAttrib *attribute = tmp->data;
|
|
|
|
|
|
|
|
if (attribute->flags & COGL_VERTEX_BUFFER_ATTRIB_FLAG_SUBMITTED)
|
2008-11-10 18:53:14 +00:00
|
|
|
{
|
|
|
|
/* 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,
|
2009-01-20 21:12:44 +00:00
|
|
|
&buffer->submitted_vbos);
|
2008-11-10 18:53:14 +00:00
|
|
|
}
|
|
|
|
else if (attribute->stride)
|
|
|
|
{
|
2009-01-20 21:12:44 +00:00
|
|
|
/* 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: */
|
2008-11-10 18:53:14 +00:00
|
|
|
filter_strided_attribute (attribute, &new_vbos);
|
|
|
|
}
|
2009-01-20 21:12:44 +00:00
|
|
|
else if (attribute->flags &
|
|
|
|
COGL_VERTEX_BUFFER_ATTRIB_FLAG_FREQUENT_RESUBMIT)
|
2008-11-10 18:53:14 +00:00
|
|
|
{
|
2009-01-20 21:12:44 +00:00
|
|
|
CoglVertexBufferVBO *cogl_vbo =
|
|
|
|
g_slice_alloc (sizeof (CoglVertexBufferVBO));
|
|
|
|
|
2008-11-10 18:53:14 +00:00
|
|
|
/* attributes we expect will be frequently resubmitted are placed
|
|
|
|
* in their own VBO so that updates don't impact other attributes
|
|
|
|
*/
|
|
|
|
|
2009-01-20 21:12:44 +00:00
|
|
|
cogl_vbo->flags =
|
2010-08-01 15:07:38 +00:00
|
|
|
COGL_VERTEX_BUFFER_VBO_FLAG_MULTIPACK
|
2009-01-20 21:12:44 +00:00
|
|
|
| COGL_VERTEX_BUFFER_VBO_FLAG_FREQUENT_RESUBMIT;
|
2008-11-10 18:53:14 +00:00
|
|
|
cogl_vbo->attributes = NULL;
|
|
|
|
cogl_vbo->attributes = g_list_prepend (cogl_vbo->attributes,
|
|
|
|
attribute);
|
2010-10-12 11:55:23 +00:00
|
|
|
cogl_vbo->array = NULL;
|
|
|
|
cogl_vbo->array_bytes = attribute->span_bytes;
|
2008-11-10 18:53:14 +00:00
|
|
|
new_vbos = g_list_prepend (new_vbos, cogl_vbo);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2010-10-12 11:55:23 +00:00
|
|
|
gsize type_size = sizeof_attribute_type (attribute->flags);
|
2008-11-10 18:53:14 +00:00
|
|
|
|
|
|
|
/* 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.
|
|
|
|
*/
|
|
|
|
|
2010-10-12 11:55:23 +00:00
|
|
|
PAD_FOR_ALIGNMENT (new_multipack_vbo->array_bytes, type_size);
|
2008-11-10 18:53:14 +00:00
|
|
|
|
2010-10-12 11:55:23 +00:00
|
|
|
new_multipack_vbo->array_bytes += attribute->span_bytes;
|
2008-11-10 18:53:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-01-20 21:12:44 +00:00
|
|
|
/* At this point all buffer->new_attributes have been filtered into
|
|
|
|
* CoglVertexBufferVBOs... */
|
|
|
|
g_list_free (buffer->new_attributes);
|
|
|
|
buffer->new_attributes = NULL;
|
|
|
|
|
2008-11-10 18:53:14 +00:00
|
|
|
/* 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);
|
2009-01-20 21:12:44 +00:00
|
|
|
g_slice_free (CoglVertexBufferVBO, new_multipack_vbo);
|
2008-11-10 18:53:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
2009-01-20 21:12:44 +00:00
|
|
|
cogl_vertex_buffer_vbo_resolve (buffer, tmp->data, &final_vbos);
|
|
|
|
|
2008-11-10 18:53:14 +00:00
|
|
|
/* Anything left corresponds to deleted attributes: */
|
2009-01-20 21:12:44 +00:00
|
|
|
for (tmp = buffer->submitted_vbos; tmp != NULL; tmp = tmp->next)
|
2010-10-12 11:55:23 +00:00
|
|
|
cogl_vertex_buffer_vbo_free (tmp->data);
|
2009-01-20 21:12:44 +00:00
|
|
|
g_list_free (buffer->submitted_vbos);
|
2009-06-16 14:34:13 +00:00
|
|
|
g_list_free (new_vbos);
|
2008-11-10 18:53:14 +00:00
|
|
|
|
2009-01-20 21:12:44 +00:00
|
|
|
buffer->submitted_vbos = final_vbos;
|
2010-10-12 11:55:23 +00:00
|
|
|
|
|
|
|
done:
|
|
|
|
update_primitive_attributes (buffer);
|
2008-11-10 18:53:14 +00:00
|
|
|
}
|
|
|
|
|
2009-02-28 17:36:25 +00:00
|
|
|
void
|
|
|
|
cogl_vertex_buffer_submit (CoglHandle handle)
|
|
|
|
{
|
|
|
|
CoglVertexBuffer *buffer;
|
|
|
|
|
|
|
|
if (!cogl_is_vertex_buffer (handle))
|
|
|
|
return;
|
|
|
|
|
|
|
|
buffer = _cogl_vertex_buffer_pointer_from_handle (handle);
|
|
|
|
|
|
|
|
cogl_vertex_buffer_submit_real (buffer);
|
|
|
|
}
|
|
|
|
|
2010-10-12 11:55:23 +00:00
|
|
|
typedef struct
|
2008-11-10 18:53:14 +00:00
|
|
|
{
|
2011-02-01 18:43:27 +00:00
|
|
|
/* 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;
|
|
|
|
|
2010-10-27 17:54:57 +00:00
|
|
|
CoglPipeline *real_source;
|
2010-10-12 11:55:23 +00:00
|
|
|
} VertexBufferMaterialPrivate;
|
2008-11-10 18:53:14 +00:00
|
|
|
|
2011-02-01 18:43:27 +00:00
|
|
|
static void
|
|
|
|
unref_pipeline_priv (VertexBufferMaterialPrivate *priv)
|
|
|
|
{
|
|
|
|
if (--priv->ref_count < 1)
|
|
|
|
g_slice_free (VertexBufferMaterialPrivate, priv);
|
|
|
|
}
|
|
|
|
|
2010-10-12 11:55:23 +00:00
|
|
|
static void
|
2010-10-27 17:54:57 +00:00
|
|
|
weak_override_source_destroyed_cb (CoglPipeline *pipeline,
|
2011-02-01 18:43:27 +00:00
|
|
|
void *user_data)
|
2010-10-12 11:55:23 +00:00
|
|
|
{
|
2010-10-27 17:54:57 +00:00
|
|
|
VertexBufferMaterialPrivate *pipeline_priv = user_data;
|
|
|
|
pipeline_priv->real_source = NULL;
|
2011-02-01 18:43:27 +00:00
|
|
|
/* A reference was added when we copied the weak material so we need
|
|
|
|
to unref it here */
|
|
|
|
unref_pipeline_priv (pipeline_priv);
|
2008-11-10 18:53:14 +00:00
|
|
|
}
|
|
|
|
|
2010-10-12 11:55:23 +00:00
|
|
|
static gboolean
|
2010-10-27 17:54:57 +00:00
|
|
|
validate_layer_cb (CoglPipeline *pipeline,
|
2010-10-12 11:55:23 +00:00
|
|
|
int layer_index,
|
|
|
|
void *user_data)
|
2008-11-10 18:53:14 +00:00
|
|
|
{
|
2010-10-27 17:54:57 +00:00
|
|
|
VertexBufferMaterialPrivate *pipeline_priv = user_data;
|
|
|
|
CoglPipeline *source = pipeline_priv->real_source;
|
2008-11-10 18:53:14 +00:00
|
|
|
|
2010-10-27 17:54:57 +00:00
|
|
|
if (!cogl_pipeline_get_layer_point_sprite_coords_enabled (source,
|
2010-10-12 11:55:23 +00:00
|
|
|
layer_index))
|
2008-11-10 18:53:14 +00:00
|
|
|
{
|
2010-10-27 17:54:57 +00:00
|
|
|
CoglPipelineWrapMode wrap_s;
|
|
|
|
CoglPipelineWrapMode wrap_t;
|
|
|
|
CoglPipelineWrapMode wrap_p;
|
2010-10-12 11:55:23 +00:00
|
|
|
gboolean need_override_source = FALSE;
|
|
|
|
|
2010-10-27 17:54:57 +00:00
|
|
|
/* By default COGL_PIPELINE_WRAP_MODE_AUTOMATIC becomes
|
2010-10-12 11:55:23 +00:00
|
|
|
* 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.
|
2009-04-15 18:25:55 +00:00
|
|
|
*/
|
2010-10-27 17:54:57 +00:00
|
|
|
wrap_s = cogl_pipeline_get_layer_wrap_mode_s (source, layer_index);
|
|
|
|
if (wrap_s == COGL_PIPELINE_WRAP_MODE_AUTOMATIC)
|
2010-04-07 10:06:20 +00:00
|
|
|
{
|
2010-10-12 11:55:23 +00:00
|
|
|
need_override_source = TRUE;
|
2010-10-27 17:54:57 +00:00
|
|
|
wrap_s = COGL_PIPELINE_WRAP_MODE_REPEAT;
|
2010-04-07 10:06:20 +00:00
|
|
|
}
|
2010-10-27 17:54:57 +00:00
|
|
|
wrap_t = cogl_pipeline_get_layer_wrap_mode_t (source, layer_index);
|
|
|
|
if (wrap_t == COGL_PIPELINE_WRAP_MODE_AUTOMATIC)
|
Fully integrates CoglMaterial throughout the rest of Cogl
This glues CoglMaterial in as the fundamental way that Cogl describes how to
fill in geometry.
It adds cogl_set_source (), which is used to set the material which will be
used by all subsequent drawing functions
It adds cogl_set_source_texture as a convenience for setting up a default
material with a single texture layer, and cogl_set_source_color is now also
a convenience for setting up a material with a solid fill.
"drawing functions" include, cogl_rectangle, cogl_texture_rectangle,
cogl_texture_multiple_rectangles, cogl_texture_polygon (though the
cogl_texture_* funcs have been renamed; see below for details),
cogl_path_fill/stroke and cogl_vertex_buffer_draw*.
cogl_texture_rectangle, cogl_texture_multiple_rectangles and
cogl_texture_polygon no longer take a texture handle; instead the current
source material is referenced. The functions have also been renamed to:
cogl_rectangle_with_texture_coords, cogl_rectangles_with_texture_coords
and cogl_polygon respectivly.
Most code that previously did:
cogl_texture_rectangle (tex_handle, x, y,...);
needs to be changed to now do:
cogl_set_source_texture (tex_handle);
cogl_rectangle_with_texture_coords (x, y,....);
In the less likely case where you were blending your source texture with a color
like:
cogl_set_source_color4ub (r,g,b,a); /* where r,g,b,a isn't just white */
cogl_texture_rectangle (tex_handle, x, y,...);
you will need your own material to do that:
mat = cogl_material_new ();
cogl_material_set_color4ub (r,g,b,a);
cogl_material_set_layer (mat, 0, tex_handle));
cogl_set_source_material (mat);
Code that uses the texture coordinates, 0, 0, 1, 1 don't need to use
cog_rectangle_with_texure_coords since these are the coordinates that
cogl_rectangle will use.
For cogl_texture_polygon; as well as dropping the texture handle, the
n_vertices and vertices arguments were transposed for consistency. So
code previously written as:
cogl_texture_polygon (tex_handle, 3, verts, TRUE);
need to be written as:
cogl_set_source_texture (tex_handle);
cogl_polygon (verts, 3, TRUE);
All of the unit tests have been updated to now use the material API and
test-cogl-material has been renamed to test-cogl-multitexture since any
textured quad is now technically a test of CoglMaterial but this test
specifically creates a material with multiple texture layers.
Note: The GLES backend has not been updated yet; that will be done in a
following commit.
2009-01-23 16:15:40 +00:00
|
|
|
{
|
2010-10-12 11:55:23 +00:00
|
|
|
need_override_source = TRUE;
|
2010-10-27 17:54:57 +00:00
|
|
|
wrap_t = COGL_PIPELINE_WRAP_MODE_REPEAT;
|
Fully integrates CoglMaterial throughout the rest of Cogl
This glues CoglMaterial in as the fundamental way that Cogl describes how to
fill in geometry.
It adds cogl_set_source (), which is used to set the material which will be
used by all subsequent drawing functions
It adds cogl_set_source_texture as a convenience for setting up a default
material with a single texture layer, and cogl_set_source_color is now also
a convenience for setting up a material with a solid fill.
"drawing functions" include, cogl_rectangle, cogl_texture_rectangle,
cogl_texture_multiple_rectangles, cogl_texture_polygon (though the
cogl_texture_* funcs have been renamed; see below for details),
cogl_path_fill/stroke and cogl_vertex_buffer_draw*.
cogl_texture_rectangle, cogl_texture_multiple_rectangles and
cogl_texture_polygon no longer take a texture handle; instead the current
source material is referenced. The functions have also been renamed to:
cogl_rectangle_with_texture_coords, cogl_rectangles_with_texture_coords
and cogl_polygon respectivly.
Most code that previously did:
cogl_texture_rectangle (tex_handle, x, y,...);
needs to be changed to now do:
cogl_set_source_texture (tex_handle);
cogl_rectangle_with_texture_coords (x, y,....);
In the less likely case where you were blending your source texture with a color
like:
cogl_set_source_color4ub (r,g,b,a); /* where r,g,b,a isn't just white */
cogl_texture_rectangle (tex_handle, x, y,...);
you will need your own material to do that:
mat = cogl_material_new ();
cogl_material_set_color4ub (r,g,b,a);
cogl_material_set_layer (mat, 0, tex_handle));
cogl_set_source_material (mat);
Code that uses the texture coordinates, 0, 0, 1, 1 don't need to use
cog_rectangle_with_texure_coords since these are the coordinates that
cogl_rectangle will use.
For cogl_texture_polygon; as well as dropping the texture handle, the
n_vertices and vertices arguments were transposed for consistency. So
code previously written as:
cogl_texture_polygon (tex_handle, 3, verts, TRUE);
need to be written as:
cogl_set_source_texture (tex_handle);
cogl_polygon (verts, 3, TRUE);
All of the unit tests have been updated to now use the material API and
test-cogl-material has been renamed to test-cogl-multitexture since any
textured quad is now technically a test of CoglMaterial but this test
specifically creates a material with multiple texture layers.
Note: The GLES backend has not been updated yet; that will be done in a
following commit.
2009-01-23 16:15:40 +00:00
|
|
|
}
|
2010-10-27 17:54:57 +00:00
|
|
|
wrap_p = cogl_pipeline_get_layer_wrap_mode_p (source, layer_index);
|
|
|
|
if (wrap_p == COGL_PIPELINE_WRAP_MODE_AUTOMATIC)
|
2010-10-25 12:25:21 +00:00
|
|
|
{
|
2010-10-12 11:55:23 +00:00
|
|
|
need_override_source = TRUE;
|
2010-10-27 17:54:57 +00:00
|
|
|
wrap_p = COGL_PIPELINE_WRAP_MODE_REPEAT;
|
2010-10-25 12:25:21 +00:00
|
|
|
}
|
2010-05-18 21:42:49 +00:00
|
|
|
|
2010-10-12 11:55:23 +00:00
|
|
|
if (need_override_source)
|
2010-10-25 12:25:21 +00:00
|
|
|
{
|
2010-10-27 17:54:57 +00:00
|
|
|
if (pipeline_priv->real_source == pipeline)
|
2011-02-01 18:43:27 +00:00
|
|
|
{
|
|
|
|
pipeline_priv->ref_count++;
|
|
|
|
pipeline_priv->real_source = source =
|
|
|
|
_cogl_pipeline_weak_copy (pipeline,
|
|
|
|
weak_override_source_destroyed_cb,
|
|
|
|
pipeline_priv);
|
|
|
|
}
|
2010-10-12 11:55:23 +00:00
|
|
|
|
2010-10-27 17:54:57 +00:00
|
|
|
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);
|
2010-10-25 12:25:21 +00:00
|
|
|
}
|
2010-04-26 09:01:43 +00:00
|
|
|
}
|
|
|
|
|
2010-10-12 11:55:23 +00:00
|
|
|
return TRUE;
|
|
|
|
}
|
2010-04-26 09:01:43 +00:00
|
|
|
|
2010-10-12 11:55:23 +00:00
|
|
|
static void
|
2010-10-27 17:54:57 +00:00
|
|
|
destroy_pipeline_priv_cb (void *user_data)
|
2010-10-12 11:55:23 +00:00
|
|
|
{
|
2011-02-01 18:43:27 +00:00
|
|
|
unref_pipeline_priv (user_data);
|
2008-11-10 18:53:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2010-10-12 11:55:23 +00:00
|
|
|
update_primitive_and_draw (CoglVertexBuffer *buffer,
|
|
|
|
CoglVerticesMode mode,
|
|
|
|
int first,
|
|
|
|
int count,
|
|
|
|
CoglVertexBufferIndices *buffer_indices)
|
2008-11-10 18:53:14 +00:00
|
|
|
{
|
2010-10-27 17:54:57 +00:00
|
|
|
VertexBufferMaterialPrivate *pipeline_priv;
|
|
|
|
CoglPipeline *users_source;
|
2008-11-10 18:53:14 +00:00
|
|
|
|
|
|
|
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
|
|
|
|
2010-10-12 11:55:23 +00:00
|
|
|
cogl_primitive_set_mode (buffer->primitive, mode);
|
|
|
|
cogl_primitive_set_first_vertex (buffer->primitive, first);
|
|
|
|
cogl_primitive_set_n_vertices (buffer->primitive, count);
|
2010-04-26 09:01:43 +00:00
|
|
|
|
2010-10-12 11:55:23 +00:00
|
|
|
if (buffer_indices)
|
|
|
|
cogl_primitive_set_indices (buffer->primitive, buffer_indices->indices);
|
|
|
|
else
|
|
|
|
cogl_primitive_set_indices (buffer->primitive, NULL);
|
2008-11-10 18:53:14 +00:00
|
|
|
|
2010-10-12 11:55:23 +00:00
|
|
|
cogl_vertex_buffer_submit_real (buffer);
|
|
|
|
|
|
|
|
users_source = cogl_get_source ();
|
2010-10-27 17:54:57 +00:00
|
|
|
pipeline_priv =
|
2010-10-12 11:55:23 +00:00
|
|
|
cogl_object_get_user_data (COGL_OBJECT (users_source),
|
2010-10-27 17:54:57 +00:00
|
|
|
&_cogl_vertex_buffer_pipeline_priv_key);
|
|
|
|
if (G_UNLIKELY (!pipeline_priv))
|
2008-11-10 18:53:14 +00:00
|
|
|
{
|
2010-10-27 17:54:57 +00:00
|
|
|
pipeline_priv = g_slice_new0 (VertexBufferMaterialPrivate);
|
2011-02-01 18:43:27 +00:00
|
|
|
pipeline_priv->ref_count = 1;
|
2010-10-12 11:55:23 +00:00
|
|
|
cogl_object_set_user_data (COGL_OBJECT (users_source),
|
2010-10-27 17:54:57 +00:00
|
|
|
&_cogl_vertex_buffer_pipeline_priv_key,
|
|
|
|
pipeline_priv,
|
|
|
|
destroy_pipeline_priv_cb);
|
2010-10-12 11:55:23 +00:00
|
|
|
}
|
2008-11-10 18:53:14 +00:00
|
|
|
|
2010-10-27 17:54:57 +00:00
|
|
|
if (G_UNLIKELY (!pipeline_priv->real_source))
|
2010-10-12 11:55:23 +00:00
|
|
|
{
|
2010-10-27 17:54:57 +00:00
|
|
|
pipeline_priv->real_source = users_source;
|
|
|
|
cogl_pipeline_foreach_layer (pipeline_priv->real_source,
|
2010-10-12 11:55:23 +00:00
|
|
|
validate_layer_cb,
|
2010-10-27 17:54:57 +00:00
|
|
|
pipeline_priv);
|
2010-10-12 11:55:23 +00:00
|
|
|
}
|
2008-11-10 18:53:14 +00:00
|
|
|
|
2010-10-27 17:54:57 +00:00
|
|
|
cogl_push_source (pipeline_priv->real_source);
|
2008-11-10 18:53:14 +00:00
|
|
|
|
2010-10-12 11:55:23 +00:00
|
|
|
cogl_primitive_draw (buffer->primitive);
|
|
|
|
|
|
|
|
cogl_pop_source ();
|
2008-11-10 18:53:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2009-05-24 10:33:29 +00:00
|
|
|
cogl_vertex_buffer_draw (CoglHandle handle,
|
|
|
|
CoglVerticesMode mode,
|
|
|
|
int first,
|
|
|
|
int count)
|
2008-11-10 18:53:14 +00:00
|
|
|
{
|
2009-01-20 21:12:44 +00:00
|
|
|
CoglVertexBuffer *buffer;
|
|
|
|
|
|
|
|
if (!cogl_is_vertex_buffer (handle))
|
2008-11-10 18:53:14 +00:00
|
|
|
return;
|
2009-01-20 21:12:44 +00:00
|
|
|
|
|
|
|
buffer = _cogl_vertex_buffer_pointer_from_handle (handle);
|
|
|
|
|
2010-10-12 11:55:23 +00:00
|
|
|
update_primitive_and_draw (buffer, mode, first, count, NULL);
|
2009-05-24 03:04:38 +00:00
|
|
|
}
|
|
|
|
|
2010-10-26 17:56:57 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2009-05-28 11:49:29 +00:00
|
|
|
CoglHandle
|
|
|
|
cogl_vertex_buffer_indices_new (CoglIndicesType indices_type,
|
2009-05-24 10:33:29 +00:00
|
|
|
const void *indices_array,
|
|
|
|
int indices_len)
|
2009-05-24 03:04:38 +00:00
|
|
|
{
|
2010-10-26 17:56:57 +00:00
|
|
|
CoglIndices *indices =
|
2010-10-12 11:55:23 +00:00
|
|
|
cogl_indices_new (indices_type, indices_array, indices_len);
|
2010-10-26 17:56:57 +00:00
|
|
|
return _cogl_vertex_buffer_indices_new_real (indices);
|
2009-05-26 15:27:36 +00:00
|
|
|
}
|
|
|
|
|
2009-06-17 14:03:33 +00:00
|
|
|
CoglIndicesType
|
|
|
|
cogl_vertex_buffer_indices_get_type (CoglHandle indices_handle)
|
|
|
|
{
|
2010-10-12 11:55:23 +00:00
|
|
|
CoglVertexBufferIndices *buffer_indices = NULL;
|
2009-06-17 14:03:33 +00:00
|
|
|
|
|
|
|
if (!cogl_is_vertex_buffer_indices (indices_handle))
|
|
|
|
return COGL_INDICES_TYPE_UNSIGNED_SHORT;
|
|
|
|
|
2010-10-12 11:55:23 +00:00
|
|
|
buffer_indices =
|
|
|
|
_cogl_vertex_buffer_indices_pointer_from_handle (indices_handle);
|
2009-06-17 14:03:33 +00:00
|
|
|
|
2010-10-12 11:55:23 +00:00
|
|
|
return cogl_indices_get_type (buffer_indices->indices);
|
2009-06-17 14:03:33 +00:00
|
|
|
}
|
|
|
|
|
2009-05-26 15:27:36 +00:00
|
|
|
void
|
2010-10-12 11:55:23 +00:00
|
|
|
_cogl_vertex_buffer_indices_free (CoglVertexBufferIndices *buffer_indices)
|
2009-05-26 15:27:36 +00:00
|
|
|
{
|
2010-10-12 11:55:23 +00:00
|
|
|
cogl_object_unref (buffer_indices->indices);
|
|
|
|
g_slice_free (CoglVertexBufferIndices, buffer_indices);
|
2009-05-24 03:04:38 +00:00
|
|
|
}
|
|
|
|
|
2008-11-10 18:53:14 +00:00
|
|
|
void
|
2009-05-24 10:33:29 +00:00
|
|
|
cogl_vertex_buffer_draw_elements (CoglHandle handle,
|
|
|
|
CoglVerticesMode mode,
|
2009-05-28 11:49:29 +00:00
|
|
|
CoglHandle indices_handle,
|
|
|
|
int min_index,
|
|
|
|
int max_index,
|
2009-05-24 10:33:29 +00:00
|
|
|
int indices_offset,
|
|
|
|
int count)
|
2008-11-10 18:53:14 +00:00
|
|
|
{
|
2009-01-20 21:12:44 +00:00
|
|
|
CoglVertexBuffer *buffer;
|
2010-10-12 11:55:23 +00:00
|
|
|
CoglVertexBufferIndices *buffer_indices;
|
2009-01-20 21:12:44 +00:00
|
|
|
|
|
|
|
if (!cogl_is_vertex_buffer (handle))
|
2008-11-10 18:53:14 +00:00
|
|
|
return;
|
2009-01-20 21:12:44 +00:00
|
|
|
|
|
|
|
buffer = _cogl_vertex_buffer_pointer_from_handle (handle);
|
|
|
|
|
2009-05-28 11:49:29 +00:00
|
|
|
if (!cogl_is_vertex_buffer_indices (indices_handle))
|
|
|
|
return;
|
|
|
|
|
2010-10-12 11:55:23 +00:00
|
|
|
buffer_indices =
|
|
|
|
_cogl_vertex_buffer_indices_pointer_from_handle (indices_handle);
|
2008-11-10 18:53:14 +00:00
|
|
|
|
2010-10-12 11:55:23 +00:00
|
|
|
update_primitive_and_draw (buffer, mode, indices_offset, count,
|
|
|
|
buffer_indices);
|
2008-11-10 18:53:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2009-01-20 21:12:44 +00:00
|
|
|
_cogl_vertex_buffer_free (CoglVertexBuffer *buffer)
|
2008-11-10 18:53:14 +00:00
|
|
|
{
|
|
|
|
GList *tmp;
|
|
|
|
|
2009-01-20 21:12:44 +00:00
|
|
|
for (tmp = buffer->submitted_vbos; tmp != NULL; tmp = tmp->next)
|
2010-10-12 11:55:23 +00:00
|
|
|
cogl_vertex_buffer_vbo_free (tmp->data);
|
2009-05-24 03:04:38 +00:00
|
|
|
g_list_free (buffer->submitted_vbos);
|
|
|
|
|
2009-01-20 21:12:44 +00:00
|
|
|
for (tmp = buffer->new_attributes; tmp != NULL; tmp = tmp->next)
|
2010-10-12 11:55:23 +00:00
|
|
|
_cogl_vertex_buffer_attrib_free (tmp->data);
|
2009-05-24 03:04:38 +00:00
|
|
|
g_list_free (buffer->new_attributes);
|
|
|
|
|
2010-10-12 11:55:23 +00:00
|
|
|
if (buffer->primitive)
|
|
|
|
cogl_object_unref (buffer->primitive);
|
|
|
|
|
2009-01-20 21:12:44 +00:00
|
|
|
g_slice_free (CoglVertexBuffer, buffer);
|
2008-11-10 18:53:14 +00:00
|
|
|
}
|
2009-05-24 03:04:38 +00:00
|
|
|
|
2009-05-28 12:47:18 +00:00
|
|
|
CoglHandle
|
cogl: improves header and coding style consistency
We've had complaints that our Cogl code/headers are a bit "special" so
this is a first pass at tidying things up by giving them some
consistency. These changes are all consistent with how new code in Cogl
is being written, but the style isn't consistently applied across all
code yet.
There are two parts to this patch; but since each one required a large
amount of effort to maintain tidy indenting it made sense to combine the
changes to reduce the time spent re indenting the same lines.
The first change is to use a consistent style for declaring function
prototypes in headers. Cogl headers now consistently use this style for
prototypes:
return_type
cogl_function_name (CoglType arg0,
CoglType arg1);
Not everyone likes this style, but it seems that most of the currently
active Cogl developers agree on it.
The second change is to constrain the use of redundant glib data types
in Cogl. Uses of gint, guint, gfloat, glong, gulong and gchar have all
been replaced with int, unsigned int, float, long, unsigned long and char
respectively. When talking about pixel data; use of guchar has been
replaced with guint8, otherwise unsigned char can be used.
The glib types that we continue to use for portability are gboolean,
gint{8,16,32,64}, guint{8,16,32,64} and gsize.
The general intention is that Cogl should look palatable to the widest
range of C programmers including those outside the Gnome community so
- especially for the public API - we want to minimize the number of
foreign looking typedefs.
2010-02-10 01:57:32 +00:00
|
|
|
cogl_vertex_buffer_indices_get_for_quads (unsigned int n_indices)
|
2009-05-28 12:47:18 +00:00
|
|
|
{
|
|
|
|
_COGL_GET_CONTEXT (ctx, COGL_INVALID_HANDLE);
|
|
|
|
|
|
|
|
if (n_indices <= 256 / 4 * 6)
|
|
|
|
{
|
2010-10-26 17:56:57 +00:00
|
|
|
if (ctx->quad_buffer_indices_byte == COGL_INVALID_HANDLE)
|
2009-05-28 12:47:18 +00:00
|
|
|
{
|
2010-10-26 17:56:57 +00:00
|
|
|
/* NB: cogl_get_quad_indices takes n_quads not n_indices... */
|
|
|
|
CoglIndices *indices = cogl_get_rectangle_indices (256 / 4);
|
|
|
|
cogl_object_ref (indices);
|
|
|
|
ctx->quad_buffer_indices_byte =
|
|
|
|
_cogl_vertex_buffer_indices_new_real (indices);
|
2009-05-28 12:47:18 +00:00
|
|
|
}
|
|
|
|
|
2010-10-26 17:56:57 +00:00
|
|
|
return ctx->quad_buffer_indices_byte;
|
2009-05-28 12:47:18 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2010-11-16 08:52:49 +00:00
|
|
|
if (ctx->quad_buffer_indices &&
|
|
|
|
ctx->quad_buffer_indices_len < n_indices)
|
2009-05-28 12:47:18 +00:00
|
|
|
{
|
2010-10-26 17:56:57 +00:00
|
|
|
cogl_handle_unref (ctx->quad_buffer_indices);
|
|
|
|
ctx->quad_buffer_indices = COGL_INVALID_HANDLE;
|
|
|
|
}
|
2009-05-28 12:47:18 +00:00
|
|
|
|
2010-10-26 17:56:57 +00:00
|
|
|
if (ctx->quad_buffer_indices == COGL_INVALID_HANDLE)
|
|
|
|
{
|
|
|
|
/* NB: cogl_get_quad_indices takes n_quads not n_indices... */
|
|
|
|
CoglIndices *indices = cogl_get_rectangle_indices (n_indices / 6);
|
|
|
|
cogl_object_ref (indices);
|
|
|
|
ctx->quad_buffer_indices =
|
|
|
|
_cogl_vertex_buffer_indices_new_real (indices);
|
2009-05-28 12:47:18 +00:00
|
|
|
}
|
|
|
|
|
2010-10-26 17:56:57 +00:00
|
|
|
ctx->quad_buffer_indices_len = n_indices;
|
|
|
|
|
|
|
|
return ctx->quad_buffer_indices;
|
2009-05-28 12:47:18 +00:00
|
|
|
}
|
2010-10-26 17:56:57 +00:00
|
|
|
|
|
|
|
g_return_val_if_reached (NULL);
|
2009-05-28 12:47:18 +00:00
|
|
|
}
|
2010-10-26 17:56:57 +00:00
|
|
|
|