glsl: Fix handling of function calls inside nested loops.
[mesa.git] / src / glsl / link_functions.cpp
index c5398f5ff0416198361ccc5bdf60ffdaee691880..68aa6203289ea13c0b7e64ec7e66558e5165fa25 100644 (file)
@@ -34,6 +34,8 @@ find_matching_signature(const char *name, const exec_list *actual_parameters,
                        gl_shader **shader_list, unsigned num_shaders,
                        bool use_builtin);
 
+namespace {
+
 class call_link_visitor : public ir_hierarchical_visitor {
 public:
    call_link_visitor(gl_shader_program *prog, gl_shader *linked,
@@ -113,7 +115,7 @@ public:
       }
 
       ir_function_signature *linked_sig =
-        f->exact_matching_signature(&callee->parameters);
+        f->exact_matching_signature(NULL, &callee->parameters);
       if ((linked_sig == NULL)
          || ((linked_sig != NULL)
              && (linked_sig->is_builtin() != ir->use_builtin))) {
@@ -153,14 +155,17 @@ public:
 
       linked_sig->replace_parameters(&formal_parameters);
 
-      foreach_list_const(node, &sig->body) {
-        const ir_instruction *const original = (ir_instruction *) node;
+      if (sig->is_defined) {
+         foreach_list_const(node, &sig->body) {
+            const ir_instruction *const original = (ir_instruction *) node;
 
-        ir_instruction *copy = original->clone(linked, ht);
-        linked_sig->body.push_tail(copy);
+            ir_instruction *copy = original->clone(linked, ht);
+            linked_sig->body.push_tail(copy);
+         }
+
+         linked_sig->is_defined = true;
       }
 
-      linked_sig->is_defined = true;
       hash_table_dtor(ht);
 
       /* Patch references inside the function to things outside the function
@@ -221,18 +226,31 @@ public:
            var = ir->var->clone(linked, NULL);
            linked->symbols->add_variable(var);
            linked->ir->push_head(var);
-        } else if (var->type->is_array()) {
-           /* It is possible to have a global array declared in multiple
-            * shaders without a size.  The array is implicitly sized by the
-            * maximal access to it in *any* shader.  Because of this, we
-            * need to track the maximal access to the array as linking pulls
-            * more functions in that access the array.
-            */
-           var->max_array_access =
-              MAX2(var->max_array_access, ir->var->max_array_access);
-
-           if (var->type->length == 0 && ir->var->type->length != 0)
-              var->type = ir->var->type;
+        } else {
+            if (var->type->is_array()) {
+               /* It is possible to have a global array declared in multiple
+                * shaders without a size.  The array is implicitly sized by
+                * the maximal access to it in *any* shader.  Because of this,
+                * we need to track the maximal access to the array as linking
+                * pulls more functions in that access the array.
+                */
+               var->max_array_access =
+                  MAX2(var->max_array_access, ir->var->max_array_access);
+
+               if (var->type->length == 0 && ir->var->type->length != 0)
+                  var->type = ir->var->type;
+            }
+            if (var->is_interface_instance()) {
+               /* Similarly, we need implicit sizes of arrays within interface
+                * blocks to be sized by the maximal access in *any* shader.
+                */
+               for (unsigned i = 0; i < var->get_interface_type()->length;
+                    i++) {
+                  var->max_ifc_array_access[i] =
+                     MAX2(var->max_ifc_array_access[i],
+                          ir->var->max_ifc_array_access[i]);
+               }
+            }
         }
 
         ir->var = var;
@@ -273,6 +291,7 @@ private:
    hash_table *locals;
 };
 
+} /* anonymous namespace */
 
 /**
  * Searches a list of shaders for a particular function definition
@@ -288,9 +307,11 @@ find_matching_signature(const char *name, const exec_list *actual_parameters,
       if (f == NULL)
         continue;
 
-      ir_function_signature *sig = f->matching_signature(actual_parameters);
+      ir_function_signature *sig =
+         f->matching_signature(NULL, actual_parameters);
 
-      if ((sig == NULL) || !sig->is_defined)
+      if ((sig == NULL) ||
+          (!sig->is_defined && !sig->is_intrinsic))
         continue;
 
       /* If this function expects to bind to a built-in function and the