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:
parent
221850eca9
commit
d69d49fada
7 changed files with 585 additions and 716 deletions
|
@ -55,6 +55,8 @@
|
|||
#define GL_TEXTURE_3D 0x806F
|
||||
#endif
|
||||
|
||||
const CoglPipelineFragend _cogl_pipeline_arbfp_fragend;
|
||||
|
||||
typedef struct _UnitState
|
||||
{
|
||||
int constant_id; /* The program.local[] index */
|
||||
|
@ -63,7 +65,7 @@ typedef struct _UnitState
|
|||
unsigned int sampled:1;
|
||||
} UnitState;
|
||||
|
||||
typedef struct _ArbfpProgramState
|
||||
typedef struct
|
||||
{
|
||||
int ref_count;
|
||||
|
||||
|
@ -84,82 +86,65 @@ typedef struct _ArbfpProgramState
|
|||
/* We need to track the last pipeline that an ARBfp program was used
|
||||
* with so know if we need to update any program.local parameters. */
|
||||
CoglPipeline *last_used_for_pipeline;
|
||||
} ArbfpProgramState;
|
||||
} CoglPipelineShaderState;
|
||||
|
||||
typedef struct _CoglPipelineFragendARBfpPrivate
|
||||
static CoglUserDataKey shader_state_key;
|
||||
|
||||
static CoglPipelineShaderState *
|
||||
shader_state_new (int n_layers)
|
||||
{
|
||||
ArbfpProgramState *arbfp_program_state;
|
||||
} CoglPipelineFragendARBfpPrivate;
|
||||
CoglPipelineShaderState *shader_state;
|
||||
|
||||
const CoglPipelineFragend _cogl_pipeline_arbfp_fragend;
|
||||
shader_state = g_slice_new0 (CoglPipelineShaderState);
|
||||
shader_state->ref_count = 1;
|
||||
shader_state->unit_state = g_new0 (UnitState, n_layers);
|
||||
|
||||
|
||||
static ArbfpProgramState *
|
||||
arbfp_program_state_new (int n_layers)
|
||||
{
|
||||
ArbfpProgramState *state = g_slice_new0 (ArbfpProgramState);
|
||||
state->ref_count = 1;
|
||||
state->unit_state = g_new0 (UnitState, n_layers);
|
||||
return state;
|
||||
return shader_state;
|
||||
}
|
||||
|
||||
static ArbfpProgramState *
|
||||
arbfp_program_state_ref (ArbfpProgramState *state)
|
||||
static CoglPipelineShaderState *
|
||||
get_shader_state (CoglPipeline *pipeline)
|
||||
{
|
||||
state->ref_count++;
|
||||
return state;
|
||||
}
|
||||
|
||||
void
|
||||
arbfp_program_state_unref (ArbfpProgramState *state)
|
||||
{
|
||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
|
||||
g_return_if_fail (state->ref_count > 0);
|
||||
|
||||
state->ref_count--;
|
||||
if (state->ref_count == 0)
|
||||
{
|
||||
if (state->gl_program)
|
||||
{
|
||||
GE (ctx, glDeletePrograms (1, &state->gl_program));
|
||||
state->gl_program = 0;
|
||||
}
|
||||
|
||||
g_free (state->unit_state);
|
||||
|
||||
g_slice_free (ArbfpProgramState, state);
|
||||
}
|
||||
}
|
||||
|
||||
static CoglPipelineFragendARBfpPrivate *
|
||||
get_arbfp_priv (CoglPipeline *pipeline)
|
||||
{
|
||||
if (!(pipeline->fragend_priv_set_mask & COGL_PIPELINE_FRAGEND_ARBFP_MASK))
|
||||
return NULL;
|
||||
|
||||
return pipeline->fragend_privs[COGL_PIPELINE_FRAGEND_ARBFP];
|
||||
return cogl_object_get_user_data (COGL_OBJECT (pipeline), &shader_state_key);
|
||||
}
|
||||
|
||||
static void
|
||||
set_arbfp_priv (CoglPipeline *pipeline, CoglPipelineFragendARBfpPrivate *priv)
|
||||
destroy_shader_state (void *user_data)
|
||||
{
|
||||
if (priv)
|
||||
CoglPipelineShaderState *shader_state = user_data;
|
||||
|
||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
|
||||
if (--shader_state->ref_count == 0)
|
||||
{
|
||||
pipeline->fragend_privs[COGL_PIPELINE_FRAGEND_ARBFP] = priv;
|
||||
pipeline->fragend_priv_set_mask |= COGL_PIPELINE_FRAGEND_ARBFP_MASK;
|
||||
if (shader_state->gl_program)
|
||||
{
|
||||
GE (ctx, glDeletePrograms (1, &shader_state->gl_program));
|
||||
shader_state->gl_program = 0;
|
||||
}
|
||||
|
||||
g_free (shader_state->unit_state);
|
||||
|
||||
g_slice_free (CoglPipelineShaderState, shader_state);
|
||||
}
|
||||
else
|
||||
pipeline->fragend_priv_set_mask &= ~COGL_PIPELINE_FRAGEND_ARBFP_MASK;
|
||||
}
|
||||
|
||||
static ArbfpProgramState *
|
||||
get_arbfp_program_state (CoglPipeline *pipeline)
|
||||
static void
|
||||
set_shader_state (CoglPipeline *pipeline, CoglPipelineShaderState *shader_state)
|
||||
{
|
||||
CoglPipelineFragendARBfpPrivate *priv = get_arbfp_priv (pipeline);
|
||||
if (!priv)
|
||||
return NULL;
|
||||
return priv->arbfp_program_state;
|
||||
cogl_object_set_user_data (COGL_OBJECT (pipeline),
|
||||
&shader_state_key,
|
||||
shader_state,
|
||||
destroy_shader_state);
|
||||
}
|
||||
|
||||
static void
|
||||
dirty_shader_state (CoglPipeline *pipeline)
|
||||
{
|
||||
cogl_object_set_user_data (COGL_OBJECT (pipeline),
|
||||
&shader_state_key,
|
||||
NULL,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
|
@ -168,10 +153,8 @@ _cogl_pipeline_fragend_arbfp_start (CoglPipeline *pipeline,
|
|||
unsigned long pipelines_difference,
|
||||
int n_tex_coord_attribs)
|
||||
{
|
||||
CoglPipelineFragendARBfpPrivate *priv;
|
||||
CoglPipelineShaderState *shader_state;
|
||||
CoglPipeline *authority;
|
||||
CoglPipelineFragendARBfpPrivate *authority_priv;
|
||||
ArbfpProgramState *arbfp_program_state;
|
||||
CoglHandle user_program;
|
||||
|
||||
_COGL_GET_CONTEXT (ctx, FALSE);
|
||||
|
@ -203,16 +186,11 @@ _cogl_pipeline_fragend_arbfp_start (CoglPipeline *pipeline,
|
|||
|
||||
/* Now lookup our ARBfp backend private state (allocating if
|
||||
* necessary) */
|
||||
priv = get_arbfp_priv (pipeline);
|
||||
if (!priv)
|
||||
{
|
||||
priv = g_slice_new0 (CoglPipelineFragendARBfpPrivate);
|
||||
set_arbfp_priv (pipeline, priv);
|
||||
}
|
||||
shader_state = get_shader_state (pipeline);
|
||||
|
||||
/* If we have a valid arbfp_program_state pointer then we are all
|
||||
* set and don't need to generate a new program. */
|
||||
if (priv->arbfp_program_state)
|
||||
/* If we have a valid shader_state then we are all set and don't
|
||||
* need to generate a new program. */
|
||||
if (shader_state)
|
||||
return TRUE;
|
||||
|
||||
/* If we don't have an associated arbfp program yet then find the
|
||||
|
@ -228,41 +206,36 @@ _cogl_pipeline_fragend_arbfp_start (CoglPipeline *pipeline,
|
|||
_cogl_pipeline_get_state_for_fragment_codegen (ctx) &
|
||||
~COGL_PIPELINE_STATE_LAYERS,
|
||||
_cogl_pipeline_get_layer_state_for_fragment_codegen (ctx));
|
||||
authority_priv = get_arbfp_priv (authority);
|
||||
if (authority_priv &&
|
||||
authority_priv->arbfp_program_state)
|
||||
shader_state = get_shader_state (authority);
|
||||
if (shader_state)
|
||||
{
|
||||
/* If we are going to share our program state with an arbfp-authority
|
||||
* then steal a reference to the program state associated with that
|
||||
* then add a reference to the program state associated with that
|
||||
* arbfp-authority... */
|
||||
priv->arbfp_program_state =
|
||||
arbfp_program_state_ref (authority_priv->arbfp_program_state);
|
||||
shader_state->ref_count++;
|
||||
set_shader_state (pipeline, shader_state);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (!authority_priv)
|
||||
{
|
||||
authority_priv = g_slice_new0 (CoglPipelineFragendARBfpPrivate);
|
||||
set_arbfp_priv (authority, authority_priv);
|
||||
}
|
||||
|
||||
/* If we haven't yet found an existing program then before we resort to
|
||||
* generating a new arbfp program we see if we can find a suitable
|
||||
* program in the arbfp_cache. */
|
||||
if (G_LIKELY (!(COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_PROGRAM_CACHES))))
|
||||
{
|
||||
arbfp_program_state = g_hash_table_lookup (ctx->arbfp_cache, authority);
|
||||
if (arbfp_program_state)
|
||||
shader_state = g_hash_table_lookup (ctx->arbfp_cache, authority);
|
||||
if (shader_state)
|
||||
{
|
||||
priv->arbfp_program_state =
|
||||
arbfp_program_state_ref (arbfp_program_state);
|
||||
shader_state->ref_count++;
|
||||
set_shader_state (pipeline, shader_state);
|
||||
|
||||
/* Since we have already resolved the arbfp-authority at this point
|
||||
* we might as well also associate any program we find from the cache
|
||||
* with the authority too... */
|
||||
if (authority_priv != priv)
|
||||
authority_priv->arbfp_program_state =
|
||||
arbfp_program_state_ref (arbfp_program_state);
|
||||
if (authority != pipeline)
|
||||
{
|
||||
shader_state->ref_count++;
|
||||
set_shader_state (authority, shader_state);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
@ -271,26 +244,27 @@ _cogl_pipeline_fragend_arbfp_start (CoglPipeline *pipeline,
|
|||
* generating code for a new program...
|
||||
*/
|
||||
|
||||
arbfp_program_state = arbfp_program_state_new (n_layers);
|
||||
|
||||
priv->arbfp_program_state = arbfp_program_state_ref (arbfp_program_state);
|
||||
shader_state = shader_state_new (n_layers);
|
||||
set_shader_state (pipeline, shader_state);
|
||||
|
||||
/* Since we have already resolved the arbfp-authority at this point we might
|
||||
* as well also associate any program we generate with the authority too...
|
||||
*/
|
||||
if (authority_priv != priv)
|
||||
authority_priv->arbfp_program_state =
|
||||
arbfp_program_state_ref (arbfp_program_state);
|
||||
if (authority != pipeline)
|
||||
{
|
||||
shader_state->ref_count++;
|
||||
set_shader_state (authority, shader_state);
|
||||
}
|
||||
|
||||
arbfp_program_state->user_program = user_program;
|
||||
shader_state->user_program = user_program;
|
||||
if (user_program == COGL_INVALID_HANDLE)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* We reuse a single grow-only GString for code-gen */
|
||||
g_string_set_size (ctx->codegen_source_buffer, 0);
|
||||
arbfp_program_state->source = ctx->codegen_source_buffer;
|
||||
g_string_append (arbfp_program_state->source,
|
||||
shader_state->source = ctx->codegen_source_buffer;
|
||||
g_string_append (shader_state->source,
|
||||
"!!ARBfp1.0\n"
|
||||
"TEMP output;\n"
|
||||
"TEMP tmp0, tmp1, tmp2, tmp3, tmp4;\n"
|
||||
|
@ -302,14 +276,14 @@ _cogl_pipeline_fragend_arbfp_start (CoglPipeline *pipeline,
|
|||
/* At the end of code-gen we'll add the program to a cache and
|
||||
* we'll use the authority pipeline as the basis for key into
|
||||
* that cache... */
|
||||
arbfp_program_state->arbfp_authority = authority;
|
||||
shader_state->arbfp_authority = authority;
|
||||
|
||||
for (i = 0; i < n_layers; i++)
|
||||
{
|
||||
arbfp_program_state->unit_state[i].sampled = FALSE;
|
||||
arbfp_program_state->unit_state[i].dirty_combine_constant = FALSE;
|
||||
shader_state->unit_state[i].sampled = FALSE;
|
||||
shader_state->unit_state[i].dirty_combine_constant = FALSE;
|
||||
}
|
||||
arbfp_program_state->next_constant_id = 0;
|
||||
shader_state->next_constant_id = 0;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
|
@ -370,20 +344,20 @@ gl_target_to_arbfp_string (GLenum gl_target)
|
|||
}
|
||||
|
||||
static void
|
||||
setup_texture_source (ArbfpProgramState *arbfp_program_state,
|
||||
setup_texture_source (CoglPipelineShaderState *shader_state,
|
||||
int unit_index,
|
||||
GLenum gl_target)
|
||||
{
|
||||
if (!arbfp_program_state->unit_state[unit_index].sampled)
|
||||
if (!shader_state->unit_state[unit_index].sampled)
|
||||
{
|
||||
if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_TEXTURING)))
|
||||
g_string_append_printf (arbfp_program_state->source,
|
||||
g_string_append_printf (shader_state->source,
|
||||
"TEMP texel%d;\n"
|
||||
"MOV texel%d, one;\n",
|
||||
unit_index,
|
||||
unit_index);
|
||||
else
|
||||
g_string_append_printf (arbfp_program_state->source,
|
||||
g_string_append_printf (shader_state->source,
|
||||
"TEMP texel%d;\n"
|
||||
"TEX texel%d,fragment.texcoord[%d],"
|
||||
"texture[%d],%s;\n",
|
||||
|
@ -392,7 +366,7 @@ setup_texture_source (ArbfpProgramState *arbfp_program_state,
|
|||
unit_index,
|
||||
unit_index,
|
||||
gl_target_to_arbfp_string (gl_target));
|
||||
arbfp_program_state->unit_state[unit_index].sampled = TRUE;
|
||||
shader_state->unit_state[unit_index].sampled = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -452,7 +426,7 @@ setup_arg (CoglPipeline *pipeline,
|
|||
GLint op,
|
||||
CoglPipelineFragendARBfpArg *arg)
|
||||
{
|
||||
ArbfpProgramState *arbfp_program_state = get_arbfp_program_state (pipeline);
|
||||
CoglPipelineShaderState *shader_state = get_shader_state (pipeline);
|
||||
static const char *tmp_name[3] = { "tmp0", "tmp1", "tmp2" };
|
||||
GLenum gl_target;
|
||||
CoglHandle texture;
|
||||
|
@ -465,14 +439,14 @@ setup_arg (CoglPipeline *pipeline,
|
|||
arg->texture_unit = _cogl_pipeline_layer_get_unit_index (layer);
|
||||
texture = _cogl_pipeline_layer_get_texture (layer);
|
||||
cogl_texture_get_gl_texture (texture, NULL, &gl_target);
|
||||
setup_texture_source (arbfp_program_state, arg->texture_unit, gl_target);
|
||||
setup_texture_source (shader_state, arg->texture_unit, gl_target);
|
||||
break;
|
||||
case COGL_PIPELINE_COMBINE_SOURCE_CONSTANT:
|
||||
{
|
||||
int unit_index = _cogl_pipeline_layer_get_unit_index (layer);
|
||||
UnitState *unit_state = &arbfp_program_state->unit_state[unit_index];
|
||||
UnitState *unit_state = &shader_state->unit_state[unit_index];
|
||||
|
||||
unit_state->constant_id = arbfp_program_state->next_constant_id++;
|
||||
unit_state->constant_id = shader_state->next_constant_id++;
|
||||
unit_state->dirty_combine_constant = TRUE;
|
||||
|
||||
arg->type = COGL_PIPELINE_FRAGEND_ARBFP_ARG_TYPE_CONSTANT;
|
||||
|
@ -497,7 +471,7 @@ setup_arg (CoglPipeline *pipeline,
|
|||
arg->texture_unit = src - GL_TEXTURE0;
|
||||
texture = _cogl_pipeline_layer_get_texture (layer);
|
||||
cogl_texture_get_gl_texture (texture, NULL, &gl_target);
|
||||
setup_texture_source (arbfp_program_state, arg->texture_unit, gl_target);
|
||||
setup_texture_source (shader_state, arg->texture_unit, gl_target);
|
||||
}
|
||||
|
||||
arg->swizzle = "";
|
||||
|
@ -507,11 +481,11 @@ setup_arg (CoglPipeline *pipeline,
|
|||
case COGL_PIPELINE_COMBINE_OP_SRC_COLOR:
|
||||
break;
|
||||
case COGL_PIPELINE_COMBINE_OP_ONE_MINUS_SRC_COLOR:
|
||||
g_string_append_printf (arbfp_program_state->source,
|
||||
g_string_append_printf (shader_state->source,
|
||||
"SUB tmp%d, one, ",
|
||||
arg_index);
|
||||
append_arg (arbfp_program_state->source, arg);
|
||||
g_string_append_printf (arbfp_program_state->source, ";\n");
|
||||
append_arg (shader_state->source, arg);
|
||||
g_string_append_printf (shader_state->source, ";\n");
|
||||
arg->type = COGL_PIPELINE_FRAGEND_ARBFP_ARG_TYPE_SIMPLE;
|
||||
arg->name = tmp_name[arg_index];
|
||||
arg->swizzle = "";
|
||||
|
@ -523,16 +497,16 @@ setup_arg (CoglPipeline *pipeline,
|
|||
arg->swizzle = ".a";
|
||||
break;
|
||||
case COGL_PIPELINE_COMBINE_OP_ONE_MINUS_SRC_ALPHA:
|
||||
g_string_append_printf (arbfp_program_state->source,
|
||||
g_string_append_printf (shader_state->source,
|
||||
"SUB tmp%d, one, ",
|
||||
arg_index);
|
||||
append_arg (arbfp_program_state->source, arg);
|
||||
append_arg (shader_state->source, arg);
|
||||
/* avoid a swizzle if we know RGB are going to be masked
|
||||
* in the end anyway */
|
||||
if (mask != COGL_BLEND_STRING_CHANNEL_MASK_ALPHA)
|
||||
g_string_append_printf (arbfp_program_state->source, ".a;\n");
|
||||
g_string_append_printf (shader_state->source, ".a;\n");
|
||||
else
|
||||
g_string_append_printf (arbfp_program_state->source, ";\n");
|
||||
g_string_append_printf (shader_state->source, ";\n");
|
||||
arg->type = COGL_PIPELINE_FRAGEND_ARBFP_ARG_TYPE_SIMPLE;
|
||||
arg->name = tmp_name[arg_index];
|
||||
break;
|
||||
|
@ -577,7 +551,7 @@ append_function (CoglPipeline *pipeline,
|
|||
CoglPipelineFragendARBfpArg *args,
|
||||
int n_args)
|
||||
{
|
||||
ArbfpProgramState *arbfp_program_state = get_arbfp_program_state (pipeline);
|
||||
CoglPipelineShaderState *shader_state = get_shader_state (pipeline);
|
||||
const char *mask_name;
|
||||
|
||||
switch (mask)
|
||||
|
@ -599,35 +573,35 @@ append_function (CoglPipeline *pipeline,
|
|||
switch (function)
|
||||
{
|
||||
case COGL_PIPELINE_COMBINE_FUNC_ADD:
|
||||
g_string_append_printf (arbfp_program_state->source,
|
||||
g_string_append_printf (shader_state->source,
|
||||
"ADD_SAT output%s, ",
|
||||
mask_name);
|
||||
break;
|
||||
case COGL_PIPELINE_COMBINE_FUNC_MODULATE:
|
||||
/* Note: no need to saturate since we can assume operands
|
||||
* have values in the range [0,1] */
|
||||
g_string_append_printf (arbfp_program_state->source, "MUL output%s, ",
|
||||
g_string_append_printf (shader_state->source, "MUL output%s, ",
|
||||
mask_name);
|
||||
break;
|
||||
case COGL_PIPELINE_COMBINE_FUNC_REPLACE:
|
||||
/* Note: no need to saturate since we can assume operand
|
||||
* has a value in the range [0,1] */
|
||||
g_string_append_printf (arbfp_program_state->source, "MOV output%s, ",
|
||||
g_string_append_printf (shader_state->source, "MOV output%s, ",
|
||||
mask_name);
|
||||
break;
|
||||
case COGL_PIPELINE_COMBINE_FUNC_SUBTRACT:
|
||||
g_string_append_printf (arbfp_program_state->source,
|
||||
g_string_append_printf (shader_state->source,
|
||||
"SUB_SAT output%s, ",
|
||||
mask_name);
|
||||
break;
|
||||
case COGL_PIPELINE_COMBINE_FUNC_ADD_SIGNED:
|
||||
g_string_append_printf (arbfp_program_state->source, "ADD tmp3%s, ",
|
||||
g_string_append_printf (shader_state->source, "ADD tmp3%s, ",
|
||||
mask_name);
|
||||
append_arg (arbfp_program_state->source, &args[0]);
|
||||
g_string_append (arbfp_program_state->source, ", ");
|
||||
append_arg (arbfp_program_state->source, &args[1]);
|
||||
g_string_append (arbfp_program_state->source, ";\n");
|
||||
g_string_append_printf (arbfp_program_state->source,
|
||||
append_arg (shader_state->source, &args[0]);
|
||||
g_string_append (shader_state->source, ", ");
|
||||
append_arg (shader_state->source, &args[1]);
|
||||
g_string_append (shader_state->source, ";\n");
|
||||
g_string_append_printf (shader_state->source,
|
||||
"SUB_SAT output%s, tmp3, half",
|
||||
mask_name);
|
||||
n_args = 0;
|
||||
|
@ -656,20 +630,20 @@ append_function (CoglPipeline *pipeline,
|
|||
* output = 4 * DP3 (src0 - 0.5, src1 - 0.5)
|
||||
*/
|
||||
|
||||
g_string_append (arbfp_program_state->source, "MAD tmp3, two, ");
|
||||
append_arg (arbfp_program_state->source, &args[0]);
|
||||
g_string_append (arbfp_program_state->source, ", minus_one;\n");
|
||||
g_string_append (shader_state->source, "MAD tmp3, two, ");
|
||||
append_arg (shader_state->source, &args[0]);
|
||||
g_string_append (shader_state->source, ", minus_one;\n");
|
||||
|
||||
if (!fragend_arbfp_args_equal (&args[0], &args[1]))
|
||||
{
|
||||
g_string_append (arbfp_program_state->source, "MAD tmp4, two, ");
|
||||
append_arg (arbfp_program_state->source, &args[1]);
|
||||
g_string_append (arbfp_program_state->source, ", minus_one;\n");
|
||||
g_string_append (shader_state->source, "MAD tmp4, two, ");
|
||||
append_arg (shader_state->source, &args[1]);
|
||||
g_string_append (shader_state->source, ", minus_one;\n");
|
||||
}
|
||||
else
|
||||
tmp4 = "tmp3";
|
||||
|
||||
g_string_append_printf (arbfp_program_state->source,
|
||||
g_string_append_printf (shader_state->source,
|
||||
"DP3_SAT output%s, tmp3, %s",
|
||||
mask_name, tmp4);
|
||||
n_args = 0;
|
||||
|
@ -681,31 +655,31 @@ append_function (CoglPipeline *pipeline,
|
|||
|
||||
/* NB: GL_INTERPOLATE = arg0*arg2 + arg1*(1-arg2)
|
||||
* but LRP dst, a, b, c = b*a + c*(1-a) */
|
||||
g_string_append_printf (arbfp_program_state->source, "LRP output%s, ",
|
||||
g_string_append_printf (shader_state->source, "LRP output%s, ",
|
||||
mask_name);
|
||||
append_arg (arbfp_program_state->source, &args[2]);
|
||||
g_string_append (arbfp_program_state->source, ", ");
|
||||
append_arg (arbfp_program_state->source, &args[0]);
|
||||
g_string_append (arbfp_program_state->source, ", ");
|
||||
append_arg (arbfp_program_state->source, &args[1]);
|
||||
append_arg (shader_state->source, &args[2]);
|
||||
g_string_append (shader_state->source, ", ");
|
||||
append_arg (shader_state->source, &args[0]);
|
||||
g_string_append (shader_state->source, ", ");
|
||||
append_arg (shader_state->source, &args[1]);
|
||||
n_args = 0;
|
||||
break;
|
||||
default:
|
||||
g_error ("Unknown texture combine function %d", function);
|
||||
g_string_append_printf (arbfp_program_state->source, "MUL_SAT output%s, ",
|
||||
g_string_append_printf (shader_state->source, "MUL_SAT output%s, ",
|
||||
mask_name);
|
||||
n_args = 2;
|
||||
break;
|
||||
}
|
||||
|
||||
if (n_args > 0)
|
||||
append_arg (arbfp_program_state->source, &args[0]);
|
||||
append_arg (shader_state->source, &args[0]);
|
||||
if (n_args > 1)
|
||||
{
|
||||
g_string_append (arbfp_program_state->source, ", ");
|
||||
append_arg (arbfp_program_state->source, &args[1]);
|
||||
g_string_append (shader_state->source, ", ");
|
||||
append_arg (shader_state->source, &args[1]);
|
||||
}
|
||||
g_string_append (arbfp_program_state->source, ";\n");
|
||||
g_string_append (shader_state->source, ";\n");
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -745,7 +719,7 @@ _cogl_pipeline_fragend_arbfp_add_layer (CoglPipeline *pipeline,
|
|||
CoglPipelineLayer *layer,
|
||||
unsigned long layers_difference)
|
||||
{
|
||||
ArbfpProgramState *arbfp_program_state = get_arbfp_program_state (pipeline);
|
||||
CoglPipelineShaderState *shader_state = get_shader_state (pipeline);
|
||||
CoglPipelineLayer *combine_authority =
|
||||
_cogl_pipeline_layer_get_authority (layer,
|
||||
COGL_PIPELINE_LAYER_STATE_COMBINE);
|
||||
|
@ -780,7 +754,7 @@ _cogl_pipeline_fragend_arbfp_add_layer (CoglPipeline *pipeline,
|
|||
* We are careful to only saturate when writing to output.
|
||||
*/
|
||||
|
||||
if (!arbfp_program_state->source)
|
||||
if (!shader_state->source)
|
||||
return TRUE;
|
||||
|
||||
if (!_cogl_pipeline_need_texture_combine_separate (combine_authority))
|
||||
|
@ -827,12 +801,12 @@ _cogl_pipeline_fragend_arbfp_add_layer (CoglPipeline *pipeline,
|
|||
gboolean
|
||||
_cogl_pipeline_fragend_arbfp_passthrough (CoglPipeline *pipeline)
|
||||
{
|
||||
ArbfpProgramState *arbfp_program_state = get_arbfp_program_state (pipeline);
|
||||
CoglPipelineShaderState *shader_state = get_shader_state (pipeline);
|
||||
|
||||
if (!arbfp_program_state->source)
|
||||
if (!shader_state->source)
|
||||
return TRUE;
|
||||
|
||||
g_string_append (arbfp_program_state->source,
|
||||
g_string_append (shader_state->source,
|
||||
"MOV output, fragment.color.primary;\n");
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -841,7 +815,7 @@ typedef struct _UpdateConstantsState
|
|||
{
|
||||
int unit;
|
||||
gboolean update_all;
|
||||
ArbfpProgramState *arbfp_program_state;
|
||||
CoglPipelineShaderState *shader_state;
|
||||
} UpdateConstantsState;
|
||||
|
||||
static gboolean
|
||||
|
@ -850,8 +824,8 @@ update_constants_cb (CoglPipeline *pipeline,
|
|||
void *user_data)
|
||||
{
|
||||
UpdateConstantsState *state = user_data;
|
||||
ArbfpProgramState *arbfp_program_state = state->arbfp_program_state;
|
||||
UnitState *unit_state = &arbfp_program_state->unit_state[state->unit++];
|
||||
CoglPipelineShaderState *shader_state = state->shader_state;
|
||||
UnitState *unit_state = &shader_state->unit_state[state->unit++];
|
||||
|
||||
_COGL_GET_CONTEXT (ctx, FALSE);
|
||||
|
||||
|
@ -873,12 +847,12 @@ static gboolean
|
|||
_cogl_pipeline_fragend_arbfp_end (CoglPipeline *pipeline,
|
||||
unsigned long pipelines_difference)
|
||||
{
|
||||
ArbfpProgramState *arbfp_program_state = get_arbfp_program_state (pipeline);
|
||||
CoglPipelineShaderState *shader_state = get_shader_state (pipeline);
|
||||
GLuint gl_program;
|
||||
|
||||
_COGL_GET_CONTEXT (ctx, FALSE);
|
||||
|
||||
if (arbfp_program_state->source)
|
||||
if (shader_state->source)
|
||||
{
|
||||
GLenum gl_error;
|
||||
COGL_STATIC_COUNTER (fragend_arbfp_compile_counter,
|
||||
|
@ -889,32 +863,32 @@ _cogl_pipeline_fragend_arbfp_end (CoglPipeline *pipeline,
|
|||
|
||||
COGL_COUNTER_INC (_cogl_uprof_context, fragend_arbfp_compile_counter);
|
||||
|
||||
g_string_append (arbfp_program_state->source,
|
||||
g_string_append (shader_state->source,
|
||||
"MOV result.color,output;\n");
|
||||
g_string_append (arbfp_program_state->source, "END\n");
|
||||
g_string_append (shader_state->source, "END\n");
|
||||
|
||||
if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_SHOW_SOURCE)))
|
||||
g_message ("pipeline program:\n%s", arbfp_program_state->source->str);
|
||||
g_message ("pipeline program:\n%s", shader_state->source->str);
|
||||
|
||||
GE (ctx, glGenPrograms (1, &arbfp_program_state->gl_program));
|
||||
GE (ctx, glGenPrograms (1, &shader_state->gl_program));
|
||||
|
||||
GE (ctx, glBindProgram (GL_FRAGMENT_PROGRAM_ARB,
|
||||
arbfp_program_state->gl_program));
|
||||
shader_state->gl_program));
|
||||
|
||||
while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR)
|
||||
;
|
||||
ctx->glProgramString (GL_FRAGMENT_PROGRAM_ARB,
|
||||
GL_PROGRAM_FORMAT_ASCII_ARB,
|
||||
arbfp_program_state->source->len,
|
||||
arbfp_program_state->source->str);
|
||||
shader_state->source->len,
|
||||
shader_state->source->str);
|
||||
if (ctx->glGetError () != GL_NO_ERROR)
|
||||
{
|
||||
g_warning ("\n%s\n%s",
|
||||
arbfp_program_state->source->str,
|
||||
shader_state->source->str,
|
||||
ctx->glGetString (GL_PROGRAM_ERROR_STRING_ARB));
|
||||
}
|
||||
|
||||
arbfp_program_state->source = NULL;
|
||||
shader_state->source = NULL;
|
||||
|
||||
if (G_LIKELY (!(COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_PROGRAM_CACHES))))
|
||||
{
|
||||
|
@ -942,9 +916,9 @@ _cogl_pipeline_fragend_arbfp_end (CoglPipeline *pipeline,
|
|||
* other pipelines) and only takes a copy of the state that
|
||||
* relates to the arbfp program and references small dummy
|
||||
* textures instead of potentially large user textures. */
|
||||
key = cogl_pipeline_copy (arbfp_program_state->arbfp_authority);
|
||||
arbfp_program_state_ref (arbfp_program_state);
|
||||
g_hash_table_insert (ctx->arbfp_cache, key, arbfp_program_state);
|
||||
key = cogl_pipeline_copy (shader_state->arbfp_authority);
|
||||
shader_state->ref_count++;
|
||||
g_hash_table_insert (ctx->arbfp_cache, key, shader_state);
|
||||
if (G_UNLIKELY (g_hash_table_size (ctx->arbfp_cache) > 50))
|
||||
{
|
||||
static gboolean seen = FALSE;
|
||||
|
@ -959,77 +933,59 @@ _cogl_pipeline_fragend_arbfp_end (CoglPipeline *pipeline,
|
|||
/* The authority is only valid during codegen since the program
|
||||
* state may have a longer lifetime than the original authority
|
||||
* it is created for. */
|
||||
arbfp_program_state->arbfp_authority = NULL;
|
||||
shader_state->arbfp_authority = NULL;
|
||||
}
|
||||
|
||||
if (arbfp_program_state->user_program != COGL_INVALID_HANDLE)
|
||||
if (shader_state->user_program != COGL_INVALID_HANDLE)
|
||||
{
|
||||
/* An arbfp program should contain exactly one shader which we
|
||||
can use directly */
|
||||
CoglProgram *program = arbfp_program_state->user_program;
|
||||
CoglProgram *program = shader_state->user_program;
|
||||
CoglShader *shader = program->attached_shaders->data;
|
||||
|
||||
gl_program = shader->gl_handle;
|
||||
}
|
||||
else
|
||||
gl_program = arbfp_program_state->gl_program;
|
||||
gl_program = shader_state->gl_program;
|
||||
|
||||
GE (ctx, glBindProgram (GL_FRAGMENT_PROGRAM_ARB, gl_program));
|
||||
_cogl_use_fragment_program (0, COGL_PIPELINE_PROGRAM_TYPE_ARBFP);
|
||||
|
||||
if (arbfp_program_state->user_program == COGL_INVALID_HANDLE)
|
||||
if (shader_state->user_program == COGL_INVALID_HANDLE)
|
||||
{
|
||||
UpdateConstantsState state;
|
||||
state.unit = 0;
|
||||
state.arbfp_program_state = arbfp_program_state;
|
||||
state.shader_state = shader_state;
|
||||
/* If this arbfp program was last used with a different pipeline
|
||||
* then we need to ensure we update all program.local params */
|
||||
state.update_all =
|
||||
pipeline != arbfp_program_state->last_used_for_pipeline;
|
||||
pipeline != shader_state->last_used_for_pipeline;
|
||||
cogl_pipeline_foreach_layer (pipeline,
|
||||
update_constants_cb,
|
||||
&state);
|
||||
}
|
||||
else
|
||||
{
|
||||
CoglProgram *program = arbfp_program_state->user_program;
|
||||
CoglProgram *program = shader_state->user_program;
|
||||
gboolean program_changed;
|
||||
|
||||
/* If the shader has changed since it was last flushed then we
|
||||
need to update all uniforms */
|
||||
program_changed = program->age != arbfp_program_state->user_program_age;
|
||||
program_changed = program->age != shader_state->user_program_age;
|
||||
|
||||
_cogl_program_flush_uniforms (program, gl_program, program_changed);
|
||||
|
||||
arbfp_program_state->user_program_age = program->age;
|
||||
shader_state->user_program_age = program->age;
|
||||
}
|
||||
|
||||
/* We need to track what pipeline used this arbfp program last since
|
||||
* we will need to update program.local params when switching
|
||||
* between different pipelines. */
|
||||
arbfp_program_state->last_used_for_pipeline = pipeline;
|
||||
shader_state->last_used_for_pipeline = pipeline;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
dirty_arbfp_program_state (CoglPipeline *pipeline)
|
||||
{
|
||||
CoglPipelineFragendARBfpPrivate *priv;
|
||||
|
||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
|
||||
priv = get_arbfp_priv (pipeline);
|
||||
if (!priv)
|
||||
return;
|
||||
|
||||
if (priv->arbfp_program_state)
|
||||
{
|
||||
arbfp_program_state_unref (priv->arbfp_program_state);
|
||||
priv->arbfp_program_state = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_cogl_pipeline_fragend_arbfp_pipeline_pre_change_notify (
|
||||
CoglPipeline *pipeline,
|
||||
|
@ -1039,7 +995,7 @@ _cogl_pipeline_fragend_arbfp_pipeline_pre_change_notify (
|
|||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
|
||||
if ((change & _cogl_pipeline_get_state_for_fragment_codegen (ctx)))
|
||||
dirty_arbfp_program_state (pipeline);
|
||||
dirty_shader_state (pipeline);
|
||||
}
|
||||
|
||||
/* NB: layers are considered immutable once they have any dependants
|
||||
|
@ -1056,29 +1012,23 @@ _cogl_pipeline_fragend_arbfp_layer_pre_change_notify (
|
|||
CoglPipelineLayer *layer,
|
||||
CoglPipelineLayerState change)
|
||||
{
|
||||
CoglPipelineFragendARBfpPrivate *priv = get_arbfp_priv (owner);
|
||||
CoglPipelineShaderState *shader_state = get_shader_state (owner);
|
||||
|
||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
|
||||
if (!priv)
|
||||
if (!shader_state)
|
||||
return;
|
||||
|
||||
if ((change & _cogl_pipeline_get_layer_state_for_fragment_codegen (ctx)))
|
||||
{
|
||||
dirty_arbfp_program_state (owner);
|
||||
dirty_shader_state (owner);
|
||||
return;
|
||||
}
|
||||
|
||||
if (change & COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT)
|
||||
{
|
||||
ArbfpProgramState *arbfp_program_state = get_arbfp_program_state (owner);
|
||||
|
||||
if (arbfp_program_state)
|
||||
{
|
||||
int unit_index = _cogl_pipeline_layer_get_unit_index (layer);
|
||||
arbfp_program_state->unit_state[unit_index].dirty_combine_constant =
|
||||
TRUE;
|
||||
}
|
||||
int unit_index = _cogl_pipeline_layer_get_unit_index (layer);
|
||||
shader_state->unit_state[unit_index].dirty_combine_constant = TRUE;
|
||||
}
|
||||
|
||||
/* TODO: we could be saving snippets of texture combine code along
|
||||
|
@ -1087,19 +1037,6 @@ _cogl_pipeline_fragend_arbfp_layer_pre_change_notify (
|
|||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
_cogl_pipeline_fragend_arbfp_free_priv (CoglPipeline *pipeline)
|
||||
{
|
||||
CoglPipelineFragendARBfpPrivate *priv = get_arbfp_priv (pipeline);
|
||||
if (priv)
|
||||
{
|
||||
if (priv->arbfp_program_state)
|
||||
arbfp_program_state_unref (priv->arbfp_program_state);
|
||||
g_slice_free (CoglPipelineFragendARBfpPrivate, priv);
|
||||
set_arbfp_priv (pipeline, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
const CoglPipelineFragend _cogl_pipeline_arbfp_fragend =
|
||||
{
|
||||
_cogl_pipeline_fragend_arbfp_start,
|
||||
|
@ -1108,8 +1045,7 @@ const CoglPipelineFragend _cogl_pipeline_arbfp_fragend =
|
|||
_cogl_pipeline_fragend_arbfp_end,
|
||||
_cogl_pipeline_fragend_arbfp_pipeline_pre_change_notify,
|
||||
NULL,
|
||||
_cogl_pipeline_fragend_arbfp_layer_pre_change_notify,
|
||||
_cogl_pipeline_fragend_arbfp_free_priv
|
||||
_cogl_pipeline_fragend_arbfp_layer_pre_change_notify
|
||||
};
|
||||
|
||||
#endif /* COGL_PIPELINE_FRAGEND_ARBFP */
|
||||
|
|
|
@ -363,7 +363,6 @@ const CoglPipelineFragend _cogl_pipeline_fixed_fragend =
|
|||
NULL, /* pipeline_change_notify */
|
||||
NULL, /* pipeline_set_parent_notify */
|
||||
NULL, /* layer_change_notify */
|
||||
NULL /* free_priv */
|
||||
};
|
||||
|
||||
#endif /* COGL_PIPELINE_FRAGEND_FIXED */
|
||||
|
|
|
@ -56,13 +56,15 @@
|
|||
#define GL_TEXTURE_3D 0x806F
|
||||
#endif
|
||||
|
||||
const CoglPipelineFragend _cogl_pipeline_glsl_backend;
|
||||
|
||||
typedef struct _UnitState
|
||||
{
|
||||
unsigned int sampled:1;
|
||||
unsigned int combine_constant_used:1;
|
||||
} UnitState;
|
||||
|
||||
typedef struct _GlslShaderState
|
||||
typedef struct
|
||||
{
|
||||
int ref_count;
|
||||
|
||||
|
@ -75,120 +77,83 @@ typedef struct _GlslShaderState
|
|||
program changes then we may need to redecide whether to generate
|
||||
a shader at all */
|
||||
unsigned int user_program_age;
|
||||
} GlslShaderState;
|
||||
} CoglPipelineShaderState;
|
||||
|
||||
typedef struct _CoglPipelineFragendGlslPrivate
|
||||
static CoglUserDataKey shader_state_key;
|
||||
|
||||
static CoglPipelineShaderState *
|
||||
shader_state_new (int n_layers)
|
||||
{
|
||||
GlslShaderState *glsl_shader_state;
|
||||
} CoglPipelineFragendGlslPrivate;
|
||||
CoglPipelineShaderState *shader_state;
|
||||
|
||||
const CoglPipelineFragend _cogl_pipeline_glsl_backend;
|
||||
shader_state = g_slice_new0 (CoglPipelineShaderState);
|
||||
shader_state->ref_count = 1;
|
||||
shader_state->unit_state = g_new0 (UnitState, n_layers);
|
||||
|
||||
static GlslShaderState *
|
||||
glsl_shader_state_new (int n_layers)
|
||||
{
|
||||
GlslShaderState *state = g_slice_new0 (GlslShaderState);
|
||||
|
||||
state->ref_count = 1;
|
||||
state->unit_state = g_new0 (UnitState, n_layers);
|
||||
|
||||
return state;
|
||||
return shader_state;
|
||||
}
|
||||
|
||||
static GlslShaderState *
|
||||
glsl_shader_state_ref (GlslShaderState *state)
|
||||
static CoglPipelineShaderState *
|
||||
get_shader_state (CoglPipeline *pipeline)
|
||||
{
|
||||
state->ref_count++;
|
||||
return state;
|
||||
}
|
||||
|
||||
void
|
||||
glsl_shader_state_unref (GlslShaderState *state)
|
||||
{
|
||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
|
||||
g_return_if_fail (state->ref_count > 0);
|
||||
|
||||
state->ref_count--;
|
||||
if (state->ref_count == 0)
|
||||
{
|
||||
if (state->gl_shader)
|
||||
GE( ctx, glDeleteShader (state->gl_shader) );
|
||||
|
||||
g_free (state->unit_state);
|
||||
|
||||
g_slice_free (GlslShaderState, state);
|
||||
}
|
||||
}
|
||||
|
||||
static CoglPipelineFragendGlslPrivate *
|
||||
get_glsl_priv (CoglPipeline *pipeline)
|
||||
{
|
||||
if (!(pipeline->fragend_priv_set_mask & COGL_PIPELINE_FRAGEND_GLSL_MASK))
|
||||
return NULL;
|
||||
|
||||
return pipeline->fragend_privs[COGL_PIPELINE_FRAGEND_GLSL];
|
||||
return cogl_object_get_user_data (COGL_OBJECT (pipeline), &shader_state_key);
|
||||
}
|
||||
|
||||
static void
|
||||
set_glsl_priv (CoglPipeline *pipeline, CoglPipelineFragendGlslPrivate *priv)
|
||||
destroy_shader_state (void *user_data)
|
||||
{
|
||||
if (priv)
|
||||
CoglPipelineShaderState *shader_state = user_data;
|
||||
|
||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
|
||||
if (--shader_state->ref_count == 0)
|
||||
{
|
||||
pipeline->fragend_privs[COGL_PIPELINE_FRAGEND_GLSL] = priv;
|
||||
pipeline->fragend_priv_set_mask |= COGL_PIPELINE_FRAGEND_GLSL_MASK;
|
||||
if (shader_state->gl_shader)
|
||||
GE( ctx, glDeleteShader (shader_state->gl_shader) );
|
||||
|
||||
g_free (shader_state->unit_state);
|
||||
|
||||
g_slice_free (CoglPipelineShaderState, shader_state);
|
||||
}
|
||||
else
|
||||
pipeline->fragend_priv_set_mask &= ~COGL_PIPELINE_FRAGEND_GLSL_MASK;
|
||||
}
|
||||
|
||||
static GlslShaderState *
|
||||
get_glsl_shader_state (CoglPipeline *pipeline)
|
||||
static void
|
||||
set_shader_state (CoglPipeline *pipeline, CoglPipelineShaderState *shader_state)
|
||||
{
|
||||
CoglPipelineFragendGlslPrivate *priv = get_glsl_priv (pipeline);
|
||||
if (!priv)
|
||||
return NULL;
|
||||
return priv->glsl_shader_state;
|
||||
cogl_object_set_user_data (COGL_OBJECT (pipeline),
|
||||
&shader_state_key,
|
||||
shader_state,
|
||||
destroy_shader_state);
|
||||
}
|
||||
|
||||
static void
|
||||
dirty_shader_state (CoglPipeline *pipeline)
|
||||
{
|
||||
cogl_object_set_user_data (COGL_OBJECT (pipeline),
|
||||
&shader_state_key,
|
||||
NULL,
|
||||
NULL);
|
||||
}
|
||||
|
||||
GLuint
|
||||
_cogl_pipeline_fragend_glsl_get_shader (CoglPipeline *pipeline)
|
||||
{
|
||||
GlslShaderState *glsl_shader_state = get_glsl_shader_state (pipeline);
|
||||
CoglPipelineShaderState *shader_state = get_shader_state (pipeline);
|
||||
|
||||
if (glsl_shader_state)
|
||||
return glsl_shader_state->gl_shader;
|
||||
if (shader_state)
|
||||
return shader_state->gl_shader;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
dirty_glsl_shader_state (CoglPipeline *pipeline)
|
||||
{
|
||||
CoglPipelineFragendGlslPrivate *priv;
|
||||
|
||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
|
||||
priv = get_glsl_priv (pipeline);
|
||||
if (!priv)
|
||||
return;
|
||||
|
||||
if (priv->glsl_shader_state)
|
||||
{
|
||||
glsl_shader_state_unref (priv->glsl_shader_state);
|
||||
priv->glsl_shader_state = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_cogl_pipeline_fragend_glsl_start (CoglPipeline *pipeline,
|
||||
int n_layers,
|
||||
unsigned long pipelines_difference,
|
||||
int n_tex_coord_attribs)
|
||||
{
|
||||
CoglPipelineFragendGlslPrivate *priv;
|
||||
CoglPipelineShaderState *shader_state;
|
||||
CoglPipeline *authority;
|
||||
CoglPipelineFragendGlslPrivate *authority_priv;
|
||||
CoglProgram *user_program;
|
||||
int i;
|
||||
|
||||
|
@ -206,16 +171,10 @@ _cogl_pipeline_fragend_glsl_start (CoglPipeline *pipeline,
|
|||
_cogl_program_get_language (user_program) != COGL_SHADER_LANGUAGE_GLSL)
|
||||
return FALSE;
|
||||
|
||||
/* Now lookup our glsl backend private state (allocating if
|
||||
* necessary) */
|
||||
priv = get_glsl_priv (pipeline);
|
||||
if (!priv)
|
||||
{
|
||||
priv = g_slice_new0 (CoglPipelineFragendGlslPrivate);
|
||||
set_glsl_priv (pipeline, priv);
|
||||
}
|
||||
/* Now lookup our glsl backend private state */
|
||||
shader_state = get_shader_state (pipeline);
|
||||
|
||||
if (!priv->glsl_shader_state)
|
||||
if (shader_state == NULL)
|
||||
{
|
||||
/* If we don't have an associated glsl shader yet then find the
|
||||
* glsl-authority (the oldest ancestor whose state will result in
|
||||
|
@ -231,43 +190,39 @@ _cogl_pipeline_fragend_glsl_start (CoglPipeline *pipeline,
|
|||
~COGL_PIPELINE_STATE_LAYERS,
|
||||
_cogl_pipeline_get_layer_state_for_fragment_codegen (ctx));
|
||||
|
||||
authority_priv = get_glsl_priv (authority);
|
||||
if (!authority_priv)
|
||||
{
|
||||
authority_priv = g_slice_new0 (CoglPipelineFragendGlslPrivate);
|
||||
set_glsl_priv (authority, authority_priv);
|
||||
}
|
||||
shader_state = get_shader_state (authority);
|
||||
|
||||
/* If we don't have an existing program associated with the
|
||||
* glsl-authority then start generating code for a new shader...
|
||||
*/
|
||||
if (!authority_priv->glsl_shader_state)
|
||||
if (shader_state == NULL)
|
||||
{
|
||||
GlslShaderState *glsl_shader_state =
|
||||
glsl_shader_state_new (n_layers);
|
||||
authority_priv->glsl_shader_state = glsl_shader_state;
|
||||
shader_state = shader_state_new (n_layers);
|
||||
set_shader_state (authority, shader_state);
|
||||
}
|
||||
|
||||
/* If the pipeline isn't actually its own glsl-authority
|
||||
* then take a reference to the program state associated
|
||||
* with the glsl-authority... */
|
||||
if (authority != pipeline)
|
||||
priv->glsl_shader_state =
|
||||
glsl_shader_state_ref (authority_priv->glsl_shader_state);
|
||||
{
|
||||
shader_state->ref_count++;
|
||||
set_shader_state (pipeline, shader_state);
|
||||
}
|
||||
}
|
||||
|
||||
if (priv->glsl_shader_state->gl_shader)
|
||||
if (shader_state->gl_shader)
|
||||
{
|
||||
/* If we already have a valid GLSL shader then we don't need to
|
||||
generate a new one. However if there's a user program and it
|
||||
has changed since the last link then we do need a new shader */
|
||||
if (user_program == NULL ||
|
||||
(priv->glsl_shader_state->user_program_age == user_program->age))
|
||||
shader_state->user_program_age == user_program->age)
|
||||
return TRUE;
|
||||
|
||||
/* We need to recreate the shader so destroy the existing one */
|
||||
GE( ctx, glDeleteShader (priv->glsl_shader_state->gl_shader) );
|
||||
priv->glsl_shader_state->gl_shader = 0;
|
||||
GE( ctx, glDeleteShader (shader_state->gl_shader) );
|
||||
shader_state->gl_shader = 0;
|
||||
}
|
||||
|
||||
/* If we make it here then we have a glsl_shader_state struct
|
||||
|
@ -275,7 +230,7 @@ _cogl_pipeline_fragend_glsl_start (CoglPipeline *pipeline,
|
|||
encountered it or because the user program has changed */
|
||||
|
||||
if (user_program)
|
||||
priv->glsl_shader_state->user_program_age = user_program->age;
|
||||
shader_state->user_program_age = user_program->age;
|
||||
|
||||
/* If the user program contains a fragment shader then we don't need
|
||||
to generate one */
|
||||
|
@ -290,25 +245,25 @@ _cogl_pipeline_fragend_glsl_start (CoglPipeline *pipeline,
|
|||
add_layer callback is invoked */
|
||||
g_string_set_size (ctx->codegen_header_buffer, 0);
|
||||
g_string_set_size (ctx->codegen_source_buffer, 0);
|
||||
priv->glsl_shader_state->header = ctx->codegen_header_buffer;
|
||||
priv->glsl_shader_state->source = ctx->codegen_source_buffer;
|
||||
shader_state->header = ctx->codegen_header_buffer;
|
||||
shader_state->source = ctx->codegen_source_buffer;
|
||||
|
||||
g_string_append (priv->glsl_shader_state->source,
|
||||
g_string_append (shader_state->source,
|
||||
"void\n"
|
||||
"main ()\n"
|
||||
"{\n");
|
||||
|
||||
for (i = 0; i < n_layers; i++)
|
||||
{
|
||||
priv->glsl_shader_state->unit_state[i].sampled = FALSE;
|
||||
priv->glsl_shader_state->unit_state[i].combine_constant_used = FALSE;
|
||||
shader_state->unit_state[i].sampled = FALSE;
|
||||
shader_state->unit_state[i].combine_constant_used = FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
add_constant_lookup (GlslShaderState *glsl_shader_state,
|
||||
add_constant_lookup (CoglPipelineShaderState *shader_state,
|
||||
CoglPipeline *pipeline,
|
||||
CoglPipelineLayer *layer,
|
||||
const char *swizzle)
|
||||
|
@ -316,21 +271,21 @@ add_constant_lookup (GlslShaderState *glsl_shader_state,
|
|||
int unit_index = _cogl_pipeline_layer_get_unit_index (layer);
|
||||
|
||||
/* Create a sampler uniform for this layer if we haven't already */
|
||||
if (!glsl_shader_state->unit_state[unit_index].combine_constant_used)
|
||||
if (!shader_state->unit_state[unit_index].combine_constant_used)
|
||||
{
|
||||
g_string_append_printf (glsl_shader_state->header,
|
||||
g_string_append_printf (shader_state->header,
|
||||
"uniform vec4 _cogl_layer_constant_%i;\n",
|
||||
unit_index);
|
||||
glsl_shader_state->unit_state[unit_index].combine_constant_used = TRUE;
|
||||
shader_state->unit_state[unit_index].combine_constant_used = TRUE;
|
||||
}
|
||||
|
||||
g_string_append_printf (glsl_shader_state->source,
|
||||
g_string_append_printf (shader_state->source,
|
||||
"_cogl_layer_constant_%i.%s",
|
||||
unit_index, swizzle);
|
||||
}
|
||||
|
||||
static void
|
||||
add_texture_lookup (GlslShaderState *glsl_shader_state,
|
||||
add_texture_lookup (CoglPipelineShaderState *shader_state,
|
||||
CoglPipeline *pipeline,
|
||||
CoglPipelineLayer *layer,
|
||||
const char *swizzle)
|
||||
|
@ -343,9 +298,9 @@ add_texture_lookup (GlslShaderState *glsl_shader_state,
|
|||
|
||||
if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_TEXTURING)))
|
||||
{
|
||||
g_string_append (glsl_shader_state->source,
|
||||
g_string_append (shader_state->source,
|
||||
"vec4 (1.0, 1.0, 1.0, 1.0).");
|
||||
g_string_append (glsl_shader_state->source, swizzle);
|
||||
g_string_append (shader_state->source, swizzle);
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -394,16 +349,16 @@ add_texture_lookup (GlslShaderState *glsl_shader_state,
|
|||
}
|
||||
|
||||
/* Create a sampler uniform for this layer if we haven't already */
|
||||
if (!glsl_shader_state->unit_state[unit_index].sampled)
|
||||
if (!shader_state->unit_state[unit_index].sampled)
|
||||
{
|
||||
g_string_append_printf (glsl_shader_state->header,
|
||||
g_string_append_printf (shader_state->header,
|
||||
"uniform sampler%s _cogl_sampler_%i;\n",
|
||||
target_string,
|
||||
unit_index);
|
||||
glsl_shader_state->unit_state[unit_index].sampled = TRUE;
|
||||
shader_state->unit_state[unit_index].sampled = TRUE;
|
||||
}
|
||||
|
||||
g_string_append_printf (glsl_shader_state->source,
|
||||
g_string_append_printf (shader_state->source,
|
||||
"texture%s (_cogl_sampler_%i, ",
|
||||
target_string, unit_index);
|
||||
|
||||
|
@ -418,15 +373,15 @@ add_texture_lookup (GlslShaderState *glsl_shader_state,
|
|||
if (ctx->driver == COGL_DRIVER_GLES2 &&
|
||||
cogl_pipeline_get_layer_point_sprite_coords_enabled (pipeline,
|
||||
layer->index))
|
||||
g_string_append_printf (glsl_shader_state->source,
|
||||
g_string_append_printf (shader_state->source,
|
||||
"gl_PointCoord.%s",
|
||||
tex_coord_swizzle);
|
||||
else
|
||||
g_string_append_printf (glsl_shader_state->source,
|
||||
g_string_append_printf (shader_state->source,
|
||||
"cogl_tex_coord_in[%d].%s",
|
||||
unit_index, tex_coord_swizzle);
|
||||
|
||||
g_string_append_printf (glsl_shader_state->source, ").%s", swizzle);
|
||||
g_string_append_printf (shader_state->source, ").%s", swizzle);
|
||||
}
|
||||
|
||||
typedef struct
|
||||
|
@ -454,14 +409,14 @@ find_pipeline_layer_cb (CoglPipelineLayer *layer,
|
|||
}
|
||||
|
||||
static void
|
||||
add_arg (GlslShaderState *glsl_shader_state,
|
||||
add_arg (CoglPipelineShaderState *shader_state,
|
||||
CoglPipeline *pipeline,
|
||||
CoglPipelineLayer *layer,
|
||||
CoglPipelineCombineSource src,
|
||||
CoglPipelineCombineOp operand,
|
||||
const char *swizzle)
|
||||
{
|
||||
GString *shader_source = glsl_shader_state->source;
|
||||
GString *shader_source = shader_state->source;
|
||||
char alpha_swizzle[5] = "aaaa";
|
||||
|
||||
g_string_append_c (shader_source, '(');
|
||||
|
@ -484,14 +439,14 @@ add_arg (GlslShaderState *glsl_shader_state,
|
|||
switch (src)
|
||||
{
|
||||
case COGL_PIPELINE_COMBINE_SOURCE_TEXTURE:
|
||||
add_texture_lookup (glsl_shader_state,
|
||||
add_texture_lookup (shader_state,
|
||||
pipeline,
|
||||
layer,
|
||||
swizzle);
|
||||
break;
|
||||
|
||||
case COGL_PIPELINE_COMBINE_SOURCE_CONSTANT:
|
||||
add_constant_lookup (glsl_shader_state,
|
||||
add_constant_lookup (shader_state,
|
||||
pipeline,
|
||||
layer,
|
||||
swizzle);
|
||||
|
@ -521,7 +476,7 @@ add_arg (GlslShaderState *glsl_shader_state,
|
|||
find_pipeline_layer_cb,
|
||||
&data);
|
||||
|
||||
add_texture_lookup (glsl_shader_state,
|
||||
add_texture_lookup (shader_state,
|
||||
pipeline,
|
||||
data.layer,
|
||||
swizzle);
|
||||
|
@ -540,40 +495,40 @@ append_masked_combine (CoglPipeline *pipeline,
|
|||
CoglPipelineCombineSource *src,
|
||||
CoglPipelineCombineOp *op)
|
||||
{
|
||||
GlslShaderState *glsl_shader_state = get_glsl_shader_state (pipeline);
|
||||
GString *shader_source = glsl_shader_state->source;
|
||||
CoglPipelineShaderState *shader_state = get_shader_state (pipeline);
|
||||
GString *shader_source = shader_state->source;
|
||||
|
||||
g_string_append_printf (glsl_shader_state->source,
|
||||
g_string_append_printf (shader_state->source,
|
||||
" cogl_color_out.%s = ", swizzle);
|
||||
|
||||
switch (function)
|
||||
{
|
||||
case COGL_PIPELINE_COMBINE_FUNC_REPLACE:
|
||||
add_arg (glsl_shader_state, pipeline, layer,
|
||||
add_arg (shader_state, pipeline, layer,
|
||||
src[0], op[0], swizzle);
|
||||
break;
|
||||
|
||||
case COGL_PIPELINE_COMBINE_FUNC_MODULATE:
|
||||
add_arg (glsl_shader_state, pipeline, layer,
|
||||
add_arg (shader_state, pipeline, layer,
|
||||
src[0], op[0], swizzle);
|
||||
g_string_append (shader_source, " * ");
|
||||
add_arg (glsl_shader_state, pipeline, layer,
|
||||
add_arg (shader_state, pipeline, layer,
|
||||
src[1], op[1], swizzle);
|
||||
break;
|
||||
|
||||
case COGL_PIPELINE_COMBINE_FUNC_ADD:
|
||||
add_arg (glsl_shader_state, pipeline, layer,
|
||||
add_arg (shader_state, pipeline, layer,
|
||||
src[0], op[0], swizzle);
|
||||
g_string_append (shader_source, " + ");
|
||||
add_arg (glsl_shader_state, pipeline, layer,
|
||||
add_arg (shader_state, pipeline, layer,
|
||||
src[1], op[1], swizzle);
|
||||
break;
|
||||
|
||||
case COGL_PIPELINE_COMBINE_FUNC_ADD_SIGNED:
|
||||
add_arg (glsl_shader_state, pipeline, layer,
|
||||
add_arg (shader_state, pipeline, layer,
|
||||
src[0], op[0], swizzle);
|
||||
g_string_append (shader_source, " + ");
|
||||
add_arg (glsl_shader_state, pipeline, layer,
|
||||
add_arg (shader_state, pipeline, layer,
|
||||
src[1], op[1], swizzle);
|
||||
g_string_append_printf (shader_source,
|
||||
" - vec4(0.5, 0.5, 0.5, 0.5).%s",
|
||||
|
@ -581,26 +536,26 @@ append_masked_combine (CoglPipeline *pipeline,
|
|||
break;
|
||||
|
||||
case COGL_PIPELINE_COMBINE_FUNC_SUBTRACT:
|
||||
add_arg (glsl_shader_state, pipeline, layer,
|
||||
add_arg (shader_state, pipeline, layer,
|
||||
src[0], op[0], swizzle);
|
||||
g_string_append (shader_source, " - ");
|
||||
add_arg (glsl_shader_state, pipeline, layer,
|
||||
add_arg (shader_state, pipeline, layer,
|
||||
src[1], op[1], swizzle);
|
||||
break;
|
||||
|
||||
case COGL_PIPELINE_COMBINE_FUNC_INTERPOLATE:
|
||||
add_arg (glsl_shader_state, pipeline, layer,
|
||||
add_arg (shader_state, pipeline, layer,
|
||||
src[0], op[0], swizzle);
|
||||
g_string_append (shader_source, " * ");
|
||||
add_arg (glsl_shader_state, pipeline, layer,
|
||||
add_arg (shader_state, pipeline, layer,
|
||||
src[2], op[2], swizzle);
|
||||
g_string_append (shader_source, " + ");
|
||||
add_arg (glsl_shader_state, pipeline, layer,
|
||||
add_arg (shader_state, pipeline, layer,
|
||||
src[1], op[1], swizzle);
|
||||
g_string_append_printf (shader_source,
|
||||
" * (vec4(1.0, 1.0, 1.0, 1.0).%s - ",
|
||||
swizzle);
|
||||
add_arg (glsl_shader_state, pipeline, layer,
|
||||
add_arg (shader_state, pipeline, layer,
|
||||
src[2], op[2], swizzle);
|
||||
g_string_append_c (shader_source, ')');
|
||||
break;
|
||||
|
@ -608,22 +563,22 @@ append_masked_combine (CoglPipeline *pipeline,
|
|||
case COGL_PIPELINE_COMBINE_FUNC_DOT3_RGB:
|
||||
case COGL_PIPELINE_COMBINE_FUNC_DOT3_RGBA:
|
||||
g_string_append (shader_source, "vec4(4.0 * ((");
|
||||
add_arg (glsl_shader_state, pipeline, layer,
|
||||
add_arg (shader_state, pipeline, layer,
|
||||
src[0], op[0], "r");
|
||||
g_string_append (shader_source, " - 0.5) * (");
|
||||
add_arg (glsl_shader_state, pipeline, layer,
|
||||
add_arg (shader_state, pipeline, layer,
|
||||
src[1], op[1], "r");
|
||||
g_string_append (shader_source, " - 0.5) + (");
|
||||
add_arg (glsl_shader_state, pipeline, layer,
|
||||
add_arg (shader_state, pipeline, layer,
|
||||
src[0], op[0], "g");
|
||||
g_string_append (shader_source, " - 0.5) * (");
|
||||
add_arg (glsl_shader_state, pipeline, layer,
|
||||
add_arg (shader_state, pipeline, layer,
|
||||
src[1], op[1], "g");
|
||||
g_string_append (shader_source, " - 0.5) + (");
|
||||
add_arg (glsl_shader_state, pipeline, layer,
|
||||
add_arg (shader_state, pipeline, layer,
|
||||
src[0], op[0], "b");
|
||||
g_string_append (shader_source, " - 0.5) * (");
|
||||
add_arg (glsl_shader_state, pipeline, layer,
|
||||
add_arg (shader_state, pipeline, layer,
|
||||
src[1], op[1], "b");
|
||||
g_string_append_printf (shader_source, " - 0.5))).%s", swizzle);
|
||||
break;
|
||||
|
@ -637,13 +592,13 @@ _cogl_pipeline_fragend_glsl_add_layer (CoglPipeline *pipeline,
|
|||
CoglPipelineLayer *layer,
|
||||
unsigned long layers_difference)
|
||||
{
|
||||
GlslShaderState *glsl_shader_state = get_glsl_shader_state (pipeline);
|
||||
CoglPipelineShaderState *shader_state = get_shader_state (pipeline);
|
||||
CoglPipelineLayer *combine_authority =
|
||||
_cogl_pipeline_layer_get_authority (layer,
|
||||
COGL_PIPELINE_LAYER_STATE_COMBINE);
|
||||
CoglPipelineLayerBigState *big_state = combine_authority->big_state;
|
||||
|
||||
if (!glsl_shader_state->source)
|
||||
if (!shader_state->source)
|
||||
return TRUE;
|
||||
|
||||
if (!_cogl_pipeline_need_texture_combine_separate (combine_authority) ||
|
||||
|
@ -680,12 +635,12 @@ _cogl_pipeline_fragend_glsl_add_layer (CoglPipeline *pipeline,
|
|||
gboolean
|
||||
_cogl_pipeline_fragend_glsl_passthrough (CoglPipeline *pipeline)
|
||||
{
|
||||
GlslShaderState *glsl_shader_state = get_glsl_shader_state (pipeline);
|
||||
CoglPipelineShaderState *shader_state = get_shader_state (pipeline);
|
||||
|
||||
if (!glsl_shader_state->source)
|
||||
if (!shader_state->source)
|
||||
return TRUE;
|
||||
|
||||
g_string_append (glsl_shader_state->source,
|
||||
g_string_append (shader_state->source,
|
||||
" cogl_color_out = cogl_color_in;\n");
|
||||
|
||||
return TRUE;
|
||||
|
@ -698,7 +653,7 @@ _cogl_pipeline_fragend_glsl_passthrough (CoglPipeline *pipeline)
|
|||
|
||||
static void
|
||||
add_alpha_test_snippet (CoglPipeline *pipeline,
|
||||
GlslShaderState *glsl_shader_state)
|
||||
CoglPipelineShaderState *shader_state)
|
||||
{
|
||||
CoglPipelineAlphaFunc alpha_func;
|
||||
|
||||
|
@ -711,7 +666,7 @@ add_alpha_test_snippet (CoglPipeline *pipeline,
|
|||
if (alpha_func == COGL_PIPELINE_ALPHA_FUNC_NEVER)
|
||||
{
|
||||
/* Always discard the fragment */
|
||||
g_string_append (glsl_shader_state->source,
|
||||
g_string_append (shader_state->source,
|
||||
" discard;\n");
|
||||
return;
|
||||
}
|
||||
|
@ -719,31 +674,31 @@ add_alpha_test_snippet (CoglPipeline *pipeline,
|
|||
/* For all of the other alpha functions we need a uniform for the
|
||||
reference */
|
||||
|
||||
g_string_append (glsl_shader_state->header,
|
||||
g_string_append (shader_state->header,
|
||||
"uniform float _cogl_alpha_test_ref;\n");
|
||||
|
||||
g_string_append (glsl_shader_state->source,
|
||||
g_string_append (shader_state->source,
|
||||
" if (cogl_color_out.a ");
|
||||
|
||||
switch (alpha_func)
|
||||
{
|
||||
case COGL_PIPELINE_ALPHA_FUNC_LESS:
|
||||
g_string_append (glsl_shader_state->source, ">=");
|
||||
g_string_append (shader_state->source, ">=");
|
||||
break;
|
||||
case COGL_PIPELINE_ALPHA_FUNC_EQUAL:
|
||||
g_string_append (glsl_shader_state->source, "!=");
|
||||
g_string_append (shader_state->source, "!=");
|
||||
break;
|
||||
case COGL_PIPELINE_ALPHA_FUNC_LEQUAL:
|
||||
g_string_append (glsl_shader_state->source, ">");
|
||||
g_string_append (shader_state->source, ">");
|
||||
break;
|
||||
case COGL_PIPELINE_ALPHA_FUNC_GREATER:
|
||||
g_string_append (glsl_shader_state->source, "<=");
|
||||
g_string_append (shader_state->source, "<=");
|
||||
break;
|
||||
case COGL_PIPELINE_ALPHA_FUNC_NOTEQUAL:
|
||||
g_string_append (glsl_shader_state->source, "==");
|
||||
g_string_append (shader_state->source, "==");
|
||||
break;
|
||||
case COGL_PIPELINE_ALPHA_FUNC_GEQUAL:
|
||||
g_string_append (glsl_shader_state->source, "< ");
|
||||
g_string_append (shader_state->source, "< ");
|
||||
break;
|
||||
|
||||
case COGL_PIPELINE_ALPHA_FUNC_ALWAYS:
|
||||
|
@ -752,7 +707,7 @@ add_alpha_test_snippet (CoglPipeline *pipeline,
|
|||
break;
|
||||
}
|
||||
|
||||
g_string_append (glsl_shader_state->source,
|
||||
g_string_append (shader_state->source,
|
||||
" _cogl_alpha_test_ref)\n discard;\n");
|
||||
}
|
||||
|
||||
|
@ -762,11 +717,11 @@ gboolean
|
|||
_cogl_pipeline_fragend_glsl_end (CoglPipeline *pipeline,
|
||||
unsigned long pipelines_difference)
|
||||
{
|
||||
GlslShaderState *glsl_shader_state = get_glsl_shader_state (pipeline);
|
||||
CoglPipelineShaderState *shader_state = get_shader_state (pipeline);
|
||||
|
||||
_COGL_GET_CONTEXT (ctx, FALSE);
|
||||
|
||||
if (glsl_shader_state->source)
|
||||
if (shader_state->source)
|
||||
{
|
||||
const char *source_strings[2];
|
||||
GLint lengths[2];
|
||||
|
@ -784,23 +739,23 @@ _cogl_pipeline_fragend_glsl_end (CoglPipeline *pipeline,
|
|||
|
||||
#ifdef HAVE_COGL_GLES2
|
||||
if (ctx->driver == COGL_DRIVER_GLES2)
|
||||
add_alpha_test_snippet (pipeline, glsl_shader_state);
|
||||
add_alpha_test_snippet (pipeline, shader_state);
|
||||
#endif
|
||||
|
||||
g_string_append (glsl_shader_state->source, "}\n");
|
||||
g_string_append (shader_state->source, "}\n");
|
||||
|
||||
GE_RET( shader, ctx, glCreateShader (GL_FRAGMENT_SHADER) );
|
||||
|
||||
lengths[0] = glsl_shader_state->header->len;
|
||||
source_strings[0] = glsl_shader_state->header->str;
|
||||
lengths[1] = glsl_shader_state->source->len;
|
||||
source_strings[1] = glsl_shader_state->source->str;
|
||||
lengths[0] = shader_state->header->len;
|
||||
source_strings[0] = shader_state->header->str;
|
||||
lengths[1] = shader_state->source->len;
|
||||
source_strings[1] = shader_state->source->str;
|
||||
|
||||
/* Find the highest texture unit that is sampled to pass as the
|
||||
number of texture coordinate attributes */
|
||||
n_layers = cogl_pipeline_get_n_layers (pipeline);
|
||||
for (i = 0; i < n_layers; i++)
|
||||
if (glsl_shader_state->unit_state[i].sampled)
|
||||
if (shader_state->unit_state[i].sampled)
|
||||
n_tex_coord_attribs = i + 1;
|
||||
|
||||
_cogl_shader_set_source_with_boilerplate (shader, GL_FRAGMENT_SHADER,
|
||||
|
@ -822,9 +777,9 @@ _cogl_pipeline_fragend_glsl_end (CoglPipeline *pipeline,
|
|||
g_warning ("Shader compilation failed:\n%s", shader_log);
|
||||
}
|
||||
|
||||
glsl_shader_state->header = NULL;
|
||||
glsl_shader_state->source = NULL;
|
||||
glsl_shader_state->gl_shader = shader;
|
||||
shader_state->header = NULL;
|
||||
shader_state->source = NULL;
|
||||
shader_state->gl_shader = shader;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
|
@ -838,7 +793,7 @@ _cogl_pipeline_fragend_glsl_pre_change_notify (CoglPipeline *pipeline,
|
|||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
|
||||
if ((change & _cogl_pipeline_get_state_for_fragment_codegen (ctx)))
|
||||
dirty_glsl_shader_state (pipeline);
|
||||
dirty_shader_state (pipeline);
|
||||
}
|
||||
|
||||
/* NB: layers are considered immutable once they have any dependants
|
||||
|
@ -855,17 +810,11 @@ _cogl_pipeline_fragend_glsl_layer_pre_change_notify (
|
|||
CoglPipelineLayer *layer,
|
||||
CoglPipelineLayerState change)
|
||||
{
|
||||
CoglPipelineFragendGlslPrivate *priv;
|
||||
|
||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
|
||||
priv = get_glsl_priv (owner);
|
||||
if (!priv)
|
||||
return;
|
||||
|
||||
if ((change & _cogl_pipeline_get_layer_state_for_fragment_codegen (ctx)))
|
||||
{
|
||||
dirty_glsl_shader_state (owner);
|
||||
dirty_shader_state (owner);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -874,19 +823,6 @@ _cogl_pipeline_fragend_glsl_layer_pre_change_notify (
|
|||
* the snippet. */
|
||||
}
|
||||
|
||||
static void
|
||||
_cogl_pipeline_fragend_glsl_free_priv (CoglPipeline *pipeline)
|
||||
{
|
||||
CoglPipelineFragendGlslPrivate *priv = get_glsl_priv (pipeline);
|
||||
if (priv)
|
||||
{
|
||||
if (priv->glsl_shader_state)
|
||||
glsl_shader_state_unref (priv->glsl_shader_state);
|
||||
g_slice_free (CoglPipelineFragendGlslPrivate, priv);
|
||||
set_glsl_priv (pipeline, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
const CoglPipelineFragend _cogl_pipeline_glsl_fragend =
|
||||
{
|
||||
_cogl_pipeline_fragend_glsl_start,
|
||||
|
@ -895,8 +831,7 @@ const CoglPipelineFragend _cogl_pipeline_glsl_fragend =
|
|||
_cogl_pipeline_fragend_glsl_end,
|
||||
_cogl_pipeline_fragend_glsl_pre_change_notify,
|
||||
NULL, /* pipeline_set_parent_notify */
|
||||
_cogl_pipeline_fragend_glsl_layer_pre_change_notify,
|
||||
_cogl_pipeline_fragend_glsl_free_priv,
|
||||
_cogl_pipeline_fragend_glsl_layer_pre_change_notify
|
||||
};
|
||||
|
||||
#endif /* COGL_PIPELINE_FRAGEND_GLSL */
|
||||
|
|
|
@ -649,10 +649,6 @@ struct _CoglPipeline
|
|||
* pipeline in comparison to its parent. */
|
||||
unsigned long differences;
|
||||
|
||||
/* The fragment processing backends can associate private data with a
|
||||
* pipeline. */
|
||||
void *fragend_privs[COGL_PIPELINE_N_FRAGENDS];
|
||||
|
||||
/* Whenever a pipeline is modified we increment the age. There's no
|
||||
* guarantee that it won't wrap but it can nevertheless be a
|
||||
* convenient mechanism to determine when a pipeline has been
|
||||
|
@ -704,17 +700,6 @@ struct _CoglPipeline
|
|||
|
||||
/* bitfields */
|
||||
|
||||
/* A pipeline can have private data associated with it for multiple
|
||||
* fragment processing backends. Although only one backend is
|
||||
* associated with a pipeline the backends may want to cache private
|
||||
* state with the ancestors of other pipelines and those ancestors
|
||||
* could currently be associated with different backends.
|
||||
*
|
||||
* Each set bit indicates if the corresponding ->fragend_privs[]
|
||||
* entry is valid.
|
||||
*/
|
||||
unsigned int fragend_priv_set_mask:COGL_PIPELINE_N_FRAGENDS;
|
||||
|
||||
/* Weak pipelines don't count as dependants on their parents which
|
||||
* means that the parent pipeline can be modified without
|
||||
* considering how the modifications may affect the weak pipeline.
|
||||
|
@ -771,8 +756,6 @@ typedef struct _CoglPipelineFragend
|
|||
void (*layer_pre_change_notify) (CoglPipeline *owner,
|
||||
CoglPipelineLayer *layer,
|
||||
CoglPipelineLayerState change);
|
||||
|
||||
void (*free_priv) (CoglPipeline *pipeline);
|
||||
} CoglPipelineFragend;
|
||||
|
||||
typedef struct _CoglPipelineVertend
|
||||
|
|
|
@ -138,14 +138,14 @@ typedef struct
|
|||
CoglPipeline *last_used_for_pipeline;
|
||||
|
||||
UnitState *unit_state;
|
||||
} CoglPipelineProgendPrivate;
|
||||
} CoglPipelineProgramState;
|
||||
|
||||
static CoglUserDataKey glsl_priv_key;
|
||||
static CoglUserDataKey program_state_key;
|
||||
|
||||
static CoglPipelineProgendPrivate *
|
||||
get_glsl_priv (CoglPipeline *pipeline)
|
||||
static CoglPipelineProgramState *
|
||||
get_program_state (CoglPipeline *pipeline)
|
||||
{
|
||||
return cogl_object_get_user_data (COGL_OBJECT (pipeline), &glsl_priv_key);
|
||||
return cogl_object_get_user_data (COGL_OBJECT (pipeline), &program_state_key);
|
||||
}
|
||||
|
||||
#ifdef HAVE_COGL_GLES2
|
||||
|
@ -162,96 +162,101 @@ get_glsl_priv (CoglPipeline *pipeline)
|
|||
int
|
||||
_cogl_pipeline_progend_glsl_get_position_attribute (CoglPipeline *pipeline)
|
||||
{
|
||||
CoglPipelineProgendPrivate *priv = get_glsl_priv (pipeline);
|
||||
CoglPipelineProgramState *program_state = get_program_state (pipeline);
|
||||
|
||||
_COGL_GET_CONTEXT (ctx, -1);
|
||||
|
||||
g_return_val_if_fail (priv != NULL, -1);
|
||||
g_return_val_if_fail (priv->program != 0, -1);
|
||||
g_return_val_if_fail (program_state != NULL, -1);
|
||||
g_return_val_if_fail (program_state->program != 0, -1);
|
||||
|
||||
if (priv->position_attribute_location == ATTRIBUTE_LOCATION_UNKNOWN)
|
||||
GE_RET( priv->position_attribute_location,
|
||||
ctx, glGetAttribLocation (priv->program, "cogl_position_in") );
|
||||
if (program_state->position_attribute_location == ATTRIBUTE_LOCATION_UNKNOWN)
|
||||
GE_RET( program_state->position_attribute_location,
|
||||
ctx, glGetAttribLocation (program_state->program,
|
||||
"cogl_position_in") );
|
||||
|
||||
return priv->position_attribute_location;
|
||||
return program_state->position_attribute_location;
|
||||
}
|
||||
|
||||
int
|
||||
_cogl_pipeline_progend_glsl_get_color_attribute (CoglPipeline *pipeline)
|
||||
{
|
||||
CoglPipelineProgendPrivate *priv = get_glsl_priv (pipeline);
|
||||
CoglPipelineProgramState *program_state = get_program_state (pipeline);
|
||||
|
||||
_COGL_GET_CONTEXT (ctx, -1);
|
||||
|
||||
g_return_val_if_fail (priv != NULL, -1);
|
||||
g_return_val_if_fail (priv->program != 0, -1);
|
||||
g_return_val_if_fail (program_state != NULL, -1);
|
||||
g_return_val_if_fail (program_state->program != 0, -1);
|
||||
|
||||
if (priv->color_attribute_location == ATTRIBUTE_LOCATION_UNKNOWN)
|
||||
GE_RET( priv->color_attribute_location,
|
||||
ctx, glGetAttribLocation (priv->program, "cogl_color_in") );
|
||||
if (program_state->color_attribute_location == ATTRIBUTE_LOCATION_UNKNOWN)
|
||||
GE_RET( program_state->color_attribute_location,
|
||||
ctx, glGetAttribLocation (program_state->program,
|
||||
"cogl_color_in") );
|
||||
|
||||
return priv->color_attribute_location;
|
||||
return program_state->color_attribute_location;
|
||||
}
|
||||
|
||||
int
|
||||
_cogl_pipeline_progend_glsl_get_normal_attribute (CoglPipeline *pipeline)
|
||||
{
|
||||
CoglPipelineProgendPrivate *priv = get_glsl_priv (pipeline);
|
||||
CoglPipelineProgramState *program_state = get_program_state (pipeline);
|
||||
|
||||
_COGL_GET_CONTEXT (ctx, -1);
|
||||
|
||||
g_return_val_if_fail (priv != NULL, -1);
|
||||
g_return_val_if_fail (priv->program != 0, -1);
|
||||
g_return_val_if_fail (program_state != NULL, -1);
|
||||
g_return_val_if_fail (program_state->program != 0, -1);
|
||||
|
||||
if (priv->normal_attribute_location == ATTRIBUTE_LOCATION_UNKNOWN)
|
||||
GE_RET( priv->normal_attribute_location,
|
||||
ctx, glGetAttribLocation (priv->program, "cogl_normal_in") );
|
||||
if (program_state->normal_attribute_location == ATTRIBUTE_LOCATION_UNKNOWN)
|
||||
GE_RET( program_state->normal_attribute_location,
|
||||
ctx, glGetAttribLocation (program_state->program,
|
||||
"cogl_normal_in") );
|
||||
|
||||
return priv->normal_attribute_location;
|
||||
return program_state->normal_attribute_location;
|
||||
}
|
||||
|
||||
int
|
||||
_cogl_pipeline_progend_glsl_get_tex_coord_attribute (CoglPipeline *pipeline,
|
||||
int unit)
|
||||
{
|
||||
CoglPipelineProgendPrivate *priv = get_glsl_priv (pipeline);
|
||||
CoglPipelineProgramState *program_state = get_program_state (pipeline);
|
||||
|
||||
_COGL_GET_CONTEXT (ctx, -1);
|
||||
|
||||
g_return_val_if_fail (priv != NULL, -1);
|
||||
g_return_val_if_fail (priv->program != 0, -1);
|
||||
g_return_val_if_fail (program_state != NULL, -1);
|
||||
g_return_val_if_fail (program_state->program != 0, -1);
|
||||
|
||||
if (unit == 0)
|
||||
{
|
||||
if (priv->tex_coord0_attribute_location == ATTRIBUTE_LOCATION_UNKNOWN)
|
||||
GE_RET( priv->tex_coord0_attribute_location,
|
||||
ctx, glGetAttribLocation (priv->program,
|
||||
if (program_state->tex_coord0_attribute_location ==
|
||||
ATTRIBUTE_LOCATION_UNKNOWN)
|
||||
GE_RET( program_state->tex_coord0_attribute_location,
|
||||
ctx, glGetAttribLocation (program_state->program,
|
||||
"cogl_tex_coord0_in") );
|
||||
|
||||
return priv->tex_coord0_attribute_location;
|
||||
return program_state->tex_coord0_attribute_location;
|
||||
}
|
||||
else
|
||||
{
|
||||
char *name = g_strdup_printf ("cogl_tex_coord%i_in", unit);
|
||||
int *locations;
|
||||
|
||||
if (priv->tex_coord_attribute_locations == NULL)
|
||||
priv->tex_coord_attribute_locations = g_array_new (FALSE, FALSE,
|
||||
sizeof (int));
|
||||
if (priv->tex_coord_attribute_locations->len <= unit - 1)
|
||||
if (program_state->tex_coord_attribute_locations == NULL)
|
||||
program_state->tex_coord_attribute_locations =
|
||||
g_array_new (FALSE, FALSE, sizeof (int));
|
||||
if (program_state->tex_coord_attribute_locations->len <= unit - 1)
|
||||
{
|
||||
int i = priv->tex_coord_attribute_locations->len;
|
||||
g_array_set_size (priv->tex_coord_attribute_locations, unit);
|
||||
int i = program_state->tex_coord_attribute_locations->len;
|
||||
g_array_set_size (program_state->tex_coord_attribute_locations, unit);
|
||||
for (; i < unit; i++)
|
||||
g_array_index (priv->tex_coord_attribute_locations, int, i) =
|
||||
ATTRIBUTE_LOCATION_UNKNOWN;
|
||||
g_array_index (program_state->tex_coord_attribute_locations, int, i)
|
||||
= ATTRIBUTE_LOCATION_UNKNOWN;
|
||||
}
|
||||
|
||||
locations = &g_array_index (priv->tex_coord_attribute_locations, int, 0);
|
||||
locations = &g_array_index (program_state->tex_coord_attribute_locations,
|
||||
int, 0);
|
||||
|
||||
if (locations[unit - 1] == ATTRIBUTE_LOCATION_UNKNOWN)
|
||||
GE_RET( locations[unit - 1],
|
||||
ctx, glGetAttribLocation (priv->program, name) );
|
||||
ctx, glGetAttribLocation (program_state->program, name) );
|
||||
|
||||
g_free (name);
|
||||
|
||||
|
@ -260,79 +265,100 @@ _cogl_pipeline_progend_glsl_get_tex_coord_attribute (CoglPipeline *pipeline,
|
|||
}
|
||||
|
||||
static void
|
||||
clear_attribute_cache (CoglPipelineProgendPrivate *priv)
|
||||
clear_attribute_cache (CoglPipelineProgramState *program_state)
|
||||
{
|
||||
priv->position_attribute_location = ATTRIBUTE_LOCATION_UNKNOWN;
|
||||
priv->color_attribute_location = ATTRIBUTE_LOCATION_UNKNOWN;
|
||||
priv->normal_attribute_location = ATTRIBUTE_LOCATION_UNKNOWN;
|
||||
priv->tex_coord0_attribute_location = ATTRIBUTE_LOCATION_UNKNOWN;
|
||||
if (priv->tex_coord_attribute_locations)
|
||||
program_state->position_attribute_location = ATTRIBUTE_LOCATION_UNKNOWN;
|
||||
program_state->color_attribute_location = ATTRIBUTE_LOCATION_UNKNOWN;
|
||||
program_state->normal_attribute_location = ATTRIBUTE_LOCATION_UNKNOWN;
|
||||
program_state->tex_coord0_attribute_location = ATTRIBUTE_LOCATION_UNKNOWN;
|
||||
if (program_state->tex_coord_attribute_locations)
|
||||
{
|
||||
g_array_free (priv->tex_coord_attribute_locations, TRUE);
|
||||
priv->tex_coord_attribute_locations = NULL;
|
||||
g_array_free (program_state->tex_coord_attribute_locations, TRUE);
|
||||
program_state->tex_coord_attribute_locations = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
clear_flushed_matrix_stacks (CoglPipelineProgendPrivate *priv)
|
||||
clear_flushed_matrix_stacks (CoglPipelineProgramState *program_state)
|
||||
{
|
||||
if (priv->flushed_modelview_stack)
|
||||
if (program_state->flushed_modelview_stack)
|
||||
{
|
||||
cogl_object_unref (priv->flushed_modelview_stack);
|
||||
priv->flushed_modelview_stack = NULL;
|
||||
cogl_object_unref (program_state->flushed_modelview_stack);
|
||||
program_state->flushed_modelview_stack = NULL;
|
||||
}
|
||||
if (priv->flushed_projection_stack)
|
||||
if (program_state->flushed_projection_stack)
|
||||
{
|
||||
cogl_object_unref (priv->flushed_projection_stack);
|
||||
priv->flushed_projection_stack = NULL;
|
||||
cogl_object_unref (program_state->flushed_projection_stack);
|
||||
program_state->flushed_projection_stack = NULL;
|
||||
}
|
||||
priv->flushed_modelview_is_identity = FALSE;
|
||||
program_state->flushed_modelview_is_identity = FALSE;
|
||||
}
|
||||
|
||||
#endif /* HAVE_COGL_GLES2 */
|
||||
|
||||
static void
|
||||
destroy_glsl_priv (void *user_data)
|
||||
static CoglPipelineProgramState *
|
||||
program_state_new (int n_layers)
|
||||
{
|
||||
CoglPipelineProgendPrivate *priv = user_data;
|
||||
CoglPipelineProgramState *program_state;
|
||||
|
||||
program_state = g_slice_new (CoglPipelineProgramState);
|
||||
program_state->ref_count = 1;
|
||||
program_state->program = 0;
|
||||
program_state->n_tex_coord_attribs = 0;
|
||||
program_state->unit_state = g_new (UnitState, n_layers);
|
||||
#ifdef HAVE_COGL_GLES2
|
||||
program_state->tex_coord_attribute_locations = NULL;
|
||||
program_state->flushed_modelview_stack = NULL;
|
||||
program_state->flushed_modelview_is_identity = FALSE;
|
||||
program_state->flushed_projection_stack = NULL;
|
||||
#endif
|
||||
|
||||
return program_state;
|
||||
}
|
||||
|
||||
static void
|
||||
destroy_program_state (void *user_data)
|
||||
{
|
||||
CoglPipelineProgramState *program_state = user_data;
|
||||
|
||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
|
||||
if (--priv->ref_count == 0)
|
||||
if (--program_state->ref_count == 0)
|
||||
{
|
||||
#ifdef HAVE_COGL_GLES2
|
||||
if (ctx->driver == COGL_DRIVER_GLES2)
|
||||
{
|
||||
clear_attribute_cache (priv);
|
||||
clear_flushed_matrix_stacks (priv);
|
||||
clear_attribute_cache (program_state);
|
||||
clear_flushed_matrix_stacks (program_state);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (priv->program)
|
||||
GE( ctx, glDeleteProgram (priv->program) );
|
||||
if (program_state->program)
|
||||
GE( ctx, glDeleteProgram (program_state->program) );
|
||||
|
||||
g_free (priv->unit_state);
|
||||
g_free (program_state->unit_state);
|
||||
|
||||
g_slice_free (CoglPipelineProgendPrivate, priv);
|
||||
g_slice_free (CoglPipelineProgramState, program_state);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
set_glsl_priv (CoglPipeline *pipeline, CoglPipelineProgendPrivate *priv)
|
||||
set_program_state (CoglPipeline *pipeline,
|
||||
CoglPipelineProgramState *program_state)
|
||||
{
|
||||
cogl_object_set_user_data (COGL_OBJECT (pipeline),
|
||||
&glsl_priv_key,
|
||||
priv,
|
||||
destroy_glsl_priv);
|
||||
&program_state_key,
|
||||
program_state,
|
||||
destroy_program_state);
|
||||
}
|
||||
|
||||
static void
|
||||
dirty_glsl_program_state (CoglPipeline *pipeline)
|
||||
dirty_program_state (CoglPipeline *pipeline)
|
||||
{
|
||||
cogl_object_set_user_data (COGL_OBJECT (pipeline),
|
||||
&glsl_priv_key,
|
||||
&program_state_key,
|
||||
NULL,
|
||||
destroy_glsl_priv);
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -371,7 +397,7 @@ typedef struct
|
|||
int unit;
|
||||
GLuint gl_program;
|
||||
gboolean update_all;
|
||||
CoglPipelineProgendPrivate *priv;
|
||||
CoglPipelineProgramState *program_state;
|
||||
} UpdateUniformsState;
|
||||
|
||||
static gboolean
|
||||
|
@ -380,8 +406,8 @@ get_uniform_cb (CoglPipeline *pipeline,
|
|||
void *user_data)
|
||||
{
|
||||
UpdateUniformsState *state = user_data;
|
||||
CoglPipelineProgendPrivate *priv = state->priv;
|
||||
UnitState *unit_state = &priv->unit_state[state->unit];
|
||||
CoglPipelineProgramState *program_state = state->program_state;
|
||||
UnitState *unit_state = &program_state->unit_state[state->unit];
|
||||
GLint uniform_location;
|
||||
|
||||
_COGL_GET_CONTEXT (ctx, FALSE);
|
||||
|
@ -439,8 +465,8 @@ update_constants_cb (CoglPipeline *pipeline,
|
|||
void *user_data)
|
||||
{
|
||||
UpdateUniformsState *state = user_data;
|
||||
CoglPipelineProgendPrivate *priv = state->priv;
|
||||
UnitState *unit_state = &priv->unit_state[state->unit++];
|
||||
CoglPipelineProgramState *program_state = state->program_state;
|
||||
UnitState *unit_state = &program_state->unit_state[state->unit++];
|
||||
|
||||
_COGL_GET_CONTEXT (ctx, FALSE);
|
||||
|
||||
|
@ -482,21 +508,22 @@ update_constants_cb (CoglPipeline *pipeline,
|
|||
static void
|
||||
update_builtin_uniforms (CoglPipeline *pipeline,
|
||||
GLuint gl_program,
|
||||
CoglPipelineProgendPrivate *priv)
|
||||
CoglPipelineProgramState *program_state)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (priv->dirty_builtin_uniforms == 0)
|
||||
if (program_state->dirty_builtin_uniforms == 0)
|
||||
return;
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (builtin_uniforms); i++)
|
||||
if ((priv->dirty_builtin_uniforms & (1 << i)) &&
|
||||
priv->builtin_uniform_locations[i] != -1)
|
||||
if ((program_state->dirty_builtin_uniforms & (1 << i)) &&
|
||||
program_state->builtin_uniform_locations[i] != -1)
|
||||
builtin_uniforms[i].update_func (pipeline,
|
||||
priv->builtin_uniform_locations[i],
|
||||
program_state
|
||||
->builtin_uniform_locations[i],
|
||||
builtin_uniforms[i].getter_func);
|
||||
|
||||
priv->dirty_builtin_uniforms = 0;
|
||||
program_state->dirty_builtin_uniforms = 0;
|
||||
}
|
||||
|
||||
#endif /* HAVE_COGL_GLES2 */
|
||||
|
@ -506,7 +533,7 @@ _cogl_pipeline_progend_glsl_end (CoglPipeline *pipeline,
|
|||
unsigned long pipelines_difference,
|
||||
int n_tex_coord_attribs)
|
||||
{
|
||||
CoglPipelineProgendPrivate *priv;
|
||||
CoglPipelineProgramState *program_state;
|
||||
GLuint gl_program;
|
||||
gboolean program_changed = FALSE;
|
||||
UpdateUniformsState state;
|
||||
|
@ -520,11 +547,11 @@ _cogl_pipeline_progend_glsl_end (CoglPipeline *pipeline,
|
|||
pipeline->vertend != COGL_PIPELINE_VERTEND_GLSL)
|
||||
return;
|
||||
|
||||
priv = get_glsl_priv (pipeline);
|
||||
program_state = get_program_state (pipeline);
|
||||
|
||||
user_program = cogl_pipeline_get_user_program (pipeline);
|
||||
|
||||
if (priv == NULL)
|
||||
if (program_state == NULL)
|
||||
{
|
||||
CoglPipeline *authority;
|
||||
|
||||
|
@ -539,29 +566,19 @@ _cogl_pipeline_progend_glsl_end (CoglPipeline *pipeline,
|
|||
_cogl_pipeline_get_layer_state_for_fragment_codegen (ctx) |
|
||||
COGL_PIPELINE_LAYER_STATE_AFFECTS_VERTEX_CODEGEN);
|
||||
|
||||
priv = get_glsl_priv (authority);
|
||||
program_state = get_program_state (authority);
|
||||
|
||||
if (priv == NULL)
|
||||
if (program_state == NULL)
|
||||
{
|
||||
priv = g_slice_new (CoglPipelineProgendPrivate);
|
||||
priv->ref_count = 1;
|
||||
priv->program = 0;
|
||||
priv->n_tex_coord_attribs = 0;
|
||||
priv->unit_state = g_new (UnitState,
|
||||
cogl_pipeline_get_n_layers (pipeline));
|
||||
#ifdef HAVE_COGL_GLES2
|
||||
priv->tex_coord_attribute_locations = NULL;
|
||||
priv->flushed_modelview_stack = NULL;
|
||||
priv->flushed_modelview_is_identity = FALSE;
|
||||
priv->flushed_projection_stack = NULL;
|
||||
#endif
|
||||
set_glsl_priv (authority, priv);
|
||||
program_state
|
||||
= program_state_new (cogl_pipeline_get_n_layers (pipeline));
|
||||
set_program_state (authority, program_state);
|
||||
}
|
||||
|
||||
if (authority != pipeline)
|
||||
{
|
||||
priv->ref_count++;
|
||||
set_glsl_priv (pipeline, priv);
|
||||
program_state->ref_count++;
|
||||
set_program_state (pipeline, program_state);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -571,26 +588,26 @@ _cogl_pipeline_progend_glsl_end (CoglPipeline *pipeline,
|
|||
* Also if the number of texture coordinate attributes in use has
|
||||
* increased, then delete the program so we can prepend a new
|
||||
* _cogl_tex_coord[] varying array declaration. */
|
||||
if (priv->program && user_program &&
|
||||
(user_program->age != priv->user_program_age ||
|
||||
n_tex_coord_attribs > priv->n_tex_coord_attribs))
|
||||
if (program_state->program && user_program &&
|
||||
(user_program->age != program_state->user_program_age ||
|
||||
n_tex_coord_attribs > program_state->n_tex_coord_attribs))
|
||||
{
|
||||
GE( ctx, glDeleteProgram (priv->program) );
|
||||
priv->program = 0;
|
||||
GE( ctx, glDeleteProgram (program_state->program) );
|
||||
program_state->program = 0;
|
||||
}
|
||||
|
||||
if (priv->program == 0)
|
||||
if (program_state->program == 0)
|
||||
{
|
||||
GLuint backend_shader;
|
||||
GSList *l;
|
||||
|
||||
GE_RET( priv->program, ctx, glCreateProgram () );
|
||||
GE_RET( program_state->program, ctx, glCreateProgram () );
|
||||
|
||||
/* Attach all of the shader from the user program */
|
||||
if (user_program)
|
||||
{
|
||||
if (priv->n_tex_coord_attribs > n_tex_coord_attribs)
|
||||
n_tex_coord_attribs = priv->n_tex_coord_attribs;
|
||||
if (program_state->n_tex_coord_attribs > n_tex_coord_attribs)
|
||||
n_tex_coord_attribs = program_state->n_tex_coord_attribs;
|
||||
|
||||
#ifdef HAVE_COGL_GLES2
|
||||
/* Find the largest count of texture coordinate attributes
|
||||
|
@ -614,29 +631,29 @@ _cogl_pipeline_progend_glsl_end (CoglPipeline *pipeline,
|
|||
|
||||
g_assert (shader->language == COGL_SHADER_LANGUAGE_GLSL);
|
||||
|
||||
GE( ctx, glAttachShader (priv->program,
|
||||
GE( ctx, glAttachShader (program_state->program,
|
||||
shader->gl_handle) );
|
||||
}
|
||||
|
||||
priv->user_program_age = user_program->age;
|
||||
program_state->user_program_age = user_program->age;
|
||||
}
|
||||
|
||||
/* Attach any shaders from the GLSL backends */
|
||||
if (pipeline->fragend == COGL_PIPELINE_FRAGEND_GLSL &&
|
||||
(backend_shader = _cogl_pipeline_fragend_glsl_get_shader (pipeline)))
|
||||
GE( ctx, glAttachShader (priv->program, backend_shader) );
|
||||
GE( ctx, glAttachShader (program_state->program, backend_shader) );
|
||||
if (pipeline->vertend == COGL_PIPELINE_VERTEND_GLSL &&
|
||||
(backend_shader = _cogl_pipeline_vertend_glsl_get_shader (pipeline)))
|
||||
GE( ctx, glAttachShader (priv->program, backend_shader) );
|
||||
GE( ctx, glAttachShader (program_state->program, backend_shader) );
|
||||
|
||||
link_program (priv->program);
|
||||
link_program (program_state->program);
|
||||
|
||||
program_changed = TRUE;
|
||||
|
||||
priv->n_tex_coord_attribs = n_tex_coord_attribs;
|
||||
program_state->n_tex_coord_attribs = n_tex_coord_attribs;
|
||||
}
|
||||
|
||||
gl_program = priv->program;
|
||||
gl_program = program_state->program;
|
||||
|
||||
if (pipeline->fragend == COGL_PIPELINE_FRAGEND_GLSL)
|
||||
_cogl_use_fragment_program (gl_program, COGL_PIPELINE_PROGRAM_TYPE_GLSL);
|
||||
|
@ -645,7 +662,7 @@ _cogl_pipeline_progend_glsl_end (CoglPipeline *pipeline,
|
|||
|
||||
state.unit = 0;
|
||||
state.gl_program = gl_program;
|
||||
state.priv = priv;
|
||||
state.program_state = program_state;
|
||||
|
||||
if (program_changed)
|
||||
cogl_pipeline_foreach_layer (pipeline,
|
||||
|
@ -654,7 +671,7 @@ _cogl_pipeline_progend_glsl_end (CoglPipeline *pipeline,
|
|||
|
||||
state.unit = 0;
|
||||
state.update_all = (program_changed ||
|
||||
priv->last_used_for_pipeline != pipeline);
|
||||
program_state->last_used_for_pipeline != pipeline);
|
||||
|
||||
cogl_pipeline_foreach_layer (pipeline,
|
||||
update_constants_cb,
|
||||
|
@ -667,33 +684,31 @@ _cogl_pipeline_progend_glsl_end (CoglPipeline *pipeline,
|
|||
{
|
||||
int i;
|
||||
|
||||
clear_attribute_cache (priv);
|
||||
clear_flushed_matrix_stacks (priv);
|
||||
clear_attribute_cache (program_state);
|
||||
clear_flushed_matrix_stacks (program_state);
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (builtin_uniforms); i++)
|
||||
GE_RET( priv->builtin_uniform_locations[i],
|
||||
ctx,
|
||||
GE_RET( program_state->builtin_uniform_locations[i], ctx,
|
||||
glGetUniformLocation (gl_program,
|
||||
builtin_uniforms[i].uniform_name) );
|
||||
|
||||
GE_RET( priv->modelview_uniform,
|
||||
ctx, glGetUniformLocation (gl_program,
|
||||
"cogl_modelview_matrix") );
|
||||
GE_RET( program_state->modelview_uniform, ctx,
|
||||
glGetUniformLocation (gl_program,
|
||||
"cogl_modelview_matrix") );
|
||||
|
||||
GE_RET( priv->projection_uniform,
|
||||
ctx, glGetUniformLocation (gl_program,
|
||||
"cogl_projection_matrix") );
|
||||
GE_RET( program_state->projection_uniform, ctx,
|
||||
glGetUniformLocation (gl_program,
|
||||
"cogl_projection_matrix") );
|
||||
|
||||
GE_RET( priv->mvp_uniform,
|
||||
ctx,
|
||||
GE_RET( program_state->mvp_uniform, ctx,
|
||||
glGetUniformLocation (gl_program,
|
||||
"cogl_modelview_projection_matrix") );
|
||||
}
|
||||
if (program_changed ||
|
||||
priv->last_used_for_pipeline != pipeline)
|
||||
priv->dirty_builtin_uniforms = ~(unsigned long) 0;
|
||||
program_state->last_used_for_pipeline != pipeline)
|
||||
program_state->dirty_builtin_uniforms = ~(unsigned long) 0;
|
||||
|
||||
update_builtin_uniforms (pipeline, gl_program, priv);
|
||||
update_builtin_uniforms (pipeline, gl_program, program_state);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -704,7 +719,7 @@ _cogl_pipeline_progend_glsl_end (CoglPipeline *pipeline,
|
|||
|
||||
/* We need to track the last pipeline that the program was used with
|
||||
* so know if we need to update all of the uniforms */
|
||||
priv->last_used_for_pipeline = pipeline;
|
||||
program_state->last_used_for_pipeline = pipeline;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -715,7 +730,8 @@ _cogl_pipeline_progend_glsl_pre_change_notify (CoglPipeline *pipeline,
|
|||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
|
||||
if ((change & _cogl_pipeline_get_state_for_fragment_codegen (ctx)))
|
||||
dirty_glsl_program_state (pipeline);
|
||||
dirty_program_state (pipeline);
|
||||
|
||||
#ifdef HAVE_COGL_GLES2
|
||||
else if (ctx->driver == COGL_DRIVER_GLES2)
|
||||
{
|
||||
|
@ -724,9 +740,10 @@ _cogl_pipeline_progend_glsl_pre_change_notify (CoglPipeline *pipeline,
|
|||
for (i = 0; i < G_N_ELEMENTS (builtin_uniforms); i++)
|
||||
if ((change & builtin_uniforms[i].change))
|
||||
{
|
||||
CoglPipelineProgendPrivate *priv = get_glsl_priv (pipeline);
|
||||
if (priv)
|
||||
priv->dirty_builtin_uniforms |= 1 << i;
|
||||
CoglPipelineProgramState *program_state
|
||||
= get_program_state (pipeline);
|
||||
if (program_state)
|
||||
program_state->dirty_builtin_uniforms |= 1 << i;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -751,27 +768,27 @@ _cogl_pipeline_progend_glsl_layer_pre_change_notify (
|
|||
|
||||
if ((change & _cogl_pipeline_get_state_for_fragment_codegen (ctx)))
|
||||
{
|
||||
dirty_glsl_program_state (owner);
|
||||
dirty_program_state (owner);
|
||||
return;
|
||||
}
|
||||
|
||||
if (change & COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT)
|
||||
{
|
||||
CoglPipelineProgendPrivate *priv = get_glsl_priv (owner);
|
||||
if (priv)
|
||||
CoglPipelineProgramState *program_state = get_program_state (owner);
|
||||
if (program_state)
|
||||
{
|
||||
int unit_index = _cogl_pipeline_layer_get_unit_index (layer);
|
||||
priv->unit_state[unit_index].dirty_combine_constant = TRUE;
|
||||
program_state->unit_state[unit_index].dirty_combine_constant = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (change & COGL_PIPELINE_LAYER_STATE_USER_MATRIX)
|
||||
{
|
||||
CoglPipelineProgendPrivate *priv = get_glsl_priv (owner);
|
||||
if (priv)
|
||||
CoglPipelineProgramState *program_state = get_program_state (owner);
|
||||
if (program_state)
|
||||
{
|
||||
int unit_index = _cogl_pipeline_layer_get_unit_index (layer);
|
||||
priv->unit_state[unit_index].dirty_texture_matrix = TRUE;
|
||||
program_state->unit_state[unit_index].dirty_texture_matrix = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -783,11 +800,11 @@ flush_modelview_cb (gboolean is_identity,
|
|||
const CoglMatrix *matrix,
|
||||
void *user_data)
|
||||
{
|
||||
CoglPipelineProgendPrivate *priv = user_data;
|
||||
CoglPipelineProgramState *program_state = user_data;
|
||||
|
||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
|
||||
GE( ctx, glUniformMatrix4fv (priv->modelview_uniform, 1, FALSE,
|
||||
GE( ctx, glUniformMatrix4fv (program_state->modelview_uniform, 1, FALSE,
|
||||
cogl_matrix_get_array (matrix)) );
|
||||
}
|
||||
|
||||
|
@ -796,17 +813,17 @@ flush_projection_cb (gboolean is_identity,
|
|||
const CoglMatrix *matrix,
|
||||
void *user_data)
|
||||
{
|
||||
CoglPipelineProgendPrivate *priv = user_data;
|
||||
CoglPipelineProgramState *program_state = user_data;
|
||||
|
||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
|
||||
GE( ctx, glUniformMatrix4fv (priv->projection_uniform, 1, FALSE,
|
||||
GE( ctx, glUniformMatrix4fv (program_state->projection_uniform, 1, FALSE,
|
||||
cogl_matrix_get_array (matrix)) );
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
CoglPipelineProgendPrivate *priv;
|
||||
CoglPipelineProgramState *program_state;
|
||||
const CoglMatrix *projection_matrix;
|
||||
} FlushCombinedData;
|
||||
|
||||
|
@ -825,7 +842,8 @@ flush_combined_step_two_cb (gboolean is_identity,
|
|||
if (is_identity)
|
||||
{
|
||||
const float *array = cogl_matrix_get_array (data->projection_matrix);
|
||||
GE( ctx, glUniformMatrix4fv (data->priv->mvp_uniform, 1, FALSE, array ) );
|
||||
GE( ctx, glUniformMatrix4fv (data->program_state->mvp_uniform,
|
||||
1, FALSE, array ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -833,7 +851,7 @@ flush_combined_step_two_cb (gboolean is_identity,
|
|||
data->projection_matrix,
|
||||
matrix);
|
||||
|
||||
GE( ctx, glUniformMatrix4fv (data->priv->mvp_uniform, 1, FALSE,
|
||||
GE( ctx, glUniformMatrix4fv (data->program_state->mvp_uniform, 1, FALSE,
|
||||
cogl_matrix_get_array (&mvp_matrix)) );
|
||||
}
|
||||
}
|
||||
|
@ -847,7 +865,7 @@ flush_combined_step_one_cb (gboolean is_identity,
|
|||
|
||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
|
||||
data.priv = user_data;
|
||||
data.program_state = user_data;
|
||||
data.projection_matrix = matrix;
|
||||
|
||||
_cogl_matrix_stack_prepare_for_flush (ctx->flushed_modelview_stack,
|
||||
|
@ -859,7 +877,7 @@ flush_combined_step_one_cb (gboolean is_identity,
|
|||
static void
|
||||
_cogl_pipeline_progend_glsl_pre_paint (CoglPipeline *pipeline)
|
||||
{
|
||||
CoglPipelineProgendPrivate *priv = get_glsl_priv (pipeline);
|
||||
CoglPipelineProgramState *program_state = get_program_state (pipeline);
|
||||
gboolean modelview_changed;
|
||||
gboolean projection_changed;
|
||||
|
||||
|
@ -872,7 +890,7 @@ _cogl_pipeline_progend_glsl_pre_paint (CoglPipeline *pipeline)
|
|||
vertend, but this is a requirement on GLES2 anyway */
|
||||
g_return_if_fail (pipeline->vertend == COGL_PIPELINE_VERTEND_GLSL);
|
||||
|
||||
priv = get_glsl_priv (pipeline);
|
||||
program_state = get_program_state (pipeline);
|
||||
|
||||
/* An initial pipeline is flushed while creating the context. At
|
||||
this point there are no matrices flushed so we can't do
|
||||
|
@ -885,59 +903,62 @@ _cogl_pipeline_progend_glsl_pre_paint (CoglPipeline *pipeline)
|
|||
the identity matrix so it makes sense to optimise this case by
|
||||
specifically checking whether we already have the identity matrix
|
||||
which will catch a lot of common cases of redundant flushing */
|
||||
if (priv->flushed_modelview_is_identity &&
|
||||
if (program_state->flushed_modelview_is_identity &&
|
||||
_cogl_matrix_stack_has_identity_flag (ctx->flushed_modelview_stack))
|
||||
modelview_changed = FALSE;
|
||||
else
|
||||
modelview_changed =
|
||||
priv->flushed_modelview_stack != ctx->flushed_modelview_stack ||
|
||||
priv->flushed_modelview_stack_age !=
|
||||
_cogl_matrix_stack_get_age (priv->flushed_modelview_stack);
|
||||
program_state->flushed_modelview_stack != ctx->flushed_modelview_stack ||
|
||||
program_state->flushed_modelview_stack_age !=
|
||||
_cogl_matrix_stack_get_age (program_state->flushed_modelview_stack);
|
||||
|
||||
projection_changed =
|
||||
priv->flushed_projection_stack != ctx->flushed_projection_stack ||
|
||||
priv->flushed_projection_stack_age !=
|
||||
_cogl_matrix_stack_get_age (priv->flushed_projection_stack);
|
||||
program_state->flushed_projection_stack != ctx->flushed_projection_stack ||
|
||||
program_state->flushed_projection_stack_age !=
|
||||
_cogl_matrix_stack_get_age (program_state->flushed_projection_stack);
|
||||
|
||||
if (modelview_changed)
|
||||
{
|
||||
cogl_object_ref (ctx->flushed_modelview_stack);
|
||||
if (priv->flushed_modelview_stack)
|
||||
cogl_object_unref (priv->flushed_modelview_stack);
|
||||
priv->flushed_modelview_stack = ctx->flushed_modelview_stack;
|
||||
priv->flushed_modelview_stack_age =
|
||||
if (program_state->flushed_modelview_stack)
|
||||
cogl_object_unref (program_state->flushed_modelview_stack);
|
||||
program_state->flushed_modelview_stack = ctx->flushed_modelview_stack;
|
||||
program_state->flushed_modelview_stack_age =
|
||||
_cogl_matrix_stack_get_age (ctx->flushed_modelview_stack);
|
||||
priv->flushed_modelview_is_identity =
|
||||
program_state->flushed_modelview_is_identity =
|
||||
_cogl_matrix_stack_has_identity_flag (ctx->flushed_modelview_stack);
|
||||
|
||||
if (priv->modelview_uniform != -1)
|
||||
_cogl_matrix_stack_prepare_for_flush (priv->flushed_modelview_stack,
|
||||
if (program_state->modelview_uniform != -1)
|
||||
_cogl_matrix_stack_prepare_for_flush (program_state
|
||||
->flushed_modelview_stack,
|
||||
COGL_MATRIX_MODELVIEW,
|
||||
flush_modelview_cb,
|
||||
priv);
|
||||
program_state);
|
||||
}
|
||||
|
||||
if (projection_changed)
|
||||
{
|
||||
cogl_object_ref (ctx->flushed_projection_stack);
|
||||
if (priv->flushed_projection_stack)
|
||||
cogl_object_unref (priv->flushed_projection_stack);
|
||||
priv->flushed_projection_stack = ctx->flushed_projection_stack;
|
||||
priv->flushed_projection_stack_age =
|
||||
if (program_state->flushed_projection_stack)
|
||||
cogl_object_unref (program_state->flushed_projection_stack);
|
||||
program_state->flushed_projection_stack = ctx->flushed_projection_stack;
|
||||
program_state->flushed_projection_stack_age =
|
||||
_cogl_matrix_stack_get_age (ctx->flushed_projection_stack);
|
||||
|
||||
if (priv->projection_uniform != -1)
|
||||
_cogl_matrix_stack_prepare_for_flush (priv->flushed_projection_stack,
|
||||
if (program_state->projection_uniform != -1)
|
||||
_cogl_matrix_stack_prepare_for_flush (program_state
|
||||
->flushed_projection_stack,
|
||||
COGL_MATRIX_PROJECTION,
|
||||
flush_projection_cb,
|
||||
priv);
|
||||
program_state);
|
||||
}
|
||||
|
||||
if (priv->mvp_uniform != -1 && (modelview_changed || projection_changed))
|
||||
if (program_state->mvp_uniform != -1 &&
|
||||
(modelview_changed || projection_changed))
|
||||
_cogl_matrix_stack_prepare_for_flush (ctx->flushed_projection_stack,
|
||||
COGL_MATRIX_PROJECTION,
|
||||
flush_combined_step_one_cb,
|
||||
priv);
|
||||
program_state);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
@ -55,57 +55,69 @@ typedef struct
|
|||
program changes then we may need to redecide whether to generate
|
||||
a shader at all */
|
||||
unsigned int user_program_age;
|
||||
} CoglPipelineVertendPrivate;
|
||||
} CoglPipelineShaderState;
|
||||
|
||||
static CoglUserDataKey glsl_priv_key;
|
||||
static CoglUserDataKey shader_state_key;
|
||||
|
||||
static CoglPipelineVertendPrivate *
|
||||
get_glsl_priv (CoglPipeline *pipeline)
|
||||
static CoglPipelineShaderState *
|
||||
shader_state_new (void)
|
||||
{
|
||||
return cogl_object_get_user_data (COGL_OBJECT (pipeline), &glsl_priv_key);
|
||||
CoglPipelineShaderState *shader_state;
|
||||
|
||||
shader_state = g_slice_new0 (CoglPipelineShaderState);
|
||||
shader_state->ref_count = 1;
|
||||
|
||||
return shader_state;
|
||||
}
|
||||
|
||||
static CoglPipelineShaderState *
|
||||
get_shader_state (CoglPipeline *pipeline)
|
||||
{
|
||||
return cogl_object_get_user_data (COGL_OBJECT (pipeline), &shader_state_key);
|
||||
}
|
||||
|
||||
static void
|
||||
destroy_glsl_priv (void *user_data)
|
||||
destroy_shader_state (void *user_data)
|
||||
{
|
||||
CoglPipelineVertendPrivate *priv = user_data;
|
||||
CoglPipelineShaderState *shader_state = user_data;
|
||||
|
||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
|
||||
if (--priv->ref_count == 0)
|
||||
if (--shader_state->ref_count == 0)
|
||||
{
|
||||
if (priv->gl_shader)
|
||||
GE( ctx, glDeleteShader (priv->gl_shader) );
|
||||
if (shader_state->gl_shader)
|
||||
GE( ctx, glDeleteShader (shader_state->gl_shader) );
|
||||
|
||||
g_slice_free (CoglPipelineVertendPrivate, priv);
|
||||
g_slice_free (CoglPipelineShaderState, shader_state);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
set_glsl_priv (CoglPipeline *pipeline, CoglPipelineVertendPrivate *priv)
|
||||
set_shader_state (CoglPipeline *pipeline,
|
||||
CoglPipelineShaderState *shader_state)
|
||||
{
|
||||
cogl_object_set_user_data (COGL_OBJECT (pipeline),
|
||||
&glsl_priv_key,
|
||||
priv,
|
||||
destroy_glsl_priv);
|
||||
&shader_state_key,
|
||||
shader_state,
|
||||
destroy_shader_state);
|
||||
}
|
||||
|
||||
static void
|
||||
dirty_glsl_shader_state (CoglPipeline *pipeline)
|
||||
dirty_shader_state (CoglPipeline *pipeline)
|
||||
{
|
||||
cogl_object_set_user_data (COGL_OBJECT (pipeline),
|
||||
&glsl_priv_key,
|
||||
&shader_state_key,
|
||||
NULL,
|
||||
destroy_glsl_priv);
|
||||
NULL);
|
||||
}
|
||||
|
||||
GLuint
|
||||
_cogl_pipeline_vertend_glsl_get_shader (CoglPipeline *pipeline)
|
||||
{
|
||||
CoglPipelineVertendPrivate *priv = get_glsl_priv (pipeline);
|
||||
CoglPipelineShaderState *shader_state = get_shader_state (pipeline);
|
||||
|
||||
if (priv)
|
||||
return priv->gl_shader;
|
||||
if (shader_state)
|
||||
return shader_state->gl_shader;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
@ -115,7 +127,7 @@ _cogl_pipeline_vertend_glsl_start (CoglPipeline *pipeline,
|
|||
int n_layers,
|
||||
unsigned long pipelines_difference)
|
||||
{
|
||||
CoglPipelineVertendPrivate *priv;
|
||||
CoglPipelineShaderState *shader_state;
|
||||
CoglProgram *user_program;
|
||||
|
||||
_COGL_GET_CONTEXT (ctx, FALSE);
|
||||
|
@ -134,9 +146,9 @@ _cogl_pipeline_vertend_glsl_start (CoglPipeline *pipeline,
|
|||
|
||||
/* Now lookup our glsl backend private state (allocating if
|
||||
* necessary) */
|
||||
priv = get_glsl_priv (pipeline);
|
||||
shader_state = get_shader_state (pipeline);
|
||||
|
||||
if (priv == NULL)
|
||||
if (shader_state == NULL)
|
||||
{
|
||||
CoglPipeline *authority;
|
||||
|
||||
|
@ -148,42 +160,41 @@ _cogl_pipeline_vertend_glsl_start (CoglPipeline *pipeline,
|
|||
~COGL_PIPELINE_STATE_LAYERS,
|
||||
COGL_PIPELINE_LAYER_STATE_AFFECTS_VERTEX_CODEGEN);
|
||||
|
||||
priv = get_glsl_priv (authority);
|
||||
shader_state = get_shader_state (authority);
|
||||
|
||||
if (priv == NULL)
|
||||
if (shader_state == NULL)
|
||||
{
|
||||
priv = g_slice_new0 (CoglPipelineVertendPrivate);
|
||||
priv->ref_count = 1;
|
||||
set_glsl_priv (authority, priv);
|
||||
shader_state = shader_state_new ();
|
||||
set_shader_state (authority, shader_state);
|
||||
}
|
||||
|
||||
if (authority != pipeline)
|
||||
{
|
||||
priv->ref_count++;
|
||||
set_glsl_priv (pipeline, priv);
|
||||
shader_state->ref_count++;
|
||||
set_shader_state (pipeline, shader_state);
|
||||
}
|
||||
}
|
||||
|
||||
if (priv->gl_shader)
|
||||
if (shader_state->gl_shader)
|
||||
{
|
||||
/* If we already have a valid GLSL shader then we don't need to
|
||||
generate a new one. However if there's a user program and it
|
||||
has changed since the last link then we do need a new shader */
|
||||
if (user_program == NULL ||
|
||||
priv->user_program_age == user_program->age)
|
||||
shader_state->user_program_age == user_program->age)
|
||||
return TRUE;
|
||||
|
||||
/* We need to recreate the shader so destroy the existing one */
|
||||
GE( ctx, glDeleteShader (priv->gl_shader) );
|
||||
priv->gl_shader = 0;
|
||||
GE( ctx, glDeleteShader (shader_state->gl_shader) );
|
||||
shader_state->gl_shader = 0;
|
||||
}
|
||||
|
||||
/* If we make it here then we have a priv struct without a gl_shader
|
||||
/* If we make it here then we have a shader_state struct without a gl_shader
|
||||
either because this is the first time we've encountered it or
|
||||
because the user program has changed */
|
||||
|
||||
if (user_program)
|
||||
priv->user_program_age = user_program->age;
|
||||
shader_state->user_program_age = user_program->age;
|
||||
|
||||
/* If the user program contains a vertex shader then we don't need
|
||||
to generate one */
|
||||
|
@ -198,10 +209,10 @@ _cogl_pipeline_vertend_glsl_start (CoglPipeline *pipeline,
|
|||
add_layer callback is invoked */
|
||||
g_string_set_size (ctx->codegen_header_buffer, 0);
|
||||
g_string_set_size (ctx->codegen_source_buffer, 0);
|
||||
priv->header = ctx->codegen_header_buffer;
|
||||
priv->source = ctx->codegen_source_buffer;
|
||||
shader_state->header = ctx->codegen_header_buffer;
|
||||
shader_state->source = ctx->codegen_source_buffer;
|
||||
|
||||
g_string_append (priv->source,
|
||||
g_string_append (shader_state->source,
|
||||
"void\n"
|
||||
"main ()\n"
|
||||
"{\n");
|
||||
|
@ -209,7 +220,7 @@ _cogl_pipeline_vertend_glsl_start (CoglPipeline *pipeline,
|
|||
if (ctx->driver == COGL_DRIVER_GLES2)
|
||||
/* There is no builtin uniform for the pointsize on GLES2 so we need
|
||||
to copy it from the custom uniform in the vertex shader */
|
||||
g_string_append (priv->source,
|
||||
g_string_append (shader_state->source,
|
||||
" cogl_point_size_out = cogl_point_size_in;\n");
|
||||
/* On regular OpenGL we'll just flush the point size builtin */
|
||||
else if (pipelines_difference & COGL_PIPELINE_STATE_POINT_SIZE)
|
||||
|
@ -232,12 +243,12 @@ _cogl_pipeline_vertend_glsl_add_layer (CoglPipeline *pipeline,
|
|||
CoglPipelineLayer *layer,
|
||||
unsigned long layers_difference)
|
||||
{
|
||||
CoglPipelineVertendPrivate *priv;
|
||||
CoglPipelineShaderState *shader_state;
|
||||
int unit_index;
|
||||
|
||||
_COGL_GET_CONTEXT (ctx, FALSE);
|
||||
|
||||
priv = get_glsl_priv (pipeline);
|
||||
shader_state = get_shader_state (pipeline);
|
||||
|
||||
unit_index = _cogl_pipeline_layer_get_unit_index (layer);
|
||||
|
||||
|
@ -263,7 +274,7 @@ _cogl_pipeline_vertend_glsl_add_layer (CoglPipeline *pipeline,
|
|||
}
|
||||
}
|
||||
|
||||
if (priv->source == NULL)
|
||||
if (shader_state->source == NULL)
|
||||
return TRUE;
|
||||
|
||||
/* Transform the texture coordinates by the layer's user matrix.
|
||||
|
@ -277,7 +288,7 @@ _cogl_pipeline_vertend_glsl_add_layer (CoglPipeline *pipeline,
|
|||
* avoid setting them if not
|
||||
*/
|
||||
|
||||
g_string_append_printf (priv->source,
|
||||
g_string_append_printf (shader_state->source,
|
||||
" cogl_tex_coord_out[%i] = "
|
||||
"cogl_texture_matrix[%i] * cogl_tex_coord%i_in;\n",
|
||||
unit_index, unit_index, unit_index);
|
||||
|
@ -289,13 +300,13 @@ static gboolean
|
|||
_cogl_pipeline_vertend_glsl_end (CoglPipeline *pipeline,
|
||||
unsigned long pipelines_difference)
|
||||
{
|
||||
CoglPipelineVertendPrivate *priv;
|
||||
CoglPipelineShaderState *shader_state;
|
||||
|
||||
_COGL_GET_CONTEXT (ctx, FALSE);
|
||||
|
||||
priv = get_glsl_priv (pipeline);
|
||||
shader_state = get_shader_state (pipeline);
|
||||
|
||||
if (priv->source)
|
||||
if (shader_state->source)
|
||||
{
|
||||
const char *source_strings[2];
|
||||
GLint lengths[2];
|
||||
|
@ -310,7 +321,7 @@ _cogl_pipeline_vertend_glsl_end (CoglPipeline *pipeline,
|
|||
0 /* no application private data */);
|
||||
COGL_COUNTER_INC (_cogl_uprof_context, vertend_glsl_compile_counter);
|
||||
|
||||
g_string_append (priv->source,
|
||||
g_string_append (shader_state->source,
|
||||
" cogl_position_out = "
|
||||
"cogl_modelview_projection_matrix * "
|
||||
"cogl_position_in;\n"
|
||||
|
@ -319,10 +330,10 @@ _cogl_pipeline_vertend_glsl_end (CoglPipeline *pipeline,
|
|||
|
||||
GE_RET( shader, ctx, glCreateShader (GL_VERTEX_SHADER) );
|
||||
|
||||
lengths[0] = priv->header->len;
|
||||
source_strings[0] = priv->header->str;
|
||||
lengths[1] = priv->source->len;
|
||||
source_strings[1] = priv->source->str;
|
||||
lengths[0] = shader_state->header->len;
|
||||
source_strings[0] = shader_state->header->str;
|
||||
lengths[1] = shader_state->source->len;
|
||||
source_strings[1] = shader_state->source->str;
|
||||
|
||||
n_layers = cogl_pipeline_get_n_layers (pipeline);
|
||||
|
||||
|
@ -345,9 +356,9 @@ _cogl_pipeline_vertend_glsl_end (CoglPipeline *pipeline,
|
|||
g_warning ("Shader compilation failed:\n%s", shader_log);
|
||||
}
|
||||
|
||||
priv->header = NULL;
|
||||
priv->source = NULL;
|
||||
priv->gl_shader = shader;
|
||||
shader_state->header = NULL;
|
||||
shader_state->source = NULL;
|
||||
shader_state->gl_shader = shader;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
|
@ -359,7 +370,7 @@ _cogl_pipeline_vertend_glsl_pre_change_notify (CoglPipeline *pipeline,
|
|||
const CoglColor *new_color)
|
||||
{
|
||||
if ((change & COGL_PIPELINE_STATE_AFFECTS_VERTEX_CODEGEN))
|
||||
dirty_glsl_shader_state (pipeline);
|
||||
dirty_shader_state (pipeline);
|
||||
}
|
||||
|
||||
/* NB: layers are considered immutable once they have any dependants
|
||||
|
@ -376,15 +387,15 @@ _cogl_pipeline_vertend_glsl_layer_pre_change_notify (
|
|||
CoglPipelineLayer *layer,
|
||||
CoglPipelineLayerState change)
|
||||
{
|
||||
CoglPipelineVertendPrivate *priv;
|
||||
CoglPipelineShaderState *shader_state;
|
||||
|
||||
priv = get_glsl_priv (owner);
|
||||
if (!priv)
|
||||
shader_state = get_shader_state (owner);
|
||||
if (!shader_state)
|
||||
return;
|
||||
|
||||
if ((change & COGL_PIPELINE_LAYER_STATE_AFFECTS_VERTEX_CODEGEN))
|
||||
{
|
||||
dirty_glsl_shader_state (owner);
|
||||
dirty_shader_state (owner);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -448,7 +448,6 @@ _cogl_pipeline_copy (CoglPipeline *src, gboolean is_weak)
|
|||
pipeline->deprecated_get_layers_list_dirty = TRUE;
|
||||
|
||||
pipeline->fragend = src->fragend;
|
||||
pipeline->fragend_priv_set_mask = 0;
|
||||
|
||||
pipeline->vertend = src->vertend;
|
||||
|
||||
|
@ -501,18 +500,6 @@ cogl_pipeline_new (void)
|
|||
return new;
|
||||
}
|
||||
|
||||
static void
|
||||
_cogl_pipeline_fragend_free_priv (CoglPipeline *pipeline)
|
||||
{
|
||||
if (pipeline->fragend != COGL_PIPELINE_FRAGEND_UNDEFINED &&
|
||||
_cogl_pipeline_fragends[pipeline->fragend]->free_priv)
|
||||
{
|
||||
const CoglPipelineFragend *fragend =
|
||||
_cogl_pipeline_fragends[pipeline->fragend];
|
||||
fragend->free_priv (pipeline);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
destroy_weak_children_cb (CoglPipelineNode *node,
|
||||
void *user_data)
|
||||
|
@ -545,8 +532,6 @@ _cogl_pipeline_free (CoglPipeline *pipeline)
|
|||
|
||||
g_assert (COGL_LIST_EMPTY (&COGL_PIPELINE_NODE (pipeline)->children));
|
||||
|
||||
_cogl_pipeline_fragend_free_priv (pipeline);
|
||||
|
||||
_cogl_pipeline_unparent (COGL_PIPELINE_NODE (pipeline));
|
||||
|
||||
if (pipeline->differences & COGL_PIPELINE_STATE_USER_SHADER &&
|
||||
|
@ -970,7 +955,6 @@ _cogl_pipeline_needs_blending_enabled (CoglPipeline *pipeline,
|
|||
void
|
||||
_cogl_pipeline_set_fragend (CoglPipeline *pipeline, int fragend)
|
||||
{
|
||||
_cogl_pipeline_fragend_free_priv (pipeline);
|
||||
pipeline->fragend = fragend;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue