glsl: Add linker support for explicit attribute locations
[mesa.git] / src / glsl / linker.cpp
index bddf8788b47a3f01d03f91040ca43511d5a10dd2..c612fe546637f02b460a0872a80e5ccbff298897 100644 (file)
@@ -191,7 +191,7 @@ invalidate_variable_locations(gl_shader *sh, enum ir_variable_mode mode,
 
       /* Only assign locations for generic attributes / varyings / etc.
        */
-      if (var->location >= generic_base)
+      if ((var->location >= generic_base) && !var->explicit_location)
          var->location = -1;
    }
 }
@@ -365,6 +365,19 @@ cross_validate_globals(struct gl_shader_program *prog,
               }
            }
 
+           if (var->explicit_location) {
+              if (existing->explicit_location
+                  && (var->location != existing->location)) {
+                    linker_error_printf(prog, "explicit locations for %s "
+                                        "`%s' have differing values\n",
+                                        mode_string(var), var->name);
+                    return false;
+              }
+
+              existing->location = var->location;
+              existing->explicit_location = true;
+           }
+
            /* FINISHME: Handle non-constant initializers.
             */
            if (var->constant_value != NULL) {
@@ -1186,6 +1199,24 @@ assign_attribute_locations(gl_shader_program *prog, unsigned max_attribute_index
       if ((var == NULL) || (var->mode != ir_var_in))
         continue;
 
+      if (var->explicit_location) {
+        const unsigned slots = count_attribute_slots(var->type);
+        const unsigned use_mask = (1 << slots) - 1;
+        const int attr = var->location - VERT_ATTRIB_GENERIC0;
+
+        if ((var->location >= (int)(max_attribute_index + VERT_ATTRIB_GENERIC0))
+            || (var->location < 0)) {
+           linker_error_printf(prog,
+                               "invalid explicit location %d specified for "
+                               "`%s'\n",
+                               (var->location < 0) ? var->location : attr,
+                               var->name);
+           return false;
+        } else if (var->location >= VERT_ATTRIB_GENERIC0) {
+           used_locations |= (use_mask << attr);
+        }
+      }
+
       /* The location was explicitly assigned, nothing to do here.
        */
       if (var->location != -1)