mesa: Only update sampler uniforms that are used by the shader stage
authorIan Romanick <ian.d.romanick@intel.com>
Thu, 10 Nov 2011 20:32:35 +0000 (12:32 -0800)
committerIan Romanick <ian.d.romanick@intel.com>
Wed, 16 Nov 2011 16:37:44 +0000 (08:37 -0800)
Previously a vertex shader that used no samplers would get updated (by
calling the driver's ProgramStringNotify) when a sampler in the
fragment shader was updated.  This was discovered while investigating
some spurious code generation for shaders in Cogs.  The behavior in
Cogs is especially pessimal because it ping-pongs sampler uniform
settings:

    glUniform1i(sampler1, 0);
    glUniform1i(sampler2, 1);
    draw();
    glUniform1i(sampler1, 1);
    glUniform1i(sampler2, 0);
    draw();
    glUniform1i(sampler1, 0);
    glUniform1i(sampler2, 1);
    draw();
    // etc.

ProgramStringNotify is still too big of a hammer.  Applications like
Cogs will still defeat the shader cache.  A lighter-weight mechanism
that can work with the shader cache is needed.  However, this patch at
least restores the previous behavior.

Signed-off-by: Ian Romanick <ian.d.romanick@intel.com>
Reviewed-by: Kenneth Graunke <kenneth@whitecape.org>
src/mesa/main/uniform_query.cpp

index 5371d6a176bb3d5454f6f7d9f674cfabe789939a..33ba53c2e7bf8197641c7942da3225edbe02c023 100644 (file)
@@ -698,11 +698,27 @@ _mesa_uniform(struct gl_context *ctx, struct gl_shader_program *shProg,
 
         prog = shProg->_LinkedShaders[i]->Program;
 
+        /* If the shader stage doesn't use any samplers, don't bother
+         * checking if any samplers have changed.
+         */
+        if (prog->SamplersUsed == 0)
+           continue;
+
         assert(sizeof(prog->SamplerUnits) == sizeof(shProg->SamplerUnits));
 
-        if (memcmp(prog->SamplerUnits,
-                   shProg->SamplerUnits,
-                   sizeof(shProg->SamplerUnits)) != 0) {
+        /* Determine if any of the samplers used by this shader stage have
+         * been modified.
+         */
+        bool changed = false;
+        for (unsigned j = 0; j < Elements(prog->SamplerUnits); j++) {
+           if ((prog->SamplersUsed & (1U << j)) != 0
+               && (prog->SamplerUnits[j] != shProg->SamplerUnits[j])) {
+              changed = true;
+              break;
+           }
+        }
+
+        if (changed) {
            if (!flushed) {
               FLUSH_VERTICES(ctx, _NEW_TEXTURE | _NEW_PROGRAM);
               flushed = true;