glsl: Track explicit location in AST to IR translation
authorIan Romanick <ian.d.romanick@intel.com>
Thu, 7 Oct 2010 22:13:38 +0000 (15:13 -0700)
committerIan Romanick <ian.d.romanick@intel.com>
Fri, 8 Oct 2010 21:21:23 +0000 (14:21 -0700)
src/glsl/ast_to_hir.cpp
src/glsl/ir.cpp
src/glsl/ir.h
src/glsl/ir_clone.cpp

index fb25dc166a3602c60eb7219be62e2940cb86aa4d..47fe7a32c3ca2f4ff0151edf9b0a769b034d351a 100644 (file)
@@ -1627,6 +1627,53 @@ apply_type_qualifier_to_variable(const struct ast_type_qualifier *qual,
                       qual_string);
    }
 
+   if (qual->flags.q.explicit_location) {
+      const bool global_scope = (state->current_function == NULL);
+      bool fail = false;
+      const char *string = "";
+
+      /* In the vertex shader only shader inputs can be given explicit
+       * locations.
+       *
+       * In the fragment shader only shader outputs can be given explicit
+       * locations.
+       */
+      switch (state->target) {
+      case vertex_shader:
+        if (!global_scope || (var->mode != ir_var_in)) {
+           fail = true;
+           string = "input";
+        }
+        break;
+
+      case geometry_shader:
+        _mesa_glsl_error(loc, state,
+                         "geometry shader variables cannot be given "
+                         "explicit locations\n");
+        break;
+
+      case fragment_shader:
+        if (!global_scope || (var->mode != ir_var_in)) {
+           fail = true;
+           string = "output";
+        }
+        break;
+      }
+
+      if (fail) {
+        _mesa_glsl_error(loc, state,
+                         "only %s shader %s variables can be given an "
+                         "explicit location\n",
+                         _mesa_glsl_shader_target_name(state->target),
+                         string);
+      } else {
+        var->explicit_location = true;
+        var->location = (state->target == vertex_shader)
+           ? (qual->location + VERT_ATTRIB_GENERIC0)
+           : (qual->location + FRAG_RESULT_DATA0);
+      }
+   }
+
    if (var->type->is_array() && state->language_version != 110) {
       var->array_lvalue = true;
    }
index 5e2109ecc6e1f0d944563ce256d156185ee0245d..fd1c5d907186942faf5dc8753d34292162450aa3 100644 (file)
@@ -1071,6 +1071,7 @@ ir_variable::ir_variable(const struct glsl_type *type, const char *name,
    this->ir_type = ir_type_variable;
    this->type = type;
    this->name = talloc_strdup(this, name);
+   this->explicit_location = false;
    this->location = -1;
    this->warn_extension = NULL;
    this->constant_value = NULL;
index fa246b5e57073308fa7fd15c19ac5c6f5e75bc09..3503bc9c8971e5d9ccb3af52d46a62cb173d5de2 100644 (file)
@@ -288,6 +288,15 @@ public:
    unsigned pixel_center_integer:1;
    /*@}*/
 
+   /**
+    * Was the location explicitly set in the shader?
+    *
+    * If the location is explicitly set in the shader, it \b cannot be changed
+    * by the linker or by the API (e.g., calls to \c glBindAttribLocation have
+    * no effect).
+    */
+   unsigned explicit_location:1;
+
    /**
     * Storage location of the base of this variable
     *
index 18543a35aa19c93a4bb52e8b1537ec9b8ec437f3..a3cc8dbc9701ba2eb8e8642f8165491d6b9e214b 100644 (file)
@@ -51,6 +51,9 @@ ir_variable::clone(void *mem_ctx, struct hash_table *ht) const
    var->warn_extension = this->warn_extension;
    var->origin_upper_left = this->origin_upper_left;
    var->pixel_center_integer = this->pixel_center_integer;
+   var->explicit_location = this->explicit_location;
+   if (this->explicit_location)
+      var->location = this->location;
 
    if (this->constant_value)
       var->constant_value = this->constant_value->clone(mem_ctx, ht);