[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 */
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 */
glReadPixels (x, viewport[3] - y -1, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel);

View File

@ -29,16 +29,17 @@
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
} CoglDebugFlags;
#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);
/**
* 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);

View File

@ -760,6 +760,20 @@ void cogl_flush_gl_state (int flags);
/* private */
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
#undef __COGL_H_INSIDE__

View File

@ -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;

View File

@ -40,7 +40,8 @@ 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 }
};
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 _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,17 +100,19 @@ 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;
@ -130,6 +142,7 @@ struct _CoglMaterial
GLint blend_dst_factor_rgb;
GList *layers;
guint n_layers;
};
/*
@ -183,39 +196,69 @@ 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;
/*
* CoglMaterialFlushOptions:
*
*/
typedef struct _CoglMaterialFlushOptions
{
CoglMaterialFlushFlag flags;
guint32 fallback_layers;
guint32 disable_layers;
GLuint layer0_override_texture;
} CoglMaterialFlushOptions;
/*
* cogl_material_flush_gl_state:
* @material: A CoglMaterial object
* @...: A NULL terminated list of (CoglMaterialFlushOption, data) pairs
*
* This function commits the state of the specified CoglMaterial - including
* the texture state for all the layers - to the OpenGL[ES] driver.
* 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.
*
* 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,
...) 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 */

View File

@ -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,6 +131,7 @@ _cogl_material_free (CoglMaterial *material)
g_free (material);
}
static void
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 */
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)
{
CoglMaterialLayer *layer = tmp->data;
@ -156,6 +164,16 @@ handle_automatic_blend_enable (CoglMaterial *material)
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
cogl_material_get_color (CoglHandle handle,
CoglColor *color)
@ -191,6 +209,9 @@ cogl_material_set_color (CoglHandle handle,
if (memcmp (unlit, material->unlit, sizeof (unlit)) == 0)
return;
/* possibly flush primitives referencing the current state... */
_cogl_material_pre_change_notify (material);
memcpy (material->unlit, unlit, sizeof (unlit));
material->flags &= ~COGL_MATERIAL_FLAG_DEFAULT_COLOR;
@ -255,6 +276,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);
ambient = material->ambient;
ambient[0] = cogl_color_get_red_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);
/* possibly flush primitives referencing the current state... */
_cogl_material_pre_change_notify (material);
diffuse = material->diffuse;
diffuse[0] = cogl_color_get_red_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);
/* possibly flush primitives referencing the current state... */
_cogl_material_pre_change_notify (material);
specular = material->specular;
specular[0] = cogl_color_get_red_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);
/* possibly flush primitives referencing the current state... */
_cogl_material_pre_change_notify (material);
material->shininess = (GLfloat)shininess * 128.0;
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);
/* possibly flush primitives referencing the current state... */
_cogl_material_pre_change_notify (material);
emission = material->emission;
emission[0] = cogl_color_get_red_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));
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_reference = (GLfloat)alpha_reference;
@ -571,6 +611,9 @@ cogl_material_set_blend (CoglHandle handle,
a = &statements[1];
}
/* possibly flush primitives referencing the current state... */
_cogl_material_pre_change_notify (material);
#ifndef HAVE_COGL_GLES
setup_blend_state (rgb,
&material->blend_equation_rgb,
@ -587,7 +630,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 +647,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);
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
}
@ -682,20 +728,26 @@ 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);
/* possibly flush primitives referencing the current state... */
_cogl_material_pre_change_notify (material);
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);
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 +908,9 @@ cogl_material_set_layer_combine (CoglHandle handle,
a = &statements[1];
}
/* possibly flush primitives referencing the current state... */
_cogl_material_pre_change_notify (material);
setup_texture_combine_state (rgb,
&layer->texture_combine_rgb_func,
layer->texture_combine_rgb_src,
@ -886,6 +941,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);
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 +967,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);
layer->matrix = *matrix;
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));
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)
{
layer = tmp->data;
@ -943,6 +1008,7 @@ cogl_material_remove_layer (CoglHandle material_handle,
CoglHandle handle = (CoglHandle) layer;
cogl_handle_unref (handle);
material->layers = g_list_remove (material->layers, layer);
material->n_layers--;
break;
}
}
@ -992,6 +1058,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 +1396,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 +1450,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 (glColor4f (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 +1494,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 +1534,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 +1577,158 @@ _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 (!(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
@ -1556,6 +1802,10 @@ cogl_material_set_layer_filters (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);
layer = _cogl_material_get_layer (material, layer_index, TRUE);
layer->min_filter = min_filter;

View File

@ -40,10 +40,53 @@
#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 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 */
void _cogl_path_add_node (gboolean new_sub_path,
float x,
@ -51,94 +94,107 @@ 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 ("stride = %d (%d bytes)\n", (int)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 + 8 + (i * stride * 4);
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;
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);
GE (glVertexPointer (2, GL_FLOAT, stride, vertex_pointer));
_cogl_current_matrix_state_flush ();
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 +205,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 +218,293 @@ _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 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
_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:
/* 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
* 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?
* The process of flushing the journal is done by splitting the entries
* by three broad criteria:
* 1) We split the entries according the number of material layers.
* Each time the number of material layers changes, then the stride
* changes, so we need to call gl{Vertex,Color,Texture}Pointer to
* inform GL of new VO offsets.
* 2) We then split according to compatible Cogl materials.
* This is where we flush material state
* 3) Finally we split according to modelview matrix changes.
* This is when we finally tell GL to draw something.
*/
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
* 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++)
for (i = 0; i < ctx->journal->len; i++)
{
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;
CoglJournalEntry *entry =
&g_array_index (ctx->journal, CoglJournalEntry, i);
_cogl_material_journal_unref (entry->material);
}
/* The last batch... */
_cogl_journal_flush_quad_batch (batch_start,
batch_len,
batch_vertex_pointer);
if (!vbo_fallback)
GE (glBindBuffer (GL_ARRAY_BUFFER, 0));
g_array_set_size (ctx->journal, 0);
g_array_set_size (ctx->logged_vertices, 0);
@ -263,18 +516,23 @@ _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;
int i;
int next_entry;
guint32 disable_layers;
CoglJournalEntry *entry;
CoglColor color;
guint8 r, g, b, a;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
@ -282,15 +540,16 @@ _cogl_journal_log_quad (float x_1,
* 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 + 2);
/* XXX: All the jumping around to fill in this strided buffer doesn't
* 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
* 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;
c[0] = r; c[1] = g; c[2] = b; c[3] = a;
v += stride;
c += byte_stride;
v[0] = x_1; v[1] = y_2;
c[0] = r; c[1] = g; c[2] = b; c[3] = a;
v += stride;
c += byte_stride;
v[0] = x_2; v[1] = y_2;
c[0] = r; c[1] = g; c[2] = b; c[3] = a;
v += stride;
c += byte_stride;
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++)
{
GLfloat *t =
&g_array_index (ctx->logged_vertices, GLfloat, next_vert + 2 + 2 * i);
/* NB: See note at top about vertex buffer layout: */
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 += stride;
@ -320,14 +593,34 @@ _cogl_journal_log_quad (float x_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;
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;
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
@ -511,12 +804,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 +894,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 +965,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 +992,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 +1003,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 +1033,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 +1059,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 +1081,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 +1096,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 +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 ();
#endif
}
void
@ -947,6 +1243,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 +1324,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 +1345,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 +1353,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 +1424,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 +1444,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 +1454,7 @@ cogl_polygon (CoglTextureVertex *vertices,
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
_cogl_journal_flush ();
cogl_clip_ensure ();
material = ctx->source_material;
@ -1228,7 +1529,7 @@ cogl_polygon (CoglTextureVertex *vertices,
"textures with waste\n", i);
warning_seen = TRUE;
fallback_mask |= (1 << i);
fallback_layers |= (1 << i);
continue;
}
}
@ -1293,7 +1594,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 +1614,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 +1636,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();
}

View File

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

View File

@ -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,17 @@ 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);
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 +1732,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 +1864,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))

View File

@ -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
@ -630,6 +650,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 +690,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 +704,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 +743,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

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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,24 @@ _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;
_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,9 +169,12 @@ _cogl_add_path_to_stencil_buffer (floatVec2 nodes_min,
GE( glColorMask (FALSE, FALSE, FALSE, FALSE) );
GE( glDepthMask (FALSE) );
_cogl_current_matrix_state_flush ();
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),
(guchar *) path
+ 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) );
cogl_rectangle (bounds_x, bounds_y,
bounds_x + bounds_w, bounds_y + bounds_h);
_cogl_journal_flush ();
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_journal_flush ();
_cogl_current_matrix_pop ();
@ -227,6 +239,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

View File

@ -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

View File

@ -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*

View File

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

View File

@ -81,6 +81,7 @@ clutter_backend_egl_redraw (ClutterBackend *backend,
eglWaitNative (EGL_CORE_NATIVE_ENGINE);
clutter_actor_paint (CLUTTER_ACTOR (stage));
_cogl_flush ();
eglWaitGL();
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 */
clutter_actor_paint (CLUTTER_ACTOR (stage));
_cogl_flush ();
/* Why this paint is done in backend as likely GL windowing system
* specific calls, like swapping buffers.

View File

@ -72,6 +72,7 @@ clutter_backend_egl_redraw (ClutterBackend *backend,
eglWaitNative (EGL_CORE_NATIVE_ENGINE);
clutter_actor_paint (CLUTTER_ACTOR (stage));
_cogl_flush ();
eglWaitGL();
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 */
clutter_actor_paint (CLUTTER_ACTOR (stage));
_cogl_flush ();
if (stage_x11->xwin != None)
{

View File

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

View File

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

View File

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