pipeline: Reset last_used_for_pipeline when the pipeline is destroyed

Both the GLSL and the ARBfp pipeline backends were using a variable
called last_used_for_pipeline to keep track of the last pipeline that
the shader or program state was used for. If this address is the same
as last time when the pipeline state is flushed then Cogl will only
flush the uniforms that have been modified, otherwise it will flush
all of them. The problem with this is that there was nothing to keep
that address alive so it could be destroyed and reused for a different
pipeline by the time the shader state is reused. This is quite likely
to happen in an application using legacy state because in that case
the shader state will always be used with a one-shot pipeline that
will likely be recycled in the next frame.

There is already a destroy callback to unref the shader state when the
pipeline is destroyed so this patch just makes that callback also
clear the last_used_for_pipeline pointer if it matches the pipeline
being destroyed.

https://bugzilla.gnome.org/show_bug.cgi?id=662542

Reviewed-by: Robert Bragg <robert@linux.intel.com>
This commit is contained in:
Neil Roberts 2011-10-23 20:22:23 +01:00
parent 54c6aec139
commit 49e733fcdc
2 changed files with 26 additions and 10 deletions

View File

@ -109,12 +109,20 @@ get_shader_state (CoglPipeline *pipeline)
} }
static void static void
destroy_shader_state (void *user_data) destroy_shader_state (void *user_data,
void *instance)
{ {
CoglPipelineShaderState *shader_state = user_data; CoglPipelineShaderState *shader_state = user_data;
_COGL_GET_CONTEXT (ctx, NO_RETVAL); _COGL_GET_CONTEXT (ctx, NO_RETVAL);
/* If the shader state was last used for this pipeline then clear it
so that if same address gets used again for a new pipeline then
we won't think it's the same pipeline and avoid updating the
constants */
if (shader_state->last_used_for_pipeline == instance)
shader_state->last_used_for_pipeline = NULL;
if (--shader_state->ref_count == 0) if (--shader_state->ref_count == 0)
{ {
if (shader_state->gl_program) if (shader_state->gl_program)
@ -132,7 +140,7 @@ destroy_shader_state (void *user_data)
static void static void
set_shader_state (CoglPipeline *pipeline, CoglPipelineShaderState *shader_state) set_shader_state (CoglPipeline *pipeline, CoglPipelineShaderState *shader_state)
{ {
cogl_object_set_user_data (COGL_OBJECT (pipeline), _cogl_object_set_user_data (COGL_OBJECT (pipeline),
&shader_state_key, &shader_state_key,
shader_state, shader_state,
destroy_shader_state); destroy_shader_state);

View File

@ -319,12 +319,20 @@ program_state_new (int n_layers)
} }
static void static void
destroy_program_state (void *user_data) destroy_program_state (void *user_data,
void *instance)
{ {
CoglPipelineProgramState *program_state = user_data; CoglPipelineProgramState *program_state = user_data;
_COGL_GET_CONTEXT (ctx, NO_RETVAL); _COGL_GET_CONTEXT (ctx, NO_RETVAL);
/* If the program state was last used for this pipeline then clear
it so that if same address gets used again for a new pipeline
then we won't think it's the same pipeline and avoid updating the
uniforms */
if (program_state->last_used_for_pipeline == instance)
program_state->last_used_for_pipeline = NULL;
if (--program_state->ref_count == 0) if (--program_state->ref_count == 0)
{ {
#ifdef HAVE_COGL_GLES2 #ifdef HAVE_COGL_GLES2
@ -348,7 +356,7 @@ static void
set_program_state (CoglPipeline *pipeline, set_program_state (CoglPipeline *pipeline,
CoglPipelineProgramState *program_state) CoglPipelineProgramState *program_state)
{ {
cogl_object_set_user_data (COGL_OBJECT (pipeline), _cogl_object_set_user_data (COGL_OBJECT (pipeline),
&program_state_key, &program_state_key,
program_state, program_state,
destroy_program_state); destroy_program_state);