GString *header, *source;
UnitState *unit_state;
- /* To allow writing shaders that are portable between GLES 2 and
- * OpenGL Cogl prepends a number of boilerplate #defines and
- * declarations to user shaders. One of those declarations is an
- * array of texture coordinate varyings, but to know how to emit the
- * declaration we need to know how many texture coordinate
- * attributes are in use. The boilerplate also needs to be changed
- * if this increases. */
- int n_tex_coord_attribs;
-
#ifdef HAVE_COGL_GLES2
/* The GLES2 generated program that was generated from the user
program. This is used to detect when the GLES2 backend generates
static gboolean
_cogl_pipeline_backend_glsl_start (CoglPipeline *pipeline,
int n_layers,
- unsigned long pipelines_difference,
- int n_tex_coord_attribs)
+ unsigned long pipelines_difference)
{
CoglPipelineBackendGlslPrivate *priv;
CoglPipeline *authority;
if (priv->glsl_program_state)
{
/* However if the program has changed since the last link then we do
- * need to relink
- *
- * Also if the number of texture coordinate attributes in use has
- * increased, then delete the program so we can prepend a new
- * _cogl_tex_coord[] varying array declaration. */
+ * need to relink */
if (user_program == NULL ||
- (priv->glsl_program_state->user_program_age == user_program->age
-#ifdef HAVE_COGL_GLES2
- && (priv->glsl_program_state->n_tex_coord_attribs >=
- n_tex_coord_attribs)
-#endif
- ))
+ (priv->glsl_program_state->user_program_age == user_program->age))
return TRUE;
/* Destroy the existing program. We can't just dirty the whole
encountered it or because the user program has changed since it
was last linked */
-#ifdef HAVE_COGL_GLES2
- /* Find the largest count of texture coordinate attributes
- * associated with each of the shaders so we can ensure a consistent
- * _cogl_tex_coord[] array declaration across all of the shaders.*/
- if (user_program)
- for (l = user_program->attached_shaders; l; l = l->next)
- {
- CoglShader *shader = l->data;
- n_tex_coord_attribs = MAX (shader->n_tex_coord_attribs,
- n_tex_coord_attribs);
- }
-#endif
-
- priv->glsl_program_state->n_tex_coord_attribs = n_tex_coord_attribs;
-
/* Check whether the user program contains a fragment
shader. Otherwise we need to generate one */
if (user_program)
g_assert (shader->language == COGL_SHADER_LANGUAGE_GLSL);
- _cogl_shader_compile_real (shader,
- glsl_program_state->
- n_tex_coord_attribs);
+ cogl_shader_compile (shader);
GE( glAttachShader (gl_program, shader->gl_handle) );
}
source_strings[1] = glsl_program_state->source->str;
_cogl_shader_set_source_with_boilerplate (shader, GL_FRAGMENT_SHADER,
- glsl_program_state->
- n_tex_coord_attribs,
2, /* count */
source_strings, lengths);
shader = g_slice_new (CoglShader);
shader->language = COGL_SHADER_LANGUAGE_GLSL;
shader->gl_handle = 0;
-#ifdef HAVE_COGL_GLES2
- shader->n_tex_coord_attribs = 0;
-#endif
shader->type = type;
return _cogl_shader_handle_new (shader);
}
-static void
-delete_shader (CoglShader *shader)
-{
- _COGL_GET_CONTEXT (ctx, NO_RETVAL);
-
-#ifdef HAVE_COGL_GL
- if (shader->language == COGL_SHADER_LANGUAGE_ARBFP)
- {
- if (shader->gl_handle)
- GE (glDeletePrograms (1, &shader->gl_handle));
- }
- else
-#endif
- {
- if (shader->gl_handle)
- GE (glDeleteShader (shader->gl_handle));
- }
-
- shader->gl_handle = 0;
-}
-
-void
-cogl_shader_source (CoglHandle handle,
- const char *source)
-{
- CoglShader *shader;
- CoglShaderLanguage language;
-
- _COGL_GET_CONTEXT (ctx, NO_RETVAL);
-
- if (!cogl_is_shader (handle))
- return;
-
- shader = _cogl_shader_pointer_from_handle (handle);
-
-#ifdef HAVE_COGL_GL
- if (strncmp (source, "!!ARBfp1.0", 10) == 0)
- language = COGL_SHADER_LANGUAGE_ARBFP;
- else
-#endif
- language = COGL_SHADER_LANGUAGE_GLSL;
-
- /* Delete the old object if the language is changing... */
- if (G_UNLIKELY (language != shader->language) &&
- shader->gl_handle)
- delete_shader (shader);
-
- shader->source = g_strdup (source);
-
- shader->language = language;
-}
-
-void
-cogl_shader_compile (CoglHandle handle)
-{
-#ifdef HAVE_COGL_GL
- CoglShader *shader = handle;
-#endif
-
- if (!cogl_is_shader (handle))
- return;
-
-#ifdef HAVE_COGL_GL
- _cogl_shader_compile_real (shader, 0 /* ignored */);
-#endif
-
- /* XXX: For GLES2 we don't actually compile anything until the
- * shader gets used so we have an opportunity to add some
- * boilerplate to the shader.
- *
- * At the end of the day this is obviously a badly designed API
- * given that we are having to lie to the user. It was a mistake to
- * so thinly wrap the OpenGL shader API and the current plan is to
- * replace it with a pipeline snippets API. */
-}
-
void
_cogl_shader_set_source_with_boilerplate (GLuint shader_gl_handle,
GLenum shader_gl_type,
- int n_tex_coord_attribs,
GLsizei count_in,
const char **strings_in,
const GLint *lengths_in)
const char **strings = g_alloca (sizeof (char *) * (count_in + 2));
GLint *lengths = g_alloca (sizeof (GLint) * (count_in + 2));
int count = 0;
-#ifdef HAVE_COGL_GLES2
- char *tex_coords_declaration = NULL;
-#endif
GET_CONTEXT (ctx, NO_RETVAL);
lengths[count++] = sizeof (fragment_boilerplate) - 1;
}
-#ifdef HAVE_COGL_GLES2
- if (n_tex_coord_attribs)
- {
- tex_coords_declaration =
- g_strdup_printf ("varying vec2 _cogl_tex_coord[%d];\n",
- n_tex_coord_attribs);
- strings[count] = tex_coords_declaration;
- lengths[count++] = -1; /* null terminated */
- }
-#endif
-
memcpy (strings + count, strings_in, sizeof (char *) * count_in);
if (lengths_in)
memcpy (lengths + count, lengths_in, sizeof (GLint) * count_in);
GE( glShaderSource (shader_gl_handle, count,
(const char **) strings, lengths) );
-
-#ifdef HAVE_COGL_GLES2
- g_free (tex_coords_declaration);
-#endif
}
void
-_cogl_shader_compile_real (CoglHandle handle,
- int n_tex_coord_attribs)
+cogl_shader_source (CoglHandle handle,
+ const char *source)
{
- CoglShader *shader = handle;
+ CoglShader *shader;
+ CoglShaderLanguage language;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
+ if (!cogl_is_shader (handle))
+ return;
+
+ shader = _cogl_shader_pointer_from_handle (handle);
+
#ifdef HAVE_COGL_GL
- if (shader->language == COGL_SHADER_LANGUAGE_ARBFP)
+ if (strncmp (source, "!!ARBfp1.0", 10) == 0)
+ language = COGL_SHADER_LANGUAGE_ARBFP;
+ else
+#endif
+ language = COGL_SHADER_LANGUAGE_GLSL;
+
+ /* Delete the old object if the language is changing... */
+ if (G_UNLIKELY (language != shader->language))
+ {
+#ifdef HAVE_COGL_GL
+ if (shader->language == COGL_SHADER_LANGUAGE_ARBFP)
+ {
+ if (shader->gl_handle)
+ GE (glDeletePrograms (1, &shader->gl_handle));
+ }
+ else
+#endif
+ {
+ if (shader->gl_handle)
+ GE (glDeleteShader (shader->gl_handle));
+ }
+ }
+
+#ifdef HAVE_COGL_GL
+ if (language == COGL_SHADER_LANGUAGE_ARBFP)
{
#ifdef COGL_GL_DEBUG
GLenum gl_error;
#endif
- if (shader->gl_handle)
- return;
-
- GE (glGenPrograms (1, &shader->gl_handle));
+ if (shader->gl_handle == 0)
+ GE (glGenPrograms (1, &shader->gl_handle));
GE (glBindProgram (GL_FRAGMENT_PROGRAM_ARB, shader->gl_handle));
#endif
glProgramString (GL_FRAGMENT_PROGRAM_ARB,
GL_PROGRAM_FORMAT_ASCII_ARB,
- strlen (shader->source),
- shader->source);
+ strlen (source),
+ source);
#ifdef COGL_GL_DEBUG
gl_error = glGetError ();
if (gl_error != GL_NO_ERROR)
g_warning ("%s: GL error (%d): Failed to compile ARBfp:\n%s\n%s",
G_STRLOC,
gl_error,
- shader->source,
+ source,
glGetString (GL_PROGRAM_ERROR_STRING_ARB));
}
#endif
{
GLenum gl_type;
- if (shader->gl_handle
-#ifdef HAVE_COGL_GLES2
- && shader->n_tex_coord_attribs >= n_tex_coord_attribs
-#endif
- )
- return;
-
- if (shader->gl_handle)
- delete_shader (shader);
-
switch (shader->type)
{
case COGL_SHADER_TYPE_VERTEX:
break;
}
- shader->gl_handle = glCreateShader (gl_type);
+ if (!shader->gl_handle)
+ shader->gl_handle = glCreateShader (gl_type);
_cogl_shader_set_source_with_boilerplate (shader->gl_handle,
gl_type,
- n_tex_coord_attribs,
- 1,
- (const char **) &shader->source,
- NULL);
+ 1, &source, NULL);
+ }
- GE (glCompileShader (shader->gl_handle));
+ shader->language = language;
+}
-#ifdef HAVE_COGL_GLES2
- shader->n_tex_coord_attribs = n_tex_coord_attribs;
-#endif
+void
+cogl_shader_compile (CoglHandle handle)
+{
+ CoglShader *shader;
+ _COGL_GET_CONTEXT (ctx, NO_RETVAL);
-#ifdef COGL_GL_DEBUG
- if (!cogl_shader_is_compiled (handle))
- {
- char *log = cogl_shader_get_info_log (handle);
- g_warning ("Failed to compile GLSL program:\nsrc:\n%s\nerror:\n%s\n",
- shader->source,
- log);
- }
-#endif
- }
+ if (!cogl_is_shader (handle))
+ return;
+
+ shader = _cogl_shader_pointer_from_handle (handle);
+
+ if (shader->language == COGL_SHADER_LANGUAGE_GLSL)
+ GE (glCompileShader (shader->gl_handle));
}
char *
{
char buffer[512];
int len = 0;
-
- /* We don't normally compile the shader when the user calls
- * cogl_shader_compile() because we want to be able to add
- * boilerplate code that depends on how it ends up finally being
- * used.
- *
- * Here we force an early compile if the user is interested in
- * log information to increase the chance that the log will be
- * useful! We have to guess the number of texture coordinate
- * attributes that may be used (normally less than 4) since that
- * affects the boilerplate.
- */
- if (!shader->gl_handle)
- _cogl_shader_compile_real (handle, 4);
-
glGetShaderInfoLog (shader->gl_handle, 511, &len, buffer);
buffer[len] = '\0';
return g_strdup (buffer);
else
#endif
{
- /* FIXME: We currently have an arbitrary limit of 4 texture
- * coordinate attributes since our API means we have to add
- * some boilerplate to the users GLSL program (for GLES2)
- * before we actually know how many attributes are in use.
- *
- * 4 will probably be enough (or at least that limitation should
- * be enough until we can replace this API with the pipeline
- * snippets API) but if it isn't then the shader won't compile,
- * through no fault of the user.
- *
- * To some extent this is just a symptom of bad API design; it
- * was a mistake for Cogl to so thinly wrap the OpenGL shader
- * API. Eventually we plan for this whole API will be deprecated
- * by the pipeline snippets framework.
- */
- if (!shader->gl_handle)
- _cogl_shader_compile_real (handle, 4);
-
GE (glGetShaderiv (shader->gl_handle, GL_COMPILE_STATUS, &status));
if (status == GL_TRUE)
return TRUE;
}
#endif /* HAVE_COGL_GLES */
-