diff --git a/cogl/cogl-attribute-private.h b/cogl/cogl-attribute-private.h index d38f4e6cc..a27924b02 100644 --- a/cogl/cogl-attribute-private.h +++ b/cogl/cogl-attribute-private.h @@ -126,5 +126,8 @@ _cogl_flush_attributes_state (CoglFramebuffer *framebuffer, CoglAttribute **attributes, int n_attributes); +int +_cogl_attribute_get_n_components (CoglAttribute *attribute); + #endif /* __COGL_ATTRIBUTE_PRIVATE_H */ diff --git a/cogl/cogl-attribute.c b/cogl/cogl-attribute.c index b0ac790e1..bc45399ff 100644 --- a/cogl/cogl-attribute.c +++ b/cogl/cogl-attribute.c @@ -657,3 +657,12 @@ _cogl_flush_attributes_state (CoglFramebuffer *framebuffer, if (copy) cogl_object_unref (copy); } + +int +_cogl_attribute_get_n_components (CoglAttribute *attribute) +{ + if (attribute->is_buffered) + return attribute->d.buffered.n_components; + else + return attribute->d.constant.boxed.size; +} diff --git a/cogl/cogl-context-private.h b/cogl/cogl-context-private.h index d73928ea3..c800b3f64 100644 --- a/cogl/cogl-context-private.h +++ b/cogl/cogl-context-private.h @@ -167,7 +167,8 @@ struct _CoglContext /* Some simple caching, to minimize state changes... */ CoglPipeline *current_pipeline; unsigned long current_pipeline_changes_since_flush; - CoglBool current_pipeline_skip_gl_color; + CoglBool current_pipeline_with_color_attrib; + CoglBool current_pipeline_unknown_color_alpha; unsigned long current_pipeline_age; CoglBool gl_blend_enable_cache; diff --git a/cogl/cogl-context.c b/cogl/cogl-context.c index 070f2d907..96254b926 100644 --- a/cogl/cogl-context.c +++ b/cogl/cogl-context.c @@ -325,7 +325,7 @@ cogl_context_new (CoglDisplay *display, context->current_pipeline = NULL; context->current_pipeline_changes_since_flush = 0; - context->current_pipeline_skip_gl_color = FALSE; + context->current_pipeline_with_color_attrib = FALSE; _cogl_bitmask_init (&context->enabled_builtin_attributes); _cogl_bitmask_init (&context->enable_builtin_attributes_tmp); diff --git a/cogl/cogl-pipeline-layer-state.c b/cogl/cogl-pipeline-layer-state.c index 606d121c6..8b8594dc7 100644 --- a/cogl/cogl-pipeline-layer-state.c +++ b/cogl/cogl-pipeline-layer-state.c @@ -210,7 +210,7 @@ _cogl_pipeline_set_layer_texture_type (CoglPipeline *pipeline, changed: - _cogl_pipeline_update_blend_enable (pipeline, COGL_PIPELINE_STATE_LAYERS); + pipeline->dirty_real_blend_enable = TRUE; } static void @@ -289,7 +289,7 @@ _cogl_pipeline_set_layer_texture_data (CoglPipeline *pipeline, changed: - _cogl_pipeline_update_blend_enable (pipeline, COGL_PIPELINE_STATE_LAYERS); + pipeline->dirty_real_blend_enable = TRUE; } void @@ -1267,7 +1267,7 @@ cogl_pipeline_set_layer_combine (CoglPipeline *pipeline, changed: - _cogl_pipeline_update_blend_enable (pipeline, COGL_PIPELINE_STATE_LAYERS); + pipeline->dirty_real_blend_enable = TRUE; return TRUE; } @@ -1352,7 +1352,7 @@ cogl_pipeline_set_layer_combine_constant (CoglPipeline *pipeline, changed: - _cogl_pipeline_update_blend_enable (pipeline, COGL_PIPELINE_STATE_LAYERS); + pipeline->dirty_real_blend_enable = TRUE; } void diff --git a/cogl/cogl-pipeline-private.h b/cogl/cogl-pipeline-private.h index acb5653cc..2679fbb40 100644 --- a/cogl/cogl-pipeline-private.h +++ b/cogl/cogl-pipeline-private.h @@ -470,6 +470,19 @@ struct _CoglPipeline * blending, this holds our final decision */ unsigned int real_blend_enable:1; + /* Since the code for deciding if blending really needs to be + * enabled for a particular pipeline is quite expensive we update + * the real_blend_enable flag lazily when flushing a pipeline if + * this dirty flag has been set. */ + unsigned int dirty_real_blend_enable:1; + + /* Whenever a pipeline is flushed we keep track of whether the + * pipeline was used with a color attribute where we don't know + * whether the colors are opaque. The real_blend_enable state + * depends on this, and must be updated whenever this changes (even + * if dirty_real_blend_enable isn't set) */ + unsigned int unknown_color_alpha:1; + unsigned int layers_cache_dirty:1; unsigned int deprecated_get_layers_list_dirty:1; @@ -597,8 +610,9 @@ _cogl_pipeline_pre_change_notify (CoglPipeline *pipeline, void _cogl_pipeline_prune_redundant_ancestry (CoglPipeline *pipeline); -void _cogl_pipeline_update_blend_enable (CoglPipeline *pipeline, - CoglPipelineState changes); +void +_cogl_pipeline_update_real_blend_enable (CoglPipeline *pipeline, + CoglBool unknown_color_alpha); typedef enum { @@ -835,13 +849,13 @@ _cogl_pipeline_compare_differences (CoglPipeline *pipeline0, CoglBool _cogl_pipeline_equal (CoglPipeline *pipeline0, CoglPipeline *pipeline1, - unsigned long differences, + unsigned int differences, unsigned long layer_differences, CoglPipelineEvalFlags flags); unsigned int _cogl_pipeline_hash (CoglPipeline *pipeline, - unsigned long differences, + unsigned int differences, unsigned long layer_differences, CoglPipelineEvalFlags flags); diff --git a/cogl/cogl-pipeline-state.c b/cogl/cogl-pipeline-state.c index 528fabd09..b3e6bde85 100644 --- a/cogl/cogl-pipeline-state.c +++ b/cogl/cogl-pipeline-state.c @@ -408,7 +408,7 @@ cogl_pipeline_set_color (CoglPipeline *pipeline, _cogl_pipeline_update_authority (pipeline, authority, state, _cogl_pipeline_color_equal); - _cogl_pipeline_update_blend_enable (pipeline, state); + pipeline->dirty_real_blend_enable = TRUE; } void @@ -482,7 +482,7 @@ _cogl_pipeline_set_blend_enabled (CoglPipeline *pipeline, _cogl_pipeline_update_authority (pipeline, authority, state, _cogl_pipeline_blend_enable_equal); - _cogl_pipeline_update_blend_enable (pipeline, state); + pipeline->dirty_real_blend_enable = TRUE; } void @@ -532,7 +532,7 @@ cogl_pipeline_set_ambient (CoglPipeline *pipeline, _cogl_pipeline_update_authority (pipeline, authority, state, _cogl_pipeline_lighting_state_equal); - _cogl_pipeline_update_blend_enable (pipeline, state); + pipeline->dirty_real_blend_enable = TRUE; } void @@ -583,7 +583,7 @@ cogl_pipeline_set_diffuse (CoglPipeline *pipeline, _cogl_pipeline_update_authority (pipeline, authority, state, _cogl_pipeline_lighting_state_equal); - _cogl_pipeline_update_blend_enable (pipeline, state); + pipeline->dirty_real_blend_enable = TRUE; } void @@ -640,7 +640,7 @@ cogl_pipeline_set_specular (CoglPipeline *pipeline, const CoglColor *specular) _cogl_pipeline_update_authority (pipeline, authority, state, _cogl_pipeline_lighting_state_equal); - _cogl_pipeline_update_blend_enable (pipeline, state); + pipeline->dirty_real_blend_enable = TRUE; } float @@ -740,7 +740,7 @@ cogl_pipeline_set_emission (CoglPipeline *pipeline, const CoglColor *emission) _cogl_pipeline_update_authority (pipeline, authority, state, _cogl_pipeline_lighting_state_equal); - _cogl_pipeline_update_blend_enable (pipeline, state); + pipeline->dirty_real_blend_enable = TRUE; } static void @@ -1008,7 +1008,7 @@ cogl_pipeline_set_blend (CoglPipeline *pipeline, _cogl_pipeline_prune_redundant_ancestry (pipeline); } - _cogl_pipeline_update_blend_enable (pipeline, state); + pipeline->dirty_real_blend_enable = TRUE; return TRUE; } @@ -1049,7 +1049,7 @@ cogl_pipeline_set_blend_constant (CoglPipeline *pipeline, _cogl_pipeline_update_authority (pipeline, authority, state, _cogl_pipeline_blend_state_equal); - _cogl_pipeline_update_blend_enable (pipeline, state); + pipeline->dirty_real_blend_enable = TRUE; } #endif } @@ -1126,7 +1126,7 @@ cogl_pipeline_set_user_program (CoglPipeline *pipeline, cogl_handle_unref (pipeline->big_state->user_program); pipeline->big_state->user_program = program; - _cogl_pipeline_update_blend_enable (pipeline, state); + pipeline->dirty_real_blend_enable = TRUE; } CoglBool diff --git a/cogl/cogl-pipeline.c b/cogl/cogl-pipeline.c index a91ad256f..6be22fba5 100644 --- a/cogl/cogl-pipeline.c +++ b/cogl/cogl-pipeline.c @@ -740,71 +740,29 @@ layer_has_alpha_cb (CoglPipelineLayer *layer, void *data) return !(*has_alpha); } +/* NB: If this pipeline returns FALSE that doesn't mean that the + * pipeline is definitely opaque, it just means that that the + * given changes dont imply transparency. + * + * If you want to find out of the pipeline is opaque then assuming + * this returns FALSE for a set of changes then you can follow + * up + */ static CoglBool -_cogl_pipeline_needs_blending_enabled (CoglPipeline *pipeline, - unsigned long changes, - const CoglColor *override_color) +_cogl_pipeline_change_implies_transparency (CoglPipeline *pipeline, + unsigned int changes, + const CoglColor *override_color, + CoglBool unknown_color_alpha) { - CoglPipeline *enable_authority; - CoglPipeline *blend_authority; - CoglPipelineBlendState *blend_state; - CoglPipelineBlendEnable enabled; - unsigned long other_state; - - _COGL_GET_CONTEXT (ctx, FALSE); - - if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_BLENDING))) - return FALSE; - - enable_authority = - _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_BLEND_ENABLE); - - enabled = enable_authority->blend_enable; - if (enabled != COGL_PIPELINE_BLEND_ENABLE_AUTOMATIC) - return enabled == COGL_PIPELINE_BLEND_ENABLE_ENABLED ? TRUE : FALSE; - - blend_authority = - _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_BLEND); - - blend_state = &blend_authority->big_state->blend_state; - - /* We are trying to identify awkward cases that are equivalent to - * blending being disable, where the output is simply GL_SRC_COLOR. - * - * Note: we assume that all OpenGL drivers will identify the simple - * case of ADD (ONE, ZERO) as equivalent to blending being disabled. - * - * We should update this when we add support for more blend - * functions... - */ - -#if defined (HAVE_COGL_GLES2) || defined (HAVE_COGL_GL) - if (ctx->driver != COGL_DRIVER_GLES1) - { - /* GLES 1 can't change the function or have separate alpha factors */ - if (blend_state->blend_equation_rgb != GL_FUNC_ADD || - blend_state->blend_equation_alpha != GL_FUNC_ADD) - return TRUE; - - if (blend_state->blend_src_factor_alpha != GL_ONE || - blend_state->blend_dst_factor_alpha != GL_ONE_MINUS_SRC_ALPHA) - return TRUE; - } -#endif - - if (blend_state->blend_src_factor_rgb != GL_ONE || - blend_state->blend_dst_factor_rgb != GL_ONE_MINUS_SRC_ALPHA) - return TRUE; - - /* Given the above constraints, it's now a case of finding any - * SRC_ALPHA that != 1 */ - /* In the case of a layer state change we need to check everything * else first since they contribute to the has_alpha status of the - * GL_PREVIOUS layer. */ + * "PREVIOUS" layer. */ if (changes & COGL_PIPELINE_STATE_LAYERS) changes = COGL_PIPELINE_STATE_AFFECTS_BLENDING; + if (unknown_color_alpha) + return TRUE; + if ((override_color && cogl_color_get_alpha_byte (override_color) != 0xff)) return TRUE; @@ -878,24 +836,104 @@ _cogl_pipeline_needs_blending_enabled (CoglPipeline *pipeline, return TRUE; } + return FALSE; +} + +static CoglBool +_cogl_pipeline_needs_blending_enabled (CoglPipeline *pipeline, + unsigned int changes, + const CoglColor *override_color, + CoglBool unknown_color_alpha) +{ + CoglPipeline *enable_authority; + CoglPipeline *blend_authority; + CoglPipelineBlendState *blend_state; + CoglPipelineBlendEnable enabled; + + if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_BLENDING))) + return FALSE; + + /* We unconditionally check the _BLEND_ENABLE state first because + * all the other changes are irrelevent if blend_enable != _AUTOMATIC + */ + enable_authority = + _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_BLEND_ENABLE); + + enabled = enable_authority->blend_enable; + if (enabled != COGL_PIPELINE_BLEND_ENABLE_AUTOMATIC) + return enabled == COGL_PIPELINE_BLEND_ENABLE_ENABLED ? TRUE : FALSE; + + blend_authority = + _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_BLEND); + + blend_state = &blend_authority->big_state->blend_state; + + /* We are trying to identify some cases that are equivalent to + * blending being disable, where the output is simply GL_SRC_COLOR. + * + * Note: we currently only consider a few cases that can be + * optimized but there could be opportunities to special case more + * blend functions later. + */ + + /* As the most common way that we currently use to effectively + * disable blending is to use an equation of + * "RGBA=ADD(SRC_COLOR, 0)" that's the first thing we check + * for... */ + if (blend_state->blend_equation_rgb == GL_FUNC_ADD && + blend_state->blend_equation_alpha == GL_FUNC_ADD && + blend_state->blend_src_factor_alpha == GL_ONE && + blend_state->blend_dst_factor_alpha == GL_ZERO) + { + return FALSE; + } + + /* NB: The default blending equation for Cogl is + * "RGBA=ADD(SRC_COLOR, DST_COLOR * (1-SRC_COLOR[A]))" + * + * Next we check if the default blending equation is being used. If + * so then we follow that by looking for cases where SRC_COLOR[A] == + * 1 since that simplifies "DST_COLOR * (1-SRC_COLOR[A])" to 0 which + * also effectively requires no blending. + */ + + if (blend_state->blend_equation_rgb != GL_FUNC_ADD || + blend_state->blend_equation_alpha != GL_FUNC_ADD) + return TRUE; + + if (blend_state->blend_src_factor_alpha != GL_ONE || + blend_state->blend_dst_factor_alpha != GL_ONE_MINUS_SRC_ALPHA) + return TRUE; + + if (blend_state->blend_src_factor_rgb != GL_ONE || + blend_state->blend_dst_factor_rgb != GL_ONE_MINUS_SRC_ALPHA) + return TRUE; + + /* Given the above constraints, it's now a case of finding any + * SRC_ALPHA that != 1 */ + + if (_cogl_pipeline_change_implies_transparency (pipeline, changes, + override_color, + unknown_color_alpha)) + return TRUE; + /* At this point, considering just the state that has changed it * looks like blending isn't needed. If blending was previously * enabled though it could be that some other state still requires - * that we have blending enabled. In this case we still need to - * go and check the other state... + * that we have blending enabled because it implies transparency. + * In this case we still need to go and check the other state... * - * FIXME: We should explicitly keep track of the mask of state - * groups that are currently causing blending to be enabled so that - * we never have to resort to checking *all* the state and can - * instead always limit the check to those in the mask. + * XXX: We could explicitly keep track of the mask of state groups + * that are currently causing blending to be enabled so that we + * never have to resort to checking *all* the state and can instead + * always limit the check to those in the mask. */ if (pipeline->real_blend_enable) { - other_state = COGL_PIPELINE_STATE_AFFECTS_BLENDING & ~changes; + unsigned int other_state = + COGL_PIPELINE_STATE_AFFECTS_BLENDING & ~changes; if (other_state && - _cogl_pipeline_needs_blending_enabled (pipeline, - other_state, - NULL)) + _cogl_pipeline_change_implies_transparency (pipeline, other_state, NULL, FALSE)) return TRUE; } @@ -1066,7 +1104,7 @@ _cogl_pipeline_copy_differences (CoglPipeline *dest, */ check_for_blending_change: if (differences & COGL_PIPELINE_STATE_AFFECTS_BLENDING) - _cogl_pipeline_update_blend_enable (dest, differences); + dest->dirty_real_blend_enable = TRUE; dest->differences |= differences; } @@ -1235,7 +1273,8 @@ _cogl_pipeline_pre_change_notify (CoglPipeline *pipeline, CoglBool will_need_blending = _cogl_pipeline_needs_blending_enabled (pipeline, change, - new_color); + new_color, + FALSE); CoglBool blend_enable = pipeline->real_blend_enable ? TRUE : FALSE; if (will_need_blending == blend_enable) @@ -1507,29 +1546,51 @@ _cogl_pipeline_try_reverting_layers_authority (CoglPipeline *authority, } } - void -_cogl_pipeline_update_blend_enable (CoglPipeline *pipeline, - CoglPipelineState change) +_cogl_pipeline_update_real_blend_enable (CoglPipeline *pipeline, + CoglBool unknown_color_alpha) { - CoglBool blend_enable = - _cogl_pipeline_needs_blending_enabled (pipeline, change, NULL); + CoglPipeline *parent; + unsigned int differences; - if (blend_enable != pipeline->real_blend_enable) + if (pipeline->dirty_real_blend_enable == FALSE && + pipeline->unknown_color_alpha == unknown_color_alpha) + return; + + if (pipeline->dirty_real_blend_enable) { - /* - Flush journal primitives referencing the current state. - * - Make sure the pipeline has no dependants so it may be - * modified. - * - If the pipeline isn't currently an authority for the state - * being changed, then initialize that state from the current - * authority. + differences = pipeline->differences; + + parent = _cogl_pipeline_get_parent (pipeline); + while (parent->dirty_real_blend_enable) + { + differences |= parent->differences; + parent = _cogl_pipeline_get_parent (parent); + } + + /* We initialize the pipeline's real_blend_enable with a known + * reference value from its nearest ancestor with clean state so + * we can then potentially reduce the work involved in checking + * if the pipeline really needs blending itself because we can + * just look at the things that differ between the ancestor and + * this pipeline. */ - _cogl_pipeline_pre_change_notify (pipeline, - COGL_PIPELINE_STATE_REAL_BLEND_ENABLE, - NULL, - FALSE); - pipeline->real_blend_enable = blend_enable; + pipeline->real_blend_enable = parent->real_blend_enable; } + else /* pipeline->unknown_color_alpha != unknown_color_alpha */ + differences = 0; + + /* Note we don't call _cogl_pipeline_pre_change_notify() for this + * state change because ->real_blend_enable is lazily derived from + * other state while flushing the pipeline and we'd need to avoid + * recursion problems in cases where _pre_change_notify() flushes + * the journal if the pipeline is referenced by a journal. + */ + pipeline->real_blend_enable = + _cogl_pipeline_needs_blending_enabled (pipeline, differences, + NULL, unknown_color_alpha); + pipeline->dirty_real_blend_enable = FALSE; + pipeline->unknown_color_alpha = unknown_color_alpha; } typedef struct @@ -2145,7 +2206,7 @@ _cogl_pipeline_resolve_authorities (CoglPipeline *pipeline, CoglBool _cogl_pipeline_equal (CoglPipeline *pipeline0, CoglPipeline *pipeline1, - unsigned long differences, + unsigned int differences, unsigned long layer_differences, CoglPipelineEvalFlags flags) { @@ -2171,6 +2232,9 @@ _cogl_pipeline_equal (CoglPipeline *pipeline0, ret = FALSE; + _cogl_pipeline_update_real_blend_enable (pipeline0, FALSE); + _cogl_pipeline_update_real_blend_enable (pipeline1, FALSE); + /* First check non-sparse properties */ if (differences & COGL_PIPELINE_STATE_REAL_BLEND_ENABLE && @@ -2438,7 +2502,7 @@ cogl_pipeline_remove_layer (CoglPipeline *pipeline, int layer_index) _cogl_pipeline_remove_layer_difference (pipeline, layer_info.layer, TRUE); _cogl_pipeline_try_reverting_layers_authority (pipeline, NULL); - _cogl_pipeline_update_blend_enable (pipeline, COGL_PIPELINE_STATE_LAYERS); + pipeline->dirty_real_blend_enable = TRUE; } static CoglBool @@ -2718,12 +2782,12 @@ _cogl_pipeline_init_state_hash_functions (void) unsigned int _cogl_pipeline_hash (CoglPipeline *pipeline, - unsigned long differences, + unsigned int differences, unsigned long layer_differences, CoglPipelineEvalFlags flags) { CoglPipeline *authorities[COGL_PIPELINE_STATE_SPARSE_COUNT]; - unsigned long mask; + unsigned int mask; int i; CoglPipelineHashState state; unsigned int final_hash = 0; @@ -2732,6 +2796,8 @@ _cogl_pipeline_hash (CoglPipeline *pipeline, state.layer_differences = layer_differences; state.flags = flags; + _cogl_pipeline_update_real_blend_enable (pipeline, FALSE); + /* hash non-sparse state */ if (differences & COGL_PIPELINE_STATE_REAL_BLEND_ENABLE) @@ -2748,7 +2814,7 @@ _cogl_pipeline_hash (CoglPipeline *pipeline, for (i = 0; i < COGL_PIPELINE_STATE_SPARSE_COUNT; i++) { - unsigned long current_state = (1L<context; int i; - CoglBool skip_gl_color = FALSE; + CoglBool with_color_attrib = FALSE; + CoglBool unknown_color_alpha = FALSE; CoglPipeline *copy = NULL; - /* Iterate the attributes to work out whether blending needs to be - enabled and how many texture coords there are. We need to do this - before flushing the pipeline. */ + /* Iterate the attributes to see if we have a color attribute which + * may affect our decision to enable blending or not. + * + * We need to do this before flushing the pipeline. */ for (i = 0; i < n_attributes; i++) switch (attributes[i]->name_state->name_id) { case COGL_ATTRIBUTE_NAME_ID_COLOR_ARRAY: if ((flags & COGL_DRAW_COLOR_ATTRIBUTE_IS_OPAQUE) == 0 && - !_cogl_pipeline_get_real_blend_enabled (pipeline)) - { - CoglPipelineBlendEnable blend_enable = - COGL_PIPELINE_BLEND_ENABLE_ENABLED; - copy = cogl_pipeline_copy (pipeline); - _cogl_pipeline_set_blend_enabled (copy, blend_enable); - pipeline = copy; - } - skip_gl_color = TRUE; + _cogl_attribute_get_n_components (attributes[i]) == 4) + unknown_color_alpha = TRUE; + with_color_attrib = TRUE; break; default: @@ -445,9 +441,11 @@ _cogl_gl_flush_attributes_state (CoglFramebuffer *framebuffer, */ } - _cogl_pipeline_flush_gl_state (pipeline, + _cogl_pipeline_flush_gl_state (ctx, + pipeline, framebuffer, - skip_gl_color); + with_color_attrib, + unknown_color_alpha); _cogl_bitmask_clear_all (&ctx->enable_builtin_attributes_tmp); _cogl_bitmask_clear_all (&ctx->enable_texcoord_attributes_tmp); diff --git a/cogl/driver/gl/cogl-clip-stack-gl.c b/cogl/driver/gl/cogl-clip-stack-gl.c index e87226761..e44025653 100644 --- a/cogl/driver/gl/cogl-clip-stack-gl.c +++ b/cogl/driver/gl/cogl-clip-stack-gl.c @@ -287,7 +287,8 @@ add_stencil_clip_silhouette (CoglFramebuffer *framebuffer, projection_stack->last_entry); _cogl_context_set_current_modelview_entry (ctx, modelview_entry); - _cogl_pipeline_flush_gl_state (ctx->stencil_pipeline, framebuffer, FALSE); + _cogl_pipeline_flush_gl_state (ctx, ctx->stencil_pipeline, + framebuffer, FALSE, FALSE); GE( ctx, glEnable (GL_STENCIL_TEST) ); diff --git a/cogl/driver/gl/cogl-pipeline-opengl-private.h b/cogl/driver/gl/cogl-pipeline-opengl-private.h index 294b611d2..aa3a0331f 100644 --- a/cogl/driver/gl/cogl-pipeline-opengl-private.h +++ b/cogl/driver/gl/cogl-pipeline-opengl-private.h @@ -142,9 +142,11 @@ void _cogl_delete_gl_texture (GLuint gl_texture); void -_cogl_pipeline_flush_gl_state (CoglPipeline *pipeline, +_cogl_pipeline_flush_gl_state (CoglContext *context, + CoglPipeline *pipeline, CoglFramebuffer *framebuffer, - CoglBool skip_gl_state); + CoglBool skip_gl_state, + CoglBool unknown_color_alpha); #endif /* __COGL_PIPELINE_OPENGL_PRIVATE_H */ diff --git a/cogl/driver/gl/cogl-pipeline-opengl.c b/cogl/driver/gl/cogl-pipeline-opengl.c index 81d1b283e..86d6124c6 100644 --- a/cogl/driver/gl/cogl-pipeline-opengl.c +++ b/cogl/driver/gl/cogl-pipeline-opengl.c @@ -448,18 +448,18 @@ static void _cogl_pipeline_flush_color_blend_alpha_depth_state ( CoglPipeline *pipeline, unsigned long pipelines_difference, - CoglBool skip_gl_color) + CoglBool with_color_attrib) { _COGL_GET_CONTEXT (ctx, NO_RETVAL); /* On GLES2 we'll flush the color later */ if ((ctx->private_feature_flags & COGL_PRIVATE_FEATURE_FIXED_FUNCTION) && - !skip_gl_color) + !with_color_attrib) { if ((pipelines_difference & COGL_PIPELINE_STATE_COLOR) || /* Assume if we were previously told to skip the color, then * the current color needs updating... */ - ctx->current_pipeline_skip_gl_color) + ctx->current_pipeline_with_color_attrib) { CoglPipeline *authority = _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_COLOR); @@ -889,7 +889,7 @@ static void _cogl_pipeline_flush_common_gl_state (CoglPipeline *pipeline, unsigned long pipelines_difference, unsigned long *layer_differences, - CoglBool skip_gl_color) + CoglBool with_color_attrib) { CoglPipelineFlushLayerState state; @@ -897,7 +897,7 @@ _cogl_pipeline_flush_common_gl_state (CoglPipeline *pipeline, _cogl_pipeline_flush_color_blend_alpha_depth_state (pipeline, pipelines_difference, - skip_gl_color); + with_color_attrib); state.i = 0; state.layer_differences = layer_differences; @@ -1149,10 +1149,13 @@ fragend_add_layer_cb (CoglPipelineLayer *layer, * isn't ideal, and can't be used with CoglVertexBuffers. */ void -_cogl_pipeline_flush_gl_state (CoglPipeline *pipeline, +_cogl_pipeline_flush_gl_state (CoglContext *ctx, + CoglPipeline *pipeline, CoglFramebuffer *framebuffer, - CoglBool skip_gl_color) + CoglBool with_color_attrib, + CoglBool unknown_color_alpha) { + CoglPipeline *current_pipeline = ctx->current_pipeline; unsigned long pipelines_difference; int n_layers; unsigned long *layer_differences; @@ -1166,29 +1169,61 @@ _cogl_pipeline_flush_gl_state (CoglPipeline *pipeline, "The time spent flushing material state", 0 /* no application private data */); - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - COGL_TIMER_START (_cogl_uprof_context, pipeline_flush_timer); - if (ctx->current_pipeline == pipeline) - { - /* Bail out asap if we've been asked to re-flush the already current - * pipeline and we can see the pipeline hasn't changed */ - if (ctx->current_pipeline_age == pipeline->age && - ctx->current_pipeline_skip_gl_color == skip_gl_color) - goto done; - - pipelines_difference = ctx->current_pipeline_changes_since_flush; - } - else if (ctx->current_pipeline) - { - pipelines_difference = ctx->current_pipeline_changes_since_flush; - pipelines_difference |= - _cogl_pipeline_compare_differences (ctx->current_pipeline, - pipeline); - } + /* Bail out asap if we've been asked to re-flush the already current + * pipeline and we can see the pipeline hasn't changed */ + if (current_pipeline == pipeline && + ctx->current_pipeline_age == pipeline->age && + ctx->current_pipeline_with_color_attrib == with_color_attrib && + ctx->current_pipeline_unknown_color_alpha == unknown_color_alpha) + goto done; else - pipelines_difference = COGL_PIPELINE_STATE_ALL_SPARSE; + { + /* Update derived state (currently just the 'real_blend_enable' + * state) and determine a mask of state that differs between the + * current pipeline and the one we are flushing. + * + * Note updating the derived state is done before doing any + * pipeline comparisons so that we can correctly compare the + * 'real_blend_enable' state itself. + */ + + if (current_pipeline == pipeline) + { + pipelines_difference = ctx->current_pipeline_changes_since_flush; + + if (pipelines_difference & COGL_PIPELINE_STATE_AFFECTS_BLENDING || + pipeline->unknown_color_alpha != unknown_color_alpha) + { + CoglBool save_real_blend_enable = pipeline->real_blend_enable; + + _cogl_pipeline_update_real_blend_enable (pipeline, + unknown_color_alpha); + + if (save_real_blend_enable != pipeline->real_blend_enable) + pipelines_difference |= COGL_PIPELINE_STATE_REAL_BLEND_ENABLE; + } + } + else if (current_pipeline) + { + pipelines_difference = ctx->current_pipeline_changes_since_flush; + + _cogl_pipeline_update_real_blend_enable (pipeline, + unknown_color_alpha); + + pipelines_difference |= + _cogl_pipeline_compare_differences (ctx->current_pipeline, + pipeline); + } + else + { + _cogl_pipeline_update_real_blend_enable (pipeline, + unknown_color_alpha); + + pipelines_difference = COGL_PIPELINE_STATE_ALL; + } + } /* Get a layer_differences mask for each layer to be flushed */ n_layers = cogl_pipeline_get_n_layers (pipeline); @@ -1225,7 +1260,7 @@ _cogl_pipeline_flush_gl_state (CoglPipeline *pipeline, _cogl_pipeline_flush_common_gl_state (pipeline, pipelines_difference, layer_differences, - skip_gl_color); + with_color_attrib); /* Now flush the fragment, vertex and program state according to the * current progend backend. @@ -1327,7 +1362,8 @@ _cogl_pipeline_flush_gl_state (CoglPipeline *pipeline, cogl_object_unref (ctx->current_pipeline); ctx->current_pipeline = pipeline; ctx->current_pipeline_changes_since_flush = 0; - ctx->current_pipeline_skip_gl_color = skip_gl_color; + ctx->current_pipeline_with_color_attrib = with_color_attrib; + ctx->current_pipeline_unknown_color_alpha = unknown_color_alpha; ctx->current_pipeline_age = pipeline->age; done: @@ -1338,7 +1374,7 @@ done: * using the glsl progend because the generic attribute values are * not stored as part of the program object so they could be * overridden by any attribute changes in another program */ - if (pipeline->progend == COGL_PIPELINE_PROGEND_GLSL && !skip_gl_color) + if (pipeline->progend == COGL_PIPELINE_PROGEND_GLSL && !with_color_attrib) { int attribute; CoglPipeline *authority =