X-Git-Url: http://git.tdb.fi/?p=libs%2Fgl.git;a=blobdiff_plain;f=source%2Fglsl%2Freflect.cpp;h=643c42e79be90f51f07009df7343ce67df80f09e;hp=688c99bf81b951ae288a23c9d5409e94fd7903c8;hb=HEAD;hpb=42903b905cd3924ecc45d3cb08222bc3548cab91 diff --git a/source/glsl/reflect.cpp b/source/glsl/reflect.cpp index 688c99bf..becc833e 100644 --- a/source/glsl/reflect.cpp +++ b/source/glsl/reflect.cpp @@ -1,3 +1,5 @@ +#include +#include #include "reflect.h" using namespace std; @@ -6,9 +8,248 @@ namespace Msp { namespace GL { namespace SL { -LocationCounter::LocationCounter(): - r_count(0) -{ } +bool is_scalar(const BasicTypeDeclaration &type) +{ + return (type.kind==BasicTypeDeclaration::INT || type.kind==BasicTypeDeclaration::FLOAT); +} + +bool is_vector_or_matrix(const BasicTypeDeclaration &type) +{ + return (type.kind==BasicTypeDeclaration::VECTOR || type.kind==BasicTypeDeclaration::MATRIX); +} + +BasicTypeDeclaration *get_element_type(BasicTypeDeclaration &type) +{ + if(is_vector_or_matrix(type) || type.kind==BasicTypeDeclaration::ARRAY) + { + BasicTypeDeclaration *basic_base = dynamic_cast(type.base_type); + return (basic_base ? get_element_type(*basic_base) : 0); + } + else + return &type; +} + +bool can_convert(const BasicTypeDeclaration &from, const BasicTypeDeclaration &to) +{ + if(from.kind==BasicTypeDeclaration::INT && to.kind==BasicTypeDeclaration::FLOAT) + return from.size<=to.size; + else if(from.kind!=to.kind) + return false; + else if(from.kind==BasicTypeDeclaration::INT && from.sign!=to.sign) + return from.sign && from.size<=to.size; + else if(is_vector_or_matrix(from) && from.size==to.size) + { + BasicTypeDeclaration *from_base = dynamic_cast(from.base_type); + BasicTypeDeclaration *to_base = dynamic_cast(to.base_type); + return (from_base && to_base && can_convert(*from_base, *to_base)); + } + else + return false; +} + + +unsigned TypeComparer::next_tag = 1; + +void TypeComparer::compare(Node &node1, Node &node2) +{ + if(&node1==&node2) + r_result = true; + else + { + second = &node2; + node1.visit(*this); + } +} + +template +T *TypeComparer::multi_visit(T &node) +{ + static unsigned tag = next_tag++; + + if(second) + { + Node *s = second; + first = &node; + first_tag = tag; + second = 0; + s->visit(*this); + } + else if(!first || tag!=first_tag) + r_result = false; + else + { + T *f = static_cast(first); + first = 0; + return f; + } + + return 0; +} + +void TypeComparer::visit(Literal &literal) +{ + if(Literal *lit1 = multi_visit(literal)) + { + if(!lit1->type || !literal.type) + r_result = false; + else + { + compare(*lit1->type, *literal.type); + if(r_result) + r_result = (literal.value.check_type() && lit1->value.value()==literal.value.value()); + } + } +} + +void TypeComparer::visit(VariableReference &var) +{ + if(VariableReference *var1 = multi_visit(var)) + { + if(!var1->declaration || !var.declaration) + r_result = false; + else if(!var1->declaration->constant || !var.declaration->constant) + r_result = false; + else if(!var1->declaration->init_expression || !var.declaration->init_expression) + r_result = false; + else + compare(*var1->declaration->init_expression, *var.declaration->init_expression); + } +} + +void TypeComparer::visit(UnaryExpression &unary) +{ + if(UnaryExpression *unary1 = multi_visit(unary)) + { + if(unary1->oper!=unary.oper) + r_result = false; + else + compare(*unary1->expression, *unary.expression); + } +} + +void TypeComparer::visit(BinaryExpression &binary) +{ + if(BinaryExpression *binary1 = multi_visit(binary)) + { + if(binary1->oper!=binary.oper) + r_result = false; + else + { + compare(*binary1->left, *binary.left); + if(r_result) + compare(*binary1->right, *binary.right); + } + } +} + +void TypeComparer::visit(TernaryExpression &ternary) +{ + if(TernaryExpression *ternary1 = multi_visit(ternary)) + { + if(ternary1->oper!=ternary.oper) + r_result = false; + else + { + compare(*ternary1->condition, *ternary.condition); + if(r_result) + compare(*ternary1->true_expr, *ternary.true_expr); + if(r_result) + compare(*ternary1->false_expr, *ternary.false_expr); + } + } +} + +void TypeComparer::visit(FunctionCall &call) +{ + if(FunctionCall *call1 = multi_visit(call)) + { + if(!call1->constructor || !call.constructor) + r_result = false; + else if(call1->name!=call.name) + r_result = false; + else if(call1->arguments.size()!=call.arguments.size()) + r_result = false; + else + { + r_result = true; + for(unsigned i=0; (r_result && iarguments[i], *call.arguments[i]); + } + } +} + +void TypeComparer::visit(BasicTypeDeclaration &basic) +{ + if(BasicTypeDeclaration *basic1 = multi_visit(basic)) + { + if(basic1->kind!=basic.kind || basic1->size!=basic.size || basic1->sign!=basic.sign) + r_result = false; + else if(basic1->base_type && basic.base_type) + compare(*basic1->base_type, *basic.base_type); + else + r_result = (!basic1->base_type && !basic.base_type); + } +} + +void TypeComparer::visit(ImageTypeDeclaration &image) +{ + if(ImageTypeDeclaration *image1 = multi_visit(image)) + { + if(image1->dimensions!=image.dimensions || image1->array!=image.array) + r_result = false; + else if(image1->sampled!=image.sampled || image1->shadow!=image.shadow || image1->multisample!=image.multisample) + r_result = false; + else if(image1->format!=image.format) + r_result = false; + else if(image1->base_type && image.base_type) + compare(*image1->base_type, *image.base_type); + else + r_result = (!image1->base_type && !image.base_type); + } +} + +void TypeComparer::visit(StructDeclaration &strct) +{ + if(StructDeclaration *strct1 = multi_visit(strct)) + { + if(strct1->members.body.size()!=strct.members.body.size()) + r_result = false; + else + { + r_result = true; + auto i = strct1->members.body.begin(); + auto j = strct.members.body.begin(); + for(; (r_result && i!=strct1->members.body.end()); ++i, ++j) + compare(**i, **j); + } + } +} + +void TypeComparer::visit(VariableDeclaration &var) +{ + if(VariableDeclaration *var1 = multi_visit(var)) + { + if(var1->name!=var.name || var1->array!=var.array) + r_result = false; + else if(!var1->type_declaration || !var.type_declaration) + r_result = false; + else + { + if(var1->array) + { + r_result = false; + if(var1->array_size && var.array_size) + compare(*var1->array_size, *var.array_size); + else if(!var1->array_size && !var.array_size) + r_result = true; + } + if(r_result && var1->type_declaration!=var.type_declaration) + compare(*var1->type_declaration, *var.type_declaration); + // TODO Compare layout qualifiers for interface block members + } + } +} + void LocationCounter::visit(BasicTypeDeclaration &basic) { @@ -23,10 +264,10 @@ void LocationCounter::visit(ImageTypeDeclaration &) void LocationCounter::visit(StructDeclaration &strct) { unsigned total = 0; - for(NodeList::const_iterator i=strct.members.body.begin(); i!=strct.members.body.end(); ++i) + for(const RefPtr &s: strct.members.body) { r_count = 1; - (*i)->visit(*this); + s->visit(*this); total += r_count; } r_count = total; @@ -44,6 +285,75 @@ void LocationCounter::visit(VariableDeclaration &var) } +void MemoryRequirementsCalculator::visit(BasicTypeDeclaration &basic) +{ + if(basic.kind==BasicTypeDeclaration::BOOL) + { + r_size = 1; + r_alignment = 1; + } + else if(basic.kind==BasicTypeDeclaration::INT || basic.kind==BasicTypeDeclaration::FLOAT) + { + r_size = basic.size/8; + r_alignment = r_size; + } + else if(basic.kind==BasicTypeDeclaration::VECTOR || basic.kind==BasicTypeDeclaration::MATRIX) + { + basic.base_type->visit(*this); + unsigned n_elem = basic.size&0xFFFF; + r_size *= n_elem; + if(basic.kind==BasicTypeDeclaration::VECTOR) + r_alignment *= (n_elem==3 ? 4 : n_elem); + } + else if(basic.kind==BasicTypeDeclaration::ARRAY) + basic.base_type->visit(*this); + + if(basic.extended_alignment) + r_alignment = (r_alignment+15)&~15U; +} + +void MemoryRequirementsCalculator::visit(StructDeclaration &strct) +{ + unsigned total = 0; + unsigned max_align = 1; + for(const RefPtr &s: strct.members.body) + { + r_size = 0; + r_alignment = 1; + r_offset = -1; + s->visit(*this); + if(r_offset>=0) + total = r_offset; + total += r_alignment-1; + total -= total%r_alignment; + total += r_size; + max_align = max(max_align, r_alignment); + } + r_size = total; + r_alignment = max_align; + if(strct.extended_alignment) + r_alignment = (r_alignment+15)&~15U; + r_size += r_alignment-1; + r_size -= r_size%r_alignment; +} + +void MemoryRequirementsCalculator::visit(VariableDeclaration &var) +{ + r_offset = get_layout_value(var.layout.get(), "offset"); + + if(var.type_declaration) + var.type_declaration->visit(*this); + if(var.array) + if(const Literal *literal = dynamic_cast(var.array_size.get())) + if(literal->value.check_type()) + { + unsigned aligned_size = r_size+r_alignment-1; + aligned_size -= aligned_size%r_alignment; + r_size = aligned_size*literal->value.value(); + } +} + + set DependencyCollector::apply(FunctionDeclaration &func) { func.visit(*this); @@ -59,19 +369,14 @@ void DependencyCollector::visit(VariableReference &var) } } -void DependencyCollector::visit(InterfaceBlockReference &iface) -{ - if(iface.declaration) - { - dependencies.insert(iface.declaration); - iface.declaration->visit(*this); - } -} - void DependencyCollector::visit(FunctionCall &call) { if(call.declaration) + { dependencies.insert(call.declaration); + if(call.declaration->definition) + call.declaration->definition->visit(*this); + } TraversingVisitor::visit(call); } @@ -87,6 +392,50 @@ void DependencyCollector::visit(VariableDeclaration &var) TraversingVisitor::visit(var); } +void DependencyCollector::visit(FunctionDeclaration &func) +{ + if(!visited_functions.count(&func)) + { + visited_functions.insert(&func); + TraversingVisitor::visit(func); + } +} + + +set AssignmentCollector::apply(Node &node) +{ + node.visit(*this); + return assigned_variables; +} + +void AssignmentCollector::visit(VariableReference &var) +{ + if(assignment_target) + assigned_variables.insert(var.declaration); +} + +void AssignmentCollector::visit(UnaryExpression &unary) +{ + SetFlag set_assignment(assignment_target, (unary.oper->token[1]=='+' || unary.oper->token[1]=='-')); + TraversingVisitor::visit(unary); +} + +void AssignmentCollector::visit(BinaryExpression &binary) +{ + binary.left->visit(*this); + SetFlag clear_assignment(assignment_target, false); + binary.right->visit(*this); +} + +void AssignmentCollector::visit(Assignment &assign) +{ + { + SetFlag set_assignment(assignment_target); + assign.left->visit(*this); + } + assign.right->visit(*this); +} + } // namespace SL } // namespace GL } // namespace Msp