summaryrefslogtreecommitdiffstats
path: root/src/glsl
diff options
context:
space:
mode:
Diffstat (limited to 'src/glsl')
-rw-r--r--src/glsl/ast.h1
-rw-r--r--src/glsl/ast_to_hir.cpp79
-rw-r--r--src/glsl/glsl_parser.yy4
-rw-r--r--src/glsl/link_interface_blocks.cpp30
4 files changed, 105 insertions, 9 deletions
diff --git a/src/glsl/ast.h b/src/glsl/ast.h
index adfc7938bff..f8ab0b71b7b 100644
--- a/src/glsl/ast.h
+++ b/src/glsl/ast.h
@@ -726,6 +726,7 @@ public:
struct _mesa_glsl_parse_state *state);
const char *name;
+ ast_type_qualifier *layout;
/* List of ast_declarator_list * */
exec_list declarations;
bool is_declaration;
diff --git a/src/glsl/ast_to_hir.cpp b/src/glsl/ast_to_hir.cpp
index 35a1e134dfa..1091c022703 100644
--- a/src/glsl/ast_to_hir.cpp
+++ b/src/glsl/ast_to_hir.cpp
@@ -6179,7 +6179,8 @@ ast_process_struct_or_iface_block_members(exec_list *instructions,
bool allow_reserved_names,
ir_variable_mode var_mode,
ast_type_qualifier *layout,
- unsigned block_stream)
+ unsigned block_stream,
+ unsigned expl_location)
{
unsigned decl_count = 0;
@@ -6200,6 +6201,9 @@ ast_process_struct_or_iface_block_members(exec_list *instructions,
glsl_struct_field *const fields = ralloc_array(state, glsl_struct_field,
decl_count);
+ bool first_member = true;
+ bool first_member_has_explicit_location;
+
unsigned i = 0;
foreach_list_typed (ast_declarator_list, decl_list, link, declarations) {
const char *type_name;
@@ -6264,6 +6268,27 @@ ast_process_struct_or_iface_block_members(exec_list *instructions,
"to struct or interface block members");
}
+ if (is_interface) {
+ if (!first_member) {
+ if (!layout->flags.q.explicit_location &&
+ ((first_member_has_explicit_location &&
+ !qual->flags.q.explicit_location) ||
+ (!first_member_has_explicit_location &&
+ qual->flags.q.explicit_location))) {
+ _mesa_glsl_error(&loc, state,
+ "when block-level location layout qualifier "
+ "is not supplied either all members must "
+ "have a location layout qualifier or all "
+ "members must not have a location layout "
+ "qualifier");
+ }
+ } else {
+ first_member = false;
+ first_member_has_explicit_location =
+ qual->flags.q.explicit_location;
+ }
+ }
+
if (qual->flags.q.std140 ||
qual->flags.q.std430 ||
qual->flags.q.packed ||
@@ -6338,7 +6363,6 @@ ast_process_struct_or_iface_block_members(exec_list *instructions,
validate_array_dimensions(field_type, state, &loc);
fields[i].type = field_type;
fields[i].name = decl->identifier;
- fields[i].location = -1;
fields[i].interpolation =
interpret_interpolation_qualifier(qual, var_mode, state, &loc);
fields[i].centroid = qual->flags.q.centroid ? 1 : 0;
@@ -6346,6 +6370,22 @@ ast_process_struct_or_iface_block_members(exec_list *instructions,
fields[i].patch = qual->flags.q.patch ? 1 : 0;
fields[i].precision = qual->precision;
+ if (qual->flags.q.explicit_location) {
+ unsigned qual_location;
+ if (process_qualifier_constant(state, &loc, "location",
+ qual->location, &qual_location)) {
+ fields[i].location = VARYING_SLOT_VAR0 + qual_location;
+ expl_location = fields[i].location + 1;
+ }
+ } else {
+ if (layout && layout->flags.q.explicit_location) {
+ fields[i].location = expl_location;
+ expl_location = expl_location + 1;
+ } else {
+ fields[i].location = -1;
+ }
+ }
+
/* Propogate row- / column-major information down the fields of the
* structure or interface block. Structures need this data because
* the structure may contain a structure that contains ... a matrix
@@ -6444,6 +6484,16 @@ ast_struct_specifier::hir(exec_list *instructions,
state->struct_specifier_depth++;
+ unsigned expl_location = -1;
+ if (layout && layout->flags.q.explicit_location) {
+ if (!process_qualifier_constant(state, &loc, "location",
+ layout->location, &expl_location)) {
+ return NULL;
+ } else {
+ expl_location = VARYING_SLOT_VAR0 + expl_location;
+ }
+ }
+
glsl_struct_field *fields;
unsigned decl_count =
ast_process_struct_or_iface_block_members(instructions,
@@ -6454,8 +6504,9 @@ ast_struct_specifier::hir(exec_list *instructions,
GLSL_MATRIX_LAYOUT_INHERITED,
false /* allow_reserved_names */,
ir_var_auto,
- NULL,
- 0 /* for interface only */);
+ layout,
+ 0, /* for interface only */
+ expl_location);
validate_identifier(this->name, loc, state);
@@ -6620,6 +6671,16 @@ ast_interface_block::hir(exec_list *instructions,
return NULL;
}
+ unsigned expl_location = -1;
+ if (layout.flags.q.explicit_location) {
+ if (!process_qualifier_constant(state, &loc, "location",
+ layout.location, &expl_location)) {
+ return NULL;
+ } else {
+ expl_location = VARYING_SLOT_VAR0 + expl_location;
+ }
+ }
+
unsigned int num_variables =
ast_process_struct_or_iface_block_members(&declared_variables,
state,
@@ -6630,7 +6691,8 @@ ast_interface_block::hir(exec_list *instructions,
redeclaring_per_vertex,
var_mode,
&this->layout,
- qual_stream);
+ qual_stream,
+ expl_location);
state->struct_specifier_depth--;
@@ -6969,6 +7031,10 @@ ast_interface_block::hir(exec_list *instructions,
}
var->data.stream = qual_stream;
+ if (layout.flags.q.explicit_location) {
+ var->data.location = expl_location;
+ var->data.explicit_location = true;
+ }
state->symbols->add_variable(var);
instructions->push_tail(var);
@@ -6989,6 +7055,9 @@ ast_interface_block::hir(exec_list *instructions,
var->data.sample = fields[i].sample;
var->data.patch = fields[i].patch;
var->data.stream = qual_stream;
+ var->data.location = fields[i].location;
+ if (fields[i].location != -1)
+ var->data.explicit_location = true;
var->init_interface_type(block_type);
if (var_mode == ir_var_shader_in || var_mode == ir_var_uniform)
diff --git a/src/glsl/glsl_parser.yy b/src/glsl/glsl_parser.yy
index 7eb383ac60c..51796a65df9 100644
--- a/src/glsl/glsl_parser.yy
+++ b/src/glsl/glsl_parser.yy
@@ -1130,6 +1130,10 @@ fully_specified_type:
$$->set_location_range(@1, @2);
$$->qualifier = $1;
$$->specifier = $2;
+ if ($$->specifier->structure != NULL &&
+ $$->specifier->structure->is_declaration) {
+ $$->specifier->structure->layout = &$$->qualifier;
+ }
}
;
diff --git a/src/glsl/link_interface_blocks.cpp b/src/glsl/link_interface_blocks.cpp
index 61ba0785d63..64c30fea9a3 100644
--- a/src/glsl/link_interface_blocks.cpp
+++ b/src/glsl/link_interface_blocks.cpp
@@ -166,9 +166,19 @@ public:
*/
ir_variable *lookup(ir_variable *var)
{
- const struct hash_entry *entry =
- _mesa_hash_table_search(ht, var->get_interface_type()->name);
- return entry ? (ir_variable *) entry->data : NULL;
+ if (var->data.explicit_location &&
+ var->data.location >= VARYING_SLOT_VAR0) {
+ char location_str[11];
+ snprintf(location_str, 11, "%d", var->data.location);
+
+ const struct hash_entry *entry =
+ _mesa_hash_table_search(ht, location_str);
+ return entry ? (ir_variable *) entry->data : NULL;
+ } else {
+ const struct hash_entry *entry =
+ _mesa_hash_table_search(ht, var->get_interface_type()->name);
+ return entry ? (ir_variable *) entry->data : NULL;
+ }
}
/**
@@ -176,7 +186,19 @@ public:
*/
void store(ir_variable *var)
{
- _mesa_hash_table_insert(ht, var->get_interface_type()->name, var);
+ if (var->data.explicit_location &&
+ var->data.location >= VARYING_SLOT_VAR0) {
+ /* If explicit location is given then lookup the variable by location.
+ * We turn the location into a string and use this as the hash key
+ * rather than the name. Note: We allocate enough space for a 32-bit
+ * unsigned location value which is overkill but future proof.
+ */
+ char location_str[11];
+ snprintf(location_str, 11, "%d", var->data.location);
+ _mesa_hash_table_insert(ht, ralloc_strdup(mem_ctx, location_str), var);
+ } else {
+ _mesa_hash_table_insert(ht, var->get_interface_type()->name, var);
+ }
}
private: