[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.
This commit is contained in:
Robert Bragg 2009-06-17 18:46:42 +01:00
parent 04bb789941
commit 845ff67301
26 changed files with 1004 additions and 297 deletions

View File

@ -409,6 +409,9 @@ _clutter_do_pick (ClutterStage *stage,
/* Calls should work under both GL and GLES, note GLES needs RGBA */ /* Calls should work under both GL and GLES, note GLES needs RGBA */
glGetIntegerv(GL_VIEWPORT, viewport); glGetIntegerv(GL_VIEWPORT, viewport);
/* Make sure Cogl flushes any batched geometry to the GPU driver */
_cogl_flush ();
/* Read the color of the screen co-ords pixel */ /* Read the color of the screen co-ords pixel */
glReadPixels (x, viewport[3] - y -1, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel); glReadPixels (x, viewport[3] - y -1, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel);

View File

@ -29,16 +29,17 @@
G_BEGIN_DECLS G_BEGIN_DECLS
typedef enum { typedef enum {
COGL_DEBUG_MISC = 1 << 0, COGL_DEBUG_MISC = 1 << 0,
COGL_DEBUG_TEXTURE = 1 << 1, COGL_DEBUG_TEXTURE = 1 << 1,
COGL_DEBUG_MATERIAL = 1 << 2, COGL_DEBUG_MATERIAL = 1 << 2,
COGL_DEBUG_SHADER = 1 << 3, COGL_DEBUG_SHADER = 1 << 3,
COGL_DEBUG_OFFSCREEN = 1 << 4, COGL_DEBUG_OFFSCREEN = 1 << 4,
COGL_DEBUG_DRAW = 1 << 5, COGL_DEBUG_DRAW = 1 << 5,
COGL_DEBUG_PANGO = 1 << 6, COGL_DEBUG_PANGO = 1 << 6,
COGL_DEBUG_RECTANGLES = 1 << 7, COGL_DEBUG_RECTANGLES = 1 << 7,
COGL_DEBUG_HANDLE = 1 << 8, COGL_DEBUG_HANDLE = 1 << 8,
COGL_DEBUG_BLEND_STRINGS = 1 << 9 COGL_DEBUG_BLEND_STRINGS = 1 << 9,
COGL_DEBUG_DISABLE_BATCHING = 1 << 10
} CoglDebugFlags; } CoglDebugFlags;
#ifdef COGL_ENABLE_DEBUG #ifdef COGL_ENABLE_DEBUG

View File

@ -673,6 +673,16 @@ void cogl_material_set_layer_matrix (CoglHandle material,
*/ */
const GList *cogl_material_get_layers (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: * CoglMaterialLayerType:
* @COGL_MATERIAL_LAYER_TYPE_TEXTURE: The layer represents a * @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. * likely return COGL_INVALID_HANDLE if you try to get the texture.
* Considering this, you can call cogl_material_layer_get_type first, * Considering this, you can call cogl_material_layer_get_type first,
* to check it is of type COGL_MATERIAL_LAYER_TYPE_TEXTURE. * 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); CoglHandle cogl_material_layer_get_texture (CoglHandle layer_handle);

View File

@ -760,6 +760,20 @@ void cogl_flush_gl_state (int flags);
/* private */ /* private */
void _cogl_set_indirect_context (gboolean indirect); void _cogl_set_indirect_context (gboolean indirect);
/* private
*
* cogl_flush:
*
* As an optimization Cogl drawing functions may batch up primitives
* internally, so you need to call _cogl_flush to ensure that the
* drawing operations you have submitted for the current frame get
* flushed through to the driver and GPU.
*
* This must be called before issuing a swap buffers.
*/
void _cogl_flush (void);
G_END_DECLS G_END_DECLS
#undef __COGL_H_INSIDE__ #undef __COGL_H_INSIDE__

View File

@ -324,6 +324,10 @@ _cogl_clip_stack_rebuild (void)
_COGL_GET_CONTEXT (ctx, NO_RETVAL); _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; stack = (CoglClipStack *) ctx->clip.stacks->data;
ctx->clip.stack_dirty = FALSE; ctx->clip.stack_dirty = FALSE;

View File

@ -40,7 +40,8 @@ static const GDebugKey cogl_debug_keys[] = {
{ "pango", COGL_DEBUG_PANGO }, { "pango", COGL_DEBUG_PANGO },
{ "rectangles", COGL_DEBUG_RECTANGLES }, { "rectangles", COGL_DEBUG_RECTANGLES },
{ "handle", COGL_DEBUG_HANDLE }, { "handle", COGL_DEBUG_HANDLE },
{ "blend-strings", COGL_DEBUG_BLEND_STRINGS } { "blend-strings", COGL_DEBUG_BLEND_STRINGS },
{ "disable-batching", COGL_DEBUG_DISABLE_BATCHING }
}; };
static const gint n_cogl_debug_keys = G_N_ELEMENTS (cogl_debug_keys); static const gint n_cogl_debug_keys = G_N_ELEMENTS (cogl_debug_keys);

View File

@ -36,6 +36,16 @@
typedef struct _CoglMaterial CoglMaterial; typedef struct _CoglMaterial CoglMaterial;
typedef struct _CoglMaterialLayer CoglMaterialLayer; 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 /* XXX: I don't think gtk-doc supports having private enums so these aren't
* bundled in with CoglMaterialLayerFlags */ * bundled in with CoglMaterialLayerFlags */
typedef enum _CoglMaterialLayerPrivFlags typedef enum _CoglMaterialLayerPrivFlags
@ -90,17 +100,19 @@ struct _CoglMaterialLayer
typedef enum _CoglMaterialFlags typedef enum _CoglMaterialFlags
{ {
COGL_MATERIAL_FLAG_ENABLE_BLEND = 1L<<0, COGL_MATERIAL_FLAG_SHOWN_SAMPLER_WARNING = 1L<<0,
COGL_MATERIAL_FLAG_SHOWN_SAMPLER_WARNING = 1L<<1,
COGL_MATERIAL_FLAG_DEFAULT_COLOR = 1L<<2, COGL_MATERIAL_FLAG_DEFAULT_COLOR = 1L<<1,
COGL_MATERIAL_FLAG_DEFAULT_GL_MATERIAL = 1L<<3, COGL_MATERIAL_FLAG_DEFAULT_GL_MATERIAL = 1L<<2,
COGL_MATERIAL_FLAG_DEFAULT_ALPHA_FUNC = 1L<<4, COGL_MATERIAL_FLAG_DEFAULT_ALPHA_FUNC = 1L<<3,
COGL_MATERIAL_FLAG_DEFAULT_BLEND_FUNC = 1L<<5 COGL_MATERIAL_FLAG_ENABLE_BLEND = 1L<<4,
COGL_MATERIAL_FLAG_DEFAULT_BLEND = 1L<<5
} CoglMaterialFlags; } CoglMaterialFlags;
struct _CoglMaterial struct _CoglMaterial
{ {
CoglHandleObject _parent; CoglHandleObject _parent;
gulong journal_ref_count;
gulong flags; gulong flags;
@ -130,6 +142,7 @@ struct _CoglMaterial
GLint blend_dst_factor_rgb; GLint blend_dst_factor_rgb;
GList *layers; GList *layers;
guint n_layers;
}; };
/* /*
@ -183,39 +196,69 @@ typedef enum _CoglMaterialLayerFlags
gulong _cogl_material_layer_get_flags (CoglHandle layer_handle); gulong _cogl_material_layer_get_flags (CoglHandle layer_handle);
/* /*
* CoglMaterialFlushOption: * CoglMaterialFlushFlag:
* @COGL_MATERIAL_FLUSH_FALLBACK_MASK: Follow this by a guin32 mask * @COGL_MATERIAL_FLUSH_FALLBACK_MASK: The fallback_layers member is set to
* of the layers that can't be supported with the user supplied texture * a guint32 mask of the layers that can't be supported with the user
* and need to be replaced with fallback textures. (1 = fallback, and the * supplied texture and need to be replaced with fallback textures. (1 =
* least significant bit = layer 0) * fallback, and the least significant bit = layer 0)
* @COGL_MATERIAL_FLUSH_DISABLE_MASK: Follow this by a guint32 mask * @COGL_MATERIAL_FLUSH_DISABLE_MASK: The disable_layers member is set to
* of the layers that you want to completly disable texturing for * a guint32 mask of the layers that you want to completly disable
* (1 = fallback, and the least significant bit = layer 0) * texturing for (1 = fallback, and the least significant bit = layer 0)
* @COGL_MATERIAL_FLUSH_LAYER0_OVERRIDE: Follow this by a GLuint OpenGL texture * @COGL_MATERIAL_FLUSH_LAYER0_OVERRIDE: The layer0_override_texture member is
* name to override the texture used for layer 0 of the material. This is * set to a GLuint OpenGL texture name to override the texture used for
* intended for dealing with sliced textures where you will need to point * layer 0 of the material. This is intended for dealing with sliced
* to each of the texture slices in turn when drawing your geometry. * textures where you will need to point to each of the texture slices in
* Passing a value of 0 is the same as not passing the option at all. * 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_FALLBACK_MASK = 1L<<0,
COGL_MATERIAL_FLUSH_DISABLE_MASK, COGL_MATERIAL_FLUSH_DISABLE_MASK = 1L<<1,
COGL_MATERIAL_FLUSH_LAYER0_OVERRIDE, COGL_MATERIAL_FLUSH_LAYER0_OVERRIDE = 1L<<2,
} CoglMaterialFlushOption; COGL_MATERIAL_FLUSH_SKIP_GL_COLOR = 1L<<3
} CoglMaterialFlushFlag;
/*
* CoglMaterialFlushOptions:
*
*/
typedef struct _CoglMaterialFlushOptions
{
CoglMaterialFlushFlag flags;
guint32 fallback_layers;
guint32 disable_layers;
GLuint layer0_override_texture;
} CoglMaterialFlushOptions;
/* /*
* cogl_material_flush_gl_state: * cogl_material_flush_gl_state:
* @material: A CoglMaterial object * @material: A CoglMaterial object
* @...: A NULL terminated list of (CoglMaterialFlushOption, data) pairs * @...: A NULL terminated list of (CoglMaterialFlushOption, data) pairs
* *
* This function commits the state of the specified CoglMaterial - including * Note: It is possible for a layer object of type
* the texture state for all the layers - to the OpenGL[ES] driver. * 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.
* *
* Since 1.0 * Returns: A CoglHandle to the layers texture object or COGL_INVALID_HANDLE
* if a texture has not been set yet.
*/ */
void _cogl_material_flush_gl_state (CoglHandle material, 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 */ #endif /* __COGL_MATERIAL_PRIVATE_H */

View File

@ -111,9 +111,10 @@ cogl_material_new (void)
#endif #endif
material->blend_src_factor_rgb = GL_ONE; material->blend_src_factor_rgb = GL_ONE;
material->blend_dst_factor_rgb = GL_ONE_MINUS_SRC_ALPHA; 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->layers = NULL;
material->n_layers = 0;
return _cogl_material_handle_new (material); return _cogl_material_handle_new (material);
} }
@ -130,6 +131,7 @@ _cogl_material_free (CoglMaterial *material)
g_free (material); g_free (material);
} }
static void static void
handle_automatic_blend_enable (CoglMaterial *material) handle_automatic_blend_enable (CoglMaterial *material)
{ {
@ -139,6 +141,12 @@ handle_automatic_blend_enable (CoglMaterial *material)
* a flag to know when it's user configured, so we don't trash it */ * a flag to know when it's user configured, so we don't trash it */
material->flags &= ~COGL_MATERIAL_FLAG_ENABLE_BLEND; material->flags &= ~COGL_MATERIAL_FLAG_ENABLE_BLEND;
/* XXX: Uncomment this to disable all blending */
#if 0
return;
#endif
for (tmp = material->layers; tmp != NULL; tmp = tmp->next) for (tmp = material->layers; tmp != NULL; tmp = tmp->next)
{ {
CoglMaterialLayer *layer = tmp->data; CoglMaterialLayer *layer = tmp->data;
@ -156,6 +164,16 @@ handle_automatic_blend_enable (CoglMaterial *material)
material->flags |= COGL_MATERIAL_FLAG_ENABLE_BLEND; 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)
{
if (material->journal_ref_count)
_cogl_journal_flush ();
}
void void
cogl_material_get_color (CoglHandle handle, cogl_material_get_color (CoglHandle handle,
CoglColor *color) CoglColor *color)
@ -191,6 +209,9 @@ cogl_material_set_color (CoglHandle handle,
if (memcmp (unlit, material->unlit, sizeof (unlit)) == 0) if (memcmp (unlit, material->unlit, sizeof (unlit)) == 0)
return; return;
/* possibly flush primitives referencing the current state... */
_cogl_material_pre_change_notify (material);
memcpy (material->unlit, unlit, sizeof (unlit)); memcpy (material->unlit, unlit, sizeof (unlit));
material->flags &= ~COGL_MATERIAL_FLAG_DEFAULT_COLOR; material->flags &= ~COGL_MATERIAL_FLAG_DEFAULT_COLOR;
@ -255,6 +276,9 @@ cogl_material_set_ambient (CoglHandle handle,
material = _cogl_material_pointer_from_handle (handle); material = _cogl_material_pointer_from_handle (handle);
/* possibly flush primitives referencing the current state... */
_cogl_material_pre_change_notify (material);
ambient = material->ambient; ambient = material->ambient;
ambient[0] = cogl_color_get_red_float (ambient_color); ambient[0] = cogl_color_get_red_float (ambient_color);
ambient[1] = cogl_color_get_green_float (ambient_color); ambient[1] = cogl_color_get_green_float (ambient_color);
@ -292,6 +316,9 @@ cogl_material_set_diffuse (CoglHandle handle,
material = _cogl_material_pointer_from_handle (handle); material = _cogl_material_pointer_from_handle (handle);
/* possibly flush primitives referencing the current state... */
_cogl_material_pre_change_notify (material);
diffuse = material->diffuse; diffuse = material->diffuse;
diffuse[0] = cogl_color_get_red_float (diffuse_color); diffuse[0] = cogl_color_get_red_float (diffuse_color);
diffuse[1] = cogl_color_get_green_float (diffuse_color); diffuse[1] = cogl_color_get_green_float (diffuse_color);
@ -337,6 +364,9 @@ cogl_material_set_specular (CoglHandle handle,
material = _cogl_material_pointer_from_handle (handle); material = _cogl_material_pointer_from_handle (handle);
/* possibly flush primitives referencing the current state... */
_cogl_material_pre_change_notify (material);
specular = material->specular; specular = material->specular;
specular[0] = cogl_color_get_red_float (specular_color); specular[0] = cogl_color_get_red_float (specular_color);
specular[1] = cogl_color_get_green_float (specular_color); specular[1] = cogl_color_get_green_float (specular_color);
@ -372,6 +402,9 @@ cogl_material_set_shininess (CoglHandle handle,
material = _cogl_material_pointer_from_handle (handle); material = _cogl_material_pointer_from_handle (handle);
/* possibly flush primitives referencing the current state... */
_cogl_material_pre_change_notify (material);
material->shininess = (GLfloat)shininess * 128.0; material->shininess = (GLfloat)shininess * 128.0;
material->flags &= ~COGL_MATERIAL_FLAG_DEFAULT_GL_MATERIAL; material->flags &= ~COGL_MATERIAL_FLAG_DEFAULT_GL_MATERIAL;
@ -405,6 +438,9 @@ cogl_material_set_emission (CoglHandle handle,
material = _cogl_material_pointer_from_handle (handle); material = _cogl_material_pointer_from_handle (handle);
/* possibly flush primitives referencing the current state... */
_cogl_material_pre_change_notify (material);
emission = material->emission; emission = material->emission;
emission[0] = cogl_color_get_red_float (emission_color); emission[0] = cogl_color_get_red_float (emission_color);
emission[1] = cogl_color_get_green_float (emission_color); emission[1] = cogl_color_get_green_float (emission_color);
@ -424,6 +460,10 @@ cogl_material_set_alpha_test_function (CoglHandle handle,
g_return_if_fail (cogl_is_material (handle)); g_return_if_fail (cogl_is_material (handle));
material = _cogl_material_pointer_from_handle (handle); material = _cogl_material_pointer_from_handle (handle);
/* possibly flush primitives referencing the current state... */
_cogl_material_pre_change_notify (material);
material->alpha_func = alpha_func; material->alpha_func = alpha_func;
material->alpha_func_reference = (GLfloat)alpha_reference; material->alpha_func_reference = (GLfloat)alpha_reference;
@ -571,6 +611,9 @@ cogl_material_set_blend (CoglHandle handle,
a = &statements[1]; a = &statements[1];
} }
/* possibly flush primitives referencing the current state... */
_cogl_material_pre_change_notify (material);
#ifndef HAVE_COGL_GLES #ifndef HAVE_COGL_GLES
setup_blend_state (rgb, setup_blend_state (rgb,
&material->blend_equation_rgb, &material->blend_equation_rgb,
@ -587,7 +630,7 @@ cogl_material_set_blend (CoglHandle handle,
&material->blend_dst_factor_rgb); &material->blend_dst_factor_rgb);
#endif #endif
material->flags &= ~COGL_MATERIAL_FLAG_DEFAULT_BLEND_FUNC; material->flags &= ~COGL_MATERIAL_FLAG_DEFAULT_BLEND;
return TRUE; return TRUE;
} }
@ -604,13 +647,16 @@ cogl_material_set_blend_constant (CoglHandle handle,
material = _cogl_material_pointer_from_handle (handle); material = _cogl_material_pointer_from_handle (handle);
/* possibly flush primitives referencing the current state... */
_cogl_material_pre_change_notify (material);
constant = material->blend_constant; constant = material->blend_constant;
constant[0] = cogl_color_get_red_float (constant_color); constant[0] = cogl_color_get_red_float (constant_color);
constant[1] = cogl_color_get_green_float (constant_color); constant[1] = cogl_color_get_green_float (constant_color);
constant[2] = cogl_color_get_blue_float (constant_color); constant[2] = cogl_color_get_blue_float (constant_color);
constant[3] = cogl_color_get_alpha_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 #endif
} }
@ -682,20 +728,26 @@ cogl_material_set_layer (CoglHandle material_handle,
{ {
CoglMaterial *material; CoglMaterial *material;
CoglMaterialLayer *layer; CoglMaterialLayer *layer;
int n_layers;
g_return_if_fail (cogl_is_material (material_handle)); g_return_if_fail (cogl_is_material (material_handle));
g_return_if_fail (texture_handle == COGL_INVALID_HANDLE g_return_if_fail (texture_handle == COGL_INVALID_HANDLE
|| cogl_is_texture (texture_handle)); || cogl_is_texture (texture_handle));
material = _cogl_material_pointer_from_handle (material_handle); material = _cogl_material_pointer_from_handle (material_handle);
/* possibly flush primitives referencing the current state... */
_cogl_material_pre_change_notify (material);
layer = _cogl_material_get_layer (material_handle, layer_index, TRUE); layer = _cogl_material_get_layer (material_handle, layer_index, TRUE);
if (texture_handle == layer->texture) if (texture_handle == layer->texture)
return; return;
n_layers = g_list_length (material->layers); /* possibly flush primitives referencing the current state... */
if (n_layers >= CGL_MAX_COMBINED_TEXTURE_IMAGE_UNITS) _cogl_material_pre_change_notify (material);
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)) if (!(material->flags & COGL_MATERIAL_FLAG_SHOWN_SAMPLER_WARNING))
{ {
@ -856,6 +908,9 @@ cogl_material_set_layer_combine (CoglHandle handle,
a = &statements[1]; a = &statements[1];
} }
/* possibly flush primitives referencing the current state... */
_cogl_material_pre_change_notify (material);
setup_texture_combine_state (rgb, setup_texture_combine_state (rgb,
&layer->texture_combine_rgb_func, &layer->texture_combine_rgb_func,
layer->texture_combine_rgb_src, layer->texture_combine_rgb_src,
@ -886,6 +941,9 @@ cogl_material_set_layer_combine_constant (CoglHandle handle,
material = _cogl_material_pointer_from_handle (handle); material = _cogl_material_pointer_from_handle (handle);
layer = _cogl_material_get_layer (material, layer_index, TRUE); layer = _cogl_material_get_layer (material, layer_index, TRUE);
/* possibly flush primitives referencing the current state... */
_cogl_material_pre_change_notify (material);
constant = layer->texture_combine_constant; constant = layer->texture_combine_constant;
constant[0] = cogl_color_get_red_float (constant_color); constant[0] = cogl_color_get_red_float (constant_color);
constant[1] = cogl_color_get_green_float (constant_color); constant[1] = cogl_color_get_green_float (constant_color);
@ -909,6 +967,9 @@ cogl_material_set_layer_matrix (CoglHandle material_handle,
material = _cogl_material_pointer_from_handle (material_handle); material = _cogl_material_pointer_from_handle (material_handle);
layer = _cogl_material_get_layer (material, layer_index, TRUE); layer = _cogl_material_get_layer (material, layer_index, TRUE);
/* possibly flush primitives referencing the current state... */
_cogl_material_pre_change_notify (material);
layer->matrix = *matrix; layer->matrix = *matrix;
layer->flags |= COGL_MATERIAL_LAYER_FLAG_DIRTY; layer->flags |= COGL_MATERIAL_LAYER_FLAG_DIRTY;
@ -935,6 +996,10 @@ cogl_material_remove_layer (CoglHandle material_handle,
g_return_if_fail (cogl_is_material (material_handle)); g_return_if_fail (cogl_is_material (material_handle));
material = _cogl_material_pointer_from_handle (material_handle); material = _cogl_material_pointer_from_handle (material_handle);
/* possibly flush primitives referencing the current state... */
_cogl_material_pre_change_notify (material);
for (tmp = material->layers; tmp != NULL; tmp = tmp->next) for (tmp = material->layers; tmp != NULL; tmp = tmp->next)
{ {
layer = tmp->data; layer = tmp->data;
@ -943,6 +1008,7 @@ cogl_material_remove_layer (CoglHandle material_handle,
CoglHandle handle = (CoglHandle) layer; CoglHandle handle = (CoglHandle) layer;
cogl_handle_unref (handle); cogl_handle_unref (handle);
material->layers = g_list_remove (material->layers, layer); material->layers = g_list_remove (material->layers, layer);
material->n_layers--;
break; break;
} }
} }
@ -992,6 +1058,18 @@ cogl_material_get_layers (CoglHandle material_handle)
return material->layers; 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 CoglMaterialLayerType
cogl_material_layer_get_type (CoglHandle layer_handle) cogl_material_layer_get_type (CoglHandle layer_handle)
{ {
@ -1318,7 +1396,10 @@ _cogl_material_flush_layers_gl_state (CoglMaterial *material,
!gl_layer_info->disabled)) !gl_layer_info->disabled))
#endif #endif
{ {
/* XXX: Debug: Comment this out to disable all texturing: */
#if 1
GE (glEnable (gl_target)); GE (glEnable (gl_target));
#endif
} }
} }
else else
@ -1369,18 +1450,30 @@ _cogl_material_flush_layers_gl_state (CoglMaterial *material,
} }
static void 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); _COGL_GET_CONTEXT (ctx, NO_RETVAL);
if (!(ctx->current_material_flags & COGL_MATERIAL_FLAG_DEFAULT_COLOR /* XXX:
&& material->flags & COGL_MATERIAL_FLAG_DEFAULT_COLOR)) * 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... */ if (!(ctx->current_material_flags & COGL_MATERIAL_FLAG_DEFAULT_COLOR
GE (glColor4f (material->unlit[0], && material->flags & COGL_MATERIAL_FLAG_DEFAULT_COLOR) ||
material->unlit[1], /* Assume if we were previously told to skip the color, then
material->unlit[2], * the current color needs updating... */
material->unlit[3])); ctx->current_material_flush_options.flags &
COGL_MATERIAL_FLUSH_SKIP_GL_COLOR)
{
GE (glColor4f (material->unlit[0],
material->unlit[1],
material->unlit[2],
material->unlit[3]));
}
} }
if (!(ctx->current_material_flags & COGL_MATERIAL_FLAG_DEFAULT_GL_MATERIAL if (!(ctx->current_material_flags & COGL_MATERIAL_FLAG_DEFAULT_GL_MATERIAL
@ -1401,8 +1494,8 @@ _cogl_material_flush_base_gl_state (CoglMaterial *material)
GE (glAlphaFunc (material->alpha_func, material->alpha_func_reference)); GE (glAlphaFunc (material->alpha_func, material->alpha_func_reference));
} }
if (!(ctx->current_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_FUNC)) && material->flags & COGL_MATERIAL_FLAG_DEFAULT_BLEND))
{ {
#if defined (HAVE_COGL_GLES2) #if defined (HAVE_COGL_GLES2)
gboolean have_blend_equation_seperate = TRUE; gboolean have_blend_equation_seperate = TRUE;
@ -1441,32 +1534,33 @@ _cogl_material_flush_base_gl_state (CoglMaterial *material)
} }
void void
_cogl_material_flush_gl_state (CoglHandle handle, ...) _cogl_material_flush_gl_state (CoglHandle handle,
CoglMaterialFlushOptions *options)
{ {
CoglMaterial *material; CoglMaterial *material;
va_list ap; guint32 fallback_layers = 0;
CoglMaterialFlushOption option; guint32 disable_layers = 0;
guint32 fallback_layers = 0; GLuint layer0_override_texture = 0;
guint32 disable_layers = 0; gboolean skip_gl_color = FALSE;
GLuint layer0_override_texture = 0;
_COGL_GET_CONTEXT (ctx, NO_RETVAL); _COGL_GET_CONTEXT (ctx, NO_RETVAL);
material = _cogl_material_pointer_from_handle (handle); material = _cogl_material_pointer_from_handle (handle);
_cogl_material_flush_base_gl_state (material); if (options)
va_start (ap, handle);
while ((option = va_arg (ap, CoglMaterialFlushOption)))
{ {
if (option == COGL_MATERIAL_FLUSH_FALLBACK_MASK) if (options->flags & COGL_MATERIAL_FLUSH_FALLBACK_MASK)
fallback_layers = va_arg (ap, guint32); fallback_layers = options->fallback_layers;
else if (option == COGL_MATERIAL_FLUSH_DISABLE_MASK) if (options->flags & COGL_MATERIAL_FLUSH_DISABLE_MASK)
disable_layers = va_arg (ap, guint32); disable_layers = options->disable_layers;
else if (option == COGL_MATERIAL_FLUSH_LAYER0_OVERRIDE) if (options->flags & COGL_MATERIAL_FLUSH_LAYER0_OVERRIDE)
layer0_override_texture = va_arg (ap, GLuint); 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, _cogl_material_flush_layers_gl_state (material,
fallback_layers, fallback_layers,
@ -1483,6 +1577,158 @@ _cogl_material_flush_gl_state (CoglHandle handle, ...)
ctx->current_material = handle; ctx->current_material = handle;
ctx->current_material_flags = material->flags; 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 (!(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 /* TODO: Should go in cogl.c, but that implies duplication which is also
@ -1556,6 +1802,10 @@ cogl_material_set_layer_filters (CoglHandle handle,
g_return_if_fail (cogl_is_material (handle)); g_return_if_fail (cogl_is_material (handle));
material = _cogl_material_pointer_from_handle (handle); material = _cogl_material_pointer_from_handle (handle);
/* possibly flush primitives referencing the current state... */
_cogl_material_pre_change_notify (material);
layer = _cogl_material_get_layer (material, layer_index, TRUE); layer = _cogl_material_get_layer (material, layer_index, TRUE);
layer->min_filter = min_filter; layer->min_filter = min_filter;

View File

@ -40,10 +40,53 @@
#ifdef HAVE_COGL_GL #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 #define glClientActiveTexture ctx->pf_glClientActiveTexture
#elif defined (HAVE_COGL_GLES2)
#include "../gles/cogl-gles2-wrapper.h"
#endif #endif
/* XXX NB:
* Our journal's vertex data is arranged as follows:
* 4 vertices per quad:
* 2 or GLfloats per position
* 4 RGBA GLubytes,
* 2 GLfloats per tex coord * n_layers
*
* So for a given number of layers this gets the stride in
* 32bit words:
*/
#define GET_JOURNAL_VB_STRIDE_FOR_N_LAYERS(N_LAYERS) \
(2 + 1 + 2 * (N_LAYERS))
typedef void (*CoglJournalBatchCallback) (CoglJournalEntry *start,
int n_entries,
void *data);
typedef gboolean (*CoglJournalBatchTest) (CoglJournalEntry *entry0,
CoglJournalEntry *entry1);
typedef struct _CoglJournalFlushState
{
/* 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 */ /* these are defined in the particular backend */
void _cogl_path_add_node (gboolean new_sub_path, void _cogl_path_add_node (gboolean new_sub_path,
float x, float x,
@ -51,94 +94,107 @@ void _cogl_path_add_node (gboolean new_sub_path,
void _cogl_path_fill_nodes (); void _cogl_path_fill_nodes ();
void _cogl_path_stroke_nodes (); void _cogl_path_stroke_nodes ();
static void void
_cogl_journal_flush_quad_batch (CoglJournalEntry *batch_start, _cogl_journal_dump_quad_vertices (guint8 *data, int n_layers)
gint batch_len,
GLfloat *vertex_pointer)
{ {
gsize stride; size_t stride = GET_JOURNAL_VB_STRIDE_FOR_N_LAYERS (n_layers);
int i; int i;
gulong enable_flags = 0;
guint32 disable_mask;
int prev_n_texcoord_arrays_enabled;
_COGL_GET_CONTEXT (ctx, NO_RETVAL); _COGL_GET_CONTEXT (ctx, NO_RETVAL);
/* XXX NB: g_print ("stride = %d (%d bytes)\n", (int)stride, (int)stride * 4);
* 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);
disable_mask = (1 << batch_start->n_layers) - 1; for (i = 0; i < 4; i++)
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++)
{ {
GE (glClientActiveTexture (GL_TEXTURE0 + i)); float *v = (float *)data + (i * stride);
GE (glEnableClientState (GL_TEXTURE_COORD_ARRAY)); guint8 *c = data + 8 + (i * stride * 4);
GE (glTexCoordPointer (2, GL_FLOAT, stride, vertex_pointer + 2 + 2 * i)); int j;
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]);
for (j = 0; j < n_layers; j++)
{
float *t = v + 3 + 2 * 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; void
for (; i < prev_n_texcoord_arrays_enabled; i++) _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)); CoglJournalEntry *entry0 = &entries[i - 1];
GE (glDisableClientState (GL_TEXTURE_COORD_ARRAY)); 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 /* The last batch... */
* re-work the cogl_enable mechanism */ batch_callback (batch_start, batch_len, data);
enable_flags |= _cogl_material_get_cogl_enable_flags (ctx->source_material); }
if (ctx->enable_backface_culling) static void
enable_flags |= COGL_ENABLE_BACKFACE_CULLING; _cogl_journal_flush_modelview_and_entries (CoglJournalEntry *batch_start,
int batch_len,
void *data)
{
CoglJournalFlushState *state = data;
enable_flags |= COGL_ENABLE_VERTEX_ARRAY; GE (glLoadMatrixf ((GLfloat *)&batch_start->model_view));
cogl_enable (enable_flags);
GE (glVertexPointer (2, GL_FLOAT, stride, vertex_pointer));
_cogl_current_matrix_state_flush ();
#ifdef HAVE_COGL_GL #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 */ #else /* HAVE_COGL_GL */
/* GLES doesn't support GL_QUADS so we will use GL_TRIANGLES and if (batch_len > 1)
indices */ {
{ int indices_offset = (state->vertex_offset / 4) * 6;
int needed_indices = batch_len * 6; GE (glDrawElements (GL_TRIANGLES,
CoglHandle indices_handle 6 * batch_len,
= cogl_vertex_buffer_indices_get_for_quads (needed_indices); indices->type,
CoglVertexBufferIndices *indices indices_offset * state->indices_type_size));
= _cogl_vertex_buffer_indices_pointer_from_handle (indices_handle); }
else
GE (glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, {
GPOINTER_TO_UINT (indices->vbo_name))); GE (glDrawArrays (GL_TRIANGLE_FAN,
GE (glDrawElements (GL_TRIANGLES, state->vertex_offset, /* first */
6 * batch_len, 4)); /* n vertices */
indices->type, }
NULL)); #endif
GE (glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, 0));
}
#endif /* HAVE_COGL_GL */
/* DEBUGGING CODE XXX: /* DEBUGGING CODE XXX:
* This path will cause all rectangles to be drawn with a red, green * This path will cause all rectangles to be drawn with a red, green
@ -149,6 +205,7 @@ _cogl_journal_flush_quad_batch (CoglJournalEntry *batch_start,
{ {
static CoglHandle outline = COGL_INVALID_HANDLE; static CoglHandle outline = COGL_INVALID_HANDLE;
static int color = 0; static int color = 0;
int i;
if (outline == COGL_INVALID_HANDLE) if (outline == COGL_INVALID_HANDLE)
outline = cogl_material_new (); outline = cogl_material_new ();
@ -161,97 +218,293 @@ _cogl_journal_flush_quad_batch (CoglJournalEntry *batch_start,
color == 2 ? 0xff : 0x00, color == 2 ? 0xff : 0x00,
0xff); 0xff);
_cogl_material_flush_gl_state (outline, NULL); _cogl_material_flush_gl_state (outline, NULL);
_cogl_current_matrix_state_flush ();
GE( glDrawArrays (GL_LINE_LOOP, 4 * i, 4) ); 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 0
if (batch_len != 1)
g_debug ("batch len = %d", batch_len);
#endif
_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);
batch_and_call (batch_start,
batch_len,
compare_entry_modelviews,
_cogl_journal_flush_modelview_and_entries,
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;
}
/* 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;
int i;
int prev_n_texcoord_arrays_enabled;
#ifndef HAVE_COGL_GL
int needed_indices = batch_len * 6;
CoglHandle indices_handle;
CoglVertexBufferIndices *indices;
#endif
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
/* XXX NB:
* Our vertex data is arranged as follows:
* 4 vertices per quad: 2 GLfloats per position,
* 4 RGBA GLubytes,
* 2 GLfloats per tex coord * n_layers
*/
stride = GET_JOURNAL_VB_STRIDE_FOR_N_LAYERS (batch_start->n_layers);
stride *= sizeof (GLfloat);
GE (glVertexPointer (2, GL_FLOAT, stride, (void *)state->vbo_offset));
GE (glColorPointer (4, GL_UNSIGNED_BYTE, stride,
(void *)(state->vbo_offset + 8)));
for (i = 0; i < batch_start->n_layers; i++)
{
GE (glClientActiveTexture (GL_TEXTURE0 + i));
GE (glEnableClientState (GL_TEXTURE_COORD_ARRAY));
GE (glTexCoordPointer (2, GL_FLOAT, stride,
(void *)(state->vbo_offset + 12 + 8 * 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));
}
#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 use a vertex offset passed to glDraw{Arrays,Elements} */
state->vertex_offset = 0;
/* XXX: Uncomment for debugging */
#if 0
g_assert (cogl_get_features () & COGL_FEATURE_VBOS);
_cogl_journal_dump_quad_batch (((guint8 *)ctx->logged_vertices->data) +
(size_t)state->vbo_offset,
batch_start->n_layers,
batch_len);
#endif
batch_and_call (batch_start,
batch_len,
compare_entry_materials,
_cogl_journal_flush_material_and_entries,
data);
#ifndef HAVE_COGL_GL
GE (glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, 0));
#endif
/* progress forward through the VBO containing all our vertices */
state->vbo_offset += (stride * 4 * batch_len);
}
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)
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);
if (ctx->journal_vbo_len < needed_vbo_len)
{
GE (glDeleteBuffers (1, &ctx->journal_vbo));
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));
ctx->journal_vbo_len = needed_vbo_len;
}
else
{
GE (glBindBuffer (GL_ARRAY_BUFFER, ctx->journal_vbo));
GE (glBufferData (GL_ARRAY_BUFFER,
needed_vbo_len,
NULL,
GL_STATIC_DRAW));
GE (glBufferSubData (GL_ARRAY_BUFFER,
0,
needed_vbo_len,
vertices->data));
}
/* 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 void
_cogl_journal_flush (void) _cogl_journal_flush (void)
{ {
GLfloat *current_vertex_pointer; CoglJournalFlushState state;
GLfloat *batch_vertex_pointer; int i;
CoglJournalEntry *batch_start; gboolean vbo_fallback =
guint batch_len; (cogl_get_features () & COGL_FEATURE_VBOS) ? FALSE : TRUE;
int i;
_COGL_GET_CONTEXT (ctx, NO_RETVAL); _COGL_GET_CONTEXT (ctx, NO_RETVAL);
if (ctx->journal->len == 0) if (ctx->journal->len == 0)
return; return;
/* Current non-variables / constraints: /* 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;
/* 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 ();
/* batch_and_call() batches a list of journal entries according to some
* given criteria and calls a callback once for each determined batch.
* *
* - We don't have to worry about much GL state changing between journal * The process of flushing the journal is done by splitting the entries
* entries since currently the journal never out lasts a single call to * by three broad criteria:
* _cogl_multitexture_multiple_rectangles. So the user doesn't get the * 1) We split the entries according the number of material layers.
* chance to fiddle with anything. (XXX: later this will be extended at * Each time the number of material layers changes, then the stride
* which point we can start logging certain state changes) * changes, so we need to call gl{Vertex,Color,Texture}Pointer to
* * inform GL of new VO offsets.
* - Implied from above: all entries will refer to the same material. * 2) We then split according to compatible Cogl materials.
* * This is where we flush material state
* - Although _cogl_multitexture_multiple_rectangles can cause the wrap mode * 3) Finally we split according to modelview matrix changes.
* of textures to be modified, the journal is flushed if a wrap mode is * This is when we finally tell GL to draw something.
* changed so we don't currently have to log wrap mode changes.
*
* - XXX - others?
*/ */
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 */
/* TODO: "compile" the journal to find ways of batching draw calls and vertex for (i = 0; i < ctx->journal->len; i++)
* 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.
*/
batch_vertex_pointer = (GLfloat *)ctx->logged_vertices->data;
batch_start = (CoglJournalEntry *)ctx->journal->data;
batch_len = 1;
current_vertex_pointer = batch_vertex_pointer;
for (i = 1; i < ctx->journal->len; i++)
{ {
CoglJournalEntry *prev_entry = CoglJournalEntry *entry =
&g_array_index (ctx->journal, CoglJournalEntry, i - 1); &g_array_index (ctx->journal, CoglJournalEntry, i);
CoglJournalEntry *current_entry = prev_entry + 1; _cogl_material_journal_unref (entry->material);
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;
} }
/* The last batch... */ if (!vbo_fallback)
_cogl_journal_flush_quad_batch (batch_start, GE (glBindBuffer (GL_ARRAY_BUFFER, 0));
batch_len,
batch_vertex_pointer);
g_array_set_size (ctx->journal, 0); g_array_set_size (ctx->journal, 0);
g_array_set_size (ctx->logged_vertices, 0); g_array_set_size (ctx->logged_vertices, 0);
@ -263,18 +516,23 @@ _cogl_journal_log_quad (float x_1,
float x_2, float x_2,
float y_2, float y_2,
CoglHandle material, CoglHandle material,
gint n_layers, int n_layers,
guint32 fallback_mask, guint32 fallback_layers,
GLuint layer0_override_texture, GLuint layer0_override_texture,
float *tex_coords, float *tex_coords,
guint tex_coords_len) guint tex_coords_len)
{ {
int stride; size_t stride;
size_t byte_stride;
int next_vert; int next_vert;
GLfloat *v; GLfloat *v;
GLubyte *c;
int i; int i;
int next_entry; int next_entry;
guint32 disable_layers;
CoglJournalEntry *entry; CoglJournalEntry *entry;
CoglColor color;
guint8 r, g, b, a;
_COGL_GET_CONTEXT (ctx, NO_RETVAL); _COGL_GET_CONTEXT (ctx, NO_RETVAL);
@ -282,15 +540,16 @@ _cogl_journal_log_quad (float x_1,
* directly passed to OpenGL * directly passed to OpenGL
*/ */
/* We pack the vertex data as 2 (x,y) GLfloats folowed by 2 (tx,ty) GLfloats /* XXX: See definition of GET_JOURNAL_VB_STRIDE_FOR_N_LAYERS for details
* for each texture being used, E.g.: * about how we pack our vertex data */
* [X, Y, TX0, TY0, TX1, TY1, X, Y, TX0, TY0, X, Y, ...] stride = GET_JOURNAL_VB_STRIDE_FOR_N_LAYERS (n_layers);
*/ /* NB: stride is in 32bit words */
stride = 2 + n_layers * 2; byte_stride = stride * 4;
next_vert = ctx->logged_vertices->len; next_vert = ctx->logged_vertices->len;
g_array_set_size (ctx->logged_vertices, next_vert + 4 * stride); g_array_set_size (ctx->logged_vertices, next_vert + 4 * stride);
v = &g_array_index (ctx->logged_vertices, GLfloat, next_vert); v = &g_array_index (ctx->logged_vertices, GLfloat, next_vert);
c = (GLubyte *)(v + 2);
/* XXX: All the jumping around to fill in this strided buffer doesn't /* XXX: All the jumping around to fill in this strided buffer doesn't
* seem ideal. */ * seem ideal. */
@ -298,18 +557,32 @@ _cogl_journal_log_quad (float x_1,
/* XXX: we could defer expanding the vertex data for GL until we come /* XXX: we could defer expanding the vertex data for GL until we come
* to flushing the journal. */ * to flushing the journal. */
cogl_material_get_color (material, &color);
r = cogl_color_get_red_byte (&color);
g = cogl_color_get_green_byte (&color);
b = cogl_color_get_blue_byte (&color);
a = cogl_color_get_alpha_byte (&color);
v[0] = x_1; v[1] = y_1; v[0] = x_1; v[1] = y_1;
c[0] = r; c[1] = g; c[2] = b; c[3] = a;
v += stride; v += stride;
c += byte_stride;
v[0] = x_1; v[1] = y_2; v[0] = x_1; v[1] = y_2;
c[0] = r; c[1] = g; c[2] = b; c[3] = a;
v += stride; v += stride;
c += byte_stride;
v[0] = x_2; v[1] = y_2; v[0] = x_2; v[1] = y_2;
c[0] = r; c[1] = g; c[2] = b; c[3] = a;
v += stride; v += stride;
c += byte_stride;
v[0] = x_2; v[1] = y_1; v[0] = x_2; v[1] = y_1;
c[0] = r; c[1] = g; c[2] = b; c[3] = a;
for (i = 0; i < n_layers; i++) for (i = 0; i < n_layers; i++)
{ {
GLfloat *t = /* NB: See note at top about vertex buffer layout: */
&g_array_index (ctx->logged_vertices, GLfloat, next_vert + 2 + 2 * i); GLfloat *t = &g_array_index (ctx->logged_vertices,
GLfloat, next_vert + 3 + 2 * i);
t[0] = tex_coords[0]; t[1] = tex_coords[1]; t[0] = tex_coords[0]; t[1] = tex_coords[1];
t += stride; t += stride;
@ -320,14 +593,34 @@ _cogl_journal_log_quad (float x_1,
t[0] = tex_coords[2]; t[1] = tex_coords[1]; t[0] = tex_coords[2]; t[1] = tex_coords[1];
} }
/* XXX: Uncomment for debugging */
#if 0
v = &g_array_index (ctx->logged_vertices, GLfloat, next_vert);
_cogl_journal_dump_quad_vertices ((guint8 *)v, n_layers);
#endif
next_entry = ctx->journal->len; next_entry = ctx->journal->len;
g_array_set_size (ctx->journal, next_entry + 1); g_array_set_size (ctx->journal, next_entry + 1);
entry = &g_array_index (ctx->journal, CoglJournalEntry, next_entry); 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->n_layers = n_layers;
entry->fallback_mask = fallback_mask; entry->flush_options.flags =
entry->layer0_override_texture = layer0_override_texture; 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;
cogl_get_modelview_matrix (&entry->model_view);
if (cogl_debug_flags & COGL_DEBUG_DISABLE_BATCHING
|| cogl_debug_flags & COGL_DEBUG_RECTANGLES)
_cogl_journal_flush ();
} }
static void static void
@ -511,12 +804,12 @@ _cogl_multitexture_unsliced_quad (float x_1,
float x_2, float x_2,
float y_2, float y_2,
CoglHandle material, CoglHandle material,
gint n_layers, guint32 fallback_layers,
guint32 fallback_mask,
const float *user_tex_coords, const float *user_tex_coords,
gint user_tex_coords_len) 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; const GList *layers;
GList *tmp; GList *tmp;
int i; int i;
@ -601,7 +894,7 @@ _cogl_multitexture_unsliced_quad (float x_1,
/* NB: marking for fallback will replace the layer with /* NB: marking for fallback will replace the layer with
* a default transparent texture */ * a default transparent texture */
fallback_mask |= (1 << i); fallback_layers |= (1 << i);
} }
} }
@ -672,7 +965,7 @@ _cogl_multitexture_unsliced_quad (float x_1,
y_2, y_2,
material, material,
n_layers, n_layers,
fallback_mask, fallback_layers,
0, /* don't replace the layer0 texture */ 0, /* don't replace the layer0 texture */
final_tex_coords, final_tex_coords,
n_layers * 4); n_layers * 4);
@ -699,7 +992,7 @@ _cogl_rectangles_with_multitexture_coords (
const GList *layers; const GList *layers;
int n_layers; int n_layers;
const GList *tmp; const GList *tmp;
guint32 fallback_mask = 0; guint32 fallback_layers = 0;
gboolean all_use_sliced_quad_fallback = FALSE; gboolean all_use_sliced_quad_fallback = FALSE;
int i; int i;
@ -710,7 +1003,7 @@ _cogl_rectangles_with_multitexture_coords (
material = ctx->source_material; material = ctx->source_material;
layers = cogl_material_get_layers (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... * Validate all the layers of the current source material...
@ -740,7 +1033,7 @@ _cogl_rectangles_with_multitexture_coords (
{ {
if (i == 0) 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; all_use_sliced_quad_fallback = TRUE;
if (tmp->next) if (tmp->next)
{ {
@ -766,7 +1059,7 @@ _cogl_rectangles_with_multitexture_coords (
/* NB: marking for fallback will replace the layer with /* NB: marking for fallback will replace the layer with
* a default transparent texture */ * a default transparent texture */
fallback_mask |= (1 << i); fallback_layers |= (1 << i);
continue; continue;
} }
} }
@ -788,7 +1081,7 @@ _cogl_rectangles_with_multitexture_coords (
/* NB: marking for fallback will replace the layer with /* NB: marking for fallback will replace the layer with
* a default transparent texture */ * a default transparent texture */
fallback_mask |= (1 << i); fallback_layers |= (1 << i);
continue; continue;
} }
} }
@ -803,8 +1096,7 @@ _cogl_rectangles_with_multitexture_coords (
|| !_cogl_multitexture_unsliced_quad (rects[i].x_1, rects[i].y_1, || !_cogl_multitexture_unsliced_quad (rects[i].x_1, rects[i].y_1,
rects[i].x_2, rects[i].y_2, rects[i].x_2, rects[i].y_2,
material, material,
n_layers, fallback_layers,
fallback_mask,
rects[i].tex_coords, rects[i].tex_coords,
rects[i].tex_coords_len)) rects[i].tex_coords_len))
{ {
@ -832,7 +1124,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 (); _cogl_journal_flush ();
#endif
} }
void void
@ -947,6 +1243,7 @@ _cogl_texture_sliced_polygon (CoglTextureVertex *vertices,
int x, y, tex_num, i; int x, y, tex_num, i;
GLuint gl_handle; GLuint gl_handle;
GLfloat *v; GLfloat *v;
CoglMaterialFlushOptions options;
_COGL_GET_CONTEXT (ctx, NO_RETVAL); _COGL_GET_CONTEXT (ctx, NO_RETVAL);
@ -1027,13 +1324,14 @@ _cogl_texture_sliced_polygon (CoglTextureVertex *vertices,
v += stride; v += stride;
} }
_cogl_material_flush_gl_state (ctx->source_material, options.flags =
COGL_MATERIAL_FLUSH_DISABLE_MASK, COGL_MATERIAL_FLUSH_DISABLE_MASK |
(guint32)~1, /* disable all except the COGL_MATERIAL_FLUSH_LAYER0_OVERRIDE;
first layer */ /* disable all except the first layer */
COGL_MATERIAL_FLUSH_LAYER0_OVERRIDE, options.disable_layers = (guint32)~1;
gl_handle, options.layer0_override_texture = gl_handle;
NULL);
_cogl_material_flush_gl_state (ctx->source_material, &options);
_cogl_current_matrix_state_flush (); _cogl_current_matrix_state_flush ();
GE( glDrawArrays (GL_TRIANGLE_FAN, 0, n_vertices) ); GE( glDrawArrays (GL_TRIANGLE_FAN, 0, n_vertices) );
@ -1047,7 +1345,7 @@ _cogl_multitexture_unsliced_polygon (CoglTextureVertex *vertices,
guint n_layers, guint n_layers,
guint stride, guint stride,
gboolean use_color, gboolean use_color,
guint32 fallback_mask) guint32 fallback_layers)
{ {
CoglHandle material; CoglHandle material;
const GList *layers; const GList *layers;
@ -1055,6 +1353,7 @@ _cogl_multitexture_unsliced_polygon (CoglTextureVertex *vertices,
GList *tmp; GList *tmp;
CoglTexSliceSpan *y_span, *x_span; CoglTexSliceSpan *y_span, *x_span;
GLfloat *v; GLfloat *v;
CoglMaterialFlushOptions options;
_COGL_GET_CONTEXT (ctx, NO_RETVAL); _COGL_GET_CONTEXT (ctx, NO_RETVAL);
@ -1125,10 +1424,11 @@ _cogl_multitexture_unsliced_polygon (CoglTextureVertex *vertices,
} }
} }
_cogl_material_flush_gl_state (ctx->source_material, options.flags = COGL_MATERIAL_FLUSH_FALLBACK_MASK;
COGL_MATERIAL_FLUSH_FALLBACK_MASK, if (use_color)
fallback_mask, options.flags |= COGL_MATERIAL_FLUSH_SKIP_GL_COLOR;
NULL); options.fallback_layers = fallback_layers;
_cogl_material_flush_gl_state (ctx->source_material, &options);
_cogl_current_matrix_state_flush (); _cogl_current_matrix_state_flush ();
GE (glDrawArrays (GL_TRIANGLE_FAN, 0, n_vertices)); GE (glDrawArrays (GL_TRIANGLE_FAN, 0, n_vertices));
@ -1144,7 +1444,7 @@ cogl_polygon (CoglTextureVertex *vertices,
int n_layers; int n_layers;
GList *tmp; GList *tmp;
gboolean use_sliced_polygon_fallback = FALSE; gboolean use_sliced_polygon_fallback = FALSE;
guint32 fallback_mask = 0; guint32 fallback_layers = 0;
int i; int i;
gulong enable_flags; gulong enable_flags;
guint stride; guint stride;
@ -1154,6 +1454,7 @@ cogl_polygon (CoglTextureVertex *vertices,
_COGL_GET_CONTEXT (ctx, NO_RETVAL); _COGL_GET_CONTEXT (ctx, NO_RETVAL);
_cogl_journal_flush ();
cogl_clip_ensure (); cogl_clip_ensure ();
material = ctx->source_material; material = ctx->source_material;
@ -1228,7 +1529,7 @@ cogl_polygon (CoglTextureVertex *vertices,
"textures with waste\n", i); "textures with waste\n", i);
warning_seen = TRUE; warning_seen = TRUE;
fallback_mask |= (1 << i); fallback_layers |= (1 << i);
continue; continue;
} }
} }
@ -1293,7 +1594,7 @@ cogl_polygon (CoglTextureVertex *vertices,
n_layers, n_layers,
stride, stride,
use_color, use_color,
fallback_mask); fallback_layers);
/* Reset the size of the logged vertex array because rendering /* Reset the size of the logged vertex array because rendering
rectangles expects it to start at 0 */ rectangles expects it to start at 0 */
@ -1313,6 +1614,7 @@ cogl_path_fill_preserve (void)
{ {
_COGL_GET_CONTEXT (ctx, NO_RETVAL); _COGL_GET_CONTEXT (ctx, NO_RETVAL);
_cogl_journal_flush ();
cogl_clip_ensure (); cogl_clip_ensure ();
if (ctx->path_nodes->len == 0) if (ctx->path_nodes->len == 0)
@ -1334,11 +1636,12 @@ cogl_path_stroke_preserve (void)
{ {
_COGL_GET_CONTEXT (ctx, NO_RETVAL); _COGL_GET_CONTEXT (ctx, NO_RETVAL);
cogl_clip_ensure ();
if (ctx->path_nodes->len == 0) if (ctx->path_nodes->len == 0)
return; return;
_cogl_journal_flush ();
cogl_clip_ensure ();
_cogl_path_stroke_nodes(); _cogl_path_stroke_nodes();
} }

View File

@ -57,4 +57,6 @@ struct _CoglBezCubic
floatVec2 p4; floatVec2 p4;
}; };
void _cogl_journal_flush (void);
#endif /* __COGL_PRIMITIVES_H */ #endif /* __COGL_PRIMITIVES_H */

View File

@ -137,6 +137,7 @@
#include "cogl-vertex-buffer-private.h" #include "cogl-vertex-buffer-private.h"
#include "cogl-texture-private.h" #include "cogl-texture-private.h"
#include "cogl-material-private.h" #include "cogl-material-private.h"
#include "cogl-primitives.h"
#define PAD_FOR_ALIGNMENT(VAR, TYPE_SIZE) \ #define PAD_FOR_ALIGNMENT(VAR, TYPE_SIZE) \
(VAR = TYPE_SIZE + ((VAR - 1) & ~(TYPE_SIZE - 1))) (VAR = TYPE_SIZE + ((VAR - 1) & ~(TYPE_SIZE - 1)))
@ -1500,9 +1501,10 @@ enable_state_for_drawing_buffer (CoglVertexBuffer *buffer)
gulong enable_flags = 0; gulong enable_flags = 0;
guint max_texcoord_attrib_unit = 0; guint max_texcoord_attrib_unit = 0;
const GList *layers; const GList *layers;
guint32 fallback_mask = 0; guint32 fallback_layers = 0;
guint32 disable_mask = ~0; guint32 disable_layers = ~0;
int i; int i;
CoglMaterialFlushOptions options;
_COGL_GET_CONTEXT (ctx, NO_RETVAL); _COGL_GET_CONTEXT (ctx, NO_RETVAL);
@ -1573,7 +1575,7 @@ enable_state_for_drawing_buffer (CoglVertexBuffer *buffer)
pointer)); pointer));
if (attribute->texture_unit > max_texcoord_attrib_unit) if (attribute->texture_unit > max_texcoord_attrib_unit)
max_texcoord_attrib_unit = attribute->texture_unit; max_texcoord_attrib_unit = attribute->texture_unit;
disable_mask &= ~(1 << attribute->texture_unit); disable_layers &= ~(1 << attribute->texture_unit);
break; break;
case COGL_VERTEX_BUFFER_ATTRIB_FLAG_VERTEX_ARRAY: case COGL_VERTEX_BUFFER_ATTRIB_FLAG_VERTEX_ARRAY:
enable_flags |= COGL_ENABLE_VERTEX_ARRAY; enable_flags |= COGL_ENABLE_VERTEX_ARRAY;
@ -1638,17 +1640,17 @@ enable_state_for_drawing_buffer (CoglVertexBuffer *buffer)
* vertices once for each layer, each time with a fiddled texture * vertices once for each layer, each time with a fiddled texture
* matrix. * matrix.
*/ */
fallback_mask |= (1 << i); fallback_layers |= (1 << i);
} }
} }
_cogl_material_flush_gl_state (ctx->source_material, options.flags =
COGL_MATERIAL_FLUSH_FALLBACK_MASK, COGL_MATERIAL_FLUSH_FALLBACK_MASK |
fallback_mask, COGL_MATERIAL_FLUSH_DISABLE_MASK;
COGL_MATERIAL_FLUSH_DISABLE_MASK, options.fallback_layers = fallback_layers;
disable_mask, options.disable_layers = disable_layers;
NULL);
_cogl_material_flush_gl_state (ctx->source_material, &options);
enable_flags |= _cogl_material_get_cogl_enable_flags (ctx->source_material); enable_flags |= _cogl_material_get_cogl_enable_flags (ctx->source_material);
if (ctx->enable_backface_culling) if (ctx->enable_backface_culling)
@ -1730,6 +1732,9 @@ cogl_vertex_buffer_draw (CoglHandle handle,
if (!cogl_is_vertex_buffer (handle)) if (!cogl_is_vertex_buffer (handle))
return; return;
_cogl_journal_flush ();
cogl_clip_ensure ();
buffer = _cogl_vertex_buffer_pointer_from_handle (handle); buffer = _cogl_vertex_buffer_pointer_from_handle (handle);
cogl_clip_ensure (); cogl_clip_ensure ();
@ -1859,6 +1864,9 @@ cogl_vertex_buffer_draw_elements (CoglHandle handle,
if (!cogl_is_vertex_buffer (handle)) if (!cogl_is_vertex_buffer (handle))
return; return;
_cogl_journal_flush ();
cogl_clip_ensure ();
buffer = _cogl_vertex_buffer_pointer_from_handle (handle); buffer = _cogl_vertex_buffer_pointer_from_handle (handle);
if (!cogl_is_vertex_buffer_indices (indices_handle)) if (!cogl_is_vertex_buffer_indices (indices_handle))

View File

@ -216,6 +216,9 @@ cogl_get_enable ()
void void
cogl_set_depth_test_enabled (gboolean setting) cogl_set_depth_test_enabled (gboolean setting)
{ {
/* Currently the journal can't track changes to depth state... */
_cogl_journal_flush ();
if (setting) if (setting)
{ {
glEnable (GL_DEPTH_TEST); glEnable (GL_DEPTH_TEST);
@ -236,6 +239,9 @@ cogl_set_backface_culling_enabled (gboolean setting)
{ {
_COGL_GET_CONTEXT (ctx, NO_RETVAL); _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; ctx->enable_backface_culling = setting;
} }
@ -388,9 +394,15 @@ _cogl_add_stencil_clip (float x_offset,
float height, float height,
gboolean first) gboolean first)
{ {
CoglHandle current_source;
_COGL_GET_CONTEXT (ctx, NO_RETVAL); _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) if (first)
{ {
@ -443,9 +455,17 @@ _cogl_add_stencil_clip (float x_offset,
_cogl_set_current_matrix (COGL_MATRIX_MODELVIEW); _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 */ /* Restore the stencil mode */
GE( glStencilFunc (GL_EQUAL, 0x1, 0x1) ); GE( glStencilFunc (GL_EQUAL, 0x1, 0x1) );
GE( glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP) ); GE( glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP) );
/* restore the original source material */
cogl_set_source (current_source);
cogl_handle_unref (current_source);
} }
void void
@ -630,6 +650,9 @@ cogl_set_fog (const CoglColor *fog_color,
GLfloat fogColor[4]; GLfloat fogColor[4];
GLenum gl_mode = GL_LINEAR; 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[0] = cogl_color_get_red_float (fog_color);
fogColor[1] = cogl_color_get_green_float (fog_color); fogColor[1] = cogl_color_get_green_float (fog_color);
fogColor[2] = cogl_color_get_blue_float (fog_color); fogColor[2] = cogl_color_get_blue_float (fog_color);
@ -667,6 +690,9 @@ cogl_set_fog (const CoglColor *fog_color,
void void
cogl_disable_fog (void) cogl_disable_fog (void)
{ {
/* Currently the journal can't track changes to fog state... */
_cogl_journal_flush ();
glDisable (GL_FOG); glDisable (GL_FOG);
} }
@ -678,6 +704,12 @@ cogl_flush_gl_state (int flags)
} }
#endif #endif
void
_cogl_flush (void)
{
_cogl_journal_flush ();
}
void void
cogl_read_pixels (int x, cogl_read_pixels (int x,
int y, int y,
@ -711,6 +743,10 @@ cogl_read_pixels (int x,
glPixelStorei (GL_PACK_SKIP_ROWS, 0); glPixelStorei (GL_PACK_SKIP_ROWS, 0);
#endif /* HAVE_COGL_GL */ #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); glReadPixels (x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
/* TODO: consider using the GL_MESA_pack_invert extension in the future /* TODO: consider using the GL_MESA_pack_invert extension in the future

View File

@ -69,9 +69,13 @@ cogl_create_context ()
_context->journal = g_array_new (FALSE, FALSE, sizeof (CoglJournalEntry)); _context->journal = g_array_new (FALSE, FALSE, sizeof (CoglJournalEntry));
_context->logged_vertices = g_array_new (FALSE, FALSE, sizeof (GLfloat)); _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 = NULL;
_context->current_material_flags = 0; _context->current_material_flags = 0;
memset (&_context->current_material_flush_options,
0, sizeof (CoglMaterialFlushOptions));
_context->current_layers = g_array_new (FALSE, FALSE, _context->current_layers = g_array_new (FALSE, FALSE,
sizeof (CoglLayerInfo)); sizeof (CoglLayerInfo));
_context->n_texcoord_arrays_enabled = 0; _context->n_texcoord_arrays_enabled = 0;

View File

@ -28,6 +28,7 @@
#include "cogl-clip-stack.h" #include "cogl-clip-stack.h"
#include "cogl-matrix-stack.h" #include "cogl-matrix-stack.h"
#include "cogl-current-matrix.h" #include "cogl-current-matrix.h"
#include "cogl-material-private.h"
typedef struct typedef struct
{ {
@ -78,10 +79,13 @@ typedef struct
* can batch things together. */ * can batch things together. */
GArray *journal; GArray *journal;
GArray *logged_vertices; GArray *logged_vertices;
GLuint journal_vbo;
size_t journal_vbo_len;
/* Some simple caching, to minimize state changes... */ /* Some simple caching, to minimize state changes... */
CoglHandle current_material; CoglHandle current_material;
gulong current_material_flags; gulong current_material_flags;
CoglMaterialFlushOptions current_material_flush_options;
GArray *current_layers; GArray *current_layers;
guint n_texcoord_arrays_enabled; guint n_texcoord_arrays_enabled;

View File

@ -169,6 +169,8 @@ cogl_set_draw_buffer (CoglBufferTarget target, CoglHandle offscreen)
_COGL_GET_CONTEXT (ctx, NO_RETVAL); _COGL_GET_CONTEXT (ctx, NO_RETVAL);
_cogl_journal_flush ();
g_assert (ctx->draw_buffer_stack != NULL); g_assert (ctx->draw_buffer_stack != NULL);
draw_buffer = ctx->draw_buffer_stack->data; draw_buffer = ctx->draw_buffer_stack->data;

View File

@ -76,16 +76,18 @@ _cogl_path_stroke_nodes ()
{ {
guint path_start = 0; guint path_start = 0;
gulong enable_flags = COGL_ENABLE_VERTEX_ARRAY; gulong enable_flags = COGL_ENABLE_VERTEX_ARRAY;
CoglMaterialFlushOptions options;
_COGL_GET_CONTEXT (ctx, NO_RETVAL); _COGL_GET_CONTEXT (ctx, NO_RETVAL);
enable_flags |= _cogl_material_get_cogl_enable_flags (ctx->source_material); enable_flags |= _cogl_material_get_cogl_enable_flags (ctx->source_material);
cogl_enable (enable_flags); cogl_enable (enable_flags);
_cogl_material_flush_gl_state (ctx->source_material, options.flags = COGL_MATERIAL_FLUSH_DISABLE_MASK;
COGL_MATERIAL_FLUSH_DISABLE_MASK, /* disable all texture layers */
(guint32)~0, /* disable all texture layers */ options.disable_layers = (guint32)~0;
NULL);
_cogl_material_flush_gl_state (ctx->source_material, &options);
_cogl_current_matrix_state_flush (); _cogl_current_matrix_state_flush ();
while (path_start < ctx->path_nodes->len) while (path_start < ctx->path_nodes->len)
@ -123,18 +125,24 @@ _cogl_add_path_to_stencil_buffer (floatVec2 nodes_min,
CoglPathNode *path, CoglPathNode *path,
gboolean merge) gboolean merge)
{ {
guint path_start = 0; guint path_start = 0;
guint sub_path_num = 0; guint sub_path_num = 0;
float bounds_x; float bounds_x;
float bounds_y; float bounds_y;
float bounds_w; float bounds_w;
float bounds_h; float bounds_h;
gulong enable_flags = COGL_ENABLE_VERTEX_ARRAY; gulong enable_flags = COGL_ENABLE_VERTEX_ARRAY;
CoglHandle prev_source;
_COGL_GET_CONTEXT (ctx, NO_RETVAL); _COGL_GET_CONTEXT (ctx, NO_RETVAL);
_cogl_journal_flush ();
/* Just setup a simple material that doesn't use texturing... */ /* 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 |= enable_flags |=
_cogl_material_get_cogl_enable_flags (ctx->source_material); _cogl_material_get_cogl_enable_flags (ctx->source_material);
@ -161,9 +169,12 @@ _cogl_add_path_to_stencil_buffer (floatVec2 nodes_min,
GE( glColorMask (FALSE, FALSE, FALSE, FALSE) ); GE( glColorMask (FALSE, FALSE, FALSE, FALSE) );
GE( glDepthMask (FALSE) ); GE( glDepthMask (FALSE) );
_cogl_current_matrix_state_flush ();
while (path_start < path_size) while (path_start < path_size)
{ {
/* NB: after calling _cogl_journal_flush the current matrix
* state is undefined */
_cogl_current_matrix_state_flush ();
GE( glVertexPointer (2, GL_FLOAT, sizeof (CoglPathNode), GE( glVertexPointer (2, GL_FLOAT, sizeof (CoglPathNode),
(guchar *) path (guchar *) path
+ G_STRUCT_OFFSET (CoglPathNode, x)) ); + G_STRUCT_OFFSET (CoglPathNode, x)) );
@ -177,7 +188,7 @@ _cogl_add_path_to_stencil_buffer (floatVec2 nodes_min,
GE( glStencilOp (GL_ZERO, GL_REPLACE, GL_REPLACE) ); GE( glStencilOp (GL_ZERO, GL_REPLACE, GL_REPLACE) );
cogl_rectangle (bounds_x, bounds_y, cogl_rectangle (bounds_x, bounds_y,
bounds_x + bounds_w, bounds_y + bounds_h); bounds_x + bounds_w, bounds_y + bounds_h);
_cogl_journal_flush ();
GE( glStencilOp (GL_INVERT, GL_INVERT, GL_INVERT) ); GE( glStencilOp (GL_INVERT, GL_INVERT, GL_INVERT) );
} }
@ -212,6 +223,7 @@ _cogl_add_path_to_stencil_buffer (floatVec2 nodes_min,
cogl_rectangle (-1.0, -1.0, 1.0, 1.0); cogl_rectangle (-1.0, -1.0, 1.0, 1.0);
cogl_rectangle (-1.0, -1.0, 1.0, 1.0); cogl_rectangle (-1.0, -1.0, 1.0, 1.0);
_cogl_journal_flush ();
_cogl_current_matrix_pop (); _cogl_current_matrix_pop ();
@ -227,6 +239,10 @@ _cogl_add_path_to_stencil_buffer (floatVec2 nodes_min,
GE( glStencilFunc (GL_EQUAL, 0x1, 0x1) ); GE( glStencilFunc (GL_EQUAL, 0x1, 0x1) );
GE( glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP) ); GE( glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP) );
/* restore the original material */
cogl_set_source (prev_source);
cogl_handle_unref (prev_source);
} }
void void

View File

@ -128,6 +128,11 @@ cogl_program_use (CoglHandle handle)
if (handle != COGL_INVALID_HANDLE && !cogl_is_program (handle)) if (handle != COGL_INVALID_HANDLE && !cogl_is_program (handle))
return; 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) if (handle == COGL_INVALID_HANDLE)
gl_handle = 0; gl_handle = 0;
else else

View File

@ -26,6 +26,7 @@
#include "cogl-bitmap-private.h" #include "cogl-bitmap-private.h"
#include "cogl-handle.h" #include "cogl-handle.h"
#include "cogl-material-private.h"
typedef struct _CoglTexture CoglTexture; typedef struct _CoglTexture CoglTexture;
typedef struct _CoglTexSliceSpan CoglTexSliceSpan; typedef struct _CoglTexSliceSpan CoglTexSliceSpan;
@ -99,10 +100,13 @@ struct _CoglTexture
* later flush the journal we aim to batch data, and gl draw calls. */ * later flush the journal we aim to batch data, and gl draw calls. */
typedef struct _CoglJournalEntry typedef struct _CoglJournalEntry
{ {
CoglHandle material; CoglHandle material;
gint n_layers; int n_layers;
guint32 fallback_mask; CoglMaterialFlushOptions flush_options;
GLuint layer0_override_texture; 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; } CoglJournalEntry;
CoglTexture* CoglTexture*

View File

@ -39,6 +39,7 @@
#include "cogl-material.h" #include "cogl-material.h"
#include "cogl-context.h" #include "cogl-context.h"
#include "cogl-handle.h" #include "cogl-handle.h"
#include "cogl-primitives.h"
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
@ -60,8 +61,6 @@
#endif #endif
extern void _cogl_journal_flush (void);
static void _cogl_texture_free (CoglTexture *tex); static void _cogl_texture_free (CoglTexture *tex);
COGL_HANDLE_DEFINE (Texture, texture); COGL_HANDLE_DEFINE (Texture, texture);

View File

@ -81,6 +81,7 @@ clutter_backend_egl_redraw (ClutterBackend *backend,
eglWaitNative (EGL_CORE_NATIVE_ENGINE); eglWaitNative (EGL_CORE_NATIVE_ENGINE);
clutter_actor_paint (CLUTTER_ACTOR (stage)); clutter_actor_paint (CLUTTER_ACTOR (stage));
_cogl_flush ();
eglWaitGL(); eglWaitGL();
eglSwapBuffers (backend_egl->edpy, stage_egl->egl_surface); eglSwapBuffers (backend_egl->edpy, stage_egl->egl_surface);

View File

@ -139,6 +139,7 @@ clutter_backend_egl_redraw (ClutterBackend *backend,
/* this will cause the stage implementation to be painted as well */ /* this will cause the stage implementation to be painted as well */
clutter_actor_paint (CLUTTER_ACTOR (stage)); clutter_actor_paint (CLUTTER_ACTOR (stage));
_cogl_flush ();
/* Why this paint is done in backend as likely GL windowing system /* Why this paint is done in backend as likely GL windowing system
* specific calls, like swapping buffers. * specific calls, like swapping buffers.

View File

@ -72,6 +72,7 @@ clutter_backend_egl_redraw (ClutterBackend *backend,
eglWaitNative (EGL_CORE_NATIVE_ENGINE); eglWaitNative (EGL_CORE_NATIVE_ENGINE);
clutter_actor_paint (CLUTTER_ACTOR (stage)); clutter_actor_paint (CLUTTER_ACTOR (stage));
_cogl_flush ();
eglWaitGL(); eglWaitGL();
eglSwapBuffers (backend_egl->edpy, stage_egl->egl_surface); eglSwapBuffers (backend_egl->edpy, stage_egl->egl_surface);
} }

View File

@ -498,6 +498,7 @@ clutter_backend_glx_redraw (ClutterBackend *backend,
/* this will cause the stage implementation to be painted */ /* this will cause the stage implementation to be painted */
clutter_actor_paint (CLUTTER_ACTOR (stage)); clutter_actor_paint (CLUTTER_ACTOR (stage));
_cogl_flush ();
if (stage_x11->xwin != None) if (stage_x11->xwin != None)
{ {

View File

@ -128,6 +128,7 @@ clutter_stage_osx_state_update (ClutterStageOSX *self,
- (void) drawRect: (NSRect) bounds - (void) drawRect: (NSRect) bounds
{ {
clutter_actor_paint (CLUTTER_ACTOR (self->stage_osx->wrapper)); clutter_actor_paint (CLUTTER_ACTOR (self->stage_osx->wrapper));
_cogl_flush ();
[[self openGLContext] flushBuffer]; [[self openGLContext] flushBuffer];
} }

View File

@ -68,7 +68,8 @@ clutter_backend_sdl_redraw (ClutterBackend *backend,
ClutterStage *stage) ClutterStage *stage)
{ {
clutter_actor_paint (CLUTTER_ACTOR (stage)); clutter_actor_paint (CLUTTER_ACTOR (stage));
_cogl_flush ();
SDL_GL_SwapBuffers(); SDL_GL_SwapBuffers();
} }

View File

@ -297,6 +297,7 @@ clutter_backend_win32_redraw (ClutterBackend *backend,
/* this will cause the stage implementation to be painted */ /* this will cause the stage implementation to be painted */
clutter_actor_paint (CLUTTER_ACTOR (stage)); clutter_actor_paint (CLUTTER_ACTOR (stage));
_cogl_flush ();
if (stage_win32->client_dc) if (stage_win32->client_dc)
SwapBuffers (stage_win32->client_dc); SwapBuffers (stage_win32->client_dc);