* 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.
This commit is contained in:
parent
eac5e21f1c
commit
d4da3a3e2a
26
ChangeLog
26
ChangeLog
@ -1,3 +1,29 @@
|
||||
2008-06-24 Neil Roberts <neil@o-hand.com>
|
||||
|
||||
* 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 <pippin@o-hand.com>
|
||||
|
||||
* clutter/fruity/clutter-fruity.c: removed dead code and unused
|
||||
|
@ -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 */
|
||||
/*** cogl_fixed_fragment_shader_texture_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
|
||||
|
||||
/*** 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;
|
||||
|
||||
if (fog_enabled)
|
||||
/*** 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)
|
||||
|
||||
/*** cogl_fixed_fragment_shader_alpha_never ***/
|
||||
discard;
|
||||
else if (alpha_test_func == GL_LESS)
|
||||
{
|
||||
/*** cogl_fixed_fragment_shader_alpha_less ***/
|
||||
if (gl_FragColor.a >= alpha_test_ref)
|
||||
discard;
|
||||
}
|
||||
else if (alpha_test_func == GL_EQUAL)
|
||||
{
|
||||
/*** cogl_fixed_fragment_shader_alpha_equal ***/
|
||||
if (gl_FragColor.a != alpha_test_ref)
|
||||
discard;
|
||||
}
|
||||
else if (alpha_test_func == GL_LEQUAL)
|
||||
{
|
||||
/*** cogl_fixed_fragment_shader_alpha_lequal ***/
|
||||
if (gl_FragColor.a > alpha_test_ref)
|
||||
discard;
|
||||
}
|
||||
else if (alpha_test_func == GL_GREATER)
|
||||
{
|
||||
/*** cogl_fixed_fragment_shader_alpha_greater ***/
|
||||
if (gl_FragColor.a <= alpha_test_ref)
|
||||
discard;
|
||||
}
|
||||
else if (alpha_test_func == GL_NOTEQUAL)
|
||||
{
|
||||
/*** cogl_fixed_fragment_shader_alpha_notequal ***/
|
||||
if (gl_FragColor.a == alpha_test_ref)
|
||||
discard;
|
||||
}
|
||||
else if (alpha_test_func == GL_GEQUAL)
|
||||
{
|
||||
/*** cogl_fixed_fragment_shader_alpha_gequal ***/
|
||||
if (gl_FragColor.a < alpha_test_ref)
|
||||
discard;
|
||||
}
|
||||
}
|
||||
|
||||
/*** cogl_fixed_fragment_shader_end ***/
|
||||
}
|
||||
|
@ -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 */
|
||||
/*** cogl_fixed_vertex_shader_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);
|
||||
|
||||
/* Calculate the fog amount per-vertex and interpolate it for
|
||||
the fragment shader */
|
||||
if (fog_mode == GL_EXP)
|
||||
/* 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);
|
||||
else if (fog_mode == GL_EXP2)
|
||||
/*** cogl_fixed_vertex_shader_fog_exp2 ***/
|
||||
fog_amount = exp (-fog_density * fog_coord
|
||||
* fog_density * fog_coord);
|
||||
else
|
||||
/*** 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 ***/
|
||||
}
|
||||
|
@ -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,10 +779,39 @@ 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)
|
||||
{
|
||||
/* Find or create a program for the current settings */
|
||||
program = cogl_gles2_wrapper_get_program (&w->settings);
|
||||
|
||||
if (program == NULL)
|
||||
/* Can't compile a shader so there is nothing we can do */
|
||||
return;
|
||||
|
||||
/* 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;
|
||||
|
||||
/* 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
|
||||
@ -544,12 +822,62 @@ cogl_wrap_glDrawArrays (GLenum mode, GLint first, GLsizei count)
|
||||
+ w->projection_stack_pos * 16,
|
||||
modelview_matrix);
|
||||
|
||||
glUniformMatrix4fv (w->uniforms->mvp_matrix_uniform, 1,
|
||||
if (program->uniforms.mvp_matrix_uniform != -1)
|
||||
glUniformMatrix4fv (program->uniforms.mvp_matrix_uniform, 1,
|
||||
GL_FALSE, mvp_matrix);
|
||||
glUniformMatrix4fv (w->uniforms->modelview_matrix_uniform, 1, GL_FALSE,
|
||||
modelview_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);
|
||||
|
||||
w->mvp_uptodate = GL_TRUE;
|
||||
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,21 +1080,21 @@ 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,
|
||||
_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,
|
||||
_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,
|
||||
_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;
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
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
|
||||
|
@ -35,6 +35,8 @@
|
||||
|
||||
#ifdef HAVE_COGL_GLES2
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#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 */
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user