X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=source%2Fglsl%2Fvalidate.cpp;h=0096ff5e5106f5a0547b24472a2a3397968e5cad;hb=20a86c5905e1f7527d3c9edc3f56f6b7679c268a;hp=154189aa2bc8c353398b9b92a6a521c47c5afe59;hpb=f2ad2730858046b08e8147297fa01bf3499b86a3;p=libs%2Fgl.git diff --git a/source/glsl/validate.cpp b/source/glsl/validate.cpp index 154189aa..0096ff5e 100644 --- a/source/glsl/validate.cpp +++ b/source/glsl/validate.cpp @@ -609,6 +609,139 @@ void ExpressionValidator::visit(Return &ret) TraversingVisitor::visit(ret); } + +int StageInterfaceValidator::get_location(const Layout &layout) +{ + for(vector::const_iterator i=layout.qualifiers.begin(); i!=layout.qualifiers.end(); ++i) + if(i->name=="location") + return i->value; + return -1; +} + +void StageInterfaceValidator::visit(VariableDeclaration &var) +{ + int location = (var.layout ? get_location(*var.layout) : -1); + if(var.interface=="in" && var.linked_declaration) + { + const Layout *linked_layout = var.linked_declaration->layout.get(); + int linked_location = (linked_layout ? get_location(*linked_layout) : -1); + if(linked_location!=location) + { + error(var, format("Mismatched location %d for 'in %s'", location, var.name)); + add_info(*var.linked_declaration, format("Linked to 'out %s' with location %d", + var.linked_declaration->name, linked_location)); + } + if(var.type_declaration && var.linked_declaration->type_declaration) + { + const TypeDeclaration *type = var.type_declaration; + if(stage->type==Stage::GEOMETRY) + { + if(const BasicTypeDeclaration *basic = dynamic_cast(type)) + if(basic->kind==BasicTypeDeclaration::ARRAY && basic->base_type) + type = basic->base_type; + } + if(!is_same_type(*type, *var.linked_declaration->type_declaration)) + { + error(var, format("Mismatched type '%s' for 'in %s'", type->name, var.name)); + add_info(*var.linked_declaration, format("Linked to 'out %s' with type '%s'", + var.linked_declaration->name, var.linked_declaration->type_declaration->name)); + } + } + } + + if(location>=0 && !var.interface.empty()) + { + map &used = used_locations[var.interface]; + + unsigned loc_count = 1; + if(var.array) + if(const Literal *literal = dynamic_cast(var.array_size.get())) + if(literal->value.check_type()) + loc_count = literal->value.value(); + + for(unsigned i=0; i::const_iterator j = used.find(location+i); + if(j!=used.end()) + { + error(var, format("Overlapping location %d for '%s %s'", location+i, var.interface, var.name)); + add_info(*j->second, format("Previously used here for '%s %s'", j->second->interface, j->second->name)); + } + else + used[location+i] = &var; + } + } +} + + +void GlobalInterfaceValidator::apply(Module &module) +{ + for(list::iterator i=module.stages.begin(); i!=module.stages.end(); ++i) + { + stage = &*i; + i->content.visit(*this); + } +} + +void GlobalInterfaceValidator::get_binding(const Layout &layout, unsigned &desc_set, int &binding) +{ + for(vector::const_iterator i=layout.qualifiers.begin(); i!=layout.qualifiers.end(); ++i) + { + if(i->name=="set") + desc_set = i->value; + else if(i->name=="binding") + binding = i->value; + } +} + +void GlobalInterfaceValidator::check_binding(const Layout &layout, const Binding &binding) +{ + unsigned desc_set = 0; + int bind_point = -1; + get_binding(layout, desc_set, bind_point); + if(bind_point<0) + return; + + map &used = used_bindings[desc_set]; + map::const_iterator i = used.find(bind_point); + if(i!=used.end()) + { + if(i->second.name!=binding.name) + { + error(*binding.node, format("Overlapping binding %d for '%s'", bind_point, binding.name)); + add_info(*i->second.node, format("Previously used here for '%s'", i->second.name)); + } + if(i->second.type && binding.type) + { + if(!is_same_type(*i->second.type, *binding.type)) + { + string type_name = (dynamic_cast(binding.type) ? "struct type" : + format("type '%s'", binding.type->name)); + error(*binding.node, format("Mismatched %s for binding %d '%s'", type_name, bind_point, binding.name)); + + string message = "Previously used here"; + if(!dynamic_cast(i->second.type)) + message += format(" with type '%s'", i->second.type->name); + add_info(*i->second.node, message); + } + } + } + else + used.insert(make_pair(bind_point, binding)); +} + +void GlobalInterfaceValidator::visit(VariableDeclaration &var) +{ + if(var.interface=="uniform" && var.layout) + check_binding(*var.layout, var); +} + +void GlobalInterfaceValidator::visit(InterfaceBlock &iface) +{ + if(iface.interface=="uniform" && iface.layout) + check_binding(*iface.layout, iface); +} + } // namespace SL } // namespace GL } // namespace Msp