diff options
-rw-r--r-- | src/glsl/ast_to_hir.cpp | 47 | ||||
-rw-r--r-- | src/glsl/ir.cpp | 1 | ||||
-rw-r--r-- | src/glsl/ir.h | 9 | ||||
-rw-r--r-- | src/glsl/ir_clone.cpp | 3 |
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); |