diff options
Diffstat (limited to 'src/glsl')
-rw-r--r-- | src/glsl/ast.h | 1 | ||||
-rw-r--r-- | src/glsl/ast_to_hir.cpp | 79 | ||||
-rw-r--r-- | src/glsl/glsl_parser.yy | 4 | ||||
-rw-r--r-- | src/glsl/link_interface_blocks.cpp | 30 |
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: |