From 77b66620c97aaf82590e0c0a43b7c8423da46e48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Sun, 23 Aug 2020 21:56:30 +0200 Subject: [PATCH] Refactor SpirV classes SpirvStatementVisitor was merged with SpirvExpressionLoad SpirvExpressionLoadAccessMember was renamed SpirvExpressionLoad --- include/Nazara/Shader/SpirvAstVisitor.hpp | 58 +++ ...atementVisitor.inl => SpirvAstVisitor.inl} | 4 +- include/Nazara/Shader/SpirvExpressionLoad.hpp | 37 +- .../SpirvExpressionLoadAccessMember.hpp | 62 --- .../SpirvExpressionLoadAccessMember.inl | 16 - .../Nazara/Shader/SpirvStatementVisitor.hpp | 43 -- include/Nazara/Shader/SpirvWriter.hpp | 4 +- src/Nazara/Shader/SpirvAstVisitor.cpp | 433 ++++++++++++++++ src/Nazara/Shader/SpirvExpressionLoad.cpp | 479 +++--------------- .../SpirvExpressionLoadAccessMember.cpp | 116 ----- src/Nazara/Shader/SpirvStatementVisitor.cpp | 49 -- src/Nazara/Shader/SpirvWriter.cpp | 4 +- 12 files changed, 591 insertions(+), 714 deletions(-) create mode 100644 include/Nazara/Shader/SpirvAstVisitor.hpp rename include/Nazara/Shader/{SpirvStatementVisitor.inl => SpirvAstVisitor.inl} (70%) delete mode 100644 include/Nazara/Shader/SpirvExpressionLoadAccessMember.hpp delete mode 100644 include/Nazara/Shader/SpirvExpressionLoadAccessMember.inl delete mode 100644 include/Nazara/Shader/SpirvStatementVisitor.hpp create mode 100644 src/Nazara/Shader/SpirvAstVisitor.cpp delete mode 100644 src/Nazara/Shader/SpirvExpressionLoadAccessMember.cpp delete mode 100644 src/Nazara/Shader/SpirvStatementVisitor.cpp diff --git a/include/Nazara/Shader/SpirvAstVisitor.hpp b/include/Nazara/Shader/SpirvAstVisitor.hpp new file mode 100644 index 000000000..743dd5130 --- /dev/null +++ b/include/Nazara/Shader/SpirvAstVisitor.hpp @@ -0,0 +1,58 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Shader generator" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_SPIRVEXPRESSIONLOAD_HPP +#define NAZARA_SPIRVEXPRESSIONLOAD_HPP + +#include +#include +#include +#include +#include + +namespace Nz +{ + class SpirvWriter; + + class NAZARA_SHADER_API SpirvAstVisitor : public ShaderAstVisitorExcept + { + public: + inline SpirvAstVisitor(SpirvWriter& writer); + SpirvAstVisitor(const SpirvAstVisitor&) = delete; + SpirvAstVisitor(SpirvAstVisitor&&) = delete; + ~SpirvAstVisitor() = default; + + UInt32 EvaluateExpression(const ShaderNodes::ExpressionPtr& expr); + + using ShaderAstVisitorExcept::Visit; + void Visit(ShaderNodes::AccessMember& node) override; + void Visit(ShaderNodes::AssignOp& node) override; + void Visit(ShaderNodes::BinaryOp& node) override; + void Visit(ShaderNodes::Cast& node) override; + void Visit(ShaderNodes::Constant& node) override; + void Visit(ShaderNodes::DeclareVariable& node) override; + void Visit(ShaderNodes::ExpressionStatement& node) override; + void Visit(ShaderNodes::Identifier& node) override; + void Visit(ShaderNodes::IntrinsicCall& node) override; + void Visit(ShaderNodes::Sample2D& node) override; + void Visit(ShaderNodes::StatementBlock& node) override; + void Visit(ShaderNodes::SwizzleOp& node) override; + + SpirvAstVisitor& operator=(const SpirvAstVisitor&) = delete; + SpirvAstVisitor& operator=(SpirvAstVisitor&&) = delete; + + private: + void PushResultId(UInt32 value); + UInt32 PopResultId(); + + std::vector m_resultIds; + SpirvWriter& m_writer; + }; +} + +#include + +#endif diff --git a/include/Nazara/Shader/SpirvStatementVisitor.inl b/include/Nazara/Shader/SpirvAstVisitor.inl similarity index 70% rename from include/Nazara/Shader/SpirvStatementVisitor.inl rename to include/Nazara/Shader/SpirvAstVisitor.inl index fc2274c10..87dc93a54 100644 --- a/include/Nazara/Shader/SpirvStatementVisitor.inl +++ b/include/Nazara/Shader/SpirvAstVisitor.inl @@ -2,12 +2,12 @@ // This file is part of the "Nazara Engine - Shader generator" // For conditions of distribution and use, see copyright notice in Config.hpp -#include +#include #include namespace Nz { - inline SpirvStatementVisitor::SpirvStatementVisitor(SpirvWriter& writer) : + inline SpirvAstVisitor::SpirvAstVisitor(SpirvWriter& writer) : m_writer(writer) { } diff --git a/include/Nazara/Shader/SpirvExpressionLoad.hpp b/include/Nazara/Shader/SpirvExpressionLoad.hpp index a766e568d..b237c720a 100644 --- a/include/Nazara/Shader/SpirvExpressionLoad.hpp +++ b/include/Nazara/Shader/SpirvExpressionLoad.hpp @@ -4,13 +4,14 @@ #pragma once -#ifndef NAZARA_SPIRVEXPRESSIONLOAD_HPP -#define NAZARA_SPIRVEXPRESSIONLOAD_HPP +#ifndef NAZARA_SPIRVEXPRESSIONLOADACCESSMEMBER_HPP +#define NAZARA_SPIRVEXPRESSIONLOADACCESSMEMBER_HPP #include #include #include #include +#include #include namespace Nz @@ -25,37 +26,35 @@ namespace Nz SpirvExpressionLoad(SpirvExpressionLoad&&) = delete; ~SpirvExpressionLoad() = default; - UInt32 EvaluateExpression(const ShaderNodes::ExpressionPtr& expr); + UInt32 Evaluate(ShaderNodes::Expression& node); - using ShaderAstVisitorExcept::Visit; + using ShaderAstVisitor::Visit; void Visit(ShaderNodes::AccessMember& node) override; - void Visit(ShaderNodes::AssignOp& node) override; - void Visit(ShaderNodes::BinaryOp& node) override; - void Visit(ShaderNodes::Cast& node) override; - void Visit(ShaderNodes::Constant& node) override; - void Visit(ShaderNodes::DeclareVariable& node) override; - void Visit(ShaderNodes::ExpressionStatement& node) override; void Visit(ShaderNodes::Identifier& node) override; - void Visit(ShaderNodes::IntrinsicCall& node) override; - void Visit(ShaderNodes::Sample2D& node) override; - void Visit(ShaderNodes::SwizzleOp& node) override; - using ShaderVarVisitorExcept::Visit; - void Visit(ShaderNodes::BuiltinVariable& var) override; + using ShaderVarVisitor::Visit; void Visit(ShaderNodes::InputVariable& var) override; void Visit(ShaderNodes::LocalVariable& var) override; - void Visit(ShaderNodes::ParameterVariable& var) override; void Visit(ShaderNodes::UniformVariable& var) override; SpirvExpressionLoad& operator=(const SpirvExpressionLoad&) = delete; SpirvExpressionLoad& operator=(SpirvExpressionLoad&&) = delete; private: - void PushResultId(UInt32 value); - UInt32 PopResultId(); + struct Pointer + { + SpirvStorageClass storage; + UInt32 resultId; + UInt32 pointedTypeId; + }; + + struct Value + { + UInt32 resultId; + }; - std::vector m_resultIds; SpirvWriter& m_writer; + std::variant m_value; }; } diff --git a/include/Nazara/Shader/SpirvExpressionLoadAccessMember.hpp b/include/Nazara/Shader/SpirvExpressionLoadAccessMember.hpp deleted file mode 100644 index 8e2e0ff3b..000000000 --- a/include/Nazara/Shader/SpirvExpressionLoadAccessMember.hpp +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright (C) 2020 Jérôme Leclercq -// This file is part of the "Nazara Engine - Shader generator" -// For conditions of distribution and use, see copyright notice in Config.hpp - -#pragma once - -#ifndef NAZARA_SPIRVEXPRESSIONLOADACCESSMEMBER_HPP -#define NAZARA_SPIRVEXPRESSIONLOADACCESSMEMBER_HPP - -#include -#include -#include -#include -#include -#include - -namespace Nz -{ - class SpirvWriter; - - class NAZARA_SHADER_API SpirvExpressionLoadAccessMember : public ShaderAstVisitorExcept, public ShaderVarVisitorExcept - { - public: - inline SpirvExpressionLoadAccessMember(SpirvWriter& writer); - SpirvExpressionLoadAccessMember(const SpirvExpressionLoadAccessMember&) = delete; - SpirvExpressionLoadAccessMember(SpirvExpressionLoadAccessMember&&) = delete; - ~SpirvExpressionLoadAccessMember() = default; - - UInt32 EvaluateExpression(ShaderNodes::AccessMember& expr); - - using ShaderAstVisitor::Visit; - void Visit(ShaderNodes::AccessMember& node) override; - void Visit(ShaderNodes::Identifier& node) override; - - using ShaderVarVisitor::Visit; - void Visit(ShaderNodes::InputVariable& var) override; - void Visit(ShaderNodes::UniformVariable& var) override; - - SpirvExpressionLoadAccessMember& operator=(const SpirvExpressionLoadAccessMember&) = delete; - SpirvExpressionLoadAccessMember& operator=(SpirvExpressionLoadAccessMember&&) = delete; - - private: - struct Pointer - { - SpirvStorageClass storage; - UInt32 resultId; - UInt32 pointedTypeId; - }; - - struct Value - { - UInt32 resultId; - }; - - SpirvWriter& m_writer; - std::variant m_value; - }; -} - -#include - -#endif diff --git a/include/Nazara/Shader/SpirvExpressionLoadAccessMember.inl b/include/Nazara/Shader/SpirvExpressionLoadAccessMember.inl deleted file mode 100644 index d81cfbb9c..000000000 --- a/include/Nazara/Shader/SpirvExpressionLoadAccessMember.inl +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (C) 2020 Jérôme Leclercq -// This file is part of the "Nazara Engine - Shader generator" -// For conditions of distribution and use, see copyright notice in Config.hpp - -#include -#include - -namespace Nz -{ - inline SpirvExpressionLoadAccessMember::SpirvExpressionLoadAccessMember(SpirvWriter& writer) : - m_writer(writer) - { - } -} - -#include diff --git a/include/Nazara/Shader/SpirvStatementVisitor.hpp b/include/Nazara/Shader/SpirvStatementVisitor.hpp deleted file mode 100644 index 1ba88942c..000000000 --- a/include/Nazara/Shader/SpirvStatementVisitor.hpp +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (C) 2020 Jérôme Leclercq -// This file is part of the "Nazara Engine - Shader generator" -// For conditions of distribution and use, see copyright notice in Config.hpp - -#pragma once - -#ifndef NAZARA_SPIRVSTATEMENTVISITOR_HPP -#define NAZARA_SPIRVSTATEMENTVISITOR_HPP - -#include -#include -#include - -namespace Nz -{ - class SpirvWriter; - - class NAZARA_SHADER_API SpirvStatementVisitor : public ShaderAstVisitorExcept - { - public: - inline SpirvStatementVisitor(SpirvWriter& writer); - SpirvStatementVisitor(const SpirvStatementVisitor&) = delete; - SpirvStatementVisitor(SpirvStatementVisitor&&) = delete; - ~SpirvStatementVisitor() = default; - - using ShaderAstVisitor::Visit; - void Visit(ShaderNodes::AssignOp& node) override; - void Visit(ShaderNodes::Branch& node) override; - void Visit(ShaderNodes::DeclareVariable& node) override; - void Visit(ShaderNodes::ExpressionStatement& node) override; - void Visit(ShaderNodes::StatementBlock& node) override; - - SpirvStatementVisitor& operator=(const SpirvStatementVisitor&) = delete; - SpirvStatementVisitor& operator=(SpirvStatementVisitor&&) = delete; - - private: - SpirvWriter& m_writer; - }; -} - -#include - -#endif diff --git a/include/Nazara/Shader/SpirvWriter.hpp b/include/Nazara/Shader/SpirvWriter.hpp index 8bb38087b..6b21de0ba 100644 --- a/include/Nazara/Shader/SpirvWriter.hpp +++ b/include/Nazara/Shader/SpirvWriter.hpp @@ -25,10 +25,10 @@ namespace Nz class NAZARA_SHADER_API SpirvWriter { + friend class SpirvAstVisitor; friend class SpirvExpressionLoad; - friend class SpirvExpressionLoadAccessMember; friend class SpirvExpressionStore; - friend class SpirvStatementVisitor; + friend class SpirvVisitor; public: struct Environment; diff --git a/src/Nazara/Shader/SpirvAstVisitor.cpp b/src/Nazara/Shader/SpirvAstVisitor.cpp new file mode 100644 index 000000000..d66f76170 --- /dev/null +++ b/src/Nazara/Shader/SpirvAstVisitor.cpp @@ -0,0 +1,433 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Shader generator" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + UInt32 SpirvAstVisitor::EvaluateExpression(const ShaderNodes::ExpressionPtr& expr) + { + Visit(expr); + return PopResultId(); + } + + void SpirvAstVisitor::Visit(ShaderNodes::AccessMember& node) + { + SpirvExpressionLoad accessMemberVisitor(m_writer); + PushResultId(accessMemberVisitor.Evaluate(node)); + } + + void SpirvAstVisitor::Visit(ShaderNodes::AssignOp& node) + { + UInt32 resultId = EvaluateExpression(node.right); + + SpirvExpressionStore storeVisitor(m_writer); + storeVisitor.Store(node.left, resultId); + + PushResultId(resultId); + } + + void SpirvAstVisitor::Visit(ShaderNodes::BinaryOp& node) + { + ShaderExpressionType resultExprType = node.GetExpressionType(); + assert(std::holds_alternative(resultExprType)); + + const ShaderExpressionType& leftExprType = node.left->GetExpressionType(); + assert(std::holds_alternative(leftExprType)); + + const ShaderExpressionType& rightExprType = node.right->GetExpressionType(); + assert(std::holds_alternative(rightExprType)); + + ShaderNodes::BasicType resultType = std::get(resultExprType); + ShaderNodes::BasicType leftType = std::get(leftExprType); + ShaderNodes::BasicType rightType = std::get(rightExprType); + + + UInt32 leftOperand = EvaluateExpression(node.left); + UInt32 rightOperand = EvaluateExpression(node.right); + UInt32 resultId = m_writer.AllocateResultId(); + + bool swapOperands = false; + + SpirvOp op = [&] + { + switch (node.op) + { + case ShaderNodes::BinaryType::Add: + { + switch (leftType) + { + case ShaderNodes::BasicType::Float1: + case ShaderNodes::BasicType::Float2: + case ShaderNodes::BasicType::Float3: + case ShaderNodes::BasicType::Float4: + case ShaderNodes::BasicType::Mat4x4: + return SpirvOp::OpFAdd; + + case ShaderNodes::BasicType::Int1: + case ShaderNodes::BasicType::Int2: + case ShaderNodes::BasicType::Int3: + case ShaderNodes::BasicType::Int4: + case ShaderNodes::BasicType::UInt1: + case ShaderNodes::BasicType::UInt2: + case ShaderNodes::BasicType::UInt3: + case ShaderNodes::BasicType::UInt4: + return SpirvOp::OpIAdd; + + case ShaderNodes::BasicType::Boolean: + case ShaderNodes::BasicType::Sampler2D: + case ShaderNodes::BasicType::Void: + break; + } + } + + case ShaderNodes::BinaryType::Substract: + { + switch (leftType) + { + case ShaderNodes::BasicType::Float1: + case ShaderNodes::BasicType::Float2: + case ShaderNodes::BasicType::Float3: + case ShaderNodes::BasicType::Float4: + case ShaderNodes::BasicType::Mat4x4: + return SpirvOp::OpFSub; + + case ShaderNodes::BasicType::Int1: + case ShaderNodes::BasicType::Int2: + case ShaderNodes::BasicType::Int3: + case ShaderNodes::BasicType::Int4: + case ShaderNodes::BasicType::UInt1: + case ShaderNodes::BasicType::UInt2: + case ShaderNodes::BasicType::UInt3: + case ShaderNodes::BasicType::UInt4: + return SpirvOp::OpISub; + + case ShaderNodes::BasicType::Boolean: + case ShaderNodes::BasicType::Sampler2D: + case ShaderNodes::BasicType::Void: + break; + } + } + + case ShaderNodes::BinaryType::Divide: + { + switch (leftType) + { + case ShaderNodes::BasicType::Float1: + case ShaderNodes::BasicType::Float2: + case ShaderNodes::BasicType::Float3: + case ShaderNodes::BasicType::Float4: + case ShaderNodes::BasicType::Mat4x4: + return SpirvOp::OpFDiv; + + case ShaderNodes::BasicType::Int1: + case ShaderNodes::BasicType::Int2: + case ShaderNodes::BasicType::Int3: + case ShaderNodes::BasicType::Int4: + return SpirvOp::OpSDiv; + + case ShaderNodes::BasicType::UInt1: + case ShaderNodes::BasicType::UInt2: + case ShaderNodes::BasicType::UInt3: + case ShaderNodes::BasicType::UInt4: + return SpirvOp::OpUDiv; + + case ShaderNodes::BasicType::Boolean: + case ShaderNodes::BasicType::Sampler2D: + case ShaderNodes::BasicType::Void: + break; + } + } + + case ShaderNodes::BinaryType::Equality: + { + switch (leftType) + { + case ShaderNodes::BasicType::Boolean: + return SpirvOp::OpLogicalEqual; + + case ShaderNodes::BasicType::Float1: + case ShaderNodes::BasicType::Float2: + case ShaderNodes::BasicType::Float3: + case ShaderNodes::BasicType::Float4: + case ShaderNodes::BasicType::Mat4x4: + return SpirvOp::OpFOrdEqual; + + case ShaderNodes::BasicType::Int1: + case ShaderNodes::BasicType::Int2: + case ShaderNodes::BasicType::Int3: + case ShaderNodes::BasicType::Int4: + case ShaderNodes::BasicType::UInt1: + case ShaderNodes::BasicType::UInt2: + case ShaderNodes::BasicType::UInt3: + case ShaderNodes::BasicType::UInt4: + return SpirvOp::OpIEqual; + + case ShaderNodes::BasicType::Sampler2D: + case ShaderNodes::BasicType::Void: + break; + } + } + + case ShaderNodes::BinaryType::Multiply: + { + switch (leftType) + { + case ShaderNodes::BasicType::Float1: + { + switch (rightType) + { + case ShaderNodes::BasicType::Float1: + return SpirvOp::OpFMul; + + case ShaderNodes::BasicType::Float2: + case ShaderNodes::BasicType::Float3: + case ShaderNodes::BasicType::Float4: + swapOperands = true; + return SpirvOp::OpVectorTimesScalar; + + case ShaderNodes::BasicType::Mat4x4: + swapOperands = true; + return SpirvOp::OpMatrixTimesScalar; + + default: + break; + } + + break; + } + + case ShaderNodes::BasicType::Float2: + case ShaderNodes::BasicType::Float3: + case ShaderNodes::BasicType::Float4: + { + switch (rightType) + { + case ShaderNodes::BasicType::Float1: + return SpirvOp::OpVectorTimesScalar; + + case ShaderNodes::BasicType::Float2: + case ShaderNodes::BasicType::Float3: + case ShaderNodes::BasicType::Float4: + return SpirvOp::OpFMul; + + case ShaderNodes::BasicType::Mat4x4: + return SpirvOp::OpVectorTimesMatrix; + + default: + break; + } + + break; + } + + case ShaderNodes::BasicType::Int1: + case ShaderNodes::BasicType::Int2: + case ShaderNodes::BasicType::Int3: + case ShaderNodes::BasicType::Int4: + case ShaderNodes::BasicType::UInt1: + case ShaderNodes::BasicType::UInt2: + case ShaderNodes::BasicType::UInt3: + case ShaderNodes::BasicType::UInt4: + return SpirvOp::OpIMul; + + case ShaderNodes::BasicType::Mat4x4: + { + switch (rightType) + { + case ShaderNodes::BasicType::Float1: return SpirvOp::OpMatrixTimesScalar; + case ShaderNodes::BasicType::Float4: return SpirvOp::OpMatrixTimesVector; + case ShaderNodes::BasicType::Mat4x4: return SpirvOp::OpMatrixTimesMatrix; + + default: + break; + } + + break; + } + + default: + break; + } + break; + } + } + + assert(false); + throw std::runtime_error("unexpected binary operation"); + }(); + + if (swapOperands) + std::swap(leftOperand, rightOperand); + + m_writer.GetInstructions().Append(op, m_writer.GetTypeId(resultType), resultId, leftOperand, rightOperand); + PushResultId(resultId); + } + + void SpirvAstVisitor::Visit(ShaderNodes::Cast& node) + { + const ShaderExpressionType& targetExprType = node.exprType; + assert(std::holds_alternative(targetExprType)); + + ShaderNodes::BasicType targetType = std::get(targetExprType); + + StackVector exprResults = NazaraStackVector(UInt32, node.expressions.size()); + + for (const auto& exprPtr : node.expressions) + { + if (!exprPtr) + break; + + exprResults.push_back(EvaluateExpression(exprPtr)); + } + + UInt32 resultId = m_writer.AllocateResultId(); + + m_writer.GetInstructions().AppendVariadic(SpirvOp::OpCompositeConstruct, [&](const auto& appender) + { + appender(m_writer.GetTypeId(targetType)); + appender(resultId); + + for (UInt32 exprResultId : exprResults) + appender(exprResultId); + }); + + PushResultId(resultId); + } + + void SpirvAstVisitor::Visit(ShaderNodes::Constant& node) + { + std::visit([&] (const auto& value) + { + PushResultId(m_writer.GetConstantId(value)); + }, node.value); + } + + void SpirvAstVisitor::Visit(ShaderNodes::DeclareVariable& node) + { + if (node.expression) + { + assert(node.variable->GetType() == ShaderNodes::VariableType::LocalVariable); + + const auto& localVar = static_cast(*node.variable); + m_writer.WriteLocalVariable(localVar.name, EvaluateExpression(node.expression)); + } + } + + void SpirvAstVisitor::Visit(ShaderNodes::ExpressionStatement& node) + { + Visit(node.expression); + PopResultId(); + } + + void SpirvAstVisitor::Visit(ShaderNodes::Identifier& node) + { + SpirvExpressionLoad loadVisitor(m_writer); + PushResultId(loadVisitor.Evaluate(node)); + } + + void SpirvAstVisitor::Visit(ShaderNodes::IntrinsicCall& node) + { + switch (node.intrinsic) + { + case ShaderNodes::IntrinsicType::DotProduct: + { + const ShaderExpressionType& vecExprType = node.parameters[0]->GetExpressionType(); + assert(std::holds_alternative(vecExprType)); + + ShaderNodes::BasicType vecType = std::get(vecExprType); + + UInt32 typeId = m_writer.GetTypeId(node.GetComponentType(vecType)); + + UInt32 vec1 = EvaluateExpression(node.parameters[0]); + UInt32 vec2 = EvaluateExpression(node.parameters[1]); + + UInt32 resultId = m_writer.AllocateResultId(); + + m_writer.GetInstructions().Append(SpirvOp::OpDot, typeId, resultId, vec1, vec2); + PushResultId(resultId); + break; + } + + case ShaderNodes::IntrinsicType::CrossProduct: + default: + throw std::runtime_error("not yet implemented"); + } + } + + void SpirvAstVisitor::Visit(ShaderNodes::Sample2D& node) + { + UInt32 typeId = m_writer.GetTypeId(ShaderNodes::BasicType::Float4); + + UInt32 samplerId = EvaluateExpression(node.sampler); + UInt32 coordinatesId = EvaluateExpression(node.coordinates); + UInt32 resultId = m_writer.AllocateResultId(); + + m_writer.GetInstructions().Append(SpirvOp::OpImageSampleImplicitLod, typeId, resultId, samplerId, coordinatesId); + PushResultId(resultId); + } + + void SpirvAstVisitor::Visit(ShaderNodes::StatementBlock& node) + { + for (auto& statement : node.statements) + Visit(statement); + } + + void SpirvAstVisitor::Visit(ShaderNodes::SwizzleOp& node) + { + const ShaderExpressionType& targetExprType = node.GetExpressionType(); + assert(std::holds_alternative(targetExprType)); + + ShaderNodes::BasicType targetType = std::get(targetExprType); + + UInt32 exprResultId = EvaluateExpression(node.expression); + UInt32 resultId = m_writer.AllocateResultId(); + + if (node.componentCount > 1) + { + // Swizzling is implemented via SpirvOp::OpVectorShuffle using the same vector twice as operands + m_writer.GetInstructions().AppendVariadic(SpirvOp::OpVectorShuffle, [&](const auto& appender) + { + appender(m_writer.GetTypeId(targetType)); + appender(resultId); + appender(exprResultId); + appender(exprResultId); + + for (std::size_t i = 0; i < node.componentCount; ++i) + appender(UInt32(node.components[0]) - UInt32(node.components[i])); + }); + } + else + { + // Extract a single component from the vector + assert(node.componentCount == 1); + + m_writer.GetInstructions().Append(SpirvOp::OpCompositeExtract, m_writer.GetTypeId(targetType), resultId, exprResultId, UInt32(node.components[0]) - UInt32(ShaderNodes::SwizzleComponent::First) ); + } + + PushResultId(resultId); + } + + void SpirvAstVisitor::PushResultId(UInt32 value) + { + m_resultIds.push_back(value); + } + + UInt32 SpirvAstVisitor::PopResultId() + { + if (m_resultIds.empty()) + throw std::runtime_error("invalid operation"); + + UInt32 resultId = m_resultIds.back(); + m_resultIds.pop_back(); + + return resultId; + } +} diff --git a/src/Nazara/Shader/SpirvExpressionLoad.cpp b/src/Nazara/Shader/SpirvExpressionLoad.cpp index b032326fb..00e7ad815 100644 --- a/src/Nazara/Shader/SpirvExpressionLoad.cpp +++ b/src/Nazara/Shader/SpirvExpressionLoad.cpp @@ -5,317 +5,88 @@ #include #include #include -#include -#include #include #include namespace Nz { + namespace + { + template struct overloaded : Ts... { using Ts::operator()...; }; + template overloaded(Ts...)->overloaded; + } + + UInt32 SpirvExpressionLoad::Evaluate(ShaderNodes::Expression& node) + { + node.Visit(*this); + + return std::visit(overloaded + { + [&](const Pointer& pointer) -> UInt32 + { + UInt32 resultId = m_writer.AllocateResultId(); + + m_writer.GetInstructions().Append(SpirvOp::OpLoad, pointer.pointedTypeId, resultId, pointer.resultId); + + return resultId; + }, + [&](const Value& value) -> UInt32 + { + return value.resultId; + }, + [this](std::monostate) -> UInt32 + { + throw std::runtime_error("an internal error occurred"); + } + }, m_value); + } + void SpirvExpressionLoad::Visit(ShaderNodes::AccessMember& node) { - SpirvExpressionLoadAccessMember accessMemberVisitor(m_writer); - PushResultId(accessMemberVisitor.EvaluateExpression(node)); - } + Visit(node.structExpr); - void SpirvExpressionLoad::Visit(ShaderNodes::AssignOp& node) - { - SpirvExpressionLoad loadVisitor(m_writer); - SpirvExpressionStore storeVisitor(m_writer); - storeVisitor.Store(node.left, EvaluateExpression(node.right)); - } - - void SpirvExpressionLoad::Visit(ShaderNodes::BinaryOp& node) - { - ShaderExpressionType resultExprType = node.GetExpressionType(); - assert(std::holds_alternative(resultExprType)); - - const ShaderExpressionType& leftExprType = node.left->GetExpressionType(); - assert(std::holds_alternative(leftExprType)); - - const ShaderExpressionType& rightExprType = node.right->GetExpressionType(); - assert(std::holds_alternative(rightExprType)); - - ShaderNodes::BasicType resultType = std::get(resultExprType); - ShaderNodes::BasicType leftType = std::get(leftExprType); - ShaderNodes::BasicType rightType = std::get(rightExprType); - - - UInt32 leftOperand = EvaluateExpression(node.left); - UInt32 rightOperand = EvaluateExpression(node.right); - UInt32 resultId = m_writer.AllocateResultId(); - - bool swapOperands = false; - - SpirvOp op = [&] + std::visit(overloaded { - switch (node.op) + [&](const Pointer& pointer) { - case ShaderNodes::BinaryType::Add: + UInt32 resultId = m_writer.AllocateResultId(); + UInt32 pointerType = m_writer.RegisterPointerType(node.exprType, pointer.storage); //< FIXME + UInt32 typeId = m_writer.GetTypeId(node.exprType); + + m_writer.GetInstructions().AppendVariadic(SpirvOp::OpAccessChain, [&](const auto& appender) { - switch (leftType) - { - case ShaderNodes::BasicType::Float1: - case ShaderNodes::BasicType::Float2: - case ShaderNodes::BasicType::Float3: - case ShaderNodes::BasicType::Float4: - case ShaderNodes::BasicType::Mat4x4: - return SpirvOp::OpFAdd; + appender(pointerType); + appender(resultId); + appender(pointer.resultId); - case ShaderNodes::BasicType::Int1: - case ShaderNodes::BasicType::Int2: - case ShaderNodes::BasicType::Int3: - case ShaderNodes::BasicType::Int4: - case ShaderNodes::BasicType::UInt1: - case ShaderNodes::BasicType::UInt2: - case ShaderNodes::BasicType::UInt3: - case ShaderNodes::BasicType::UInt4: - return SpirvOp::OpIAdd; + for (std::size_t index : node.memberIndices) + appender(m_writer.GetConstantId(Int32(index))); + }); - case ShaderNodes::BasicType::Boolean: - case ShaderNodes::BasicType::Sampler2D: - case ShaderNodes::BasicType::Void: - break; - } - } + m_value = Pointer { pointer.storage, resultId, typeId }; + }, + [&](const Value& value) + { + UInt32 resultId = m_writer.AllocateResultId(); + UInt32 typeId = m_writer.GetTypeId(node.exprType); - case ShaderNodes::BinaryType::Substract: + m_writer.GetInstructions().AppendVariadic(SpirvOp::OpCompositeExtract, [&](const auto& appender) { - switch (leftType) - { - case ShaderNodes::BasicType::Float1: - case ShaderNodes::BasicType::Float2: - case ShaderNodes::BasicType::Float3: - case ShaderNodes::BasicType::Float4: - case ShaderNodes::BasicType::Mat4x4: - return SpirvOp::OpFSub; + appender(typeId); + appender(resultId); + appender(value.resultId); - case ShaderNodes::BasicType::Int1: - case ShaderNodes::BasicType::Int2: - case ShaderNodes::BasicType::Int3: - case ShaderNodes::BasicType::Int4: - case ShaderNodes::BasicType::UInt1: - case ShaderNodes::BasicType::UInt2: - case ShaderNodes::BasicType::UInt3: - case ShaderNodes::BasicType::UInt4: - return SpirvOp::OpISub; + for (std::size_t index : node.memberIndices) + appender(m_writer.GetConstantId(Int32(index))); + }); - case ShaderNodes::BasicType::Boolean: - case ShaderNodes::BasicType::Sampler2D: - case ShaderNodes::BasicType::Void: - break; - } - } - - case ShaderNodes::BinaryType::Divide: - { - switch (leftType) - { - case ShaderNodes::BasicType::Float1: - case ShaderNodes::BasicType::Float2: - case ShaderNodes::BasicType::Float3: - case ShaderNodes::BasicType::Float4: - case ShaderNodes::BasicType::Mat4x4: - return SpirvOp::OpFDiv; - - case ShaderNodes::BasicType::Int1: - case ShaderNodes::BasicType::Int2: - case ShaderNodes::BasicType::Int3: - case ShaderNodes::BasicType::Int4: - return SpirvOp::OpSDiv; - - case ShaderNodes::BasicType::UInt1: - case ShaderNodes::BasicType::UInt2: - case ShaderNodes::BasicType::UInt3: - case ShaderNodes::BasicType::UInt4: - return SpirvOp::OpUDiv; - - case ShaderNodes::BasicType::Boolean: - case ShaderNodes::BasicType::Sampler2D: - case ShaderNodes::BasicType::Void: - break; - } - } - - case ShaderNodes::BinaryType::Equality: - { - switch (leftType) - { - case ShaderNodes::BasicType::Boolean: - return SpirvOp::OpLogicalEqual; - - case ShaderNodes::BasicType::Float1: - case ShaderNodes::BasicType::Float2: - case ShaderNodes::BasicType::Float3: - case ShaderNodes::BasicType::Float4: - case ShaderNodes::BasicType::Mat4x4: - return SpirvOp::OpFOrdEqual; - - case ShaderNodes::BasicType::Int1: - case ShaderNodes::BasicType::Int2: - case ShaderNodes::BasicType::Int3: - case ShaderNodes::BasicType::Int4: - case ShaderNodes::BasicType::UInt1: - case ShaderNodes::BasicType::UInt2: - case ShaderNodes::BasicType::UInt3: - case ShaderNodes::BasicType::UInt4: - return SpirvOp::OpIEqual; - - case ShaderNodes::BasicType::Sampler2D: - case ShaderNodes::BasicType::Void: - break; - } - } - - case ShaderNodes::BinaryType::Multiply: - { - switch (leftType) - { - case ShaderNodes::BasicType::Float1: - { - switch (rightType) - { - case ShaderNodes::BasicType::Float1: - return SpirvOp::OpFMul; - - case ShaderNodes::BasicType::Float2: - case ShaderNodes::BasicType::Float3: - case ShaderNodes::BasicType::Float4: - swapOperands = true; - return SpirvOp::OpVectorTimesScalar; - - case ShaderNodes::BasicType::Mat4x4: - swapOperands = true; - return SpirvOp::OpMatrixTimesScalar; - - default: - break; - } - - break; - } - - case ShaderNodes::BasicType::Float2: - case ShaderNodes::BasicType::Float3: - case ShaderNodes::BasicType::Float4: - { - switch (rightType) - { - case ShaderNodes::BasicType::Float1: - return SpirvOp::OpVectorTimesScalar; - - case ShaderNodes::BasicType::Float2: - case ShaderNodes::BasicType::Float3: - case ShaderNodes::BasicType::Float4: - return SpirvOp::OpFMul; - - case ShaderNodes::BasicType::Mat4x4: - return SpirvOp::OpVectorTimesMatrix; - - default: - break; - } - - break; - } - - case ShaderNodes::BasicType::Int1: - case ShaderNodes::BasicType::Int2: - case ShaderNodes::BasicType::Int3: - case ShaderNodes::BasicType::Int4: - case ShaderNodes::BasicType::UInt1: - case ShaderNodes::BasicType::UInt2: - case ShaderNodes::BasicType::UInt3: - case ShaderNodes::BasicType::UInt4: - return SpirvOp::OpIMul; - - case ShaderNodes::BasicType::Mat4x4: - { - switch (rightType) - { - case ShaderNodes::BasicType::Float1: return SpirvOp::OpMatrixTimesScalar; - case ShaderNodes::BasicType::Float4: return SpirvOp::OpMatrixTimesVector; - case ShaderNodes::BasicType::Mat4x4: return SpirvOp::OpMatrixTimesMatrix; - - default: - break; - } - - break; - } - - default: - break; - } - break; - } + m_value = Value { resultId }; + }, + [this](std::monostate) + { + throw std::runtime_error("an internal error occurred"); } - - assert(false); - throw std::runtime_error("unexpected binary operation"); - }(); - - if (swapOperands) - std::swap(leftOperand, rightOperand); - - m_writer.GetInstructions().Append(op, m_writer.GetTypeId(resultType), resultId, leftOperand, rightOperand); - PushResultId(resultId); - } - - void SpirvExpressionLoad::Visit(ShaderNodes::Cast& node) - { - const ShaderExpressionType& targetExprType = node.exprType; - assert(std::holds_alternative(targetExprType)); - - ShaderNodes::BasicType targetType = std::get(targetExprType); - - StackVector exprResults = NazaraStackVector(UInt32, node.expressions.size()); - - for (const auto& exprPtr : node.expressions) - { - if (!exprPtr) - break; - - exprResults.push_back(EvaluateExpression(exprPtr)); - } - - UInt32 resultId = m_writer.AllocateResultId(); - - m_writer.GetInstructions().AppendVariadic(SpirvOp::OpCompositeConstruct, [&](const auto& appender) - { - appender(m_writer.GetTypeId(targetType)); - appender(resultId); - - for (UInt32 exprResultId : exprResults) - appender(exprResultId); - }); - - PushResultId(resultId); - } - - void SpirvExpressionLoad::Visit(ShaderNodes::Constant& node) - { - std::visit([&] (const auto& value) - { - PushResultId(m_writer.GetConstantId(value)); - }, node.value); - } - - void SpirvExpressionLoad::Visit(ShaderNodes::DeclareVariable& node) - { - if (node.expression) - { - assert(node.variable->GetType() == ShaderNodes::VariableType::LocalVariable); - - const auto& localVar = static_cast(*node.variable); - m_writer.WriteLocalVariable(localVar.name, EvaluateExpression(node.expression)); - } - } - - void SpirvExpressionLoad::Visit(ShaderNodes::ExpressionStatement& node) - { - Visit(node.expression); - PopResultId(); + }, m_value); } void SpirvExpressionLoad::Visit(ShaderNodes::Identifier& node) @@ -323,126 +94,28 @@ namespace Nz Visit(node.var); } - void SpirvExpressionLoad::Visit(ShaderNodes::IntrinsicCall& node) - { - switch (node.intrinsic) - { - case ShaderNodes::IntrinsicType::DotProduct: - { - const ShaderExpressionType& vecExprType = node.parameters[0]->GetExpressionType(); - assert(std::holds_alternative(vecExprType)); - - ShaderNodes::BasicType vecType = std::get(vecExprType); - - UInt32 typeId = m_writer.GetTypeId(node.GetComponentType(vecType)); - - UInt32 vec1 = EvaluateExpression(node.parameters[0]); - UInt32 vec2 = EvaluateExpression(node.parameters[1]); - - UInt32 resultId = m_writer.AllocateResultId(); - - m_writer.GetInstructions().Append(SpirvOp::OpDot, typeId, resultId, vec1, vec2); - PushResultId(resultId); - break; - } - - case ShaderNodes::IntrinsicType::CrossProduct: - default: - throw std::runtime_error("not yet implemented"); - } - } - - void SpirvExpressionLoad::Visit(ShaderNodes::Sample2D& node) - { - UInt32 typeId = m_writer.GetTypeId(ShaderNodes::BasicType::Float4); - - UInt32 samplerId = EvaluateExpression(node.sampler); - UInt32 coordinatesId = EvaluateExpression(node.coordinates); - UInt32 resultId = m_writer.AllocateResultId(); - - m_writer.GetInstructions().Append(SpirvOp::OpImageSampleImplicitLod, typeId, resultId, samplerId, coordinatesId); - PushResultId(resultId); - } - - void SpirvExpressionLoad::Visit(ShaderNodes::SwizzleOp& node) - { - const ShaderExpressionType& targetExprType = node.GetExpressionType(); - assert(std::holds_alternative(targetExprType)); - - ShaderNodes::BasicType targetType = std::get(targetExprType); - - UInt32 exprResultId = EvaluateExpression(node.expression); - UInt32 resultId = m_writer.AllocateResultId(); - - if (node.componentCount > 1) - { - // Swizzling is implemented via SpirvOp::OpVectorShuffle using the same vector twice as operands - m_writer.GetInstructions().AppendVariadic(SpirvOp::OpVectorShuffle, [&](const auto& appender) - { - appender(m_writer.GetTypeId(targetType)); - appender(resultId); - appender(exprResultId); - appender(exprResultId); - - for (std::size_t i = 0; i < node.componentCount; ++i) - appender(UInt32(node.components[0]) - UInt32(node.components[i])); - }); - } - else - { - // Extract a single component from the vector - assert(node.componentCount == 1); - - m_writer.GetInstructions().Append(SpirvOp::OpCompositeExtract, m_writer.GetTypeId(targetType), resultId, exprResultId, UInt32(node.components[0]) - UInt32(ShaderNodes::SwizzleComponent::First) ); - } - - PushResultId(resultId); - } - - void SpirvExpressionLoad::Visit(ShaderNodes::BuiltinVariable& /*var*/) - { - throw std::runtime_error("not implemented yet"); - } - void SpirvExpressionLoad::Visit(ShaderNodes::InputVariable& var) { - PushResultId(m_writer.ReadInputVariable(var.name)); + auto inputVar = m_writer.GetInputVariable(var.name); + + if (auto resultIdOpt = m_writer.ReadVariable(inputVar, SpirvWriter::OnlyCache{})) + m_value = Value{ *resultIdOpt }; + else + m_value = Pointer{ SpirvStorageClass::Input, inputVar.varId, inputVar.typeId }; } void SpirvExpressionLoad::Visit(ShaderNodes::LocalVariable& var) { - PushResultId(m_writer.ReadLocalVariable(var.name)); - } - - void SpirvExpressionLoad::Visit(ShaderNodes::ParameterVariable& /*var*/) - { - throw std::runtime_error("not implemented yet"); + m_value = Value{ m_writer.ReadLocalVariable(var.name) }; } void SpirvExpressionLoad::Visit(ShaderNodes::UniformVariable& var) { - PushResultId(m_writer.ReadUniformVariable(var.name)); - } + auto uniformVar = m_writer.GetUniformVariable(var.name); - UInt32 SpirvExpressionLoad::EvaluateExpression(const ShaderNodes::ExpressionPtr& expr) - { - Visit(expr); - return PopResultId(); - } - - void SpirvExpressionLoad::PushResultId(UInt32 value) - { - m_resultIds.push_back(value); - } - - UInt32 SpirvExpressionLoad::PopResultId() - { - if (m_resultIds.empty()) - throw std::runtime_error("invalid operation"); - - UInt32 resultId = m_resultIds.back(); - m_resultIds.pop_back(); - - return resultId; + if (auto resultIdOpt = m_writer.ReadVariable(uniformVar, SpirvWriter::OnlyCache{})) + m_value = Value{ *resultIdOpt }; + else + m_value = Pointer{ SpirvStorageClass::Uniform, uniformVar.varId, uniformVar.typeId }; } } diff --git a/src/Nazara/Shader/SpirvExpressionLoadAccessMember.cpp b/src/Nazara/Shader/SpirvExpressionLoadAccessMember.cpp deleted file mode 100644 index c59bd806d..000000000 --- a/src/Nazara/Shader/SpirvExpressionLoadAccessMember.cpp +++ /dev/null @@ -1,116 +0,0 @@ -// Copyright (C) 2020 Jérôme Leclercq -// This file is part of the "Nazara Engine - Shader generator" -// For conditions of distribution and use, see copyright notice in Config.hpp - -#include -#include -#include -#include -#include - -namespace Nz -{ - namespace - { - template struct overloaded : Ts... { using Ts::operator()...; }; - template overloaded(Ts...)->overloaded; - } - - UInt32 SpirvExpressionLoadAccessMember::EvaluateExpression(ShaderNodes::AccessMember& expr) - { - Visit(expr); - - return std::visit(overloaded - { - [&](const Pointer& pointer) -> UInt32 - { - UInt32 resultId = m_writer.AllocateResultId(); - - m_writer.GetInstructions().Append(SpirvOp::OpLoad, pointer.pointedTypeId, resultId, pointer.resultId); - - return resultId; - }, - [&](const Value& value) -> UInt32 - { - return value.resultId; - }, - [this](std::monostate) -> UInt32 - { - throw std::runtime_error("an internal error occurred"); - } - }, m_value); - } - - void SpirvExpressionLoadAccessMember::Visit(ShaderNodes::AccessMember& node) - { - Visit(node.structExpr); - - std::visit(overloaded - { - [&](const Pointer& pointer) - { - UInt32 resultId = m_writer.AllocateResultId(); - UInt32 pointerType = m_writer.RegisterPointerType(node.exprType, pointer.storage); //< FIXME - UInt32 typeId = m_writer.GetTypeId(node.exprType); - - m_writer.GetInstructions().AppendVariadic(SpirvOp::OpAccessChain, [&](const auto& appender) - { - appender(pointerType); - appender(resultId); - appender(pointer.resultId); - - for (std::size_t index : node.memberIndices) - appender(m_writer.GetConstantId(Int32(index))); - }); - - m_value = Pointer { pointer.storage, resultId, typeId }; - }, - [&](const Value& value) - { - UInt32 resultId = m_writer.AllocateResultId(); - UInt32 typeId = m_writer.GetTypeId(node.exprType); - - m_writer.GetInstructions().AppendVariadic(SpirvOp::OpCompositeExtract, [&](const auto& appender) - { - appender(typeId); - appender(resultId); - appender(value.resultId); - - for (std::size_t index : node.memberIndices) - appender(m_writer.GetConstantId(Int32(index))); - }); - - m_value = Value { resultId }; - }, - [this](std::monostate) - { - throw std::runtime_error("an internal error occurred"); - } - }, m_value); - } - - void SpirvExpressionLoadAccessMember::Visit(ShaderNodes::Identifier& node) - { - Visit(node.var); - } - - void SpirvExpressionLoadAccessMember::Visit(ShaderNodes::InputVariable& var) - { - auto inputVar = m_writer.GetInputVariable(var.name); - - if (auto resultIdOpt = m_writer.ReadVariable(inputVar, SpirvWriter::OnlyCache{})) - m_value = Value{ *resultIdOpt }; - else - m_value = Pointer{ SpirvStorageClass::Input, inputVar.varId, inputVar.typeId }; - } - - void SpirvExpressionLoadAccessMember::Visit(ShaderNodes::UniformVariable& var) - { - auto uniformVar = m_writer.GetUniformVariable(var.name); - - if (auto resultIdOpt = m_writer.ReadVariable(uniformVar, SpirvWriter::OnlyCache{})) - m_value = Value{ *resultIdOpt }; - else - m_value = Pointer{ SpirvStorageClass::Uniform, uniformVar.varId, uniformVar.typeId }; - } -} diff --git a/src/Nazara/Shader/SpirvStatementVisitor.cpp b/src/Nazara/Shader/SpirvStatementVisitor.cpp deleted file mode 100644 index 312879375..000000000 --- a/src/Nazara/Shader/SpirvStatementVisitor.cpp +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright (C) 2020 Jérôme Leclercq -// This file is part of the "Nazara Engine - Shader generator" -// For conditions of distribution and use, see copyright notice in Config.hpp - -#include -#include -#include -#include -#include - -namespace Nz -{ - void SpirvStatementVisitor::Visit(ShaderNodes::AssignOp& node) - { - SpirvExpressionLoad loadVisitor(m_writer); - SpirvExpressionStore storeVisitor(m_writer); - storeVisitor.Store(node.left, loadVisitor.EvaluateExpression(node.right)); - } - - void SpirvStatementVisitor::Visit(ShaderNodes::Branch& node) - { - throw std::runtime_error("not yet implemented"); - } - - void SpirvStatementVisitor::Visit(ShaderNodes::DeclareVariable& node) - { - if (node.expression) - { - assert(node.variable->GetType() == ShaderNodes::VariableType::LocalVariable); - - const auto& localVar = static_cast(*node.variable); - - SpirvExpressionLoad loadVisitor(m_writer); - m_writer.WriteLocalVariable(localVar.name, loadVisitor.EvaluateExpression(node.expression)); - } - } - - void SpirvStatementVisitor::Visit(ShaderNodes::ExpressionStatement& node) - { - SpirvExpressionLoad loadVisitor(m_writer); - loadVisitor.Visit(node.expression); - } - - void SpirvStatementVisitor::Visit(ShaderNodes::StatementBlock& node) - { - for (auto& statement : node.statements) - Visit(statement); - } -} diff --git a/src/Nazara/Shader/SpirvWriter.cpp b/src/Nazara/Shader/SpirvWriter.cpp index 8412a1491..81f9d1d7f 100644 --- a/src/Nazara/Shader/SpirvWriter.cpp +++ b/src/Nazara/Shader/SpirvWriter.cpp @@ -7,10 +7,10 @@ #include #include #include +#include #include #include #include -#include #include #include #include @@ -380,7 +380,7 @@ namespace Nz state.instructions.Append(SpirvOp::OpFunctionParameter, GetTypeId(param.type), paramResultId); } - SpirvStatementVisitor visitor(*this); + SpirvAstVisitor visitor(*this); visitor.Visit(functionStatements[funcIndex]); if (func.returnType == ShaderNodes::BasicType::Void)