X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=source%2Fglsl%2Ffinalize.cpp;h=0805a29e830eb45d626970a80faa1d10ae072c3b;hb=7b03ca83ca6c48b9f8c3f77c13760e7f87e9632d;hp=0725b7394213f9defb1553d728425009c1d66567;hpb=3bb1cda37e23840236b46c4de20cab2c70b02327;p=libs%2Fgl.git diff --git a/source/glsl/finalize.cpp b/source/glsl/finalize.cpp index 0725b739..0805a29e 100644 --- a/source/glsl/finalize.cpp +++ b/source/glsl/finalize.cpp @@ -3,6 +3,7 @@ #include #include "finalize.h" #include "glsl_error.h" +#include "reflect.h" using namespace std; @@ -10,6 +11,113 @@ namespace Msp { namespace GL { namespace SL { +void LocationAllocator::apply(Module &module) +{ + for(list::iterator i=module.stages.begin(); i!=module.stages.end(); ++i) + apply(*i); + allocate_locations("uniform"); +} + +void LocationAllocator::apply(Stage &stage) +{ + swap(used_locations["in"], used_locations["out"]); + used_locations["out"].clear(); + + stage.content.visit(*this); + + allocate_locations("in"); + allocate_locations("out"); +} + +void LocationAllocator::allocate_locations(const string &iface) +{ + vector::iterator write = unplaced_variables.begin(); + unsigned next = 0; + for(vector::const_iterator i=unplaced_variables.begin(); i!=unplaced_variables.end(); ++i) + { + if((*i)->interface!=iface) + { + if(write!=i) + *write = *i; + ++write; + continue; + } + + if((*i)->interface=="uniform") + { + map::const_iterator j = uniform_locations.find((*i)->name); + if(j!=uniform_locations.end()) + { + add_location((*i)->layout, j->second); + continue; + } + } + + set &used = used_locations[(*i)->interface]; + + unsigned size = LocationCounter().apply(**i); + while(1) + { + int blocking = -1; + for(unsigned j=0; jlayout, next); + if((*i)->interface=="uniform") + uniform_locations[(*i)->name] = next; + + for(unsigned j=0; j &layout, unsigned location) +{ + if(!layout) + layout = new Layout; + + Layout::Qualifier qual; + qual.name = "location"; + qual.has_value = true; + qual.value = location; + layout->qualifiers.push_back(qual); +} + +void LocationAllocator::visit(VariableDeclaration &var) +{ + if(!var.interface.empty() && var.name.compare(0, 3, "gl_")) + { + int location = (var.layout ? get_layout_value(*var.layout, "location") : -1); + + if(location<0 && var.linked_declaration && var.linked_declaration->layout) + { + location = get_layout_value(*var.linked_declaration->layout, "location"); + if(location>=0) + add_location(var.layout, location); + } + + if(location>=0) + { + unsigned size = LocationCounter().apply(var); + for(unsigned i=0; irequired_features.glsl_version) + stage->required_features.glsl_version = Version(1, (stage->required_features.gl_api==OPENGL_ES2 ? 0 : 10)); + } else unsupported(format("Stage %s is not supported", Stage::get_stage_name(s.type))); } @@ -161,12 +275,7 @@ void LegacyConverter::visit(VariableReference &var) { var.name = "gl_FragColor"; var.declaration = 0; - r_type = "vec4"; } - else if(var.declaration) - r_type = var.declaration->type; - else - r_type.clear(); } void LegacyConverter::visit(Assignment &assign) @@ -186,58 +295,39 @@ bool LegacyConverter::supports_unified_sampling_functions() const void LegacyConverter::visit(FunctionCall &call) { - if(call.name=="texture") + if(call.declaration && call.declaration->source==BUILTIN_SOURCE) { - string sampler_type; - r_type.clear(); - NodeArray::iterator i = call.arguments.begin(); - if(i!=call.arguments.end()) - { - (*i)->visit(*this); - sampler_type = r_type; - - for(; i!=call.arguments.end(); ++i) - (*i)->visit(*this); - } - - if(!supports_unified_sampling_functions()) + if(!call.name.compare(0, 7, "texture") && call.arguments.size()>=1) { - if(sampler_type=="sampler1D") - call.name = "texture1D"; - else if(sampler_type=="sampler2D") - call.name = "texture2D"; - else if(sampler_type=="sampler3D") - call.name = "texture3D"; - else if(sampler_type=="samplerCube") - call.name = "textureCube"; - else if(sampler_type=="sampler1DShadow") - call.name = "shadow1D"; - else if(sampler_type=="sampler2DShadow") - call.name = "shadow2D"; - else if(sampler_type=="sampler1DArray") - { - check_extension(&Features::ext_texture_array); - call.name = "texture1DArray"; - } - else if(sampler_type=="sampler2DArray") - { - check_extension(&Features::ext_texture_array); - call.name = "texture2DArray"; - } - else if(sampler_type=="sampler1DArrayShadow") - { - check_extension(&Features::ext_texture_array); - call.name = "shadow1DArray"; - } - else if(sampler_type=="sampler2DArrayShadow") + const ImageTypeDeclaration *arg_image = dynamic_cast(call.arguments.front()->type); + if(arg_image && !supports_unified_sampling_functions()) { - check_extension(&Features::ext_texture_array); - call.name = "shadow2DArray"; + string suffix = call.name.substr(7); + call.name = (arg_image->shadow ? "shadow" : "texture"); + + switch(arg_image->dimensions) + { + case ImageTypeDeclaration::ONE: call.name += "1D"; break; + case ImageTypeDeclaration::TWO: call.name += "2D"; break; + case ImageTypeDeclaration::THREE: call.name += "3D"; break; + case ImageTypeDeclaration::CUBE: call.name += "Cube"; break; + } + + if(arg_image->array) + { + /* Array textures and the unified sampling function name were + both introduced in GLSL 1.30. */ + if(arg_image->dimensions==ImageTypeDeclaration::ONE || arg_image->dimensions==ImageTypeDeclaration::TWO) + check_extension(&Features::ext_texture_array); + call.name += "Array"; + } + + call.name += suffix; } } } - else - TraversingVisitor::visit(call); + + TraversingVisitor::visit(call); } bool LegacyConverter::supports_interface_layouts() const @@ -246,8 +336,20 @@ bool LegacyConverter::supports_interface_layouts() const return check_version(Version(3, 0)); else if(check_version(Version(3, 30))) return true; - else + else if(check_version(Version(1, 30))) return check_extension(&Features::arb_explicit_attrib_location); + else + return false; +} + +bool LegacyConverter::supports_stage_interface_layouts() const +{ + if(features.gl_api==OPENGL_ES2) + return check_version(Version(3, 10)); + else if(check_version(Version(4, 10))) + return true; + else + return check_extension(&Features::arb_separate_shader_objects); } bool LegacyConverter::supports_centroid_sampling() const @@ -270,31 +372,60 @@ bool LegacyConverter::supports_sample_sampling() const return check_extension(&Features::arb_gpu_shader5); } +bool LegacyConverter::supports_uniform_location() const +{ + if(features.gl_api==OPENGL_ES2) + return check_version(Version(3, 10)); + else if(check_version(Version(4, 30))) + return true; + else + return check_extension(&Features::arb_explicit_uniform_location); +} + void LegacyConverter::visit(VariableDeclaration &var) { - if(var.layout && !supports_interface_layouts()) + if(var.layout) { - vector::iterator i; - for(i=var.layout->qualifiers.begin(); (i!=var.layout->qualifiers.end() && i->name!="location"); ++i) ; - if(i!=var.layout->qualifiers.end()) + for(vector::const_iterator i=var.layout->qualifiers.begin(); i!=var.layout->qualifiers.end(); ) { - if(stage->type==Stage::VERTEX && var.interface=="in") + if(i->name=="location") { - stage->locations[var.name] = i->value; - var.layout->qualifiers.erase(i); + bool supported = true; + bool external = false; + if(var.interface=="in") + { + external = (stage->type==Stage::VERTEX); + supported = (external ? supports_interface_layouts() : supports_stage_interface_layouts()); + } + else if(var.interface=="out") + { + external = (stage->type==Stage::FRAGMENT); + supported = (external ? supports_interface_layouts() : supports_stage_interface_layouts()); + if(external && !supported && !check_extension(&Features::ext_gpu_shader4)) + { + external = false; + if(i->value!=0) + unsupported("EXT_gpu_shader4 required for multiple fragment shader outputs"); + } + } + else if(var.interface=="uniform") + supported = supports_uniform_location(); + + if(!supported) + { + if(external) + stage->locations[var.name] = i->value; + i = var.layout->qualifiers.erase(i); + } + else + ++i; } - else if(stage->type==Stage::FRAGMENT && var.interface=="out") - { - if(check_extension(&Features::ext_gpu_shader4)) - stage->locations[var.name] = i->value; - else if(i->value!=0) - unsupported("EXT_gpu_shader4 required for multiple fragment shader outputs"); - var.layout->qualifiers.erase(i); - } - - if(var.layout->qualifiers.empty()) - var.layout = 0; + else + ++i; } + + if(var.layout->qualifiers.empty()) + var.layout = 0; } if(var.sampling=="centroid") @@ -337,8 +468,32 @@ bool LegacyConverter::supports_interface_blocks(const string &iface) const return false; } +bool LegacyConverter::supports_interface_block_location() const +{ + if(features.gl_api==OPENGL_ES2) + return check_version(Version(3, 20)); + else if(check_version(Version(4, 40))) + return true; + else + return check_extension(&Features::arb_enhanced_layouts); +} + void LegacyConverter::visit(InterfaceBlock &iface) { + if(iface.layout) + { + for(vector::const_iterator i=iface.layout->qualifiers.begin(); i!=iface.layout->qualifiers.end(); ) + { + if(i->name=="location" && !supports_interface_block_location()) + i = iface.layout->qualifiers.erase(i); + else + ++i; + } + + if(iface.layout->qualifiers.empty()) + iface.layout = 0; + } + if(!supports_interface_blocks(iface.interface) && iface.type_declaration) { if(!iface.instance_name.empty())