diff --git a/include/Nazara/Renderer.hpp b/include/Nazara/Renderer.hpp index 8271bd3c8..ff9193d3f 100644 --- a/include/Nazara/Renderer.hpp +++ b/include/Nazara/Renderer.hpp @@ -53,6 +53,7 @@ #include #include #include +#include #include #include #include diff --git a/include/Nazara/Renderer/ShaderAstCloner.hpp b/include/Nazara/Renderer/ShaderAstCloner.hpp new file mode 100644 index 000000000..b48de17b8 --- /dev/null +++ b/include/Nazara/Renderer/ShaderAstCloner.hpp @@ -0,0 +1,73 @@ +// Copyright (C) 2015 Jérôme Leclercq +// This file is part of the "Nazara Engine - Renderer module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_SHADERASTCLONER_HPP +#define NAZARA_SHADERASTCLONER_HPP + +#include +#include +#include +#include +#include + +namespace Nz +{ + class NAZARA_RENDERER_API ShaderAstCloner : public ShaderAstVisitor, public ShaderVarVisitor + { + public: + ShaderAstCloner() = default; + ShaderAstCloner(const ShaderAstCloner&) = default; + ShaderAstCloner(ShaderAstCloner&&) = default; + ~ShaderAstCloner() = default; + + ShaderNodes::StatementPtr Clone(const ShaderNodes::StatementPtr& statement); + + ShaderAstCloner& operator=(const ShaderAstCloner&) = default; + ShaderAstCloner& operator=(ShaderAstCloner&&) = default; + + private: + void Visit(const ShaderNodes::ExpressionPtr& expr); + void Visit(const ShaderNodes::StatementPtr& statement); + + void Visit(const ShaderNodes::AccessMember& node) override; + void Visit(const ShaderNodes::AssignOp& node) override; + void Visit(const ShaderNodes::BinaryOp& node) override; + void Visit(const ShaderNodes::Branch& node) override; + void Visit(const ShaderNodes::Cast& node) override; + void Visit(const ShaderNodes::Constant& node) override; + void Visit(const ShaderNodes::DeclareVariable& node) override; + void Visit(const ShaderNodes::ExpressionStatement& node) override; + void Visit(const ShaderNodes::Identifier& node) override; + void Visit(const ShaderNodes::IntrinsicCall& node) override; + void Visit(const ShaderNodes::Sample2D& node) override; + void Visit(const ShaderNodes::StatementBlock& node) override; + void Visit(const ShaderNodes::SwizzleOp& node) override; + + using ShaderVarVisitor::Visit; + void Visit(const ShaderNodes::BuiltinVariable& var) override; + void Visit(const ShaderNodes::InputVariable& var) override; + void Visit(const ShaderNodes::LocalVariable& var) override; + void Visit(const ShaderNodes::OutputVariable& var) override; + void Visit(const ShaderNodes::ParameterVariable& var) override; + void Visit(const ShaderNodes::UniformVariable& var) override; + + void PushExpression(ShaderNodes::ExpressionPtr expression); + void PushStatement(ShaderNodes::StatementPtr statement); + void PushVariable(ShaderNodes::VariablePtr variable); + + ShaderNodes::ExpressionPtr PopExpression(); + ShaderNodes::StatementPtr PopStatement(); + ShaderNodes::VariablePtr PopVariable(); + + std::vector m_expressionStack; + std::vector m_statementStack; + std::vector m_variableStack; + }; +} + +#include + +#endif diff --git a/include/Nazara/Renderer/ShaderAstCloner.inl b/include/Nazara/Renderer/ShaderAstCloner.inl new file mode 100644 index 000000000..1acdd41ab --- /dev/null +++ b/include/Nazara/Renderer/ShaderAstCloner.inl @@ -0,0 +1,12 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Renderer module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include + +namespace Nz +{ +} + +#include diff --git a/include/Nazara/Renderer/ShaderNodes.hpp b/include/Nazara/Renderer/ShaderNodes.hpp index 5bfd47f6b..c0b8688e2 100644 --- a/include/Nazara/Renderer/ShaderNodes.hpp +++ b/include/Nazara/Renderer/ShaderNodes.hpp @@ -106,6 +106,7 @@ namespace Nz std::vector statements; + static inline std::shared_ptr Build(std::vector statements); template static std::shared_ptr Build(Args&&... args); }; @@ -115,10 +116,10 @@ namespace Nz void Visit(ShaderAstVisitor& visitor) override; - LocalVariablePtr variable; ExpressionPtr expression; + VariablePtr variable; - static inline std::shared_ptr Build(LocalVariablePtr variable, ExpressionPtr expression = nullptr); + static inline std::shared_ptr Build(VariablePtr variable, ExpressionPtr expression = nullptr); }; struct NAZARA_RENDERER_API Identifier : public Expression @@ -196,7 +197,8 @@ namespace Nz StatementPtr statement; }; - inline std::shared_ptr Build(ExpressionPtr condition, StatementPtr trueStatement, StatementPtr falseStatement = nullptr); + static inline std::shared_ptr Build(ExpressionPtr condition, StatementPtr trueStatement, StatementPtr falseStatement = nullptr); + static inline std::shared_ptr Build(std::vector statements, StatementPtr elseStatement = nullptr); }; struct NAZARA_RENDERER_API Cast : public Expression @@ -246,6 +248,7 @@ namespace Nz ExpressionPtr expression; static inline std::shared_ptr Build(ExpressionPtr expressionPtr, std::initializer_list swizzleComponents); + static inline std::shared_ptr Build(ExpressionPtr expressionPtr, const SwizzleComponent* components, std::size_t componentCount); }; ////////////////////////////////////////////////////////////////////////// diff --git a/include/Nazara/Renderer/ShaderNodes.inl b/include/Nazara/Renderer/ShaderNodes.inl index 27d387bcd..0e9307ff4 100644 --- a/include/Nazara/Renderer/ShaderNodes.inl +++ b/include/Nazara/Renderer/ShaderNodes.inl @@ -107,6 +107,14 @@ namespace Nz::ShaderNodes { } + inline std::shared_ptr StatementBlock::Build(std::vector statements) + { + auto node = std::make_shared(); + node->statements = std::move(statements); + + return node; + } + template std::shared_ptr StatementBlock::Build(Args&&... args) { @@ -122,7 +130,7 @@ namespace Nz::ShaderNodes { } - inline std::shared_ptr DeclareVariable::Build(LocalVariablePtr variable, ExpressionPtr expression) + inline std::shared_ptr DeclareVariable::Build(VariablePtr variable, ExpressionPtr expression) { auto node = std::make_shared(); node->expression = std::move(expression); @@ -208,6 +216,15 @@ namespace Nz::ShaderNodes return node; } + inline std::shared_ptr Branch::Build(std::vector statements, StatementPtr elseStatement) + { + auto node = std::make_shared(); + node->condStatements = std::move(statements); + node->elseStatement = std::move(elseStatement); + + return node; + } + inline Cast::Cast() : Expression(NodeType::Cast) @@ -265,6 +282,20 @@ namespace Nz::ShaderNodes return node; } + inline std::shared_ptr SwizzleOp::Build(ExpressionPtr expressionPtr, const SwizzleComponent* components, std::size_t componentCount) + { + auto node = std::make_shared(); + + assert(componentCount < node->components.size()); + + node->componentCount = componentCount; + node->expression = std::move(expressionPtr); + + std::copy(components, components + componentCount, node->components.begin()); + + return node; + } + inline Sample2D::Sample2D() : Expression(NodeType::Sample2D) diff --git a/src/Nazara/Renderer/GlslWriter.cpp b/src/Nazara/Renderer/GlslWriter.cpp index 1383da334..8fa23755a 100644 --- a/src/Nazara/Renderer/GlslWriter.cpp +++ b/src/Nazara/Renderer/GlslWriter.cpp @@ -448,9 +448,13 @@ namespace Nz void GlslWriter::Visit(const ShaderNodes::DeclareVariable& node) { - Append(node.variable->type); + assert(node.variable->GetType() == ShaderNodes::VariableType::LocalVariable); + + const auto& localVar = static_cast(*node.variable); + + Append(localVar.type); Append(" "); - Append(node.variable->name); + Append(localVar.name); if (node.expression) { Append(" = "); diff --git a/src/Nazara/Renderer/ShaderAstCloner.cpp b/src/Nazara/Renderer/ShaderAstCloner.cpp new file mode 100644 index 000000000..f4ec37329 --- /dev/null +++ b/src/Nazara/Renderer/ShaderAstCloner.cpp @@ -0,0 +1,246 @@ +// Copyright (C) 2015 Jérôme Leclercq +// This file is part of the "Nazara Engine - Renderer module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include + +namespace Nz +{ + ShaderNodes::StatementPtr ShaderAstCloner::Clone(const ShaderNodes::StatementPtr& statement) + { + ShaderAstVisitor::Visit(statement); + + if (!m_expressionStack.empty() || !m_variableStack.empty() || m_statementStack.size() != 1) + throw std::runtime_error("An error occured during clone"); + + return PopStatement(); + } + + void ShaderAstCloner::Visit(const ShaderNodes::ExpressionPtr& expr) + { + if (expr) + ShaderAstVisitor::Visit(expr); + else + PushExpression(nullptr); + } + + void ShaderAstCloner::Visit(const ShaderNodes::StatementPtr& statement) + { + if (statement) + ShaderAstVisitor::Visit(statement); + else + PushStatement(nullptr); + } + + void ShaderAstCloner::Visit(const ShaderNodes::AccessMember& node) + { + Visit(node.structExpr); + + PushExpression(ShaderNodes::AccessMember::Build(PopExpression(), node.memberIndex, node.exprType)); + } + + void ShaderAstCloner::Visit(const ShaderNodes::AssignOp& node) + { + Visit(node.left); + Visit(node.right); + + auto right = PopExpression(); + auto left = PopExpression(); + + PushExpression(ShaderNodes::AssignOp::Build(node.op, std::move(left), std::move(right))); + } + + void ShaderAstCloner::Visit(const ShaderNodes::BinaryOp& node) + { + Visit(node.left); + Visit(node.right); + + auto right = PopExpression(); + auto left = PopExpression(); + + PushExpression(ShaderNodes::BinaryOp::Build(node.op, std::move(left), std::move(right))); + } + + void ShaderAstCloner::Visit(const ShaderNodes::Branch& node) + { + for (auto& cond : node.condStatements) + { + Visit(cond.condition); + Visit(cond.statement); + } + + Visit(node.elseStatement); + + auto elseStatement = PopStatement(); + + std::vector condStatements(node.condStatements.size()); + for (std::size_t i = 0; i < condStatements.size(); ++i) + { + auto& condStatement = condStatements[condStatements.size() - i - 1]; + condStatement.condition = PopExpression(); + condStatement.statement = PopStatement(); + } + + PushStatement(ShaderNodes::Branch::Build(std::move(condStatements), std::move(elseStatement))); + } + + void ShaderAstCloner::Visit(const ShaderNodes::Cast& node) + { + std::size_t expressionCount = 0; + std::array expressions; + for (const auto& expr : node.expressions) + { + Visit(expr); + expressionCount++; + } + + for (std::size_t i = 0; i < expressionCount; ++i) + expressions[expressionCount - i - 1] = PopExpression(); + + PushExpression(ShaderNodes::Cast::Build(node.exprType, expressions.data(), expressionCount)); + } + + void ShaderAstCloner::Visit(const ShaderNodes::Constant& node) + { + PushExpression(ShaderNodes::Constant::Build(node.value)); + } + + void ShaderAstCloner::Visit(const ShaderNodes::DeclareVariable& node) + { + Visit(node.expression); + Visit(node.variable); + + PushStatement(ShaderNodes::DeclareVariable::Build(PopVariable(), PopExpression())); + } + + void ShaderAstCloner::Visit(const ShaderNodes::ExpressionStatement& node) + { + Visit(node.expression); + + PushStatement(ShaderNodes::ExpressionStatement::Build(PopExpression())); + } + + void ShaderAstCloner::Visit(const ShaderNodes::Identifier& node) + { + Visit(node.var); + + PushExpression(ShaderNodes::Identifier::Build(PopVariable())); + } + + void ShaderAstCloner::Visit(const ShaderNodes::IntrinsicCall& node) + { + for (auto& parameter : node.parameters) + Visit(parameter); + + std::vector parameters(node.parameters.size()); + for (std::size_t i = 0; i < parameters.size(); ++i) + parameters[parameters.size() - i - 1] = PopExpression(); + + PushExpression(ShaderNodes::IntrinsicCall::Build(node.intrinsic, std::move(parameters))); + } + + void ShaderAstCloner::Visit(const ShaderNodes::Sample2D& node) + { + Visit(node.coordinates); + Visit(node.sampler); + + auto sampler = PopExpression(); + auto coordinates = PopExpression(); + + PushExpression(ShaderNodes::Sample2D::Build(std::move(sampler), std::move(coordinates))); + } + + void ShaderAstCloner::Visit(const ShaderNodes::StatementBlock& node) + { + for (auto& statement : node.statements) + Visit(statement); + + std::vector statements(node.statements.size()); + for (std::size_t i = 0; i < statements.size(); ++i) + statements[statements.size() - i - 1] = PopStatement(); + + PushStatement(ShaderNodes::StatementBlock::Build(std::move(statements))); + } + + void ShaderAstCloner::Visit(const ShaderNodes::SwizzleOp& node) + { + PushExpression(ShaderNodes::SwizzleOp::Build(PopExpression(), node.components.data(), node.componentCount)); + } + + void ShaderAstCloner::Visit(const ShaderNodes::BuiltinVariable& var) + { + PushVariable(ShaderNodes::BuiltinVariable::Build(var.entry, var.type)); + } + + void ShaderAstCloner::Visit(const ShaderNodes::InputVariable& var) + { + PushVariable(ShaderNodes::InputVariable::Build(var.name, var.type)); + } + + void ShaderAstCloner::Visit(const ShaderNodes::LocalVariable& var) + { + PushVariable(ShaderNodes::LocalVariable::Build(var.name, var.type)); + } + + void ShaderAstCloner::Visit(const ShaderNodes::OutputVariable& var) + { + PushVariable(ShaderNodes::OutputVariable::Build(var.name, var.type)); + } + + void ShaderAstCloner::Visit(const ShaderNodes::ParameterVariable& var) + { + PushVariable(ShaderNodes::ParameterVariable::Build(var.name, var.type)); + } + + void ShaderAstCloner::Visit(const ShaderNodes::UniformVariable& var) + { + PushVariable(ShaderNodes::UniformVariable::Build(var.name, var.type)); + } + + void ShaderAstCloner::PushExpression(ShaderNodes::ExpressionPtr expression) + { + m_expressionStack.emplace_back(std::move(expression)); + } + + void ShaderAstCloner::PushStatement(ShaderNodes::StatementPtr statement) + { + m_statementStack.emplace_back(std::move(statement)); + } + + void ShaderAstCloner::PushVariable(ShaderNodes::VariablePtr variable) + { + m_variableStack.emplace_back(std::move(variable)); + } + + ShaderNodes::ExpressionPtr ShaderAstCloner::PopExpression() + { + assert(!m_expressionStack.empty()); + + ShaderNodes::ExpressionPtr expr = std::move(m_expressionStack.back()); + m_expressionStack.pop_back(); + + return expr; + } + + ShaderNodes::StatementPtr ShaderAstCloner::PopStatement() + { + assert(!m_statementStack.empty()); + + ShaderNodes::StatementPtr expr = std::move(m_statementStack.back()); + m_statementStack.pop_back(); + + return expr; + } + + ShaderNodes::VariablePtr ShaderAstCloner::PopVariable() + { + assert(!m_variableStack.empty()); + + ShaderNodes::VariablePtr var = std::move(m_variableStack.back()); + m_variableStack.pop_back(); + + return var; + } +} diff --git a/src/Nazara/Renderer/ShaderAstValidator.cpp b/src/Nazara/Renderer/ShaderAstValidator.cpp index 57404ba6b..8e161d532 100644 --- a/src/Nazara/Renderer/ShaderAstValidator.cpp +++ b/src/Nazara/Renderer/ShaderAstValidator.cpp @@ -230,9 +230,14 @@ namespace Nz { assert(m_context); + if (node.variable->GetType() != ShaderNodes::VariableType::LocalVariable) + throw AstError{ "Only local variables can be declared in a statement" }; + + const auto& localVar = static_cast(*node.variable); + auto& local = m_context->declaredLocals.emplace_back(); - local.name = node.variable->name; - local.type = node.variable->type; + local.name = localVar.name; + local.type = localVar.type; ShaderAstRecursiveVisitor::Visit(node); }