diff --git a/ChangeLog b/ChangeLog index c1db93827..fd4f53315 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,29 @@ +2008-06-24 Neil Roberts + + * clutter/cogl/gles/cogl-gles2-wrapper.h: + * clutter/cogl/gles/cogl-gles2-wrapper.c: All of the settings and + uniforms are now proxied into COGL variables instead of setting + the GL uniforms directly. Just before glDrawArrays is executed a + shader is generated using the given settings to avoid using 'if' + statements. The shaders are cached. + + * clutter/cogl/gles/cogl-fixed-vertex-shader.glsl: + * clutter/cogl/gles/cogl-fixed-fragment-shader.glsl: The shaders + are now split into parts using comments instead of 'if' statements + so that the simplest shader can be generated on the fly. + + * clutter/cogl/gles/stringify.sh: Now splits up the shader sources + into separate C strings where deliminated by special comments. + + * clutter/cogl/gles/cogl-program.h: + * clutter/cogl/gles/cogl-program.c: A custom shader can no longer + be directly linked with the fixed-functionality replacement + because the replacement changes depending on the settings. Instead + the bound shader is linked with the appropriate replacement shader + just before glDrawArrays is executed. The custom uniform variables + must also be proxied through COGL variables because their location + can change when relinked. + 2008-06-24 Øyvind Kolås * clutter/fruity/clutter-fruity.c: removed dead code and unused diff --git a/clutter/cogl/gles/cogl-fixed-fragment-shader.glsl b/clutter/cogl/gles/cogl-fixed-fragment-shader.glsl index 68e026160..2a5c7b676 100644 --- a/clutter/cogl/gles/cogl-fixed-fragment-shader.glsl +++ b/clutter/cogl/gles/cogl-fixed-fragment-shader.glsl @@ -1,3 +1,5 @@ +/*** cogl_fixed_fragment_shader_start ***/ + /* There is no default precision for floats in fragment shaders in GLES 2 so we need to define one */ precision mediump float; @@ -8,86 +10,64 @@ varying vec2 tex_coord; varying float fog_amount; /* Texturing options */ -uniform bool texture_2d_enabled; uniform sampler2D texture_unit; -uniform bool alpha_only; /* Fogging options */ -uniform bool fog_enabled; uniform vec4 fog_color; /* Alpha test options */ -uniform bool alpha_test_enabled; -uniform int alpha_test_func; uniform float alpha_test_ref; -/* Alpha test functions */ -const int GL_NEVER = 0x0200; -const int GL_LESS = 0x0201; -const int GL_EQUAL = 0x0202; -const int GL_LEQUAL = 0x0203; -const int GL_GREATER = 0x0204; -const int GL_NOTEQUAL = 0x0205; -const int GL_GEQUAL = 0x0206; - void main (void) { - if (texture_2d_enabled) - { - if (alpha_only) - { - /* If the texture only has an alpha channel (eg, with the - textures from the pango renderer) then the RGB components - will be black. We want to use the RGB from the current - color in that case */ - gl_FragColor = frag_color; - gl_FragColor.a *= texture2D (texture_unit, tex_coord).a; - } - else - gl_FragColor = frag_color * texture2D (texture_unit, tex_coord); - } - else - gl_FragColor = frag_color; + /*** cogl_fixed_fragment_shader_texture_alpha_only ***/ - if (fog_enabled) - /* Mix the calculated color with the fog color */ - gl_FragColor.rgb = mix (fog_color.rgb, gl_FragColor.rgb, fog_amount); + /* If the texture only has an alpha channel (eg, with the textures + from the pango renderer) then the RGB components will be + black. We want to use the RGB from the current color in that + case */ + gl_FragColor = frag_color; + gl_FragColor.a *= texture2D (texture_unit, tex_coord).a; + + /*** cogl_fixed_fragment_shader_texture ***/ + + /* This pointless extra variable is needed to work around an + apparent bug in the PowerVR drivers. Without it the alpha + blending seems to stop working */ + vec4 frag_color_copy = frag_color; + gl_FragColor = frag_color_copy * texture2D (texture_unit, tex_coord); + + /*** cogl_fixed_fragment_shader_solid_color ***/ + gl_FragColor = frag_color; + + /*** cogl_fixed_fragment_shader_fog ***/ + + /* Mix the calculated color with the fog color */ + gl_FragColor.rgb = mix (fog_color.rgb, gl_FragColor.rgb, fog_amount); /* Alpha testing */ - if (alpha_test_enabled) - { - if (alpha_test_func == GL_NEVER) - discard; - else if (alpha_test_func == GL_LESS) - { - if (gl_FragColor.a >= alpha_test_ref) - discard; - } - else if (alpha_test_func == GL_EQUAL) - { - if (gl_FragColor.a != alpha_test_ref) - discard; - } - else if (alpha_test_func == GL_LEQUAL) - { - if (gl_FragColor.a > alpha_test_ref) - discard; - } - else if (alpha_test_func == GL_GREATER) - { - if (gl_FragColor.a <= alpha_test_ref) - discard; - } - else if (alpha_test_func == GL_NOTEQUAL) - { - if (gl_FragColor.a == alpha_test_ref) - discard; - } - else if (alpha_test_func == GL_GEQUAL) - { - if (gl_FragColor.a < alpha_test_ref) - discard; - } - } + + /*** cogl_fixed_fragment_shader_alpha_never ***/ + discard; + /*** cogl_fixed_fragment_shader_alpha_less ***/ + if (gl_FragColor.a >= alpha_test_ref) + discard; + /*** cogl_fixed_fragment_shader_alpha_equal ***/ + if (gl_FragColor.a != alpha_test_ref) + discard; + /*** cogl_fixed_fragment_shader_alpha_lequal ***/ + if (gl_FragColor.a > alpha_test_ref) + discard; + /*** cogl_fixed_fragment_shader_alpha_greater ***/ + if (gl_FragColor.a <= alpha_test_ref) + discard; + /*** cogl_fixed_fragment_shader_alpha_notequal ***/ + if (gl_FragColor.a == alpha_test_ref) + discard; + /*** cogl_fixed_fragment_shader_alpha_gequal ***/ + if (gl_FragColor.a < alpha_test_ref) + discard; + + /*** cogl_fixed_fragment_shader_end ***/ } diff --git a/clutter/cogl/gles/cogl-fixed-vertex-shader.glsl b/clutter/cogl/gles/cogl-fixed-vertex-shader.glsl index 7fed8439d..050f7dea4 100644 --- a/clutter/cogl/gles/cogl-fixed-vertex-shader.glsl +++ b/clutter/cogl/gles/cogl-fixed-vertex-shader.glsl @@ -1,3 +1,5 @@ +/*** cogl_fixed_vertex_shader_start ***/ + /* Per vertex attributes */ attribute vec4 vertex_attrib; attribute vec4 tex_coord_attrib; @@ -14,17 +16,10 @@ varying vec2 tex_coord; varying float fog_amount; /* Fogging options */ -uniform bool fog_enabled; -uniform int fog_mode; uniform float fog_density; uniform float fog_start; uniform float fog_end; -/* Fogging modes */ -const int GL_LINEAR = 0x2601; -const int GL_EXP = 0x0800; -const int GL_EXP2 = 0x0801; - void main (void) { @@ -38,23 +33,26 @@ main (void) /* Pass the interpolated vertex color on to the fragment shader */ frag_color = color_attrib; - if (fog_enabled) - { - /* Estimate the distance from the eye using just the - z-coordinate to use as the fog coord */ - vec4 eye_coord = modelview_matrix * vertex_attrib; - float fog_coord = abs (eye_coord.z / eye_coord.w); + /*** cogl_fixed_vertex_shader_fog_start ***/ - /* Calculate the fog amount per-vertex and interpolate it for - the fragment shader */ - if (fog_mode == GL_EXP) - fog_amount = exp (-fog_density * fog_coord); - else if (fog_mode == GL_EXP2) - fog_amount = exp (-fog_density * fog_coord - * fog_density * fog_coord); - else - fog_amount = (fog_end - fog_coord) / (fog_end - fog_start); + /* Estimate the distance from the eye using just the z-coordinate to + use as the fog coord */ + vec4 eye_coord = modelview_matrix * vertex_attrib; + float fog_coord = abs (eye_coord.z / eye_coord.w); - fog_amount = clamp (fog_amount, 0.0, 1.0); - } + /* Calculate the fog amount per-vertex and interpolate it for the + fragment shader */ + + /*** cogl_fixed_vertex_shader_fog_exp ***/ + fog_amount = exp (-fog_density * fog_coord); + /*** cogl_fixed_vertex_shader_fog_exp2 ***/ + fog_amount = exp (-fog_density * fog_coord + * fog_density * fog_coord); + /*** cogl_fixed_vertex_shader_fog_linear ***/ + fog_amount = (fog_end - fog_coord) / (fog_end - fog_start); + + /*** cogl_fixed_vertex_shader_fog_end ***/ + fog_amount = clamp (fog_amount, 0.0, 1.0); + + /*** cogl_fixed_vertex_shader_end ***/ } diff --git a/clutter/cogl/gles/cogl-gles2-wrapper.c b/clutter/cogl/gles/cogl-gles2-wrapper.c index 3a2f2dca1..394ab8e3d 100644 --- a/clutter/cogl/gles/cogl-gles2-wrapper.c +++ b/clutter/cogl/gles/cogl-gles2-wrapper.c @@ -36,6 +36,8 @@ #include "cogl-fixed-vertex-shader.h" #include "cogl-fixed-fragment-shader.h" #include "cogl-context.h" +#include "cogl-shader.h" +#include "cogl-program.h" #define _COGL_GET_GLES2_WRAPPER(wvar, retval) \ CoglGles2Wrapper *wvar; \ @@ -45,6 +47,24 @@ wvar = &__ctxvar->gles2; \ } +#define _COGL_GLES2_CHANGE_SETTING(w, var, val) \ + do \ + if ((w)->settings.var != (val)) \ + { \ + (w)->settings.var = (val); \ + (w)->settings_dirty = TRUE; \ + } \ + while (0) + +#define _COGL_GLES2_CHANGE_UNIFORM(w, flag, var, val) \ + do \ + if ((w)->var != (val)) \ + { \ + (w)->var = (val); \ + (w)->dirty_uniforms |= COGL_GLES2_DIRTY_ ## flag; \ + } \ + while (0) + #define COGL_GLES2_WRAPPER_VERTEX_ATTRIB 0 #define COGL_GLES2_WRAPPER_TEX_COORD_ATTRIB 1 #define COGL_GLES2_WRAPPER_COLOR_ATTRIB 2 @@ -83,62 +103,10 @@ cogl_gles2_wrapper_create_shader (GLenum type, const char *source) void cogl_gles2_wrapper_init (CoglGles2Wrapper *wrapper) { - GLint status; GLfixed default_fog_color[4] = { 0, 0, 0, 0 }; memset (wrapper, 0, sizeof (CoglGles2Wrapper)); - /* Create the shader program */ - wrapper->vertex_shader - = cogl_gles2_wrapper_create_shader (GL_VERTEX_SHADER, - cogl_fixed_vertex_shader); - - if (wrapper->vertex_shader == 0) - return; - - wrapper->fragment_shader - = cogl_gles2_wrapper_create_shader (GL_FRAGMENT_SHADER, - cogl_fixed_fragment_shader); - - if (wrapper->fragment_shader == 0) - { - glDeleteShader (wrapper->vertex_shader); - return; - } - - wrapper->program = glCreateProgram (); - glAttachShader (wrapper->program, wrapper->fragment_shader); - glAttachShader (wrapper->program, wrapper->vertex_shader); - cogl_gles2_wrapper_bind_attributes (wrapper->program); - glLinkProgram (wrapper->program); - - glGetProgramiv (wrapper->program, GL_LINK_STATUS, &status); - - if (!status) - { - char log[1024]; - GLint len; - - glGetProgramInfoLog (wrapper->program, sizeof (log) - 1, &len, log); - log[len] = '\0'; - - g_critical ("%s", log); - - glDeleteProgram (wrapper->program); - glDeleteShader (wrapper->vertex_shader); - glDeleteShader (wrapper->fragment_shader); - - return; - } - - glUseProgram (wrapper->program); - - wrapper->uniforms = &wrapper->fixed_uniforms; - cogl_gles2_wrapper_get_uniforms (wrapper->program, wrapper->uniforms); - - /* Always use the first texture unit */ - glUniform1i (wrapper->uniforms->bound_texture_uniform, 0); - /* Initialize the stacks */ cogl_wrap_glMatrixMode (GL_TEXTURE); cogl_wrap_glLoadIdentity (); @@ -147,8 +115,6 @@ cogl_gles2_wrapper_init (CoglGles2Wrapper *wrapper) cogl_wrap_glMatrixMode (GL_MODELVIEW); cogl_wrap_glLoadIdentity (); - wrapper->mvp_uptodate = GL_FALSE; - /* Initialize the fogging options */ cogl_wrap_glDisable (GL_FOG); cogl_wrap_glFogx (GL_FOG_MODE, GL_LINEAR); @@ -162,6 +128,293 @@ cogl_gles2_wrapper_init (CoglGles2Wrapper *wrapper) cogl_wrap_glAlphaFunc (GL_ALWAYS, 0.0f); } +static gboolean +cogl_gles2_settings_equal (const CoglGles2WrapperSettings *a, + const CoglGles2WrapperSettings *b, + gboolean vertex_tests, + gboolean fragment_tests) +{ + if (fragment_tests) + { + if (a->texture_2d_enabled != b->texture_2d_enabled) + return FALSE; + + if (a->texture_2d_enabled && a->alpha_only != b->alpha_only) + return FALSE; + + if (a->alpha_test_enabled != b->alpha_test_enabled) + return FALSE; + if (a->alpha_test_enabled && a->alpha_test_func != b->alpha_test_func) + return FALSE; + } + + if (a->fog_enabled != b->fog_enabled) + return FALSE; + + if (vertex_tests && a->fog_enabled && a->fog_mode != b->fog_mode) + return FALSE; + + return TRUE; +} + +static CoglGles2WrapperShader * +cogl_gles2_get_vertex_shader (const CoglGles2WrapperSettings *settings) +{ + GString *shader_source; + GLuint shader_obj; + CoglGles2WrapperShader *shader; + GSList *node; + + _COGL_GET_GLES2_WRAPPER (w, NULL); + + /* Check if we already have a vertex shader for these settings */ + for (node = w->compiled_vertex_shaders; node; node = node->next) + if (cogl_gles2_settings_equal (settings, + &((CoglGles2WrapperShader *) + node->data)->settings, + TRUE, FALSE)) + return (CoglGles2WrapperShader *) node->data; + + /* Otherwise create a new shader */ + shader_source = g_string_new (cogl_fixed_vertex_shader_start); + + if (settings->fog_enabled) + { + g_string_append (shader_source, cogl_fixed_vertex_shader_fog_start); + + switch (settings->fog_mode) + { + case GL_EXP: + g_string_append (shader_source, cogl_fixed_vertex_shader_fog_exp); + break; + + case GL_EXP2: + g_string_append (shader_source, cogl_fixed_vertex_shader_fog_exp2); + break; + + default: + g_string_append (shader_source, cogl_fixed_vertex_shader_fog_linear); + break; + } + + g_string_append (shader_source, cogl_fixed_vertex_shader_fog_end); + } + + g_string_append (shader_source, cogl_fixed_vertex_shader_end); + + shader_obj = cogl_gles2_wrapper_create_shader (GL_VERTEX_SHADER, + shader_source->str); + + g_string_free (shader_source, TRUE); + + if (shader_obj == 0) + return NULL; + + shader = g_slice_new (CoglGles2WrapperShader); + shader->shader = shader_obj; + shader->settings = *settings; + + w->compiled_vertex_shaders = g_slist_prepend (w->compiled_vertex_shaders, + shader); + + return shader; +} + +static CoglGles2WrapperShader * +cogl_gles2_get_fragment_shader (const CoglGles2WrapperSettings *settings) +{ + GString *shader_source; + GLuint shader_obj; + CoglGles2WrapperShader *shader; + GSList *node; + + _COGL_GET_GLES2_WRAPPER (w, NULL); + + /* Check if we already have a fragment shader for these settings */ + for (node = w->compiled_fragment_shaders; node; node = node->next) + if (cogl_gles2_settings_equal (settings, + &((CoglGles2WrapperShader *) + node->data)->settings, + FALSE, TRUE)) + return (CoglGles2WrapperShader *) node->data; + + /* Otherwise create a new shader */ + shader_source = g_string_new (cogl_fixed_fragment_shader_start); + if (settings->texture_2d_enabled) + { + if (settings->alpha_only) + g_string_append (shader_source, + cogl_fixed_fragment_shader_texture_alpha_only); + else + g_string_append (shader_source, + cogl_fixed_fragment_shader_texture); + } + else + g_string_append (shader_source, cogl_fixed_fragment_shader_solid_color); + + if (settings->fog_enabled) + g_string_append (shader_source, cogl_fixed_fragment_shader_fog); + + if (settings->alpha_test_enabled) + switch (settings->alpha_test_func) + { + case GL_NEVER: + g_string_append (shader_source, + cogl_fixed_fragment_shader_alpha_never); + break; + case GL_LESS: + g_string_append (shader_source, + cogl_fixed_fragment_shader_alpha_less); + break; + case GL_EQUAL: + g_string_append (shader_source, + cogl_fixed_fragment_shader_alpha_equal); + break; + case GL_LEQUAL: + g_string_append (shader_source, + cogl_fixed_fragment_shader_alpha_lequal); + break; + case GL_GREATER: + g_string_append (shader_source, + cogl_fixed_fragment_shader_alpha_greater); + break; + case GL_NOTEQUAL: + g_string_append (shader_source, + cogl_fixed_fragment_shader_alpha_notequal); + break; + case GL_GEQUAL: + g_string_append (shader_source, + cogl_fixed_fragment_shader_alpha_gequal); + } + + g_string_append (shader_source, cogl_fixed_fragment_shader_end); + + shader_obj = cogl_gles2_wrapper_create_shader (GL_FRAGMENT_SHADER, + shader_source->str); + + g_string_free (shader_source, TRUE); + + if (shader_obj == 0) + return NULL; + + shader = g_slice_new (CoglGles2WrapperShader); + shader->shader = shader_obj; + shader->settings = *settings; + + w->compiled_fragment_shaders = g_slist_prepend (w->compiled_fragment_shaders, + shader); + + return shader; +} + +static CoglGles2WrapperProgram * +cogl_gles2_wrapper_get_program (const CoglGles2WrapperSettings *settings) +{ + GSList *node; + CoglGles2WrapperProgram *program; + CoglGles2WrapperShader *vertex_shader, *fragment_shader; + GLint status; + gboolean custom_vertex_shader = FALSE, custom_fragment_shader = FALSE; + CoglProgram *user_program = NULL; + int i; + + _COGL_GET_GLES2_WRAPPER (w, NULL); + + /* Check if we've already got a program for these settings */ + for (node = w->compiled_programs; node; node = node->next) + { + program = (CoglGles2WrapperProgram *) node->data; + + if (cogl_gles2_settings_equal (settings, &program->settings, TRUE, TRUE) + && program->settings.user_program == settings->user_program) + return (CoglGles2WrapperProgram *) node->data; + } + + /* Otherwise create a new program */ + + /* Check whether the currently used custom program has vertex and + fragment shaders */ + if (w->settings.user_program != COGL_INVALID_HANDLE) + { + user_program + = _cogl_program_pointer_from_handle (w->settings.user_program); + + for (node = user_program->attached_shaders; node; node = node->next) + { + CoglShader *shader + = _cogl_shader_pointer_from_handle ((CoglHandle) node->data); + + if (shader->type == CGL_VERTEX_SHADER) + custom_vertex_shader = TRUE; + else if (shader->type == CGL_FRAGMENT_SHADER) + custom_fragment_shader = TRUE; + } + } + + /* Get or create the fixed functionality shaders for these settings + if there is no custom replacement */ + if (!custom_vertex_shader) + { + vertex_shader = cogl_gles2_get_vertex_shader (settings); + if (vertex_shader == NULL) + return NULL; + } + if (!custom_fragment_shader) + { + fragment_shader = cogl_gles2_get_fragment_shader (settings); + if (fragment_shader == NULL) + return NULL; + } + + program = g_slice_new (CoglGles2WrapperProgram); + + program->program = glCreateProgram (); + if (!custom_vertex_shader) + glAttachShader (program->program, vertex_shader->shader); + if (!custom_fragment_shader) + glAttachShader (program->program, fragment_shader->shader); + if (user_program) + for (node = user_program->attached_shaders; node; node = node->next) + { + CoglShader *shader + = _cogl_shader_pointer_from_handle ((CoglHandle) node->data); + glAttachShader (program->program, shader->gl_handle); + } + cogl_gles2_wrapper_bind_attributes (program->program); + glLinkProgram (program->program); + + glGetProgramiv (program->program, GL_LINK_STATUS, &status); + + if (!status) + { + char log[1024]; + GLint len; + + glGetProgramInfoLog (program->program, sizeof (log) - 1, &len, log); + log[len] = '\0'; + + g_critical ("%s", log); + + glDeleteProgram (program->program); + g_slice_free (CoglGles2WrapperProgram, program); + + return NULL; + } + + program->settings = *settings; + + cogl_gles2_wrapper_get_uniforms (program->program, &program->uniforms); + + /* We haven't tried to get a location for any of the custom uniforms + yet */ + for (i = 0; i < COGL_GLES2_NUM_CUSTOM_UNIFORMS; i++) + program->custom_uniforms[i] = COGL_GLES2_UNBOUND_CUSTOM_UNIFORM; + + w->compiled_programs = g_slist_append (w->compiled_programs, program); + + return program; +} + void cogl_gles2_wrapper_bind_attributes (GLuint program) { @@ -183,17 +436,9 @@ cogl_gles2_wrapper_get_uniforms (GLuint program, = glGetUniformLocation (program, "modelview_matrix"); uniforms->texture_matrix_uniform = glGetUniformLocation (program, "texture_matrix"); - uniforms->texture_2d_enabled_uniform - = glGetUniformLocation (program, "texture_2d_enabled"); uniforms->bound_texture_uniform = glGetUniformLocation (program, "texture_unit"); - uniforms->alpha_only_uniform - = glGetUniformLocation (program, "alpha_only"); - uniforms->fog_enabled_uniform - = glGetUniformLocation (program, "fog_enabled"); - uniforms->fog_mode_uniform - = glGetUniformLocation (program, "fog_mode"); uniforms->fog_density_uniform = glGetUniformLocation (program, "fog_density"); uniforms->fog_start_uniform @@ -203,10 +448,6 @@ cogl_gles2_wrapper_get_uniforms (GLuint program, uniforms->fog_color_uniform = glGetUniformLocation (program, "fog_color"); - uniforms->alpha_test_enabled_uniform - = glGetUniformLocation (program, "alpha_test_enabled"); - uniforms->alpha_test_func_uniform - = glGetUniformLocation (program, "alpha_test_func"); uniforms->alpha_test_ref_uniform = glGetUniformLocation (program, "alpha_test_ref"); } @@ -214,42 +455,50 @@ cogl_gles2_wrapper_get_uniforms (GLuint program, void cogl_gles2_wrapper_deinit (CoglGles2Wrapper *wrapper) { - if (wrapper->program) + GSList *node, *next; + + for (node = wrapper->compiled_programs; node; node = next) { - glDeleteProgram (wrapper->program); - wrapper->program = 0; + next = node->next; + glDeleteProgram (((CoglGles2WrapperProgram *) node->data)->program); + g_slist_free1 (node); } - if (wrapper->vertex_shader) + wrapper->compiled_programs = NULL; + + for (node = wrapper->compiled_vertex_shaders; node; node = next) { - glDeleteShader (wrapper->vertex_shader); - wrapper->vertex_shader = 0; + next = node->next; + glDeleteShader (((CoglGles2WrapperShader *) node->data)->shader); + g_slist_free1 (node); } - if (wrapper->fragment_shader) + wrapper->compiled_vertex_shaders = NULL; + + for (node = wrapper->compiled_fragment_shaders; node; node = next) { - glDeleteShader (wrapper->fragment_shader); - wrapper->fragment_shader = 0; + next = node->next; + glDeleteShader (((CoglGles2WrapperShader *) node->data)->shader); + g_slist_free1 (node); } + wrapper->compiled_fragment_shaders = NULL; } void cogl_gles2_wrapper_update_matrix (CoglGles2Wrapper *wrapper, GLenum matrix_num) { - const float *matrix; - switch (matrix_num) { default: case GL_MODELVIEW: + wrapper->dirty_uniforms |= COGL_GLES2_DIRTY_MVP_MATRIX + | COGL_GLES2_DIRTY_MODELVIEW_MATRIX; + break; + case GL_PROJECTION: - /* Queue a recalculation of the combined modelview and - projection matrix at the next draw */ - wrapper->mvp_uptodate = GL_FALSE; + wrapper->dirty_uniforms |= COGL_GLES2_DIRTY_MVP_MATRIX; break; case GL_TEXTURE: - matrix = wrapper->texture_stack + wrapper->texture_stack_pos * 16; - glUniformMatrix4fv (wrapper->uniforms->texture_matrix_uniform, - 1, GL_FALSE, matrix); + wrapper->dirty_uniforms |= COGL_GLES2_DIRTY_TEXTURE_MATRIX; break; } } @@ -530,26 +779,105 @@ cogl_wrap_glColorPointer (GLint size, GLenum type, GLsizei stride, void cogl_wrap_glDrawArrays (GLenum mode, GLint first, GLsizei count) { + CoglGles2WrapperProgram *program; + _COGL_GET_GLES2_WRAPPER (w, NO_RETVAL); - /* Make sure the modelview+projection matrix is up to date */ - if (!w->mvp_uptodate) + /* Check if we need to switch programs */ + if (w->settings_dirty) { - float mvp_matrix[16]; - const float *modelview_matrix = w->modelview_stack - + w->modelview_stack_pos * 16; + /* Find or create a program for the current settings */ + program = cogl_gles2_wrapper_get_program (&w->settings); - cogl_gles2_wrapper_mult_matrix (mvp_matrix, - w->projection_stack - + w->projection_stack_pos * 16, - modelview_matrix); + if (program == NULL) + /* Can't compile a shader so there is nothing we can do */ + return; - glUniformMatrix4fv (w->uniforms->mvp_matrix_uniform, 1, - GL_FALSE, mvp_matrix); - glUniformMatrix4fv (w->uniforms->modelview_matrix_uniform, 1, GL_FALSE, - modelview_matrix); + /* Start using it if we aren't already */ + if (w->current_program != program) + { + glUseProgram (program->program); + w->current_program = program; + /* All of the uniforms are probably now out of date */ + w->dirty_uniforms = COGL_GLES2_DIRTY_ALL; + w->dirty_custom_uniforms = (1 << COGL_GLES2_NUM_CUSTOM_UNIFORMS) - 1; + } + w->settings_dirty = FALSE; + } + else + program = w->current_program; - w->mvp_uptodate = GL_TRUE; + /* Make sure all of the uniforms are up to date */ + if (w->dirty_uniforms) + { + if ((w->dirty_uniforms & (COGL_GLES2_DIRTY_MVP_MATRIX + | COGL_GLES2_DIRTY_MODELVIEW_MATRIX))) + { + float mvp_matrix[16]; + const float *modelview_matrix = w->modelview_stack + + w->modelview_stack_pos * 16; + + cogl_gles2_wrapper_mult_matrix (mvp_matrix, + w->projection_stack + + w->projection_stack_pos * 16, + modelview_matrix); + + if (program->uniforms.mvp_matrix_uniform != -1) + glUniformMatrix4fv (program->uniforms.mvp_matrix_uniform, 1, + GL_FALSE, mvp_matrix); + if (program->uniforms.modelview_matrix_uniform != -1) + glUniformMatrix4fv (program->uniforms.modelview_matrix_uniform, 1, + GL_FALSE, modelview_matrix); + } + if ((w->dirty_uniforms & COGL_GLES2_DIRTY_TEXTURE_MATRIX) + && program->uniforms.texture_matrix_uniform != -1) + glUniformMatrix4fv (program->uniforms.texture_matrix_uniform, 1, + GL_FALSE, + w->texture_stack + w->texture_stack_pos * 16); + + if ((w->dirty_uniforms & COGL_GLES2_DIRTY_FOG_DENSITY) + && program->uniforms.fog_density_uniform != -1) + glUniform1f (program->uniforms.fog_density_uniform, w->fog_density); + if ((w->dirty_uniforms & COGL_GLES2_DIRTY_FOG_START) + && program->uniforms.fog_start_uniform != -1) + glUniform1f (program->uniforms.fog_start_uniform, w->fog_start); + if ((w->dirty_uniforms & COGL_GLES2_DIRTY_FOG_END) + && program->uniforms.fog_end_uniform != -1) + glUniform1f (program->uniforms.fog_end_uniform, w->fog_end); + + if ((w->dirty_uniforms & COGL_GLES2_DIRTY_ALPHA_TEST_REF) + && program->uniforms.alpha_test_ref_uniform != -1) + glUniform1f (program->uniforms.alpha_test_ref_uniform, + w->alpha_test_ref); + + w->dirty_uniforms = 0; + } + + if (w->dirty_custom_uniforms) + { + int i; + + if (w->settings.user_program != COGL_INVALID_HANDLE) + { + CoglProgram *user_program + = _cogl_program_pointer_from_handle (w->settings.user_program); + const char *uniform_name; + + for (i = 0; i < COGL_GLES2_NUM_CUSTOM_UNIFORMS; i++) + if ((w->dirty_custom_uniforms & (1 << i)) + && (uniform_name = user_program->custom_uniform_names[i])) + { + if (program->custom_uniforms[i] + == COGL_GLES2_UNBOUND_CUSTOM_UNIFORM) + program->custom_uniforms[i] + = glGetUniformLocation (program->program, uniform_name); + if (program->custom_uniforms[i] >= 0) + glUniform1f (program->custom_uniforms[i], + w->custom_uniforms[i]); + } + } + + w->dirty_custom_uniforms = 0; } glDrawArrays (mode, first, count); @@ -566,8 +894,7 @@ cogl_gles2_wrapper_bind_texture (GLenum target, GLuint texture, /* We need to keep track of whether the texture is alpha-only because the emulation of GL_MODULATE needs to work differently in that case */ - glUniform1i (w->uniforms->alpha_only_uniform, - internal_format == GL_ALPHA ? GL_TRUE : GL_FALSE); + _COGL_GLES2_CHANGE_SETTING (w, alpha_only, internal_format == GL_ALPHA); } void @@ -586,15 +913,15 @@ cogl_wrap_glEnable (GLenum cap) switch (cap) { case GL_TEXTURE_2D: - glUniform1i (w->uniforms->texture_2d_enabled_uniform, GL_TRUE); + _COGL_GLES2_CHANGE_SETTING (w, texture_2d_enabled, TRUE); break; case GL_FOG: - glUniform1i (w->uniforms->fog_enabled_uniform, GL_TRUE); + _COGL_GLES2_CHANGE_SETTING (w, fog_enabled, TRUE); break; case GL_ALPHA_TEST: - glUniform1i (w->uniforms->alpha_test_enabled_uniform, GL_TRUE); + _COGL_GLES2_CHANGE_SETTING (w, alpha_test_enabled, TRUE); break; default: @@ -610,15 +937,15 @@ cogl_wrap_glDisable (GLenum cap) switch (cap) { case GL_TEXTURE_2D: - glUniform1i (w->uniforms->texture_2d_enabled_uniform, GL_FALSE); + _COGL_GLES2_CHANGE_SETTING (w, texture_2d_enabled, FALSE); break; case GL_FOG: - glUniform1i (w->uniforms->fog_enabled_uniform, GL_FALSE); + _COGL_GLES2_CHANGE_SETTING (w, fog_enabled, FALSE); break; case GL_ALPHA_TEST: - glUniform1i (w->uniforms->alpha_test_enabled_uniform, GL_FALSE); + _COGL_GLES2_CHANGE_SETTING (w, alpha_test_enabled, FALSE); break; default: @@ -670,8 +997,8 @@ cogl_wrap_glAlphaFunc (GLenum func, GLclampf ref) else if (ref > 1.0f) ref = 1.0f; - glUniform1i (w->uniforms->alpha_test_func_uniform, func); - glUniform1f (w->uniforms->alpha_test_ref_uniform, ref); + _COGL_GLES2_CHANGE_SETTING (w, alpha_test_func, func); + _COGL_GLES2_CHANGE_UNIFORM (w, ALPHA_TEST_REF, alpha_test_ref, ref); } void @@ -753,22 +1080,22 @@ cogl_wrap_glFogx (GLenum pname, GLfixed param) switch (pname) { case GL_FOG_MODE: - glUniform1i (w->uniforms->fog_mode_uniform, param); + _COGL_GLES2_CHANGE_SETTING (w, fog_mode, param); break; case GL_FOG_DENSITY: - glUniform1f (w->uniforms->fog_density_uniform, - CLUTTER_FIXED_TO_FLOAT (param)); + _COGL_GLES2_CHANGE_UNIFORM (w, FOG_DENSITY, fog_density, + CLUTTER_FIXED_TO_FLOAT (param)); break; case GL_FOG_START: - glUniform1f (w->uniforms->fog_start_uniform, - CLUTTER_FIXED_TO_FLOAT (param)); + _COGL_GLES2_CHANGE_UNIFORM (w, FOG_START, fog_start, + CLUTTER_FIXED_TO_FLOAT (param)); break; case GL_FOG_END: - glUniform1f (w->uniforms->fog_end_uniform, - CLUTTER_FIXED_TO_FLOAT (param)); + _COGL_GLES2_CHANGE_UNIFORM (w, FOG_END, fog_end, + CLUTTER_FIXED_TO_FLOAT (param)); break; } } @@ -776,14 +1103,15 @@ cogl_wrap_glFogx (GLenum pname, GLfixed param) void cogl_wrap_glFogxv (GLenum pname, const GLfixed *params) { + int i; _COGL_GET_GLES2_WRAPPER (w, NO_RETVAL); if (pname == GL_FOG_COLOR) - glUniform4f (w->uniforms->fog_color_uniform, - CLUTTER_FIXED_TO_FLOAT (params[0]), - CLUTTER_FIXED_TO_FLOAT (params[1]), - CLUTTER_FIXED_TO_FLOAT (params[2]), - CLUTTER_FIXED_TO_FLOAT (params[3])); + { + for (i = 0; i < 4; i++) + w->fog_color[i] = CLUTTER_FIXED_TO_FLOAT (params[i]); + w->dirty_uniforms |= COGL_GLES2_DIRTY_FOG_COLOR; + } } void @@ -792,3 +1120,33 @@ cogl_wrap_glTexParameteri (GLenum target, GLenum pname, GLfloat param) if (pname != GL_GENERATE_MIPMAP) glTexParameteri (target, pname, param); } + +void +_cogl_gles2_clear_cache_for_program (CoglHandle user_program) +{ + GSList *node, *next, *last = NULL; + CoglGles2WrapperProgram *program; + + _COGL_GET_GLES2_WRAPPER (w, NO_RETVAL); + + /* Remove any cached programs that link against this custom program */ + for (node = w->compiled_programs; node; node = next) + { + next = node->next; + program = (CoglGles2WrapperProgram *) node->data; + + if (program->settings.user_program == user_program) + { + glDeleteProgram (program->program); + + if (last) + last->next = next; + else + w->compiled_programs = next; + + g_slist_free1 (node); + } + else + last = node; + } +} diff --git a/clutter/cogl/gles/cogl-gles2-wrapper.h b/clutter/cogl/gles/cogl-gles2-wrapper.h index fc2314004..650bbedd0 100644 --- a/clutter/cogl/gles/cogl-gles2-wrapper.h +++ b/clutter/cogl/gles/cogl-gles2-wrapper.h @@ -32,39 +32,64 @@ G_BEGIN_DECLS typedef struct _CoglGles2Wrapper CoglGles2Wrapper; typedef struct _CoglGles2WrapperUniforms CoglGles2WrapperUniforms; +typedef struct _CoglGles2WrapperSettings CoglGles2WrapperSettings; +typedef struct _CoglGles2WrapperProgram CoglGles2WrapperProgram; +typedef struct _CoglGles2WrapperShader CoglGles2WrapperShader; + +#define COGL_GLES2_NUM_CUSTOM_UNIFORMS 16 +#define COGL_GLES2_UNBOUND_CUSTOM_UNIFORM -2 /* Must be a power of two */ -#define COGL_GLES2_MODELVIEW_STACK_SIZE 32 -#define COGL_GLES2_PROJECTION_STACK_SIZE 2 -#define COGL_GLES2_TEXTURE_STACK_SIZE 2 +#define COGL_GLES2_MODELVIEW_STACK_SIZE 32 +#define COGL_GLES2_PROJECTION_STACK_SIZE 2 +#define COGL_GLES2_TEXTURE_STACK_SIZE 2 + +enum + { + COGL_GLES2_DIRTY_MVP_MATRIX = 1 << 0, + COGL_GLES2_DIRTY_MODELVIEW_MATRIX = 1 << 1, + COGL_GLES2_DIRTY_TEXTURE_MATRIX = 1 << 2, + COGL_GLES2_DIRTY_FOG_DENSITY = 1 << 3, + COGL_GLES2_DIRTY_FOG_START = 1 << 4, + COGL_GLES2_DIRTY_FOG_END = 1 << 5, + COGL_GLES2_DIRTY_FOG_COLOR = 1 << 6, + COGL_GLES2_DIRTY_ALPHA_TEST_REF = 1 << 7, + + COGL_GLES2_DIRTY_ALL = (1 << 8) - 1 + }; struct _CoglGles2WrapperUniforms { GLint mvp_matrix_uniform; GLint modelview_matrix_uniform; GLint texture_matrix_uniform; - GLint texture_2d_enabled_uniform; GLint bound_texture_uniform; - GLint alpha_only_uniform; - GLint fog_enabled_uniform; - GLint fog_mode_uniform; GLint fog_density_uniform; GLint fog_start_uniform; GLint fog_end_uniform; GLint fog_color_uniform; - GLint alpha_test_enabled_uniform; - GLint alpha_test_func_uniform; GLint alpha_test_ref_uniform; }; +struct _CoglGles2WrapperSettings +{ + gboolean texture_2d_enabled; + gboolean alpha_only; + + gboolean alpha_test_enabled; + GLint alpha_test_func; + + gboolean fog_enabled; + GLint fog_mode; + + /* The current in-use user program */ + CoglHandle user_program; +}; + struct _CoglGles2Wrapper { - GLuint program; - GLuint vertex_shader; - GLuint fragment_shader; - GLuint matrix_mode; GLfloat modelview_stack[COGL_GLES2_MODELVIEW_STACK_SIZE * 16]; GLuint modelview_stack_pos; @@ -73,19 +98,61 @@ struct _CoglGles2Wrapper GLfloat texture_stack[COGL_GLES2_TEXTURE_STACK_SIZE * 16]; GLuint texture_stack_pos; - /* The uniforms for the fixed-functionality emulation program */ - CoglGles2WrapperUniforms fixed_uniforms; - /* The uniforms for the currently bound program */ - CoglGles2WrapperUniforms *uniforms; - /* The combined modelview and projection matrix is only updated at the last minute in glDrawArrays to avoid recalculating it for every change to the modelview matrix */ GLboolean mvp_uptodate; + + /* The currently bound program */ + CoglGles2WrapperProgram *current_program; + + /* The current settings */ + CoglGles2WrapperSettings settings; + /* Whether the settings have changed since the last draw */ + gboolean settings_dirty; + /* Uniforms that have changed since the last draw */ + int dirty_uniforms, dirty_custom_uniforms; + + /* List of all compiled program combinations */ + GSList *compiled_programs; + + /* List of all compiled vertex shaders */ + GSList *compiled_vertex_shaders; + + /* List of all compiled fragment shaders */ + GSList *compiled_fragment_shaders; + + /* Values for the uniforms */ + GLfloat alpha_test_ref; + GLfloat fog_density; + GLfloat fog_start; + GLfloat fog_end; + GLfloat fog_color[4]; + GLfloat custom_uniforms[COGL_GLES2_NUM_CUSTOM_UNIFORMS]; +}; + +struct _CoglGles2WrapperProgram +{ + GLuint program; + + /* The settings that were used to generate this combination */ + CoglGles2WrapperSettings settings; + + /* The uniforms for this program */ + CoglGles2WrapperUniforms uniforms; + GLint custom_uniforms[COGL_GLES2_NUM_CUSTOM_UNIFORMS]; +}; + +struct _CoglGles2WrapperShader +{ + GLuint shader; + + /* The settings that were used to generate this shader */ + CoglGles2WrapperSettings settings; }; /* These defines are missing from GL ES 2 but we can still use them - with the wrapper funcions */ + with the wrapper functions */ #ifndef GL_MODELVIEW @@ -122,6 +189,9 @@ struct _CoglGles2Wrapper #define GL_TEXTURE_ENV_MODE 0x2200 #define GL_MODULATE 0x2100 +#define GL_EXP 0x8000 +#define GL_EXP2 0x8001 + #endif /* GL_MODELVIEW */ void cogl_gles2_wrapper_init (CoglGles2Wrapper *wrapper); @@ -184,6 +254,8 @@ void cogl_gles2_wrapper_get_uniforms (GLuint program, void cogl_gles2_wrapper_update_matrix (CoglGles2Wrapper *wrapper, GLenum matrix_num); +void _cogl_gles2_clear_cache_for_program (CoglHandle program); + #else /* HAVE_COGL_GLES2 */ /* If we're not using GL ES 2 then just use the GL functions diff --git a/clutter/cogl/gles/cogl-program.c b/clutter/cogl/gles/cogl-program.c index bca76584c..cfc61f57d 100644 --- a/clutter/cogl/gles/cogl-program.c +++ b/clutter/cogl/gles/cogl-program.c @@ -35,6 +35,8 @@ #ifdef HAVE_COGL_GLES2 +#include + #include "cogl-shader.h" #include "cogl-program.h" @@ -45,26 +47,38 @@ COGL_HANDLE_DEFINE (Program, program, program_handles); static void _cogl_program_free (CoglProgram *program) { - /* Frees program resources but its handle is not - released! Do that separately before this! */ + int i; + _COGL_GET_CONTEXT (ctx, NO_RETVAL); - glDeleteProgram (program->gl_handle); + + /* Unref all of the attached shaders */ + g_slist_foreach (program->attached_shaders, (GFunc) cogl_shader_unref, NULL); + /* Destroy the list */ + g_slist_free (program->attached_shaders); + + _cogl_gles2_clear_cache_for_program ((CoglHandle) program); + + if (ctx->gles2.settings.user_program == (CoglHandle) program) + { + ctx->gles2.settings.user_program = COGL_INVALID_HANDLE; + ctx->gles2.settings_dirty = TRUE; + } + + for (i = 0; i < COGL_GLES2_NUM_CUSTOM_UNIFORMS; i++) + if (program->custom_uniform_names[i]) + g_free (program->custom_uniform_names[i]); } CoglHandle cogl_create_program (void) { CoglProgram *program; - _COGL_GET_CONTEXT (ctx, 0); program = g_slice_new (CoglProgram); program->ref_count = 1; - program->gl_handle = glCreateProgram (); - - program->attached_vertex_shader = FALSE; - program->attached_fragment_shader = FALSE; - program->attached_fixed_vertex_shader = FALSE; - program->attached_fixed_fragment_shader = FALSE; + program->attached_shaders = NULL; + memset (program->custom_uniform_names, 0, + COGL_GLES2_NUM_CUSTOM_UNIFORMS * sizeof (char *)); COGL_HANDLE_DEBUG_NEW (program, program); @@ -76,7 +90,6 @@ cogl_program_attach_shader (CoglHandle program_handle, CoglHandle shader_handle) { CoglProgram *program; - CoglShader *shader; _COGL_GET_CONTEXT (ctx, NO_RETVAL); @@ -84,110 +97,66 @@ cogl_program_attach_shader (CoglHandle program_handle, return; program = _cogl_program_pointer_from_handle (program_handle); - shader = _cogl_shader_pointer_from_handle (shader_handle); + program->attached_shaders + = g_slist_prepend (program->attached_shaders, + cogl_shader_ref (shader_handle)); - if (shader->type == GL_VERTEX_SHADER) - { - if (program->attached_fixed_vertex_shader) - { - glDetachShader (program->gl_handle, ctx->gles2.vertex_shader); - program->attached_fixed_vertex_shader = FALSE; - } - program->attached_vertex_shader = TRUE; - } - else if (shader->type == GL_FRAGMENT_SHADER) - { - if (program->attached_fixed_fragment_shader) - { - glDetachShader (program->gl_handle, ctx->gles2.fragment_shader); - program->attached_fixed_fragment_shader = FALSE; - } - program->attached_fragment_shader = TRUE; - } - - glAttachShader (program->gl_handle, shader->gl_handle); + /* Whenever the shader changes we will need to relink the program + with the fixed functionality shaders so we should forget the + cached programs */ + _cogl_gles2_clear_cache_for_program (program); } void cogl_program_link (CoglHandle handle) { - CoglProgram *program; - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - - if (!cogl_is_program (handle)) - return; - - program = _cogl_program_pointer_from_handle (handle); - - if (!program->attached_vertex_shader - && !program->attached_fixed_vertex_shader) - { - glAttachShader (program->gl_handle, ctx->gles2.vertex_shader); - program->attached_fixed_vertex_shader = TRUE; - } - - if (!program->attached_fragment_shader - && !program->attached_fixed_fragment_shader) - { - glAttachShader (program->gl_handle, ctx->gles2.fragment_shader); - program->attached_fixed_fragment_shader = TRUE; - } - - /* Set the attributes so that the wrapper functions will still work */ - cogl_gles2_wrapper_bind_attributes (program->gl_handle); - - glLinkProgram (program->gl_handle); - - /* Retrieve the uniforms */ - cogl_gles2_wrapper_get_uniforms (program->gl_handle, - &program->uniforms); + /* There's no point in linking the program here because it will have + to be relinked with a different fixed functionality shader + whenever the settings change */ } void cogl_program_use (CoglHandle handle) { - CoglProgram *program; - GLuint gl_handle; _COGL_GET_CONTEXT (ctx, NO_RETVAL); if (handle != COGL_INVALID_HANDLE && !cogl_is_program (handle)) return; - if (handle == COGL_INVALID_HANDLE) - { - /* Go back to the fixed-functionality emulator program */ - gl_handle = ctx->gles2.program; - ctx->gles2.uniforms = &ctx->gles2.fixed_uniforms; - } - else - { - program = _cogl_program_pointer_from_handle (handle); - gl_handle = program->gl_handle; - /* Use the uniforms in the program */ - ctx->gles2.uniforms = &program->uniforms; - } - - glUseProgram (gl_handle); - - /* Update all of the matrix attributes */ - cogl_gles2_wrapper_update_matrix (&ctx->gles2, GL_MODELVIEW); - cogl_gles2_wrapper_update_matrix (&ctx->gles2, GL_PROJECTION); - cogl_gles2_wrapper_update_matrix (&ctx->gles2, GL_TEXTURE); + ctx->gles2.settings.user_program = handle; + ctx->gles2.settings_dirty = TRUE; } COGLint cogl_program_get_uniform_location (CoglHandle handle, const gchar *uniform_name) { + int i; CoglProgram *program; - _COGL_GET_CONTEXT (ctx, 0); - + if (!cogl_is_program (handle)) - return 0; + return -1; program = _cogl_program_pointer_from_handle (handle); - return glGetUniformLocation (program->gl_handle, uniform_name); + /* We can't just ask the GL program object for the uniform location + directly because it will change every time the program is linked + with a new fixed functionality shader. Instead we make our own + mapping of uniform numbers and cache the names */ + for (i = 0; program->custom_uniform_names[i] + && i < COGL_GLES2_NUM_CUSTOM_UNIFORMS; i++) + if (!strcmp (program->custom_uniform_names[i], uniform_name)) + return i; + + if (i < COGL_GLES2_NUM_CUSTOM_UNIFORMS) + { + program->custom_uniform_names[i] = g_strdup (uniform_name); + return i; + } + else + /* We've run out of space for new uniform names so just pretend it + isn't there */ + return -1; } void @@ -195,7 +164,12 @@ cogl_program_uniform_1f (COGLint uniform_no, gfloat value) { _COGL_GET_CONTEXT (ctx, NO_RETVAL); - glUniform1f (uniform_no, value); + + if (uniform_no >= 0 && uniform_no < COGL_GLES2_NUM_CUSTOM_UNIFORMS) + { + ctx->gles2.custom_uniforms[uniform_no] = value; + ctx->gles2.dirty_custom_uniforms |= 1 << uniform_no; + } } #else /* HAVE_COGL_GLES2 */ diff --git a/clutter/cogl/gles/cogl-program.h b/clutter/cogl/gles/cogl-program.h index 242d97062..65a274c79 100644 --- a/clutter/cogl/gles/cogl-program.h +++ b/clutter/cogl/gles/cogl-program.h @@ -33,16 +33,10 @@ typedef struct _CoglProgram CoglProgram; struct _CoglProgram { guint ref_count; - GLuint gl_handle; - /* Keep track of which types of shader we've attached so we can link - in our replacement fixed functionality shader */ - gboolean attached_vertex_shader; - gboolean attached_fragment_shader; - gboolean attached_fixed_vertex_shader; - gboolean attached_fixed_fragment_shader; + GSList *attached_shaders; - CoglGles2WrapperUniforms uniforms; + char *custom_uniform_names[COGL_GLES2_NUM_CUSTOM_UNIFORMS]; }; CoglProgram *_cogl_program_pointer_from_handle (CoglHandle handle); diff --git a/clutter/cogl/gles/stringify.sh b/clutter/cogl/gles/stringify.sh index c8b3cf8b4..bb8e7574d 100644 --- a/clutter/cogl/gles/stringify.sh +++ b/clutter/cogl/gles/stringify.sh @@ -44,7 +44,11 @@ if test "$#" = 2; then echo "#ifndef ${guardname}" >> "${headername}"; echo "#define ${guardname}" >> "${headername}"; echo >> "${headername}"; - echo "extern const char ${varname}[];" >> "${headername}"; + + sed -n \ + -e 's/^ *\/\*\*\* \([a-zA-Z0-9_]*\) \*\*\*\//extern const char \1[];/p' \ + < "$2" >> "${headername}"; + echo >> "${headername}"; echo "#endif /* ${guardname} */" >> "${headername}"; @@ -57,9 +61,16 @@ else output_copyright "${cname}"; echo >> "${cname}"; - echo "const char ${varname}[] =" >> "${cname}"; - sed -e 's/"/\\"/' -e 's/^/ \"/' -e 's/$/\\n"/' \ + sed -n \ + -e h \ + -e 's/^ *\/\*\*\* \([a-zA-Z0-9_]*\) \*\*\*\// ;\nconst char \1[] =/' \ + -e 't got' \ + -e g \ + -e 's/"/\\"/' \ + -e 's/^/ "/' \ + -e 's/$/\\n"/' \ + -e ': got' \ + -e p \ < "$1" >> "${cname}"; echo " ;" >> "${cname}"; - fi;