mirror of
https://github.com/brl/mutter.git
synced 2024-11-26 01:50:42 -05:00
snippet: Add a hook for the layer fragment processing
This adds a hook to replace or wrap the fragment processing for a particular layer. Reviewed-by: Robert Bragg <robert@linux.intel.com>
This commit is contained in:
parent
4581ce5f15
commit
b7e15929b6
@ -369,16 +369,7 @@ add_constant_lookup (CoglPipelineShaderState *shader_state,
|
|||||||
{
|
{
|
||||||
int unit_index = _cogl_pipeline_layer_get_unit_index (layer);
|
int unit_index = _cogl_pipeline_layer_get_unit_index (layer);
|
||||||
|
|
||||||
/* Create a sampler uniform for this layer if we haven't already */
|
g_string_append_printf (shader_state->header,
|
||||||
if (!shader_state->unit_state[unit_index].combine_constant_used)
|
|
||||||
{
|
|
||||||
g_string_append_printf (shader_state->header,
|
|
||||||
"uniform vec4 _cogl_layer_constant_%i;\n",
|
|
||||||
unit_index);
|
|
||||||
shader_state->unit_state[unit_index].combine_constant_used = TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_string_append_printf (shader_state->source,
|
|
||||||
"_cogl_layer_constant_%i.%s",
|
"_cogl_layer_constant_%i.%s",
|
||||||
unit_index, swizzle);
|
unit_index, swizzle);
|
||||||
}
|
}
|
||||||
@ -532,7 +523,7 @@ add_arg (CoglPipelineShaderState *shader_state,
|
|||||||
CoglPipelineCombineOp operand,
|
CoglPipelineCombineOp operand,
|
||||||
const char *swizzle)
|
const char *swizzle)
|
||||||
{
|
{
|
||||||
GString *shader_source = shader_state->source;
|
GString *shader_source = shader_state->header;
|
||||||
char alpha_swizzle[5] = "aaaa";
|
char alpha_swizzle[5] = "aaaa";
|
||||||
|
|
||||||
g_string_append_c (shader_source, '(');
|
g_string_append_c (shader_source, '(');
|
||||||
@ -630,9 +621,22 @@ ensure_arg_generated (CoglPipeline *pipeline,
|
|||||||
|
|
||||||
switch (src)
|
switch (src)
|
||||||
{
|
{
|
||||||
case COGL_PIPELINE_COMBINE_SOURCE_CONSTANT:
|
|
||||||
case COGL_PIPELINE_COMBINE_SOURCE_PRIMARY_COLOR:
|
case COGL_PIPELINE_COMBINE_SOURCE_PRIMARY_COLOR:
|
||||||
/* These don't involve any other layers */
|
/* This doesn't involve any other layers */
|
||||||
|
break;
|
||||||
|
|
||||||
|
case COGL_PIPELINE_COMBINE_SOURCE_CONSTANT:
|
||||||
|
{
|
||||||
|
int unit_index = _cogl_pipeline_layer_get_unit_index (layer);
|
||||||
|
/* Create a sampler uniform for this layer if we haven't already */
|
||||||
|
if (!shader_state->unit_state[unit_index].combine_constant_used)
|
||||||
|
{
|
||||||
|
g_string_append_printf (shader_state->header,
|
||||||
|
"uniform vec4 _cogl_layer_constant_%i;\n",
|
||||||
|
unit_index);
|
||||||
|
shader_state->unit_state[unit_index].combine_constant_used = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case COGL_PIPELINE_COMBINE_SOURCE_PREVIOUS:
|
case COGL_PIPELINE_COMBINE_SOURCE_PREVIOUS:
|
||||||
@ -667,6 +671,20 @@ ensure_arg_generated (CoglPipeline *pipeline,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ensure_args_for_func (CoglPipeline *pipeline,
|
||||||
|
CoglPipelineLayer *layer,
|
||||||
|
int previous_layer_index,
|
||||||
|
CoglPipelineCombineFunc function,
|
||||||
|
CoglPipelineCombineSource *src)
|
||||||
|
{
|
||||||
|
int n_args = _cogl_get_n_args_for_combine_func (function);
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < n_args; i++)
|
||||||
|
ensure_arg_generated (pipeline, layer, previous_layer_index, src[i]);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
append_masked_combine (CoglPipeline *pipeline,
|
append_masked_combine (CoglPipeline *pipeline,
|
||||||
CoglPipelineLayer *layer,
|
CoglPipelineLayer *layer,
|
||||||
@ -677,18 +695,10 @@ append_masked_combine (CoglPipeline *pipeline,
|
|||||||
CoglPipelineCombineOp *op)
|
CoglPipelineCombineOp *op)
|
||||||
{
|
{
|
||||||
CoglPipelineShaderState *shader_state = get_shader_state (pipeline);
|
CoglPipelineShaderState *shader_state = get_shader_state (pipeline);
|
||||||
GString *shader_source = shader_state->source;
|
GString *shader_source = shader_state->header;
|
||||||
int n_args;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
n_args = _cogl_get_n_args_for_combine_func (function);
|
g_string_append_printf (shader_state->header,
|
||||||
|
" cogl_layer.%s = ",
|
||||||
for (i = 0; i < n_args; i++)
|
|
||||||
ensure_arg_generated (pipeline, layer, previous_layer_index, src[i]);
|
|
||||||
|
|
||||||
g_string_append_printf (shader_state->source,
|
|
||||||
" cogl_layer%i.%s = ",
|
|
||||||
layer->index,
|
|
||||||
swizzle);
|
swizzle);
|
||||||
|
|
||||||
switch (function)
|
switch (function)
|
||||||
@ -785,6 +795,7 @@ ensure_layer_generated (CoglPipeline *pipeline,
|
|||||||
CoglPipelineLayer *combine_authority;
|
CoglPipelineLayer *combine_authority;
|
||||||
CoglPipelineLayerBigState *big_state;
|
CoglPipelineLayerBigState *big_state;
|
||||||
CoglPipelineLayer *layer;
|
CoglPipelineLayer *layer;
|
||||||
|
CoglPipelineSnippetData snippet_data;
|
||||||
LayerData *layer_data;
|
LayerData *layer_data;
|
||||||
|
|
||||||
/* Find the layer that corresponds to this layer_num */
|
/* Find the layer that corresponds to this layer_num */
|
||||||
@ -815,37 +826,93 @@ ensure_layer_generated (CoglPipeline *pipeline,
|
|||||||
"vec4 cogl_layer%i;\n",
|
"vec4 cogl_layer%i;\n",
|
||||||
layer_index);
|
layer_index);
|
||||||
|
|
||||||
if (!_cogl_pipeline_layer_needs_combine_separate (combine_authority) ||
|
/* Skip the layer generation if there is a snippet that replaces the
|
||||||
/* GL_DOT3_RGBA Is a bit weird as a GL_COMBINE_RGB function
|
default layer code. This is important because generating this
|
||||||
* since if you use it, it overrides your ALPHA function...
|
code may cause the code for other layers to be generated and
|
||||||
*/
|
stored in the global variable. If this code isn't actually used
|
||||||
big_state->texture_combine_rgb_func ==
|
then the global variables would be uninitialised and they may be
|
||||||
COGL_PIPELINE_COMBINE_FUNC_DOT3_RGBA)
|
used from other layers */
|
||||||
append_masked_combine (pipeline,
|
if (!has_replace_hook (layer, COGL_SNIPPET_HOOK_LAYER_FRAGMENT))
|
||||||
layer,
|
|
||||||
layer_data->previous_layer_index,
|
|
||||||
"rgba",
|
|
||||||
big_state->texture_combine_rgb_func,
|
|
||||||
big_state->texture_combine_rgb_src,
|
|
||||||
big_state->texture_combine_rgb_op);
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
append_masked_combine (pipeline,
|
ensure_args_for_func (pipeline,
|
||||||
layer,
|
layer,
|
||||||
layer_data->previous_layer_index,
|
layer_data->previous_layer_index,
|
||||||
"rgb",
|
big_state->texture_combine_rgb_func,
|
||||||
big_state->texture_combine_rgb_func,
|
big_state->texture_combine_rgb_src);
|
||||||
big_state->texture_combine_rgb_src,
|
ensure_args_for_func (pipeline,
|
||||||
big_state->texture_combine_rgb_op);
|
layer,
|
||||||
append_masked_combine (pipeline,
|
layer_data->previous_layer_index,
|
||||||
layer,
|
big_state->texture_combine_alpha_func,
|
||||||
layer_data->previous_layer_index,
|
big_state->texture_combine_alpha_src);
|
||||||
"a",
|
|
||||||
big_state->texture_combine_alpha_func,
|
g_string_append_printf (shader_state->header,
|
||||||
big_state->texture_combine_alpha_src,
|
"vec4\n"
|
||||||
big_state->texture_combine_alpha_op);
|
"cogl_real_generate_layer%i ()\n"
|
||||||
|
"{\n"
|
||||||
|
" vec4 cogl_layer;\n",
|
||||||
|
layer_index);
|
||||||
|
|
||||||
|
if (!_cogl_pipeline_layer_needs_combine_separate (combine_authority) ||
|
||||||
|
/* GL_DOT3_RGBA Is a bit weird as a GL_COMBINE_RGB function
|
||||||
|
* since if you use it, it overrides your ALPHA function...
|
||||||
|
*/
|
||||||
|
big_state->texture_combine_rgb_func ==
|
||||||
|
COGL_PIPELINE_COMBINE_FUNC_DOT3_RGBA)
|
||||||
|
append_masked_combine (pipeline,
|
||||||
|
layer,
|
||||||
|
layer_data->previous_layer_index,
|
||||||
|
"rgba",
|
||||||
|
big_state->texture_combine_rgb_func,
|
||||||
|
big_state->texture_combine_rgb_src,
|
||||||
|
big_state->texture_combine_rgb_op);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
append_masked_combine (pipeline,
|
||||||
|
layer,
|
||||||
|
layer_data->previous_layer_index,
|
||||||
|
"rgb",
|
||||||
|
big_state->texture_combine_rgb_func,
|
||||||
|
big_state->texture_combine_rgb_src,
|
||||||
|
big_state->texture_combine_rgb_op);
|
||||||
|
append_masked_combine (pipeline,
|
||||||
|
layer,
|
||||||
|
layer_data->previous_layer_index,
|
||||||
|
"a",
|
||||||
|
big_state->texture_combine_alpha_func,
|
||||||
|
big_state->texture_combine_alpha_src,
|
||||||
|
big_state->texture_combine_alpha_op);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_string_append (shader_state->header,
|
||||||
|
" return cogl_layer;\n"
|
||||||
|
"}\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Wrap the layer code in any snippets that have been hooked */
|
||||||
|
memset (&snippet_data, 0, sizeof (snippet_data));
|
||||||
|
snippet_data.snippets = get_layer_fragment_snippets (layer);
|
||||||
|
snippet_data.hook = COGL_SNIPPET_HOOK_LAYER_FRAGMENT;
|
||||||
|
snippet_data.chain_function = g_strdup_printf ("cogl_real_generate_layer%i",
|
||||||
|
layer_index);
|
||||||
|
snippet_data.final_name = g_strdup_printf ("cogl_generate_layer%i",
|
||||||
|
layer_index);
|
||||||
|
snippet_data.function_prefix = g_strdup_printf ("cogl_generate_layer%i",
|
||||||
|
layer_index);
|
||||||
|
snippet_data.return_type = "vec4";
|
||||||
|
snippet_data.return_variable = "cogl_layer";
|
||||||
|
snippet_data.source_buf = shader_state->header;
|
||||||
|
|
||||||
|
_cogl_pipeline_snippet_generate_code (&snippet_data);
|
||||||
|
|
||||||
|
g_free ((char *) snippet_data.chain_function);
|
||||||
|
g_free ((char *) snippet_data.final_name);
|
||||||
|
g_free ((char *) snippet_data.function_prefix);
|
||||||
|
|
||||||
|
g_string_append_printf (shader_state->source,
|
||||||
|
" cogl_layer%i = cogl_generate_layer%i ();\n",
|
||||||
|
layer_index,
|
||||||
|
layer_index);
|
||||||
|
|
||||||
g_slice_free (LayerData, layer_data);
|
g_slice_free (LayerData, layer_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,6 +54,8 @@ typedef struct _CoglSnippet CoglSnippet;
|
|||||||
* stage of the pipeline.
|
* stage of the pipeline.
|
||||||
* @COGL_SNIPPET_HOOK_FRAGMENT: A hook for the entire fragment
|
* @COGL_SNIPPET_HOOK_FRAGMENT: A hook for the entire fragment
|
||||||
* processing stage of the pipeline.
|
* processing stage of the pipeline.
|
||||||
|
* @COGL_SNIPPET_HOOK_LAYER_FRAGMENT: A hook for the fragment
|
||||||
|
* processing of a particular layer.
|
||||||
* @COGL_SNIPPET_HOOK_TEXTURE_LOOKUP: A hook for the texture lookup
|
* @COGL_SNIPPET_HOOK_TEXTURE_LOOKUP: A hook for the texture lookup
|
||||||
* stage of a given layer in a pipeline.
|
* stage of a given layer in a pipeline.
|
||||||
*
|
*
|
||||||
@ -127,6 +129,39 @@ typedef struct _CoglSnippet CoglSnippet;
|
|||||||
* </glossdef>
|
* </glossdef>
|
||||||
* </glossentry>
|
* </glossentry>
|
||||||
* <glossentry>
|
* <glossentry>
|
||||||
|
* <glossterm>%COGL_SNIPPET_HOOK_LAYER_FRAGMENT</glossterm>
|
||||||
|
* Adds a shader snippet that will hook on to the fragment processing
|
||||||
|
* of a particular layer. This can be used to replace the processing
|
||||||
|
* for a layer or to modify the results.
|
||||||
|
* </para>
|
||||||
|
* <para>
|
||||||
|
* Within the snippet code for this hook there is an extra vec4
|
||||||
|
* variable called ‘cogl_layer’. This contains the resulting color
|
||||||
|
* that will be used for the layer. This can be modified in the ‘post’
|
||||||
|
* section or it the default processing can be replaced entirely using
|
||||||
|
* the ‘replace’ section.
|
||||||
|
* </para>
|
||||||
|
* <para>
|
||||||
|
* The ‘declarations’ string in @snippet will be inserted in the
|
||||||
|
* global scope of the shader. Use this to declare any uniforms,
|
||||||
|
* attributes or functions that the snippet requires.
|
||||||
|
* </para>
|
||||||
|
* <para>
|
||||||
|
* The ‘pre’ string in @snippet will be inserted just before the
|
||||||
|
* fragment processing for this layer.
|
||||||
|
* </para>
|
||||||
|
* <para>
|
||||||
|
* If a ‘replace’ string is given then this will be used instead of
|
||||||
|
* the default fragment processing for this layer. The snippet must write to
|
||||||
|
* the ‘cogl_layer’ variable in that case.
|
||||||
|
* </para>
|
||||||
|
* <para>
|
||||||
|
* The ‘post’ string in @snippet will be inserted just after the
|
||||||
|
* fragment processing for the layer. The results can be modified by changing
|
||||||
|
* the value of the ‘cogl_layer’ variable.
|
||||||
|
* </para>
|
||||||
|
* </glossentry>
|
||||||
|
* <glossentry>
|
||||||
* <glossterm>%COGL_SNIPPET_HOOK_TEXTURE_LOOKUP</glossterm>
|
* <glossterm>%COGL_SNIPPET_HOOK_TEXTURE_LOOKUP</glossterm>
|
||||||
* Adds a shader snippet that will hook on to the texture lookup part
|
* Adds a shader snippet that will hook on to the texture lookup part
|
||||||
* of a given layer. This gives a chance for the application to modify
|
* of a given layer. This gives a chance for the application to modify
|
||||||
@ -178,7 +213,8 @@ typedef enum {
|
|||||||
/* ... = 4096 */
|
/* ... = 4096 */
|
||||||
|
|
||||||
/* Per layer fragment hooks */
|
/* Per layer fragment hooks */
|
||||||
COGL_SNIPPET_HOOK_TEXTURE_LOOKUP = 6144
|
COGL_SNIPPET_HOOK_LAYER_FRAGMENT = 6144,
|
||||||
|
COGL_SNIPPET_HOOK_TEXTURE_LOOKUP
|
||||||
} CoglSnippetHook;
|
} CoglSnippetHook;
|
||||||
|
|
||||||
#define cogl_snippet_new cogl_snippet_new_EXP
|
#define cogl_snippet_new cogl_snippet_new_EXP
|
||||||
|
@ -268,6 +268,49 @@ paint (TestState *state)
|
|||||||
cogl_pop_source ();
|
cogl_pop_source ();
|
||||||
cogl_object_unref (pipeline);
|
cogl_object_unref (pipeline);
|
||||||
|
|
||||||
|
/* Test replacing the layer code */
|
||||||
|
pipeline = create_texture_pipeline ();
|
||||||
|
|
||||||
|
snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_LAYER_FRAGMENT, NULL, NULL);
|
||||||
|
cogl_snippet_set_replace (snippet, "cogl_layer = vec4 (0.0, 0.0, 1.0, 1.0);");
|
||||||
|
cogl_pipeline_add_layer_snippet (pipeline, 0, snippet);
|
||||||
|
cogl_object_unref (snippet);
|
||||||
|
|
||||||
|
/* Add a second layer which samples from the texture in the first
|
||||||
|
layer. The snippet override should cause the first layer not to
|
||||||
|
generate the code for the texture lookup but this second layer
|
||||||
|
should still be able to cause it to be generated */
|
||||||
|
cogl_pipeline_set_layer_combine (pipeline, 1,
|
||||||
|
"RGB = ADD(TEXTURE_0, PREVIOUS)"
|
||||||
|
"A = REPLACE(PREVIOUS)",
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
cogl_push_source (pipeline);
|
||||||
|
cogl_rectangle_with_texture_coords (110, 0, 120, 10,
|
||||||
|
0, 0, 0, 0);
|
||||||
|
cogl_pop_source ();
|
||||||
|
cogl_object_unref (pipeline);
|
||||||
|
|
||||||
|
/* Test modifying the layer code */
|
||||||
|
pipeline = cogl_pipeline_new ();
|
||||||
|
|
||||||
|
cogl_pipeline_set_uniform_1f (pipeline,
|
||||||
|
cogl_pipeline_get_uniform_location (pipeline,
|
||||||
|
"a_value"),
|
||||||
|
0.5);
|
||||||
|
|
||||||
|
snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_LAYER_FRAGMENT,
|
||||||
|
"uniform float a_value;",
|
||||||
|
"cogl_layer.g = a_value;");
|
||||||
|
cogl_pipeline_add_layer_snippet (pipeline, 0, snippet);
|
||||||
|
cogl_object_unref (snippet);
|
||||||
|
|
||||||
|
cogl_push_source (pipeline);
|
||||||
|
cogl_rectangle_with_texture_coords (120, 0, 130, 10,
|
||||||
|
0, 0, 0, 0);
|
||||||
|
cogl_pop_source ();
|
||||||
|
cogl_object_unref (pipeline);
|
||||||
|
|
||||||
/* Sanity check modifying the snippet */
|
/* Sanity check modifying the snippet */
|
||||||
snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT, "foo", "bar");
|
snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT, "foo", "bar");
|
||||||
g_assert_cmpstr (cogl_snippet_get_declarations (snippet), ==, "foo");
|
g_assert_cmpstr (cogl_snippet_get_declarations (snippet), ==, "foo");
|
||||||
@ -318,6 +361,8 @@ validate_result (void)
|
|||||||
test_utils_check_pixel (85, 5, 0x00ffffff);
|
test_utils_check_pixel (85, 5, 0x00ffffff);
|
||||||
test_utils_check_pixel (95, 5, 0x0000ffff);
|
test_utils_check_pixel (95, 5, 0x0000ffff);
|
||||||
test_utils_check_pixel (105, 5, 0xff0000ff);
|
test_utils_check_pixel (105, 5, 0xff0000ff);
|
||||||
|
test_utils_check_pixel (115, 5, 0xff00ffff);
|
||||||
|
test_utils_check_pixel (125, 5, 0xff80ffff);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
Loading…
Reference in New Issue
Block a user