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

View File

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

View File

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

View File

@ -649,10 +649,6 @@ struct _CoglPipeline
* pipeline in comparison to its parent. */ * pipeline in comparison to its parent. */
unsigned long differences; 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 /* Whenever a pipeline is modified we increment the age. There's no
* guarantee that it won't wrap but it can nevertheless be a * guarantee that it won't wrap but it can nevertheless be a
* convenient mechanism to determine when a pipeline has been * convenient mechanism to determine when a pipeline has been
@ -704,17 +700,6 @@ struct _CoglPipeline
/* bitfields */ /* 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 /* Weak pipelines don't count as dependants on their parents which
* means that the parent pipeline can be modified without * means that the parent pipeline can be modified without
* considering how the modifications may affect the weak pipeline. * considering how the modifications may affect the weak pipeline.
@ -771,8 +756,6 @@ typedef struct _CoglPipelineFragend
void (*layer_pre_change_notify) (CoglPipeline *owner, void (*layer_pre_change_notify) (CoglPipeline *owner,
CoglPipelineLayer *layer, CoglPipelineLayer *layer,
CoglPipelineLayerState change); CoglPipelineLayerState change);
void (*free_priv) (CoglPipeline *pipeline);
} CoglPipelineFragend; } CoglPipelineFragend;
typedef struct _CoglPipelineVertend typedef struct _CoglPipelineVertend

View File

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

View File

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

View File

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