mirror of
https://github.com/brl/mutter.git
synced 2024-11-22 16:10:41 -05:00
Generate GLSL in the CoglPipeline GLSL backend
The GLSL pipeline backend can now generate code to represent the pipeline state in a similar way to the ARBfp backend. Most of the code for this is taken from the GLES 2 wrapper.
This commit is contained in:
parent
46e59dc50f
commit
7da3610e82
@ -132,6 +132,7 @@ cogl_create_context (void)
|
|||||||
_context->opaque_color_pipeline = cogl_pipeline_new ();
|
_context->opaque_color_pipeline = cogl_pipeline_new ();
|
||||||
_context->blended_color_pipeline = cogl_pipeline_new ();
|
_context->blended_color_pipeline = cogl_pipeline_new ();
|
||||||
_context->texture_pipeline = cogl_pipeline_new ();
|
_context->texture_pipeline = cogl_pipeline_new ();
|
||||||
|
_context->fragment_header_buffer = g_string_new ("");
|
||||||
_context->fragment_source_buffer = g_string_new ("");
|
_context->fragment_source_buffer = g_string_new ("");
|
||||||
_context->source_stack = NULL;
|
_context->source_stack = NULL;
|
||||||
|
|
||||||
|
@ -86,6 +86,7 @@ typedef struct
|
|||||||
CoglPipeline *opaque_color_pipeline; /* used for set_source_color */
|
CoglPipeline *opaque_color_pipeline; /* used for set_source_color */
|
||||||
CoglPipeline *blended_color_pipeline; /* used for set_source_color */
|
CoglPipeline *blended_color_pipeline; /* used for set_source_color */
|
||||||
CoglPipeline *texture_pipeline; /* used for set_source_texture */
|
CoglPipeline *texture_pipeline; /* used for set_source_texture */
|
||||||
|
GString *fragment_header_buffer;
|
||||||
GString *fragment_source_buffer;
|
GString *fragment_source_buffer;
|
||||||
GList *source_stack;
|
GList *source_stack;
|
||||||
|
|
||||||
|
@ -29,8 +29,11 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#include "cogl-pipeline-private.h"
|
#include "cogl-pipeline-private.h"
|
||||||
#include "cogl-shader-private.h"
|
#include "cogl-shader-private.h"
|
||||||
|
#include "cogl-blend-string.h"
|
||||||
|
|
||||||
#ifdef COGL_PIPELINE_BACKEND_GLSL
|
#ifdef COGL_PIPELINE_BACKEND_GLSL
|
||||||
|
|
||||||
@ -43,13 +46,22 @@
|
|||||||
|
|
||||||
#ifndef HAVE_COGL_GLES2
|
#ifndef HAVE_COGL_GLES2
|
||||||
|
|
||||||
#define glCreateProgram ctx->drv.pf_glCreateProgram
|
#define glCreateProgram ctx->drv.pf_glCreateProgram
|
||||||
#define glAttachShader ctx->drv.pf_glAttachShader
|
#define glAttachShader ctx->drv.pf_glAttachShader
|
||||||
#define glUseProgram ctx->drv.pf_glUseProgram
|
#define glUseProgram ctx->drv.pf_glUseProgram
|
||||||
#define glLinkProgram ctx->drv.pf_glLinkProgram
|
#define glLinkProgram ctx->drv.pf_glLinkProgram
|
||||||
#define glDeleteProgram ctx->drv.pf_glDeleteProgram
|
#define glDeleteProgram ctx->drv.pf_glDeleteProgram
|
||||||
#define glGetProgramInfoLog ctx->drv.pf_glGetProgramInfoLog
|
#define glGetProgramInfoLog ctx->drv.pf_glGetProgramInfoLog
|
||||||
#define glGetProgramiv ctx->drv.pf_glGetProgramiv
|
#define glGetProgramiv ctx->drv.pf_glGetProgramiv
|
||||||
|
#define glCreateShader ctx->drv.pf_glCreateShader
|
||||||
|
#define glGetShaderiv ctx->drv.pf_glGetShaderiv
|
||||||
|
#define glGetShaderInfoLog ctx->drv.pf_glGetShaderInfoLog
|
||||||
|
#define glCompileShader ctx->drv.pf_glCompileShader
|
||||||
|
#define glShaderSource ctx->drv.pf_glShaderSource
|
||||||
|
#define glDeleteShader ctx->drv.pf_glDeleteShader
|
||||||
|
#define glGetUniformLocation ctx->drv.pf_glGetUniformLocation
|
||||||
|
#define glUniform1i ctx->drv.pf_glUniform1i
|
||||||
|
#define glUniform4fv ctx->drv.pf_glUniform4fv
|
||||||
|
|
||||||
#endif /* HAVE_COGL_GLES2 */
|
#endif /* HAVE_COGL_GLES2 */
|
||||||
|
|
||||||
@ -63,6 +75,20 @@
|
|||||||
#include "../gles/cogl-gles2-wrapper.h"
|
#include "../gles/cogl-gles2-wrapper.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* This might not be defined on GLES */
|
||||||
|
#ifndef GL_TEXTURE_3D
|
||||||
|
#define GL_TEXTURE_3D 0x806F
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct _UnitState
|
||||||
|
{
|
||||||
|
unsigned int sampled:1;
|
||||||
|
unsigned int combine_constant_used:1;
|
||||||
|
unsigned int dirty_combine_constant:1;
|
||||||
|
|
||||||
|
GLint combine_constant_uniform;
|
||||||
|
} UnitState;
|
||||||
|
|
||||||
typedef struct _GlslProgramState
|
typedef struct _GlslProgramState
|
||||||
{
|
{
|
||||||
int ref_count;
|
int ref_count;
|
||||||
@ -72,8 +98,9 @@ typedef struct _GlslProgramState
|
|||||||
program */
|
program */
|
||||||
unsigned int user_program_age;
|
unsigned int user_program_age;
|
||||||
GLuint gl_program;
|
GLuint gl_program;
|
||||||
|
GString *header, *source;
|
||||||
|
UnitState *unit_state;
|
||||||
|
|
||||||
#ifdef HAVE_COGL_GLES2
|
|
||||||
/* To allow writing shaders that are portable between GLES 2 and
|
/* To allow writing shaders that are portable between GLES 2 and
|
||||||
* OpenGL Cogl prepends a number of boilerplate #defines and
|
* OpenGL Cogl prepends a number of boilerplate #defines and
|
||||||
* declarations to user shaders. One of those declarations is an
|
* declarations to user shaders. One of those declarations is an
|
||||||
@ -82,11 +109,6 @@ typedef struct _GlslProgramState
|
|||||||
* attributes are in use. The boilerplate also needs to be changed
|
* attributes are in use. The boilerplate also needs to be changed
|
||||||
* if this increases. */
|
* if this increases. */
|
||||||
int n_tex_coord_attribs;
|
int n_tex_coord_attribs;
|
||||||
#endif
|
|
||||||
|
|
||||||
/* This is set to TRUE if the program has changed since we last
|
|
||||||
flushed the uniforms */
|
|
||||||
gboolean gl_program_changed;
|
|
||||||
|
|
||||||
#ifdef HAVE_COGL_GLES2
|
#ifdef HAVE_COGL_GLES2
|
||||||
/* The GLES2 generated program that was generated from the user
|
/* The GLES2 generated program that was generated from the user
|
||||||
@ -96,6 +118,10 @@ typedef struct _GlslProgramState
|
|||||||
this GLSL backend starts generating its own shaders */
|
this GLSL backend starts generating its own shaders */
|
||||||
GLuint gles2_program;
|
GLuint gles2_program;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* We need to track the last pipeline that the program was used with
|
||||||
|
* so know if we need to update all of the uniforms */
|
||||||
|
CoglPipeline *last_used_for_pipeline;
|
||||||
} GlslProgramState;
|
} GlslProgramState;
|
||||||
|
|
||||||
typedef struct _CoglPipelineBackendGlslPrivate
|
typedef struct _CoglPipelineBackendGlslPrivate
|
||||||
@ -117,6 +143,7 @@ glsl_program_state_new (int n_layers)
|
|||||||
GlslProgramState *state = g_slice_new0 (GlslProgramState);
|
GlslProgramState *state = g_slice_new0 (GlslProgramState);
|
||||||
|
|
||||||
state->ref_count = 1;
|
state->ref_count = 1;
|
||||||
|
state->unit_state = g_new0 (UnitState, n_layers);
|
||||||
|
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
@ -158,23 +185,12 @@ glsl_program_state_unref (GlslProgramState *state)
|
|||||||
state->gl_program = 0;
|
state->gl_program = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
g_free (state->unit_state);
|
||||||
|
|
||||||
g_slice_free (GlslProgramState, state);
|
g_slice_free (GlslProgramState, state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This tries to find the oldest ancestor whos state would generate
|
|
||||||
* the same glsl program as the current pipeline. This is a simple
|
|
||||||
* mechanism for reducing the number of glsl programs we have to
|
|
||||||
* generate.
|
|
||||||
*/
|
|
||||||
static CoglPipeline *
|
|
||||||
find_glsl_authority (CoglPipeline *pipeline, CoglHandle user_program)
|
|
||||||
{
|
|
||||||
/* Find the first pipeline that modifies the user shader */
|
|
||||||
return _cogl_pipeline_get_authority (pipeline,
|
|
||||||
COGL_PIPELINE_STATE_USER_SHADER);
|
|
||||||
}
|
|
||||||
|
|
||||||
static CoglPipelineBackendGlslPrivate *
|
static CoglPipelineBackendGlslPrivate *
|
||||||
get_glsl_priv (CoglPipeline *pipeline)
|
get_glsl_priv (CoglPipeline *pipeline)
|
||||||
{
|
{
|
||||||
@ -270,8 +286,8 @@ _cogl_pipeline_backend_glsl_start (CoglPipeline *pipeline,
|
|||||||
CoglPipeline *authority;
|
CoglPipeline *authority;
|
||||||
CoglPipelineBackendGlslPrivate *authority_priv;
|
CoglPipelineBackendGlslPrivate *authority_priv;
|
||||||
CoglProgram *user_program;
|
CoglProgram *user_program;
|
||||||
GLuint gl_program;
|
|
||||||
GSList *l;
|
GSList *l;
|
||||||
|
int i;
|
||||||
|
|
||||||
_COGL_GET_CONTEXT (ctx, FALSE);
|
_COGL_GET_CONTEXT (ctx, FALSE);
|
||||||
|
|
||||||
@ -279,9 +295,9 @@ _cogl_pipeline_backend_glsl_start (CoglPipeline *pipeline,
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
user_program = cogl_pipeline_get_user_program (pipeline);
|
user_program = cogl_pipeline_get_user_program (pipeline);
|
||||||
if (user_program == COGL_INVALID_HANDLE ||
|
if (user_program &&
|
||||||
_cogl_program_get_language (user_program) != COGL_SHADER_LANGUAGE_GLSL)
|
_cogl_program_get_language (user_program) != COGL_SHADER_LANGUAGE_GLSL)
|
||||||
return FALSE; /* XXX: change me when we support code generation here */
|
return FALSE;
|
||||||
|
|
||||||
/* Now lookup our glsl backend private state (allocating if
|
/* Now lookup our glsl backend private state (allocating if
|
||||||
* necessary) */
|
* necessary) */
|
||||||
@ -302,12 +318,13 @@ _cogl_pipeline_backend_glsl_start (CoglPipeline *pipeline,
|
|||||||
* Also if the number of texture coordinate attributes in use has
|
* Also if the number of texture coordinate attributes in use has
|
||||||
* increased, then delete the program so we can prepend a new
|
* increased, then delete the program so we can prepend a new
|
||||||
* _cogl_tex_coord[] varying array declaration. */
|
* _cogl_tex_coord[] varying array declaration. */
|
||||||
if (priv->glsl_program_state->user_program_age == user_program->age
|
if (user_program == NULL ||
|
||||||
|
(priv->glsl_program_state->user_program_age == user_program->age
|
||||||
#ifdef HAVE_COGL_GLES2
|
#ifdef HAVE_COGL_GLES2
|
||||||
&& priv->glsl_program_state->n_tex_coord_attribs >=
|
&& (priv->glsl_program_state->n_tex_coord_attribs >=
|
||||||
n_tex_coord_attribs
|
n_tex_coord_attribs)
|
||||||
#endif
|
#endif
|
||||||
)
|
))
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
/* Destroy the existing program. We can't just dirty the whole
|
/* Destroy the existing program. We can't just dirty the whole
|
||||||
@ -326,7 +343,8 @@ _cogl_pipeline_backend_glsl_start (CoglPipeline *pipeline,
|
|||||||
* glsl-authority to maximize the chance that other pipelines can
|
* glsl-authority to maximize the chance that other pipelines can
|
||||||
* share it.
|
* share it.
|
||||||
*/
|
*/
|
||||||
authority = find_glsl_authority (pipeline, user_program);
|
authority =
|
||||||
|
_cogl_pipeline_find_codegen_authority (pipeline, user_program);
|
||||||
authority_priv = get_glsl_priv (authority);
|
authority_priv = get_glsl_priv (authority);
|
||||||
if (!authority_priv)
|
if (!authority_priv)
|
||||||
{
|
{
|
||||||
@ -342,14 +360,14 @@ _cogl_pipeline_backend_glsl_start (CoglPipeline *pipeline,
|
|||||||
GlslProgramState *glsl_program_state =
|
GlslProgramState *glsl_program_state =
|
||||||
glsl_program_state_new (n_layers);
|
glsl_program_state_new (n_layers);
|
||||||
authority_priv->glsl_program_state = glsl_program_state;
|
authority_priv->glsl_program_state = glsl_program_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_program_state =
|
|
||||||
glsl_program_state_ref (authority_priv->glsl_program_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_program_state =
|
||||||
|
glsl_program_state_ref (authority_priv->glsl_program_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If we make it here then we have a glsl_program_state struct
|
/* If we make it here then we have a glsl_program_state struct
|
||||||
@ -357,56 +375,506 @@ _cogl_pipeline_backend_glsl_start (CoglPipeline *pipeline,
|
|||||||
encountered it or because the user program has changed since it
|
encountered it or because the user program has changed since it
|
||||||
was last linked */
|
was last linked */
|
||||||
|
|
||||||
priv->glsl_program_state->gl_program_changed = TRUE;
|
|
||||||
|
|
||||||
GE_RET( gl_program, glCreateProgram () );
|
|
||||||
|
|
||||||
#ifdef HAVE_COGL_GLES2
|
#ifdef HAVE_COGL_GLES2
|
||||||
/* Find the largest count of texture coordinate attributes
|
/* Find the largest count of texture coordinate attributes
|
||||||
* associated with each of the shaders so we can ensure a consistent
|
* associated with each of the shaders so we can ensure a consistent
|
||||||
* _cogl_tex_coord[] array declaration across all of the shaders.*/
|
* _cogl_tex_coord[] array declaration across all of the shaders.*/
|
||||||
for (l = user_program->attached_shaders; l; l = l->next)
|
if (user_program)
|
||||||
{
|
for (l = user_program->attached_shaders; l; l = l->next)
|
||||||
CoglShader *shader = l->data;
|
{
|
||||||
n_tex_coord_attribs = MAX (shader->n_tex_coord_attribs,
|
CoglShader *shader = l->data;
|
||||||
n_tex_coord_attribs);
|
n_tex_coord_attribs = MAX (shader->n_tex_coord_attribs,
|
||||||
}
|
n_tex_coord_attribs);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Add all of the shaders from the user program */
|
|
||||||
for (l = user_program->attached_shaders; l; l = l->next)
|
|
||||||
{
|
|
||||||
CoglShader *shader = l->data;
|
|
||||||
|
|
||||||
g_assert (shader->language == COGL_SHADER_LANGUAGE_GLSL);
|
|
||||||
|
|
||||||
_cogl_shader_compile_real (shader, n_tex_coord_attribs);
|
|
||||||
|
|
||||||
GE( glAttachShader (gl_program, shader->gl_handle) );
|
|
||||||
}
|
|
||||||
|
|
||||||
priv->glsl_program_state->gl_program = gl_program;
|
|
||||||
priv->glsl_program_state->user_program_age = user_program->age;
|
|
||||||
#ifdef HAVE_COGL_GLES2
|
|
||||||
priv->glsl_program_state->n_tex_coord_attribs = n_tex_coord_attribs;
|
priv->glsl_program_state->n_tex_coord_attribs = n_tex_coord_attribs;
|
||||||
#endif
|
|
||||||
|
|
||||||
link_program (gl_program);
|
/* Check whether the user program contains a fragment
|
||||||
|
shader. Otherwise we need to generate one */
|
||||||
|
if (user_program)
|
||||||
|
for (l = user_program->attached_shaders; l; l = l->next)
|
||||||
|
{
|
||||||
|
CoglShader *shader = l->data;
|
||||||
|
|
||||||
|
if (shader->type == COGL_SHADER_TYPE_FRAGMENT)
|
||||||
|
goto no_fragment_shader_needed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We reuse two grow-only GStrings for code-gen. One string
|
||||||
|
contains the uniform and attribute declarations while the
|
||||||
|
other contains the main function. We need two strings
|
||||||
|
because we need to dynamically declare attributes as the
|
||||||
|
add_layer callback is invoked */
|
||||||
|
g_string_set_size (ctx->fragment_header_buffer, 0);
|
||||||
|
g_string_set_size (ctx->fragment_source_buffer, 0);
|
||||||
|
priv->glsl_program_state->header = ctx->fragment_header_buffer;
|
||||||
|
priv->glsl_program_state->source = ctx->fragment_source_buffer;
|
||||||
|
|
||||||
|
g_string_append (priv->glsl_program_state->source,
|
||||||
|
"void\n"
|
||||||
|
"main ()\n"
|
||||||
|
"{\n");
|
||||||
|
|
||||||
|
for (i = 0; i < n_layers; i++)
|
||||||
|
{
|
||||||
|
priv->glsl_program_state->unit_state[i].sampled = FALSE;
|
||||||
|
priv->glsl_program_state->unit_state[i].combine_constant_used = FALSE;
|
||||||
|
priv->glsl_program_state->unit_state[i].dirty_combine_constant = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
no_fragment_shader_needed:
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean
|
static void
|
||||||
_cogl_pipeline_backend_glsl_add_layer (CoglPipeline *pipeline,
|
add_constant_lookup (GlslProgramState *glsl_program_state,
|
||||||
CoglPipelineLayer *layer,
|
CoglPipeline *pipeline,
|
||||||
unsigned long layers_difference)
|
CoglPipelineLayer *layer,
|
||||||
|
const char *swizzle)
|
||||||
{
|
{
|
||||||
|
int unit_index = _cogl_pipeline_layer_get_unit_index (layer);
|
||||||
|
|
||||||
|
/* Create a sampler uniform for this layer if we haven't already */
|
||||||
|
if (!glsl_program_state->unit_state[unit_index].combine_constant_used)
|
||||||
|
{
|
||||||
|
g_string_append_printf (glsl_program_state->header,
|
||||||
|
"uniform vec4 _cogl_layer_constant_%i;\n",
|
||||||
|
unit_index);
|
||||||
|
glsl_program_state->unit_state[unit_index].combine_constant_used = TRUE;
|
||||||
|
glsl_program_state->unit_state[unit_index].dirty_combine_constant = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_string_append_printf (glsl_program_state->source,
|
||||||
|
"_cogl_layer_constant_%i.%s",
|
||||||
|
unit_index, swizzle);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
add_texture_lookup (GlslProgramState *glsl_program_state,
|
||||||
|
CoglPipeline *pipeline,
|
||||||
|
CoglPipelineLayer *layer,
|
||||||
|
const char *swizzle)
|
||||||
|
{
|
||||||
|
CoglHandle texture;
|
||||||
|
int unit_index = _cogl_pipeline_layer_get_unit_index (layer);
|
||||||
|
const char *target_string, *tex_coord_swizzle;
|
||||||
|
|
||||||
|
texture = _cogl_pipeline_layer_get_texture (layer);
|
||||||
|
|
||||||
|
if (texture == COGL_INVALID_HANDLE)
|
||||||
|
{
|
||||||
|
target_string = "2D";
|
||||||
|
tex_coord_swizzle = "st";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GLenum gl_target;
|
||||||
|
|
||||||
|
cogl_texture_get_gl_texture (texture, NULL, &gl_target);
|
||||||
|
switch (gl_target)
|
||||||
|
{
|
||||||
|
#ifndef HAVE_COGL_GLES2
|
||||||
|
case GL_TEXTURE_1D:
|
||||||
|
target_string = "1D";
|
||||||
|
tex_coord_swizzle = "s";
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
case GL_TEXTURE_2D:
|
||||||
|
target_string = "2D";
|
||||||
|
tex_coord_swizzle = "st";
|
||||||
|
break;
|
||||||
|
|
||||||
|
#ifdef GL_ARB_texture_rectangle
|
||||||
|
case GL_TEXTURE_RECTANGLE_ARB:
|
||||||
|
target_string = "2DRect";
|
||||||
|
tex_coord_swizzle = "st";
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
case GL_TEXTURE_3D:
|
||||||
|
target_string = "3D";
|
||||||
|
tex_coord_swizzle = "stp";
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
g_assert_not_reached ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create a sampler uniform for this layer if we haven't already */
|
||||||
|
if (!glsl_program_state->unit_state[unit_index].sampled)
|
||||||
|
{
|
||||||
|
g_string_append_printf (glsl_program_state->header,
|
||||||
|
"uniform sampler%s _cogl_sampler_%i;\n",
|
||||||
|
target_string,
|
||||||
|
unit_index);
|
||||||
|
glsl_program_state->unit_state[unit_index].sampled = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_string_append_printf (glsl_program_state->source,
|
||||||
|
"texture%s (_cogl_sampler_%i, ",
|
||||||
|
target_string, unit_index);
|
||||||
|
|
||||||
|
/* If point sprite coord generation is being used then divert to the
|
||||||
|
built-in varying var for that instead of the texture
|
||||||
|
coordinates */
|
||||||
|
if (cogl_pipeline_get_layer_point_sprite_coords_enabled (pipeline,
|
||||||
|
layer->index))
|
||||||
|
g_string_append_printf (glsl_program_state->source,
|
||||||
|
"gl_PointCoord.%s",
|
||||||
|
tex_coord_swizzle);
|
||||||
|
else
|
||||||
|
g_string_append_printf (glsl_program_state->source,
|
||||||
|
"cogl_tex_coord_in[%d].%s",
|
||||||
|
unit_index, tex_coord_swizzle);
|
||||||
|
|
||||||
|
g_string_append_printf (glsl_program_state->source, ").%s", swizzle);
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
int unit_index;
|
||||||
|
CoglPipelineLayer *layer;
|
||||||
|
} FindPipelineLayerData;
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
find_pipeline_layer_cb (CoglPipelineLayer *layer,
|
||||||
|
void *user_data)
|
||||||
|
{
|
||||||
|
FindPipelineLayerData *data = user_data;
|
||||||
|
int unit_index;
|
||||||
|
|
||||||
|
unit_index = _cogl_pipeline_layer_get_unit_index (layer);
|
||||||
|
|
||||||
|
if (unit_index == data->unit_index)
|
||||||
|
{
|
||||||
|
data->layer = layer;
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
add_arg (GlslProgramState *glsl_program_state,
|
||||||
|
CoglPipeline *pipeline,
|
||||||
|
CoglPipelineLayer *layer,
|
||||||
|
GLint src,
|
||||||
|
GLenum operand,
|
||||||
|
const char *swizzle)
|
||||||
|
{
|
||||||
|
GString *shader_source = glsl_program_state->source;
|
||||||
|
char alpha_swizzle[5] = "aaaa";
|
||||||
|
|
||||||
|
g_string_append_c (shader_source, '(');
|
||||||
|
|
||||||
|
if (operand == GL_ONE_MINUS_SRC_COLOR || operand == GL_ONE_MINUS_SRC_ALPHA)
|
||||||
|
g_string_append_printf (shader_source,
|
||||||
|
"vec4(1.0, 1.0, 1.0, 1.0).%s - ",
|
||||||
|
swizzle);
|
||||||
|
|
||||||
|
/* If the operand is reading from the alpha then replace the swizzle
|
||||||
|
with the same number of copies of the alpha */
|
||||||
|
if (operand == GL_SRC_ALPHA || operand == GL_ONE_MINUS_SRC_ALPHA)
|
||||||
|
{
|
||||||
|
alpha_swizzle[strlen (swizzle)] = '\0';
|
||||||
|
swizzle = alpha_swizzle;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (src)
|
||||||
|
{
|
||||||
|
case GL_TEXTURE:
|
||||||
|
add_texture_lookup (glsl_program_state,
|
||||||
|
pipeline,
|
||||||
|
layer,
|
||||||
|
swizzle);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GL_CONSTANT:
|
||||||
|
add_constant_lookup (glsl_program_state,
|
||||||
|
pipeline,
|
||||||
|
layer,
|
||||||
|
swizzle);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GL_PREVIOUS:
|
||||||
|
if (_cogl_pipeline_layer_get_unit_index (layer) > 0)
|
||||||
|
{
|
||||||
|
g_string_append_printf (shader_source, "cogl_color_out.%s", swizzle);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* flow through */
|
||||||
|
case GL_PRIMARY_COLOR:
|
||||||
|
g_string_append_printf (shader_source, "cogl_color_in.%s", swizzle);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
if (src >= GL_TEXTURE0 && src < GL_TEXTURE0 + 32)
|
||||||
|
{
|
||||||
|
FindPipelineLayerData data;
|
||||||
|
|
||||||
|
data.unit_index = src - GL_TEXTURE0;
|
||||||
|
data.layer = layer;
|
||||||
|
|
||||||
|
_cogl_pipeline_foreach_layer_internal (pipeline,
|
||||||
|
find_pipeline_layer_cb,
|
||||||
|
&data);
|
||||||
|
|
||||||
|
add_texture_lookup (glsl_program_state,
|
||||||
|
pipeline,
|
||||||
|
data.layer,
|
||||||
|
swizzle);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_string_append_c (shader_source, ')');
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
append_masked_combine (CoglPipeline *pipeline,
|
||||||
|
CoglPipelineLayer *layer,
|
||||||
|
const char *swizzle,
|
||||||
|
GLint function,
|
||||||
|
GLint *src,
|
||||||
|
GLint *op)
|
||||||
|
{
|
||||||
|
GlslProgramState *glsl_program_state = get_glsl_program_state (pipeline);
|
||||||
|
GString *shader_source = glsl_program_state->source;
|
||||||
|
|
||||||
|
g_string_append_printf (glsl_program_state->source,
|
||||||
|
" cogl_color_out.%s = ", swizzle);
|
||||||
|
|
||||||
|
switch (function)
|
||||||
|
{
|
||||||
|
case GL_REPLACE:
|
||||||
|
add_arg (glsl_program_state, pipeline, layer,
|
||||||
|
src[0], op[0], swizzle);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GL_MODULATE:
|
||||||
|
add_arg (glsl_program_state, pipeline, layer,
|
||||||
|
src[0], op[0], swizzle);
|
||||||
|
g_string_append (shader_source, " * ");
|
||||||
|
add_arg (glsl_program_state, pipeline, layer,
|
||||||
|
src[1], op[1], swizzle);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GL_ADD:
|
||||||
|
add_arg (glsl_program_state, pipeline, layer,
|
||||||
|
src[0], op[0], swizzle);
|
||||||
|
g_string_append (shader_source, " + ");
|
||||||
|
add_arg (glsl_program_state, pipeline, layer,
|
||||||
|
src[1], op[1], swizzle);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GL_ADD_SIGNED:
|
||||||
|
add_arg (glsl_program_state, pipeline, layer,
|
||||||
|
src[0], op[0], swizzle);
|
||||||
|
g_string_append (shader_source, " + ");
|
||||||
|
add_arg (glsl_program_state, pipeline, layer,
|
||||||
|
src[1], op[1], swizzle);
|
||||||
|
g_string_append_printf (shader_source,
|
||||||
|
" - vec4(0.5, 0.5, 0.5, 0.5).%s",
|
||||||
|
swizzle);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GL_SUBTRACT:
|
||||||
|
add_arg (glsl_program_state, pipeline, layer,
|
||||||
|
src[0], op[0], swizzle);
|
||||||
|
g_string_append (shader_source, " - ");
|
||||||
|
add_arg (glsl_program_state, pipeline, layer,
|
||||||
|
src[1], op[1], swizzle);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GL_INTERPOLATE:
|
||||||
|
add_arg (glsl_program_state, pipeline, layer,
|
||||||
|
src[0], op[0], swizzle);
|
||||||
|
g_string_append (shader_source, " * ");
|
||||||
|
add_arg (glsl_program_state, pipeline, layer,
|
||||||
|
src[2], op[2], swizzle);
|
||||||
|
g_string_append (shader_source, " + ");
|
||||||
|
add_arg (glsl_program_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_program_state, pipeline, layer,
|
||||||
|
src[2], op[2], swizzle);
|
||||||
|
g_string_append_c (shader_source, ')');
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GL_DOT3_RGB:
|
||||||
|
case GL_DOT3_RGBA:
|
||||||
|
g_string_append (shader_source, "vec4(4 * ((");
|
||||||
|
add_arg (glsl_program_state, pipeline, layer,
|
||||||
|
src[0], op[0], "r");
|
||||||
|
g_string_append (shader_source, " - 0.5) * (");
|
||||||
|
add_arg (glsl_program_state, pipeline, layer,
|
||||||
|
src[1], op[1], "r");
|
||||||
|
g_string_append (shader_source, " - 0.5) + (");
|
||||||
|
add_arg (glsl_program_state, pipeline, layer,
|
||||||
|
src[0], op[0], "g");
|
||||||
|
g_string_append (shader_source, " - 0.5) * (");
|
||||||
|
add_arg (glsl_program_state, pipeline, layer,
|
||||||
|
src[1], op[1], "g");
|
||||||
|
g_string_append (shader_source, " - 0.5) + (");
|
||||||
|
add_arg (glsl_program_state, pipeline, layer,
|
||||||
|
src[0], op[0], "b");
|
||||||
|
g_string_append (shader_source, " - 0.5) * (");
|
||||||
|
add_arg (glsl_program_state, pipeline, layer,
|
||||||
|
src[1], op[1], "b");
|
||||||
|
g_string_append_printf (shader_source, " - 0.5))).%s", swizzle);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_string_append_printf (shader_source, ";\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
_cogl_pipeline_backend_glsl_add_layer (CoglPipeline *pipeline,
|
||||||
|
CoglPipelineLayer *layer,
|
||||||
|
unsigned long layers_difference)
|
||||||
|
{
|
||||||
|
GlslProgramState *glsl_program_state = get_glsl_program_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_program_state->source)
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
if (!_cogl_pipeline_need_texture_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 == GL_DOT3_RGBA)
|
||||||
|
append_masked_combine (pipeline,
|
||||||
|
layer,
|
||||||
|
"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,
|
||||||
|
"rgb",
|
||||||
|
big_state->texture_combine_rgb_func,
|
||||||
|
big_state->texture_combine_rgb_src,
|
||||||
|
big_state->texture_combine_rgb_op);
|
||||||
|
append_masked_combine (pipeline,
|
||||||
|
layer,
|
||||||
|
"a",
|
||||||
|
big_state->texture_combine_alpha_func,
|
||||||
|
big_state->texture_combine_alpha_src,
|
||||||
|
big_state->texture_combine_alpha_op);
|
||||||
|
}
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
_cogl_pipeline_backend_glsl_passthrough (CoglPipeline *pipeline)
|
_cogl_pipeline_backend_glsl_passthrough (CoglPipeline *pipeline)
|
||||||
{
|
{
|
||||||
|
GlslProgramState *glsl_program_state = get_glsl_program_state (pipeline);
|
||||||
|
|
||||||
|
if (!glsl_program_state->source)
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
g_string_append (glsl_program_state->source,
|
||||||
|
" cogl_color_out = cogl_color_in;\n");
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
int unit;
|
||||||
|
GLuint gl_program;
|
||||||
|
gboolean update_all;
|
||||||
|
GlslProgramState *glsl_program_state;
|
||||||
|
} UpdateUniformsState;
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
get_uniform_cb (CoglPipeline *pipeline,
|
||||||
|
int layer_index,
|
||||||
|
void *user_data)
|
||||||
|
{
|
||||||
|
UpdateUniformsState *state = user_data;
|
||||||
|
GlslProgramState *glsl_program_state = state->glsl_program_state;
|
||||||
|
UnitState *unit_state = &glsl_program_state->unit_state[state->unit];
|
||||||
|
GLint uniform_location;
|
||||||
|
|
||||||
|
_COGL_GET_CONTEXT (ctx, FALSE);
|
||||||
|
|
||||||
|
if (unit_state->sampled)
|
||||||
|
{
|
||||||
|
/* We can reuse the source buffer to create the uniform name because
|
||||||
|
the program has now been linked */
|
||||||
|
g_string_set_size (ctx->fragment_source_buffer, 0);
|
||||||
|
g_string_append_printf (ctx->fragment_source_buffer,
|
||||||
|
"_cogl_sampler_%i", state->unit);
|
||||||
|
|
||||||
|
GE_RET( uniform_location,
|
||||||
|
glGetUniformLocation (state->gl_program,
|
||||||
|
ctx->fragment_source_buffer->str) );
|
||||||
|
|
||||||
|
g_return_val_if_fail (uniform_location != -1, TRUE);
|
||||||
|
|
||||||
|
/* We can set the uniform immediately because the samplers are
|
||||||
|
the unit index not the texture object number so it will never
|
||||||
|
change. Unfortunately GL won't let us use a constant instead
|
||||||
|
of a uniform */
|
||||||
|
GE( glUniform1i (uniform_location, state->unit) );
|
||||||
|
}
|
||||||
|
|
||||||
|
if (unit_state->combine_constant_used)
|
||||||
|
{
|
||||||
|
g_string_set_size (ctx->fragment_source_buffer, 0);
|
||||||
|
g_string_append_printf (ctx->fragment_source_buffer,
|
||||||
|
"_cogl_layer_constant_%i", state->unit);
|
||||||
|
|
||||||
|
GE_RET( uniform_location,
|
||||||
|
glGetUniformLocation (state->gl_program,
|
||||||
|
ctx->fragment_source_buffer->str) );
|
||||||
|
|
||||||
|
g_return_val_if_fail (uniform_location != -1, TRUE);
|
||||||
|
|
||||||
|
unit_state->combine_constant_uniform = uniform_location;
|
||||||
|
}
|
||||||
|
|
||||||
|
state->unit++;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
update_constants_cb (CoglPipeline *pipeline,
|
||||||
|
int layer_index,
|
||||||
|
void *user_data)
|
||||||
|
{
|
||||||
|
UpdateUniformsState *state = user_data;
|
||||||
|
GlslProgramState *glsl_program_state = state->glsl_program_state;
|
||||||
|
UnitState *unit_state = &glsl_program_state->unit_state[state->unit++];
|
||||||
|
|
||||||
|
_COGL_GET_CONTEXT (ctx, FALSE);
|
||||||
|
|
||||||
|
if (unit_state->combine_constant_used &&
|
||||||
|
(state->update_all || unit_state->dirty_combine_constant))
|
||||||
|
{
|
||||||
|
float constant[4];
|
||||||
|
_cogl_pipeline_get_layer_combine_constant (pipeline,
|
||||||
|
layer_index,
|
||||||
|
constant);
|
||||||
|
GE (glUniform4fv (unit_state->combine_constant_uniform,
|
||||||
|
1, constant));
|
||||||
|
unit_state->dirty_combine_constant = FALSE;
|
||||||
|
}
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -415,11 +883,105 @@ _cogl_pipeline_backend_glsl_end (CoglPipeline *pipeline,
|
|||||||
unsigned long pipelines_difference)
|
unsigned long pipelines_difference)
|
||||||
{
|
{
|
||||||
GlslProgramState *glsl_program_state = get_glsl_program_state (pipeline);
|
GlslProgramState *glsl_program_state = get_glsl_program_state (pipeline);
|
||||||
|
CoglProgram *user_program;
|
||||||
GLuint gl_program;
|
GLuint gl_program;
|
||||||
gboolean gl_program_changed;
|
gboolean gl_program_changed = FALSE;
|
||||||
|
UpdateUniformsState state;
|
||||||
|
|
||||||
|
_COGL_GET_CONTEXT (ctx, FALSE);
|
||||||
|
|
||||||
gl_program = glsl_program_state->gl_program;
|
gl_program = glsl_program_state->gl_program;
|
||||||
gl_program_changed = glsl_program_state->gl_program_changed;
|
user_program = cogl_pipeline_get_user_program (pipeline);
|
||||||
|
|
||||||
|
if (gl_program == 0)
|
||||||
|
{
|
||||||
|
gl_program_changed = TRUE;
|
||||||
|
|
||||||
|
GE_RET( gl_program, glCreateProgram () );
|
||||||
|
|
||||||
|
if (user_program)
|
||||||
|
{
|
||||||
|
GSList *l;
|
||||||
|
|
||||||
|
/* Add all of the shaders from the user program */
|
||||||
|
for (l = user_program->attached_shaders; l; l = l->next)
|
||||||
|
{
|
||||||
|
CoglShader *shader = l->data;
|
||||||
|
|
||||||
|
g_assert (shader->language == COGL_SHADER_LANGUAGE_GLSL);
|
||||||
|
|
||||||
|
_cogl_shader_compile_real (shader,
|
||||||
|
glsl_program_state->
|
||||||
|
n_tex_coord_attribs);
|
||||||
|
|
||||||
|
GE( glAttachShader (gl_program, shader->gl_handle) );
|
||||||
|
}
|
||||||
|
|
||||||
|
glsl_program_state->user_program_age = user_program->age;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (glsl_program_state->source)
|
||||||
|
{
|
||||||
|
const GLchar *source_strings[2];
|
||||||
|
GLint lengths[2];
|
||||||
|
GLint compile_status;
|
||||||
|
GLuint shader;
|
||||||
|
|
||||||
|
COGL_STATIC_COUNTER (backend_glsl_compile_counter,
|
||||||
|
"glsl compile counter",
|
||||||
|
"Increments each time a new GLSL "
|
||||||
|
"program is compiled",
|
||||||
|
0 /* no application private data */);
|
||||||
|
COGL_COUNTER_INC (_cogl_uprof_context, backend_glsl_compile_counter);
|
||||||
|
|
||||||
|
g_string_append (glsl_program_state->source, "}\n");
|
||||||
|
|
||||||
|
if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_SHOW_SOURCE))
|
||||||
|
g_message ("pipeline program:\n%s%s",
|
||||||
|
glsl_program_state->header->str,
|
||||||
|
glsl_program_state->source->str);
|
||||||
|
|
||||||
|
GE_RET( shader, glCreateShader (GL_FRAGMENT_SHADER) );
|
||||||
|
|
||||||
|
lengths[0] = glsl_program_state->header->len;
|
||||||
|
source_strings[0] = glsl_program_state->header->str;
|
||||||
|
lengths[1] = glsl_program_state->source->len;
|
||||||
|
source_strings[1] = glsl_program_state->source->str;
|
||||||
|
|
||||||
|
_cogl_shader_set_source_with_boilerplate (shader, GL_FRAGMENT_SHADER,
|
||||||
|
glsl_program_state->
|
||||||
|
n_tex_coord_attribs,
|
||||||
|
2, /* count */
|
||||||
|
source_strings, lengths);
|
||||||
|
|
||||||
|
GE( glCompileShader (shader) );
|
||||||
|
GE( glGetShaderiv (shader, GL_COMPILE_STATUS, &compile_status) );
|
||||||
|
|
||||||
|
if (!compile_status)
|
||||||
|
{
|
||||||
|
GLint len = 0;
|
||||||
|
char *shader_log;
|
||||||
|
|
||||||
|
GE( glGetShaderiv (shader, GL_INFO_LOG_LENGTH, &len) );
|
||||||
|
shader_log = g_alloca (len);
|
||||||
|
GE( glGetShaderInfoLog (shader, len, &len, shader_log) );
|
||||||
|
g_warning ("Shader compilation failed:\n%s", shader_log);
|
||||||
|
}
|
||||||
|
|
||||||
|
GE( glAttachShader (gl_program, shader) );
|
||||||
|
|
||||||
|
/* We can delete the shader now, but it won't actually be
|
||||||
|
destroyed until the program is also desroyed */
|
||||||
|
GE( glDeleteShader (shader) );
|
||||||
|
|
||||||
|
glsl_program_state->header = NULL;
|
||||||
|
glsl_program_state->source = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
link_program (gl_program);
|
||||||
|
|
||||||
|
glsl_program_state->gl_program = gl_program;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef HAVE_COGL_GLES2
|
#ifdef HAVE_COGL_GLES2
|
||||||
/* This function is a massive hack to get the GLES2 backend to
|
/* This function is a massive hack to get the GLES2 backend to
|
||||||
@ -437,10 +999,31 @@ _cogl_pipeline_backend_glsl_end (CoglPipeline *pipeline,
|
|||||||
_cogl_use_program (gl_program, COGL_PIPELINE_PROGRAM_TYPE_GLSL);
|
_cogl_use_program (gl_program, COGL_PIPELINE_PROGRAM_TYPE_GLSL);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
_cogl_program_flush_uniforms (cogl_pipeline_get_user_program (pipeline),
|
state.unit = 0;
|
||||||
gl_program, gl_program_changed);
|
state.gl_program = gl_program;
|
||||||
|
state.glsl_program_state = glsl_program_state;
|
||||||
|
|
||||||
glsl_program_state->gl_program_changed = FALSE;
|
if (gl_program_changed)
|
||||||
|
cogl_pipeline_foreach_layer (pipeline,
|
||||||
|
get_uniform_cb,
|
||||||
|
&state);
|
||||||
|
|
||||||
|
state.unit = 0;
|
||||||
|
state.update_all = (gl_program_changed ||
|
||||||
|
glsl_program_state->last_used_for_pipeline != pipeline);
|
||||||
|
|
||||||
|
cogl_pipeline_foreach_layer (pipeline,
|
||||||
|
update_constants_cb,
|
||||||
|
&state);
|
||||||
|
|
||||||
|
if (user_program)
|
||||||
|
_cogl_program_flush_uniforms (user_program,
|
||||||
|
gl_program,
|
||||||
|
gl_program_changed);
|
||||||
|
|
||||||
|
/* We need to track the last pipeline that the program was used with
|
||||||
|
* so know if we need to update all of the uniforms */
|
||||||
|
glsl_program_state->last_used_for_pipeline = pipeline;
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
@ -450,15 +1033,60 @@ _cogl_pipeline_backend_glsl_pre_change_notify (CoglPipeline *pipeline,
|
|||||||
CoglPipelineState change,
|
CoglPipelineState change,
|
||||||
const CoglColor *new_color)
|
const CoglColor *new_color)
|
||||||
{
|
{
|
||||||
static const unsigned long glsl_op_changes =
|
static const unsigned long fragment_op_changes =
|
||||||
|
COGL_PIPELINE_STATE_LAYERS |
|
||||||
COGL_PIPELINE_STATE_USER_SHADER;
|
COGL_PIPELINE_STATE_USER_SHADER;
|
||||||
|
/* TODO: COGL_PIPELINE_STATE_FOG */
|
||||||
|
|
||||||
if (!(change & glsl_op_changes))
|
if (!(change & fragment_op_changes))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
dirty_glsl_program_state (pipeline);
|
dirty_glsl_program_state (pipeline);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* NB: layers are considered immutable once they have any dependants
|
||||||
|
* so although multiple pipelines can end up depending on a single
|
||||||
|
* static layer, we can guarantee that if a layer is being *changed*
|
||||||
|
* then it can only have one pipeline depending on it.
|
||||||
|
*
|
||||||
|
* XXX: Don't forget this is *pre* change, we can't read the new value
|
||||||
|
* yet!
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
_cogl_pipeline_backend_glsl_layer_pre_change_notify (
|
||||||
|
CoglPipeline *owner,
|
||||||
|
CoglPipelineLayer *layer,
|
||||||
|
CoglPipelineLayerState change)
|
||||||
|
{
|
||||||
|
CoglPipelineBackendGlslPrivate *priv;
|
||||||
|
static const unsigned long not_fragment_op_changes =
|
||||||
|
COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT |
|
||||||
|
COGL_PIPELINE_LAYER_STATE_TEXTURE;
|
||||||
|
|
||||||
|
priv = get_glsl_priv (owner);
|
||||||
|
if (!priv)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!(change & not_fragment_op_changes))
|
||||||
|
{
|
||||||
|
dirty_glsl_program_state (owner);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (change & COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT)
|
||||||
|
{
|
||||||
|
GlslProgramState *glsl_program_state =
|
||||||
|
get_glsl_program_state (owner);
|
||||||
|
int unit_index = _cogl_pipeline_layer_get_unit_index (layer);
|
||||||
|
glsl_program_state->unit_state[unit_index].dirty_combine_constant = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO: we could be saving snippets of texture combine code along
|
||||||
|
* with each layer and then when a layer changes we would just free
|
||||||
|
* the snippet. */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
_cogl_pipeline_backend_glsl_free_priv (CoglPipeline *pipeline)
|
_cogl_pipeline_backend_glsl_free_priv (CoglPipeline *pipeline)
|
||||||
{
|
{
|
||||||
@ -481,7 +1109,7 @@ const CoglPipelineBackend _cogl_pipeline_glsl_backend =
|
|||||||
_cogl_pipeline_backend_glsl_end,
|
_cogl_pipeline_backend_glsl_end,
|
||||||
_cogl_pipeline_backend_glsl_pre_change_notify,
|
_cogl_pipeline_backend_glsl_pre_change_notify,
|
||||||
NULL, /* pipeline_set_parent_notify */
|
NULL, /* pipeline_set_parent_notify */
|
||||||
NULL, /* layer_pre_change_notify */
|
_cogl_pipeline_backend_glsl_layer_pre_change_notify,
|
||||||
_cogl_pipeline_backend_glsl_free_priv,
|
_cogl_pipeline_backend_glsl_free_priv,
|
||||||
NULL /* free_layer_priv */
|
NULL /* free_layer_priv */
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user