X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=source%2Fglsl%2Fvalidate.cpp;h=4a5ffe841801b064c04c7ea68d6d91eb53ea1c59;hb=c701c8787cb19fbb6dc5b0bfae1a94e2b07dd549;hp=0096ff5e5106f5a0547b24472a2a3397968e5cad;hpb=20a86c5905e1f7527d3c9edc3f56f6b7679c268a;p=libs%2Fgl.git diff --git a/source/glsl/validate.cpp b/source/glsl/validate.cpp index 0096ff5e..4a5ffe84 100644 --- a/source/glsl/validate.cpp +++ b/source/glsl/validate.cpp @@ -3,6 +3,7 @@ #include #include #include +#include "reflect.h" #include "validate.h" using namespace std; @@ -69,16 +70,26 @@ void DeclarationValidator::visit(Layout &layout) allowed = (variable && scope==GLOBAL); else if(i->name=="binding" || i->name=="set") { + if(i->name=="set") + { + error(layout, "Layout qualifier 'set' not allowed when targeting OpenGL"); + continue; + } + if(variable) { TypeDeclaration *type = variable->type_declaration; while(BasicTypeDeclaration *basic = dynamic_cast(type)) type = basic->base_type; - allowed = (scope==GLOBAL && dynamic_cast(type)); - err_descr = "variable of non-opaque type"; + bool uniform = (variable->interface=="uniform"); + allowed = (scope==GLOBAL && uniform && dynamic_cast(type)); + err_descr = (uniform ? "variable of non-opaque type" : "non-uniform variable"); } else if(iface_block) - allowed = true; + { + allowed = (iface_block->interface=="uniform"); + err_descr = "non-uniform interface block"; + } } else if(i->name=="constant_id") { @@ -103,7 +114,9 @@ void DeclarationValidator::visit(Layout &layout) } } else if(i->name=="offset") - allowed = (variable && scope==INTERFACE_BLOCK); + allowed = (variable && scope==INTERFACE_BLOCK && iface_block->interface=="uniform"); + else if(i->name=="align") + allowed = (scope==INTERFACE_BLOCK && iface_block->interface=="uniform"); else if(i->name=="points") { allowed = (stage->type==Stage::GEOMETRY && iface_layout && (iface_layout->interface=="in" || iface_layout->interface=="out")); @@ -128,6 +141,18 @@ void DeclarationValidator::visit(Layout &layout) allowed = (iface_block && !variable && iface_block->interface=="uniform"); value = false; } + else if(i->name=="column_major" || i->name=="row_major") + { + allowed = (variable && scope==INTERFACE_BLOCK); + if(allowed) + { + BasicTypeDeclaration *basic = dynamic_cast(variable->type_declaration); + while(basic && basic->kind==BasicTypeDeclaration::ARRAY) + basic = dynamic_cast(basic->base_type); + allowed = (basic && basic->kind==BasicTypeDeclaration::MATRIX); + err_descr = "non-matrix variable"; + } + } if(!allowed) { @@ -203,6 +228,8 @@ void DeclarationValidator::visit(VariableDeclaration &var) { if(scope==STRUCT || scope==INTERFACE_BLOCK) error(var, format("Constant qualifier not allowed on %s", descr)); + if(!var.init_expression) + error(var, "Constant variable must have an initializer"); } if(!var.interpolation.empty() || !var.sampling.empty()) @@ -224,8 +251,12 @@ void DeclarationValidator::visit(VariableDeclaration &var) } TypeDeclaration *type = var.type_declaration; + BasicTypeDeclaration::Kind kind = BasicTypeDeclaration::ALIAS; while(BasicTypeDeclaration *basic = dynamic_cast(type)) + { + kind = basic->kind; type = basic->base_type; + } if(dynamic_cast(type)) { if(scope!=GLOBAL && scope!=FUNCTION_PARAM) @@ -233,6 +264,10 @@ void DeclarationValidator::visit(VariableDeclaration &var) else if(scope==GLOBAL && var.interface!="uniform") error(var, format("Type '%s' only allowed with uniform interface", type->name)); } + else if(kind==BasicTypeDeclaration::VOID) + error(var, "Type 'void' not allowed on variable"); + else if(kind==BasicTypeDeclaration::BOOL && !var.interface.empty() && var.source!=BUILTIN_SOURCE) + error(var, "Type 'bool' not allowed on interface variable"); if(var.init_expression) { @@ -326,7 +361,7 @@ void IdentifierValidator::visit(VariableDeclaration &var) void IdentifierValidator::visit(InterfaceBlock &iface) { - string key = iface.interface+iface.block_name; + string key = format("%s %s", iface.interface, iface.block_name); map::const_iterator i = interface_blocks.find(key); if(i!=interface_blocks.end()) multiple_definition(format("interface block '%s %s'", iface.interface, iface.block_name), iface, *i->second); @@ -590,6 +625,28 @@ void ExpressionValidator::visit(FunctionDeclaration &func) TraversingVisitor::visit(func); } +void ExpressionValidator::visit(Conditional &cond) +{ + if(cond.condition->type) + { + BasicTypeDeclaration *basic_cond = dynamic_cast(cond.condition->type); + if(!basic_cond || basic_cond->kind!=BasicTypeDeclaration::BOOL) + error(cond, "Condition is not a boolean"); + } + TraversingVisitor::visit(cond); +} + +void ExpressionValidator::visit(Iteration &iter) +{ + if(iter.condition->type) + { + BasicTypeDeclaration *basic_cond = dynamic_cast(iter.condition->type); + if(!basic_cond || basic_cond->kind!=BasicTypeDeclaration::BOOL) + error(iter, "Loop condition is not a boolean"); + } + TraversingVisitor::visit(iter); +} + void ExpressionValidator::visit(Return &ret) { if(current_function && current_function->return_type_declaration) @@ -633,14 +690,14 @@ void StageInterfaceValidator::visit(VariableDeclaration &var) } if(var.type_declaration && var.linked_declaration->type_declaration) { - const TypeDeclaration *type = var.type_declaration; + 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)) + if(!TypeComparer().apply(*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'", @@ -653,12 +710,7 @@ void StageInterfaceValidator::visit(VariableDeclaration &var) { 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(); - + unsigned loc_count = LocationCounter().apply(var); for(unsigned i=0; i::const_iterator j = used.find(location+i); @@ -683,63 +735,109 @@ void GlobalInterfaceValidator::apply(Module &module) } } -void GlobalInterfaceValidator::get_binding(const Layout &layout, unsigned &desc_set, int &binding) +void GlobalInterfaceValidator::check_uniform(const Uniform &uni) { - for(vector::const_iterator i=layout.qualifiers.begin(); i!=layout.qualifiers.end(); ++i) + map::const_iterator i = used_names.find(uni.name); + if(i!=used_names.end()) { - if(i->name=="set") - desc_set = i->value; - else if(i->name=="binding") - binding = i->value; + if(uni.location>=0 && i->second->location>=0 && i->second->location!=uni.location) + { + error(*uni.node, format("Mismatched location %d for uniform '%s'", uni.location, uni.name)); + add_info(*i->second->node, format("Previously declared here with location %d", i->second->location)); + } + if(uni.bind_point>=0 && i->second->bind_point>=0 && i->second->bind_point!=uni.bind_point) + { + error(*uni.node, format("Mismatched binding %d for uniform '%s'", uni.bind_point, uni.name)); + add_info(*i->second->node, format("Previously declared here with binding %d", i->second->bind_point)); + } + if(uni.type && i->second->type && !TypeComparer().apply(*uni.type, *i->second->type)) + { + string type_name = (dynamic_cast(uni.type) ? + "structure" : format("type '%s'", uni.type->name)); + error(*uni.node, format("Mismatched %s for uniform '%s'", type_name, uni.name)); + + string message = "Previously declared here"; + if(!dynamic_cast(i->second->type)) + message += format(" with type '%s'", i->second->type->name); + add_info(*i->second->node, message); + } } -} - -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; + else + used_names.insert(make_pair(uni.name, &uni)); - map &used = used_bindings[desc_set]; - map::const_iterator i = used.find(bind_point); - if(i!=used.end()) + if(uni.location>=0) { - if(i->second.name!=binding.name) + map::const_iterator j = used_locations.find(uni.location); + if(j!=used_locations.end()) { - 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(j->second->name!=uni.name) + { + error(*uni.node, format("Overlapping location %d for '%s'", uni.location, uni.name)); + add_info(*j->second->node, format("Previously used here for '%s'", j->second->name)); + } } - if(i->second.type && binding.type) + else { - if(!is_same_type(*i->second.type, *binding.type)) + for(unsigned k=0; k=0) + { + map &used = used_bindings[uni.desc_set]; + map::const_iterator j = used.find(uni.bind_point); + if(j!=used.end()) + { + if(j->second->name!=uni.name) { - 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); + error(*uni.node, format("Overlapping binding %d for '%s'", uni.bind_point, uni.name)); + add_info(*j->second->node, format("Previously used here for '%s'", j->second->name)); } } + else + used.insert(make_pair(uni.bind_point, &uni)); } - else - used.insert(make_pair(bind_point, binding)); } void GlobalInterfaceValidator::visit(VariableDeclaration &var) { - if(var.interface=="uniform" && var.layout) - check_binding(*var.layout, var); + if(var.interface=="uniform") + { + Uniform uni; + uni.node = &var; + uni.type = var.type_declaration; + uni.name = var.name; + if(var.layout) + { + uni.location = get_layout_value(*var.layout, "location"); + uni.loc_count = LocationCounter().apply(var); + uni.desc_set = get_layout_value(*var.layout, "set", 0); + uni.bind_point = get_layout_value(*var.layout, "binding"); + } + + uniforms.push_back(uni); + check_uniform(uniforms.back()); + } } void GlobalInterfaceValidator::visit(InterfaceBlock &iface) { - if(iface.interface=="uniform" && iface.layout) - check_binding(*iface.layout, iface); + if(iface.interface=="uniform") + { + Uniform uni; + uni.node = &iface; + uni.type = iface.struct_declaration; + uni.name = iface.block_name; + if(iface.layout) + { + uni.desc_set = get_layout_value(*iface.layout, "set", 0); + uni.bind_point = get_layout_value(*iface.layout, "binding"); + } + + uniforms.push_back(uni); + check_uniform(uniforms.back()); + } } } // namespace SL