summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/glsl/ast_to_hir.cpp47
-rw-r--r--src/glsl/ir.cpp1
-rw-r--r--src/glsl/ir.h9
-rw-r--r--src/glsl/ir_clone.cpp3
4 files changed, 60 insertions, 0 deletions
diff --git a/src/glsl/ast_to_hir.cpp b/src/glsl/ast_to_hir.cpp
index fb25dc166a3..47fe7a32c3c 100644
--- a/src/glsl/ast_to_hir.cpp
+++ b/src/glsl/ast_to_hir.cpp
@@ -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;
}
diff --git a/src/glsl/ir.cpp b/src/glsl/ir.cpp
index 5e2109ecc6e..fd1c5d90718 100644
--- a/src/glsl/ir.cpp
+++ b/src/glsl/ir.cpp
@@ -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;
diff --git a/src/glsl/ir.h b/src/glsl/ir.h
index fa246b5e570..3503bc9c897 100644
--- a/src/glsl/ir.h
+++ b/src/glsl/ir.h
@@ -289,6 +289,15 @@ public:
/*@}*/
/**
+ * 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
*
* The precise meaning of this field depends on the nature of the variable.
diff --git a/src/glsl/ir_clone.cpp b/src/glsl/ir_clone.cpp
index 18543a35aa1..a3cc8dbc970 100644
--- a/src/glsl/ir_clone.cpp
+++ b/src/glsl/ir_clone.cpp
@@ -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);