summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNeil Roberts <neil@linux.intel.com>2011-10-19 12:47:22 +0100
committerNeil Roberts <neil@linux.intel.com>2011-11-02 13:52:01 +0000
commit521b39c31a9ef1276bc7209326d306f28eff93c9 (patch)
treeea82c964976afa0bfe618eabeb3506179beb1dc5
parentb76fb45da8ee0dffa7479fee685db4e0a6be4f12 (diff)
downloadcogl-521b39c31a9ef1276bc7209326d306f28eff93c9.tar.gz
Use the same number for n_tex_coord_attribs in all linked shaders
On GLES2, we need to specify an array size for the texture coord varying array. Previously this size would be decided in one of the following ways: - For generated vertex shaders it is always the number of layers in the pipeline. - For generated fragment shaders it is the highest sampled texture unit in the pipeline or the number of attributes supplied by the primitive, whichever is higher. - For user shaders it is usually the number of attributes supplied by the primitive. However, if the application tries to compile the shader and query the result before using it, it will always be at least 4. These shaders can quite easily end up with different values for the declaration which makes it fail to link. This patch changes it so that all of the shaders are generated with the maximum of the number of texture attributes supplied by the primitive and the number of layers in the pipeline. If this value changes then the shaders are regenerated, including user shaders. That way all of the shaders will always have the same value. https://bugzilla.gnome.org/show_bug.cgi?id=662184 Reviewed-by: Robert Bragg <robert@linux.intel.com> (cherry picked from commit 00f0a66ec949a641db744f56230c2bcfc98c1883)
-rw-r--r--cogl/cogl-pipeline-fragend-glsl.c30
-rw-r--r--cogl/cogl-pipeline-opengl.c13
-rw-r--r--cogl/cogl-pipeline-private.h3
-rw-r--r--cogl/cogl-pipeline-progend-glsl.c28
-rw-r--r--cogl/cogl-pipeline-vertend-fixed.c3
-rw-r--r--cogl/cogl-pipeline-vertend-glsl.c27
-rw-r--r--cogl/cogl-shader.c10
7 files changed, 64 insertions, 50 deletions
diff --git a/cogl/cogl-pipeline-fragend-glsl.c b/cogl/cogl-pipeline-fragend-glsl.c
index 48e523bd..6b3904e9 100644
--- a/cogl/cogl-pipeline-fragend-glsl.c
+++ b/cogl/cogl-pipeline-fragend-glsl.c
@@ -101,6 +101,11 @@ typedef struct
program changes then we may need to redecide whether to generate
a shader at all */
unsigned int user_program_age;
+
+ /* The number of tex coord attributes that the shader was generated
+ for. If this changes on GLES2 then we need to regenerate the
+ shader */
+ int n_tex_coord_attribs;
} CoglPipelineShaderState;
static CoglUserDataKey shader_state_key;
@@ -266,9 +271,14 @@ _cogl_pipeline_fragend_glsl_start (CoglPipeline *pipeline,
{
/* If we already have a valid GLSL shader then we don't need to
generate a new one. However if there's a user program and it
- has changed since the last link then we do need a new shader */
- if (user_program == NULL ||
- shader_state->user_program_age == user_program->age)
+ has changed since the last link then we do need a new
+ shader. If the number of tex coord attribs changes on GLES2
+ then we need to regenerate the shader with a different boiler
+ plate */
+ if ((user_program == NULL ||
+ shader_state->user_program_age == user_program->age)
+ && (ctx->driver != COGL_DRIVER_GLES2 ||
+ shader_state->n_tex_coord_attribs == n_tex_coord_attribs))
return TRUE;
/* We need to recreate the shader so destroy the existing one */
@@ -283,6 +293,8 @@ _cogl_pipeline_fragend_glsl_start (CoglPipeline *pipeline,
if (user_program)
shader_state->user_program_age = user_program->age;
+ shader_state->n_tex_coord_attribs = n_tex_coord_attribs;
+
/* If the user program contains a fragment shader then we don't need
to generate one */
if (user_program &&
@@ -871,8 +883,6 @@ _cogl_pipeline_fragend_glsl_end (CoglPipeline *pipeline,
GLint lengths[2];
GLint compile_status;
GLuint shader;
- int n_tex_coord_attribs = 0;
- int i, n_layers;
COGL_STATIC_COUNTER (fragend_glsl_compile_counter,
"glsl fragment compile counter",
@@ -919,15 +929,9 @@ _cogl_pipeline_fragend_glsl_end (CoglPipeline *pipeline,
lengths[1] = shader_state->source->len;
source_strings[1] = shader_state->source->str;
- /* Find the highest texture unit that is sampled to pass as the
- number of texture coordinate attributes */
- n_layers = cogl_pipeline_get_n_layers (pipeline);
- for (i = 0; i < n_layers; i++)
- if (shader_state->unit_state[i].sampled)
- n_tex_coord_attribs = i + 1;
-
_cogl_shader_set_source_with_boilerplate (shader, GL_FRAGMENT_SHADER,
- n_tex_coord_attribs,
+ shader_state
+ ->n_tex_coord_attribs,
2, /* count */
source_strings, lengths);
diff --git a/cogl/cogl-pipeline-opengl.c b/cogl/cogl-pipeline-opengl.c
index caede90d..8220c5e1 100644
--- a/cogl/cogl-pipeline-opengl.c
+++ b/cogl/cogl-pipeline-opengl.c
@@ -1199,6 +1199,16 @@ _cogl_pipeline_flush_gl_state (CoglPipeline *pipeline,
else
layer_differences = NULL;
+ /* Make sure we generate the texture coordinate array to be at least
+ the number of layers. This is important because the vertend will
+ try to pass along the corresponding varying for each layer
+ regardless of whether the fragment shader is actually using
+ it. Also it is possible that the application is assuming that if
+ the attribute isn't passed then it will default to 0,0. This is
+ what test-cogl-primitive does */
+ if (n_layers > n_tex_coord_attribs)
+ n_tex_coord_attribs = n_layers;
+
/* First flush everything that's the same regardless of which
* pipeline backend is being used...
*
@@ -1299,7 +1309,8 @@ _cogl_pipeline_flush_gl_state (CoglPipeline *pipeline,
* scratch buffers here... */
if (G_UNLIKELY (!vertend->start (pipeline,
n_layers,
- pipelines_difference)))
+ pipelines_difference,
+ n_tex_coord_attribs)))
continue;
state.vertend = vertend;
diff --git a/cogl/cogl-pipeline-private.h b/cogl/cogl-pipeline-private.h
index 346026e8..2570c524 100644
--- a/cogl/cogl-pipeline-private.h
+++ b/cogl/cogl-pipeline-private.h
@@ -814,7 +814,8 @@ typedef struct _CoglPipelineVertend
{
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);
diff --git a/cogl/cogl-pipeline-progend-glsl.c b/cogl/cogl-pipeline-progend-glsl.c
index bade8531..d26d3c20 100644
--- a/cogl/cogl-pipeline-progend-glsl.c
+++ b/cogl/cogl-pipeline-progend-glsl.c
@@ -104,7 +104,7 @@ typedef struct
* 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. */
+ * if this changes. */
int n_tex_coord_attribs;
#ifdef HAVE_COGL_GLES2
@@ -618,11 +618,12 @@ _cogl_pipeline_progend_glsl_end (CoglPipeline *pipeline,
* 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
+ * changed, then delete the program so we can prepend a new
* _cogl_tex_coord[] varying array declaration. */
- if (program_state->program && user_program &&
- (user_program->age != program_state->user_program_age ||
- n_tex_coord_attribs > program_state->n_tex_coord_attribs))
+ if ((program_state->program && user_program &&
+ user_program->age != program_state->user_program_age) ||
+ (ctx->driver == COGL_DRIVER_GLES2 &&
+ n_tex_coord_attribs != program_state->n_tex_coord_attribs))
{
GE( ctx, glDeleteProgram (program_state->program) );
program_state->program = 0;
@@ -638,23 +639,6 @@ _cogl_pipeline_progend_glsl_end (CoglPipeline *pipeline,
/* Attach all of the shader from the user program */
if (user_program)
{
- if (program_state->n_tex_coord_attribs > n_tex_coord_attribs)
- n_tex_coord_attribs = program_state->n_tex_coord_attribs;
-
-#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 (ctx->driver == COGL_DRIVER_GLES2 &&
- 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
-
for (l = user_program->attached_shaders; l; l = l->next)
{
CoglShader *shader = l->data;
diff --git a/cogl/cogl-pipeline-vertend-fixed.c b/cogl/cogl-pipeline-vertend-fixed.c
index a3d3ae4f..a229c70f 100644
--- a/cogl/cogl-pipeline-vertend-fixed.c
+++ b/cogl/cogl-pipeline-vertend-fixed.c
@@ -45,7 +45,8 @@ const CoglPipelineVertend _cogl_pipeline_fixed_vertend;
static gboolean
_cogl_pipeline_vertend_fixed_start (CoglPipeline *pipeline,
int n_layers,
- unsigned long pipelines_difference)
+ unsigned long pipelines_difference,
+ int n_tex_coord_attribs)
{
CoglProgram *user_program;
diff --git a/cogl/cogl-pipeline-vertend-glsl.c b/cogl/cogl-pipeline-vertend-glsl.c
index b8a4535b..9fd5c904 100644
--- a/cogl/cogl-pipeline-vertend-glsl.c
+++ b/cogl/cogl-pipeline-vertend-glsl.c
@@ -55,6 +55,11 @@ typedef struct
program changes then we may need to redecide whether to generate
a shader at all */
unsigned int user_program_age;
+
+ /* The number of tex coord attributes that the shader was generated
+ for. If this changes on GLES2 then we need to regenerate the
+ shader */
+ int n_tex_coord_attribs;
} CoglPipelineShaderState;
static CoglUserDataKey shader_state_key;
@@ -125,7 +130,8 @@ _cogl_pipeline_vertend_glsl_get_shader (CoglPipeline *pipeline)
static gboolean
_cogl_pipeline_vertend_glsl_start (CoglPipeline *pipeline,
int n_layers,
- unsigned long pipelines_difference)
+ unsigned long pipelines_difference,
+ int n_tex_coord_attribs)
{
CoglPipelineShaderState *shader_state;
CoglPipeline *template_pipeline = NULL;
@@ -202,9 +208,14 @@ _cogl_pipeline_vertend_glsl_start (CoglPipeline *pipeline,
{
/* If we already have a valid GLSL shader then we don't need to
generate a new one. However if there's a user program and it
- has changed since the last link then we do need a new shader */
- if (user_program == NULL ||
- shader_state->user_program_age == user_program->age)
+ has changed since the last link then we do need a new
+ shader. If the number of tex coord attribs changes on GLES2
+ then we need to regenerate the shader with a different boiler
+ plate */
+ if ((user_program == NULL ||
+ shader_state->user_program_age == user_program->age)
+ && (ctx->driver != COGL_DRIVER_GLES2 ||
+ shader_state->n_tex_coord_attribs == n_tex_coord_attribs))
return TRUE;
/* We need to recreate the shader so destroy the existing one */
@@ -219,6 +230,8 @@ _cogl_pipeline_vertend_glsl_start (CoglPipeline *pipeline,
if (user_program)
shader_state->user_program_age = user_program->age;
+ shader_state->n_tex_coord_attribs = n_tex_coord_attribs;
+
/* If the user program contains a vertex shader then we don't need
to generate one */
if (user_program &&
@@ -335,7 +348,6 @@ _cogl_pipeline_vertend_glsl_end (CoglPipeline *pipeline,
GLint lengths[2];
GLint compile_status;
GLuint shader;
- int n_layers;
COGL_STATIC_COUNTER (vertend_glsl_compile_counter,
"glsl vertex compile counter",
@@ -358,10 +370,9 @@ _cogl_pipeline_vertend_glsl_end (CoglPipeline *pipeline,
lengths[1] = shader_state->source->len;
source_strings[1] = shader_state->source->str;
- n_layers = cogl_pipeline_get_n_layers (pipeline);
-
_cogl_shader_set_source_with_boilerplate (shader, GL_VERTEX_SHADER,
- n_layers,
+ shader_state
+ ->n_tex_coord_attribs,
2, /* count */
source_strings, lengths);
diff --git a/cogl/cogl-shader.c b/cogl/cogl-shader.c
index 4d662ab3..cb70976c 100644
--- a/cogl/cogl-shader.c
+++ b/cogl/cogl-shader.c
@@ -342,7 +342,7 @@ _cogl_shader_compile_real (CoglHandle handle,
#ifdef HAVE_COGL_GLES2
&&
(ctx->driver != COGL_DRIVER_GLES2 ||
- shader->n_tex_coord_attribs >= n_tex_coord_attribs)
+ shader->n_tex_coord_attribs == n_tex_coord_attribs)
#endif
)
return;
@@ -424,9 +424,11 @@ cogl_shader_get_info_log (CoglHandle handle)
* 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.
- */
+ * attributes that may be used since that affects the
+ * boilerplate. We use four so that the shader will still
+ * compile if the user is using more than one
+ * layer. Unfortunately this is likely to end up causing it to
+ * be compiled again when we know the actual number of layers */
if (!shader->gl_handle)
_cogl_shader_compile_real (handle, 4);