glsl: Handle the binding qualifier for arrays of samplers.
authorKenneth Graunke <kenneth@whitecape.org>
Wed, 17 Jul 2013 18:24:11 +0000 (11:24 -0700)
committerKenneth Graunke <kenneth@whitecape.org>
Thu, 18 Jul 2013 23:57:24 +0000 (16:57 -0700)
Normally, uniform array variables are initialized by array literals.
That is, val->type->array_elements >= storage->array_elements.

However, samplers are different.  Consider a declaration such as:

   layout(binding = 5) uniform sampler2D[3];

The initializer value is a single integer (5), while the storage has 3
array elements.  The proper behavior here is to increment one for each
element; they should be initialized to 5, 6, and 7.

This patch introduces new code for sampler types which handles both
arrays of samplers and single samplers correctly.

v2: Move into the other function; use binding, not constant_value.

Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Acked-by: Paul Berry <stereotype441@gmail.com>
src/glsl/link_uniform_initializers.cpp

index 4efa1b44ae9e2871a434975bfdb7d0c1b5eea584..1b7609a4725b3a22433e1b98e812e13ce60b0631 100644 (file)
@@ -93,6 +93,31 @@ set_uniform_binding(void *mem_ctx, gl_shader_program *prog,
       return;
    }
 
+   if (storage->type->is_sampler()) {
+      unsigned elements = MAX2(storage->array_elements, 1);
+
+      /* From section 4.4.4 of the GLSL 4.20 specification:
+       * "If the binding identifier is used with an array, the first element
+       *  of the array takes the specified unit and each subsequent element
+       *  takes the next consecutive unit."
+       */
+      for (unsigned int i = 0; i < elements; i++) {
+         storage->storage[i].i = binding + i;
+      }
+
+      for (int sh = 0; sh < MESA_SHADER_TYPES; sh++) {
+         gl_shader *shader = prog->_LinkedShaders[sh];
+
+         if (shader && storage->sampler[sh].active) {
+            for (unsigned i = 0; i < elements; i++) {
+               unsigned index = storage->sampler[sh].index + i;
+
+               shader->SamplerUnits[index] = storage->storage[i].i;
+            }
+         }
+      }
+   }
+
    storage->initialized = true;
 }