Revert "cogl: Remove the generated array size for cogl_tex_coord_in"

This reverts commit 4cfe90bde2.

GLSL 1.00 on GLES doesn't support unsized arrays so the whole idea
can't work.

Conflicts:

	clutter/cogl/cogl/cogl-pipeline-glsl.c
This commit is contained in:
Neil Roberts 2010-12-02 21:08:30 +00:00
parent f54cc7abd4
commit f8449582c8
13 changed files with 265 additions and 90 deletions

View File

@ -262,7 +262,7 @@ cogl_create_context (void)
default_texture_data);
cogl_push_source (_context->opaque_color_pipeline);
_cogl_pipeline_flush_gl_state (_context->opaque_color_pipeline, FALSE);
_cogl_pipeline_flush_gl_state (_context->opaque_color_pipeline, FALSE, 0);
_cogl_enable (enable_flags);
_cogl_flush_face_winding ();

View File

@ -184,7 +184,8 @@ get_arbfp_program_state (CoglPipeline *pipeline)
static gboolean
_cogl_pipeline_backend_arbfp_start (CoglPipeline *pipeline,
int n_layers,
unsigned long pipelines_difference)
unsigned long pipelines_difference,
int n_tex_coord_attribs)
{
CoglPipelineBackendARBfpPrivate *priv;
CoglPipeline *authority;

View File

@ -69,7 +69,8 @@ _cogl_pipeline_backend_fixed_get_max_texture_units (void)
static gboolean
_cogl_pipeline_backend_fixed_start (CoglPipeline *pipeline,
int n_layers,
unsigned long pipelines_difference)
unsigned long pipelines_difference,
int n_tex_coord_attribs)
{
CoglHandle user_program;

View File

@ -102,6 +102,15 @@ typedef struct _GlslProgramState
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
@ -277,7 +286,8 @@ link_program (GLint gl_program)
static gboolean
_cogl_pipeline_backend_glsl_start (CoglPipeline *pipeline,
int n_layers,
unsigned long pipelines_difference)
unsigned long pipelines_difference,
int n_tex_coord_attribs)
{
CoglPipelineBackendGlslPrivate *priv;
CoglPipeline *authority;
@ -345,13 +355,24 @@ _cogl_pipeline_backend_glsl_start (CoglPipeline *pipeline,
if (priv->glsl_program_state->gl_program)
{
/* If we already have a valid GLSL program then we don't need to
relink a new one. However if the program has changed since
the last link then we do need to relink */
* relink a new one. 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. */
if (user_program == NULL ||
(priv->glsl_program_state->user_program_age == user_program->age))
(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
))
return TRUE;
/* We need to recreate the program so destroy the existing one */
/* Destroy the existing program. We can't just dirty the whole
glsl state because otherwise if we are not the authority on
the user program then we'll just find the same state again */
delete_program (priv->glsl_program_state->gl_program);
priv->glsl_program_state->gl_program = 0;
}
@ -361,6 +382,21 @@ _cogl_pipeline_backend_glsl_start (CoglPipeline *pipeline,
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)
@ -991,7 +1027,9 @@ _cogl_pipeline_backend_glsl_end (CoglPipeline *pipeline,
g_assert (shader->language == COGL_SHADER_LANGUAGE_GLSL);
cogl_shader_compile (shader);
_cogl_shader_compile_real (shader,
glsl_program_state->
n_tex_coord_attribs);
GE( glAttachShader (gl_program, shader->gl_handle) );
}
@ -1032,6 +1070,8 @@ _cogl_pipeline_backend_glsl_end (CoglPipeline *pipeline,
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);

View File

@ -150,7 +150,8 @@ _cogl_gl_use_program_wrapper (CoglHandle program);
void
_cogl_pipeline_flush_gl_state (CoglPipeline *pipeline,
gboolean skip_gl_state);
gboolean skip_gl_state,
int n_tex_coord_attribs);
#endif /* __COGL_PIPELINE_OPENGL_PRIVATE_H */

View File

@ -1031,7 +1031,8 @@ backend_add_layer_cb (CoglPipelineLayer *layer,
*/
void
_cogl_pipeline_flush_gl_state (CoglPipeline *pipeline,
gboolean skip_gl_color)
gboolean skip_gl_color,
int n_tex_coord_attribs)
{
unsigned long pipelines_difference;
int n_layers;
@ -1134,7 +1135,8 @@ _cogl_pipeline_flush_gl_state (CoglPipeline *pipeline,
* scratch buffers here... */
if (G_UNLIKELY (!backend->start (pipeline,
n_layers,
pipelines_difference)))
pipelines_difference,
n_tex_coord_attribs)))
continue;
state.backend = backend;

View File

@ -567,7 +567,8 @@ typedef struct _CoglPipelineBackend
gboolean (*start) (CoglPipeline *pipeline,
int n_layers,
unsigned long pipelines_difference);
unsigned long pipelines_difference,
int n_tex_coord_attribs);
gboolean (*add_layer) (CoglPipeline *pipeline,
CoglPipelineLayer *layer,
unsigned long layers_difference);

View File

@ -92,7 +92,6 @@
"#endif\n" \
"\n" \
"varying vec4 _cogl_color;\n" \
"varying vec4 _cogl_tex_coord[];\n" \
"\n" \
"#define cogl_color_in _cogl_color\n" \
"#define cogl_tex_coord_in _cogl_tex_coord\n" \

View File

@ -40,18 +40,24 @@ struct _CoglShader
{
CoglHandleObject _parent;
GLuint gl_handle;
int n_tex_coord_attribs;
CoglShaderType type;
CoglShaderLanguage language;
char *source;
};
CoglShader *_cogl_shader_pointer_from_handle (CoglHandle handle);
void
_cogl_shader_compile_real (CoglHandle handle, int n_tex_coord_attribs);
CoglShaderLanguage
_cogl_program_get_language (CoglHandle handle);
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);

View File

@ -101,52 +101,33 @@ cogl_create_shader (CoglShaderType type)
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);
}
void
_cogl_shader_set_source_with_boilerplate (GLuint shader_gl_handle,
GLenum shader_gl_type,
GLsizei count_in,
const char **strings_in,
const GLint *lengths_in)
static void
delete_shader (CoglShader *shader)
{
static const char vertex_boilerplate[] = _COGL_VERTEX_SHADER_BOILERPLATE;
static const char fragment_boilerplate[] = _COGL_FRAGMENT_SHADER_BOILERPLATE;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
const char **strings = g_alloca (sizeof (char *) * (count_in + 2));
GLint *lengths = g_alloca (sizeof (GLint) * (count_in + 2));
int count = 0;
GET_CONTEXT (ctx, NO_RETVAL);
if (shader_gl_type == GL_VERTEX_SHADER)
#ifdef HAVE_COGL_GL
if (shader->language == COGL_SHADER_LANGUAGE_ARBFP)
{
strings[count] = vertex_boilerplate;
lengths[count++] = sizeof (vertex_boilerplate) - 1;
if (shader->gl_handle)
GE (glDeletePrograms (1, &shader->gl_handle));
}
else if (shader_gl_type == GL_FRAGMENT_SHADER)
{
strings[count] = fragment_boilerplate;
lengths[count++] = sizeof (fragment_boilerplate) - 1;
}
memcpy (strings + count, strings_in, sizeof (char *) * count_in);
if (lengths_in)
memcpy (lengths + count, lengths_in, sizeof (GLint) * count_in);
else
#endif
{
int i;
for (i = 0; i < count_in; i++)
lengths[count + i] = -1; /* null terminated */
if (shader->gl_handle)
GE (glDeleteShader (shader->gl_handle));
}
count += count_in;
GE( glShaderSource (shader_gl_handle, count,
(const char **) strings, lengths) );
shader->gl_handle = 0;
}
void
@ -171,30 +152,119 @@ cogl_shader_source (CoglHandle handle,
language = COGL_SHADER_LANGUAGE_GLSL;
/* Delete the old object if the language is changing... */
if (G_UNLIKELY (language != shader->language))
{
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
if (shader->language == COGL_SHADER_LANGUAGE_ARBFP)
{
if (shader->gl_handle)
GE (glDeletePrograms (1, &shader->gl_handle));
}
else
CoglShader *shader = handle;
#endif
{
if (shader->gl_handle)
GE (glDeleteShader (shader->gl_handle));
}
}
if (!cogl_is_shader (handle))
return;
#ifdef HAVE_COGL_GL
if (language == COGL_SHADER_LANGUAGE_ARBFP)
_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)
{
static const char vertex_boilerplate[] = _COGL_VERTEX_SHADER_BOILERPLATE;
static const char fragment_boilerplate[] = _COGL_FRAGMENT_SHADER_BOILERPLATE;
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);
if (shader_gl_type == GL_VERTEX_SHADER)
{
strings[count] = vertex_boilerplate;
lengths[count++] = sizeof (vertex_boilerplate) - 1;
}
else if (shader_gl_type == GL_FRAGMENT_SHADER)
{
strings[count] = fragment_boilerplate;
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);
else
{
int i;
for (i = 0; i < count_in; i++)
lengths[count + i] = -1; /* null terminated */
}
count += 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)
{
CoglShader *shader = handle;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
#ifdef HAVE_COGL_GL
if (shader->language == COGL_SHADER_LANGUAGE_ARBFP)
{
#ifdef COGL_GL_DEBUG
GLenum gl_error;
#endif
if (shader->gl_handle == 0)
if (shader->gl_handle)
return;
GE (glGenPrograms (1, &shader->gl_handle));
GE (glBindProgram (GL_FRAGMENT_PROGRAM_ARB, shader->gl_handle));
@ -205,8 +275,8 @@ cogl_shader_source (CoglHandle handle,
#endif
glProgramString (GL_FRAGMENT_PROGRAM_ARB,
GL_PROGRAM_FORMAT_ASCII_ARB,
strlen (source),
source);
strlen (shader->source),
shader->source);
#ifdef COGL_GL_DEBUG
gl_error = glGetError ();
if (gl_error != GL_NO_ERROR)
@ -214,7 +284,7 @@ cogl_shader_source (CoglHandle handle,
g_warning ("%s: GL error (%d): Failed to compile ARBfp:\n%s\n%s",
G_STRLOC,
gl_error,
source,
shader->source,
glGetString (GL_PROGRAM_ERROR_STRING_ARB));
}
#endif
@ -224,6 +294,16 @@ cogl_shader_source (CoglHandle handle,
{
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:
@ -237,30 +317,31 @@ cogl_shader_source (CoglHandle handle,
break;
}
if (!shader->gl_handle)
shader->gl_handle = glCreateShader (gl_type);
_cogl_shader_set_source_with_boilerplate (shader->gl_handle,
gl_type,
1, &source, NULL);
}
n_tex_coord_attribs,
1,
(const char **) &shader->source,
NULL);
shader->language = language;
}
void
cogl_shader_compile (CoglHandle handle)
{
CoglShader *shader;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
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));
#ifdef HAVE_COGL_GLES2
shader->n_tex_coord_attribs = n_tex_coord_attribs;
#endif
#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
}
}
char *
@ -288,6 +369,21 @@ cogl_shader_get_info_log (CoglHandle handle)
{
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);
@ -330,6 +426,24 @@ cogl_shader_is_compiled (CoglHandle handle)
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;
@ -395,3 +509,4 @@ cogl_shader_is_compiled (CoglHandle handle)
}
#endif /* HAVE_COGL_GLES */

View File

@ -435,6 +435,7 @@ enable_gl_state (CoglVertexAttribute **attributes,
gboolean skip_gl_color = FALSE;
CoglPipeline *source;
CoglPipeline *copy = NULL;
int n_tex_coord_attribs = 0;
_COGL_GET_CONTEXT (ctx, COGL_INVALID_HANDLE);
@ -490,6 +491,7 @@ enable_gl_state (CoglVertexAttribute **attributes,
base + attribute->offset));
_cogl_bitmask_set (&ctx->temp_bitmask,
attribute->texture_unit, TRUE);
n_tex_coord_attribs++;
break;
case COGL_VERTEX_ATTRIBUTE_NAME_ID_POSITION_ARRAY:
enable_flags |= COGL_ENABLE_VERTEX_ARRAY;
@ -578,7 +580,7 @@ enable_gl_state (CoglVertexAttribute **attributes,
_cogl_pipeline_apply_legacy_state (source);
}
_cogl_pipeline_flush_gl_state (source, skip_gl_color);
_cogl_pipeline_flush_gl_state (source, skip_gl_color, n_tex_coord_attribs);
if (ctx->enable_backface_culling)
enable_flags |= COGL_ENABLE_BACKFACE_CULLING;

View File

@ -770,13 +770,20 @@ cogl_begin_gl (void)
* A user should instead call cogl_set_source_color4ub() before
* cogl_begin_gl() to simplify the state flushed.
*
* XXX: note defining n_tex_coord_attribs using
* cogl_pipeline_get_n_layers is a hack, but the problem is that
* n_tex_coord_attribs is usually defined when drawing a primitive
* which isn't happening here.
*
* Maybe it would be more useful if this code did flush the
* opaque_color_pipeline and then call into cogl-pipeline-opengl.c to then
* restore all state for the material's backend back to default OpenGL
* values.
*/
pipeline = cogl_get_source ();
_cogl_pipeline_flush_gl_state (pipeline, FALSE);
_cogl_pipeline_flush_gl_state (pipeline,
FALSE,
cogl_pipeline_get_n_layers (pipeline));
if (ctx->enable_backface_culling)
enable_flags |= COGL_ENABLE_BACKFACE_CULLING;

View File

@ -221,7 +221,7 @@ _cogl_path_stroke_nodes (CoglPath *path)
cogl_push_source (source);
_cogl_pipeline_flush_gl_state (source, FALSE);
_cogl_pipeline_flush_gl_state (source, FALSE, 0);
/* Disable all client texture coordinate arrays */
_cogl_bitmask_clear_all (&ctx->temp_bitmask);
@ -365,7 +365,7 @@ _cogl_add_path_to_stencil_buffer (CoglPath *path,
/* Just setup a simple pipeline that doesn't use texturing... */
cogl_push_source (ctx->stencil_pipeline);
_cogl_pipeline_flush_gl_state (ctx->stencil_pipeline, FALSE);
_cogl_pipeline_flush_gl_state (ctx->stencil_pipeline, FALSE, 0);
_cogl_enable (enable_flags);