diff --git a/cogl-color.h b/cogl-color.h
index 73de891de..6ade2594f 100644
--- a/cogl-color.h
+++ b/cogl-color.h
@@ -240,6 +240,22 @@ float cogl_color_get_alpha (const CoglColor *color);
*/
void cogl_color_premultiply (CoglColor *color);
+/**
+ * cogl_color_equal:
+ * @v1: a #CoglColor
+ * @v2: a #CoglColor
+ *
+ * Compares two #CoglColors and checks if they are the same.
+ *
+ * This function can be passed to g_hash_table_new() as the @key_equal_func
+ * parameter, when using #CoglColors as keys in a #GHashTable.
+ *
+ * Return value: %TRUE if the two colors are the same.
+ *
+ * Since: 1.0
+ */
+gboolean cogl_color_equal (gconstpointer v1, gconstpointer v2);
+
G_END_DECLS
#endif /* __COGL_COLOR_H__ */
diff --git a/cogl-debug.h b/cogl-debug.h
index 8aa1e8f87..0c602909a 100644
--- a/cogl-debug.h
+++ b/cogl-debug.h
@@ -29,16 +29,22 @@
G_BEGIN_DECLS
typedef enum {
- COGL_DEBUG_MISC = 1 << 0,
- COGL_DEBUG_TEXTURE = 1 << 1,
- COGL_DEBUG_MATERIAL = 1 << 2,
- COGL_DEBUG_SHADER = 1 << 3,
- COGL_DEBUG_OFFSCREEN = 1 << 4,
- COGL_DEBUG_DRAW = 1 << 5,
- COGL_DEBUG_PANGO = 1 << 6,
- COGL_DEBUG_RECTANGLES = 1 << 7,
- COGL_DEBUG_HANDLE = 1 << 8,
- COGL_DEBUG_BLEND_STRINGS = 1 << 9
+ COGL_DEBUG_MISC = 1 << 0,
+ COGL_DEBUG_TEXTURE = 1 << 1,
+ COGL_DEBUG_MATERIAL = 1 << 2,
+ COGL_DEBUG_SHADER = 1 << 3,
+ COGL_DEBUG_OFFSCREEN = 1 << 4,
+ COGL_DEBUG_DRAW = 1 << 5,
+ COGL_DEBUG_PANGO = 1 << 6,
+ COGL_DEBUG_RECTANGLES = 1 << 7,
+ COGL_DEBUG_HANDLE = 1 << 8,
+ COGL_DEBUG_BLEND_STRINGS = 1 << 9,
+ COGL_DEBUG_DISABLE_BATCHING = 1 << 10,
+ COGL_DEBUG_FORCE_CLIENT_SIDE_MATRICES = 1 << 11,
+ COGL_DEBUG_DISABLE_VBOS = 1 << 12,
+ COGL_DEBUG_JOURNAL = 1 << 13,
+ COGL_DEBUG_BATCHING = 1 << 14,
+ COGL_DEBUG_DISABLE_SOFTWARE_TRANSFORM = 1 << 15
} CoglDebugFlags;
#ifdef COGL_ENABLE_DEBUG
diff --git a/cogl-material.h b/cogl-material.h
index 786ff344a..94ea5b260 100644
--- a/cogl-material.h
+++ b/cogl-material.h
@@ -673,6 +673,16 @@ void cogl_material_set_layer_matrix (CoglHandle material,
*/
const GList *cogl_material_get_layers (CoglHandle material);
+/**
+ * cogl_material_get_n_layers:
+ * @material: A CoglMaterial object
+ *
+ * Returns: The number of layers defined for the given material
+ *
+ * Since: 1.0
+ */
+int cogl_material_get_n_layers (CoglHandle material);
+
/**
* CoglMaterialLayerType:
* @COGL_MATERIAL_LAYER_TYPE_TEXTURE: The layer represents a
@@ -713,15 +723,6 @@ CoglMaterialLayerType cogl_material_layer_get_type (CoglHandle layer_handle);
* likely return COGL_INVALID_HANDLE if you try to get the texture.
* Considering this, you can call cogl_material_layer_get_type first,
* to check it is of type COGL_MATERIAL_LAYER_TYPE_TEXTURE.
- *
- * Note: It is possible for a layer object of type
- * COGL_MATERIAL_LAYER_TYPE_TEXTURE to be realized before a texture
- * object has been associated with the layer. For example this happens
- * if you setup layer combining for a given layer index before calling
- * cogl_material_set_layer for that index.
- *
- * Returns: A CoglHandle to the layers texture object or COGL_INVALID_HANDLE
- * if a texture has not been set yet.
*/
CoglHandle cogl_material_layer_get_texture (CoglHandle layer_handle);
diff --git a/cogl.h.in b/cogl.h.in
index adc329288..ffa5cce0b 100644
--- a/cogl.h.in
+++ b/cogl.h.in
@@ -724,6 +724,113 @@ void cogl_read_pixels (int x,
CoglPixelFormat format,
guint8 *pixels);
+/**
+ * cogl_flush:
+ *
+ * This function should only need to be called in exceptional circumstances.
+ *
+ * As an optimization Cogl drawing functions may batch up primitives
+ * internally, so if you are trying to use raw GL outside of Cogl you stand a
+ * better chance of being successful if you ask Cogl to flush any batched
+ * geometry before making your state changes.
+ *
+ * It only ensure that the underlying driver is issued all the commands
+ * necessary to draw the batched primitives. It provides no guarantees about
+ * when the driver will complete the rendering.
+ *
+ * This provides no guarantees about the GL state upon returning and to avoid
+ * confusing Cogl you should aim to restore any changes you make before
+ * resuming use of Cogl.
+ *
+ * If you are making state changes with the intention of affecting Cogl drawing
+ * primitives you are 100% on your own since you stand a good chance of
+ * conflicting with Cogl internals. For example clutter-gst which currently
+ * uses direct GL calls to bind ARBfp programs will very likely break when Cogl
+ * starts to use ARBfb programs itself for the material API.
+ *
+ * Since: 1.0
+ */
+void cogl_flush (void);
+
+/**
+ * cogl_begin_gl:
+ *
+ * We do not advise nor reliably support the interleaving of raw GL drawing and
+ * Cogl drawing functions, but if you insist, cogl_begin_gl() and cogl_end_gl()
+ * provide a simple mechanism that may at least give you a fighting chance of
+ * succeeding.
+ *
+ * Note: this doesn't help you modify the behaviour of Cogl drawing functions
+ * through the modification of GL state; that will never be reliably supported,
+ * but if you are trying to do something like:
+ *
+ * {
+ * - setup some OpenGL state.
+ * - draw using OpenGL (e.g. glDrawArrays() )
+ * - reset modified OpenGL state.
+ * - continue using Cogl to draw
+ * }
+ *
+ * You should surround blocks of drawing using raw GL with cogl_begin_gl()
+ * and cogl_end_gl():
+ *
+ * {
+ * cogl_begin_gl ();
+ * - setup some OpenGL state.
+ * - draw using OpenGL (e.g. glDrawArrays() )
+ * - reset modified OpenGL state.
+ * cogl_end_gl ();
+ * - continue using Cogl to draw
+ * }
+ *
+ *
+ * Don't ever try and do:
+ *
+ * {
+ * - setup some OpenGL state.
+ * - use Cogl to draw
+ * - reset modified OpenGL state.
+ * }
+ *
+ * When the internals of Cogl evolves, this is very liable to break.
+ *
+ * This function will flush all batched primitives, and subsequently flush
+ * all internal Cogl state to OpenGL as if it were going to draw something
+ * itself.
+ *
+ * The result is that the OpenGL modelview matrix will be setup; the state
+ * corresponding to the current source material will be set up and other world
+ * state such as backface culling, depth and fogging enabledness will be sent
+ * to OpenGL.
+ *
+ * Note: no special material state is flushed, so if you want Cogl to setup a
+ * simplified material state it is your responsibility to set a simple source
+ * material before calling cogl_begin_gl. E.g. by calling
+ * cogl_set_source_color4ub().
+ *
+ * Note: It is your responsibility to restore any OpenGL state that you modify
+ * to how it was after calling cogl_begin_gl() if you don't do this then the
+ * result of further Cogl calls is undefined.
+ *
+ * Note: You can not nest begin/end blocks.
+ *
+ * Again we would like to stress, we do not advise the use of this API and if
+ * possible we would prefer to improve Cogl than have developers require raw
+ * OpenGL.
+ *
+ * Since: 1.0
+ */
+void cogl_begin_gl (void);
+
+/**
+ * cogl_end_gl:
+ *
+ * This is the counterpart to cogl_begin_gl() used to delimit blocks of drawing
+ * code using raw OpenGL. Please refer to cogl_begin_gl() for full details.
+ *
+ * Since: 1.0
+ */
+void cogl_end_gl (void);
/*
* Internal API available only to Clutter.
diff --git a/common/cogl-clip-stack.c b/common/cogl-clip-stack.c
index 3ef1b2b16..9efa5c22d 100644
--- a/common/cogl-clip-stack.c
+++ b/common/cogl-clip-stack.c
@@ -324,6 +324,10 @@ _cogl_clip_stack_rebuild (void)
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
+ /* The current primitive journal does not support tracking changes to the
+ * clip stack... */
+ _cogl_journal_flush ();
+
stack = (CoglClipStack *) ctx->clip.stacks->data;
ctx->clip.stack_dirty = FALSE;
diff --git a/common/cogl-color.c b/common/cogl-color.c
index df338fcc4..25a1bdaf2 100644
--- a/common/cogl-color.c
+++ b/common/cogl-color.c
@@ -25,6 +25,8 @@
#include "config.h"
#endif
+#include
+
#include "cogl.h"
#include "cogl-color.h"
#include "cogl-fixed.h"
@@ -184,3 +186,16 @@ cogl_set_source_color4f (float red,
cogl_color_set_from_4f (&c, red, green, blue, alpha);
cogl_set_source_color (&c);
}
+
+gboolean
+cogl_color_equal (gconstpointer v1, gconstpointer v2)
+{
+ const guint32 *c1 = v1, *c2 = v2;
+
+ g_return_val_if_fail (v1 != NULL, FALSE);
+ g_return_val_if_fail (v2 != NULL, FALSE);
+
+ /* XXX: We don't compare the padding */
+ return *c1 == *c2 ? TRUE : FALSE;
+}
+
diff --git a/common/cogl-current-matrix.c b/common/cogl-current-matrix.c
index 7c3bc57a3..6f70be880 100644
--- a/common/cogl-current-matrix.c
+++ b/common/cogl-current-matrix.c
@@ -320,7 +320,10 @@ _cogl_current_matrix_state_init (void)
ctx->matrix_mode = COGL_MATRIX_MODELVIEW;
ctx->modelview_stack = NULL;
- if (ctx->indirect)
+#if 0
+ if (ctx->indirect ||
+ cogl_debug_flags & COGL_DEBUG_FORCE_CLIENT_SIDE_MATRICES)
+#endif
{
ctx->modelview_stack =
_cogl_matrix_stack_new ();
diff --git a/common/cogl-debug.c b/common/cogl-debug.c
index b6dfd7559..28c475295 100644
--- a/common/cogl-debug.c
+++ b/common/cogl-debug.c
@@ -40,7 +40,13 @@ static const GDebugKey cogl_debug_keys[] = {
{ "pango", COGL_DEBUG_PANGO },
{ "rectangles", COGL_DEBUG_RECTANGLES },
{ "handle", COGL_DEBUG_HANDLE },
- { "blend-strings", COGL_DEBUG_BLEND_STRINGS }
+ { "blend-strings", COGL_DEBUG_BLEND_STRINGS },
+ { "disable-batching", COGL_DEBUG_DISABLE_BATCHING },
+ { "client-side-matrices", COGL_DEBUG_FORCE_CLIENT_SIDE_MATRICES },
+ { "disable-vbos", COGL_DEBUG_DISABLE_VBOS },
+ { "journal", COGL_DEBUG_JOURNAL },
+ { "batching", COGL_DEBUG_BATCHING },
+ { "disable-software-transform", COGL_DEBUG_DISABLE_SOFTWARE_TRANSFORM }
};
static const gint n_cogl_debug_keys = G_N_ELEMENTS (cogl_debug_keys);
diff --git a/common/cogl-material-private.h b/common/cogl-material-private.h
index e61ab97bd..36763e73e 100644
--- a/common/cogl-material-private.h
+++ b/common/cogl-material-private.h
@@ -36,6 +36,16 @@
typedef struct _CoglMaterial CoglMaterial;
typedef struct _CoglMaterialLayer CoglMaterialLayer;
+typedef enum _CoglMaterialEqualFlags
+{
+ /* Return FALSE if any component of either material isn't set to its
+ * default value. (Note: if the materials have corresponding flush
+ * options indicating that e.g. the material color won't be flushed then
+ * this will not assert a default color value.) */
+ COGL_MATERIAL_EQUAL_FLAGS_ASSERT_ALL_DEFAULTS = 1L<<0,
+
+} CoglMaterialEqualFlags;
+
/* XXX: I don't think gtk-doc supports having private enums so these aren't
* bundled in with CoglMaterialLayerFlags */
typedef enum _CoglMaterialLayerPrivFlags
@@ -90,22 +100,24 @@ struct _CoglMaterialLayer
typedef enum _CoglMaterialFlags
{
- COGL_MATERIAL_FLAG_ENABLE_BLEND = 1L<<0,
- COGL_MATERIAL_FLAG_SHOWN_SAMPLER_WARNING = 1L<<1,
- COGL_MATERIAL_FLAG_DEFAULT_COLOR = 1L<<2,
- COGL_MATERIAL_FLAG_DEFAULT_GL_MATERIAL = 1L<<3,
- COGL_MATERIAL_FLAG_DEFAULT_ALPHA_FUNC = 1L<<4,
- COGL_MATERIAL_FLAG_DEFAULT_BLEND_FUNC = 1L<<5
+ COGL_MATERIAL_FLAG_SHOWN_SAMPLER_WARNING = 1L<<0,
+
+ COGL_MATERIAL_FLAG_DEFAULT_COLOR = 1L<<1,
+ COGL_MATERIAL_FLAG_DEFAULT_GL_MATERIAL = 1L<<2,
+ COGL_MATERIAL_FLAG_DEFAULT_ALPHA_FUNC = 1L<<3,
+ COGL_MATERIAL_FLAG_ENABLE_BLEND = 1L<<4,
+ COGL_MATERIAL_FLAG_DEFAULT_BLEND = 1L<<5
} CoglMaterialFlags;
struct _CoglMaterial
{
CoglHandleObject _parent;
+ gulong journal_ref_count;
gulong flags;
/* If no lighting is enabled; this is the basic material color */
- GLfloat unlit[4];
+ GLubyte unlit[4];
/* Standard OpenGL lighting model attributes */
GLfloat ambient[4];
@@ -130,6 +142,7 @@ struct _CoglMaterial
GLint blend_dst_factor_rgb;
GList *layers;
+ guint n_layers;
};
/*
@@ -183,39 +196,60 @@ typedef enum _CoglMaterialLayerFlags
gulong _cogl_material_layer_get_flags (CoglHandle layer_handle);
/*
- * CoglMaterialFlushOption:
- * @COGL_MATERIAL_FLUSH_FALLBACK_MASK: Follow this by a guin32 mask
- * of the layers that can't be supported with the user supplied texture
- * and need to be replaced with fallback textures. (1 = fallback, and the
- * least significant bit = layer 0)
- * @COGL_MATERIAL_FLUSH_DISABLE_MASK: Follow this by a guint32 mask
- * of the layers that you want to completly disable texturing for
- * (1 = fallback, and the least significant bit = layer 0)
- * @COGL_MATERIAL_FLUSH_LAYER0_OVERRIDE: Follow this by a GLuint OpenGL texture
- * name to override the texture used for layer 0 of the material. This is
- * intended for dealing with sliced textures where you will need to point
- * to each of the texture slices in turn when drawing your geometry.
- * Passing a value of 0 is the same as not passing the option at all.
+ * CoglMaterialFlushFlag:
+ * @COGL_MATERIAL_FLUSH_FALLBACK_MASK: The fallback_layers member is set to
+ * a guint32 mask of the layers that can't be supported with the user
+ * supplied texture and need to be replaced with fallback textures. (1 =
+ * fallback, and the least significant bit = layer 0)
+ * @COGL_MATERIAL_FLUSH_DISABLE_MASK: The disable_layers member is set to
+ * a guint32 mask of the layers that you want to completly disable
+ * texturing for (1 = fallback, and the least significant bit = layer 0)
+ * @COGL_MATERIAL_FLUSH_LAYER0_OVERRIDE: The layer0_override_texture member is
+ * set to a GLuint OpenGL texture name to override the texture used for
+ * layer 0 of the material. This is intended for dealing with sliced
+ * textures where you will need to point to each of the texture slices in
+ * turn when drawing your geometry. Passing a value of 0 is the same as
+ * not passing the option at all.
+ * @COGL_MATERIAL_FLUSH_SKIP_GL_COLOR: When flushing the GL state for the
+ * material don't call glColor.
*/
-typedef enum _CoglMaterialFlushOption
+typedef enum _CoglMaterialFlushFlag
{
- COGL_MATERIAL_FLUSH_FALLBACK_MASK = 1,
- COGL_MATERIAL_FLUSH_DISABLE_MASK,
- COGL_MATERIAL_FLUSH_LAYER0_OVERRIDE,
-} CoglMaterialFlushOption;
+ COGL_MATERIAL_FLUSH_FALLBACK_MASK = 1L<<0,
+ COGL_MATERIAL_FLUSH_DISABLE_MASK = 1L<<1,
+ COGL_MATERIAL_FLUSH_LAYER0_OVERRIDE = 1L<<2,
+ COGL_MATERIAL_FLUSH_SKIP_GL_COLOR = 1L<<3
+} CoglMaterialFlushFlag;
/*
- * cogl_material_flush_gl_state:
- * @material: A CoglMaterial object
- * @...: A NULL terminated list of (CoglMaterialFlushOption, data) pairs
+ * CoglMaterialFlushOptions:
*
- * This function commits the state of the specified CoglMaterial - including
- * the texture state for all the layers - to the OpenGL[ES] driver.
- *
- * Since 1.0
*/
+typedef struct _CoglMaterialFlushOptions
+{
+ CoglMaterialFlushFlag flags;
+
+ guint32 fallback_layers;
+ guint32 disable_layers;
+ GLuint layer0_override_texture;
+} CoglMaterialFlushOptions;
+
+
+
+void _cogl_material_get_colorubv (CoglHandle handle,
+ guint8 *color);
+
void _cogl_material_flush_gl_state (CoglHandle material,
- ...) G_GNUC_NULL_TERMINATED;
+ CoglMaterialFlushOptions *options);
+
+gboolean _cogl_material_equal (CoglHandle material0_handle,
+ CoglMaterialFlushOptions *material0_flush_options,
+ CoglHandle material1_handle,
+ CoglMaterialFlushOptions *material1_flush_options,
+ CoglMaterialEqualFlags flags);
+
+CoglHandle _cogl_material_journal_ref (CoglHandle material_handle);
+void _cogl_material_journal_unref (CoglHandle material_handle);
#endif /* __COGL_MATERIAL_PRIVATE_H */
diff --git a/common/cogl-material.c b/common/cogl-material.c
index d39120be9..453fd23cf 100644
--- a/common/cogl-material.c
+++ b/common/cogl-material.c
@@ -76,14 +76,14 @@ cogl_material_new (void)
{
/* Create new - blank - material */
CoglMaterial *material = g_new0 (CoglMaterial, 1);
- GLfloat *unlit = material->unlit;
+ GLubyte *unlit = material->unlit;
GLfloat *ambient = material->ambient;
GLfloat *diffuse = material->diffuse;
GLfloat *specular = material->specular;
GLfloat *emission = material->emission;
/* Use the same defaults as the GL spec... */
- unlit[0] = 1.0; unlit[1] = 1.0; unlit[2] = 1.0; unlit[3] = 1.0;
+ unlit[0] = 0xff; unlit[1] = 0xff; unlit[2] = 0xff; unlit[3] = 0xff;
material->flags |= COGL_MATERIAL_FLAG_DEFAULT_COLOR;
/* Use the same defaults as the GL spec... */
@@ -111,9 +111,10 @@ cogl_material_new (void)
#endif
material->blend_src_factor_rgb = GL_ONE;
material->blend_dst_factor_rgb = GL_ONE_MINUS_SRC_ALPHA;
- material->flags |= COGL_MATERIAL_FLAG_DEFAULT_BLEND_FUNC;
+ material->flags |= COGL_MATERIAL_FLAG_DEFAULT_BLEND;
material->layers = NULL;
+ material->n_layers = 0;
return _cogl_material_handle_new (material);
}
@@ -130,15 +131,24 @@ _cogl_material_free (CoglMaterial *material)
g_free (material);
}
-static void
-handle_automatic_blend_enable (CoglMaterial *material)
+static gboolean
+_cogl_material_needs_blending_enabled (CoglMaterial *material,
+ GLubyte *override_color)
{
GList *tmp;
/* XXX: If we expose manual control over ENABLE_BLEND, we'll add
* a flag to know when it's user configured, so we don't trash it */
- material->flags &= ~COGL_MATERIAL_FLAG_ENABLE_BLEND;
+ /* XXX: Uncomment this to disable all blending */
+#if 0
+ return;
+#endif
+
+ if ((override_color && override_color[3] != 0xff) ||
+ material->unlit[3] != 0xff)
+ return TRUE;
+
for (tmp = material->layers; tmp != NULL; tmp = tmp->next)
{
CoglMaterialLayer *layer = tmp->data;
@@ -149,13 +159,46 @@ handle_automatic_blend_enable (CoglMaterial *material)
continue;
if (cogl_texture_get_format (layer->texture) & COGL_A_BIT)
- material->flags |= COGL_MATERIAL_FLAG_ENABLE_BLEND;
+ return TRUE;
}
- if (material->unlit[3] != 1.0)
+ return FALSE;
+}
+
+static void
+handle_automatic_blend_enable (CoglMaterial *material)
+{
+ material->flags &= ~COGL_MATERIAL_FLAG_ENABLE_BLEND;
+
+ if (_cogl_material_needs_blending_enabled (material, NULL))
material->flags |= COGL_MATERIAL_FLAG_ENABLE_BLEND;
}
+/* If primitives have been logged in the journal referencing the current
+ * state of this material we need to flush the journal before we can
+ * modify it... */
+static void
+_cogl_material_pre_change_notify (CoglMaterial *material,
+ gboolean only_color_change,
+ GLubyte *new_color)
+{
+ /* XXX: We don't usually need to flush the journal just due to color changes
+ * since material colors are logged in the journals vertex buffer. The
+ * exception is when the change in color enables or disables the need for
+ * blending. */
+ if (only_color_change)
+ {
+ gboolean will_need_blending =
+ _cogl_material_needs_blending_enabled (material, new_color);
+ if (will_need_blending ==
+ (material->flags & COGL_MATERIAL_FLAG_ENABLE_BLEND) ? TRUE : FALSE)
+ return;
+ }
+
+ if (material->journal_ref_count)
+ _cogl_journal_flush ();
+}
+
void
cogl_material_get_color (CoglHandle handle,
CoglColor *color)
@@ -166,11 +209,20 @@ cogl_material_get_color (CoglHandle handle,
material = _cogl_material_pointer_from_handle (handle);
- cogl_color_set_from_4f (color,
- material->unlit[0],
- material->unlit[1],
- material->unlit[2],
- material->unlit[3]);
+ cogl_color_set_from_4ub (color,
+ material->unlit[0],
+ material->unlit[1],
+ material->unlit[2],
+ material->unlit[3]);
+}
+
+/* This is used heavily by the cogl journal when logging quads */
+void
+_cogl_material_get_colorubv (CoglHandle handle,
+ guint8 *color)
+{
+ CoglMaterial *material = _cogl_material_pointer_from_handle (handle);
+ memcpy (color, material->unlit, 4);
}
void
@@ -178,26 +230,29 @@ cogl_material_set_color (CoglHandle handle,
const CoglColor *unlit_color)
{
CoglMaterial *material;
- GLfloat unlit[4];
+ GLubyte unlit[4];
g_return_if_fail (cogl_is_material (handle));
material = _cogl_material_pointer_from_handle (handle);
- unlit[0] = cogl_color_get_red_float (unlit_color);
- unlit[1] = cogl_color_get_green_float (unlit_color);
- unlit[2] = cogl_color_get_blue_float (unlit_color);
- unlit[3] = cogl_color_get_alpha_float (unlit_color);
+ unlit[0] = cogl_color_get_red_byte (unlit_color);
+ unlit[1] = cogl_color_get_green_byte (unlit_color);
+ unlit[2] = cogl_color_get_blue_byte (unlit_color);
+ unlit[3] = cogl_color_get_alpha_byte (unlit_color);
if (memcmp (unlit, material->unlit, sizeof (unlit)) == 0)
return;
+ /* possibly flush primitives referencing the current state... */
+ _cogl_material_pre_change_notify (material, TRUE, unlit);
+
memcpy (material->unlit, unlit, sizeof (unlit));
material->flags &= ~COGL_MATERIAL_FLAG_DEFAULT_COLOR;
- if (unlit[0] == 1.0 &&
- unlit[1] == 1.0 &&
- unlit[2] == 1.0 &&
- unlit[3] == 1.0)
+ if (unlit[0] == 0xff &&
+ unlit[1] == 0xff &&
+ unlit[2] == 0xff &&
+ unlit[3] == 0xff)
material->flags |= COGL_MATERIAL_FLAG_DEFAULT_COLOR;
handle_automatic_blend_enable (material);
@@ -255,6 +310,9 @@ cogl_material_set_ambient (CoglHandle handle,
material = _cogl_material_pointer_from_handle (handle);
+ /* possibly flush primitives referencing the current state... */
+ _cogl_material_pre_change_notify (material, FALSE, NULL);
+
ambient = material->ambient;
ambient[0] = cogl_color_get_red_float (ambient_color);
ambient[1] = cogl_color_get_green_float (ambient_color);
@@ -292,6 +350,9 @@ cogl_material_set_diffuse (CoglHandle handle,
material = _cogl_material_pointer_from_handle (handle);
+ /* possibly flush primitives referencing the current state... */
+ _cogl_material_pre_change_notify (material, FALSE, NULL);
+
diffuse = material->diffuse;
diffuse[0] = cogl_color_get_red_float (diffuse_color);
diffuse[1] = cogl_color_get_green_float (diffuse_color);
@@ -337,6 +398,9 @@ cogl_material_set_specular (CoglHandle handle,
material = _cogl_material_pointer_from_handle (handle);
+ /* possibly flush primitives referencing the current state... */
+ _cogl_material_pre_change_notify (material, FALSE, NULL);
+
specular = material->specular;
specular[0] = cogl_color_get_red_float (specular_color);
specular[1] = cogl_color_get_green_float (specular_color);
@@ -372,6 +436,9 @@ cogl_material_set_shininess (CoglHandle handle,
material = _cogl_material_pointer_from_handle (handle);
+ /* possibly flush primitives referencing the current state... */
+ _cogl_material_pre_change_notify (material, FALSE, NULL);
+
material->shininess = (GLfloat)shininess * 128.0;
material->flags &= ~COGL_MATERIAL_FLAG_DEFAULT_GL_MATERIAL;
@@ -405,6 +472,9 @@ cogl_material_set_emission (CoglHandle handle,
material = _cogl_material_pointer_from_handle (handle);
+ /* possibly flush primitives referencing the current state... */
+ _cogl_material_pre_change_notify (material, FALSE, NULL);
+
emission = material->emission;
emission[0] = cogl_color_get_red_float (emission_color);
emission[1] = cogl_color_get_green_float (emission_color);
@@ -424,6 +494,10 @@ cogl_material_set_alpha_test_function (CoglHandle handle,
g_return_if_fail (cogl_is_material (handle));
material = _cogl_material_pointer_from_handle (handle);
+
+ /* possibly flush primitives referencing the current state... */
+ _cogl_material_pre_change_notify (material, FALSE, NULL);
+
material->alpha_func = alpha_func;
material->alpha_func_reference = (GLfloat)alpha_reference;
@@ -571,6 +645,9 @@ cogl_material_set_blend (CoglHandle handle,
a = &statements[1];
}
+ /* possibly flush primitives referencing the current state... */
+ _cogl_material_pre_change_notify (material, FALSE, NULL);
+
#ifndef HAVE_COGL_GLES
setup_blend_state (rgb,
&material->blend_equation_rgb,
@@ -587,7 +664,7 @@ cogl_material_set_blend (CoglHandle handle,
&material->blend_dst_factor_rgb);
#endif
- material->flags &= ~COGL_MATERIAL_FLAG_DEFAULT_BLEND_FUNC;
+ material->flags &= ~COGL_MATERIAL_FLAG_DEFAULT_BLEND;
return TRUE;
}
@@ -604,13 +681,16 @@ cogl_material_set_blend_constant (CoglHandle handle,
material = _cogl_material_pointer_from_handle (handle);
+ /* possibly flush primitives referencing the current state... */
+ _cogl_material_pre_change_notify (material, FALSE, NULL);
+
constant = material->blend_constant;
constant[0] = cogl_color_get_red_float (constant_color);
constant[1] = cogl_color_get_green_float (constant_color);
constant[2] = cogl_color_get_blue_float (constant_color);
constant[3] = cogl_color_get_alpha_float (constant_color);
- material->flags &= ~COGL_MATERIAL_FLAG_DEFAULT_BLEND_FUNC;
+ material->flags &= ~COGL_MATERIAL_FLAG_DEFAULT_BLEND;
#endif
}
@@ -644,6 +724,9 @@ _cogl_material_get_layer (CoglMaterial *material,
if (!create_if_not_found)
return NULL;
+ /* possibly flush primitives referencing the current state... */
+ _cogl_material_pre_change_notify (material, FALSE, NULL);
+
layer = g_new0 (CoglMaterialLayer, 1);
layer_handle = _cogl_material_layer_handle_new (layer);
@@ -682,20 +765,23 @@ cogl_material_set_layer (CoglHandle material_handle,
{
CoglMaterial *material;
CoglMaterialLayer *layer;
- int n_layers;
g_return_if_fail (cogl_is_material (material_handle));
g_return_if_fail (texture_handle == COGL_INVALID_HANDLE
|| cogl_is_texture (texture_handle));
material = _cogl_material_pointer_from_handle (material_handle);
+
layer = _cogl_material_get_layer (material_handle, layer_index, TRUE);
if (texture_handle == layer->texture)
return;
- n_layers = g_list_length (material->layers);
- if (n_layers >= CGL_MAX_COMBINED_TEXTURE_IMAGE_UNITS)
+ /* possibly flush primitives referencing the current state... */
+ _cogl_material_pre_change_notify (material, FALSE, NULL);
+
+ material->n_layers = g_list_length (material->layers);
+ if (material->n_layers >= CGL_MAX_COMBINED_TEXTURE_IMAGE_UNITS)
{
if (!(material->flags & COGL_MATERIAL_FLAG_SHOWN_SAMPLER_WARNING))
{
@@ -856,6 +942,9 @@ cogl_material_set_layer_combine (CoglHandle handle,
a = &statements[1];
}
+ /* possibly flush primitives referencing the current state... */
+ _cogl_material_pre_change_notify (material, FALSE, NULL);
+
setup_texture_combine_state (rgb,
&layer->texture_combine_rgb_func,
layer->texture_combine_rgb_src,
@@ -886,6 +975,9 @@ cogl_material_set_layer_combine_constant (CoglHandle handle,
material = _cogl_material_pointer_from_handle (handle);
layer = _cogl_material_get_layer (material, layer_index, TRUE);
+ /* possibly flush primitives referencing the current state... */
+ _cogl_material_pre_change_notify (material, FALSE, NULL);
+
constant = layer->texture_combine_constant;
constant[0] = cogl_color_get_red_float (constant_color);
constant[1] = cogl_color_get_green_float (constant_color);
@@ -909,6 +1001,9 @@ cogl_material_set_layer_matrix (CoglHandle material_handle,
material = _cogl_material_pointer_from_handle (material_handle);
layer = _cogl_material_get_layer (material, layer_index, TRUE);
+ /* possibly flush primitives referencing the current state... */
+ _cogl_material_pre_change_notify (material, FALSE, NULL);
+
layer->matrix = *matrix;
layer->flags |= COGL_MATERIAL_LAYER_FLAG_DIRTY;
@@ -931,18 +1026,29 @@ cogl_material_remove_layer (CoglHandle material_handle,
CoglMaterial *material;
CoglMaterialLayer *layer;
GList *tmp;
+ gboolean notified_change = FALSE;
g_return_if_fail (cogl_is_material (material_handle));
material = _cogl_material_pointer_from_handle (material_handle);
+
for (tmp = material->layers; tmp != NULL; tmp = tmp->next)
{
layer = tmp->data;
if (layer->index == layer_index)
{
CoglHandle handle = (CoglHandle) layer;
+
+ /* possibly flush primitives referencing the current state... */
+ if (!notified_change)
+ {
+ _cogl_material_pre_change_notify (material, FALSE, NULL);
+ notified_change = TRUE;
+ }
+
cogl_handle_unref (handle);
material->layers = g_list_remove (material->layers, layer);
+ material->n_layers--;
break;
}
}
@@ -992,6 +1098,18 @@ cogl_material_get_layers (CoglHandle material_handle)
return material->layers;
}
+int
+cogl_material_get_n_layers (CoglHandle material_handle)
+{
+ CoglMaterial *material;
+
+ g_return_val_if_fail (cogl_is_material (material_handle), 0);
+
+ material = _cogl_material_pointer_from_handle (material_handle);
+
+ return material->n_layers;
+}
+
CoglMaterialLayerType
cogl_material_layer_get_type (CoglHandle layer_handle)
{
@@ -1318,7 +1436,10 @@ _cogl_material_flush_layers_gl_state (CoglMaterial *material,
!gl_layer_info->disabled))
#endif
{
+ /* XXX: Debug: Comment this out to disable all texturing: */
+#if 1
GE (glEnable (gl_target));
+#endif
}
}
else
@@ -1369,18 +1490,30 @@ _cogl_material_flush_layers_gl_state (CoglMaterial *material,
}
static void
-_cogl_material_flush_base_gl_state (CoglMaterial *material)
+_cogl_material_flush_base_gl_state (CoglMaterial *material,
+ gboolean skip_gl_color)
{
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
- if (!(ctx->current_material_flags & COGL_MATERIAL_FLAG_DEFAULT_COLOR
- && material->flags & COGL_MATERIAL_FLAG_DEFAULT_COLOR))
+ /* XXX:
+ * Currently we only don't update state when the flags indicate that the
+ * current material uses the defaults, and the new material also uses the
+ * defaults, but we could do deeper comparisons of state. */
+
+ if (!skip_gl_color)
{
- /* GLES doesn't have glColor4fv... */
- GE (glColor4f (material->unlit[0],
- material->unlit[1],
- material->unlit[2],
- material->unlit[3]));
+ if (!(ctx->current_material_flags & COGL_MATERIAL_FLAG_DEFAULT_COLOR
+ && material->flags & COGL_MATERIAL_FLAG_DEFAULT_COLOR) ||
+ /* Assume if we were previously told to skip the color, then
+ * the current color needs updating... */
+ ctx->current_material_flush_options.flags &
+ COGL_MATERIAL_FLUSH_SKIP_GL_COLOR)
+ {
+ GE (glColor4ub (material->unlit[0],
+ material->unlit[1],
+ material->unlit[2],
+ material->unlit[3]));
+ }
}
if (!(ctx->current_material_flags & COGL_MATERIAL_FLAG_DEFAULT_GL_MATERIAL
@@ -1401,8 +1534,8 @@ _cogl_material_flush_base_gl_state (CoglMaterial *material)
GE (glAlphaFunc (material->alpha_func, material->alpha_func_reference));
}
- if (!(ctx->current_material_flags & COGL_MATERIAL_FLAG_DEFAULT_BLEND_FUNC
- && material->flags & COGL_MATERIAL_FLAG_DEFAULT_BLEND_FUNC))
+ if (!(ctx->current_material_flags & COGL_MATERIAL_FLAG_DEFAULT_BLEND
+ && material->flags & COGL_MATERIAL_FLAG_DEFAULT_BLEND))
{
#if defined (HAVE_COGL_GLES2)
gboolean have_blend_equation_seperate = TRUE;
@@ -1441,32 +1574,33 @@ _cogl_material_flush_base_gl_state (CoglMaterial *material)
}
void
-_cogl_material_flush_gl_state (CoglHandle handle, ...)
+_cogl_material_flush_gl_state (CoglHandle handle,
+ CoglMaterialFlushOptions *options)
{
- CoglMaterial *material;
- va_list ap;
- CoglMaterialFlushOption option;
- guint32 fallback_layers = 0;
- guint32 disable_layers = 0;
- GLuint layer0_override_texture = 0;
+ CoglMaterial *material;
+ guint32 fallback_layers = 0;
+ guint32 disable_layers = 0;
+ GLuint layer0_override_texture = 0;
+ gboolean skip_gl_color = FALSE;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
material = _cogl_material_pointer_from_handle (handle);
- _cogl_material_flush_base_gl_state (material);
-
- va_start (ap, handle);
- while ((option = va_arg (ap, CoglMaterialFlushOption)))
+ if (options)
{
- if (option == COGL_MATERIAL_FLUSH_FALLBACK_MASK)
- fallback_layers = va_arg (ap, guint32);
- else if (option == COGL_MATERIAL_FLUSH_DISABLE_MASK)
- disable_layers = va_arg (ap, guint32);
- else if (option == COGL_MATERIAL_FLUSH_LAYER0_OVERRIDE)
- layer0_override_texture = va_arg (ap, GLuint);
+ if (options->flags & COGL_MATERIAL_FLUSH_FALLBACK_MASK)
+ fallback_layers = options->fallback_layers;
+ if (options->flags & COGL_MATERIAL_FLUSH_DISABLE_MASK)
+ disable_layers = options->disable_layers;
+ if (options->flags & COGL_MATERIAL_FLUSH_LAYER0_OVERRIDE)
+ layer0_override_texture = options->layer0_override_texture;
+ if (options->flags & COGL_MATERIAL_FLUSH_SKIP_GL_COLOR)
+ skip_gl_color = TRUE;
}
- va_end (ap);
+
+ _cogl_material_flush_base_gl_state (material,
+ skip_gl_color);
_cogl_material_flush_layers_gl_state (material,
fallback_layers,
@@ -1483,6 +1617,162 @@ _cogl_material_flush_gl_state (CoglHandle handle, ...)
ctx->current_material = handle;
ctx->current_material_flags = material->flags;
+ if (options)
+ ctx->current_material_flush_options = *options;
+ else
+ memset (&ctx->current_material_flush_options,
+ 0, sizeof (CoglMaterialFlushOptions));
+}
+
+gboolean
+_cogl_material_equal (CoglHandle material0_handle,
+ CoglMaterialFlushOptions *material0_flush_options,
+ CoglHandle material1_handle,
+ CoglMaterialFlushOptions *material1_flush_options,
+ CoglMaterialEqualFlags flags)
+{
+ CoglMaterial *material0;
+ CoglMaterial *material1;
+ GList *l0, *l1;
+
+ if (material0_handle == material1_handle &&
+ material0_flush_options->flags == material1_flush_options->flags)
+ return TRUE;
+
+ if (!(flags & COGL_MATERIAL_EQUAL_FLAGS_ASSERT_ALL_DEFAULTS))
+ {
+ g_critical ("FIXME: _cogl_material_equal doesn't yet support "
+ "deep comparisons of materials");
+ return FALSE;
+ }
+ /* Note: the following code is written with the assumption this
+ * constraint will go away*/
+
+ material0 = _cogl_material_pointer_from_handle (material0_handle);
+ material1 = _cogl_material_pointer_from_handle (material1_handle);
+
+ if (!((material0_flush_options->flags & COGL_MATERIAL_FLUSH_SKIP_GL_COLOR &&
+ material1_flush_options->flags & COGL_MATERIAL_FLUSH_SKIP_GL_COLOR)))
+ {
+ if ((material0->flags & COGL_MATERIAL_FLAG_DEFAULT_COLOR) !=
+ (material1->flags & COGL_MATERIAL_FLAG_DEFAULT_COLOR))
+ return FALSE;
+ else if (flags & COGL_MATERIAL_EQUAL_FLAGS_ASSERT_ALL_DEFAULTS &&
+ !(material0->flags & COGL_MATERIAL_FLAG_DEFAULT_COLOR))
+ return FALSE;
+ else if (!memcmp (material0->unlit, material1->unlit,
+ sizeof (material0->unlit)))
+ return FALSE;
+ }
+
+ if ((material0->flags & COGL_MATERIAL_FLAG_DEFAULT_GL_MATERIAL) !=
+ (material1->flags & COGL_MATERIAL_FLAG_DEFAULT_GL_MATERIAL))
+ return FALSE;
+ else if (flags & COGL_MATERIAL_EQUAL_FLAGS_ASSERT_ALL_DEFAULTS &&
+ !(material0->flags & COGL_MATERIAL_FLAG_DEFAULT_GL_MATERIAL))
+ return FALSE;
+#if 0
+ else if (!_deep_are_gl_materials_equal ())
+ return FALSE;
+#endif
+
+ if ((material0->flags & COGL_MATERIAL_FLAG_DEFAULT_ALPHA_FUNC) !=
+ (material1->flags & COGL_MATERIAL_FLAG_DEFAULT_ALPHA_FUNC))
+ return FALSE;
+ else if (flags & COGL_MATERIAL_EQUAL_FLAGS_ASSERT_ALL_DEFAULTS &&
+ !(material0->flags & COGL_MATERIAL_FLAG_DEFAULT_ALPHA_FUNC))
+ return FALSE;
+#if 0
+ else if (!_deep_are_alpha_funcs_equal ())
+ return FALSE;
+#endif
+
+ if ((material0->flags & COGL_MATERIAL_FLAG_ENABLE_BLEND) !=
+ (material1->flags & COGL_MATERIAL_FLAG_ENABLE_BLEND))
+ return FALSE;
+ /* XXX: potentially blending could be "enabled" but the blend mode
+ * could be equivalent to being disabled. */
+
+ if (material0->flags & COGL_MATERIAL_FLAG_ENABLE_BLEND)
+ {
+ if ((material0->flags & COGL_MATERIAL_FLAG_DEFAULT_BLEND) !=
+ (material1->flags & COGL_MATERIAL_FLAG_DEFAULT_BLEND))
+ return FALSE;
+ else if (flags & COGL_MATERIAL_EQUAL_FLAGS_ASSERT_ALL_DEFAULTS &&
+ !(material0->flags & COGL_MATERIAL_FLAG_DEFAULT_BLEND))
+ return FALSE;
+#if 0
+ else if (!_deep_is_blend_equal ())
+ return FALSE;
+#endif
+ }
+
+ if (material0_flush_options->fallback_layers !=
+ material1_flush_options->fallback_layers ||
+ material0_flush_options->disable_layers !=
+ material1_flush_options->disable_layers)
+ return FALSE;
+
+ l0 = material0->layers;
+ l1 = material1->layers;
+
+ while (l0 && l1)
+ {
+ CoglMaterialLayer *layer0;
+ CoglMaterialLayer *layer1;
+
+ if ((l0 == NULL && l1 != NULL) ||
+ (l1 == NULL && l0 != NULL))
+ return FALSE;
+
+ layer0 = l0->data;
+ layer1 = l1->data;
+
+ if (layer0->texture != layer1->texture)
+ return FALSE;
+
+ if ((layer0->flags & COGL_MATERIAL_LAYER_FLAG_DEFAULT_COMBINE) !=
+ (layer1->flags & COGL_MATERIAL_LAYER_FLAG_DEFAULT_COMBINE))
+ return FALSE;
+ else if (flags & COGL_MATERIAL_EQUAL_FLAGS_ASSERT_ALL_DEFAULTS &&
+ !(layer0->flags & COGL_MATERIAL_LAYER_FLAG_DEFAULT_COMBINE))
+ return FALSE;
+#if 0
+ else if (!_deep_are_layer_combines_equal ())
+ return FALSE;
+#endif
+
+ l0 = l0->next;
+ l1 = l1->next;
+ }
+
+ if ((l0 == NULL && l1 != NULL) ||
+ (l1 == NULL && l0 != NULL))
+ return FALSE;
+
+ return TRUE;
+}
+
+/* While a material is referenced by the Cogl journal we can not allow
+ * modifications, so this gives us a mechanism to track journal
+ * references separately */
+CoglHandle
+_cogl_material_journal_ref (CoglHandle material_handle)
+{
+ CoglMaterial *material =
+ material = _cogl_material_pointer_from_handle (material_handle);
+ material->journal_ref_count++;
+ cogl_handle_ref (material_handle);
+ return material_handle;
+}
+
+void
+_cogl_material_journal_unref (CoglHandle material_handle)
+{
+ CoglMaterial *material =
+ material = _cogl_material_pointer_from_handle (material_handle);
+ material->journal_ref_count--;
+ cogl_handle_unref (material_handle);
}
/* TODO: Should go in cogl.c, but that implies duplication which is also
@@ -1558,6 +1848,9 @@ cogl_material_set_layer_filters (CoglHandle handle,
material = _cogl_material_pointer_from_handle (handle);
layer = _cogl_material_get_layer (material, layer_index, TRUE);
+ /* possibly flush primitives referencing the current state... */
+ _cogl_material_pre_change_notify (material, FALSE, NULL);
+
layer->min_filter = min_filter;
layer->mag_filter = mag_filter;
}
diff --git a/common/cogl-primitives.c b/common/cogl-primitives.c
index dafe92fa4..dcef4547f 100644
--- a/common/cogl-primitives.c
+++ b/common/cogl-primitives.c
@@ -40,10 +40,69 @@
#ifdef HAVE_COGL_GL
+#define glGenBuffers ctx->pf_glGenBuffersARB
+#define glBindBuffer ctx->pf_glBindBufferARB
+#define glBufferData ctx->pf_glBufferDataARB
+#define glBufferSubData ctx->pf_glBufferSubDataARB
+#define glDeleteBuffers ctx->pf_glDeleteBuffersARB
#define glClientActiveTexture ctx->pf_glClientActiveTexture
+#elif defined (HAVE_COGL_GLES2)
+
+#include "../gles/cogl-gles2-wrapper.h"
+
#endif
+
+/* XXX NB:
+ * Our journal's vertex data is arranged as follows:
+ * 4 vertices per quad:
+ * 2 or 3 GLfloats per position (3 when doing software transforms)
+ * 4 RGBA GLubytes,
+ * 2 GLfloats per tex coord * n_layers
+ *
+ * Where n_layers corresponds to the number of material layers enabled
+ *
+ * To avoid frequent changes in the stride of our vertex data we always pad
+ * n_layers to be >= 2
+ *
+ * When we are transforming quads in software we need to also track the z
+ * coordinate of transformed vertices.
+ *
+ * So for a given number of layers this gets the stride in 32bit words:
+ */
+#define SW_TRANSFORM (!(cogl_debug_flags & \
+ COGL_DEBUG_DISABLE_SOFTWARE_TRANSFORM))
+#define POS_STRIDE (SW_TRANSFORM ? 3 : 2) /* number of 32bit words */
+#define N_POS_COMPONENTS POS_STRIDE
+#define COLOR_STRIDE 1 /* number of 32bit words */
+#define TEX_STRIDE 2 /* number of 32bit words */
+#define MIN_LAYER_PADING 2
+#define GET_JOURNAL_VB_STRIDE_FOR_N_LAYERS(N_LAYERS) \
+ (POS_STRIDE + COLOR_STRIDE + \
+ TEX_STRIDE * (N_LAYERS < MIN_LAYER_PADING ? MIN_LAYER_PADING : N_LAYERS))
+
+
+typedef void (*CoglJournalBatchCallback) (CoglJournalEntry *start,
+ int n_entries,
+ void *data);
+typedef gboolean (*CoglJournalBatchTest) (CoglJournalEntry *entry0,
+ CoglJournalEntry *entry1);
+
+typedef struct _CoglJournalFlushState
+{
+ size_t stride;
+ /* Note: this is a pointer to handle fallbacks. It normally holds a VBO
+ * offset, but when the driver doesn't support VBOs then this points into
+ * our GArray of logged vertices. */
+ char * vbo_offset;
+ GLuint vertex_offset;
+#ifndef HAVE_COGL_GL
+ CoglJournalIndices *indices;
+ size_t indices_type_size;
+#endif
+} CoglJournalFlushState;
+
/* these are defined in the particular backend */
void _cogl_path_add_node (gboolean new_sub_path,
float x,
@@ -51,94 +110,118 @@ void _cogl_path_add_node (gboolean new_sub_path,
void _cogl_path_fill_nodes ();
void _cogl_path_stroke_nodes ();
-static void
-_cogl_journal_flush_quad_batch (CoglJournalEntry *batch_start,
- gint batch_len,
- GLfloat *vertex_pointer)
+void
+_cogl_journal_dump_quad_vertices (guint8 *data, int n_layers)
{
- gsize stride;
- int i;
- gulong enable_flags = 0;
- guint32 disable_mask;
- int prev_n_texcoord_arrays_enabled;
+ size_t stride = GET_JOURNAL_VB_STRIDE_FOR_N_LAYERS (n_layers);
+ int i;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
- /* XXX NB:
- * Our vertex data is arranged as follows:
- * 4 vertices per quad: 2 GLfloats per position,
- * 2 GLfloats per tex coord * n_layers
- */
- stride = 2 + 2 * batch_start->n_layers;
- stride *= sizeof (GLfloat);
+ g_print ("n_layers = %d; stride = %d; pos stride = %d; color stride = %d; "
+ "tex stride = %d; stride in bytes = %d\n",
+ n_layers, (int)stride, POS_STRIDE, COLOR_STRIDE,
+ TEX_STRIDE, (int)stride * 4);
- disable_mask = (1 << batch_start->n_layers) - 1;
- disable_mask = ~disable_mask;
-
- _cogl_material_flush_gl_state (ctx->source_material,
- COGL_MATERIAL_FLUSH_FALLBACK_MASK,
- batch_start->fallback_mask,
- COGL_MATERIAL_FLUSH_DISABLE_MASK,
- disable_mask,
- /* Redundant when dealing with unsliced
- * textures but does no harm... */
- COGL_MATERIAL_FLUSH_LAYER0_OVERRIDE,
- batch_start->layer0_override_texture,
- NULL);
-
- for (i = 0; i < batch_start->n_layers; i++)
+ for (i = 0; i < 4; i++)
{
- GE (glClientActiveTexture (GL_TEXTURE0 + i));
- GE (glEnableClientState (GL_TEXTURE_COORD_ARRAY));
- GE (glTexCoordPointer (2, GL_FLOAT, stride, vertex_pointer + 2 + 2 * i));
+ float *v = (float *)data + (i * stride);
+ guint8 *c = data + (POS_STRIDE * 4) + (i * stride * 4);
+ int j;
+
+ if (cogl_debug_flags & COGL_DEBUG_DISABLE_SOFTWARE_TRANSFORM)
+ g_print ("v%d: x = %f, y = %f, rgba=0x%02X%02X%02X%02X",
+ i, v[0], v[1], c[0], c[1], c[2], c[3]);
+ else
+ g_print ("v%d: x = %f, y = %f, z = %f, rgba=0x%02X%02X%02X%02X",
+ i, v[0], v[1], v[2], c[0], c[1], c[2], c[3]);
+ for (j = 0; j < n_layers; j++)
+ {
+ float *t = v + POS_STRIDE + COLOR_STRIDE + TEX_STRIDE * j;
+ g_print (", tx%d = %f, ty%d = %f", j, t[0], j, t[1]);
+ }
+ g_print ("\n");
}
- prev_n_texcoord_arrays_enabled =
- ctx->n_texcoord_arrays_enabled;
- ctx->n_texcoord_arrays_enabled = batch_start->n_layers;
- for (; i < prev_n_texcoord_arrays_enabled; i++)
+}
+
+void
+_cogl_journal_dump_quad_batch (guint8 *data, int n_layers, int n_quads)
+{
+ size_t byte_stride = GET_JOURNAL_VB_STRIDE_FOR_N_LAYERS (n_layers) * 4;
+ int i;
+
+ g_print ("_cogl_journal_dump_quad_batch: n_layers = %d, n_quads = %d\n",
+ n_layers, n_quads);
+ for (i = 0; i < n_quads; i++)
+ _cogl_journal_dump_quad_vertices (data + byte_stride * 4 * i, n_layers);
+}
+
+static void
+batch_and_call (CoglJournalEntry *entries,
+ int n_entries,
+ CoglJournalBatchTest can_batch_callback,
+ CoglJournalBatchCallback batch_callback,
+ void *data)
+{
+ int i;
+ int batch_len = 1;
+ CoglJournalEntry *batch_start = entries;
+
+ for (i = 1; i < n_entries; i++)
{
- GE (glClientActiveTexture (GL_TEXTURE0 + i));
- GE (glDisableClientState (GL_TEXTURE_COORD_ARRAY));
+ CoglJournalEntry *entry0 = &entries[i - 1];
+ CoglJournalEntry *entry1 = entry0 + 1;
+
+ if (can_batch_callback (entry0, entry1))
+ {
+ batch_len++;
+ continue;
+ }
+
+ batch_callback (batch_start, batch_len, data);
+
+ batch_start = entry1;
+ batch_len = 1;
}
- /* FIXME: This api is a bit yukky, ideally it will be removed if we
- * re-work the cogl_enable mechanism */
- enable_flags |= _cogl_material_get_cogl_enable_flags (ctx->source_material);
+ /* The last batch... */
+ batch_callback (batch_start, batch_len, data);
+}
- if (ctx->enable_backface_culling)
- enable_flags |= COGL_ENABLE_BACKFACE_CULLING;
+static void
+_cogl_journal_flush_modelview_and_entries (CoglJournalEntry *batch_start,
+ int batch_len,
+ void *data)
+{
+ CoglJournalFlushState *state = data;
- enable_flags |= COGL_ENABLE_VERTEX_ARRAY;
- cogl_enable (enable_flags);
+ if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_BATCHING))
+ g_print ("BATCHING: modelview batch len = %d\n", batch_len);
- GE (glVertexPointer (2, GL_FLOAT, stride, vertex_pointer));
- _cogl_current_matrix_state_flush ();
+ if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_DISABLE_SOFTWARE_TRANSFORM))
+ GE (glLoadMatrixf ((GLfloat *)&batch_start->model_view));
#ifdef HAVE_COGL_GL
- GE( glDrawArrays (GL_QUADS, 0, batch_len * 4) );
+ GE (glDrawArrays (GL_QUADS, state->vertex_offset, batch_len * 4));
#else /* HAVE_COGL_GL */
- /* GLES doesn't support GL_QUADS so we will use GL_TRIANGLES and
- indices */
- {
- int needed_indices = batch_len * 6;
- CoglHandle indices_handle
- = cogl_vertex_buffer_indices_get_for_quads (needed_indices);
- CoglVertexBufferIndices *indices
- = _cogl_vertex_buffer_indices_pointer_from_handle (indices_handle);
-
- GE (glBindBuffer (GL_ELEMENT_ARRAY_BUFFER,
- GPOINTER_TO_UINT (indices->vbo_name)));
- GE (glDrawElements (GL_TRIANGLES,
- 6 * batch_len,
- indices->type,
- NULL));
- GE (glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, 0));
- }
-
-#endif /* HAVE_COGL_GL */
+ if (batch_len > 1)
+ {
+ int indices_offset = (state->vertex_offset / 4) * 6;
+ GE (glDrawElements (GL_TRIANGLES,
+ 6 * batch_len,
+ indices->type,
+ indices_offset * state->indices_type_size));
+ }
+ else
+ {
+ GE (glDrawArrays (GL_TRIANGLE_FAN,
+ state->vertex_offset, /* first */
+ 4)); /* n vertices */
+ }
+#endif
/* DEBUGGING CODE XXX:
* This path will cause all rectangles to be drawn with a red, green
@@ -149,6 +232,7 @@ _cogl_journal_flush_quad_batch (CoglJournalEntry *batch_start,
{
static CoglHandle outline = COGL_INVALID_HANDLE;
static int color = 0;
+ int i;
if (outline == COGL_INVALID_HANDLE)
outline = cogl_material_new ();
@@ -161,97 +245,359 @@ _cogl_journal_flush_quad_batch (CoglJournalEntry *batch_start,
color == 2 ? 0xff : 0x00,
0xff);
_cogl_material_flush_gl_state (outline, NULL);
- _cogl_current_matrix_state_flush ();
GE( glDrawArrays (GL_LINE_LOOP, 4 * i, 4) );
}
}
+
+ state->vertex_offset += (4 * batch_len);
}
+static gboolean
+compare_entry_modelviews (CoglJournalEntry *entry0,
+ CoglJournalEntry *entry1)
+{
+ /* Batch together quads with the same model view matrix */
+
+ /* FIXME: this is nasty, there are much nicer ways to track this
+ * (at the add_quad_vertices level) without resorting to a memcmp!
+ *
+ * E.g. If the cogl-current-matrix code maintained an "age" for
+ * the modelview matrix we could simply check in add_quad_vertices
+ * if the age has increased, and if so record the change as a
+ * boolean in the journal.
+ */
+
+ if (memcmp (&entry0->model_view, &entry1->model_view,
+ sizeof (GLfloat) * 16) == 0)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+/* At this point we have a run of quads that we know have compatible
+ * materials, but they may not all have the same modelview matrix */
+static void
+_cogl_journal_flush_material_and_entries (CoglJournalEntry *batch_start,
+ gint batch_len,
+ void *data)
+{
+ gulong enable_flags = 0;
+
+ _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+
+ if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_BATCHING))
+ g_print ("BATCHING: material batch len = %d\n", batch_len);
+
+ _cogl_material_flush_gl_state (batch_start->material,
+ &batch_start->flush_options);
+
+ /* FIXME: This api is a bit yukky, ideally it will be removed if we
+ * re-work the cogl_enable mechanism */
+ enable_flags |= _cogl_material_get_cogl_enable_flags (batch_start->material);
+
+ if (ctx->enable_backface_culling)
+ enable_flags |= COGL_ENABLE_BACKFACE_CULLING;
+
+ enable_flags |= COGL_ENABLE_VERTEX_ARRAY;
+ enable_flags |= COGL_ENABLE_COLOR_ARRAY;
+ cogl_enable (enable_flags);
+
+ /* If we haven't transformed the quads in software then we need to also break
+ * up batches according to changes in the modelview matrix... */
+ if (cogl_debug_flags & COGL_DEBUG_DISABLE_SOFTWARE_TRANSFORM)
+ {
+ batch_and_call (batch_start,
+ batch_len,
+ compare_entry_modelviews,
+ _cogl_journal_flush_modelview_and_entries,
+ data);
+ }
+ else
+ _cogl_journal_flush_modelview_and_entries (batch_start, batch_len, data);
+}
+
+static gboolean
+compare_entry_materials (CoglJournalEntry *entry0, CoglJournalEntry *entry1)
+{
+ /* batch rectangles using compatible materials */
+
+ /* XXX: _cogl_material_equal may give false negatives since it avoids
+ * deep comparisons as an optimization. It aims to compare enough so
+ * that we that we are able to batch the 90% common cases, but may not
+ * look at less common differences. */
+ if (_cogl_material_equal (entry0->material,
+ &entry0->flush_options,
+ entry1->material,
+ &entry1->flush_options,
+ COGL_MATERIAL_EQUAL_FLAGS_ASSERT_ALL_DEFAULTS))
+ return TRUE;
+ else
+ return FALSE;
+}
+
+/* Since the stride may not reflect the number of texture layers in use
+ * (due to padding) we deal with texture coordinate offsets separately
+ * from vertex and color offsets... */
+static void
+_cogl_journal_flush_texcoord_vbo_offsets_and_entries (
+ CoglJournalEntry *batch_start,
+ gint batch_len,
+ void *data)
+{
+ CoglJournalFlushState *state = data;
+ int prev_n_texcoord_arrays_enabled;
+ int i;
+
+ _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+
+ for (i = 0; i < batch_start->n_layers; i++)
+ {
+ GE (glClientActiveTexture (GL_TEXTURE0 + i));
+ GE (glEnableClientState (GL_TEXTURE_COORD_ARRAY));
+ /* XXX NB:
+ * Our journal's vertex data is arranged as follows:
+ * 4 vertices per quad:
+ * 2 or 3 GLfloats per position (3 when doing software transforms)
+ * 4 RGBA GLubytes,
+ * 2 GLfloats per tex coord * n_layers
+ * (though n_layers may be padded; see definition of
+ * GET_JOURNAL_VB_STRIDE_FOR_N_LAYERS for details)
+ */
+ GE (glTexCoordPointer (2, GL_FLOAT, state->stride,
+ (void *)(state->vbo_offset +
+ (POS_STRIDE + COLOR_STRIDE) * 4 +
+ TEX_STRIDE * 4 * i)));
+ }
+ prev_n_texcoord_arrays_enabled =
+ ctx->n_texcoord_arrays_enabled;
+ ctx->n_texcoord_arrays_enabled = batch_start->n_layers;
+ for (; i < prev_n_texcoord_arrays_enabled; i++)
+ {
+ GE (glClientActiveTexture (GL_TEXTURE0 + i));
+ GE (glDisableClientState (GL_TEXTURE_COORD_ARRAY));
+ }
+
+ batch_and_call (batch_start,
+ batch_len,
+ compare_entry_materials,
+ _cogl_journal_flush_material_and_entries,
+ data);
+}
+
+static gboolean
+compare_entry_n_layers (CoglJournalEntry *entry0, CoglJournalEntry *entry1)
+{
+ if (entry0->n_layers == entry1->n_layers)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+/* At this point we know the stride has changed from the previous batch
+ * of journal entries */
+static void
+_cogl_journal_flush_vbo_offsets_and_entries (CoglJournalEntry *batch_start,
+ gint batch_len,
+ void *data)
+{
+ CoglJournalFlushState *state = data;
+ size_t stride;
+#ifndef HAVE_COGL_GL
+ int needed_indices = batch_len * 6;
+ CoglHandle indices_handle;
+ CoglVertexBufferIndices *indices;
+#endif
+
+ _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+
+ if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_BATCHING))
+ g_print ("BATCHING: vbo offset batch len = %d\n", batch_len);
+
+ /* XXX NB:
+ * Our journal's vertex data is arranged as follows:
+ * 4 vertices per quad:
+ * 2 or 3 GLfloats per position (3 when doing software transforms)
+ * 4 RGBA GLubytes,
+ * 2 GLfloats per tex coord * n_layers
+ * (though n_layers may be padded; see definition of
+ * GET_JOURNAL_VB_STRIDE_FOR_N_LAYERS for details)
+ */
+ stride = GET_JOURNAL_VB_STRIDE_FOR_N_LAYERS (batch_start->n_layers);
+ stride *= sizeof (GLfloat);
+ state->stride = stride;
+
+ GE (glVertexPointer (N_POS_COMPONENTS, GL_FLOAT, stride,
+ (void *)state->vbo_offset));
+ GE (glColorPointer (4, GL_UNSIGNED_BYTE, stride,
+ (void *)(state->vbo_offset + (POS_STRIDE * 4))));
+
+#ifndef HAVE_COGL_GL
+ indices_handle = cogl_vertex_buffer_indices_get_for_quads (needed_indices);
+ indices = _cogl_vertex_buffer_indices_pointer_from_handle (indices_handle);
+ state->indices = indices;
+
+ if (indices->type == GL_UNSIGNED_BYTE)
+ state->indices_type_size = 1;
+ else if (indices->type == GL_UNSIGNED_SHORT)
+ state->indices_type_size = 2;
+ else
+ g_critical ("unknown indices type %d", indices->type);
+
+ GE (glBindBuffer (GL_ELEMENT_ARRAY_BUFFER,
+ GPOINTER_TO_UINT (indices->vbo_name)));
+#endif
+
+ /* We only call gl{Vertex,Color,Texture}Pointer when the stride within
+ * the VBO changes. (due to a change in the number of material layers)
+ * While the stride remains constant we walk forward through the above
+ * VBO using a vertex offset passed to glDraw{Arrays,Elements} */
+ state->vertex_offset = 0;
+
+ if (cogl_debug_flags & COGL_DEBUG_JOURNAL)
+ {
+ guint8 *verts;
+
+ if (cogl_get_features () & COGL_FEATURE_VBOS)
+ verts = ((guint8 *)ctx->logged_vertices->data) +
+ (size_t)state->vbo_offset;
+ else
+ verts = (guint8 *)state->vbo_offset;
+ _cogl_journal_dump_quad_batch (verts,
+ batch_start->n_layers,
+ batch_len);
+ }
+
+ batch_and_call (batch_start,
+ batch_len,
+ compare_entry_n_layers,
+ _cogl_journal_flush_texcoord_vbo_offsets_and_entries,
+ data);
+
+ /* progress forward through the VBO containing all our vertices */
+ state->vbo_offset += (stride * 4 * batch_len);
+ if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_JOURNAL))
+ g_print ("new vbo offset = %lu\n", (gulong)state->vbo_offset);
+}
+
+static gboolean
+compare_entry_strides (CoglJournalEntry *entry0, CoglJournalEntry *entry1)
+{
+ /* Currently the only thing that affects the stride for our vertex arrays
+ * is the number of material layers. We need to update our VBO offsets
+ * whenever the stride changes. */
+ /* TODO: We should be padding the n_layers == 1 case as if it were
+ * n_layers == 2 so we can reduce the need to split batches. */
+ if (entry0->n_layers == entry1->n_layers ||
+ (entry0->n_layers <= MIN_LAYER_PADING &&
+ entry1->n_layers <= MIN_LAYER_PADING))
+ return TRUE;
+ else
+ return FALSE;
+}
+
+static void
+upload_vertices_to_vbo (GArray *vertices, CoglJournalFlushState *state)
+{
+ size_t needed_vbo_len;
+
+ _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+
+ needed_vbo_len = vertices->len * sizeof (GLfloat);
+
+ g_assert (ctx->journal_vbo == 0);
+ g_assert (needed_vbo_len);
+ GE (glGenBuffers (1, &ctx->journal_vbo));
+ GE (glBindBuffer (GL_ARRAY_BUFFER, ctx->journal_vbo));
+ GE (glBufferData (GL_ARRAY_BUFFER,
+ needed_vbo_len,
+ vertices->data,
+ GL_STATIC_DRAW));
+
+ /* As we flush the journal entries in batches we walk forward through the
+ * above VBO starting at offset 0... */
+ state->vbo_offset = 0;
+}
+
+/* XXX NB: When _cogl_journal_flush() returns all state relating
+ * to materials, all glEnable flags and current matrix state
+ * is undefined.
+ */
void
_cogl_journal_flush (void)
{
- GLfloat *current_vertex_pointer;
- GLfloat *batch_vertex_pointer;
- CoglJournalEntry *batch_start;
- guint batch_len;
- int i;
+ CoglJournalFlushState state;
+ int i;
+ gboolean vbo_fallback =
+ (cogl_get_features () & COGL_FEATURE_VBOS) ? FALSE : TRUE;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
if (ctx->journal->len == 0)
return;
- /* Current non-variables / constraints:
- *
- * - We don't have to worry about much GL state changing between journal
- * entries since currently the journal never out lasts a single call to
- * _cogl_multitexture_multiple_rectangles. So the user doesn't get the
- * chance to fiddle with anything. (XXX: later this will be extended at
- * which point we can start logging certain state changes)
- *
- * - Implied from above: all entries will refer to the same material.
- *
- * - Although _cogl_multitexture_multiple_rectangles can cause the wrap mode
- * of textures to be modified, the journal is flushed if a wrap mode is
- * changed so we don't currently have to log wrap mode changes.
- *
- * - XXX - others?
- */
+ if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_BATCHING))
+ g_print ("BATCHING: journal len = %d\n", ctx->journal->len);
- /* TODO: "compile" the journal to find ways of batching draw calls and vertex
- * data.
- *
- * Simple E.g. given current constraints...
- * pass 0 - load all data into a single CoglVertexBuffer
- * pass 1 - batch gl draw calls according to entries that use the same
- * textures.
- *
- * We will be able to do cooler stuff here when we extend the life of
- * journals beyond _cogl_multitexture_multiple_rectangles.
- */
+ /* Load all the vertex data we have accumulated so far into a single VBO
+ * to minimize memory management costs within the GL driver. */
+ if (!vbo_fallback)
+ upload_vertices_to_vbo (ctx->logged_vertices, &state);
+ else
+ state.vbo_offset = (char *)ctx->logged_vertices->data;
- batch_vertex_pointer = (GLfloat *)ctx->logged_vertices->data;
- batch_start = (CoglJournalEntry *)ctx->journal->data;
- batch_len = 1;
+ /* Since the journal deals with emitting the modelview matrices manually
+ * we need to dirty our client side matrix stack cache... */
+ _cogl_current_matrix_state_dirty ();
- current_vertex_pointer = batch_vertex_pointer;
-
- for (i = 1; i < ctx->journal->len; i++)
+ /* If we have transformed all our quads at log time then the whole journal
+ * then we ensure no further model transform is applied by loading the
+ * identity matrix here...*/
+ if (!(cogl_debug_flags & COGL_DEBUG_DISABLE_SOFTWARE_TRANSFORM))
{
- CoglJournalEntry *prev_entry =
- &g_array_index (ctx->journal, CoglJournalEntry, i - 1);
- CoglJournalEntry *current_entry = prev_entry + 1;
- gsize stride;
-
- /* Progress the vertex pointer to the next quad */
- stride = 2 + current_entry->n_layers * 2;
- current_vertex_pointer += stride * 4;
-
- /* batch rectangles using the same textures */
- if (current_entry->material == prev_entry->material &&
- current_entry->n_layers == prev_entry->n_layers &&
- current_entry->fallback_mask == prev_entry->fallback_mask &&
- current_entry->layer0_override_texture
- == prev_entry->layer0_override_texture)
- {
- batch_len++;
- continue;
- }
-
- _cogl_journal_flush_quad_batch (batch_start,
- batch_len,
- batch_vertex_pointer);
-
- batch_start = current_entry;
- batch_len = 1;
- batch_vertex_pointer = current_vertex_pointer;
+ GE (glMatrixMode (GL_MODELVIEW));
+ glLoadIdentity ();
}
- /* The last batch... */
- _cogl_journal_flush_quad_batch (batch_start,
- batch_len,
- batch_vertex_pointer);
+ /* batch_and_call() batches a list of journal entries according to some
+ * given criteria and calls a callback once for each determined batch.
+ *
+ * The process of flushing the journal is staggered to reduce the amount
+ * of driver/GPU state changes necessary:
+ * 1) We split the entries according to the stride of the vertices:
+ * Each time the stride of our vertex data changes we need to call
+ * gl{Vertex,Color}Pointer to inform GL of new VBO offsets.
+ * Currently the only thing that affects the stride of our vertex data
+ * is the number of material layers.
+ * 2) We split the entries explicitly by the number of material layers:
+ * We pad our vertex data when the number of layers is < 2 so that we
+ * can minimize changes in stride. Each time the number of layers
+ * changes we need to call glTexCoordPointer to inform GL of new VBO
+ * offsets.
+ * 3) We then split according to compatible Cogl materials:
+ * This is where we flush material state
+ * 4) Finally we split according to modelview matrix changes:
+ * This is when we finally tell GL to draw something.
+ * Note: Splitting by modelview changes is skipped when are doing the
+ * vertex transformation in software at log time.
+ */
+ batch_and_call ((CoglJournalEntry *)ctx->journal->data, /* first entry */
+ ctx->journal->len, /* max number of entries to consider */
+ compare_entry_strides,
+ _cogl_journal_flush_vbo_offsets_and_entries, /* callback */
+ &state); /* data */
+ for (i = 0; i < ctx->journal->len; i++)
+ {
+ CoglJournalEntry *entry =
+ &g_array_index (ctx->journal, CoglJournalEntry, i);
+ _cogl_material_journal_unref (entry->material);
+ }
+
+ if (!vbo_fallback)
+ {
+ GE (glDeleteBuffers (1, &ctx->journal_vbo));
+ ctx->journal_vbo = 0;
+ }
g_array_set_size (ctx->journal, 0);
g_array_set_size (ctx->logged_vertices, 0);
@@ -263,34 +609,39 @@ _cogl_journal_log_quad (float x_1,
float x_2,
float y_2,
CoglHandle material,
- gint n_layers,
- guint32 fallback_mask,
+ int n_layers,
+ guint32 fallback_layers,
GLuint layer0_override_texture,
float *tex_coords,
guint tex_coords_len)
{
- int stride;
+ size_t stride;
+ size_t byte_stride;
int next_vert;
GLfloat *v;
+ GLubyte *c;
+ GLubyte *src_c;
int i;
int next_entry;
+ guint32 disable_layers;
CoglJournalEntry *entry;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
- /* The vertex data is logged into a seperate array in a layout that can be
+ /* The vertex data is logged into a separate array in a layout that can be
* directly passed to OpenGL
*/
- /* We pack the vertex data as 2 (x,y) GLfloats folowed by 2 (tx,ty) GLfloats
- * for each texture being used, E.g.:
- * [X, Y, TX0, TY0, TX1, TY1, X, Y, TX0, TY0, X, Y, ...]
- */
- stride = 2 + n_layers * 2;
+ /* XXX: See definition of GET_JOURNAL_VB_STRIDE_FOR_N_LAYERS for details
+ * about how we pack our vertex data */
+ stride = GET_JOURNAL_VB_STRIDE_FOR_N_LAYERS (n_layers);
+ /* NB: stride is in 32bit words */
+ byte_stride = stride * 4;
next_vert = ctx->logged_vertices->len;
g_array_set_size (ctx->logged_vertices, next_vert + 4 * stride);
v = &g_array_index (ctx->logged_vertices, GLfloat, next_vert);
+ c = (GLubyte *)(v + POS_STRIDE);
/* XXX: All the jumping around to fill in this strided buffer doesn't
* seem ideal. */
@@ -298,18 +649,57 @@ _cogl_journal_log_quad (float x_1,
/* XXX: we could defer expanding the vertex data for GL until we come
* to flushing the journal. */
- v[0] = x_1; v[1] = y_1;
- v += stride;
- v[0] = x_1; v[1] = y_2;
- v += stride;
- v[0] = x_2; v[1] = y_2;
- v += stride;
- v[0] = x_2; v[1] = y_1;
+ /* FIXME: This is a hacky optimization, since it will break if we
+ * change the definition of CoglColor: */
+ _cogl_material_get_colorubv (material, c);
+ src_c = c;
+ for (i = 0; i < 3; i++)
+ {
+ c += byte_stride;
+ memcpy (c, src_c, 4);
+ }
+
+ if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_DISABLE_SOFTWARE_TRANSFORM))
+ {
+ v[0] = x_1; v[1] = y_1;
+ v += stride;
+ v[0] = x_1; v[1] = y_2;
+ v += stride;
+ v[0] = x_2; v[1] = y_2;
+ v += stride;
+ v[0] = x_2; v[1] = y_1;
+ }
+ else
+ {
+ CoglMatrix mv;
+ float x, y, z, w;
+
+ cogl_get_modelview_matrix (&mv);
+
+ x = x_1, y = y_1, z = 0; w = 1;
+ cogl_matrix_transform_point (&mv, &x, &y, &z, &w);
+ v[0] = x; v[1] = y; v[2] = z;
+ v += stride;
+ x = x_1, y = y_2, z = 0; w = 1;
+ cogl_matrix_transform_point (&mv, &x, &y, &z, &w);
+ v[0] = x; v[1] = y; v[2] = z;
+ v += stride;
+ x = x_2, y = y_2, z = 0; w = 1;
+ cogl_matrix_transform_point (&mv, &x, &y, &z, &w);
+ v[0] = x; v[1] = y; v[2] = z;
+ v += stride;
+ x = x_2, y = y_1, z = 0; w = 1;
+ cogl_matrix_transform_point (&mv, &x, &y, &z, &w);
+ v[0] = x; v[1] = y; v[2] = z;
+ }
for (i = 0; i < n_layers; i++)
{
- GLfloat *t =
- &g_array_index (ctx->logged_vertices, GLfloat, next_vert + 2 + 2 * i);
+ /* XXX: See definition of GET_JOURNAL_VB_STRIDE_FOR_N_LAYERS for details
+ * about how we pack our vertex data */
+ GLfloat *t = &g_array_index (ctx->logged_vertices, GLfloat,
+ next_vert + POS_STRIDE +
+ COLOR_STRIDE + TEX_STRIDE * i);
t[0] = tex_coords[0]; t[1] = tex_coords[1];
t += stride;
@@ -320,14 +710,36 @@ _cogl_journal_log_quad (float x_1,
t[0] = tex_coords[2]; t[1] = tex_coords[1];
}
+ if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_JOURNAL))
+ {
+ g_print ("Logged new quad:\n");
+ v = &g_array_index (ctx->logged_vertices, GLfloat, next_vert);
+ _cogl_journal_dump_quad_vertices ((guint8 *)v, n_layers);
+ }
+
next_entry = ctx->journal->len;
g_array_set_size (ctx->journal, next_entry + 1);
entry = &g_array_index (ctx->journal, CoglJournalEntry, next_entry);
- entry->material = material;
+ disable_layers = (1 << n_layers) - 1;
+ disable_layers = ~disable_layers;
+
+ entry->material = _cogl_material_journal_ref (material);
entry->n_layers = n_layers;
- entry->fallback_mask = fallback_mask;
- entry->layer0_override_texture = layer0_override_texture;
+ entry->flush_options.flags =
+ COGL_MATERIAL_FLUSH_FALLBACK_MASK |
+ COGL_MATERIAL_FLUSH_DISABLE_MASK |
+ COGL_MATERIAL_FLUSH_LAYER0_OVERRIDE |
+ COGL_MATERIAL_FLUSH_SKIP_GL_COLOR;
+ entry->flush_options.fallback_layers = fallback_layers;
+ entry->flush_options.disable_layers = disable_layers;
+ entry->flush_options.layer0_override_texture = layer0_override_texture;
+ if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_DISABLE_SOFTWARE_TRANSFORM))
+ cogl_get_modelview_matrix (&entry->model_view);
+
+ if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_DISABLE_BATCHING
+ || cogl_debug_flags & COGL_DEBUG_RECTANGLES))
+ _cogl_journal_flush ();
}
static void
@@ -511,12 +923,12 @@ _cogl_multitexture_unsliced_quad (float x_1,
float x_2,
float y_2,
CoglHandle material,
- gint n_layers,
- guint32 fallback_mask,
+ guint32 fallback_layers,
const float *user_tex_coords,
gint user_tex_coords_len)
{
- float *final_tex_coords = alloca (sizeof (float) * 4 * n_layers);
+ int n_layers = cogl_material_get_n_layers (material);
+ float *final_tex_coords = alloca (sizeof (float) * 4 * n_layers);
const GList *layers;
GList *tmp;
int i;
@@ -601,7 +1013,7 @@ _cogl_multitexture_unsliced_quad (float x_1,
/* NB: marking for fallback will replace the layer with
* a default transparent texture */
- fallback_mask |= (1 << i);
+ fallback_layers |= (1 << i);
}
}
@@ -672,7 +1084,7 @@ _cogl_multitexture_unsliced_quad (float x_1,
y_2,
material,
n_layers,
- fallback_mask,
+ fallback_layers,
0, /* don't replace the layer0 texture */
final_tex_coords,
n_layers * 4);
@@ -699,7 +1111,7 @@ _cogl_rectangles_with_multitexture_coords (
const GList *layers;
int n_layers;
const GList *tmp;
- guint32 fallback_mask = 0;
+ guint32 fallback_layers = 0;
gboolean all_use_sliced_quad_fallback = FALSE;
int i;
@@ -710,7 +1122,7 @@ _cogl_rectangles_with_multitexture_coords (
material = ctx->source_material;
layers = cogl_material_get_layers (material);
- n_layers = g_list_length ((GList *)layers);
+ n_layers = cogl_material_get_n_layers (material);
/*
* Validate all the layers of the current source material...
@@ -740,7 +1152,7 @@ _cogl_rectangles_with_multitexture_coords (
{
if (i == 0)
{
- fallback_mask = ~1; /* fallback all except the first layer */
+ fallback_layers = ~1; /* fallback all except the first layer */
all_use_sliced_quad_fallback = TRUE;
if (tmp->next)
{
@@ -766,7 +1178,7 @@ _cogl_rectangles_with_multitexture_coords (
/* NB: marking for fallback will replace the layer with
* a default transparent texture */
- fallback_mask |= (1 << i);
+ fallback_layers |= (1 << i);
continue;
}
}
@@ -788,7 +1200,7 @@ _cogl_rectangles_with_multitexture_coords (
/* NB: marking for fallback will replace the layer with
* a default transparent texture */
- fallback_mask |= (1 << i);
+ fallback_layers |= (1 << i);
continue;
}
}
@@ -803,8 +1215,7 @@ _cogl_rectangles_with_multitexture_coords (
|| !_cogl_multitexture_unsliced_quad (rects[i].x_1, rects[i].y_1,
rects[i].x_2, rects[i].y_2,
material,
- n_layers,
- fallback_mask,
+ fallback_layers,
rects[i].tex_coords,
rects[i].tex_coords_len))
{
@@ -832,7 +1243,11 @@ _cogl_rectangles_with_multitexture_coords (
}
}
+#if 0
+ /* XXX: The current journal doesn't handle changes to the model view matrix
+ * so for now we force a flush at the end of every primitive. */
_cogl_journal_flush ();
+#endif
}
void
@@ -947,6 +1362,7 @@ _cogl_texture_sliced_polygon (CoglTextureVertex *vertices,
int x, y, tex_num, i;
GLuint gl_handle;
GLfloat *v;
+ CoglMaterialFlushOptions options;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
@@ -1027,13 +1443,14 @@ _cogl_texture_sliced_polygon (CoglTextureVertex *vertices,
v += stride;
}
- _cogl_material_flush_gl_state (ctx->source_material,
- COGL_MATERIAL_FLUSH_DISABLE_MASK,
- (guint32)~1, /* disable all except the
- first layer */
- COGL_MATERIAL_FLUSH_LAYER0_OVERRIDE,
- gl_handle,
- NULL);
+ options.flags =
+ COGL_MATERIAL_FLUSH_DISABLE_MASK |
+ COGL_MATERIAL_FLUSH_LAYER0_OVERRIDE;
+ /* disable all except the first layer */
+ options.disable_layers = (guint32)~1;
+ options.layer0_override_texture = gl_handle;
+
+ _cogl_material_flush_gl_state (ctx->source_material, &options);
_cogl_current_matrix_state_flush ();
GE( glDrawArrays (GL_TRIANGLE_FAN, 0, n_vertices) );
@@ -1047,7 +1464,7 @@ _cogl_multitexture_unsliced_polygon (CoglTextureVertex *vertices,
guint n_layers,
guint stride,
gboolean use_color,
- guint32 fallback_mask)
+ guint32 fallback_layers)
{
CoglHandle material;
const GList *layers;
@@ -1055,6 +1472,7 @@ _cogl_multitexture_unsliced_polygon (CoglTextureVertex *vertices,
GList *tmp;
CoglTexSliceSpan *y_span, *x_span;
GLfloat *v;
+ CoglMaterialFlushOptions options;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
@@ -1125,10 +1543,11 @@ _cogl_multitexture_unsliced_polygon (CoglTextureVertex *vertices,
}
}
- _cogl_material_flush_gl_state (ctx->source_material,
- COGL_MATERIAL_FLUSH_FALLBACK_MASK,
- fallback_mask,
- NULL);
+ options.flags = COGL_MATERIAL_FLUSH_FALLBACK_MASK;
+ if (use_color)
+ options.flags |= COGL_MATERIAL_FLUSH_SKIP_GL_COLOR;
+ options.fallback_layers = fallback_layers;
+ _cogl_material_flush_gl_state (ctx->source_material, &options);
_cogl_current_matrix_state_flush ();
GE (glDrawArrays (GL_TRIANGLE_FAN, 0, n_vertices));
@@ -1144,7 +1563,7 @@ cogl_polygon (CoglTextureVertex *vertices,
int n_layers;
GList *tmp;
gboolean use_sliced_polygon_fallback = FALSE;
- guint32 fallback_mask = 0;
+ guint32 fallback_layers = 0;
int i;
gulong enable_flags;
guint stride;
@@ -1154,6 +1573,7 @@ cogl_polygon (CoglTextureVertex *vertices,
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
+ _cogl_journal_flush ();
cogl_clip_ensure ();
material = ctx->source_material;
@@ -1228,7 +1648,7 @@ cogl_polygon (CoglTextureVertex *vertices,
"textures with waste\n", i);
warning_seen = TRUE;
- fallback_mask |= (1 << i);
+ fallback_layers |= (1 << i);
continue;
}
}
@@ -1293,7 +1713,7 @@ cogl_polygon (CoglTextureVertex *vertices,
n_layers,
stride,
use_color,
- fallback_mask);
+ fallback_layers);
/* Reset the size of the logged vertex array because rendering
rectangles expects it to start at 0 */
@@ -1313,6 +1733,7 @@ cogl_path_fill_preserve (void)
{
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
+ _cogl_journal_flush ();
cogl_clip_ensure ();
if (ctx->path_nodes->len == 0)
@@ -1334,11 +1755,12 @@ cogl_path_stroke_preserve (void)
{
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
- cogl_clip_ensure ();
-
if (ctx->path_nodes->len == 0)
return;
+ _cogl_journal_flush ();
+ cogl_clip_ensure ();
+
_cogl_path_stroke_nodes();
}
diff --git a/common/cogl-primitives.h b/common/cogl-primitives.h
index 268fba3cd..dd5a73c8b 100644
--- a/common/cogl-primitives.h
+++ b/common/cogl-primitives.h
@@ -57,4 +57,6 @@ struct _CoglBezCubic
floatVec2 p4;
};
+void _cogl_journal_flush (void);
+
#endif /* __COGL_PRIMITIVES_H */
diff --git a/common/cogl-vertex-buffer.c b/common/cogl-vertex-buffer.c
index a18852078..2892bfe71 100644
--- a/common/cogl-vertex-buffer.c
+++ b/common/cogl-vertex-buffer.c
@@ -137,6 +137,7 @@
#include "cogl-vertex-buffer-private.h"
#include "cogl-texture-private.h"
#include "cogl-material-private.h"
+#include "cogl-primitives.h"
#define PAD_FOR_ALIGNMENT(VAR, TYPE_SIZE) \
(VAR = TYPE_SIZE + ((VAR - 1) & ~(TYPE_SIZE - 1)))
@@ -1500,9 +1501,10 @@ enable_state_for_drawing_buffer (CoglVertexBuffer *buffer)
gulong enable_flags = 0;
guint max_texcoord_attrib_unit = 0;
const GList *layers;
- guint32 fallback_mask = 0;
- guint32 disable_mask = ~0;
+ guint32 fallback_layers = 0;
+ guint32 disable_layers = ~0;
int i;
+ CoglMaterialFlushOptions options;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
@@ -1573,7 +1575,7 @@ enable_state_for_drawing_buffer (CoglVertexBuffer *buffer)
pointer));
if (attribute->texture_unit > max_texcoord_attrib_unit)
max_texcoord_attrib_unit = attribute->texture_unit;
- disable_mask &= ~(1 << attribute->texture_unit);
+ disable_layers &= ~(1 << attribute->texture_unit);
break;
case COGL_VERTEX_BUFFER_ATTRIB_FLAG_VERTEX_ARRAY:
enable_flags |= COGL_ENABLE_VERTEX_ARRAY;
@@ -1638,17 +1640,24 @@ enable_state_for_drawing_buffer (CoglVertexBuffer *buffer)
* vertices once for each layer, each time with a fiddled texture
* matrix.
*/
- fallback_mask |= (1 << i);
+ fallback_layers |= (1 << i);
}
}
- _cogl_material_flush_gl_state (ctx->source_material,
- COGL_MATERIAL_FLUSH_FALLBACK_MASK,
- fallback_mask,
- COGL_MATERIAL_FLUSH_DISABLE_MASK,
- disable_mask,
- NULL);
+ for (i = max_texcoord_attrib_unit + 1; i < ctx->n_texcoord_arrays_enabled; i++)
+ {
+ GE (glClientActiveTexture (GL_TEXTURE0 + i));
+ GE (glDisableClientState (GL_TEXTURE_COORD_ARRAY));
+ }
+ ctx->n_texcoord_arrays_enabled = max_texcoord_attrib_unit + 1;
+ options.flags =
+ COGL_MATERIAL_FLUSH_FALLBACK_MASK |
+ COGL_MATERIAL_FLUSH_DISABLE_MASK;
+ options.fallback_layers = fallback_layers;
+ options.disable_layers = disable_layers;
+
+ _cogl_material_flush_gl_state (ctx->source_material, &options);
enable_flags |= _cogl_material_get_cogl_enable_flags (ctx->source_material);
if (ctx->enable_backface_culling)
@@ -1730,6 +1739,9 @@ cogl_vertex_buffer_draw (CoglHandle handle,
if (!cogl_is_vertex_buffer (handle))
return;
+ _cogl_journal_flush ();
+ cogl_clip_ensure ();
+
buffer = _cogl_vertex_buffer_pointer_from_handle (handle);
cogl_clip_ensure ();
@@ -1859,6 +1871,9 @@ cogl_vertex_buffer_draw_elements (CoglHandle handle,
if (!cogl_is_vertex_buffer (handle))
return;
+ _cogl_journal_flush ();
+ cogl_clip_ensure ();
+
buffer = _cogl_vertex_buffer_pointer_from_handle (handle);
if (!cogl_is_vertex_buffer_indices (indices_handle))
diff --git a/common/cogl.c b/common/cogl.c
index d06d8ddd9..309e744d5 100644
--- a/common/cogl.c
+++ b/common/cogl.c
@@ -216,6 +216,9 @@ cogl_get_enable ()
void
cogl_set_depth_test_enabled (gboolean setting)
{
+ /* Currently the journal can't track changes to depth state... */
+ _cogl_journal_flush ();
+
if (setting)
{
glEnable (GL_DEPTH_TEST);
@@ -236,6 +239,9 @@ cogl_set_backface_culling_enabled (gboolean setting)
{
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
+ /* Currently the journal can't track changes to backface culling state... */
+ _cogl_journal_flush ();
+
ctx->enable_backface_culling = setting;
}
@@ -388,9 +394,15 @@ _cogl_add_stencil_clip (float x_offset,
float height,
gboolean first)
{
+ CoglHandle current_source;
+
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
- _cogl_material_flush_gl_state (ctx->stencil_material, NULL);
+ _cogl_journal_flush ();
+
+ /* temporarily swap in our special stenciling material */
+ current_source = cogl_handle_ref (ctx->source_material);
+ cogl_set_source (ctx->stencil_material);
if (first)
{
@@ -443,9 +455,17 @@ _cogl_add_stencil_clip (float x_offset,
_cogl_set_current_matrix (COGL_MATRIX_MODELVIEW);
}
+ /* make sure our rectangles hit the stencil buffer before we restore
+ * the stencil function / operation */
+ _cogl_journal_flush ();
+
/* Restore the stencil mode */
GE( glStencilFunc (GL_EQUAL, 0x1, 0x1) );
GE( glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP) );
+
+ /* restore the original source material */
+ cogl_set_source (current_source);
+ cogl_handle_unref (current_source);
}
void
@@ -554,6 +574,9 @@ cogl_get_features (void)
if (!ctx->features_cached)
_cogl_features_init ();
+ if (cogl_debug_flags & COGL_DEBUG_DISABLE_VBOS)
+ ctx->feature_flags &= ~COGL_FEATURE_VBOS;
+
return ctx->feature_flags;
}
@@ -630,6 +653,9 @@ cogl_set_fog (const CoglColor *fog_color,
GLfloat fogColor[4];
GLenum gl_mode = GL_LINEAR;
+ /* The cogl journal doesn't currently track fog state changes */
+ _cogl_journal_flush ();
+
fogColor[0] = cogl_color_get_red_float (fog_color);
fogColor[1] = cogl_color_get_green_float (fog_color);
fogColor[2] = cogl_color_get_blue_float (fog_color);
@@ -667,6 +693,9 @@ cogl_set_fog (const CoglColor *fog_color,
void
cogl_disable_fog (void)
{
+ /* Currently the journal can't track changes to fog state... */
+ _cogl_journal_flush ();
+
glDisable (GL_FOG);
}
@@ -678,6 +707,12 @@ cogl_flush_gl_state (int flags)
}
#endif
+void
+cogl_flush (void)
+{
+ _cogl_journal_flush ();
+}
+
void
cogl_read_pixels (int x,
int y,
@@ -711,6 +746,10 @@ cogl_read_pixels (int x,
glPixelStorei (GL_PACK_SKIP_ROWS, 0);
#endif /* HAVE_COGL_GL */
+ /* make sure any batched primitives get emitted to the GL driver before
+ * issuing our read pixels... */
+ cogl_flush ();
+
glReadPixels (x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
/* TODO: consider using the GL_MESA_pack_invert extension in the future
@@ -732,3 +771,78 @@ cogl_read_pixels (int x,
}
}
+void
+cogl_begin_gl (void)
+{
+ CoglMaterialFlushOptions options;
+ gulong enable_flags;
+ int i;
+
+ _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+
+ if (ctx->in_begin_gl_block)
+ {
+ static gboolean shown = FALSE;
+ if (!shown)
+ g_warning ("You should not nest cogl_begin_gl/cogl_end_gl blocks");
+ shown = TRUE;
+ return;
+ }
+ ctx->in_begin_gl_block = TRUE;
+
+ /* Flush all batched primitives */
+ cogl_flush ();
+
+ /* Flush our clipping state to GL */
+ cogl_clip_ensure ();
+
+ /* Flush any client side matrix state */
+ _cogl_current_matrix_state_flush ();
+
+
+ /* Setup the state for the current material */
+
+ /* We considered flushing a specific, minimal material here to try and
+ * simplify the GL state, but decided to avoid special cases and second
+ * guessing what would be actually helpful.
+ *
+ * A user should instead call cogl_set_source_color4ub() before
+ * cogl_begin_gl() to simplify the state flushed.
+ */
+ options.flags = 0;
+ _cogl_material_flush_gl_state (ctx->source_material, &options);
+
+ /* FIXME: This api is a bit yukky, ideally it will be removed if we
+ * re-work the cogl_enable mechanism */
+ enable_flags |= _cogl_material_get_cogl_enable_flags (ctx->source_material);
+
+ if (ctx->enable_backface_culling)
+ enable_flags |= COGL_ENABLE_BACKFACE_CULLING;
+
+ cogl_enable (enable_flags);
+
+ /* Disable all client texture coordinate arrays */
+ for (i = 0; i < ctx->n_texcoord_arrays_enabled; i++)
+ {
+ GE (glClientActiveTexture (GL_TEXTURE0 + i));
+ GE (glDisableClientState (GL_TEXTURE_COORD_ARRAY));
+ }
+ ctx->n_texcoord_arrays_enabled = 0;
+}
+
+void
+cogl_end_gl (void)
+{
+ _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+
+ if (!ctx->in_begin_gl_block)
+ {
+ static gboolean shown = FALSE;
+ if (!shown)
+ g_warning ("cogl_end_gl is being called before cogl_begin_gl");
+ shown = TRUE;
+ return;
+ }
+ ctx->in_begin_gl_block = FALSE;
+}
+
diff --git a/doc/reference/cogl/cogl-sections.txt b/doc/reference/cogl/cogl-sections.txt
index c28ab52f6..5a80895f2 100644
--- a/doc/reference/cogl/cogl-sections.txt
+++ b/doc/reference/cogl/cogl-sections.txt
@@ -72,6 +72,11 @@ cogl_set_source_texture
CoglReadPixelsFlags
cogl_read_pixels
+
+cogl_flush
+cogl_begin_gl
+cogl_end_gl
+
COGL_TYPE_ATTRIBUTE_TYPE
COGL_TYPE_BUFFER_BIT
diff --git a/gl/cogl-context.c b/gl/cogl-context.c
index 1b6fab8f6..f587f8cd1 100644
--- a/gl/cogl-context.c
+++ b/gl/cogl-context.c
@@ -69,9 +69,13 @@ cogl_create_context ()
_context->journal = g_array_new (FALSE, FALSE, sizeof (CoglJournalEntry));
_context->logged_vertices = g_array_new (FALSE, FALSE, sizeof (GLfloat));
+ _context->journal_vbo = 0;
+ _context->journal_vbo_len = 0;
_context->current_material = NULL;
_context->current_material_flags = 0;
+ memset (&_context->current_material_flush_options,
+ 0, sizeof (CoglMaterialFlushOptions));
_context->current_layers = g_array_new (FALSE, FALSE,
sizeof (CoglLayerInfo));
_context->n_texcoord_arrays_enabled = 0;
@@ -86,6 +90,8 @@ cogl_create_context ()
_context->last_path = 0;
_context->stencil_material = cogl_material_new ();
+ _context->in_begin_gl_block = FALSE;
+
_context->pf_glGenRenderbuffersEXT = NULL;
_context->pf_glBindRenderbufferEXT = NULL;
_context->pf_glRenderbufferStorageEXT = NULL;
diff --git a/gl/cogl-context.h b/gl/cogl-context.h
index 9e1596e36..81d17c4fa 100644
--- a/gl/cogl-context.h
+++ b/gl/cogl-context.h
@@ -28,6 +28,7 @@
#include "cogl-clip-stack.h"
#include "cogl-matrix-stack.h"
#include "cogl-current-matrix.h"
+#include "cogl-material-private.h"
typedef struct
{
@@ -78,10 +79,13 @@ typedef struct
* can batch things together. */
GArray *journal;
GArray *logged_vertices;
+ GLuint journal_vbo;
+ size_t journal_vbo_len;
/* Some simple caching, to minimize state changes... */
CoglHandle current_material;
gulong current_material_flags;
+ CoglMaterialFlushOptions current_material_flush_options;
GArray *current_layers;
guint n_texcoord_arrays_enabled;
@@ -106,6 +110,8 @@ typedef struct
guint quad_indices_short_len;
CoglHandle quad_indices_short;
+ gboolean in_begin_gl_block;
+
/* Relying on glext.h to define these */
COGL_PFNGLGENRENDERBUFFERSEXTPROC pf_glGenRenderbuffersEXT;
COGL_PFNGLDELETERENDERBUFFERSEXTPROC pf_glDeleteRenderbuffersEXT;
diff --git a/gl/cogl-fbo.c b/gl/cogl-fbo.c
index db99e6ace..f13340966 100644
--- a/gl/cogl-fbo.c
+++ b/gl/cogl-fbo.c
@@ -169,6 +169,8 @@ cogl_set_draw_buffer (CoglBufferTarget target, CoglHandle offscreen)
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
+ _cogl_journal_flush ();
+
g_assert (ctx->draw_buffer_stack != NULL);
draw_buffer = ctx->draw_buffer_stack->data;
diff --git a/gl/cogl-primitives.c b/gl/cogl-primitives.c
index 6c106f9ec..cb6671c08 100644
--- a/gl/cogl-primitives.c
+++ b/gl/cogl-primitives.c
@@ -76,16 +76,18 @@ _cogl_path_stroke_nodes ()
{
guint path_start = 0;
gulong enable_flags = COGL_ENABLE_VERTEX_ARRAY;
+ CoglMaterialFlushOptions options;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
enable_flags |= _cogl_material_get_cogl_enable_flags (ctx->source_material);
cogl_enable (enable_flags);
- _cogl_material_flush_gl_state (ctx->source_material,
- COGL_MATERIAL_FLUSH_DISABLE_MASK,
- (guint32)~0, /* disable all texture layers */
- NULL);
+ options.flags = COGL_MATERIAL_FLUSH_DISABLE_MASK;
+ /* disable all texture layers */
+ options.disable_layers = (guint32)~0;
+
+ _cogl_material_flush_gl_state (ctx->source_material, &options);
_cogl_current_matrix_state_flush ();
while (path_start < ctx->path_nodes->len)
@@ -123,18 +125,25 @@ _cogl_add_path_to_stencil_buffer (floatVec2 nodes_min,
CoglPathNode *path,
gboolean merge)
{
- guint path_start = 0;
- guint sub_path_num = 0;
- float bounds_x;
- float bounds_y;
- float bounds_w;
- float bounds_h;
- gulong enable_flags = COGL_ENABLE_VERTEX_ARRAY;
+ guint path_start = 0;
+ guint sub_path_num = 0;
+ float bounds_x;
+ float bounds_y;
+ float bounds_w;
+ float bounds_h;
+ gulong enable_flags = COGL_ENABLE_VERTEX_ARRAY;
+ CoglHandle prev_source;
+ int i;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
+ _cogl_journal_flush ();
+
/* Just setup a simple material that doesn't use texturing... */
- _cogl_material_flush_gl_state (ctx->stencil_material, NULL);
+ prev_source = cogl_handle_ref (ctx->source_material);
+ cogl_set_source (ctx->stencil_material);
+
+ _cogl_material_flush_gl_state (ctx->source_material, NULL);
enable_flags |=
_cogl_material_get_cogl_enable_flags (ctx->source_material);
@@ -161,7 +170,15 @@ _cogl_add_path_to_stencil_buffer (floatVec2 nodes_min,
GE( glColorMask (FALSE, FALSE, FALSE, FALSE) );
GE( glDepthMask (FALSE) );
+ for (i = 0; i < ctx->n_texcoord_arrays_enabled; i++)
+ {
+ GE (glClientActiveTexture (GL_TEXTURE0 + i));
+ GE (glDisableClientState (GL_TEXTURE_COORD_ARRAY));
+ }
+ ctx->n_texcoord_arrays_enabled = 0;
+
_cogl_current_matrix_state_flush ();
+
while (path_start < path_size)
{
GE( glVertexPointer (2, GL_FLOAT, sizeof (CoglPathNode),
@@ -175,9 +192,8 @@ _cogl_add_path_to_stencil_buffer (floatVec2 nodes_min,
significant bit */
GE( glStencilMask (merge ? 6 : 3) );
GE( glStencilOp (GL_ZERO, GL_REPLACE, GL_REPLACE) );
- cogl_rectangle (bounds_x, bounds_y,
- bounds_x + bounds_w, bounds_y + bounds_h);
-
+ glRectf (bounds_x, bounds_y,
+ bounds_x + bounds_w, bounds_y + bounds_h);
GE( glStencilOp (GL_INVERT, GL_INVERT, GL_INVERT) );
}
@@ -210,8 +226,10 @@ _cogl_add_path_to_stencil_buffer (floatVec2 nodes_min,
_cogl_current_matrix_push ();
_cogl_current_matrix_identity ();
- cogl_rectangle (-1.0, -1.0, 1.0, 1.0);
- cogl_rectangle (-1.0, -1.0, 1.0, 1.0);
+ _cogl_current_matrix_state_flush ();
+
+ glRectf (-1.0, -1.0, 1.0, 1.0);
+ glRectf (-1.0, -1.0, 1.0, 1.0);
_cogl_current_matrix_pop ();
@@ -227,6 +245,10 @@ _cogl_add_path_to_stencil_buffer (floatVec2 nodes_min,
GE( glStencilFunc (GL_EQUAL, 0x1, 0x1) );
GE( glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP) );
+
+ /* restore the original material */
+ cogl_set_source (prev_source);
+ cogl_handle_unref (prev_source);
}
void
diff --git a/gl/cogl-program.c b/gl/cogl-program.c
index 0a10cd4c4..75cf8e2f8 100644
--- a/gl/cogl-program.c
+++ b/gl/cogl-program.c
@@ -128,6 +128,11 @@ cogl_program_use (CoglHandle handle)
if (handle != COGL_INVALID_HANDLE && !cogl_is_program (handle))
return;
+ /* The Cogl journal doesn't currently cope with the use of
+ * shaders so we have to flush all priitives whenever the
+ * current shader changes... */
+ _cogl_journal_flush ();
+
if (handle == COGL_INVALID_HANDLE)
gl_handle = 0;
else
diff --git a/gl/cogl-texture-private.h b/gl/cogl-texture-private.h
index 365a47921..6a2ed7e39 100644
--- a/gl/cogl-texture-private.h
+++ b/gl/cogl-texture-private.h
@@ -26,6 +26,7 @@
#include "cogl-bitmap-private.h"
#include "cogl-handle.h"
+#include "cogl-material-private.h"
typedef struct _CoglTexture CoglTexture;
typedef struct _CoglTexSliceSpan CoglTexSliceSpan;
@@ -99,10 +100,13 @@ struct _CoglTexture
* later flush the journal we aim to batch data, and gl draw calls. */
typedef struct _CoglJournalEntry
{
- CoglHandle material;
- gint n_layers;
- guint32 fallback_mask;
- GLuint layer0_override_texture;
+ CoglHandle material;
+ int n_layers;
+ CoglMaterialFlushOptions flush_options;
+ CoglMatrix model_view;
+ /* XXX: These entries are pretty big now considering the padding in
+ * CoglMaterialFlushOptions and CoglMatrix, so we might need to optimize this
+ * later. */
} CoglJournalEntry;
CoglTexture*
diff --git a/gl/cogl-texture.c b/gl/cogl-texture.c
index fb118c707..7721ea2a8 100644
--- a/gl/cogl-texture.c
+++ b/gl/cogl-texture.c
@@ -39,6 +39,7 @@
#include "cogl-material.h"
#include "cogl-context.h"
#include "cogl-handle.h"
+#include "cogl-primitives.h"
#include
#include
@@ -60,8 +61,6 @@
#endif
-extern void _cogl_journal_flush (void);
-
static void _cogl_texture_free (CoglTexture *tex);
COGL_HANDLE_DEFINE (Texture, texture);
diff --git a/gles/cogl-gles2-wrapper.c b/gles/cogl-gles2-wrapper.c
index 979ade598..12716f009 100644
--- a/gles/cogl-gles2-wrapper.c
+++ b/gles/cogl-gles2-wrapper.c
@@ -1480,6 +1480,13 @@ cogl_wrap_glColor4f (GLclampf r, GLclampf g, GLclampf b, GLclampf a)
glVertexAttrib4f (COGL_GLES2_WRAPPER_COLOR_ATTRIB, r, g, b, a);
}
+void
+cogl_wrap_glColor4ub (GLubyte r, GLubyte g, GLubyte b, GLubyte a)
+{
+ glVertexAttrib4f (COGL_GLES2_WRAPPER_COLOR_ATTRIB,
+ r/255.0, g/255.0, b/255.0, a/255.0);
+}
+
void
cogl_wrap_glClipPlanef (GLenum plane, GLfloat *equation)
{
diff --git a/gles/cogl-gles2-wrapper.h b/gles/cogl-gles2-wrapper.h
index 51bee2d5c..5d232f922 100644
--- a/gles/cogl-gles2-wrapper.h
+++ b/gles/cogl-gles2-wrapper.h
@@ -340,6 +340,7 @@ void cogl_wrap_glDisableClientState (GLenum array);
void cogl_wrap_glAlphaFunc (GLenum func, GLclampf ref);
void cogl_wrap_glColor4f (GLclampf r, GLclampf g, GLclampf b, GLclampf a);
+void cogl_wrap_glColor4ub (GLubyte r, GLubyte g, GLubyte b, GLubyte a);
void cogl_wrap_glClipPlanef (GLenum plane, GLfloat *equation);
@@ -393,6 +394,7 @@ void _cogl_gles2_clear_cache_for_program (CoglHandle program);
#define glDisableClientState cogl_wrap_glDisableClientState
#define glAlphaFunc cogl_wrap_glAlphaFunc
#define glColor4f cogl_wrap_glColor4f
+#define glColor4ub cogl_wrap_glColor4ub
#define glClipPlanef cogl_wrap_glClipPlanef
#define glGetIntegerv cogl_wrap_glGetIntegerv
#define glGetFloatv cogl_wrap_glGetFloatv