material: Adds experimental cogl_material_foreach_layer API
This adds a way to iterate the layer indices of the given material since cogl_material_get_layers has been deprecated. The user provides a callback to be called once for each layer. Because modification of layers in the callback may potentially invalidate any number of the internal CoglMaterialLayer structures and invalidate the material's layer cache this should be more robust than cogl_material_get_layers() which used to return a const GList * pointing directly to internal state.
This commit is contained in:
parent
7eff623b96
commit
16c64054b9
@ -226,17 +226,17 @@ find_arbfp_authority (CoglMaterial *material, CoglHandle user_program)
|
||||
g_alloca (sizeof (CoglMaterialLayer *) * n_layers);
|
||||
state.i = 0;
|
||||
state.layers = authority0_layers;
|
||||
_cogl_material_foreach_layer (authority0,
|
||||
add_layer_to_array_cb,
|
||||
&state);
|
||||
_cogl_material_foreach_layer_internal (authority0,
|
||||
add_layer_to_array_cb,
|
||||
&state);
|
||||
|
||||
authority1_layers =
|
||||
g_alloca (sizeof (CoglMaterialLayer *) * n_layers);
|
||||
state.i = 0;
|
||||
state.layers = authority1_layers;
|
||||
_cogl_material_foreach_layer (authority1,
|
||||
add_layer_to_array_cb,
|
||||
&state);
|
||||
_cogl_material_foreach_layer_internal (authority1,
|
||||
add_layer_to_array_cb,
|
||||
&state);
|
||||
|
||||
if (layers_arbfp_would_differ (authority0_layers, authority1_layers,
|
||||
n_layers))
|
||||
|
@ -833,9 +833,9 @@ _cogl_material_flush_common_gl_state (CoglMaterial *material,
|
||||
|
||||
state.i = 0;
|
||||
state.layer_differences = layer_differences;
|
||||
_cogl_material_foreach_layer (material,
|
||||
flush_layers_common_gl_state_cb,
|
||||
&state);
|
||||
_cogl_material_foreach_layer_internal (material,
|
||||
flush_layers_common_gl_state_cb,
|
||||
&state);
|
||||
|
||||
/* Disable additional texture units that may have previously been in use.. */
|
||||
for (; state.i < ctx->texture_units->len; state.i++)
|
||||
@ -1115,9 +1115,9 @@ _cogl_material_flush_gl_state (CoglMaterial *material,
|
||||
memset (layer_differences, 0, sizeof (layer_differences));
|
||||
state.i = 0;
|
||||
state.layer_differences = layer_differences;
|
||||
_cogl_material_foreach_layer (material,
|
||||
compare_layer_differences_cb,
|
||||
&state);
|
||||
_cogl_material_foreach_layer_internal (material,
|
||||
compare_layer_differences_cb,
|
||||
&state);
|
||||
}
|
||||
|
||||
/* First flush everything that's the same regardless of which
|
||||
@ -1178,9 +1178,9 @@ _cogl_material_flush_gl_state (CoglMaterial *material,
|
||||
state.layer_differences = layer_differences;
|
||||
state.error_adding_layer = FALSE;
|
||||
state.added_layer = FALSE;
|
||||
_cogl_material_foreach_layer (material,
|
||||
backend_add_layer_cb,
|
||||
&state);
|
||||
_cogl_material_foreach_layer_internal (material,
|
||||
backend_add_layer_cb,
|
||||
&state);
|
||||
|
||||
if (G_UNLIKELY (state.error_adding_layer))
|
||||
continue;
|
||||
|
@ -903,13 +903,13 @@ _cogl_material_layer_get_authority (CoglMaterialLayer *layer,
|
||||
CoglHandle
|
||||
_cogl_material_layer_get_texture (CoglMaterialLayer *layer);
|
||||
|
||||
typedef gboolean (*CoglMaterialLayerCallback) (CoglMaterialLayer *layer,
|
||||
void *user_data);
|
||||
typedef gboolean (*CoglMaterialInternalLayerCallback) (CoglMaterialLayer *layer,
|
||||
void *user_data);
|
||||
|
||||
void
|
||||
_cogl_material_foreach_layer (CoglMaterial *material,
|
||||
CoglMaterialLayerCallback callback,
|
||||
void *user_data);
|
||||
_cogl_material_foreach_layer_internal (CoglMaterial *material,
|
||||
CoglMaterialInternalLayerCallback callback,
|
||||
void *user_data);
|
||||
|
||||
int
|
||||
_cogl_material_layer_get_unit_index (CoglMaterialLayer *layer);
|
||||
|
@ -676,14 +676,12 @@ _cogl_material_update_layers_cache (CoglMaterial *material)
|
||||
g_warn_if_reached ();
|
||||
}
|
||||
|
||||
/* TODO: add public cogl_material_foreach_layer but instead of passing
|
||||
* a CoglMaterialLayer pointer to the callback we should pass a
|
||||
* layer_index instead. */
|
||||
|
||||
/* XXX: Be carefull when using this API that the callback given doesn't result
|
||||
* in the layer cache being invalidated during the iteration! */
|
||||
void
|
||||
_cogl_material_foreach_layer (CoglMaterial *material,
|
||||
CoglMaterialLayerCallback callback,
|
||||
void *user_data)
|
||||
_cogl_material_foreach_layer_internal (CoglMaterial *material,
|
||||
CoglMaterialInternalLayerCallback callback,
|
||||
void *user_data)
|
||||
{
|
||||
CoglMaterial *authority =
|
||||
_cogl_material_get_authority (material, COGL_MATERIAL_STATE_LAYERS);
|
||||
@ -698,7 +696,53 @@ _cogl_material_foreach_layer (CoglMaterial *material,
|
||||
_cogl_material_update_layers_cache (authority);
|
||||
|
||||
for (i = 0, cont = TRUE; i < n_layers && cont == TRUE; i++)
|
||||
cont = callback (authority->layers_cache[i], user_data);
|
||||
{
|
||||
g_return_if_fail (authority->layers_cache_dirty == FALSE);
|
||||
cont = callback (authority->layers_cache[i], user_data);
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int i;
|
||||
int *indices;
|
||||
} AppendLayerIndexState;
|
||||
|
||||
static gboolean
|
||||
append_layer_index_cb (CoglMaterialLayer *layer,
|
||||
void *user_data)
|
||||
{
|
||||
AppendLayerIndexState *state = user_data;
|
||||
state->indices[state->i++] = layer->index;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
cogl_material_foreach_layer (CoglMaterial *material,
|
||||
CoglMaterialLayerCallback callback,
|
||||
void *user_data)
|
||||
{
|
||||
CoglMaterial *authority =
|
||||
_cogl_material_get_authority (material, COGL_MATERIAL_STATE_LAYERS);
|
||||
AppendLayerIndexState state;
|
||||
gboolean cont;
|
||||
int i;
|
||||
|
||||
/* XXX: We don't know what the user is going to want to do to the layers
|
||||
* but any modification of layers can result in the layer graph changing
|
||||
* which could confuse _cogl_material_foreach_layer_internal(). We first
|
||||
* get a list of layer indices which will remain valid so long as the
|
||||
* user doesn't remove layers. */
|
||||
|
||||
state.i = 0;
|
||||
state.indices = g_alloca (authority->n_layers * sizeof (int));
|
||||
|
||||
_cogl_material_foreach_layer_internal (material,
|
||||
append_layer_index_cb,
|
||||
&state);
|
||||
|
||||
for (i = 0, cont = TRUE; i < authority->n_layers && cont; i++)
|
||||
cont = callback (material, state.indices[i], user_data);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@ -872,9 +916,9 @@ _cogl_material_needs_blending_enabled (CoglMaterial *material,
|
||||
* To start with that's defined by the material color which
|
||||
* must be fully opaque if we got this far. */
|
||||
gboolean has_alpha = FALSE;
|
||||
_cogl_material_foreach_layer (material,
|
||||
layer_has_alpha_cb,
|
||||
&has_alpha);
|
||||
_cogl_material_foreach_layer_internal (material,
|
||||
layer_has_alpha_cb,
|
||||
&has_alpha);
|
||||
if (has_alpha)
|
||||
return TRUE;
|
||||
}
|
||||
@ -1393,9 +1437,9 @@ _cogl_material_prune_to_n_layers (CoglMaterial *material, int n)
|
||||
state.keep_n = n;
|
||||
state.current_pos = 0;
|
||||
state.needs_pruning = FALSE;
|
||||
_cogl_material_foreach_layer (material,
|
||||
update_prune_layers_info_cb,
|
||||
&state);
|
||||
_cogl_material_foreach_layer_internal (material,
|
||||
update_prune_layers_info_cb,
|
||||
&state);
|
||||
|
||||
material->n_layers = n;
|
||||
|
||||
@ -1814,7 +1858,7 @@ _cogl_material_get_layer_info (CoglMaterial *material,
|
||||
int n_layers = material->n_layers;
|
||||
int i;
|
||||
|
||||
/* FIXME: _cogl_material_foreach_layer now calls
|
||||
/* FIXME: _cogl_material_foreach_layer_internal now calls
|
||||
* _cogl_material_update_layers_cache anyway so this codepath is
|
||||
* pointless! */
|
||||
if (layer_info->ignore_shift_layers_if_found &&
|
||||
@ -1827,9 +1871,9 @@ _cogl_material_get_layer_info (CoglMaterial *material,
|
||||
* necessarily have to iterate all the layers of the material we
|
||||
* use a foreach_layer callback instead of updating the cache
|
||||
* and iterating that as below. */
|
||||
_cogl_material_foreach_layer (material,
|
||||
update_layer_info_cb,
|
||||
layer_info);
|
||||
_cogl_material_foreach_layer_internal (material,
|
||||
update_layer_info_cb,
|
||||
layer_info);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -2743,9 +2787,9 @@ _cogl_material_apply_overrides (CoglMaterial *material,
|
||||
state.material = material;
|
||||
state.fallback_layers = options->fallback_layers;
|
||||
|
||||
_cogl_material_foreach_layer (material,
|
||||
fallback_layer_cb,
|
||||
&state);
|
||||
_cogl_material_foreach_layer_internal (material,
|
||||
fallback_layer_cb,
|
||||
&state);
|
||||
}
|
||||
|
||||
if (options->flags & COGL_MATERIAL_FLUSH_LAYER0_OVERRIDE)
|
||||
@ -2756,13 +2800,13 @@ _cogl_material_apply_overrides (CoglMaterial *material,
|
||||
|
||||
/* NB: we are overriding the first layer, but we don't know
|
||||
* the user's given layer_index, which is why we use
|
||||
* _cogl_material_foreach_layer() here even though we know
|
||||
* _cogl_material_foreach_layer_internal() here even though we know
|
||||
* there's only one layer. */
|
||||
state.material = material;
|
||||
state.gl_texture = options->layer0_override_texture;
|
||||
_cogl_material_foreach_layer (material,
|
||||
override_layer_texture_cb,
|
||||
&state);
|
||||
_cogl_material_foreach_layer_internal (material,
|
||||
override_layer_texture_cb,
|
||||
&state);
|
||||
}
|
||||
|
||||
if (options->flags & COGL_MATERIAL_FLUSH_WRAP_MODE_OVERRIDES)
|
||||
@ -2772,9 +2816,9 @@ _cogl_material_apply_overrides (CoglMaterial *material,
|
||||
state.material = material;
|
||||
state.wrap_mode_overrides = &options->wrap_mode_overrides;
|
||||
state.i = 0;
|
||||
_cogl_material_foreach_layer (material,
|
||||
apply_wrap_mode_overrides_cb,
|
||||
&state);
|
||||
_cogl_material_foreach_layer_internal (material,
|
||||
apply_wrap_mode_overrides_cb,
|
||||
&state);
|
||||
}
|
||||
}
|
||||
|
||||
@ -5074,9 +5118,9 @@ cogl_material_get_layers (CoglMaterial *material)
|
||||
|
||||
material->deprecated_get_layers_list = NULL;
|
||||
|
||||
_cogl_material_foreach_layer (material,
|
||||
prepend_layer_to_list_cb,
|
||||
&material->deprecated_get_layers_list);
|
||||
_cogl_material_foreach_layer_internal (material,
|
||||
prepend_layer_to_list_cb,
|
||||
&material->deprecated_get_layers_list);
|
||||
material->deprecated_get_layers_list =
|
||||
g_list_reverse (material->deprecated_get_layers_list);
|
||||
|
||||
@ -5550,7 +5594,7 @@ dump_material_cb (CoglMaterialNode *node, void *user_data)
|
||||
}
|
||||
|
||||
if (layers)
|
||||
_cogl_material_foreach_layer (material, dump_layer_ref_cb, state);
|
||||
_cogl_material_foreach_layer_internal (material, dump_layer_ref_cb, state);
|
||||
|
||||
state_out.parent_id = material_id;
|
||||
|
||||
|
@ -1348,6 +1348,39 @@ cogl_material_get_depth_range (CoglMaterial *material,
|
||||
float *near_val,
|
||||
float *far_val);
|
||||
|
||||
/**
|
||||
* CoglMaterialLayerCallback:
|
||||
* @material: The #CoglMaterial whos layers are being iterated
|
||||
* @layer_index: The current layer index
|
||||
* @user_data: The private data passed to cogl_material_foreach_layer()
|
||||
*
|
||||
* The callback prototype used with cogl_material_foreach_layer() for
|
||||
* iterating all the layers of a @material.
|
||||
*
|
||||
* Since: 1.4
|
||||
* Stability: Unstable
|
||||
*/
|
||||
typedef gboolean (*CoglMaterialLayerCallback) (CoglMaterial *material,
|
||||
int layer_index,
|
||||
void *user_data);
|
||||
|
||||
/**
|
||||
* cogl_material_foreach_layer:
|
||||
* @material: A #CoglMaterial object
|
||||
* @callback: A #CoglMaterialLayerCallback to be called for each layer
|
||||
* index
|
||||
* @user_data: Private data that will be passed to the callback
|
||||
*
|
||||
* Iterates all the layer indices of the given @material.
|
||||
*
|
||||
* Since: 1.4
|
||||
* Stability: Unstable
|
||||
*/
|
||||
void
|
||||
cogl_material_foreach_layer (CoglMaterial *material,
|
||||
CoglMaterialLayerCallback callback,
|
||||
void *user_data);
|
||||
|
||||
#endif /* COGL_ENABLE_EXPERIMENTAL_API */
|
||||
|
||||
G_END_DECLS
|
||||
|
Loading…
Reference in New Issue
Block a user