cogl-pipeline-progend-glsl: Generalize updating GLES2 uniforms

The uniforms for the alpha test reference value and point size on
GLES2 are updating using similar code. This generalizes the code so
that there is a static array of predefined builtin uniforms which
contains the uniform name, a pointer to a function to get the value
from the pipeline, a pointer to a function to update the uniform and a
flag representing which CoglPipelineState change affects the
uniform. The uniforms are then updated in a loop. This should simplify
adding more builtin uniforms.
This commit is contained in:
Neil Roberts 2011-01-13 18:24:22 +00:00
parent b2285058a4
commit 242d9a5002

View File

@ -56,6 +56,37 @@
#define glUniform1f ctx->drv.pf_glUniform1f #define glUniform1f ctx->drv.pf_glUniform1f
#define glUniform4fv ctx->drv.pf_glUniform4fv #define glUniform4fv ctx->drv.pf_glUniform4fv
#else
/* These are used to generalise updating some uniforms that are
required when building for GLES2 */
typedef void (* UpdateUniformFunc) (CoglPipeline *pipeline,
int uniform_location,
void *getter_func);
static void update_float_uniform (CoglPipeline *pipeline,
int uniform_location,
void *getter_func);
typedef struct
{
const char *uniform_name;
void *getter_func;
UpdateUniformFunc update_func;
CoglPipelineState change;
} BuiltinUniformData;
static BuiltinUniformData builtin_uniforms[] =
{
{ "cogl_point_size_in",
cogl_pipeline_get_point_size, update_float_uniform,
COGL_PIPELINE_STATE_POINT_SIZE },
{ "_cogl_alpha_test_ref",
cogl_pipeline_get_alpha_test_reference, update_float_uniform,
COGL_PIPELINE_STATE_ALPHA_FUNC_REFERENCE }
};
#endif /* HAVE_COGL_GLES2 */ #endif /* HAVE_COGL_GLES2 */
const CoglPipelineProgend _cogl_pipeline_glsl_progend; const CoglPipelineProgend _cogl_pipeline_glsl_progend;
@ -90,13 +121,8 @@ typedef struct
int n_tex_coord_attribs; int n_tex_coord_attribs;
#ifdef HAVE_COGL_GLES2 #ifdef HAVE_COGL_GLES2
/* Under GLES2 the alpha test is implemented in the shader. We need unsigned long dirty_builtin_uniforms;
a uniform for the reference value */ GLint builtin_uniform_locations[G_N_ELEMENTS (builtin_uniforms)];
gboolean dirty_alpha_test_reference;
GLint alpha_test_reference_uniform;
gboolean dirty_point_size;
GLint point_size_uniform;
/* Under GLES2 we can't use the builtin functions to set attribute /* Under GLES2 we can't use the builtin functions to set attribute
pointers such as the vertex position. Instead the vertex pointers such as the vertex position. Instead the vertex
@ -454,37 +480,23 @@ update_constants_cb (CoglPipeline *pipeline,
#ifdef HAVE_COGL_GLES2 #ifdef HAVE_COGL_GLES2
static void static void
update_alpha_test_reference (CoglPipeline *pipeline, update_builtin_uniforms (CoglPipeline *pipeline,
GLuint gl_program, GLuint gl_program,
CoglPipelineProgendPrivate *priv) CoglPipelineProgendPrivate *priv)
{ {
float alpha_reference; int i;
if (priv->dirty_alpha_test_reference && if (priv->dirty_builtin_uniforms == 0)
priv->alpha_test_reference_uniform != -1) return;
{
alpha_reference = cogl_pipeline_get_alpha_test_reference (pipeline);
GE( glUniform1f (priv->alpha_test_reference_uniform, for (i = 0; i < G_N_ELEMENTS (builtin_uniforms); i++)
alpha_reference) ); if ((priv->dirty_builtin_uniforms & (1 << i)) &&
priv->builtin_uniform_locations[i] != -1)
builtin_uniforms[i].update_func (pipeline,
priv->builtin_uniform_locations[i],
builtin_uniforms[i].getter_func);
priv->dirty_alpha_test_reference = FALSE; priv->dirty_builtin_uniforms = 0;
}
}
static void
update_point_size (CoglPipeline *pipeline,
GLuint gl_program,
CoglPipelineProgendPrivate *priv)
{
if (priv->dirty_point_size && priv->point_size_uniform != -1)
{
float point_size = cogl_pipeline_get_point_size (pipeline);
GE( glUniform1f (priv->point_size_uniform, point_size) );
priv->dirty_point_size = FALSE;
}
} }
#endif /* HAVE_COGL_GLES2 */ #endif /* HAVE_COGL_GLES2 */
@ -650,12 +662,15 @@ _cogl_pipeline_progend_glsl_end (CoglPipeline *pipeline,
#ifdef HAVE_COGL_GLES2 #ifdef HAVE_COGL_GLES2
if (program_changed) if (program_changed)
{ {
int i;
clear_attribute_cache (priv); clear_attribute_cache (priv);
clear_flushed_matrix_stacks (priv); clear_flushed_matrix_stacks (priv);
GE_RET( priv->alpha_test_reference_uniform, for (i = 0; i < G_N_ELEMENTS (builtin_uniforms); i++)
glGetUniformLocation (gl_program, GE_RET( priv->builtin_uniform_locations[i],
"_cogl_alpha_test_ref") ); glGetUniformLocation (gl_program,
builtin_uniforms[i].uniform_name) );
GE_RET( priv->modelview_uniform, GE_RET( priv->modelview_uniform,
glGetUniformLocation (gl_program, glGetUniformLocation (gl_program,
@ -668,20 +683,12 @@ _cogl_pipeline_progend_glsl_end (CoglPipeline *pipeline,
GE_RET( priv->mvp_uniform, GE_RET( priv->mvp_uniform,
glGetUniformLocation (gl_program, glGetUniformLocation (gl_program,
"cogl_modelview_projection_matrix") ); "cogl_modelview_projection_matrix") );
GE_RET( priv->point_size_uniform,
glGetUniformLocation (gl_program,
"cogl_point_size_in") );
} }
if (program_changed || if (program_changed ||
priv->last_used_for_pipeline != pipeline) priv->last_used_for_pipeline != pipeline)
{ priv->dirty_builtin_uniforms = ~(unsigned long) 0;
priv->dirty_alpha_test_reference = TRUE;
priv->dirty_point_size = TRUE;
}
update_alpha_test_reference (pipeline, gl_program, priv); update_builtin_uniforms (pipeline, gl_program, priv);
update_point_size (pipeline, gl_program, priv);
#endif #endif
if (user_program) if (user_program)
@ -702,17 +709,18 @@ _cogl_pipeline_progend_glsl_pre_change_notify (CoglPipeline *pipeline,
if ((change & COGL_PIPELINE_STATE_AFFECTS_FRAGMENT_CODEGEN)) if ((change & COGL_PIPELINE_STATE_AFFECTS_FRAGMENT_CODEGEN))
dirty_glsl_program_state (pipeline); dirty_glsl_program_state (pipeline);
#ifdef HAVE_COGL_GLES2 #ifdef HAVE_COGL_GLES2
else if ((change & COGL_PIPELINE_STATE_ALPHA_FUNC_REFERENCE)) else
{ {
CoglPipelineProgendPrivate *priv = get_glsl_priv (pipeline); int i;
if (priv)
priv->dirty_alpha_test_reference = TRUE; for (i = 0; i < G_N_ELEMENTS (builtin_uniforms); i++)
} if ((change & builtin_uniforms[i].change))
else if ((change & COGL_PIPELINE_STATE_POINT_SIZE)) {
{ CoglPipelineProgendPrivate *priv = get_glsl_priv (pipeline);
CoglPipelineProgendPrivate *priv = get_glsl_priv (pipeline); if (priv)
if (priv) priv->dirty_builtin_uniforms |= 1 << i;
priv->dirty_point_size = TRUE; return;
}
} }
#endif /* HAVE_COGL_GLES2 */ #endif /* HAVE_COGL_GLES2 */
} }
@ -911,6 +919,18 @@ _cogl_pipeline_progend_glsl_pre_paint (CoglPipeline *pipeline)
priv); priv);
} }
static void
update_float_uniform (CoglPipeline *pipeline,
int uniform_location,
void *getter_func)
{
float (* float_getter_func) (CoglPipeline *) = getter_func;
float value;
value = float_getter_func (pipeline);
GE( glUniform1f (uniform_location, value) );
}
#endif #endif
const CoglPipelineProgend _cogl_pipeline_glsl_progend = const CoglPipelineProgend _cogl_pipeline_glsl_progend =