primitives: validate with _cogl_pipeline_foreach_layer
Switch _cogl_rectangles_with_multitexture_coords to using _cogl_pipeline_foreach_layer to iterate the layers of a pipeline when validating instead of iterating the pipelines internal list, which is risky since any modifications to pipelines (even to an override pipeline derived from the original), could potentially corrupt the list as it is being iterated.
This commit is contained in:
parent
1a3f946cc6
commit
56f36cf9c2
@ -599,7 +599,8 @@ gboolean
|
||||
_cogl_pipeline_get_real_blend_enabled (CoglPipeline *pipeline);
|
||||
|
||||
gboolean
|
||||
_cogl_pipeline_layer_has_user_matrix (CoglPipelineLayer *layer);
|
||||
_cogl_pipeline_layer_has_user_matrix (CoglPipeline *pipeline,
|
||||
int layer_index);
|
||||
|
||||
/*
|
||||
* Calls the pre_paint method on the layer texture if there is
|
||||
|
@ -5046,11 +5046,13 @@ _cogl_pipeline_layer_get_texture (CoglPipelineLayer *layer)
|
||||
}
|
||||
|
||||
gboolean
|
||||
_cogl_pipeline_layer_has_user_matrix (CoglPipelineLayer *layer)
|
||||
_cogl_pipeline_layer_has_user_matrix (CoglPipeline *pipeline,
|
||||
int layer_index)
|
||||
{
|
||||
CoglPipelineLayer *layer;
|
||||
CoglPipelineLayer *authority;
|
||||
|
||||
g_return_val_if_fail (_cogl_is_pipeline_layer (layer), FALSE);
|
||||
layer = _cogl_pipeline_get_layer (pipeline, layer_index);
|
||||
|
||||
authority =
|
||||
_cogl_pipeline_layer_get_authority (layer,
|
||||
|
@ -513,7 +513,6 @@ validate_tex_coords_cb (CoglPipeline *pipeline,
|
||||
static gboolean
|
||||
_cogl_multitexture_quad_single_primitive (const float *position,
|
||||
CoglPipeline *pipeline,
|
||||
guint32 fallback_layers,
|
||||
const float *user_tex_coords,
|
||||
int user_tex_coords_len)
|
||||
{
|
||||
@ -555,41 +554,23 @@ _cogl_multitexture_quad_single_primitive (const float *position,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
struct _CoglMutiTexturedRect
|
||||
typedef struct _ValidateLayerState
|
||||
{
|
||||
const float *position; /* x0,y0,x1,y1 */
|
||||
const float *tex_coords; /* (tx0,ty0,tx1,ty1)(tx0,ty0,tx1,ty1)(... */
|
||||
int tex_coords_len; /* number of floats in tex_coords? */
|
||||
};
|
||||
|
||||
static void
|
||||
_cogl_rectangles_with_multitexture_coords (
|
||||
struct _CoglMutiTexturedRect *rects,
|
||||
int n_rects)
|
||||
{
|
||||
CoglPipeline *pipeline;
|
||||
const GList *layers;
|
||||
int n_layers;
|
||||
const GList *tmp;
|
||||
guint32 fallback_layers = 0;
|
||||
gboolean all_use_sliced_quad_fallback = FALSE;
|
||||
int i;
|
||||
int first_layer;
|
||||
CoglPipeline *override_source;
|
||||
gboolean all_use_sliced_quad_fallback;
|
||||
} ValidateLayerState;
|
||||
|
||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
|
||||
pipeline = cogl_get_source ();
|
||||
|
||||
layers = _cogl_pipeline_get_layers (pipeline);
|
||||
n_layers = cogl_pipeline_get_n_layers (pipeline);
|
||||
|
||||
/*
|
||||
* Validate all the layers of the current source pipeline...
|
||||
*/
|
||||
|
||||
for (tmp = layers, i = 0; tmp != NULL; tmp = tmp->next, i++)
|
||||
static gboolean
|
||||
_cogl_rectangles_validate_layer_cb (CoglPipeline *pipeline,
|
||||
int layer_index,
|
||||
void *user_data)
|
||||
{
|
||||
CoglHandle layer = tmp->data;
|
||||
CoglHandle tex_handle;
|
||||
ValidateLayerState *state = user_data;
|
||||
CoglHandle texture;
|
||||
|
||||
state->i++;
|
||||
|
||||
/* We need to ensure the mipmaps are ready before deciding
|
||||
* anything else about the texture because the texture storage
|
||||
@ -631,14 +612,17 @@ _cogl_rectangles_with_multitexture_coords (
|
||||
* sure the referenced texture is migrated out of the atlas and
|
||||
* mipmaps are generated.)
|
||||
*/
|
||||
_cogl_pipeline_layer_pre_paint (layer);
|
||||
_cogl_pipeline_pre_paint_for_layer (pipeline, layer_index);
|
||||
|
||||
tex_handle = _cogl_pipeline_layer_get_texture (layer);
|
||||
texture = _cogl_pipeline_get_layer_texture (pipeline, layer_index);
|
||||
|
||||
/* COGL_INVALID_HANDLE textures are handled by
|
||||
* _cogl_pipeline_flush_gl_state */
|
||||
if (tex_handle == COGL_INVALID_HANDLE)
|
||||
continue;
|
||||
if (texture == COGL_INVALID_HANDLE)
|
||||
return TRUE;
|
||||
|
||||
if (state->i == 0)
|
||||
state->first_layer = layer_index;
|
||||
|
||||
/* XXX:
|
||||
* For now, if the first layer is sliced then all other layers are
|
||||
@ -649,15 +633,17 @@ _cogl_rectangles_with_multitexture_coords (
|
||||
* TODO: Add support for multi-texturing rectangles with sliced
|
||||
* textures if no texture matrices are in use.
|
||||
*/
|
||||
if (cogl_texture_is_sliced (tex_handle))
|
||||
if (cogl_texture_is_sliced (texture))
|
||||
{
|
||||
if (i == 0)
|
||||
{
|
||||
fallback_layers = ~1; /* fallback all except the first layer */
|
||||
all_use_sliced_quad_fallback = TRUE;
|
||||
if (tmp->next)
|
||||
if (state->i == 0)
|
||||
{
|
||||
static gboolean warning_seen = FALSE;
|
||||
|
||||
if (!state->override_source)
|
||||
state->override_source = cogl_pipeline_copy (pipeline);
|
||||
_cogl_pipeline_prune_to_n_layers (state->override_source, 1);
|
||||
state->all_use_sliced_quad_fallback = TRUE;
|
||||
|
||||
if (!warning_seen)
|
||||
g_warning ("Skipping layers 1..n of your pipeline since "
|
||||
"the first layer is sliced. We don't currently "
|
||||
@ -665,65 +651,106 @@ _cogl_rectangles_with_multitexture_coords (
|
||||
"textures but assume layer 0 is the most "
|
||||
"important to keep");
|
||||
warning_seen = TRUE;
|
||||
}
|
||||
break;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
static gboolean warning_seen = FALSE;
|
||||
|
||||
_COGL_GET_CONTEXT (ctx, FALSE);
|
||||
|
||||
if (!warning_seen)
|
||||
g_warning ("Skipping layer %d of your pipeline consisting of "
|
||||
"a sliced texture (unsuported for multi texturing)",
|
||||
i);
|
||||
state->i);
|
||||
warning_seen = TRUE;
|
||||
|
||||
/* NB: marking for fallback will replace the layer with
|
||||
* a default transparent texture */
|
||||
fallback_layers |= (1 << i);
|
||||
continue;
|
||||
/* Note: currently only 2D textures can be sliced. */
|
||||
cogl_pipeline_set_layer_texture (pipeline, layer_index,
|
||||
ctx->default_gl_texture_2d_tex);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef COGL_ENABLE_DEBUG
|
||||
/* If the texture can't be repeated with the GPU (e.g. because it has
|
||||
* waste or if using GL_TEXTURE_RECTANGLE_ARB) then we don't support
|
||||
* multi texturing since we don't know if the result will end up trying
|
||||
* to texture from the waste area. */
|
||||
if (_cogl_pipeline_layer_has_user_matrix (layer)
|
||||
&& !_cogl_texture_can_hardware_repeat (tex_handle))
|
||||
* waste or if using GL_TEXTURE_RECTANGLE_ARB) then if a texture matrix
|
||||
* is also in use we don't know if the result will end up trying
|
||||
* to texture from the waste area.
|
||||
*
|
||||
* Note: we check can_hardware_repeat() first since it's cheaper.
|
||||
*
|
||||
* Note: cases where the texture coordinates will require repeating
|
||||
* will be caught by later validation.
|
||||
*/
|
||||
if (!_cogl_texture_can_hardware_repeat (texture) &&
|
||||
_cogl_pipeline_layer_has_user_matrix (pipeline, layer_index))
|
||||
{
|
||||
static gboolean warning_seen = FALSE;
|
||||
if (!warning_seen)
|
||||
g_warning ("Skipping layer %d of your pipeline since a custom "
|
||||
"texture matrix was given for a texture that can't be "
|
||||
"repeated using the GPU and the result may try to "
|
||||
"sample beyond the bounds of the texture ",
|
||||
i);
|
||||
g_warning ("layer %d of your pipeline uses a custom "
|
||||
"texture matrix but because the texture doesn't "
|
||||
"support hardware repeating you may see artefacts "
|
||||
"due to sampling beyond the texture's bounds.",
|
||||
state->i);
|
||||
warning_seen = TRUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* NB: marking for fallback will replace the layer with
|
||||
* a default transparent texture */
|
||||
fallback_layers |= (1 << i);
|
||||
continue;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
struct _CoglMutiTexturedRect
|
||||
{
|
||||
const float *position; /* x0,y0,x1,y1 */
|
||||
const float *tex_coords; /* (tx0,ty0,tx1,ty1)(tx0,ty0,tx1,ty1)(... */
|
||||
int tex_coords_len; /* number of floats in tex_coords? */
|
||||
};
|
||||
|
||||
static void
|
||||
_cogl_rectangles_with_multitexture_coords (
|
||||
struct _CoglMutiTexturedRect *rects,
|
||||
int n_rects)
|
||||
{
|
||||
CoglPipeline *pipeline;
|
||||
ValidateLayerState state;
|
||||
int i;
|
||||
|
||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
|
||||
pipeline = cogl_get_source ();
|
||||
|
||||
/*
|
||||
* Validate all the layers of the current source pipeline...
|
||||
*/
|
||||
state.i = -1;
|
||||
state.first_layer = 0;
|
||||
state.override_source = NULL;
|
||||
state.all_use_sliced_quad_fallback = FALSE;
|
||||
cogl_pipeline_foreach_layer (pipeline,
|
||||
_cogl_rectangles_validate_layer_cb,
|
||||
&state);
|
||||
|
||||
if (state.override_source)
|
||||
pipeline = state.override_source;
|
||||
|
||||
/*
|
||||
* Emit geometry for each of the rectangles...
|
||||
*/
|
||||
|
||||
for (i = 0; i < n_rects; i++)
|
||||
{
|
||||
CoglHandle first_layer, tex_handle;
|
||||
CoglHandle texture;
|
||||
const float default_tex_coords[4] = {0.0, 0.0, 1.0, 1.0};
|
||||
const float *tex_coords;
|
||||
gboolean clamp_s, clamp_t;
|
||||
|
||||
if (!all_use_sliced_quad_fallback)
|
||||
if (!state.all_use_sliced_quad_fallback)
|
||||
{
|
||||
gboolean success =
|
||||
_cogl_multitexture_quad_single_primitive (rects[i].position,
|
||||
pipeline,
|
||||
fallback_layers,
|
||||
rects[i].tex_coords,
|
||||
rects[i].tex_coords_len);
|
||||
|
||||
@ -738,23 +765,23 @@ _cogl_rectangles_with_multitexture_coords (
|
||||
/* If multitexturing failed or we are drawing with a sliced texture
|
||||
* then we only support a single layer so we pluck out the texture
|
||||
* from the first pipeline layer... */
|
||||
layers = _cogl_pipeline_get_layers (pipeline);
|
||||
first_layer = layers->data;
|
||||
tex_handle = _cogl_pipeline_layer_get_texture (first_layer);
|
||||
texture = _cogl_pipeline_get_layer_texture (pipeline, state.first_layer);
|
||||
|
||||
if (rects[i].tex_coords)
|
||||
tex_coords = rects[i].tex_coords;
|
||||
else
|
||||
tex_coords = default_tex_coords;
|
||||
|
||||
clamp_s = (_cogl_pipeline_layer_get_wrap_mode_s (first_layer) ==
|
||||
clamp_s = (cogl_pipeline_get_layer_wrap_mode_s (pipeline,
|
||||
state.first_layer) ==
|
||||
COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE);
|
||||
clamp_t = (_cogl_pipeline_layer_get_wrap_mode_t (first_layer) ==
|
||||
clamp_t = (cogl_pipeline_get_layer_wrap_mode_t (pipeline,
|
||||
state.first_layer) ==
|
||||
COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE);
|
||||
|
||||
COGL_NOTE (DRAW, "Drawing Tex Quad (Multi-Prim Mode)");
|
||||
|
||||
_cogl_texture_quad_multiple_primitives (tex_handle,
|
||||
_cogl_texture_quad_multiple_primitives (texture,
|
||||
pipeline,
|
||||
clamp_s, clamp_t,
|
||||
rects[i].position,
|
||||
@ -764,11 +791,8 @@ _cogl_rectangles_with_multitexture_coords (
|
||||
tex_coords[3]);
|
||||
}
|
||||
|
||||
#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
|
||||
if (state.override_source)
|
||||
cogl_object_unref (pipeline);
|
||||
}
|
||||
|
||||
void
|
||||
@ -971,8 +995,8 @@ typedef struct _ValidateState
|
||||
CoglPipeline *pipeline;
|
||||
} ValidateState;
|
||||
|
||||
gboolean
|
||||
validate_layer_cb (CoglPipeline *pipeline,
|
||||
static gboolean
|
||||
_cogl_polygon_validate_layer_cb (CoglPipeline *pipeline,
|
||||
int layer_index,
|
||||
void *user_data)
|
||||
{
|
||||
@ -1029,7 +1053,7 @@ cogl_polygon (const CoglTextureVertex *vertices,
|
||||
validate_state.original_pipeline = pipeline;
|
||||
validate_state.pipeline = pipeline;
|
||||
cogl_pipeline_foreach_layer (pipeline,
|
||||
validate_layer_cb,
|
||||
_cogl_polygon_validate_layer_cb,
|
||||
&validate_state);
|
||||
pipeline = validate_state.pipeline;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user