#ifndef MSP_GL_SL_COMPILER_H_
#define MSP_GL_SL_COMPILER_H_
-#include <set>
+#include <vector>
+#include <msp/datafile/collection.h>
+#include <msp/io/base.h>
#include "parser.h"
-#include "program.h"
-#include "resources.h"
#include "syntax.h"
namespace Msp {
class Compiler
{
-private:
- struct Visitor: TraversingVisitor
+public:
+ enum Mode
{
- typedef void ResultType;
-
- Stage *stage;
-
- Visitor();
-
- virtual void apply(Stage &);
- void get_result() const { }
+ MODULE,
+ PROGRAM,
+ SPIRV
};
- struct BlockModifier: Visitor
- {
- bool remove_node;
- std::vector<RefPtr<Statement> > insert_nodes;
-
- BlockModifier();
-
- void flatten_block(Block &);
- void apply_and_increment(Block &, NodeList<Statement>::iterator &);
- using Visitor::visit;
- virtual void visit(Block &);
- };
-
- struct Formatter: Visitor
+private:
+ enum OptimizeResult
{
- typedef std::string ResultType;
-
- std::string formatted;
- unsigned source_index;
- unsigned source_line;
- unsigned indent;
- bool parameter_list;
- std::string block_interface;
-
- Formatter();
-
- virtual void apply(Stage &);
- const std::string &get_result() const { return formatted; }
- using Visitor::visit;
- void append(const std::string &);
- void append(char);
- void set_source(unsigned, unsigned);
- virtual void visit(Block &);
- virtual void visit(Literal &);
- virtual void visit(ParenthesizedExpression &);
- virtual void visit(VariableReference &);
- virtual void visit(MemberAccess &);
- virtual void visit(UnaryExpression &);
- virtual void visit(BinaryExpression &);
- virtual void visit(Assignment &);
- virtual void visit(FunctionCall &);
- virtual void visit(ExpressionStatement &);
- virtual void visit(Import &);
- virtual void visit(Precision &);
- virtual void visit(Layout &);
- virtual void visit(InterfaceLayout &);
- virtual void visit(StructDeclaration &);
- virtual void visit(VariableDeclaration &);
- virtual void visit(InterfaceBlock &);
- virtual void visit(FunctionDeclaration &);
- virtual void visit(Conditional &);
- virtual void visit(Iteration &);
- virtual void visit(Return &);
- virtual void visit(Jump &);
+ NEXT_STAGE,
+ REDO_STAGE,
+ REDO_PREVIOUS
};
- template<typename T>
- struct NodeGatherer: Visitor
+ enum ResolveFlags
{
- typedef std::vector<T *> ResultType;
-
- std::vector<T *> nodes;
-
- const ResultType &get_result() const { return nodes; }
- using Visitor::visit;
- virtual void visit(T &n) { nodes.push_back(&n); }
+ RESOLVE_BLOCKS = 1,
+ RESOLVE_TYPES = 2,
+ RESOLVE_VARIABLES = 4,
+ RESOLVE_EXPRESSIONS = 8,
+ RESOLVE_FUNCTIONS = 16,
+ RESOLVE_ALL = 31
};
- struct DeclarationCombiner: BlockModifier
- {
- bool toplevel;
- std::map<std::string, std::vector<FunctionDeclaration *> > functions;
- std::map<std::string, VariableDeclaration *> variables;
+ Features features;
+ Module *module = 0;
+ std::vector<std::string> imported_names;
+ bool compiled = false;
+ bool specialized = false;
+ std::map<std::string, int> spec_values;
- DeclarationCombiner();
+public:
+ /** Creates a compiler using features from the current OpenGL context. */
+ Compiler();
- using Visitor::visit;
- virtual void visit(Block &);
- virtual void visit(FunctionDeclaration &);
- virtual void visit(VariableDeclaration &);
- };
+ /** Creates a compiler targeting a specific set of features. */
+ Compiler(const Features &);
- struct VariableResolver: Visitor
- {
- std::vector<Block *> blocks;
- StructDeclaration *type;
- bool anonymous;
- std::string block_interface;
- bool record_target;
- VariableDeclaration *assignment_target;
- bool self_referencing;
-
- VariableResolver();
-
- virtual void apply(Stage &);
- using Visitor::visit;
- virtual void visit(Block &);
- virtual void visit(VariableReference &);
- virtual void visit(MemberAccess &);
- virtual void visit(BinaryExpression &);
- virtual void visit(Assignment &);
- virtual void visit(StructDeclaration &);
- virtual void visit(VariableDeclaration &);
- virtual void visit(InterfaceBlock &);
- };
+ ~Compiler();
- struct FunctionResolver: Visitor
- {
- std::map<std::string, std::vector<FunctionDeclaration *> > functions;
+private:
+ void clear();
- using Visitor::visit;
- virtual void visit(FunctionCall &);
- virtual void visit(FunctionDeclaration &);
- };
+public:
+ /** Sets the source code to be compiled. Only builtin imports are
+ available. */
+ void set_source(const std::string &, const std::string & = "<string>");
- struct InterfaceGenerator: BlockModifier
- {
- std::string in_prefix;
- std::string out_prefix;
- unsigned scope_level;
- std::map<std::string, RefPtr<VariableDeclaration> > iface_declarations;
-
- InterfaceGenerator();
-
- static std::string get_out_prefix(StageType);
- virtual void apply(Stage &);
- using Visitor::visit;
- virtual void visit(Block &);
- std::string change_prefix(const std::string &, const std::string &) const;
- bool generate_interface(VariableDeclaration &, const std::string &, const std::string &);
- ExpressionStatement &insert_assignment(const std::string &, Expression *);
- virtual void visit(VariableReference &);
- virtual void visit(VariableDeclaration &);
- virtual void visit(Passthrough &);
- };
+ /** Loads source code from an I/O object. If a collection is used, imports
+ can be fetched from it. */
+ void load_source(IO::Base &, DataFile::Collection * = 0, const std::string & = "<file>");
- struct DeclarationReorderer: Visitor
- {
- enum DeclarationKind
- {
- NO_DECLARATION,
- LAYOUT,
- STRUCT,
- VARIABLE,
- FUNCTION
- };
-
- unsigned scope_level;
- DeclarationKind kind;
- std::set<Node *> ordered_funcs;
- std::set<Node *> needed_funcs;
-
- DeclarationReorderer();
-
- using Visitor::visit;
- virtual void visit(Block &);
- virtual void visit(FunctionCall &);
- virtual void visit(InterfaceLayout &) { kind = LAYOUT; }
- virtual void visit(StructDeclaration &) { kind = STRUCT; }
- virtual void visit(VariableDeclaration &);
- virtual void visit(InterfaceBlock &) { kind = VARIABLE; }
- virtual void visit(FunctionDeclaration &);
- };
+ /** Loads source code from an I/O object. Only builtin imports are
+ available. */
+ void load_source(IO::Base &, const std::string &);
- struct InlineableFunctionLocator: Visitor
- {
- typedef std::set<FunctionDeclaration *> ResultType;
+ /** Specializes the shader. All specialization constants are considered
+ specialized, even if they do not appear in the map. */
+ void specialize(const std::map<std::string, int> &);
- std::map<FunctionDeclaration *, unsigned> refcounts;
- std::set<FunctionDeclaration *> inlineable;
- FunctionDeclaration *in_function;
+ /** Compiles the shader. */
+ void compile(Mode);
- InlineableFunctionLocator();
+ /** Returns combined GLSL source for all shader stages. The result is
+ suitable for feeding back to the compiler. */
+ std::string get_combined_glsl() const;
- const ResultType &get_result() const { return inlineable; }
- using Visitor::visit;
- virtual void visit(FunctionCall &);
- virtual void visit(FunctionDeclaration &);
- };
+ /** Returns a list of compiled stage types. */
+ std::vector<Stage::Type> get_stages() const;
- struct FunctionInliner: Visitor
- {
- std::set<FunctionDeclaration *> inlineable;
- unsigned extract_result;
- RefPtr<Expression> inline_result;
-
- FunctionInliner();
- FunctionInliner(const std::set<FunctionDeclaration *> &);
-
- void visit_and_inline(RefPtr<Expression> &);
- using Visitor::visit;
- virtual void visit(Block &);
- virtual void visit(UnaryExpression &);
- virtual void visit(BinaryExpression &);
- virtual void visit(MemberAccess &);
- virtual void visit(FunctionCall &);
- virtual void visit(VariableDeclaration &);
- virtual void visit(Return &);
- };
+ /** Returns GLSL source for a single shader stage. The result is standard
+ GLSL suitable for OpenGL or an external GLSL compiler. */
+ std::string get_stage_glsl(Stage::Type) const;
- struct ExpressionEvaluator: NodeVisitor
- {
- typedef std::map<VariableDeclaration *, Expression *> ValueMap;
+ /** Returns a combined SPIR-V binary for all shader stages. The result is
+ suitable for use with OpenGL or Vulkan. */
+ std::vector<std::uint32_t> get_combined_spirv() const;
- const ValueMap *variable_values;
- float result;
- bool result_valid;
+ /** Returns a map of vertex attribute locations. If the target GLSL version
+ supports interface layouts, the map is empty (locations are included in the
+ GLSL soucre). */
+ const std::map<std::string, unsigned> &get_vertex_attributes() const;
- ExpressionEvaluator();
- ExpressionEvaluator(const ValueMap &);
+ /** Returns a map of fragment output locations. If the target GLSL version
+ supports interface layouts, the map is empty (locations are included in the
+ GLSL soucre). */
+ const std::map<std::string, unsigned> &get_fragment_outputs() const;
- using NodeVisitor::visit;
- virtual void visit(Literal &);
- virtual void visit(ParenthesizedExpression &);
- virtual void visit(VariableReference &);
- virtual void visit(UnaryExpression &);
- virtual void visit(BinaryExpression &);
- };
+ /** Returns a map of texture bindings. If the target GLSL version supports
+ bindings, the map is empty (bindings are included in the GLSL source). */
+ const std::map<std::string, unsigned> &get_texture_bindings() const;
- struct ConstantConditionEliminator: BlockModifier
- {
- unsigned scope_level;
- bool record_only;
- ExpressionEvaluator::ValueMap variable_values;
-
- ConstantConditionEliminator();
-
- using Visitor::visit;
- virtual void visit(Block &);
- virtual void visit(UnaryExpression &);
- virtual void visit(Assignment &);
- virtual void visit(VariableDeclaration &);
- virtual void visit(Conditional &);
- virtual void visit(Iteration &);
- };
+ /** Returns a map of uniform block bindings. If the target GLSL version
+ supports bindings, the map is empty (bindings are included in the GLSL
+ source). */
+ const std::map<std::string, unsigned> &get_uniform_block_bindings() const;
- struct UnusedVariableLocator: Visitor
- {
- struct VariableInfo
- {
- bool local;
- std::vector<Node *> assignments;
- bool conditionally_assigned;
- bool referenced;
-
- VariableInfo();
- };
-
- typedef std::set<Node *> ResultType;
- typedef std::map<VariableDeclaration *, VariableInfo> BlockVariableMap;
-
- std::set<Node *> unused_nodes;
- std::map<VariableDeclaration *, Node *> aggregates;
- Node *aggregate;
- std::vector<BlockVariableMap> variables;
- Assignment *assignment;
- bool assignment_target;
- bool assign_to_subscript;
- bool global_scope;
-
- UnusedVariableLocator();
-
- virtual void apply(Stage &);
- const ResultType &get_result() const { return unused_nodes; }
- using Visitor::visit;
- virtual void visit(VariableReference &);
- virtual void visit(MemberAccess &);
- virtual void visit(BinaryExpression &);
- virtual void visit(Assignment &);
- void record_assignment(VariableDeclaration &, Node &, bool);
- void clear_assignments(VariableInfo &, bool);
- virtual void visit(ExpressionStatement &);
- virtual void visit(StructDeclaration &);
- virtual void visit(VariableDeclaration &);
- virtual void visit(InterfaceBlock &);
- virtual void visit(FunctionDeclaration &);
- void merge_down_variables();
- virtual void visit(Conditional &);
- virtual void visit(Iteration &);
- };
+ unsigned get_n_clip_distances() const;
- struct UnusedFunctionLocator: Visitor
- {
- typedef std::set<Node *> ResultType;
+ /** Returns the mapping of source indices to filenames. Can be used to
+ translate error messages. */
+ const SourceMap &get_source_map() const;
- std::set<Node *> unused_nodes;
- std::set<FunctionDeclaration *> used_definitions;
+ /** Returns a textual representation of the syntax tree for a shader stage.
+ Intended for debugging purposes. */
+ std::string get_stage_debug(Stage::Type) const;
- const ResultType &get_result() const { return unused_nodes; }
- using Visitor::visit;
- virtual void visit(FunctionCall &);
- virtual void visit(FunctionDeclaration &);
- };
+ /** Returns diagnostics from compilation. The output is intended to be
+ viewed by humans. */
+ std::string get_diagnostics() const;
- struct NodeRemover: Visitor
- {
- std::set<Node *> to_remove;
+private:
+ /** Appends a module to the target, processing any imports found in it. */
+ void append_module(const Module &, ModuleCache &);
- NodeRemover() { }
- NodeRemover(const std::set<Node *> &);
+ /** Appends a single stage to the matching stage of the target. */
+ void append_stage(const Stage &);
- using Visitor::visit;
- virtual void visit(Block &);
- virtual void visit(VariableDeclaration &);
- virtual void visit(Iteration &);
- };
+ /// Imports a module by name and appends it to the target. */
+ void import(ModuleCache &, const std::string &);
- struct PrecisionRemover: BlockModifier
- {
- using Visitor::visit;
- virtual void visit(Precision &);
- virtual void visit(VariableDeclaration &);
- };
+ /** Generates any implicitly defines syntactic structures and resolves
+ variables. */
+ void generate(Stage &);
- struct DefaultPrecisionGenerator: BlockModifier
- {
- bool toplevel;
- std::set<std::string> have_default;
+ template<typename T>
+ bool resolve(Stage &, unsigned &, unsigned);
- DefaultPrecisionGenerator();
+ /** Resolves various references between nodes. Flags can be specified to
+ request resolving particular aspects. Resolving may ripple into other
+ aspects as necessary. */
+ void resolve(Stage &, unsigned = RESOLVE_ALL);
- using Visitor::visit;
- virtual void visit(Block &);
- virtual void visit(Precision &);
- virtual void visit(VariableDeclaration &);
- };
+ /** Runs validators on a stage. Diagnostic messages are recorded in the
+ stage for later inspection. */
+ void validate(Stage &);
- struct LegacyConverter: BlockModifier
- {
- GLApi target_api;
- Version target_version;
- std::string type;
- VariableDeclaration *frag_out;
-
- LegacyConverter();
- LegacyConverter(const Version &);
-
- bool check_version(const Version &) const;
- bool check_extension(const Extension &) const;
- using Visitor::visit;
- bool supports_unified_interface_syntax() const;
- virtual void visit(VariableReference &);
- virtual void visit(Assignment &);
- bool supports_unified_sampling_functions() const;
- virtual void visit(FunctionCall &);
- bool supports_interface_layouts() const;
- bool supports_centroid_sampling() const;
- bool supports_sample_sampling() const;
- virtual void visit(VariableDeclaration &);
- bool supports_interface_blocks(const std::string &) const;
- virtual void visit(InterfaceBlock &);
- };
+ /** Checks a stage's recorded diagnostics for errors. If any are found,
+ returns true. */
+ bool check_errors(Stage &);
- Resources *resources;
- Module *module;
- std::vector<std::string> imported_names;
+ static bool diagnostic_line_order(const Diagnostic &, const Diagnostic &);
-public:
- Compiler();
- ~Compiler();
+ /** Applies optimizations to a stage. The return value indicates which
+ stage should be optimized next. */
+ OptimizeResult optimize(Stage &);
- void compile(const std::string &, const std::string & = "<string>");
- void compile(IO::Base &, Resources * = 0, const std::string & = "<file>");
- void compile(IO::Base &, const std::string &);
- void add_shaders(Program &);
+ /** Performs final adjustments on a stage after compilation. */
+ void finalize(Stage &, Mode);
-private:
- static Module *create_builtins_module();
- static Module &get_builtins_module();
- static Stage *get_builtins(StageType);
- void append_module(Module &);
- void append_stage(Stage &);
- void process();
- void import(const std::string &);
- void generate(Stage &);
- bool optimize(Stage &);
- void finalize(Stage &);
static void inject_block(Block &, const Block &);
- template<typename T>
- static typename T::ResultType apply(Stage &);
- template<typename T, typename A>
- static typename T::ResultType apply(Stage &, const A &);
};
} // namespace SL