mesa: Validate sampler settings using uniform storage
authorIan Romanick <ian.d.romanick@intel.com>
Mon, 14 Nov 2011 20:11:46 +0000 (12:11 -0800)
committerIan Romanick <ian.d.romanick@intel.com>
Wed, 11 Jan 2012 20:51:24 +0000 (12:51 -0800)
Rather than looking at the settings in individual assembly programs,
look at the settings in the top-level uniform values.  The old code
was flawed because examining each shader stage in isolation could
allow inconsitent usage across stages (e.g., bind unit 0 to a
sampler2D in the vertex shader and sampler1DShadow in the fragment
shader).

Signed-off-by: Ian Romanick <ian.d.romanick@intel.com>
Reviewed-by: Eric Anholt <eric@anholt.net>
Reviewed-by: Kenneth Graunke <kenneth@whitecape.org>
src/mesa/main/shaderapi.c
src/mesa/main/uniform_query.cpp
src/mesa/main/uniforms.h

index f3f13a02645e3772b34c2c14ad4bddea7de8bfa8..5bfe217ae863fa30fe0d69f57165b83b165e84cf 100644 (file)
@@ -927,62 +927,6 @@ _mesa_use_program(struct gl_context *ctx, struct gl_shader_program *shProg)
       ctx->Driver.UseProgram(ctx, shProg);
 }
 
-
-/**
- * Validate a program's samplers.
- * Specifically, check that there aren't two samplers of different types
- * pointing to the same texture unit.
- * \return GL_TRUE if valid, GL_FALSE if invalid
- */
-static GLboolean
-validate_samplers(const struct gl_program *prog, char *errMsg)
-{
-   static const char *targetName[] = {
-      "TEXTURE_BUFFER",
-      "TEXTURE_2D_ARRAY",
-      "TEXTURE_1D_ARRAY",
-      "TEXTURE_EXTERNAL",
-      "TEXTURE_CUBE",
-      "TEXTURE_3D",
-      "TEXTURE_RECT",
-      "TEXTURE_2D",
-      "TEXTURE_1D",
-   };
-   GLint targetUsed[MAX_COMBINED_TEXTURE_IMAGE_UNITS];
-   GLbitfield samplersUsed = prog->SamplersUsed;
-   GLuint i;
-
-   STATIC_ASSERT(Elements(targetName) == NUM_TEXTURE_TARGETS);
-
-   if (samplersUsed == 0x0)
-      return GL_TRUE;
-
-   for (i = 0; i < Elements(targetUsed); i++)
-      targetUsed[i] = -1;
-
-   /* walk over bits which are set in 'samplers' */
-   while (samplersUsed) {
-      GLuint unit;
-      gl_texture_index target;
-      GLint sampler = _mesa_ffs(samplersUsed) - 1;
-      assert(sampler >= 0);
-      assert(sampler < Elements(prog->SamplerUnits));
-      unit = prog->SamplerUnits[sampler];
-      target = prog->SamplerTargets[sampler];
-      if (targetUsed[unit] != -1 && targetUsed[unit] != (int) target) {
-         _mesa_snprintf(errMsg, 100,
-                 "Texture unit %d is accessed both as %s and %s",
-                 unit, targetName[targetUsed[unit]], targetName[target]);
-         return GL_FALSE;
-      }
-      targetUsed[unit] = target;
-      samplersUsed ^= (1 << sampler);
-   }
-
-   return GL_TRUE;
-}
-
-
 /**
  * Do validation of the given shader program.
  * \param errMsg  returns error message if validation fails.
@@ -1018,12 +962,8 @@ validate_shader_program(const struct gl_shader_program *shProg,
     * Check: any two active samplers in the current program object are of
     * different types, but refer to the same texture image unit,
     */
-   for (i = 0; i < Elements(shProg->_LinkedShaders); i++) {
-      if (shProg->_LinkedShaders[i]
-         && !validate_samplers(shProg->_LinkedShaders[i]->Program, errMsg)) {
-        return GL_FALSE;
-      }
-   }
+   if (!_mesa_sampler_uniforms_are_valid(shProg, errMsg, 100))
+      return GL_FALSE;
 
    return GL_TRUE;
 }
index f3d6a16eef9debab0e949de64fbc19a1fd7c8547..a5a85cd9c1324c11230dfc289e8902ea64820b53 100644 (file)
@@ -933,3 +933,46 @@ _mesa_get_uniform_location(struct gl_context *ctx,
 
    return _mesa_uniform_merge_location_offset(location, offset);
 }
+
+extern "C" bool
+_mesa_sampler_uniforms_are_valid(const struct gl_shader_program *shProg,
+                                char *errMsg, size_t errMsgLength)
+{
+   const glsl_type *unit_types[MAX_COMBINED_TEXTURE_IMAGE_UNITS];
+
+   memset(unit_types, 0, sizeof(unit_types));
+
+   for (unsigned i = 0; i < shProg->NumUserUniformStorage; i++) {
+      const struct gl_uniform_storage *const storage =
+        &shProg->UniformStorage[i];
+      const glsl_type *const t = (storage->type->is_array())
+        ? storage->type->fields.array : storage->type;
+
+      if (!t->is_sampler())
+        continue;
+
+      const unsigned count = MAX2(1, storage->type->array_size());
+      for (unsigned j = 0; j < count; j++) {
+        const unsigned unit = storage->storage[j].i;
+
+        /* The types of the samplers associated with a particular texture
+         * unit must be an exact match.  Page 74 (page 89 of the PDF) of the
+         * OpenGL 3.3 core spec says:
+         *
+         *     "It is not allowed to have variables of different sampler
+         *     types pointing to the same texture image unit within a program
+         *     object."
+         */
+        if (unit_types[unit] == NULL) {
+           unit_types[unit] = t;
+        } else if (unit_types[unit] != t) {
+           _mesa_snprintf(errMsg, errMsgLength,
+                          "Texture unit %d is accessed both as %s and %s",
+                          unit, unit_types[unit]->name, t->name);
+           return false;
+        }
+      }
+   }
+
+   return true;
+}
index 123d7b95423f90cfa9b5283ad9a7c17a8250ec8a..f796f82766ed5cf6e61ca2b92907f23d32f41f8b 100644 (file)
@@ -214,6 +214,9 @@ _mesa_propagate_uniforms_to_driver_storage(struct gl_uniform_storage *uni,
 extern void
 _mesa_update_shader_textures_used(struct gl_program *prog);
 
+extern bool
+_mesa_sampler_uniforms_are_valid(const struct gl_shader_program *shProg,
+                                char *errMsg, size_t errMsgLength);
 
 extern void
 _mesa_init_shader_uniform_dispatch(struct _glapi_table *exec);