1
0
Fork 0

pipeline: Unify how the backends store private data

Previously the fragends had a separate private data pointer which was
used by the GLSL and ARBfp fragends to store a tiny struct containing
a single pointer to the ref-counted shader state. The space for the
private data pointer is reserved in all of the pipelines for all of
the potential backends. The vertends and progends however did this
differently by directly storing the pointer to the ref counted data
using cogl_object_set_user_data. This patch unifies the different
methods so that they all use cogl_object_set_user_data and the
fragends don't bother with the separate tiny allocation for the
private data. The private data pointer array has been removed from
CoglPipeline and the corresponding fragend virtual to free the private
data has also been removed because this can instead be done with the
destroy notify from the object user data.

The variable names used have been unified so that all of the vertends
and fragends name their data struct CoglPipelineShaderState and use a
variable called shader_state to refer to it. The progend uses
CoglPipelineProgramState and a variable called program_state.

This should also fix two potential bugs. the ARBfp fragend was
apprently leaking a reference to the private state when it creates the
private data because it was adding a reference before stroring the
pointer to the newly allocated data but the ref count is already set
to 1 on creation. The other potential bug is that the free function
for CoglPipeline was only calling the free_priv virtual for the
currently used fragend of the pipeline. The design of the fragends is
meant to allow a pipeline to have multiple fragend priv datas because
a child pipeline could be attaching its fragend data to the ancestor
and its allowed to pick a different fragend.
This commit is contained in:
Neil Roberts 2011-06-30 13:39:48 +01:00
parent 221850eca9
commit d69d49fada
7 changed files with 585 additions and 716 deletions

View file

@ -55,6 +55,8 @@
#define GL_TEXTURE_3D 0x806F
#endif
const CoglPipelineFragend _cogl_pipeline_arbfp_fragend;
typedef struct _UnitState
{
int constant_id; /* The program.local[] index */
@ -63,7 +65,7 @@ typedef struct _UnitState
unsigned int sampled:1;
} UnitState;
typedef struct _ArbfpProgramState
typedef struct
{
int ref_count;
@ -84,82 +86,65 @@ typedef struct _ArbfpProgramState
/* We need to track the last pipeline that an ARBfp program was used
* with so know if we need to update any program.local parameters. */
CoglPipeline *last_used_for_pipeline;
} ArbfpProgramState;
} CoglPipelineShaderState;
typedef struct _CoglPipelineFragendARBfpPrivate
static CoglUserDataKey shader_state_key;
static CoglPipelineShaderState *
shader_state_new (int n_layers)
{
ArbfpProgramState *arbfp_program_state;
} CoglPipelineFragendARBfpPrivate;
CoglPipelineShaderState *shader_state;
const CoglPipelineFragend _cogl_pipeline_arbfp_fragend;
shader_state = g_slice_new0 (CoglPipelineShaderState);
shader_state->ref_count = 1;
shader_state->unit_state = g_new0 (UnitState, n_layers);
static ArbfpProgramState *
arbfp_program_state_new (int n_layers)
{
ArbfpProgramState *state = g_slice_new0 (ArbfpProgramState);
state->ref_count = 1;
state->unit_state = g_new0 (UnitState, n_layers);
return state;
return shader_state;
}
static ArbfpProgramState *
arbfp_program_state_ref (ArbfpProgramState *state)
static CoglPipelineShaderState *
get_shader_state (CoglPipeline *pipeline)
{
state->ref_count++;
return state;
}
void
arbfp_program_state_unref (ArbfpProgramState *state)
{
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
g_return_if_fail (state->ref_count > 0);
state->ref_count--;
if (state->ref_count == 0)
{
if (state->gl_program)
{
GE (ctx, glDeletePrograms (1, &state->gl_program));
state->gl_program = 0;
}
g_free (state->unit_state);
g_slice_free (ArbfpProgramState, state);
}
}
static CoglPipelineFragendARBfpPrivate *
get_arbfp_priv (CoglPipeline *pipeline)
{
if (!(pipeline->fragend_priv_set_mask & COGL_PIPELINE_FRAGEND_ARBFP_MASK))
return NULL;
return pipeline->fragend_privs[COGL_PIPELINE_FRAGEND_ARBFP];
return cogl_object_get_user_data (COGL_OBJECT (pipeline), &shader_state_key);
}
static void
set_arbfp_priv (CoglPipeline *pipeline, CoglPipelineFragendARBfpPrivate *priv)
destroy_shader_state (void *user_data)
{
if (priv)
CoglPipelineShaderState *shader_state = user_data;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
if (--shader_state->ref_count == 0)
{
pipeline->fragend_privs[COGL_PIPELINE_FRAGEND_ARBFP] = priv;
pipeline->fragend_priv_set_mask |= COGL_PIPELINE_FRAGEND_ARBFP_MASK;
if (shader_state->gl_program)
{
GE (ctx, glDeletePrograms (1, &shader_state->gl_program));
shader_state->gl_program = 0;
}
g_free (shader_state->unit_state);
g_slice_free (CoglPipelineShaderState, shader_state);
}
else
pipeline->fragend_priv_set_mask &= ~COGL_PIPELINE_FRAGEND_ARBFP_MASK;
}
static ArbfpProgramState *
get_arbfp_program_state (CoglPipeline *pipeline)
static void
set_shader_state (CoglPipeline *pipeline, CoglPipelineShaderState *shader_state)
{
CoglPipelineFragendARBfpPrivate *priv = get_arbfp_priv (pipeline);
if (!priv)
return NULL;
return priv->arbfp_program_state;
cogl_object_set_user_data (COGL_OBJECT (pipeline),
&shader_state_key,
shader_state,
destroy_shader_state);
}
static void
dirty_shader_state (CoglPipeline *pipeline)
{
cogl_object_set_user_data (COGL_OBJECT (pipeline),
&shader_state_key,
NULL,
NULL);
}
static gboolean
@ -168,10 +153,8 @@ _cogl_pipeline_fragend_arbfp_start (CoglPipeline *pipeline,
unsigned long pipelines_difference,
int n_tex_coord_attribs)
{
CoglPipelineFragendARBfpPrivate *priv;
CoglPipelineShaderState *shader_state;
CoglPipeline *authority;
CoglPipelineFragendARBfpPrivate *authority_priv;
ArbfpProgramState *arbfp_program_state;
CoglHandle user_program;
_COGL_GET_CONTEXT (ctx, FALSE);
@ -203,16 +186,11 @@ _cogl_pipeline_fragend_arbfp_start (CoglPipeline *pipeline,
/* Now lookup our ARBfp backend private state (allocating if
* necessary) */
priv = get_arbfp_priv (pipeline);
if (!priv)
{
priv = g_slice_new0 (CoglPipelineFragendARBfpPrivate);
set_arbfp_priv (pipeline, priv);
}
shader_state = get_shader_state (pipeline);
/* If we have a valid arbfp_program_state pointer then we are all
* set and don't need to generate a new program. */
if (priv->arbfp_program_state)
/* If we have a valid shader_state then we are all set and don't
* need to generate a new program. */
if (shader_state)
return TRUE;
/* If we don't have an associated arbfp program yet then find the
@ -228,41 +206,36 @@ _cogl_pipeline_fragend_arbfp_start (CoglPipeline *pipeline,
_cogl_pipeline_get_state_for_fragment_codegen (ctx) &
~COGL_PIPELINE_STATE_LAYERS,
_cogl_pipeline_get_layer_state_for_fragment_codegen (ctx));
authority_priv = get_arbfp_priv (authority);
if (authority_priv &&
authority_priv->arbfp_program_state)
shader_state = get_shader_state (authority);
if (shader_state)
{
/* If we are going to share our program state with an arbfp-authority
* then steal a reference to the program state associated with that
* then add a reference to the program state associated with that
* arbfp-authority... */
priv->arbfp_program_state =
arbfp_program_state_ref (authority_priv->arbfp_program_state);
shader_state->ref_count++;
set_shader_state (pipeline, shader_state);
return TRUE;
}
if (!authority_priv)
{
authority_priv = g_slice_new0 (CoglPipelineFragendARBfpPrivate);
set_arbfp_priv (authority, authority_priv);
}
/* If we haven't yet found an existing program then before we resort to
* generating a new arbfp program we see if we can find a suitable
* program in the arbfp_cache. */
if (G_LIKELY (!(COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_PROGRAM_CACHES))))
{
arbfp_program_state = g_hash_table_lookup (ctx->arbfp_cache, authority);
if (arbfp_program_state)
shader_state = g_hash_table_lookup (ctx->arbfp_cache, authority);
if (shader_state)
{
priv->arbfp_program_state =
arbfp_program_state_ref (arbfp_program_state);
shader_state->ref_count++;
set_shader_state (pipeline, shader_state);
/* Since we have already resolved the arbfp-authority at this point
* we might as well also associate any program we find from the cache
* with the authority too... */
if (authority_priv != priv)
authority_priv->arbfp_program_state =
arbfp_program_state_ref (arbfp_program_state);
if (authority != pipeline)
{
shader_state->ref_count++;
set_shader_state (authority, shader_state);
}
return TRUE;
}
}
@ -271,26 +244,27 @@ _cogl_pipeline_fragend_arbfp_start (CoglPipeline *pipeline,
* generating code for a new program...
*/
arbfp_program_state = arbfp_program_state_new (n_layers);
priv->arbfp_program_state = arbfp_program_state_ref (arbfp_program_state);
shader_state = shader_state_new (n_layers);
set_shader_state (pipeline, shader_state);
/* Since we have already resolved the arbfp-authority at this point we might
* as well also associate any program we generate with the authority too...
*/
if (authority_priv != priv)
authority_priv->arbfp_program_state =
arbfp_program_state_ref (arbfp_program_state);
if (authority != pipeline)
{
shader_state->ref_count++;
set_shader_state (authority, shader_state);
}
arbfp_program_state->user_program = user_program;
shader_state->user_program = user_program;
if (user_program == COGL_INVALID_HANDLE)
{
int i;
/* We reuse a single grow-only GString for code-gen */
g_string_set_size (ctx->codegen_source_buffer, 0);
arbfp_program_state->source = ctx->codegen_source_buffer;
g_string_append (arbfp_program_state->source,
shader_state->source = ctx->codegen_source_buffer;
g_string_append (shader_state->source,
"!!ARBfp1.0\n"
"TEMP output;\n"
"TEMP tmp0, tmp1, tmp2, tmp3, tmp4;\n"
@ -302,14 +276,14 @@ _cogl_pipeline_fragend_arbfp_start (CoglPipeline *pipeline,
/* At the end of code-gen we'll add the program to a cache and
* we'll use the authority pipeline as the basis for key into
* that cache... */
arbfp_program_state->arbfp_authority = authority;
shader_state->arbfp_authority = authority;
for (i = 0; i < n_layers; i++)
{
arbfp_program_state->unit_state[i].sampled = FALSE;
arbfp_program_state->unit_state[i].dirty_combine_constant = FALSE;
shader_state->unit_state[i].sampled = FALSE;
shader_state->unit_state[i].dirty_combine_constant = FALSE;
}
arbfp_program_state->next_constant_id = 0;
shader_state->next_constant_id = 0;
}
return TRUE;
@ -370,20 +344,20 @@ gl_target_to_arbfp_string (GLenum gl_target)
}
static void
setup_texture_source (ArbfpProgramState *arbfp_program_state,
setup_texture_source (CoglPipelineShaderState *shader_state,
int unit_index,
GLenum gl_target)
{
if (!arbfp_program_state->unit_state[unit_index].sampled)
if (!shader_state->unit_state[unit_index].sampled)
{
if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_TEXTURING)))
g_string_append_printf (arbfp_program_state->source,
g_string_append_printf (shader_state->source,
"TEMP texel%d;\n"
"MOV texel%d, one;\n",
unit_index,
unit_index);
else
g_string_append_printf (arbfp_program_state->source,
g_string_append_printf (shader_state->source,
"TEMP texel%d;\n"
"TEX texel%d,fragment.texcoord[%d],"
"texture[%d],%s;\n",
@ -392,7 +366,7 @@ setup_texture_source (ArbfpProgramState *arbfp_program_state,
unit_index,
unit_index,
gl_target_to_arbfp_string (gl_target));
arbfp_program_state->unit_state[unit_index].sampled = TRUE;
shader_state->unit_state[unit_index].sampled = TRUE;
}
}
@ -452,7 +426,7 @@ setup_arg (CoglPipeline *pipeline,
GLint op,
CoglPipelineFragendARBfpArg *arg)
{
ArbfpProgramState *arbfp_program_state = get_arbfp_program_state (pipeline);
CoglPipelineShaderState *shader_state = get_shader_state (pipeline);
static const char *tmp_name[3] = { "tmp0", "tmp1", "tmp2" };
GLenum gl_target;
CoglHandle texture;
@ -465,14 +439,14 @@ setup_arg (CoglPipeline *pipeline,
arg->texture_unit = _cogl_pipeline_layer_get_unit_index (layer);
texture = _cogl_pipeline_layer_get_texture (layer);
cogl_texture_get_gl_texture (texture, NULL, &gl_target);
setup_texture_source (arbfp_program_state, arg->texture_unit, gl_target);
setup_texture_source (shader_state, arg->texture_unit, gl_target);
break;
case COGL_PIPELINE_COMBINE_SOURCE_CONSTANT:
{
int unit_index = _cogl_pipeline_layer_get_unit_index (layer);
UnitState *unit_state = &arbfp_program_state->unit_state[unit_index];
UnitState *unit_state = &shader_state->unit_state[unit_index];
unit_state->constant_id = arbfp_program_state->next_constant_id++;
unit_state->constant_id = shader_state->next_constant_id++;
unit_state->dirty_combine_constant = TRUE;
arg->type = COGL_PIPELINE_FRAGEND_ARBFP_ARG_TYPE_CONSTANT;
@ -497,7 +471,7 @@ setup_arg (CoglPipeline *pipeline,
arg->texture_unit = src - GL_TEXTURE0;
texture = _cogl_pipeline_layer_get_texture (layer);
cogl_texture_get_gl_texture (texture, NULL, &gl_target);
setup_texture_source (arbfp_program_state, arg->texture_unit, gl_target);
setup_texture_source (shader_state, arg->texture_unit, gl_target);
}
arg->swizzle = "";
@ -507,11 +481,11 @@ setup_arg (CoglPipeline *pipeline,
case COGL_PIPELINE_COMBINE_OP_SRC_COLOR:
break;
case COGL_PIPELINE_COMBINE_OP_ONE_MINUS_SRC_COLOR:
g_string_append_printf (arbfp_program_state->source,
g_string_append_printf (shader_state->source,
"SUB tmp%d, one, ",
arg_index);
append_arg (arbfp_program_state->source, arg);
g_string_append_printf (arbfp_program_state->source, ";\n");
append_arg (shader_state->source, arg);
g_string_append_printf (shader_state->source, ";\n");
arg->type = COGL_PIPELINE_FRAGEND_ARBFP_ARG_TYPE_SIMPLE;
arg->name = tmp_name[arg_index];
arg->swizzle = "";
@ -523,16 +497,16 @@ setup_arg (CoglPipeline *pipeline,
arg->swizzle = ".a";
break;
case COGL_PIPELINE_COMBINE_OP_ONE_MINUS_SRC_ALPHA:
g_string_append_printf (arbfp_program_state->source,
g_string_append_printf (shader_state->source,
"SUB tmp%d, one, ",
arg_index);
append_arg (arbfp_program_state->source, arg);
append_arg (shader_state->source, arg);
/* avoid a swizzle if we know RGB are going to be masked
* in the end anyway */
if (mask != COGL_BLEND_STRING_CHANNEL_MASK_ALPHA)
g_string_append_printf (arbfp_program_state->source, ".a;\n");
g_string_append_printf (shader_state->source, ".a;\n");
else
g_string_append_printf (arbfp_program_state->source, ";\n");
g_string_append_printf (shader_state->source, ";\n");
arg->type = COGL_PIPELINE_FRAGEND_ARBFP_ARG_TYPE_SIMPLE;
arg->name = tmp_name[arg_index];
break;
@ -577,7 +551,7 @@ append_function (CoglPipeline *pipeline,
CoglPipelineFragendARBfpArg *args,
int n_args)
{
ArbfpProgramState *arbfp_program_state = get_arbfp_program_state (pipeline);
CoglPipelineShaderState *shader_state = get_shader_state (pipeline);
const char *mask_name;
switch (mask)
@ -599,35 +573,35 @@ append_function (CoglPipeline *pipeline,
switch (function)
{
case COGL_PIPELINE_COMBINE_FUNC_ADD:
g_string_append_printf (arbfp_program_state->source,
g_string_append_printf (shader_state->source,
"ADD_SAT output%s, ",
mask_name);
break;
case COGL_PIPELINE_COMBINE_FUNC_MODULATE:
/* Note: no need to saturate since we can assume operands
* have values in the range [0,1] */
g_string_append_printf (arbfp_program_state->source, "MUL output%s, ",
g_string_append_printf (shader_state->source, "MUL output%s, ",
mask_name);
break;
case COGL_PIPELINE_COMBINE_FUNC_REPLACE:
/* Note: no need to saturate since we can assume operand
* has a value in the range [0,1] */
g_string_append_printf (arbfp_program_state->source, "MOV output%s, ",
g_string_append_printf (shader_state->source, "MOV output%s, ",
mask_name);
break;
case COGL_PIPELINE_COMBINE_FUNC_SUBTRACT:
g_string_append_printf (arbfp_program_state->source,
g_string_append_printf (shader_state->source,
"SUB_SAT output%s, ",
mask_name);
break;
case COGL_PIPELINE_COMBINE_FUNC_ADD_SIGNED:
g_string_append_printf (arbfp_program_state->source, "ADD tmp3%s, ",
g_string_append_printf (shader_state->source, "ADD tmp3%s, ",
mask_name);
append_arg (arbfp_program_state->source, &args[0]);
g_string_append (arbfp_program_state->source, ", ");
append_arg (arbfp_program_state->source, &args[1]);
g_string_append (arbfp_program_state->source, ";\n");
g_string_append_printf (arbfp_program_state->source,
append_arg (shader_state->source, &args[0]);
g_string_append (shader_state->source, ", ");
append_arg (shader_state->source, &args[1]);
g_string_append (shader_state->source, ";\n");
g_string_append_printf (shader_state->source,
"SUB_SAT output%s, tmp3, half",
mask_name);
n_args = 0;
@ -656,20 +630,20 @@ append_function (CoglPipeline *pipeline,
* output = 4 * DP3 (src0 - 0.5, src1 - 0.5)
*/
g_string_append (arbfp_program_state->source, "MAD tmp3, two, ");
append_arg (arbfp_program_state->source, &args[0]);
g_string_append (arbfp_program_state->source, ", minus_one;\n");
g_string_append (shader_state->source, "MAD tmp3, two, ");
append_arg (shader_state->source, &args[0]);
g_string_append (shader_state->source, ", minus_one;\n");
if (!fragend_arbfp_args_equal (&args[0], &args[1]))
{
g_string_append (arbfp_program_state->source, "MAD tmp4, two, ");
append_arg (arbfp_program_state->source, &args[1]);
g_string_append (arbfp_program_state->source, ", minus_one;\n");
g_string_append (shader_state->source, "MAD tmp4, two, ");
append_arg (shader_state->source, &args[1]);
g_string_append (shader_state->source, ", minus_one;\n");
}
else
tmp4 = "tmp3";
g_string_append_printf (arbfp_program_state->source,
g_string_append_printf (shader_state->source,
"DP3_SAT output%s, tmp3, %s",
mask_name, tmp4);
n_args = 0;
@ -681,31 +655,31 @@ append_function (CoglPipeline *pipeline,
/* NB: GL_INTERPOLATE = arg0*arg2 + arg1*(1-arg2)
* but LRP dst, a, b, c = b*a + c*(1-a) */
g_string_append_printf (arbfp_program_state->source, "LRP output%s, ",
g_string_append_printf (shader_state->source, "LRP output%s, ",
mask_name);
append_arg (arbfp_program_state->source, &args[2]);
g_string_append (arbfp_program_state->source, ", ");
append_arg (arbfp_program_state->source, &args[0]);
g_string_append (arbfp_program_state->source, ", ");
append_arg (arbfp_program_state->source, &args[1]);
append_arg (shader_state->source, &args[2]);
g_string_append (shader_state->source, ", ");
append_arg (shader_state->source, &args[0]);
g_string_append (shader_state->source, ", ");
append_arg (shader_state->source, &args[1]);
n_args = 0;
break;
default:
g_error ("Unknown texture combine function %d", function);
g_string_append_printf (arbfp_program_state->source, "MUL_SAT output%s, ",
g_string_append_printf (shader_state->source, "MUL_SAT output%s, ",
mask_name);
n_args = 2;
break;
}
if (n_args > 0)
append_arg (arbfp_program_state->source, &args[0]);
append_arg (shader_state->source, &args[0]);
if (n_args > 1)
{
g_string_append (arbfp_program_state->source, ", ");
append_arg (arbfp_program_state->source, &args[1]);
g_string_append (shader_state->source, ", ");
append_arg (shader_state->source, &args[1]);
}
g_string_append (arbfp_program_state->source, ";\n");
g_string_append (shader_state->source, ";\n");
}
static void
@ -745,7 +719,7 @@ _cogl_pipeline_fragend_arbfp_add_layer (CoglPipeline *pipeline,
CoglPipelineLayer *layer,
unsigned long layers_difference)
{
ArbfpProgramState *arbfp_program_state = get_arbfp_program_state (pipeline);
CoglPipelineShaderState *shader_state = get_shader_state (pipeline);
CoglPipelineLayer *combine_authority =
_cogl_pipeline_layer_get_authority (layer,
COGL_PIPELINE_LAYER_STATE_COMBINE);
@ -780,7 +754,7 @@ _cogl_pipeline_fragend_arbfp_add_layer (CoglPipeline *pipeline,
* We are careful to only saturate when writing to output.
*/
if (!arbfp_program_state->source)
if (!shader_state->source)
return TRUE;
if (!_cogl_pipeline_need_texture_combine_separate (combine_authority))
@ -827,12 +801,12 @@ _cogl_pipeline_fragend_arbfp_add_layer (CoglPipeline *pipeline,
gboolean
_cogl_pipeline_fragend_arbfp_passthrough (CoglPipeline *pipeline)
{
ArbfpProgramState *arbfp_program_state = get_arbfp_program_state (pipeline);
CoglPipelineShaderState *shader_state = get_shader_state (pipeline);
if (!arbfp_program_state->source)
if (!shader_state->source)
return TRUE;
g_string_append (arbfp_program_state->source,
g_string_append (shader_state->source,
"MOV output, fragment.color.primary;\n");
return TRUE;
}
@ -841,7 +815,7 @@ typedef struct _UpdateConstantsState
{
int unit;
gboolean update_all;
ArbfpProgramState *arbfp_program_state;
CoglPipelineShaderState *shader_state;
} UpdateConstantsState;
static gboolean
@ -850,8 +824,8 @@ update_constants_cb (CoglPipeline *pipeline,
void *user_data)
{
UpdateConstantsState *state = user_data;
ArbfpProgramState *arbfp_program_state = state->arbfp_program_state;
UnitState *unit_state = &arbfp_program_state->unit_state[state->unit++];
CoglPipelineShaderState *shader_state = state->shader_state;
UnitState *unit_state = &shader_state->unit_state[state->unit++];
_COGL_GET_CONTEXT (ctx, FALSE);
@ -873,12 +847,12 @@ static gboolean
_cogl_pipeline_fragend_arbfp_end (CoglPipeline *pipeline,
unsigned long pipelines_difference)
{
ArbfpProgramState *arbfp_program_state = get_arbfp_program_state (pipeline);
CoglPipelineShaderState *shader_state = get_shader_state (pipeline);
GLuint gl_program;
_COGL_GET_CONTEXT (ctx, FALSE);
if (arbfp_program_state->source)
if (shader_state->source)
{
GLenum gl_error;
COGL_STATIC_COUNTER (fragend_arbfp_compile_counter,
@ -889,32 +863,32 @@ _cogl_pipeline_fragend_arbfp_end (CoglPipeline *pipeline,
COGL_COUNTER_INC (_cogl_uprof_context, fragend_arbfp_compile_counter);
g_string_append (arbfp_program_state->source,
g_string_append (shader_state->source,
"MOV result.color,output;\n");
g_string_append (arbfp_program_state->source, "END\n");
g_string_append (shader_state->source, "END\n");
if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_SHOW_SOURCE)))
g_message ("pipeline program:\n%s", arbfp_program_state->source->str);
g_message ("pipeline program:\n%s", shader_state->source->str);
GE (ctx, glGenPrograms (1, &arbfp_program_state->gl_program));
GE (ctx, glGenPrograms (1, &shader_state->gl_program));
GE (ctx, glBindProgram (GL_FRAGMENT_PROGRAM_ARB,
arbfp_program_state->gl_program));
shader_state->gl_program));
while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR)
;
ctx->glProgramString (GL_FRAGMENT_PROGRAM_ARB,
GL_PROGRAM_FORMAT_ASCII_ARB,
arbfp_program_state->source->len,
arbfp_program_state->source->str);
shader_state->source->len,
shader_state->source->str);
if (ctx->glGetError () != GL_NO_ERROR)
{
g_warning ("\n%s\n%s",
arbfp_program_state->source->str,
shader_state->source->str,
ctx->glGetString (GL_PROGRAM_ERROR_STRING_ARB));
}
arbfp_program_state->source = NULL;
shader_state->source = NULL;
if (G_LIKELY (!(COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_PROGRAM_CACHES))))
{
@ -942,9 +916,9 @@ _cogl_pipeline_fragend_arbfp_end (CoglPipeline *pipeline,
* other pipelines) and only takes a copy of the state that
* relates to the arbfp program and references small dummy
* textures instead of potentially large user textures. */
key = cogl_pipeline_copy (arbfp_program_state->arbfp_authority);
arbfp_program_state_ref (arbfp_program_state);
g_hash_table_insert (ctx->arbfp_cache, key, arbfp_program_state);
key = cogl_pipeline_copy (shader_state->arbfp_authority);
shader_state->ref_count++;
g_hash_table_insert (ctx->arbfp_cache, key, shader_state);
if (G_UNLIKELY (g_hash_table_size (ctx->arbfp_cache) > 50))
{
static gboolean seen = FALSE;
@ -959,77 +933,59 @@ _cogl_pipeline_fragend_arbfp_end (CoglPipeline *pipeline,
/* The authority is only valid during codegen since the program
* state may have a longer lifetime than the original authority
* it is created for. */
arbfp_program_state->arbfp_authority = NULL;
shader_state->arbfp_authority = NULL;
}
if (arbfp_program_state->user_program != COGL_INVALID_HANDLE)
if (shader_state->user_program != COGL_INVALID_HANDLE)
{
/* An arbfp program should contain exactly one shader which we
can use directly */
CoglProgram *program = arbfp_program_state->user_program;
CoglProgram *program = shader_state->user_program;
CoglShader *shader = program->attached_shaders->data;
gl_program = shader->gl_handle;
}
else
gl_program = arbfp_program_state->gl_program;
gl_program = shader_state->gl_program;
GE (ctx, glBindProgram (GL_FRAGMENT_PROGRAM_ARB, gl_program));
_cogl_use_fragment_program (0, COGL_PIPELINE_PROGRAM_TYPE_ARBFP);
if (arbfp_program_state->user_program == COGL_INVALID_HANDLE)
if (shader_state->user_program == COGL_INVALID_HANDLE)
{
UpdateConstantsState state;
state.unit = 0;
state.arbfp_program_state = arbfp_program_state;
state.shader_state = shader_state;
/* If this arbfp program was last used with a different pipeline
* then we need to ensure we update all program.local params */
state.update_all =
pipeline != arbfp_program_state->last_used_for_pipeline;
pipeline != shader_state->last_used_for_pipeline;
cogl_pipeline_foreach_layer (pipeline,
update_constants_cb,
&state);
}
else
{
CoglProgram *program = arbfp_program_state->user_program;
CoglProgram *program = shader_state->user_program;
gboolean program_changed;
/* If the shader has changed since it was last flushed then we
need to update all uniforms */
program_changed = program->age != arbfp_program_state->user_program_age;
program_changed = program->age != shader_state->user_program_age;
_cogl_program_flush_uniforms (program, gl_program, program_changed);
arbfp_program_state->user_program_age = program->age;
shader_state->user_program_age = program->age;
}
/* We need to track what pipeline used this arbfp program last since
* we will need to update program.local params when switching
* between different pipelines. */
arbfp_program_state->last_used_for_pipeline = pipeline;
shader_state->last_used_for_pipeline = pipeline;
return TRUE;
}
static void
dirty_arbfp_program_state (CoglPipeline *pipeline)
{
CoglPipelineFragendARBfpPrivate *priv;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
priv = get_arbfp_priv (pipeline);
if (!priv)
return;
if (priv->arbfp_program_state)
{
arbfp_program_state_unref (priv->arbfp_program_state);
priv->arbfp_program_state = NULL;
}
}
static void
_cogl_pipeline_fragend_arbfp_pipeline_pre_change_notify (
CoglPipeline *pipeline,
@ -1039,7 +995,7 @@ _cogl_pipeline_fragend_arbfp_pipeline_pre_change_notify (
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
if ((change & _cogl_pipeline_get_state_for_fragment_codegen (ctx)))
dirty_arbfp_program_state (pipeline);
dirty_shader_state (pipeline);
}
/* NB: layers are considered immutable once they have any dependants
@ -1056,29 +1012,23 @@ _cogl_pipeline_fragend_arbfp_layer_pre_change_notify (
CoglPipelineLayer *layer,
CoglPipelineLayerState change)
{
CoglPipelineFragendARBfpPrivate *priv = get_arbfp_priv (owner);
CoglPipelineShaderState *shader_state = get_shader_state (owner);
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
if (!priv)
if (!shader_state)
return;
if ((change & _cogl_pipeline_get_layer_state_for_fragment_codegen (ctx)))
{
dirty_arbfp_program_state (owner);
dirty_shader_state (owner);
return;
}
if (change & COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT)
{
ArbfpProgramState *arbfp_program_state = get_arbfp_program_state (owner);
if (arbfp_program_state)
{
int unit_index = _cogl_pipeline_layer_get_unit_index (layer);
arbfp_program_state->unit_state[unit_index].dirty_combine_constant =
TRUE;
}
int unit_index = _cogl_pipeline_layer_get_unit_index (layer);
shader_state->unit_state[unit_index].dirty_combine_constant = TRUE;
}
/* TODO: we could be saving snippets of texture combine code along
@ -1087,19 +1037,6 @@ _cogl_pipeline_fragend_arbfp_layer_pre_change_notify (
return;
}
static void
_cogl_pipeline_fragend_arbfp_free_priv (CoglPipeline *pipeline)
{
CoglPipelineFragendARBfpPrivate *priv = get_arbfp_priv (pipeline);
if (priv)
{
if (priv->arbfp_program_state)
arbfp_program_state_unref (priv->arbfp_program_state);
g_slice_free (CoglPipelineFragendARBfpPrivate, priv);
set_arbfp_priv (pipeline, NULL);
}
}
const CoglPipelineFragend _cogl_pipeline_arbfp_fragend =
{
_cogl_pipeline_fragend_arbfp_start,
@ -1108,8 +1045,7 @@ const CoglPipelineFragend _cogl_pipeline_arbfp_fragend =
_cogl_pipeline_fragend_arbfp_end,
_cogl_pipeline_fragend_arbfp_pipeline_pre_change_notify,
NULL,
_cogl_pipeline_fragend_arbfp_layer_pre_change_notify,
_cogl_pipeline_fragend_arbfp_free_priv
_cogl_pipeline_fragend_arbfp_layer_pre_change_notify
};
#endif /* COGL_PIPELINE_FRAGEND_ARBFP */

View file

@ -363,7 +363,6 @@ const CoglPipelineFragend _cogl_pipeline_fixed_fragend =
NULL, /* pipeline_change_notify */
NULL, /* pipeline_set_parent_notify */
NULL, /* layer_change_notify */
NULL /* free_priv */
};
#endif /* COGL_PIPELINE_FRAGEND_FIXED */

View file

@ -56,13 +56,15 @@
#define GL_TEXTURE_3D 0x806F
#endif
const CoglPipelineFragend _cogl_pipeline_glsl_backend;
typedef struct _UnitState
{
unsigned int sampled:1;
unsigned int combine_constant_used:1;
} UnitState;
typedef struct _GlslShaderState
typedef struct
{
int ref_count;
@ -75,120 +77,83 @@ typedef struct _GlslShaderState
program changes then we may need to redecide whether to generate
a shader at all */
unsigned int user_program_age;
} GlslShaderState;
} CoglPipelineShaderState;
typedef struct _CoglPipelineFragendGlslPrivate
static CoglUserDataKey shader_state_key;
static CoglPipelineShaderState *
shader_state_new (int n_layers)
{
GlslShaderState *glsl_shader_state;
} CoglPipelineFragendGlslPrivate;
CoglPipelineShaderState *shader_state;
const CoglPipelineFragend _cogl_pipeline_glsl_backend;
shader_state = g_slice_new0 (CoglPipelineShaderState);
shader_state->ref_count = 1;
shader_state->unit_state = g_new0 (UnitState, n_layers);
static GlslShaderState *
glsl_shader_state_new (int n_layers)
{
GlslShaderState *state = g_slice_new0 (GlslShaderState);
state->ref_count = 1;
state->unit_state = g_new0 (UnitState, n_layers);
return state;
return shader_state;
}
static GlslShaderState *
glsl_shader_state_ref (GlslShaderState *state)
static CoglPipelineShaderState *
get_shader_state (CoglPipeline *pipeline)
{
state->ref_count++;
return state;
}
void
glsl_shader_state_unref (GlslShaderState *state)
{
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
g_return_if_fail (state->ref_count > 0);
state->ref_count--;
if (state->ref_count == 0)
{
if (state->gl_shader)
GE( ctx, glDeleteShader (state->gl_shader) );
g_free (state->unit_state);
g_slice_free (GlslShaderState, state);
}
}
static CoglPipelineFragendGlslPrivate *
get_glsl_priv (CoglPipeline *pipeline)
{
if (!(pipeline->fragend_priv_set_mask & COGL_PIPELINE_FRAGEND_GLSL_MASK))
return NULL;
return pipeline->fragend_privs[COGL_PIPELINE_FRAGEND_GLSL];
return cogl_object_get_user_data (COGL_OBJECT (pipeline), &shader_state_key);
}
static void
set_glsl_priv (CoglPipeline *pipeline, CoglPipelineFragendGlslPrivate *priv)
destroy_shader_state (void *user_data)
{
if (priv)
CoglPipelineShaderState *shader_state = user_data;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
if (--shader_state->ref_count == 0)
{
pipeline->fragend_privs[COGL_PIPELINE_FRAGEND_GLSL] = priv;
pipeline->fragend_priv_set_mask |= COGL_PIPELINE_FRAGEND_GLSL_MASK;
if (shader_state->gl_shader)
GE( ctx, glDeleteShader (shader_state->gl_shader) );
g_free (shader_state->unit_state);
g_slice_free (CoglPipelineShaderState, shader_state);
}
else
pipeline->fragend_priv_set_mask &= ~COGL_PIPELINE_FRAGEND_GLSL_MASK;
}
static GlslShaderState *
get_glsl_shader_state (CoglPipeline *pipeline)
static void
set_shader_state (CoglPipeline *pipeline, CoglPipelineShaderState *shader_state)
{
CoglPipelineFragendGlslPrivate *priv = get_glsl_priv (pipeline);
if (!priv)
return NULL;
return priv->glsl_shader_state;
cogl_object_set_user_data (COGL_OBJECT (pipeline),
&shader_state_key,
shader_state,
destroy_shader_state);
}
static void
dirty_shader_state (CoglPipeline *pipeline)
{
cogl_object_set_user_data (COGL_OBJECT (pipeline),
&shader_state_key,
NULL,
NULL);
}
GLuint
_cogl_pipeline_fragend_glsl_get_shader (CoglPipeline *pipeline)
{
GlslShaderState *glsl_shader_state = get_glsl_shader_state (pipeline);
CoglPipelineShaderState *shader_state = get_shader_state (pipeline);
if (glsl_shader_state)
return glsl_shader_state->gl_shader;
if (shader_state)
return shader_state->gl_shader;
else
return 0;
}
static void
dirty_glsl_shader_state (CoglPipeline *pipeline)
{
CoglPipelineFragendGlslPrivate *priv;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
priv = get_glsl_priv (pipeline);
if (!priv)
return;
if (priv->glsl_shader_state)
{
glsl_shader_state_unref (priv->glsl_shader_state);
priv->glsl_shader_state = NULL;
}
}
static gboolean
_cogl_pipeline_fragend_glsl_start (CoglPipeline *pipeline,
int n_layers,
unsigned long pipelines_difference,
int n_tex_coord_attribs)
{
CoglPipelineFragendGlslPrivate *priv;
CoglPipelineShaderState *shader_state;
CoglPipeline *authority;
CoglPipelineFragendGlslPrivate *authority_priv;
CoglProgram *user_program;
int i;
@ -206,16 +171,10 @@ _cogl_pipeline_fragend_glsl_start (CoglPipeline *pipeline,
_cogl_program_get_language (user_program) != COGL_SHADER_LANGUAGE_GLSL)
return FALSE;
/* Now lookup our glsl backend private state (allocating if
* necessary) */
priv = get_glsl_priv (pipeline);
if (!priv)
{
priv = g_slice_new0 (CoglPipelineFragendGlslPrivate);
set_glsl_priv (pipeline, priv);
}
/* Now lookup our glsl backend private state */
shader_state = get_shader_state (pipeline);
if (!priv->glsl_shader_state)
if (shader_state == NULL)
{
/* If we don't have an associated glsl shader yet then find the
* glsl-authority (the oldest ancestor whose state will result in
@ -231,43 +190,39 @@ _cogl_pipeline_fragend_glsl_start (CoglPipeline *pipeline,
~COGL_PIPELINE_STATE_LAYERS,
_cogl_pipeline_get_layer_state_for_fragment_codegen (ctx));
authority_priv = get_glsl_priv (authority);
if (!authority_priv)
{
authority_priv = g_slice_new0 (CoglPipelineFragendGlslPrivate);
set_glsl_priv (authority, authority_priv);
}
shader_state = get_shader_state (authority);
/* If we don't have an existing program associated with the
* glsl-authority then start generating code for a new shader...
*/
if (!authority_priv->glsl_shader_state)
if (shader_state == NULL)
{
GlslShaderState *glsl_shader_state =
glsl_shader_state_new (n_layers);
authority_priv->glsl_shader_state = glsl_shader_state;
shader_state = shader_state_new (n_layers);
set_shader_state (authority, shader_state);
}
/* If the pipeline isn't actually its own glsl-authority
* then take a reference to the program state associated
* with the glsl-authority... */
if (authority != pipeline)
priv->glsl_shader_state =
glsl_shader_state_ref (authority_priv->glsl_shader_state);
{
shader_state->ref_count++;
set_shader_state (pipeline, shader_state);
}
}
if (priv->glsl_shader_state->gl_shader)
if (shader_state->gl_shader)
{
/* If we already have a valid GLSL shader then we don't need to
generate a new one. However if there's a user program and it
has changed since the last link then we do need a new shader */
if (user_program == NULL ||
(priv->glsl_shader_state->user_program_age == user_program->age))
shader_state->user_program_age == user_program->age)
return TRUE;
/* We need to recreate the shader so destroy the existing one */
GE( ctx, glDeleteShader (priv->glsl_shader_state->gl_shader) );
priv->glsl_shader_state->gl_shader = 0;
GE( ctx, glDeleteShader (shader_state->gl_shader) );
shader_state->gl_shader = 0;
}
/* If we make it here then we have a glsl_shader_state struct
@ -275,7 +230,7 @@ _cogl_pipeline_fragend_glsl_start (CoglPipeline *pipeline,
encountered it or because the user program has changed */
if (user_program)
priv->glsl_shader_state->user_program_age = user_program->age;
shader_state->user_program_age = user_program->age;
/* If the user program contains a fragment shader then we don't need
to generate one */
@ -290,25 +245,25 @@ _cogl_pipeline_fragend_glsl_start (CoglPipeline *pipeline,
add_layer callback is invoked */
g_string_set_size (ctx->codegen_header_buffer, 0);
g_string_set_size (ctx->codegen_source_buffer, 0);
priv->glsl_shader_state->header = ctx->codegen_header_buffer;
priv->glsl_shader_state->source = ctx->codegen_source_buffer;
shader_state->header = ctx->codegen_header_buffer;
shader_state->source = ctx->codegen_source_buffer;
g_string_append (priv->glsl_shader_state->source,
g_string_append (shader_state->source,
"void\n"
"main ()\n"
"{\n");
for (i = 0; i < n_layers; i++)
{
priv->glsl_shader_state->unit_state[i].sampled = FALSE;
priv->glsl_shader_state->unit_state[i].combine_constant_used = FALSE;
shader_state->unit_state[i].sampled = FALSE;
shader_state->unit_state[i].combine_constant_used = FALSE;
}
return TRUE;
}
static void
add_constant_lookup (GlslShaderState *glsl_shader_state,
add_constant_lookup (CoglPipelineShaderState *shader_state,
CoglPipeline *pipeline,
CoglPipelineLayer *layer,
const char *swizzle)
@ -316,21 +271,21 @@ add_constant_lookup (GlslShaderState *glsl_shader_state,
int unit_index = _cogl_pipeline_layer_get_unit_index (layer);
/* Create a sampler uniform for this layer if we haven't already */
if (!glsl_shader_state->unit_state[unit_index].combine_constant_used)
if (!shader_state->unit_state[unit_index].combine_constant_used)
{
g_string_append_printf (glsl_shader_state->header,
g_string_append_printf (shader_state->header,
"uniform vec4 _cogl_layer_constant_%i;\n",
unit_index);
glsl_shader_state->unit_state[unit_index].combine_constant_used = TRUE;
shader_state->unit_state[unit_index].combine_constant_used = TRUE;
}
g_string_append_printf (glsl_shader_state->source,
g_string_append_printf (shader_state->source,
"_cogl_layer_constant_%i.%s",
unit_index, swizzle);
}
static void
add_texture_lookup (GlslShaderState *glsl_shader_state,
add_texture_lookup (CoglPipelineShaderState *shader_state,
CoglPipeline *pipeline,
CoglPipelineLayer *layer,
const char *swizzle)
@ -343,9 +298,9 @@ add_texture_lookup (GlslShaderState *glsl_shader_state,
if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_TEXTURING)))
{
g_string_append (glsl_shader_state->source,
g_string_append (shader_state->source,
"vec4 (1.0, 1.0, 1.0, 1.0).");
g_string_append (glsl_shader_state->source, swizzle);
g_string_append (shader_state->source, swizzle);
return;
}
@ -394,16 +349,16 @@ add_texture_lookup (GlslShaderState *glsl_shader_state,
}
/* Create a sampler uniform for this layer if we haven't already */
if (!glsl_shader_state->unit_state[unit_index].sampled)
if (!shader_state->unit_state[unit_index].sampled)
{
g_string_append_printf (glsl_shader_state->header,
g_string_append_printf (shader_state->header,
"uniform sampler%s _cogl_sampler_%i;\n",
target_string,
unit_index);
glsl_shader_state->unit_state[unit_index].sampled = TRUE;
shader_state->unit_state[unit_index].sampled = TRUE;
}
g_string_append_printf (glsl_shader_state->source,
g_string_append_printf (shader_state->source,
"texture%s (_cogl_sampler_%i, ",
target_string, unit_index);
@ -418,15 +373,15 @@ add_texture_lookup (GlslShaderState *glsl_shader_state,
if (ctx->driver == COGL_DRIVER_GLES2 &&
cogl_pipeline_get_layer_point_sprite_coords_enabled (pipeline,
layer->index))
g_string_append_printf (glsl_shader_state->source,
g_string_append_printf (shader_state->source,
"gl_PointCoord.%s",
tex_coord_swizzle);
else
g_string_append_printf (glsl_shader_state->source,
g_string_append_printf (shader_state->source,
"cogl_tex_coord_in[%d].%s",
unit_index, tex_coord_swizzle);
g_string_append_printf (glsl_shader_state->source, ").%s", swizzle);
g_string_append_printf (shader_state->source, ").%s", swizzle);
}
typedef struct
@ -454,14 +409,14 @@ find_pipeline_layer_cb (CoglPipelineLayer *layer,
}
static void
add_arg (GlslShaderState *glsl_shader_state,
add_arg (CoglPipelineShaderState *shader_state,
CoglPipeline *pipeline,
CoglPipelineLayer *layer,
CoglPipelineCombineSource src,
CoglPipelineCombineOp operand,
const char *swizzle)
{
GString *shader_source = glsl_shader_state->source;
GString *shader_source = shader_state->source;
char alpha_swizzle[5] = "aaaa";
g_string_append_c (shader_source, '(');
@ -484,14 +439,14 @@ add_arg (GlslShaderState *glsl_shader_state,
switch (src)
{
case COGL_PIPELINE_COMBINE_SOURCE_TEXTURE:
add_texture_lookup (glsl_shader_state,
add_texture_lookup (shader_state,
pipeline,
layer,
swizzle);
break;
case COGL_PIPELINE_COMBINE_SOURCE_CONSTANT:
add_constant_lookup (glsl_shader_state,
add_constant_lookup (shader_state,
pipeline,
layer,
swizzle);
@ -521,7 +476,7 @@ add_arg (GlslShaderState *glsl_shader_state,
find_pipeline_layer_cb,
&data);
add_texture_lookup (glsl_shader_state,
add_texture_lookup (shader_state,
pipeline,
data.layer,
swizzle);
@ -540,40 +495,40 @@ append_masked_combine (CoglPipeline *pipeline,
CoglPipelineCombineSource *src,
CoglPipelineCombineOp *op)
{
GlslShaderState *glsl_shader_state = get_glsl_shader_state (pipeline);
GString *shader_source = glsl_shader_state->source;
CoglPipelineShaderState *shader_state = get_shader_state (pipeline);
GString *shader_source = shader_state->source;
g_string_append_printf (glsl_shader_state->source,
g_string_append_printf (shader_state->source,
" cogl_color_out.%s = ", swizzle);
switch (function)
{
case COGL_PIPELINE_COMBINE_FUNC_REPLACE:
add_arg (glsl_shader_state, pipeline, layer,
add_arg (shader_state, pipeline, layer,
src[0], op[0], swizzle);
break;
case COGL_PIPELINE_COMBINE_FUNC_MODULATE:
add_arg (glsl_shader_state, pipeline, layer,
add_arg (shader_state, pipeline, layer,
src[0], op[0], swizzle);
g_string_append (shader_source, " * ");
add_arg (glsl_shader_state, pipeline, layer,
add_arg (shader_state, pipeline, layer,
src[1], op[1], swizzle);
break;
case COGL_PIPELINE_COMBINE_FUNC_ADD:
add_arg (glsl_shader_state, pipeline, layer,
add_arg (shader_state, pipeline, layer,
src[0], op[0], swizzle);
g_string_append (shader_source, " + ");
add_arg (glsl_shader_state, pipeline, layer,
add_arg (shader_state, pipeline, layer,
src[1], op[1], swizzle);
break;
case COGL_PIPELINE_COMBINE_FUNC_ADD_SIGNED:
add_arg (glsl_shader_state, pipeline, layer,
add_arg (shader_state, pipeline, layer,
src[0], op[0], swizzle);
g_string_append (shader_source, " + ");
add_arg (glsl_shader_state, pipeline, layer,
add_arg (shader_state, pipeline, layer,
src[1], op[1], swizzle);
g_string_append_printf (shader_source,
" - vec4(0.5, 0.5, 0.5, 0.5).%s",
@ -581,26 +536,26 @@ append_masked_combine (CoglPipeline *pipeline,
break;
case COGL_PIPELINE_COMBINE_FUNC_SUBTRACT:
add_arg (glsl_shader_state, pipeline, layer,
add_arg (shader_state, pipeline, layer,
src[0], op[0], swizzle);
g_string_append (shader_source, " - ");
add_arg (glsl_shader_state, pipeline, layer,
add_arg (shader_state, pipeline, layer,
src[1], op[1], swizzle);
break;
case COGL_PIPELINE_COMBINE_FUNC_INTERPOLATE:
add_arg (glsl_shader_state, pipeline, layer,
add_arg (shader_state, pipeline, layer,
src[0], op[0], swizzle);
g_string_append (shader_source, " * ");
add_arg (glsl_shader_state, pipeline, layer,
add_arg (shader_state, pipeline, layer,
src[2], op[2], swizzle);
g_string_append (shader_source, " + ");
add_arg (glsl_shader_state, pipeline, layer,
add_arg (shader_state, pipeline, layer,
src[1], op[1], swizzle);
g_string_append_printf (shader_source,
" * (vec4(1.0, 1.0, 1.0, 1.0).%s - ",
swizzle);
add_arg (glsl_shader_state, pipeline, layer,
add_arg (shader_state, pipeline, layer,
src[2], op[2], swizzle);
g_string_append_c (shader_source, ')');
break;
@ -608,22 +563,22 @@ append_masked_combine (CoglPipeline *pipeline,
case COGL_PIPELINE_COMBINE_FUNC_DOT3_RGB:
case COGL_PIPELINE_COMBINE_FUNC_DOT3_RGBA:
g_string_append (shader_source, "vec4(4.0 * ((");
add_arg (glsl_shader_state, pipeline, layer,
add_arg (shader_state, pipeline, layer,
src[0], op[0], "r");
g_string_append (shader_source, " - 0.5) * (");
add_arg (glsl_shader_state, pipeline, layer,
add_arg (shader_state, pipeline, layer,
src[1], op[1], "r");
g_string_append (shader_source, " - 0.5) + (");
add_arg (glsl_shader_state, pipeline, layer,
add_arg (shader_state, pipeline, layer,
src[0], op[0], "g");
g_string_append (shader_source, " - 0.5) * (");
add_arg (glsl_shader_state, pipeline, layer,
add_arg (shader_state, pipeline, layer,
src[1], op[1], "g");
g_string_append (shader_source, " - 0.5) + (");
add_arg (glsl_shader_state, pipeline, layer,
add_arg (shader_state, pipeline, layer,
src[0], op[0], "b");
g_string_append (shader_source, " - 0.5) * (");
add_arg (glsl_shader_state, pipeline, layer,
add_arg (shader_state, pipeline, layer,
src[1], op[1], "b");
g_string_append_printf (shader_source, " - 0.5))).%s", swizzle);
break;
@ -637,13 +592,13 @@ _cogl_pipeline_fragend_glsl_add_layer (CoglPipeline *pipeline,
CoglPipelineLayer *layer,
unsigned long layers_difference)
{
GlslShaderState *glsl_shader_state = get_glsl_shader_state (pipeline);
CoglPipelineShaderState *shader_state = get_shader_state (pipeline);
CoglPipelineLayer *combine_authority =
_cogl_pipeline_layer_get_authority (layer,
COGL_PIPELINE_LAYER_STATE_COMBINE);
CoglPipelineLayerBigState *big_state = combine_authority->big_state;
if (!glsl_shader_state->source)
if (!shader_state->source)
return TRUE;
if (!_cogl_pipeline_need_texture_combine_separate (combine_authority) ||
@ -680,12 +635,12 @@ _cogl_pipeline_fragend_glsl_add_layer (CoglPipeline *pipeline,
gboolean
_cogl_pipeline_fragend_glsl_passthrough (CoglPipeline *pipeline)
{
GlslShaderState *glsl_shader_state = get_glsl_shader_state (pipeline);
CoglPipelineShaderState *shader_state = get_shader_state (pipeline);
if (!glsl_shader_state->source)
if (!shader_state->source)
return TRUE;
g_string_append (glsl_shader_state->source,
g_string_append (shader_state->source,
" cogl_color_out = cogl_color_in;\n");
return TRUE;
@ -698,7 +653,7 @@ _cogl_pipeline_fragend_glsl_passthrough (CoglPipeline *pipeline)
static void
add_alpha_test_snippet (CoglPipeline *pipeline,
GlslShaderState *glsl_shader_state)
CoglPipelineShaderState *shader_state)
{
CoglPipelineAlphaFunc alpha_func;
@ -711,7 +666,7 @@ add_alpha_test_snippet (CoglPipeline *pipeline,
if (alpha_func == COGL_PIPELINE_ALPHA_FUNC_NEVER)
{
/* Always discard the fragment */
g_string_append (glsl_shader_state->source,
g_string_append (shader_state->source,
" discard;\n");
return;
}
@ -719,31 +674,31 @@ add_alpha_test_snippet (CoglPipeline *pipeline,
/* For all of the other alpha functions we need a uniform for the
reference */
g_string_append (glsl_shader_state->header,
g_string_append (shader_state->header,
"uniform float _cogl_alpha_test_ref;\n");
g_string_append (glsl_shader_state->source,
g_string_append (shader_state->source,
" if (cogl_color_out.a ");
switch (alpha_func)
{
case COGL_PIPELINE_ALPHA_FUNC_LESS:
g_string_append (glsl_shader_state->source, ">=");
g_string_append (shader_state->source, ">=");
break;
case COGL_PIPELINE_ALPHA_FUNC_EQUAL:
g_string_append (glsl_shader_state->source, "!=");
g_string_append (shader_state->source, "!=");
break;
case COGL_PIPELINE_ALPHA_FUNC_LEQUAL:
g_string_append (glsl_shader_state->source, ">");
g_string_append (shader_state->source, ">");
break;
case COGL_PIPELINE_ALPHA_FUNC_GREATER:
g_string_append (glsl_shader_state->source, "<=");
g_string_append (shader_state->source, "<=");
break;
case COGL_PIPELINE_ALPHA_FUNC_NOTEQUAL:
g_string_append (glsl_shader_state->source, "==");
g_string_append (shader_state->source, "==");
break;
case COGL_PIPELINE_ALPHA_FUNC_GEQUAL:
g_string_append (glsl_shader_state->source, "< ");
g_string_append (shader_state->source, "< ");
break;
case COGL_PIPELINE_ALPHA_FUNC_ALWAYS:
@ -752,7 +707,7 @@ add_alpha_test_snippet (CoglPipeline *pipeline,
break;
}
g_string_append (glsl_shader_state->source,
g_string_append (shader_state->source,
" _cogl_alpha_test_ref)\n discard;\n");
}
@ -762,11 +717,11 @@ gboolean
_cogl_pipeline_fragend_glsl_end (CoglPipeline *pipeline,
unsigned long pipelines_difference)
{
GlslShaderState *glsl_shader_state = get_glsl_shader_state (pipeline);
CoglPipelineShaderState *shader_state = get_shader_state (pipeline);
_COGL_GET_CONTEXT (ctx, FALSE);
if (glsl_shader_state->source)
if (shader_state->source)
{
const char *source_strings[2];
GLint lengths[2];
@ -784,23 +739,23 @@ _cogl_pipeline_fragend_glsl_end (CoglPipeline *pipeline,
#ifdef HAVE_COGL_GLES2
if (ctx->driver == COGL_DRIVER_GLES2)
add_alpha_test_snippet (pipeline, glsl_shader_state);
add_alpha_test_snippet (pipeline, shader_state);
#endif
g_string_append (glsl_shader_state->source, "}\n");
g_string_append (shader_state->source, "}\n");
GE_RET( shader, ctx, glCreateShader (GL_FRAGMENT_SHADER) );
lengths[0] = glsl_shader_state->header->len;
source_strings[0] = glsl_shader_state->header->str;
lengths[1] = glsl_shader_state->source->len;
source_strings[1] = glsl_shader_state->source->str;
lengths[0] = shader_state->header->len;
source_strings[0] = shader_state->header->str;
lengths[1] = shader_state->source->len;
source_strings[1] = shader_state->source->str;
/* Find the highest texture unit that is sampled to pass as the
number of texture coordinate attributes */
n_layers = cogl_pipeline_get_n_layers (pipeline);
for (i = 0; i < n_layers; i++)
if (glsl_shader_state->unit_state[i].sampled)
if (shader_state->unit_state[i].sampled)
n_tex_coord_attribs = i + 1;
_cogl_shader_set_source_with_boilerplate (shader, GL_FRAGMENT_SHADER,
@ -822,9 +777,9 @@ _cogl_pipeline_fragend_glsl_end (CoglPipeline *pipeline,
g_warning ("Shader compilation failed:\n%s", shader_log);
}
glsl_shader_state->header = NULL;
glsl_shader_state->source = NULL;
glsl_shader_state->gl_shader = shader;
shader_state->header = NULL;
shader_state->source = NULL;
shader_state->gl_shader = shader;
}
return TRUE;
@ -838,7 +793,7 @@ _cogl_pipeline_fragend_glsl_pre_change_notify (CoglPipeline *pipeline,
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
if ((change & _cogl_pipeline_get_state_for_fragment_codegen (ctx)))
dirty_glsl_shader_state (pipeline);
dirty_shader_state (pipeline);
}
/* NB: layers are considered immutable once they have any dependants
@ -855,17 +810,11 @@ _cogl_pipeline_fragend_glsl_layer_pre_change_notify (
CoglPipelineLayer *layer,
CoglPipelineLayerState change)
{
CoglPipelineFragendGlslPrivate *priv;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
priv = get_glsl_priv (owner);
if (!priv)
return;
if ((change & _cogl_pipeline_get_layer_state_for_fragment_codegen (ctx)))
{
dirty_glsl_shader_state (owner);
dirty_shader_state (owner);
return;
}
@ -874,19 +823,6 @@ _cogl_pipeline_fragend_glsl_layer_pre_change_notify (
* the snippet. */
}
static void
_cogl_pipeline_fragend_glsl_free_priv (CoglPipeline *pipeline)
{
CoglPipelineFragendGlslPrivate *priv = get_glsl_priv (pipeline);
if (priv)
{
if (priv->glsl_shader_state)
glsl_shader_state_unref (priv->glsl_shader_state);
g_slice_free (CoglPipelineFragendGlslPrivate, priv);
set_glsl_priv (pipeline, NULL);
}
}
const CoglPipelineFragend _cogl_pipeline_glsl_fragend =
{
_cogl_pipeline_fragend_glsl_start,
@ -895,8 +831,7 @@ const CoglPipelineFragend _cogl_pipeline_glsl_fragend =
_cogl_pipeline_fragend_glsl_end,
_cogl_pipeline_fragend_glsl_pre_change_notify,
NULL, /* pipeline_set_parent_notify */
_cogl_pipeline_fragend_glsl_layer_pre_change_notify,
_cogl_pipeline_fragend_glsl_free_priv,
_cogl_pipeline_fragend_glsl_layer_pre_change_notify
};
#endif /* COGL_PIPELINE_FRAGEND_GLSL */

View file

@ -649,10 +649,6 @@ struct _CoglPipeline
* pipeline in comparison to its parent. */
unsigned long differences;
/* The fragment processing backends can associate private data with a
* pipeline. */
void *fragend_privs[COGL_PIPELINE_N_FRAGENDS];
/* Whenever a pipeline is modified we increment the age. There's no
* guarantee that it won't wrap but it can nevertheless be a
* convenient mechanism to determine when a pipeline has been
@ -704,17 +700,6 @@ struct _CoglPipeline
/* bitfields */
/* A pipeline can have private data associated with it for multiple
* fragment processing backends. Although only one backend is
* associated with a pipeline the backends may want to cache private
* state with the ancestors of other pipelines and those ancestors
* could currently be associated with different backends.
*
* Each set bit indicates if the corresponding ->fragend_privs[]
* entry is valid.
*/
unsigned int fragend_priv_set_mask:COGL_PIPELINE_N_FRAGENDS;
/* Weak pipelines don't count as dependants on their parents which
* means that the parent pipeline can be modified without
* considering how the modifications may affect the weak pipeline.
@ -771,8 +756,6 @@ typedef struct _CoglPipelineFragend
void (*layer_pre_change_notify) (CoglPipeline *owner,
CoglPipelineLayer *layer,
CoglPipelineLayerState change);
void (*free_priv) (CoglPipeline *pipeline);
} CoglPipelineFragend;
typedef struct _CoglPipelineVertend

View file

@ -138,14 +138,14 @@ typedef struct
CoglPipeline *last_used_for_pipeline;
UnitState *unit_state;
} CoglPipelineProgendPrivate;
} CoglPipelineProgramState;
static CoglUserDataKey glsl_priv_key;
static CoglUserDataKey program_state_key;
static CoglPipelineProgendPrivate *
get_glsl_priv (CoglPipeline *pipeline)
static CoglPipelineProgramState *
get_program_state (CoglPipeline *pipeline)
{
return cogl_object_get_user_data (COGL_OBJECT (pipeline), &glsl_priv_key);
return cogl_object_get_user_data (COGL_OBJECT (pipeline), &program_state_key);
}
#ifdef HAVE_COGL_GLES2
@ -162,96 +162,101 @@ get_glsl_priv (CoglPipeline *pipeline)
int
_cogl_pipeline_progend_glsl_get_position_attribute (CoglPipeline *pipeline)
{
CoglPipelineProgendPrivate *priv = get_glsl_priv (pipeline);
CoglPipelineProgramState *program_state = get_program_state (pipeline);
_COGL_GET_CONTEXT (ctx, -1);
g_return_val_if_fail (priv != NULL, -1);
g_return_val_if_fail (priv->program != 0, -1);
g_return_val_if_fail (program_state != NULL, -1);
g_return_val_if_fail (program_state->program != 0, -1);
if (priv->position_attribute_location == ATTRIBUTE_LOCATION_UNKNOWN)
GE_RET( priv->position_attribute_location,
ctx, glGetAttribLocation (priv->program, "cogl_position_in") );
if (program_state->position_attribute_location == ATTRIBUTE_LOCATION_UNKNOWN)
GE_RET( program_state->position_attribute_location,
ctx, glGetAttribLocation (program_state->program,
"cogl_position_in") );
return priv->position_attribute_location;
return program_state->position_attribute_location;
}
int
_cogl_pipeline_progend_glsl_get_color_attribute (CoglPipeline *pipeline)
{
CoglPipelineProgendPrivate *priv = get_glsl_priv (pipeline);
CoglPipelineProgramState *program_state = get_program_state (pipeline);
_COGL_GET_CONTEXT (ctx, -1);
g_return_val_if_fail (priv != NULL, -1);
g_return_val_if_fail (priv->program != 0, -1);
g_return_val_if_fail (program_state != NULL, -1);
g_return_val_if_fail (program_state->program != 0, -1);
if (priv->color_attribute_location == ATTRIBUTE_LOCATION_UNKNOWN)
GE_RET( priv->color_attribute_location,
ctx, glGetAttribLocation (priv->program, "cogl_color_in") );
if (program_state->color_attribute_location == ATTRIBUTE_LOCATION_UNKNOWN)
GE_RET( program_state->color_attribute_location,
ctx, glGetAttribLocation (program_state->program,
"cogl_color_in") );
return priv->color_attribute_location;
return program_state->color_attribute_location;
}
int
_cogl_pipeline_progend_glsl_get_normal_attribute (CoglPipeline *pipeline)
{
CoglPipelineProgendPrivate *priv = get_glsl_priv (pipeline);
CoglPipelineProgramState *program_state = get_program_state (pipeline);
_COGL_GET_CONTEXT (ctx, -1);
g_return_val_if_fail (priv != NULL, -1);
g_return_val_if_fail (priv->program != 0, -1);
g_return_val_if_fail (program_state != NULL, -1);
g_return_val_if_fail (program_state->program != 0, -1);
if (priv->normal_attribute_location == ATTRIBUTE_LOCATION_UNKNOWN)
GE_RET( priv->normal_attribute_location,
ctx, glGetAttribLocation (priv->program, "cogl_normal_in") );
if (program_state->normal_attribute_location == ATTRIBUTE_LOCATION_UNKNOWN)
GE_RET( program_state->normal_attribute_location,
ctx, glGetAttribLocation (program_state->program,
"cogl_normal_in") );
return priv->normal_attribute_location;
return program_state->normal_attribute_location;
}
int
_cogl_pipeline_progend_glsl_get_tex_coord_attribute (CoglPipeline *pipeline,
int unit)
{
CoglPipelineProgendPrivate *priv = get_glsl_priv (pipeline);
CoglPipelineProgramState *program_state = get_program_state (pipeline);
_COGL_GET_CONTEXT (ctx, -1);
g_return_val_if_fail (priv != NULL, -1);
g_return_val_if_fail (priv->program != 0, -1);
g_return_val_if_fail (program_state != NULL, -1);
g_return_val_if_fail (program_state->program != 0, -1);
if (unit == 0)
{
if (priv->tex_coord0_attribute_location == ATTRIBUTE_LOCATION_UNKNOWN)
GE_RET( priv->tex_coord0_attribute_location,
ctx, glGetAttribLocation (priv->program,
if (program_state->tex_coord0_attribute_location ==
ATTRIBUTE_LOCATION_UNKNOWN)
GE_RET( program_state->tex_coord0_attribute_location,
ctx, glGetAttribLocation (program_state->program,
"cogl_tex_coord0_in") );
return priv->tex_coord0_attribute_location;
return program_state->tex_coord0_attribute_location;
}
else
{
char *name = g_strdup_printf ("cogl_tex_coord%i_in", unit);
int *locations;
if (priv->tex_coord_attribute_locations == NULL)
priv->tex_coord_attribute_locations = g_array_new (FALSE, FALSE,
sizeof (int));
if (priv->tex_coord_attribute_locations->len <= unit - 1)
if (program_state->tex_coord_attribute_locations == NULL)
program_state->tex_coord_attribute_locations =
g_array_new (FALSE, FALSE, sizeof (int));
if (program_state->tex_coord_attribute_locations->len <= unit - 1)
{
int i = priv->tex_coord_attribute_locations->len;
g_array_set_size (priv->tex_coord_attribute_locations, unit);
int i = program_state->tex_coord_attribute_locations->len;
g_array_set_size (program_state->tex_coord_attribute_locations, unit);
for (; i < unit; i++)
g_array_index (priv->tex_coord_attribute_locations, int, i) =
ATTRIBUTE_LOCATION_UNKNOWN;
g_array_index (program_state->tex_coord_attribute_locations, int, i)
= ATTRIBUTE_LOCATION_UNKNOWN;
}
locations = &g_array_index (priv->tex_coord_attribute_locations, int, 0);
locations = &g_array_index (program_state->tex_coord_attribute_locations,
int, 0);
if (locations[unit - 1] == ATTRIBUTE_LOCATION_UNKNOWN)
GE_RET( locations[unit - 1],
ctx, glGetAttribLocation (priv->program, name) );
ctx, glGetAttribLocation (program_state->program, name) );
g_free (name);
@ -260,79 +265,100 @@ _cogl_pipeline_progend_glsl_get_tex_coord_attribute (CoglPipeline *pipeline,
}
static void
clear_attribute_cache (CoglPipelineProgendPrivate *priv)
clear_attribute_cache (CoglPipelineProgramState *program_state)
{
priv->position_attribute_location = ATTRIBUTE_LOCATION_UNKNOWN;
priv->color_attribute_location = ATTRIBUTE_LOCATION_UNKNOWN;
priv->normal_attribute_location = ATTRIBUTE_LOCATION_UNKNOWN;
priv->tex_coord0_attribute_location = ATTRIBUTE_LOCATION_UNKNOWN;
if (priv->tex_coord_attribute_locations)
program_state->position_attribute_location = ATTRIBUTE_LOCATION_UNKNOWN;
program_state->color_attribute_location = ATTRIBUTE_LOCATION_UNKNOWN;
program_state->normal_attribute_location = ATTRIBUTE_LOCATION_UNKNOWN;
program_state->tex_coord0_attribute_location = ATTRIBUTE_LOCATION_UNKNOWN;
if (program_state->tex_coord_attribute_locations)
{
g_array_free (priv->tex_coord_attribute_locations, TRUE);
priv->tex_coord_attribute_locations = NULL;
g_array_free (program_state->tex_coord_attribute_locations, TRUE);
program_state->tex_coord_attribute_locations = NULL;
}
}
static void
clear_flushed_matrix_stacks (CoglPipelineProgendPrivate *priv)
clear_flushed_matrix_stacks (CoglPipelineProgramState *program_state)
{
if (priv->flushed_modelview_stack)
if (program_state->flushed_modelview_stack)
{
cogl_object_unref (priv->flushed_modelview_stack);
priv->flushed_modelview_stack = NULL;
cogl_object_unref (program_state->flushed_modelview_stack);
program_state->flushed_modelview_stack = NULL;
}
if (priv->flushed_projection_stack)
if (program_state->flushed_projection_stack)
{
cogl_object_unref (priv->flushed_projection_stack);
priv->flushed_projection_stack = NULL;
cogl_object_unref (program_state->flushed_projection_stack);
program_state->flushed_projection_stack = NULL;
}
priv->flushed_modelview_is_identity = FALSE;
program_state->flushed_modelview_is_identity = FALSE;
}
#endif /* HAVE_COGL_GLES2 */
static void
destroy_glsl_priv (void *user_data)
static CoglPipelineProgramState *
program_state_new (int n_layers)
{
CoglPipelineProgendPrivate *priv = user_data;
CoglPipelineProgramState *program_state;
program_state = g_slice_new (CoglPipelineProgramState);
program_state->ref_count = 1;
program_state->program = 0;
program_state->n_tex_coord_attribs = 0;
program_state->unit_state = g_new (UnitState, n_layers);
#ifdef HAVE_COGL_GLES2
program_state->tex_coord_attribute_locations = NULL;
program_state->flushed_modelview_stack = NULL;
program_state->flushed_modelview_is_identity = FALSE;
program_state->flushed_projection_stack = NULL;
#endif
return program_state;
}
static void
destroy_program_state (void *user_data)
{
CoglPipelineProgramState *program_state = user_data;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
if (--priv->ref_count == 0)
if (--program_state->ref_count == 0)
{
#ifdef HAVE_COGL_GLES2
if (ctx->driver == COGL_DRIVER_GLES2)
{
clear_attribute_cache (priv);
clear_flushed_matrix_stacks (priv);
clear_attribute_cache (program_state);
clear_flushed_matrix_stacks (program_state);
}
#endif
if (priv->program)
GE( ctx, glDeleteProgram (priv->program) );
if (program_state->program)
GE( ctx, glDeleteProgram (program_state->program) );
g_free (priv->unit_state);
g_free (program_state->unit_state);
g_slice_free (CoglPipelineProgendPrivate, priv);
g_slice_free (CoglPipelineProgramState, program_state);
}
}
static void
set_glsl_priv (CoglPipeline *pipeline, CoglPipelineProgendPrivate *priv)
set_program_state (CoglPipeline *pipeline,
CoglPipelineProgramState *program_state)
{
cogl_object_set_user_data (COGL_OBJECT (pipeline),
&glsl_priv_key,
priv,
destroy_glsl_priv);
&program_state_key,
program_state,
destroy_program_state);
}
static void
dirty_glsl_program_state (CoglPipeline *pipeline)
dirty_program_state (CoglPipeline *pipeline)
{
cogl_object_set_user_data (COGL_OBJECT (pipeline),
&glsl_priv_key,
&program_state_key,
NULL,
destroy_glsl_priv);
NULL);
}
static void
@ -371,7 +397,7 @@ typedef struct
int unit;
GLuint gl_program;
gboolean update_all;
CoglPipelineProgendPrivate *priv;
CoglPipelineProgramState *program_state;
} UpdateUniformsState;
static gboolean
@ -380,8 +406,8 @@ get_uniform_cb (CoglPipeline *pipeline,
void *user_data)
{
UpdateUniformsState *state = user_data;
CoglPipelineProgendPrivate *priv = state->priv;
UnitState *unit_state = &priv->unit_state[state->unit];
CoglPipelineProgramState *program_state = state->program_state;
UnitState *unit_state = &program_state->unit_state[state->unit];
GLint uniform_location;
_COGL_GET_CONTEXT (ctx, FALSE);
@ -439,8 +465,8 @@ update_constants_cb (CoglPipeline *pipeline,
void *user_data)
{
UpdateUniformsState *state = user_data;
CoglPipelineProgendPrivate *priv = state->priv;
UnitState *unit_state = &priv->unit_state[state->unit++];
CoglPipelineProgramState *program_state = state->program_state;
UnitState *unit_state = &program_state->unit_state[state->unit++];
_COGL_GET_CONTEXT (ctx, FALSE);
@ -482,21 +508,22 @@ update_constants_cb (CoglPipeline *pipeline,
static void
update_builtin_uniforms (CoglPipeline *pipeline,
GLuint gl_program,
CoglPipelineProgendPrivate *priv)
CoglPipelineProgramState *program_state)
{
int i;
if (priv->dirty_builtin_uniforms == 0)
if (program_state->dirty_builtin_uniforms == 0)
return;
for (i = 0; i < G_N_ELEMENTS (builtin_uniforms); i++)
if ((priv->dirty_builtin_uniforms & (1 << i)) &&
priv->builtin_uniform_locations[i] != -1)
if ((program_state->dirty_builtin_uniforms & (1 << i)) &&
program_state->builtin_uniform_locations[i] != -1)
builtin_uniforms[i].update_func (pipeline,
priv->builtin_uniform_locations[i],
program_state
->builtin_uniform_locations[i],
builtin_uniforms[i].getter_func);
priv->dirty_builtin_uniforms = 0;
program_state->dirty_builtin_uniforms = 0;
}
#endif /* HAVE_COGL_GLES2 */
@ -506,7 +533,7 @@ _cogl_pipeline_progend_glsl_end (CoglPipeline *pipeline,
unsigned long pipelines_difference,
int n_tex_coord_attribs)
{
CoglPipelineProgendPrivate *priv;
CoglPipelineProgramState *program_state;
GLuint gl_program;
gboolean program_changed = FALSE;
UpdateUniformsState state;
@ -520,11 +547,11 @@ _cogl_pipeline_progend_glsl_end (CoglPipeline *pipeline,
pipeline->vertend != COGL_PIPELINE_VERTEND_GLSL)
return;
priv = get_glsl_priv (pipeline);
program_state = get_program_state (pipeline);
user_program = cogl_pipeline_get_user_program (pipeline);
if (priv == NULL)
if (program_state == NULL)
{
CoglPipeline *authority;
@ -539,29 +566,19 @@ _cogl_pipeline_progend_glsl_end (CoglPipeline *pipeline,
_cogl_pipeline_get_layer_state_for_fragment_codegen (ctx) |
COGL_PIPELINE_LAYER_STATE_AFFECTS_VERTEX_CODEGEN);
priv = get_glsl_priv (authority);
program_state = get_program_state (authority);
if (priv == NULL)
if (program_state == NULL)
{
priv = g_slice_new (CoglPipelineProgendPrivate);
priv->ref_count = 1;
priv->program = 0;
priv->n_tex_coord_attribs = 0;
priv->unit_state = g_new (UnitState,
cogl_pipeline_get_n_layers (pipeline));
#ifdef HAVE_COGL_GLES2
priv->tex_coord_attribute_locations = NULL;
priv->flushed_modelview_stack = NULL;
priv->flushed_modelview_is_identity = FALSE;
priv->flushed_projection_stack = NULL;
#endif
set_glsl_priv (authority, priv);
program_state
= program_state_new (cogl_pipeline_get_n_layers (pipeline));
set_program_state (authority, program_state);
}
if (authority != pipeline)
{
priv->ref_count++;
set_glsl_priv (pipeline, priv);
program_state->ref_count++;
set_program_state (pipeline, program_state);
}
}
@ -571,26 +588,26 @@ _cogl_pipeline_progend_glsl_end (CoglPipeline *pipeline,
* Also if the number of texture coordinate attributes in use has
* increased, then delete the program so we can prepend a new
* _cogl_tex_coord[] varying array declaration. */
if (priv->program && user_program &&
(user_program->age != priv->user_program_age ||
n_tex_coord_attribs > priv->n_tex_coord_attribs))
if (program_state->program && user_program &&
(user_program->age != program_state->user_program_age ||
n_tex_coord_attribs > program_state->n_tex_coord_attribs))
{
GE( ctx, glDeleteProgram (priv->program) );
priv->program = 0;
GE( ctx, glDeleteProgram (program_state->program) );
program_state->program = 0;
}
if (priv->program == 0)
if (program_state->program == 0)
{
GLuint backend_shader;
GSList *l;
GE_RET( priv->program, ctx, glCreateProgram () );
GE_RET( program_state->program, ctx, glCreateProgram () );
/* Attach all of the shader from the user program */
if (user_program)
{
if (priv->n_tex_coord_attribs > n_tex_coord_attribs)
n_tex_coord_attribs = priv->n_tex_coord_attribs;
if (program_state->n_tex_coord_attribs > n_tex_coord_attribs)
n_tex_coord_attribs = program_state->n_tex_coord_attribs;
#ifdef HAVE_COGL_GLES2
/* Find the largest count of texture coordinate attributes
@ -614,29 +631,29 @@ _cogl_pipeline_progend_glsl_end (CoglPipeline *pipeline,
g_assert (shader->language == COGL_SHADER_LANGUAGE_GLSL);
GE( ctx, glAttachShader (priv->program,
GE( ctx, glAttachShader (program_state->program,
shader->gl_handle) );
}
priv->user_program_age = user_program->age;
program_state->user_program_age = user_program->age;
}
/* Attach any shaders from the GLSL backends */
if (pipeline->fragend == COGL_PIPELINE_FRAGEND_GLSL &&
(backend_shader = _cogl_pipeline_fragend_glsl_get_shader (pipeline)))
GE( ctx, glAttachShader (priv->program, backend_shader) );
GE( ctx, glAttachShader (program_state->program, backend_shader) );
if (pipeline->vertend == COGL_PIPELINE_VERTEND_GLSL &&
(backend_shader = _cogl_pipeline_vertend_glsl_get_shader (pipeline)))
GE( ctx, glAttachShader (priv->program, backend_shader) );
GE( ctx, glAttachShader (program_state->program, backend_shader) );
link_program (priv->program);
link_program (program_state->program);
program_changed = TRUE;
priv->n_tex_coord_attribs = n_tex_coord_attribs;
program_state->n_tex_coord_attribs = n_tex_coord_attribs;
}
gl_program = priv->program;
gl_program = program_state->program;
if (pipeline->fragend == COGL_PIPELINE_FRAGEND_GLSL)
_cogl_use_fragment_program (gl_program, COGL_PIPELINE_PROGRAM_TYPE_GLSL);
@ -645,7 +662,7 @@ _cogl_pipeline_progend_glsl_end (CoglPipeline *pipeline,
state.unit = 0;
state.gl_program = gl_program;
state.priv = priv;
state.program_state = program_state;
if (program_changed)
cogl_pipeline_foreach_layer (pipeline,
@ -654,7 +671,7 @@ _cogl_pipeline_progend_glsl_end (CoglPipeline *pipeline,
state.unit = 0;
state.update_all = (program_changed ||
priv->last_used_for_pipeline != pipeline);
program_state->last_used_for_pipeline != pipeline);
cogl_pipeline_foreach_layer (pipeline,
update_constants_cb,
@ -667,33 +684,31 @@ _cogl_pipeline_progend_glsl_end (CoglPipeline *pipeline,
{
int i;
clear_attribute_cache (priv);
clear_flushed_matrix_stacks (priv);
clear_attribute_cache (program_state);
clear_flushed_matrix_stacks (program_state);
for (i = 0; i < G_N_ELEMENTS (builtin_uniforms); i++)
GE_RET( priv->builtin_uniform_locations[i],
ctx,
GE_RET( program_state->builtin_uniform_locations[i], ctx,
glGetUniformLocation (gl_program,
builtin_uniforms[i].uniform_name) );
GE_RET( priv->modelview_uniform,
ctx, glGetUniformLocation (gl_program,
"cogl_modelview_matrix") );
GE_RET( program_state->modelview_uniform, ctx,
glGetUniformLocation (gl_program,
"cogl_modelview_matrix") );
GE_RET( priv->projection_uniform,
ctx, glGetUniformLocation (gl_program,
"cogl_projection_matrix") );
GE_RET( program_state->projection_uniform, ctx,
glGetUniformLocation (gl_program,
"cogl_projection_matrix") );
GE_RET( priv->mvp_uniform,
ctx,
GE_RET( program_state->mvp_uniform, ctx,
glGetUniformLocation (gl_program,
"cogl_modelview_projection_matrix") );
}
if (program_changed ||
priv->last_used_for_pipeline != pipeline)
priv->dirty_builtin_uniforms = ~(unsigned long) 0;
program_state->last_used_for_pipeline != pipeline)
program_state->dirty_builtin_uniforms = ~(unsigned long) 0;
update_builtin_uniforms (pipeline, gl_program, priv);
update_builtin_uniforms (pipeline, gl_program, program_state);
}
#endif
@ -704,7 +719,7 @@ _cogl_pipeline_progend_glsl_end (CoglPipeline *pipeline,
/* We need to track the last pipeline that the program was used with
* so know if we need to update all of the uniforms */
priv->last_used_for_pipeline = pipeline;
program_state->last_used_for_pipeline = pipeline;
}
static void
@ -715,7 +730,8 @@ _cogl_pipeline_progend_glsl_pre_change_notify (CoglPipeline *pipeline,
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
if ((change & _cogl_pipeline_get_state_for_fragment_codegen (ctx)))
dirty_glsl_program_state (pipeline);
dirty_program_state (pipeline);
#ifdef HAVE_COGL_GLES2
else if (ctx->driver == COGL_DRIVER_GLES2)
{
@ -724,9 +740,10 @@ _cogl_pipeline_progend_glsl_pre_change_notify (CoglPipeline *pipeline,
for (i = 0; i < G_N_ELEMENTS (builtin_uniforms); i++)
if ((change & builtin_uniforms[i].change))
{
CoglPipelineProgendPrivate *priv = get_glsl_priv (pipeline);
if (priv)
priv->dirty_builtin_uniforms |= 1 << i;
CoglPipelineProgramState *program_state
= get_program_state (pipeline);
if (program_state)
program_state->dirty_builtin_uniforms |= 1 << i;
return;
}
}
@ -751,27 +768,27 @@ _cogl_pipeline_progend_glsl_layer_pre_change_notify (
if ((change & _cogl_pipeline_get_state_for_fragment_codegen (ctx)))
{
dirty_glsl_program_state (owner);
dirty_program_state (owner);
return;
}
if (change & COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT)
{
CoglPipelineProgendPrivate *priv = get_glsl_priv (owner);
if (priv)
CoglPipelineProgramState *program_state = get_program_state (owner);
if (program_state)
{
int unit_index = _cogl_pipeline_layer_get_unit_index (layer);
priv->unit_state[unit_index].dirty_combine_constant = TRUE;
program_state->unit_state[unit_index].dirty_combine_constant = TRUE;
}
}
if (change & COGL_PIPELINE_LAYER_STATE_USER_MATRIX)
{
CoglPipelineProgendPrivate *priv = get_glsl_priv (owner);
if (priv)
CoglPipelineProgramState *program_state = get_program_state (owner);
if (program_state)
{
int unit_index = _cogl_pipeline_layer_get_unit_index (layer);
priv->unit_state[unit_index].dirty_texture_matrix = TRUE;
program_state->unit_state[unit_index].dirty_texture_matrix = TRUE;
}
}
}
@ -783,11 +800,11 @@ flush_modelview_cb (gboolean is_identity,
const CoglMatrix *matrix,
void *user_data)
{
CoglPipelineProgendPrivate *priv = user_data;
CoglPipelineProgramState *program_state = user_data;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
GE( ctx, glUniformMatrix4fv (priv->modelview_uniform, 1, FALSE,
GE( ctx, glUniformMatrix4fv (program_state->modelview_uniform, 1, FALSE,
cogl_matrix_get_array (matrix)) );
}
@ -796,17 +813,17 @@ flush_projection_cb (gboolean is_identity,
const CoglMatrix *matrix,
void *user_data)
{
CoglPipelineProgendPrivate *priv = user_data;
CoglPipelineProgramState *program_state = user_data;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
GE( ctx, glUniformMatrix4fv (priv->projection_uniform, 1, FALSE,
GE( ctx, glUniformMatrix4fv (program_state->projection_uniform, 1, FALSE,
cogl_matrix_get_array (matrix)) );
}
typedef struct
{
CoglPipelineProgendPrivate *priv;
CoglPipelineProgramState *program_state;
const CoglMatrix *projection_matrix;
} FlushCombinedData;
@ -825,7 +842,8 @@ flush_combined_step_two_cb (gboolean is_identity,
if (is_identity)
{
const float *array = cogl_matrix_get_array (data->projection_matrix);
GE( ctx, glUniformMatrix4fv (data->priv->mvp_uniform, 1, FALSE, array ) );
GE( ctx, glUniformMatrix4fv (data->program_state->mvp_uniform,
1, FALSE, array ) );
}
else
{
@ -833,7 +851,7 @@ flush_combined_step_two_cb (gboolean is_identity,
data->projection_matrix,
matrix);
GE( ctx, glUniformMatrix4fv (data->priv->mvp_uniform, 1, FALSE,
GE( ctx, glUniformMatrix4fv (data->program_state->mvp_uniform, 1, FALSE,
cogl_matrix_get_array (&mvp_matrix)) );
}
}
@ -847,7 +865,7 @@ flush_combined_step_one_cb (gboolean is_identity,
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
data.priv = user_data;
data.program_state = user_data;
data.projection_matrix = matrix;
_cogl_matrix_stack_prepare_for_flush (ctx->flushed_modelview_stack,
@ -859,7 +877,7 @@ flush_combined_step_one_cb (gboolean is_identity,
static void
_cogl_pipeline_progend_glsl_pre_paint (CoglPipeline *pipeline)
{
CoglPipelineProgendPrivate *priv = get_glsl_priv (pipeline);
CoglPipelineProgramState *program_state = get_program_state (pipeline);
gboolean modelview_changed;
gboolean projection_changed;
@ -872,7 +890,7 @@ _cogl_pipeline_progend_glsl_pre_paint (CoglPipeline *pipeline)
vertend, but this is a requirement on GLES2 anyway */
g_return_if_fail (pipeline->vertend == COGL_PIPELINE_VERTEND_GLSL);
priv = get_glsl_priv (pipeline);
program_state = get_program_state (pipeline);
/* An initial pipeline is flushed while creating the context. At
this point there are no matrices flushed so we can't do
@ -885,59 +903,62 @@ _cogl_pipeline_progend_glsl_pre_paint (CoglPipeline *pipeline)
the identity matrix so it makes sense to optimise this case by
specifically checking whether we already have the identity matrix
which will catch a lot of common cases of redundant flushing */
if (priv->flushed_modelview_is_identity &&
if (program_state->flushed_modelview_is_identity &&
_cogl_matrix_stack_has_identity_flag (ctx->flushed_modelview_stack))
modelview_changed = FALSE;
else
modelview_changed =
priv->flushed_modelview_stack != ctx->flushed_modelview_stack ||
priv->flushed_modelview_stack_age !=
_cogl_matrix_stack_get_age (priv->flushed_modelview_stack);
program_state->flushed_modelview_stack != ctx->flushed_modelview_stack ||
program_state->flushed_modelview_stack_age !=
_cogl_matrix_stack_get_age (program_state->flushed_modelview_stack);
projection_changed =
priv->flushed_projection_stack != ctx->flushed_projection_stack ||
priv->flushed_projection_stack_age !=
_cogl_matrix_stack_get_age (priv->flushed_projection_stack);
program_state->flushed_projection_stack != ctx->flushed_projection_stack ||
program_state->flushed_projection_stack_age !=
_cogl_matrix_stack_get_age (program_state->flushed_projection_stack);
if (modelview_changed)
{
cogl_object_ref (ctx->flushed_modelview_stack);
if (priv->flushed_modelview_stack)
cogl_object_unref (priv->flushed_modelview_stack);
priv->flushed_modelview_stack = ctx->flushed_modelview_stack;
priv->flushed_modelview_stack_age =
if (program_state->flushed_modelview_stack)
cogl_object_unref (program_state->flushed_modelview_stack);
program_state->flushed_modelview_stack = ctx->flushed_modelview_stack;
program_state->flushed_modelview_stack_age =
_cogl_matrix_stack_get_age (ctx->flushed_modelview_stack);
priv->flushed_modelview_is_identity =
program_state->flushed_modelview_is_identity =
_cogl_matrix_stack_has_identity_flag (ctx->flushed_modelview_stack);
if (priv->modelview_uniform != -1)
_cogl_matrix_stack_prepare_for_flush (priv->flushed_modelview_stack,
if (program_state->modelview_uniform != -1)
_cogl_matrix_stack_prepare_for_flush (program_state
->flushed_modelview_stack,
COGL_MATRIX_MODELVIEW,
flush_modelview_cb,
priv);
program_state);
}
if (projection_changed)
{
cogl_object_ref (ctx->flushed_projection_stack);
if (priv->flushed_projection_stack)
cogl_object_unref (priv->flushed_projection_stack);
priv->flushed_projection_stack = ctx->flushed_projection_stack;
priv->flushed_projection_stack_age =
if (program_state->flushed_projection_stack)
cogl_object_unref (program_state->flushed_projection_stack);
program_state->flushed_projection_stack = ctx->flushed_projection_stack;
program_state->flushed_projection_stack_age =
_cogl_matrix_stack_get_age (ctx->flushed_projection_stack);
if (priv->projection_uniform != -1)
_cogl_matrix_stack_prepare_for_flush (priv->flushed_projection_stack,
if (program_state->projection_uniform != -1)
_cogl_matrix_stack_prepare_for_flush (program_state
->flushed_projection_stack,
COGL_MATRIX_PROJECTION,
flush_projection_cb,
priv);
program_state);
}
if (priv->mvp_uniform != -1 && (modelview_changed || projection_changed))
if (program_state->mvp_uniform != -1 &&
(modelview_changed || projection_changed))
_cogl_matrix_stack_prepare_for_flush (ctx->flushed_projection_stack,
COGL_MATRIX_PROJECTION,
flush_combined_step_one_cb,
priv);
program_state);
}
static void

View file

@ -55,57 +55,69 @@ typedef struct
program changes then we may need to redecide whether to generate
a shader at all */
unsigned int user_program_age;
} CoglPipelineVertendPrivate;
} CoglPipelineShaderState;
static CoglUserDataKey glsl_priv_key;
static CoglUserDataKey shader_state_key;
static CoglPipelineVertendPrivate *
get_glsl_priv (CoglPipeline *pipeline)
static CoglPipelineShaderState *
shader_state_new (void)
{
return cogl_object_get_user_data (COGL_OBJECT (pipeline), &glsl_priv_key);
CoglPipelineShaderState *shader_state;
shader_state = g_slice_new0 (CoglPipelineShaderState);
shader_state->ref_count = 1;
return shader_state;
}
static CoglPipelineShaderState *
get_shader_state (CoglPipeline *pipeline)
{
return cogl_object_get_user_data (COGL_OBJECT (pipeline), &shader_state_key);
}
static void
destroy_glsl_priv (void *user_data)
destroy_shader_state (void *user_data)
{
CoglPipelineVertendPrivate *priv = user_data;
CoglPipelineShaderState *shader_state = user_data;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
if (--priv->ref_count == 0)
if (--shader_state->ref_count == 0)
{
if (priv->gl_shader)
GE( ctx, glDeleteShader (priv->gl_shader) );
if (shader_state->gl_shader)
GE( ctx, glDeleteShader (shader_state->gl_shader) );
g_slice_free (CoglPipelineVertendPrivate, priv);
g_slice_free (CoglPipelineShaderState, shader_state);
}
}
static void
set_glsl_priv (CoglPipeline *pipeline, CoglPipelineVertendPrivate *priv)
set_shader_state (CoglPipeline *pipeline,
CoglPipelineShaderState *shader_state)
{
cogl_object_set_user_data (COGL_OBJECT (pipeline),
&glsl_priv_key,
priv,
destroy_glsl_priv);
&shader_state_key,
shader_state,
destroy_shader_state);
}
static void
dirty_glsl_shader_state (CoglPipeline *pipeline)
dirty_shader_state (CoglPipeline *pipeline)
{
cogl_object_set_user_data (COGL_OBJECT (pipeline),
&glsl_priv_key,
&shader_state_key,
NULL,
destroy_glsl_priv);
NULL);
}
GLuint
_cogl_pipeline_vertend_glsl_get_shader (CoglPipeline *pipeline)
{
CoglPipelineVertendPrivate *priv = get_glsl_priv (pipeline);
CoglPipelineShaderState *shader_state = get_shader_state (pipeline);
if (priv)
return priv->gl_shader;
if (shader_state)
return shader_state->gl_shader;
else
return 0;
}
@ -115,7 +127,7 @@ _cogl_pipeline_vertend_glsl_start (CoglPipeline *pipeline,
int n_layers,
unsigned long pipelines_difference)
{
CoglPipelineVertendPrivate *priv;
CoglPipelineShaderState *shader_state;
CoglProgram *user_program;
_COGL_GET_CONTEXT (ctx, FALSE);
@ -134,9 +146,9 @@ _cogl_pipeline_vertend_glsl_start (CoglPipeline *pipeline,
/* Now lookup our glsl backend private state (allocating if
* necessary) */
priv = get_glsl_priv (pipeline);
shader_state = get_shader_state (pipeline);
if (priv == NULL)
if (shader_state == NULL)
{
CoglPipeline *authority;
@ -148,42 +160,41 @@ _cogl_pipeline_vertend_glsl_start (CoglPipeline *pipeline,
~COGL_PIPELINE_STATE_LAYERS,
COGL_PIPELINE_LAYER_STATE_AFFECTS_VERTEX_CODEGEN);
priv = get_glsl_priv (authority);
shader_state = get_shader_state (authority);
if (priv == NULL)
if (shader_state == NULL)
{
priv = g_slice_new0 (CoglPipelineVertendPrivate);
priv->ref_count = 1;
set_glsl_priv (authority, priv);
shader_state = shader_state_new ();
set_shader_state (authority, shader_state);
}
if (authority != pipeline)
{
priv->ref_count++;
set_glsl_priv (pipeline, priv);
shader_state->ref_count++;
set_shader_state (pipeline, shader_state);
}
}
if (priv->gl_shader)
if (shader_state->gl_shader)
{
/* If we already have a valid GLSL shader then we don't need to
generate a new one. However if there's a user program and it
has changed since the last link then we do need a new shader */
if (user_program == NULL ||
priv->user_program_age == user_program->age)
shader_state->user_program_age == user_program->age)
return TRUE;
/* We need to recreate the shader so destroy the existing one */
GE( ctx, glDeleteShader (priv->gl_shader) );
priv->gl_shader = 0;
GE( ctx, glDeleteShader (shader_state->gl_shader) );
shader_state->gl_shader = 0;
}
/* If we make it here then we have a priv struct without a gl_shader
/* If we make it here then we have a shader_state struct without a gl_shader
either because this is the first time we've encountered it or
because the user program has changed */
if (user_program)
priv->user_program_age = user_program->age;
shader_state->user_program_age = user_program->age;
/* If the user program contains a vertex shader then we don't need
to generate one */
@ -198,10 +209,10 @@ _cogl_pipeline_vertend_glsl_start (CoglPipeline *pipeline,
add_layer callback is invoked */
g_string_set_size (ctx->codegen_header_buffer, 0);
g_string_set_size (ctx->codegen_source_buffer, 0);
priv->header = ctx->codegen_header_buffer;
priv->source = ctx->codegen_source_buffer;
shader_state->header = ctx->codegen_header_buffer;
shader_state->source = ctx->codegen_source_buffer;
g_string_append (priv->source,
g_string_append (shader_state->source,
"void\n"
"main ()\n"
"{\n");
@ -209,7 +220,7 @@ _cogl_pipeline_vertend_glsl_start (CoglPipeline *pipeline,
if (ctx->driver == COGL_DRIVER_GLES2)
/* There is no builtin uniform for the pointsize on GLES2 so we need
to copy it from the custom uniform in the vertex shader */
g_string_append (priv->source,
g_string_append (shader_state->source,
" cogl_point_size_out = cogl_point_size_in;\n");
/* On regular OpenGL we'll just flush the point size builtin */
else if (pipelines_difference & COGL_PIPELINE_STATE_POINT_SIZE)
@ -232,12 +243,12 @@ _cogl_pipeline_vertend_glsl_add_layer (CoglPipeline *pipeline,
CoglPipelineLayer *layer,
unsigned long layers_difference)
{
CoglPipelineVertendPrivate *priv;
CoglPipelineShaderState *shader_state;
int unit_index;
_COGL_GET_CONTEXT (ctx, FALSE);
priv = get_glsl_priv (pipeline);
shader_state = get_shader_state (pipeline);
unit_index = _cogl_pipeline_layer_get_unit_index (layer);
@ -263,7 +274,7 @@ _cogl_pipeline_vertend_glsl_add_layer (CoglPipeline *pipeline,
}
}
if (priv->source == NULL)
if (shader_state->source == NULL)
return TRUE;
/* Transform the texture coordinates by the layer's user matrix.
@ -277,7 +288,7 @@ _cogl_pipeline_vertend_glsl_add_layer (CoglPipeline *pipeline,
* avoid setting them if not
*/
g_string_append_printf (priv->source,
g_string_append_printf (shader_state->source,
" cogl_tex_coord_out[%i] = "
"cogl_texture_matrix[%i] * cogl_tex_coord%i_in;\n",
unit_index, unit_index, unit_index);
@ -289,13 +300,13 @@ static gboolean
_cogl_pipeline_vertend_glsl_end (CoglPipeline *pipeline,
unsigned long pipelines_difference)
{
CoglPipelineVertendPrivate *priv;
CoglPipelineShaderState *shader_state;
_COGL_GET_CONTEXT (ctx, FALSE);
priv = get_glsl_priv (pipeline);
shader_state = get_shader_state (pipeline);
if (priv->source)
if (shader_state->source)
{
const char *source_strings[2];
GLint lengths[2];
@ -310,7 +321,7 @@ _cogl_pipeline_vertend_glsl_end (CoglPipeline *pipeline,
0 /* no application private data */);
COGL_COUNTER_INC (_cogl_uprof_context, vertend_glsl_compile_counter);
g_string_append (priv->source,
g_string_append (shader_state->source,
" cogl_position_out = "
"cogl_modelview_projection_matrix * "
"cogl_position_in;\n"
@ -319,10 +330,10 @@ _cogl_pipeline_vertend_glsl_end (CoglPipeline *pipeline,
GE_RET( shader, ctx, glCreateShader (GL_VERTEX_SHADER) );
lengths[0] = priv->header->len;
source_strings[0] = priv->header->str;
lengths[1] = priv->source->len;
source_strings[1] = priv->source->str;
lengths[0] = shader_state->header->len;
source_strings[0] = shader_state->header->str;
lengths[1] = shader_state->source->len;
source_strings[1] = shader_state->source->str;
n_layers = cogl_pipeline_get_n_layers (pipeline);
@ -345,9 +356,9 @@ _cogl_pipeline_vertend_glsl_end (CoglPipeline *pipeline,
g_warning ("Shader compilation failed:\n%s", shader_log);
}
priv->header = NULL;
priv->source = NULL;
priv->gl_shader = shader;
shader_state->header = NULL;
shader_state->source = NULL;
shader_state->gl_shader = shader;
}
return TRUE;
@ -359,7 +370,7 @@ _cogl_pipeline_vertend_glsl_pre_change_notify (CoglPipeline *pipeline,
const CoglColor *new_color)
{
if ((change & COGL_PIPELINE_STATE_AFFECTS_VERTEX_CODEGEN))
dirty_glsl_shader_state (pipeline);
dirty_shader_state (pipeline);
}
/* NB: layers are considered immutable once they have any dependants
@ -376,15 +387,15 @@ _cogl_pipeline_vertend_glsl_layer_pre_change_notify (
CoglPipelineLayer *layer,
CoglPipelineLayerState change)
{
CoglPipelineVertendPrivate *priv;
CoglPipelineShaderState *shader_state;
priv = get_glsl_priv (owner);
if (!priv)
shader_state = get_shader_state (owner);
if (!shader_state)
return;
if ((change & COGL_PIPELINE_LAYER_STATE_AFFECTS_VERTEX_CODEGEN))
{
dirty_glsl_shader_state (owner);
dirty_shader_state (owner);
return;
}

View file

@ -448,7 +448,6 @@ _cogl_pipeline_copy (CoglPipeline *src, gboolean is_weak)
pipeline->deprecated_get_layers_list_dirty = TRUE;
pipeline->fragend = src->fragend;
pipeline->fragend_priv_set_mask = 0;
pipeline->vertend = src->vertend;
@ -501,18 +500,6 @@ cogl_pipeline_new (void)
return new;
}
static void
_cogl_pipeline_fragend_free_priv (CoglPipeline *pipeline)
{
if (pipeline->fragend != COGL_PIPELINE_FRAGEND_UNDEFINED &&
_cogl_pipeline_fragends[pipeline->fragend]->free_priv)
{
const CoglPipelineFragend *fragend =
_cogl_pipeline_fragends[pipeline->fragend];
fragend->free_priv (pipeline);
}
}
static gboolean
destroy_weak_children_cb (CoglPipelineNode *node,
void *user_data)
@ -545,8 +532,6 @@ _cogl_pipeline_free (CoglPipeline *pipeline)
g_assert (COGL_LIST_EMPTY (&COGL_PIPELINE_NODE (pipeline)->children));
_cogl_pipeline_fragend_free_priv (pipeline);
_cogl_pipeline_unparent (COGL_PIPELINE_NODE (pipeline));
if (pipeline->differences & COGL_PIPELINE_STATE_USER_SHADER &&
@ -970,7 +955,6 @@ _cogl_pipeline_needs_blending_enabled (CoglPipeline *pipeline,
void
_cogl_pipeline_set_fragend (CoglPipeline *pipeline, int fragend)
{
_cogl_pipeline_fragend_free_priv (pipeline);
pipeline->fragend = fragend;
}