]> git.tdb.fi Git - libs/gl.git/blobdiff - source/glsl/compiler.cpp
Transform interface block contents into structs
[libs/gl.git] / source / glsl / compiler.cpp
index 7ff589e7050bc854c1e3b3fd5856c42ea852405d..ccfbe691195eefd91aa4314281db6afc1bb97c97 100644 (file)
@@ -1,16 +1,17 @@
 #include <msp/core/algorithm.h>
-#include <msp/gl/extensions/ext_gpu_shader4.h>
 #include <msp/strings/format.h>
+#include <msp/strings/utils.h>
 #include "builtin.h"
 #include "compatibility.h"
 #include "compiler.h"
 #include "debug.h"
 #include "error.h"
 #include "generate.h"
+#include "glsl_error.h"
 #include "optimize.h"
 #include "output.h"
 #include "resources.h"
-#include "shader.h"
+#include "validate.h"
 
 #undef interface
 
@@ -76,8 +77,16 @@ void Compiler::compile(Mode mode)
 {
        for(list<Stage>::iterator i=module->stages.begin(); i!=module->stages.end(); ++i)
                generate(*i, mode);
+
+       bool valid = true;
+       for(list<Stage>::iterator i=module->stages.begin(); i!=module->stages.end(); ++i)
+               if(!validate(*i))
+                       valid = false;
+       if(!valid)
+               throw invalid_shader_source(get_diagnostics());
+
        unsigned n = 0;
-       for(list<Stage>::iterator i=module->stages.begin(); (i!=module->stages.end() && n<10000); ++n)
+       for(list<Stage>::iterator i=module->stages.begin(); i!=module->stages.end(); ++n)
        {
                OptimizeResult result = optimize(*i);
                if(result==REDO_PREVIOUS)
@@ -152,11 +161,24 @@ string Compiler::get_stage_debug(Stage::Type stage_type) const
        throw key_error(Stage::get_stage_name(stage_type));
 }
 
+string Compiler::get_diagnostics() const
+{
+       string combined;
+       for(list<Stage>::const_iterator i=module->stages.begin(); i!=module->stages.end(); ++i)
+               for(vector<Diagnostic>::const_iterator j=i->diagnostics.begin(); j!=i->diagnostics.end(); ++j)
+                       if(j->source!=INTERNAL_SOURCE)
+                               append(combined, "\n", format("%s:%d: %s", module->source_map.get_name(j->source), j->line, j->message));
+       return combined;
+}
+
 void Compiler::append_module(Module &mod, DataFile::Collection *res)
 {
        module->source_map.merge_from(mod.source_map);
 
-       vector<Import *> imports = NodeGatherer<Import>().apply(mod.shared);
+       vector<Import *> imports;
+       for(NodeList<Statement>::const_iterator i=mod.shared.content.body.begin(); i!=mod.shared.content.body.end(); ++i)
+               if(Import *imp = dynamic_cast<Import *>(i->get()))
+                       imports.push_back(imp);
        for(vector<Import *>::iterator i=imports.begin(); i!=imports.end(); ++i)
                import(res, (*i)->module);
        NodeRemover().apply(mod.shared, set<Node *>(imports.begin(), imports.end()));
@@ -188,13 +210,6 @@ void Compiler::append_stage(Stage &stage)
                target = &*i;
        }
 
-       if(target->content.body.empty())
-       {
-               Stage *builtins = get_builtins(stage.type);
-               if(builtins && builtins!=&stage)
-                       append_stage(*builtins);
-       }
-
        if(stage.required_features.glsl_version>target->required_features.glsl_version)
                target->required_features.glsl_version = stage.required_features.glsl_version;
        for(NodeList<Statement>::iterator i=stage.content.body.begin(); i!=stage.content.body.end(); ++i)
@@ -221,40 +236,91 @@ void Compiler::generate(Stage &stage, Mode mode)
        stage.required_features.gl_api = features.gl_api;
        if(module->shared.required_features.glsl_version>stage.required_features.glsl_version)
                stage.required_features.glsl_version = module->shared.required_features.glsl_version;
+
        inject_block(stage.content, module->shared.content);
+       if(const Stage *builtins = get_builtins(stage.type))
+               inject_block(stage.content, builtins->content);
+       if(const Stage *builtins = get_builtins(Stage::SHARED))
+               inject_block(stage.content, builtins->content);
 
        // Initial resolving pass
-       BlockHierarchyResolver().apply(stage);
-       FunctionResolver().apply(stage);
-       VariableResolver().apply(stage);
+       resolve(stage);
 
        /* All variables local to a stage have been resolved.  Resolve non-local
        variables through interfaces. */
        InterfaceGenerator().apply(stage);
-       VariableResolver().apply(stage);
+       resolve(stage, RESOLVE_BLOCKS|RESOLVE_TYPES|RESOLVE_VARIABLES);
 
-       FunctionResolver().apply(stage);
        ConstantSpecializer().apply(stage, (mode==PROGRAM && specialized ? &spec_values : 0));
        if(mode==PROGRAM)
+       {
                LegacyConverter().apply(stage, features);
+               resolve(stage, RESOLVE_VARIABLES|RESOLVE_FUNCTIONS);
+       }
+}
+
+template<typename T>
+bool Compiler::resolve(Stage &stage, unsigned &flags, unsigned bit)
+{
+       if(!(flags&bit))
+               return false;
+
+       flags &= ~bit;
+       return T().apply(stage);
+}
+
+void Compiler::resolve(Stage &stage, unsigned flags)
+{
+       while(flags)
+       {
+               if(resolve<BlockHierarchyResolver>(stage, flags, RESOLVE_BLOCKS))
+                       ;
+               else if(resolve<TypeResolver>(stage, flags, RESOLVE_TYPES))
+                       flags |= RESOLVE_BLOCKS|RESOLVE_VARIABLES|RESOLVE_EXPRESSIONS;
+               else if(resolve<VariableResolver>(stage, flags, RESOLVE_VARIABLES))
+                       flags |= RESOLVE_EXPRESSIONS;
+               else if(resolve<FunctionResolver>(stage, flags, RESOLVE_FUNCTIONS))
+                       flags |= RESOLVE_EXPRESSIONS;
+               else if(resolve<ExpressionResolver>(stage, flags, RESOLVE_EXPRESSIONS))
+                       flags |= RESOLVE_VARIABLES;
+       }
+}
+
+bool Compiler::validate(Stage &stage)
+{
+       TypeValidator().apply(stage);
+       DeclarationValidator().apply(stage);
+       ReferenceValidator().apply(stage);
+       ExpressionValidator().apply(stage);
+
+       for(vector<Diagnostic>::const_iterator i=stage.diagnostics.begin(); i!=stage.diagnostics.end(); ++i)
+               if(i->severity==Diagnostic::ERR)
+                       return false;
+
+       return true;
 }
 
 Compiler::OptimizeResult Compiler::optimize(Stage &stage)
 {
        ConstantConditionEliminator().apply(stage);
 
-       bool any_inlined = FunctionInliner().apply(stage);
-       any_inlined |= ExpressionInliner().apply(stage);
-       if(any_inlined)
+       bool any_inlined = false;
+       if(FunctionInliner().apply(stage))
+       {
+               resolve(stage, RESOLVE_TYPES|RESOLVE_VARIABLES|RESOLVE_EXPRESSIONS);
+               any_inlined = true;
+       }
+       if(ExpressionInliner().apply(stage))
        {
-               VariableResolver().apply(stage);
-               FunctionResolver().apply(stage);
+               resolve(stage, RESOLVE_VARIABLES|RESOLVE_EXPRESSIONS);
+               any_inlined = true;
        }
 
        /* Removing variables or functions may cause things from the previous stage
        to become unused. */
        bool any_removed = UnusedVariableRemover().apply(stage);
        any_removed |= UnusedFunctionRemover().apply(stage);
+       any_removed |= UnusedTypeRemover().apply(stage);
 
        return any_removed ? REDO_PREVIOUS : any_inlined ? REDO_STAGE : NEXT_STAGE;
 }