X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=source%2Fglsl%2Fgenerate.cpp;h=563609918ae216f28178dca421be4c627175f1b5;hb=d4b8a3f67c1f7184124bf95caee7e36ae8d6c82a;hp=8547152e45df9edb714f06ae8c2c83cccae40350;hpb=cc3f4aaaf8d2b34347f69b026c10f82797059aa4;p=libs%2Fgl.git diff --git a/source/glsl/generate.cpp b/source/glsl/generate.cpp index 8547152e..56360991 100644 --- a/source/glsl/generate.cpp +++ b/source/glsl/generate.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include "builtin.h" #include "generate.h" @@ -11,57 +12,6 @@ namespace Msp { namespace GL { namespace SL { -void DeclarationCombiner::apply(Stage &stage) -{ - stage.content.visit(*this); - NodeRemover().apply(stage, nodes_to_remove); -} - -void DeclarationCombiner::visit(Block &block) -{ - if(current_block) - return; - - TraversingVisitor::visit(block); -} - -void DeclarationCombiner::visit(VariableDeclaration &var) -{ - VariableDeclaration *&ptr = variables[var.name]; - if(ptr) - { - ptr->type = var.type; - if(var.init_expression) - ptr->init_expression = var.init_expression; - if(var.layout) - { - if(ptr->layout) - { - for(vector::iterator i=var.layout->qualifiers.begin(); i!=var.layout->qualifiers.end(); ++i) - { - bool found = false; - for(vector::iterator j=ptr->layout->qualifiers.begin(); (!found && j!=ptr->layout->qualifiers.end()); ++j) - if(j->name==i->name) - { - j->has_value = i->value; - j->value = i->value; - found = true; - } - - if(!found) - ptr->layout->qualifiers.push_back(*i); - } - } - else - ptr->layout = var.layout; - } - nodes_to_remove.insert(&var); - } - else - ptr = &var; -} - - ConstantSpecializer::ConstantSpecializer(): values(0) { } @@ -190,6 +140,9 @@ void TypeResolver::visit(BasicTypeDeclaration &type) if(basic_base->kind==BasicTypeDeclaration::VECTOR) { type.kind = BasicTypeDeclaration::MATRIX; + /* A matrix's base type is its column vector type. This will put + the column vector's size, i.e. the matrix's row count, in the high + half of the size. */ type.size |= basic_base->size<<16; } @@ -266,6 +219,9 @@ bool VariableResolver::apply(Stage &s) s.interface_blocks.clear(); r_any_resolved = false; s.content.visit(*this); + for(vector::const_iterator i=redeclared_builtins.begin(); i!=redeclared_builtins.end(); ++i) + (*i)->source = GENERATED_SOURCE; + NodeRemover().apply(s, nodes_to_remove); return r_any_resolved; } @@ -274,7 +230,7 @@ void VariableResolver::enter(Block &block) block.variables.clear(); } -void VariableResolver::visit_and_replace(RefPtr &expr) +void VariableResolver::visit(RefPtr &expr) { r_replacement_expr = 0; expr->visit(*this); @@ -376,7 +332,7 @@ void VariableResolver::add_to_chain(Assignment::Target::ChainType type, unsigned void VariableResolver::visit(MemberAccess &memacc) { - visit_and_replace(memacc.left); + TraversingVisitor::visit(memacc); VariableDeclaration *declaration = 0; if(StructDeclaration *strct = dynamic_cast(memacc.left->type)) @@ -430,7 +386,7 @@ void VariableResolver::visit(MemberAccess &memacc) void VariableResolver::visit(Swizzle &swizzle) { - visit_and_replace(swizzle.left); + TraversingVisitor::visit(swizzle); if(record_target) { @@ -441,11 +397,6 @@ void VariableResolver::visit(Swizzle &swizzle) } } -void VariableResolver::visit(UnaryExpression &unary) -{ - visit_and_replace(unary.expression); -} - void VariableResolver::visit(BinaryExpression &binary) { if(binary.oper->token[0]=='[') @@ -454,9 +405,9 @@ void VariableResolver::visit(BinaryExpression &binary) /* The subscript expression is not a part of the primary assignment target. */ SetFlag set(record_target, false); - visit_and_replace(binary.right); + visit(binary.right); } - visit_and_replace(binary.left); + visit(binary.left); if(record_target) { @@ -468,10 +419,7 @@ void VariableResolver::visit(BinaryExpression &binary) } } else - { - visit_and_replace(binary.left); - visit_and_replace(binary.right); - } + TraversingVisitor::visit(binary); } void VariableResolver::visit(Assignment &assign) @@ -479,31 +427,61 @@ void VariableResolver::visit(Assignment &assign) { SetFlag set(record_target); r_assignment_target = Assignment::Target(); - visit_and_replace(assign.left); + visit(assign.left); r_any_resolved |= (r_assignment_targettoken[0]!='='); } -void VariableResolver::visit(FunctionCall &call) +void VariableResolver::merge_layouts(Layout &to_layout, const Layout &from_layout) { - for(NodeArray::iterator i=call.arguments.begin(); i!=call.arguments.end(); ++i) - visit_and_replace(*i); + for(vector::const_iterator i=from_layout.qualifiers.begin(); i!=from_layout.qualifiers.end(); ++i) + { + bool found = false; + for(vector::iterator j=to_layout.qualifiers.begin(); (!found && j!=to_layout.qualifiers.end()); ++j) + if(j->name==i->name) + { + j->has_value = i->value; + j->value = i->value; + found = true; + } + + if(!found) + to_layout.qualifiers.push_back(*i); + } } void VariableResolver::visit(VariableDeclaration &var) { - if(var.layout) - var.layout->visit(*this); - if(var.array_size) - visit_and_replace(var.array_size); - if(var.init_expression) - visit_and_replace(var.init_expression); - current_block->variables.insert(make_pair(var.name, &var)); + TraversingVisitor::visit(var); + VariableDeclaration *&ptr = current_block->variables[var.name]; + if(!ptr) + ptr = &var; + else if(!current_block->parent && ptr->interface==var.interface && ptr->type==var.type) + { + if(ptr->source==BUILTIN_SOURCE) + redeclared_builtins.push_back(&var); + else + stage->diagnostics.push_back(Diagnostic(Diagnostic::WARN, var.source, var.line, + format("Redeclaring non-builtin variable '%s' is deprecated", var.name))); + + if(var.init_expression) + ptr->init_expression = var.init_expression; + if(var.layout) + { + if(ptr->layout) + merge_layouts(*ptr->layout, *var.layout); + else + ptr->layout = var.layout; + } + nodes_to_remove.insert(&var); + + r_any_resolved = true; + } } void VariableResolver::visit(InterfaceBlock &iface) @@ -601,19 +579,18 @@ void ExpressionResolver::convert_to(RefPtr &expr, BasicTypeDeclarati RefPtr call = new FunctionCall; call->name = type.name; call->constructor = true; - call->arguments.push_back(0); - call->arguments.back() = expr; + call->arguments.push_back_nocopy(expr); call->type = &type; expr = call; } bool ExpressionResolver::convert_to_element(RefPtr &expr, BasicTypeDeclaration &elem_type) { - if(BasicTypeDeclaration *expr_type = dynamic_cast(expr->type)) + if(BasicTypeDeclaration *expr_basic = dynamic_cast(expr->type)) { BasicTypeDeclaration *to_type = &elem_type; - if(is_vector_or_matrix(*expr_type)) - to_type = find_type(elem_type, expr_type->kind, expr_type->size); + if(is_vector_or_matrix(*expr_basic)) + to_type = find_type(elem_type, expr_basic->kind, expr_basic->size); if(to_type) { convert_to(expr, *to_type); @@ -624,6 +601,30 @@ bool ExpressionResolver::convert_to_element(RefPtr &expr, BasicTypeD return false; } +bool ExpressionResolver::truncate_vector(RefPtr &expr, unsigned size) +{ + if(BasicTypeDeclaration *expr_basic = dynamic_cast(expr->type)) + if(BasicTypeDeclaration *expr_elem = get_element_type(*expr_basic)) + { + RefPtr swizzle = new Swizzle; + swizzle->left = expr; + swizzle->oper = &Operator::get_operator(".", Operator::POSTFIX); + swizzle->component_group = string("xyzw", size); + swizzle->count = size; + for(unsigned i=0; icomponents[i] = i; + if(size==1) + swizzle->type = expr_elem; + else + swizzle->type = find_type(*expr_elem, BasicTypeDeclaration::VECTOR, size); + expr = swizzle; + + return true; + } + + return false; +} + void ExpressionResolver::resolve(Expression &expr, TypeDeclaration *type, bool lvalue) { r_any_resolved |= (type!=expr.type || lvalue!=expr.lvalue); @@ -631,6 +632,16 @@ void ExpressionResolver::resolve(Expression &expr, TypeDeclaration *type, bool l expr.lvalue = lvalue; } +void ExpressionResolver::visit(Block &block) +{ + SetForScope set_block(current_block, &block); + for(NodeList::iterator i=block.body.begin(); i!=block.body.end(); ++i) + { + insert_point = i; + (*i)->visit(*this); + } +} + void ExpressionResolver::visit(Literal &literal) { if(literal.value.check_type()) @@ -641,12 +652,6 @@ void ExpressionResolver::visit(Literal &literal) resolve(literal, find_type(BasicTypeDeclaration::FLOAT, 32), false); } -void ExpressionResolver::visit(ParenthesizedExpression &parexpr) -{ - TraversingVisitor::visit(parexpr); - resolve(parexpr, parexpr.expression->type, parexpr.expression->lvalue); -} - void ExpressionResolver::visit(VariableReference &var) { if(var.declaration) @@ -887,19 +892,256 @@ void ExpressionResolver::visit(Assignment &assign) resolve(assign, assign.left->type, true); } +void ExpressionResolver::visit(TernaryExpression &ternary) +{ + TraversingVisitor::visit(ternary); + + BasicTypeDeclaration *basic_cond = dynamic_cast(ternary.condition->type); + if(!basic_cond || basic_cond->kind!=BasicTypeDeclaration::BOOL) + return; + + TypeDeclaration *type = 0; + if(ternary.true_expr->type==ternary.false_expr->type) + type = ternary.true_expr->type; + else + { + BasicTypeDeclaration *basic_true = dynamic_cast(ternary.true_expr->type); + BasicTypeDeclaration *basic_false = dynamic_cast(ternary.false_expr->type); + if(!basic_true || !basic_false) + return; + + Compatibility compat = get_compatibility(*basic_true, *basic_false); + if(compat==NOT_COMPATIBLE) + return; + + type = (compat==LEFT_CONVERTIBLE ? basic_true : basic_false); + + if(compat==LEFT_CONVERTIBLE) + convert_to(ternary.true_expr, *basic_false); + else if(compat==RIGHT_CONVERTIBLE) + convert_to(ternary.false_expr, *basic_true); + } + + resolve(ternary, type, false); +} + +void ExpressionResolver::visit_constructor(FunctionCall &call) +{ + if(call.arguments.empty()) + return; + + map::const_iterator i = stage->types.find(call.name); + if(i==stage->types.end()) + return; + else if(BasicTypeDeclaration *basic = dynamic_cast(i->second)) + { + BasicTypeDeclaration *elem = get_element_type(*basic); + if(!elem) + return; + + vector args; + args.reserve(call.arguments.size()); + unsigned arg_component_total = 0; + bool has_matrices = false; + for(NodeArray::const_iterator j=call.arguments.begin(); j!=call.arguments.end(); ++j) + { + ArgumentInfo info; + if(!(info.type=dynamic_cast((*j)->type))) + return; + if(is_scalar(*info.type) || info.type->kind==BasicTypeDeclaration::BOOL) + info.component_count = 1; + else if(info.type->kind==BasicTypeDeclaration::VECTOR) + info.component_count = info.type->size; + else if(info.type->kind==BasicTypeDeclaration::MATRIX) + { + info.component_count = (info.type->size>>16)*(info.type->size&0xFFFF); + has_matrices = true; + } + else + return; + arg_component_total += info.component_count; + args.push_back(info); + } + + bool convert_args = false; + if((is_scalar(*basic) || basic->kind==BasicTypeDeclaration::BOOL) && call.arguments.size()==1 && !has_matrices) + { + if(arg_component_total>1) + truncate_vector(call.arguments.front(), 1); + + /* Single-element type constructors never need to convert their + arguments because the constructor *is* the conversion. */ + } + else if(basic->kind==BasicTypeDeclaration::VECTOR && !has_matrices) + { + /* Vector constructors need either a single scalar argument or + enough components to fill out the vector. */ + if(arg_component_total!=1 && arg_component_totalsize) + return; + + /* A vector of same size can be converted directly. For other + combinations the individual arguments need to be converted. */ + if(call.arguments.size()==1) + { + if(arg_component_total==1) + convert_args = true; + else if(arg_component_total>basic->size) + truncate_vector(call.arguments.front(), basic->size); + } + else if(arg_component_total==basic->size) + convert_args = true; + else + return; + } + else if(basic->kind==BasicTypeDeclaration::MATRIX) + { + unsigned column_count = basic->size&0xFFFF; + unsigned row_count = basic->size>>16; + if(call.arguments.size()==1) + { + /* A matrix can be constructed from a single element or another + matrix of sufficient size. */ + if(arg_component_total==1) + convert_args = true; + else if(args.front().type->kind==BasicTypeDeclaration::MATRIX) + { + unsigned arg_columns = args.front().type->size&0xFFFF; + unsigned arg_rows = args.front().type->size>>16; + if(arg_columns temporary = new VariableDeclaration; + temporary->type = args.front().type->name; + temporary->name = get_unused_variable_name(*current_block, "_temp"); + temporary->init_expression = call.arguments.front(); + current_block->body.insert(insert_point, temporary); + + // Create expressions to build each column. + vector > columns; + columns.reserve(column_count); + for(unsigned j=0; j ref = new VariableReference; + ref->name = temporary->name; + + RefPtr index = new Literal; + index->token = lexical_cast(j); + index->value = static_cast(j); + + RefPtr subscript = new BinaryExpression; + subscript->left = ref; + subscript->oper = &Operator::get_operator("[", Operator::BINARY); + subscript->right = index; + subscript->type = args.front().type->base_type; + + columns.push_back(subscript); + if(arg_rows>row_count) + truncate_vector(columns.back(), row_count); + } + + call.arguments.resize(column_count); + copy(columns.begin(), columns.end(), call.arguments.begin()); + + /* Let VariableResolver process the new nodes and finish + resolving the constructor on the next pass. */ + r_any_resolved = true; + return; + } + else + return; + } + else if(arg_component_total==column_count*row_count && !has_matrices) + { + /* Construct a matrix from individual components in column-major + order. Arguments must align at column boundaries. */ + vector > columns; + columns.reserve(column_count); + + vector > column_args; + column_args.reserve(row_count); + unsigned column_component_count = 0; + + for(unsigned j=0; jkind==BasicTypeDeclaration::VECTOR && info.component_count==row_count) + // A vector filling the entire column can be used as is. + columns.push_back(call.arguments[j]); + else + { + column_args.push_back(call.arguments[j]); + column_component_count += info.component_count; + if(column_component_count==row_count) + { + /* The column has filled up. Create a vector constructor + for it.*/ + RefPtr column_call = new FunctionCall; + column_call->name = basic->base_type->name; + column_call->constructor = true; + column_call->arguments.resize(column_args.size()); + copy(column_args.begin(), column_args.end(), column_call->arguments.begin()); + column_call->type = basic->base_type; + visit_constructor(*column_call); + columns.push_back(column_call); + + column_args.clear(); + column_component_count = 0; + } + else if(column_component_count>row_count) + // Argument alignment mismatch. + return; + } + } + } + else + return; + } + else + return; + + if(convert_args) + { + // The argument list may have changed so can't rely on args. + for(NodeArray::iterator j=call.arguments.begin(); j!=call.arguments.end(); ++j) + if(BasicTypeDeclaration *basic_arg = dynamic_cast((*j)->type)) + { + BasicTypeDeclaration *elem_arg = get_element_type(*basic_arg); + if(elem_arg!=elem) + convert_to_element(*j, *elem); + } + } + } + else if(StructDeclaration *strct = dynamic_cast(i->second)) + { + if(call.arguments.size()!=strct->members.body.size()) + return; + + unsigned k = 0; + for(NodeList::const_iterator j=strct->members.body.begin(); j!=strct->members.body.end(); ++j, ++k) + { + if(VariableDeclaration *var = dynamic_cast(j->get())) + { + if(!call.arguments[k]->type || call.arguments[k]->type!=var->type_declaration) + return; + } + else + return; + } + } + + resolve(call, i->second, false); +} + void ExpressionResolver::visit(FunctionCall &call) { TraversingVisitor::visit(call); - TypeDeclaration *type = 0; if(call.declaration) - type = call.declaration->return_type_declaration; + resolve(call, call.declaration->return_type_declaration, false); else if(call.constructor) - { - map::const_iterator i=stage->types.find(call.name); - type = (i!=stage->types.end() ? i->second : 0); - } - resolve(call, type, false); + visit_constructor(call); } void ExpressionResolver::visit(BasicTypeDeclaration &type) @@ -935,35 +1177,82 @@ bool FunctionResolver::apply(Stage &s) void FunctionResolver::visit(FunctionCall &call) { - map::iterator i = stage->functions.find(call.name); - if(i!=stage->functions.end()) - call.declaration = i->second; + FunctionDeclaration *declaration = 0; + if(stage->types.count(call.name)) + call.constructor = true; + else + { + string arg_types; + bool has_signature = true; + for(NodeArray::const_iterator i=call.arguments.begin(); (has_signature && i!=call.arguments.end()); ++i) + { + if((*i)->type) + append(arg_types, ",", (*i)->type->name); + else + has_signature = false; + } + + if(has_signature) + { + map::iterator i = stage->functions.find(format("%s(%s)", call.name, arg_types)); + declaration = (i!=stage->functions.end() ? i->second : 0); + } + } + + r_any_resolved |= (declaration!=call.declaration); + call.declaration = declaration; TraversingVisitor::visit(call); } void FunctionResolver::visit(FunctionDeclaration &func) { - FunctionDeclaration *&stage_decl = stage->functions[func.name]; - vector &decls = declarations[func.name]; + if(func.signature.empty()) + { + string param_types; + for(NodeArray::const_iterator i=func.parameters.begin(); i!=func.parameters.end(); ++i) + { + if((*i)->type_declaration) + append(param_types, ",", (*i)->type_declaration->name); + else + return; + } + func.signature = format("(%s)", param_types); + r_any_resolved = true; + } + + string key = func.name+func.signature; + FunctionDeclaration *&stage_decl = stage->functions[key]; + vector &decls = declarations[key]; if(func.definition==&func) { + if(stage_decl && stage_decl->definition) + { + if(!func.overrd) + stage->diagnostics.push_back(Diagnostic(Diagnostic::WARN, func.source, func.line, + format("Overriding function '%s' without the override keyword is deprecated", key))); + if(!stage_decl->definition->virtua) + stage->diagnostics.push_back(Diagnostic(Diagnostic::WARN, func.source, func.line, + format("Overriding function '%s' not declared as virtual is deprecated", key))); + } stage_decl = &func; // Set all previous declarations to use this definition. for(vector::iterator i=decls.begin(); i!=decls.end(); ++i) { + r_any_resolved |= (func.definition!=(*i)->definition); (*i)->definition = func.definition; (*i)->body.body.clear(); } } else { - func.definition = 0; + FunctionDeclaration *definition = (stage_decl ? stage_decl->definition : 0); + r_any_resolved |= (definition!=func.definition); + func.definition = definition; + if(!stage_decl) stage_decl = &func; - else - func.definition = stage_decl->definition; } decls.push_back(&func); @@ -1023,6 +1312,9 @@ VariableDeclaration *InterfaceGenerator::generate_interface(VariableDeclaration if(stage->content.variables.count(name)) return 0; + if(stage->type==Stage::GEOMETRY && !copy_block && var.interface=="out" && var.array) + return 0; + VariableDeclaration* iface_var = new VariableDeclaration; iface_var->sampling = var.sampling; iface_var->interface = iface; @@ -1045,6 +1337,8 @@ VariableDeclaration *InterfaceGenerator::generate_interface(VariableDeclaration iface_target_block->body.insert(iface_insert_point, iface_var); iface_target_block->variables.insert(make_pair(name, iface_var)); + if(iface_target_block==&stage->content && iface=="in") + declared_inputs.push_back(iface_var); return iface_var; } @@ -1120,8 +1414,14 @@ void InterfaceGenerator::visit(VariableReference &var) i = prev_vars.find(in_prefix+var.name); if(i!=prev_vars.end() && i->second->interface=="out") { - generate_interface(*i->second, "in", i->second->name); - var.name = i->second->name; + if(stage->type==Stage::GEOMETRY && i->second->array) + stage->diagnostics.push_back(Diagnostic(Diagnostic::WARN, var.source, var.line, + format("Can't access '%s' through automatic interface because it's an array", var.name))); + else + { + generate_interface(*i->second, "in", i->second->name); + var.name = i->second->name; + } return; } @@ -1171,11 +1471,14 @@ void InterfaceGenerator::visit(VariableDeclaration &var) } } } - else if(var.interface=="in") + else if(var.interface=="in" && current_block==&stage->content) { + if(var.name.compare(0, 3, "gl_")) + declared_inputs.push_back(&var); + /* Try to link input variables in global scope with output variables from previous stage. */ - if(current_block==&stage->content && !var.linked_declaration && stage->previous) + if(!var.linked_declaration && stage->previous) { const map &prev_vars = stage->previous->content.variables; map::const_iterator i = prev_vars.find(var.name); @@ -1220,12 +1523,8 @@ void InterfaceGenerator::visit(FunctionDeclaration &func) void InterfaceGenerator::visit(Passthrough &pass) { - vector pass_vars; - - // Pass through all input variables of this stage. - for(map::const_iterator i=stage->content.variables.begin(); i!=stage->content.variables.end(); ++i) - if(i->second->interface=="in") - pass_vars.push_back(i->second); + // Pass through all input variables declared so far. + vector pass_vars = declared_inputs; if(stage->previous) {