pipeline: improve real_blend_enable checks
Since _cogl_pipeline_update_blend_enable() can sometimes show up quite high in profiles; instead of calling _cogl_pipeline_update_blend_enable() whenever we change pipeline state that may affect blending we now just set a dirty flag and when we flush a pipeline we check this dirty flag and lazily calculate whether blender really needs to be enabled if it's set. Since it turns out we were too optimistic in assuming most GL drivers would recognize blending with ADD(src,0) is equivalent to disabling GL_BLEND we now check this case ourselves so we can always explicitly disable GL_BLEND if we know we don't need blending. This introduces the idea of an 'unknown_color_alpha' boolean to the pipeline flush code which is set whenever we can't guarantee that the color attribute is opaque. For example this is set whenever a user specifies a color attribute with 4 components when drawing a primitive. This boolean needs to be cached along with every pipeline because pipeline::real_blend_enabled depends on this and so we need to also call _cogl_pipeline_update_blend_enable() if the status of this changes. Incidentally with this patch we now no longer ever use _cogl_pipeline_set_blend_enable() internally. For now the internal api hasn't been removed though since we might want to consider re-purposing it as a public api since it will now not conflict with our own internal state tracking and could provide a more convenient way to disable blending than setting a blend string. Reviewed-by: Neil Roberts <neil@linux.intel.com> (cherry picked from commit ab2ae18f3207514c91fa6fd9f2d3f2ed93a86497)
This commit is contained in:
parent
2ed926120d
commit
8f9151303d
@ -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 */
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
@ -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<<i);
|
||||
unsigned int current_state = (1<<i);
|
||||
|
||||
/* XXX: we are hashing the un-mixed hash values of all the
|
||||
* individual state groups; we should provide a means to test
|
||||
|
@ -390,8 +390,10 @@ cogl_begin_gl (void)
|
||||
* values.
|
||||
*/
|
||||
pipeline = cogl_get_source ();
|
||||
_cogl_pipeline_flush_gl_state (pipeline,
|
||||
_cogl_pipeline_flush_gl_state (ctx,
|
||||
pipeline,
|
||||
cogl_get_draw_framebuffer (),
|
||||
FALSE,
|
||||
FALSE);
|
||||
|
||||
/* Disable any cached vertex arrays */
|
||||
|
@ -375,26 +375,22 @@ _cogl_gl_flush_attributes_state (CoglFramebuffer *framebuffer,
|
||||
{
|
||||
CoglContext *ctx = framebuffer->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);
|
||||
|
@ -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) );
|
||||
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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 =
|
||||
|
Loading…
Reference in New Issue
Block a user