Big SpirVWriter refactor

This commit is contained in:
Jérôme Leclercq 2020-08-23 18:32:28 +02:00
parent 66a14721cb
commit 93de44d293
22 changed files with 1604 additions and 618 deletions

View File

@ -4,8 +4,8 @@
#pragma once
#ifndef NAZARA_SHADERVISITOR_HPP
#define NAZARA_SHADERVISITOR_HPP
#ifndef NAZARA_SHADERASTVISITOR_HPP
#define NAZARA_SHADERASTVISITOR_HPP
#include <Nazara/Prerequisites.hpp>
#include <Nazara/Shader/Config.hpp>

View File

@ -0,0 +1,36 @@
// 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_SHADERASTVISITOREXCEPT_HPP
#define NAZARA_SHADERASTVISITOREXCEPT_HPP
#include <Nazara/Prerequisites.hpp>
#include <Nazara/Shader/Config.hpp>
#include <Nazara/Shader/ShaderAstVisitor.hpp>
namespace Nz
{
class NAZARA_SHADER_API ShaderAstVisitorExcept : public ShaderAstVisitor
{
public:
using ShaderAstVisitor::Visit;
void Visit(ShaderNodes::AccessMember& node) override;
void Visit(ShaderNodes::AssignOp& node) override;
void Visit(ShaderNodes::BinaryOp& node) override;
void Visit(ShaderNodes::Branch& 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;
};
}
#endif

View File

@ -0,0 +1,28 @@
// Copyright (C) 2015 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_SHADERVARVISITOREXCEPT_HPP
#define NAZARA_SHADERVARVISITOREXCEPT_HPP
#include <Nazara/Prerequisites.hpp>
#include <Nazara/Shader/ShaderVarVisitor.hpp>
namespace Nz
{
class NAZARA_SHADER_API ShaderVarVisitorExcept : public ShaderVarVisitor
{
public:
using ShaderVarVisitor::Visit;
void Visit(ShaderNodes::BuiltinVariable& var) override;
void Visit(ShaderNodes::InputVariable& var) override;
void Visit(ShaderNodes::LocalVariable& var) override;
void Visit(ShaderNodes::OutputVariable& var) override;
void Visit(ShaderNodes::ParameterVariable& var) override;
void Visit(ShaderNodes::UniformVariable& var) override;
};
}
#endif

View File

@ -0,0 +1,64 @@
// 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 <Nazara/Prerequisites.hpp>
#include <Nazara/Shader/Config.hpp>
#include <Nazara/Shader/ShaderAstVisitorExcept.hpp>
#include <Nazara/Shader/ShaderVarVisitorExcept.hpp>
#include <vector>
namespace Nz
{
class SpirvWriter;
class NAZARA_SHADER_API SpirvExpressionLoad : public ShaderAstVisitorExcept, public ShaderVarVisitorExcept
{
public:
inline SpirvExpressionLoad(SpirvWriter& writer);
SpirvExpressionLoad(const SpirvExpressionLoad&) = delete;
SpirvExpressionLoad(SpirvExpressionLoad&&) = delete;
~SpirvExpressionLoad() = 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::SwizzleOp& node) override;
using ShaderVarVisitorExcept::Visit;
void Visit(ShaderNodes::BuiltinVariable& var) override;
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();
std::vector<UInt32> m_resultIds;
SpirvWriter& m_writer;
};
}
#include <Nazara/Shader/SpirvExpressionLoad.inl>
#endif

View File

@ -0,0 +1,16 @@
// 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 <Nazara/Shader/SpirvExpressionLoad.hpp>
#include <Nazara/Shader/Debug.hpp>
namespace Nz
{
inline SpirvExpressionLoad::SpirvExpressionLoad(SpirvWriter& writer) :
m_writer(writer)
{
}
}
#include <Nazara/Shader/DebugOff.hpp>

View File

@ -0,0 +1,62 @@
// 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 <Nazara/Prerequisites.hpp>
#include <Nazara/Shader/Config.hpp>
#include <Nazara/Shader/ShaderAstVisitorExcept.hpp>
#include <Nazara/Shader/ShaderVarVisitorExcept.hpp>
#include <Nazara/Shader/SpirvData.hpp>
#include <vector>
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<std::monostate, Pointer, Value> m_value;
};
}
#include <Nazara/Shader/SpirvExpressionLoadAccessMember.inl>
#endif

View File

@ -0,0 +1,16 @@
// 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 <Nazara/Shader/SpirvExpressionLoadAccessMember.hpp>
#include <Nazara/Shader/Debug.hpp>
namespace Nz
{
inline SpirvExpressionLoadAccessMember::SpirvExpressionLoadAccessMember(SpirvWriter& writer) :
m_writer(writer)
{
}
}
#include <Nazara/Shader/DebugOff.hpp>

View File

@ -0,0 +1,63 @@
// 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_SPIRVEXPRESSIONSTORE_HPP
#define NAZARA_SPIRVEXPRESSIONSTORE_HPP
#include <Nazara/Prerequisites.hpp>
#include <Nazara/Shader/Config.hpp>
#include <Nazara/Shader/ShaderAstVisitorExcept.hpp>
#include <Nazara/Shader/ShaderVarVisitorExcept.hpp>
#include <Nazara/Shader/SpirvData.hpp>
namespace Nz
{
class SpirvSection;
class SpirvWriter;
class NAZARA_SHADER_API SpirvExpressionStore : public ShaderAstVisitorExcept, public ShaderVarVisitorExcept
{
public:
inline SpirvExpressionStore(SpirvWriter& writer);
SpirvExpressionStore(const SpirvExpressionStore&) = delete;
SpirvExpressionStore(SpirvExpressionStore&&) = delete;
~SpirvExpressionStore() = default;
void Store(const ShaderNodes::ExpressionPtr& node, UInt32 resultId);
using ShaderAstVisitorExcept::Visit;
void Visit(ShaderNodes::AccessMember& node) override;
void Visit(ShaderNodes::Identifier& node) override;
void Visit(ShaderNodes::SwizzleOp& node) override;
using ShaderVarVisitorExcept::Visit;
void Visit(ShaderNodes::BuiltinVariable& var) override;
void Visit(ShaderNodes::LocalVariable& var) override;
void Visit(ShaderNodes::OutputVariable& var) override;
SpirvExpressionStore& operator=(const SpirvExpressionStore&) = delete;
SpirvExpressionStore& operator=(SpirvExpressionStore&&) = delete;
private:
struct LocalVar
{
std::string varName;
};
struct Pointer
{
SpirvStorageClass storage;
UInt32 resultId;
};
SpirvWriter& m_writer;
std::variant<std::monostate, LocalVar, Pointer> m_value;
};
}
#include <Nazara/Shader/SpirvExpressionStore.inl>
#endif

View File

@ -0,0 +1,16 @@
// 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 <Nazara/Shader/SpirvExpressionStore.hpp>
#include <Nazara/Shader/Debug.hpp>
namespace Nz
{
inline SpirvExpressionStore::SpirvExpressionStore(SpirvWriter& writer) :
m_writer(writer)
{
}
}
#include <Nazara/Shader/DebugOff.hpp>

View File

@ -0,0 +1,42 @@
// 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_SPIRVPRINTER_HPP
#define NAZARA_SPIRVPRINTER_HPP
#include <Nazara/Prerequisites.hpp>
#include <Nazara/Shader/Config.hpp>
#include <string>
namespace Nz
{
class NAZARA_SHADER_API SpirvPrinter
{
public:
inline SpirvPrinter();
SpirvPrinter(const SpirvPrinter&) = default;
SpirvPrinter(SpirvPrinter&&) = default;
~SpirvPrinter() = default;
std::string Print(const UInt32* codepoints, std::size_t count);
SpirvPrinter& operator=(const SpirvPrinter&) = default;
SpirvPrinter& operator=(SpirvPrinter&&) = default;
private:
void AppendInstruction();
std::string ReadString();
UInt32 ReadWord();
struct State;
State* m_currentState;
};
}
#include <Nazara/Shader/SpirvPrinter.inl>
#endif

View File

@ -0,0 +1,16 @@
// 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 <Nazara/Shader/SpirvPrinter.hpp>
#include <Nazara/Shader/Debug.hpp>
namespace Nz
{
inline SpirvPrinter::SpirvPrinter() :
m_currentState(nullptr)
{
}
}
#include <Nazara/Shader/DebugOff.hpp>

View File

@ -0,0 +1,43 @@
// 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 <Nazara/Prerequisites.hpp>
#include <Nazara/Shader/Config.hpp>
#include <Nazara/Shader/ShaderAstVisitorExcept.hpp>
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 <Nazara/Shader/SpirvStatementVisitor.inl>
#endif

View File

@ -0,0 +1,16 @@
// 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 <Nazara/Shader/SpirvStatementVisitor.hpp>
#include <Nazara/Shader/Debug.hpp>
namespace Nz
{
inline SpirvStatementVisitor::SpirvStatementVisitor(SpirvWriter& writer) :
m_writer(writer)
{
}
}
#include <Nazara/Shader/DebugOff.hpp>

View File

@ -23,8 +23,13 @@ namespace Nz
{
class SpirvSection;
class NAZARA_SHADER_API SpirvWriter : public ShaderAstVisitor, public ShaderVarVisitor
class NAZARA_SHADER_API SpirvWriter
{
friend class SpirvExpressionLoad;
friend class SpirvExpressionLoadAccessMember;
friend class SpirvExpressionStore;
friend class SpirvStatementVisitor;
public:
struct Environment;
@ -45,49 +50,37 @@ namespace Nz
private:
struct ExtVar;
struct OnlyCache {};
UInt32 AllocateResultId();
void AppendHeader();
UInt32 EvaluateExpression(const ShaderNodes::ExpressionPtr& expr);
UInt32 GetConstantId(const ShaderConstantValue& value) const;
UInt32 GetFunctionTypeId(ShaderExpressionType retType, const std::vector<ShaderAst::FunctionParameter>& parameters);
const ExtVar& GetBuiltinVariable(ShaderNodes::BuiltinEntry builtin) const;
const ExtVar& GetInputVariable(const std::string& name) const;
const ExtVar& GetOutputVariable(const std::string& name) const;
const ExtVar& GetUniformVariable(const std::string& name) const;
SpirvSection& GetInstructions();
UInt32 GetPointerTypeId(const ShaderExpressionType& type, SpirvStorageClass storageClass) const;
UInt32 GetTypeId(const ShaderExpressionType& type) const;
void PushResultId(UInt32 value);
UInt32 PopResultId();
UInt32 ReadInputVariable(const std::string& name);
std::optional<UInt32> ReadInputVariable(const std::string& name, OnlyCache);
UInt32 ReadLocalVariable(const std::string& name);
std::optional<UInt32> ReadLocalVariable(const std::string& name, OnlyCache);
UInt32 ReadUniformVariable(const std::string& name);
std::optional<UInt32> ReadUniformVariable(const std::string& name, OnlyCache);
UInt32 ReadVariable(ExtVar& var);
std::optional<UInt32> ReadVariable(const ExtVar& var, OnlyCache);
UInt32 RegisterConstant(const ShaderConstantValue& value);
UInt32 RegisterFunctionType(ShaderExpressionType retType, const std::vector<ShaderAst::FunctionParameter>& parameters);
UInt32 RegisterPointerType(ShaderExpressionType type, SpirvStorageClass storageClass);
UInt32 RegisterType(ShaderExpressionType type);
using ShaderAstVisitor::Visit;
void Visit(ShaderNodes::AccessMember& node) override;
void Visit(ShaderNodes::AssignOp& node) override;
void Visit(ShaderNodes::Branch& 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;
using ShaderVarVisitor::Visit;
void Visit(ShaderNodes::BuiltinVariable& var) override;
void Visit(ShaderNodes::InputVariable& var) override;
void Visit(ShaderNodes::LocalVariable& var) override;
void Visit(ShaderNodes::OutputVariable& var) override;
void Visit(ShaderNodes::ParameterVariable& var) override;
void Visit(ShaderNodes::UniformVariable& var) override;
void WriteLocalVariable(std::string name, UInt32 resultId);
static void MergeBlocks(std::vector<UInt32>& output, const SpirvSection& from);
@ -97,6 +90,14 @@ namespace Nz
const ShaderAst::Function* currentFunction = nullptr;
};
struct ExtVar
{
UInt32 pointerTypeId;
UInt32 typeId;
UInt32 varId;
std::optional<UInt32> valueId;
};
struct State;
Context m_context;

View File

@ -0,0 +1,75 @@
// 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 <Nazara/Shader/ShaderAstVisitorExcept.hpp>
#include <stdexcept>
#include <Nazara/Shader/Debug.hpp>
namespace Nz
{
void ShaderAstVisitorExcept::Visit(ShaderNodes::AccessMember& node)
{
throw std::runtime_error("unhandled AccessMember node");
}
void ShaderAstVisitorExcept::Visit(ShaderNodes::AssignOp& node)
{
throw std::runtime_error("unhandled AssignOp node");
}
void ShaderAstVisitorExcept::Visit(ShaderNodes::BinaryOp& node)
{
throw std::runtime_error("unhandled AccessMember node");
}
void ShaderAstVisitorExcept::Visit(ShaderNodes::Branch& node)
{
throw std::runtime_error("unhandled Branch node");
}
void ShaderAstVisitorExcept::Visit(ShaderNodes::Cast& node)
{
throw std::runtime_error("unhandled Cast node");
}
void ShaderAstVisitorExcept::Visit(ShaderNodes::Constant& node)
{
throw std::runtime_error("unhandled Constant node");
}
void ShaderAstVisitorExcept::Visit(ShaderNodes::DeclareVariable& node)
{
throw std::runtime_error("unhandled DeclareVariable node");
}
void ShaderAstVisitorExcept::Visit(ShaderNodes::ExpressionStatement& node)
{
throw std::runtime_error("unhandled ExpressionStatement node");
}
void ShaderAstVisitorExcept::Visit(ShaderNodes::Identifier& node)
{
throw std::runtime_error("unhandled Identifier node");
}
void ShaderAstVisitorExcept::Visit(ShaderNodes::IntrinsicCall& node)
{
throw std::runtime_error("unhandled IntrinsicCall node");
}
void ShaderAstVisitorExcept::Visit(ShaderNodes::Sample2D& node)
{
throw std::runtime_error("unhandled Sample2D node");
}
void ShaderAstVisitorExcept::Visit(ShaderNodes::StatementBlock& node)
{
throw std::runtime_error("unhandled StatementBlock node");
}
void ShaderAstVisitorExcept::Visit(ShaderNodes::SwizzleOp& node)
{
throw std::runtime_error("unhandled SwizzleOp node");
}
}

View File

@ -0,0 +1,40 @@
// 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 <Nazara/Shader/ShaderVarVisitorExcept.hpp>
#include <stdexcept>
#include <Nazara/Shader/Debug.hpp>
namespace Nz
{
void ShaderVarVisitorExcept::Visit(ShaderNodes::BuiltinVariable& var)
{
throw std::runtime_error("unhandled BuiltinVariable");
}
void ShaderVarVisitorExcept::Visit(ShaderNodes::InputVariable& var)
{
throw std::runtime_error("unhandled InputVariable");
}
void ShaderVarVisitorExcept::Visit(ShaderNodes::LocalVariable& var)
{
throw std::runtime_error("unhandled LocalVariable");
}
void ShaderVarVisitorExcept::Visit(ShaderNodes::OutputVariable& var)
{
throw std::runtime_error("unhandled OutputVariable");
}
void ShaderVarVisitorExcept::Visit(ShaderNodes::ParameterVariable& var)
{
throw std::runtime_error("unhandled ParameterVariable");
}
void ShaderVarVisitorExcept::Visit(ShaderNodes::UniformVariable& var)
{
throw std::runtime_error("unhandled UniformVariable");
}
}

View File

@ -0,0 +1,448 @@
// 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 <Nazara/Shader/SpirvExpressionLoad.hpp>
#include <Nazara/Core/StackVector.hpp>
#include <Nazara/Shader/SpirvSection.hpp>
#include <Nazara/Shader/SpirvExpressionLoadAccessMember.hpp>
#include <Nazara/Shader/SpirvExpressionStore.hpp>
#include <Nazara/Shader/SpirvWriter.hpp>
#include <Nazara/Shader/Debug.hpp>
namespace Nz
{
void SpirvExpressionLoad::Visit(ShaderNodes::AccessMember& node)
{
SpirvExpressionLoadAccessMember accessMemberVisitor(m_writer);
PushResultId(accessMemberVisitor.EvaluateExpression(node));
}
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<ShaderNodes::BasicType>(resultExprType));
const ShaderExpressionType& leftExprType = node.left->GetExpressionType();
assert(std::holds_alternative<ShaderNodes::BasicType>(leftExprType));
const ShaderExpressionType& rightExprType = node.right->GetExpressionType();
assert(std::holds_alternative<ShaderNodes::BasicType>(rightExprType));
ShaderNodes::BasicType resultType = std::get<ShaderNodes::BasicType>(resultExprType);
ShaderNodes::BasicType leftType = std::get<ShaderNodes::BasicType>(leftExprType);
ShaderNodes::BasicType rightType = std::get<ShaderNodes::BasicType>(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 SpirvExpressionLoad::Visit(ShaderNodes::Cast& node)
{
const ShaderExpressionType& targetExprType = node.exprType;
assert(std::holds_alternative<ShaderNodes::BasicType>(targetExprType));
ShaderNodes::BasicType targetType = std::get<ShaderNodes::BasicType>(targetExprType);
StackVector<UInt32> 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<const ShaderNodes::LocalVariable&>(*node.variable);
m_writer.WriteLocalVariable(localVar.name, EvaluateExpression(node.expression));
}
}
void SpirvExpressionLoad::Visit(ShaderNodes::ExpressionStatement& node)
{
Visit(node.expression);
PopResultId();
}
void SpirvExpressionLoad::Visit(ShaderNodes::Identifier& node)
{
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<ShaderNodes::BasicType>(vecExprType));
ShaderNodes::BasicType vecType = std::get<ShaderNodes::BasicType>(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<ShaderNodes::BasicType>(targetExprType));
ShaderNodes::BasicType targetType = std::get<ShaderNodes::BasicType>(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));
}
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");
}
void SpirvExpressionLoad::Visit(ShaderNodes::UniformVariable& var)
{
PushResultId(m_writer.ReadUniformVariable(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;
}
}

View File

@ -0,0 +1,116 @@
// 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 <Nazara/Shader/SpirvExpressionLoadAccessMember.hpp>
#include <Nazara/Core/StackVector.hpp>
#include <Nazara/Shader/SpirvSection.hpp>
#include <Nazara/Shader/SpirvWriter.hpp>
#include <Nazara/Shader/Debug.hpp>
namespace Nz
{
namespace
{
template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
template<class... Ts> overloaded(Ts...)->overloaded<Ts...>;
}
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 };
}
}

View File

@ -0,0 +1,104 @@
// 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 <Nazara/Shader/SpirvExpressionStore.hpp>
#include <Nazara/Shader/SpirvSection.hpp>
#include <Nazara/Shader/SpirvWriter.hpp>
#include <Nazara/Shader/Debug.hpp>
namespace Nz
{
namespace
{
template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
template<class... Ts> overloaded(Ts...)->overloaded<Ts...>;
}
void SpirvExpressionStore::Store(const ShaderNodes::ExpressionPtr& node, UInt32 resultId)
{
Visit(node);
std::visit(overloaded
{
[&](const Pointer& pointer)
{
m_writer.GetInstructions().Append(SpirvOp::OpStore, pointer.resultId, resultId);
},
[&](const LocalVar& value)
{
m_writer.WriteLocalVariable(value.varName, resultId);
},
[this](std::monostate)
{
throw std::runtime_error("an internal error occurred");
}
}, m_value);
}
void SpirvExpressionStore::Visit(ShaderNodes::AccessMember& node)
{
Visit(node.structExpr);
std::visit(overloaded
{
[&](const Pointer& pointer) -> UInt32
{
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 };
return resultId;
},
[&](const LocalVar& value) -> UInt32
{
throw std::runtime_error("not yet implemented");
},
[this](std::monostate) -> UInt32
{
throw std::runtime_error("an internal error occurred");
}
}, m_value);
}
void SpirvExpressionStore::Visit(ShaderNodes::Identifier& node)
{
Visit(node.var);
}
void SpirvExpressionStore::Visit(ShaderNodes::SwizzleOp& node)
{
throw std::runtime_error("not yet implemented");
}
void SpirvExpressionStore::Visit(ShaderNodes::BuiltinVariable& var)
{
const auto& outputVar = m_writer.GetBuiltinVariable(var.entry);
m_value = Pointer{ SpirvStorageClass::Output, outputVar.varId };
}
void SpirvExpressionStore::Visit(ShaderNodes::LocalVariable& var)
{
m_value = LocalVar{ var.name };
}
void SpirvExpressionStore::Visit(ShaderNodes::OutputVariable& var)
{
const auto& outputVar = m_writer.GetOutputVariable(var.name);
m_value = Pointer{ SpirvStorageClass::Output, outputVar.varId };
}
}

View File

@ -0,0 +1,231 @@
// 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 <Nazara/Shader/SpirvPrinter.hpp>
#include <Nazara/Core/CallOnExit.hpp>
#include <Nazara/Shader/SpirvData.hpp>
#include <SpirV/spirv.h>
#include <cassert>
#include <sstream>
#include <stdexcept>
#include <Nazara/Shader/Debug.hpp>
namespace Nz
{
struct SpirvPrinter::State
{
const UInt32* codepoints;
std::size_t index = 0;
std::size_t count;
std::ostringstream stream;
};
std::string SpirvPrinter::Print(const UInt32* codepoints, std::size_t count)
{
State state;
state.codepoints = codepoints;
state.count = count;
m_currentState = &state;
CallOnExit resetOnExit([&] { m_currentState = nullptr; });
UInt32 magicNumber = ReadWord();
if (magicNumber != SpvMagicNumber)
throw std::runtime_error("invalid Spir-V: magic number didn't match");
m_currentState->stream << "Spir-V module\n";
UInt32 versionNumber = ReadWord();
if (versionNumber > SpvVersion)
throw std::runtime_error("Spir-V is more recent than printer, dismissing");
UInt8 majorVersion = ((versionNumber) >> 16) & 0xFF;
UInt8 minorVersion = ((versionNumber) >> 8) & 0xFF;
m_currentState->stream << "Version " + std::to_string(+majorVersion) << "." << std::to_string(+minorVersion) << "\n";
UInt32 generatorId = ReadWord();
m_currentState->stream << "Generator: " << std::to_string(generatorId) << "\n";
UInt32 bound = ReadWord();
m_currentState->stream << "Bound: " << std::to_string(bound) << "\n";
UInt32 schema = ReadWord();
m_currentState->stream << "Schema: " << std::to_string(schema) << "\n";
while (m_currentState->index < m_currentState->count)
AppendInstruction();
return m_currentState->stream.str();
}
void SpirvPrinter::AppendInstruction()
{
std::size_t startIndex = m_currentState->index;
UInt32 firstWord = ReadWord();
UInt16 wordCount = static_cast<UInt16>((firstWord >> 16) & 0xFFFF);
UInt16 opcode = static_cast<UInt16>(firstWord & 0xFFFF);
const SpirvInstruction* inst = GetInstructionData(opcode);
if (!inst)
throw std::runtime_error("invalid instruction");
m_currentState->stream << inst->name;
std::size_t currentOperand = 0;
std::size_t instructionEnd = startIndex + wordCount;
while (m_currentState->index < instructionEnd)
{
const SpirvInstruction::Operand* operand = &inst->operands[currentOperand];
m_currentState->stream << " " << operand->name << "(";
switch (operand->kind)
{
case SpirvOperandKind::ImageOperands:
case SpirvOperandKind::FPFastMathMode:
case SpirvOperandKind::SelectionControl:
case SpirvOperandKind::LoopControl:
case SpirvOperandKind::FunctionControl:
case SpirvOperandKind::MemorySemantics:
case SpirvOperandKind::MemoryAccess:
case SpirvOperandKind::KernelProfilingInfo:
case SpirvOperandKind::RayFlags:
case SpirvOperandKind::SourceLanguage:
case SpirvOperandKind::ExecutionModel:
case SpirvOperandKind::AddressingModel:
case SpirvOperandKind::MemoryModel:
case SpirvOperandKind::ExecutionMode:
case SpirvOperandKind::StorageClass:
case SpirvOperandKind::Dim:
case SpirvOperandKind::SamplerAddressingMode:
case SpirvOperandKind::SamplerFilterMode:
case SpirvOperandKind::ImageFormat:
case SpirvOperandKind::ImageChannelOrder:
case SpirvOperandKind::ImageChannelDataType:
case SpirvOperandKind::FPRoundingMode:
case SpirvOperandKind::LinkageType:
case SpirvOperandKind::AccessQualifier:
case SpirvOperandKind::FunctionParameterAttribute:
case SpirvOperandKind::Decoration:
case SpirvOperandKind::BuiltIn:
case SpirvOperandKind::Scope:
case SpirvOperandKind::GroupOperation:
case SpirvOperandKind::KernelEnqueueFlags:
case SpirvOperandKind::Capability:
case SpirvOperandKind::RayQueryIntersection:
case SpirvOperandKind::RayQueryCommittedIntersectionType:
case SpirvOperandKind::RayQueryCandidateIntersectionType:
case SpirvOperandKind::IdResultType:
case SpirvOperandKind::IdResult:
case SpirvOperandKind::IdMemorySemantics:
case SpirvOperandKind::IdScope:
case SpirvOperandKind::IdRef:
case SpirvOperandKind::LiteralInteger:
case SpirvOperandKind::LiteralExtInstInteger:
case SpirvOperandKind::LiteralSpecConstantOpInteger:
case SpirvOperandKind::LiteralContextDependentNumber: //< FIXME
{
UInt32 value = ReadWord();
m_currentState->stream << value;
break;
}
case SpirvOperandKind::LiteralString:
{
std::string str = ReadString();
m_currentState->stream << "\"" << str << "\"";
/*
std::size_t offset = GetOutputOffset();
std::size_t size4 = CountWord(str);
for (std::size_t i = 0; i < size4; ++i)
{
UInt32 codepoint = 0;
for (std::size_t j = 0; j < 4; ++j)
{
std::size_t pos = i * 4 + j;
if (pos < str.size())
codepoint |= UInt32(str[pos]) << (j * 8);
}
Append(codepoint);
}
*/
break;
}
case SpirvOperandKind::PairLiteralIntegerIdRef:
{
ReadWord();
ReadWord();
break;
}
case SpirvOperandKind::PairIdRefLiteralInteger:
{
ReadWord();
ReadWord();
break;
}
case SpirvOperandKind::PairIdRefIdRef:
{
ReadWord();
ReadWord();
break;
}
/*case SpirvOperandKind::LiteralContextDependentNumber:
{
throw std::runtime_error("not yet implemented");
}*/
default:
break;
}
m_currentState->stream << ")";
if (currentOperand < inst->minOperandCount - 1)
currentOperand++;
}
m_currentState->stream << "\n";
assert(m_currentState->index == startIndex + wordCount);
}
std::string SpirvPrinter::ReadString()
{
std::string str;
for (;;)
{
UInt32 value = ReadWord();
for (std::size_t j = 0; j < 4; ++j)
{
char c = static_cast<char>((value >> (j * 8)) & 0xFF);
if (c == '\0')
return str;
str.push_back(c);
}
}
}
UInt32 SpirvPrinter::ReadWord()
{
if (m_currentState->index >= m_currentState->count)
throw std::runtime_error("unexpected end of stream");
return m_currentState->codepoints[m_currentState->index++];
}
}

View File

@ -0,0 +1,49 @@
// 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 <Nazara/Shader/SpirvStatementVisitor.hpp>
#include <Nazara/Shader/SpirvExpressionLoad.hpp>
#include <Nazara/Shader/SpirvExpressionStore.hpp>
#include <Nazara/Shader/SpirvWriter.hpp>
#include <Nazara/Shader/Debug.hpp>
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<const ShaderNodes::LocalVariable&>(*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);
}
}

View File

@ -10,6 +10,7 @@
#include <Nazara/Shader/SpirvConstantCache.hpp>
#include <Nazara/Shader/SpirvData.hpp>
#include <Nazara/Shader/SpirvSection.hpp>
#include <Nazara/Shader/SpirvStatementVisitor.hpp>
#include <tsl/ordered_map.h>
#include <tsl/ordered_set.h>
#include <SpirV/spirv.h>
@ -154,14 +155,6 @@ namespace Nz
}
}
struct SpirvWriter::ExtVar
{
UInt32 pointerTypeId;
UInt32 typeId;
UInt32 varId;
std::optional<UInt32> valueId;
};
struct SpirvWriter::State
{
State() :
@ -387,7 +380,8 @@ namespace Nz
state.instructions.Append(SpirvOp::OpFunctionParameter, GetTypeId(param.type), paramResultId);
}
Visit(functionStatements[funcIndex]);
SpirvStatementVisitor visitor(*this);
visitor.Visit(functionStatements[funcIndex]);
if (func.returnType == ShaderNodes::BasicType::Void)
state.instructions.Append(SpirvOp::OpReturn);
@ -480,12 +474,6 @@ namespace Nz
m_currentState->header.Append(SpirvOp::OpMemoryModel, SpvAddressingModelLogical, SpvMemoryModelGLSL450);
}
UInt32 SpirvWriter::EvaluateExpression(const ShaderNodes::ExpressionPtr& expr)
{
Visit(expr);
return PopResultId();
}
UInt32 SpirvWriter::GetConstantId(const ShaderConstantValue& value) const
{
return m_currentState->constantTypeCache.GetId(*SpirvConstantCache::BuildConstant(value));
@ -507,6 +495,43 @@ namespace Nz
});
}
auto SpirvWriter::GetBuiltinVariable(ShaderNodes::BuiltinEntry builtin) const -> const ExtVar&
{
auto it = m_currentState->builtinIds.find(builtin);
assert(it != m_currentState->builtinIds.end());
return it->second;
}
auto SpirvWriter::GetInputVariable(const std::string& name) const -> const ExtVar&
{
auto it = m_currentState->inputIds.find(name);
assert(it != m_currentState->inputIds.end());
return it->second;
}
auto SpirvWriter::GetOutputVariable(const std::string& name) const -> const ExtVar&
{
auto it = m_currentState->outputIds.find(name);
assert(it != m_currentState->outputIds.end());
return it->second;
}
auto SpirvWriter::GetUniformVariable(const std::string& name) const -> const ExtVar&
{
auto it = m_currentState->uniformIds.find(name);
assert(it != m_currentState->uniformIds.end());
return it.value();
}
SpirvSection& SpirvWriter::GetInstructions()
{
return m_currentState->instructions;
}
UInt32 SpirvWriter::GetPointerTypeId(const ShaderExpressionType& type, SpirvStorageClass storageClass) const
{
return m_currentState->constantTypeCache.GetId(*SpirvConstantCache::BuildPointerType(*m_context.shader, type, storageClass));
@ -517,20 +542,53 @@ namespace Nz
return m_currentState->constantTypeCache.GetId(*SpirvConstantCache::BuildType(*m_context.shader, type));
}
void SpirvWriter::PushResultId(UInt32 value)
UInt32 SpirvWriter::ReadInputVariable(const std::string& name)
{
m_currentState->resultIds.push_back(value);
auto it = m_currentState->inputIds.find(name);
assert(it != m_currentState->inputIds.end());
return ReadVariable(it.value());
}
UInt32 SpirvWriter::PopResultId()
std::optional<UInt32> SpirvWriter::ReadInputVariable(const std::string& name, OnlyCache)
{
if (m_currentState->resultIds.empty())
throw std::runtime_error("invalid operation");
auto it = m_currentState->inputIds.find(name);
assert(it != m_currentState->inputIds.end());
UInt32 resultId = m_currentState->resultIds.back();
m_currentState->resultIds.pop_back();
return ReadVariable(it.value(), OnlyCache{});
}
return resultId;
UInt32 SpirvWriter::ReadLocalVariable(const std::string& name)
{
auto it = m_currentState->varToResult.find(name);
assert(it != m_currentState->varToResult.end());
return it->second;
}
std::optional<UInt32> SpirvWriter::ReadLocalVariable(const std::string& name, OnlyCache)
{
auto it = m_currentState->varToResult.find(name);
if (it == m_currentState->varToResult.end())
return {};
return it->second;
}
UInt32 SpirvWriter::ReadUniformVariable(const std::string& name)
{
auto it = m_currentState->uniformIds.find(name);
assert(it != m_currentState->uniformIds.end());
return ReadVariable(it.value());
}
std::optional<UInt32> SpirvWriter::ReadUniformVariable(const std::string& name, OnlyCache)
{
auto it = m_currentState->uniformIds.find(name);
assert(it != m_currentState->uniformIds.end());
return ReadVariable(it.value(), OnlyCache{});
}
UInt32 SpirvWriter::ReadVariable(ExtVar& var)
@ -546,6 +604,14 @@ namespace Nz
return var.valueId.value();
}
std::optional<UInt32> SpirvWriter::ReadVariable(const ExtVar& var, OnlyCache)
{
if (!var.valueId.has_value())
return {};
return var.valueId.value();
}
UInt32 SpirvWriter::RegisterConstant(const ShaderConstantValue& value)
{
return m_currentState->constantTypeCache.Register(*SpirvConstantCache::BuildConstant(value));
@ -578,572 +644,10 @@ namespace Nz
return m_currentState->constantTypeCache.Register(*SpirvConstantCache::BuildType(*m_context.shader, type));
}
void SpirvWriter::Visit(ShaderNodes::AccessMember& node)
void SpirvWriter::WriteLocalVariable(std::string name, UInt32 resultId)
{
UInt32 pointerId;
SpirvStorageClass storage;
switch (node.structExpr->GetType())
{
case ShaderNodes::NodeType::Identifier:
{
auto& identifier = static_cast<ShaderNodes::Identifier&>(*node.structExpr);
switch (identifier.var->GetType())
{
case ShaderNodes::VariableType::BuiltinVariable:
{
auto& builtinvar = static_cast<ShaderNodes::BuiltinVariable&>(*identifier.var);
auto it = m_currentState->builtinIds.find(builtinvar.entry);
assert(it != m_currentState->builtinIds.end());
pointerId = it->second.varId;
break;
}
case ShaderNodes::VariableType::InputVariable:
{
auto& inputVar = static_cast<ShaderNodes::InputVariable&>(*identifier.var);
auto it = m_currentState->inputIds.find(inputVar.name);
assert(it != m_currentState->inputIds.end());
storage = SpirvStorageClass::Input;
pointerId = it->second.varId;
break;
}
case ShaderNodes::VariableType::OutputVariable:
{
auto& outputVar = static_cast<ShaderNodes::OutputVariable&>(*identifier.var);
auto it = m_currentState->outputIds.find(outputVar.name);
assert(it != m_currentState->outputIds.end());
storage = SpirvStorageClass::Output;
pointerId = it->second.varId;
break;
}
case ShaderNodes::VariableType::UniformVariable:
{
auto& uniformVar = static_cast<ShaderNodes::UniformVariable&>(*identifier.var);
auto it = m_currentState->uniformIds.find(uniformVar.name);
assert(it != m_currentState->uniformIds.end());
storage = SpirvStorageClass::Uniform;
pointerId = it->second.varId;
break;
}
case ShaderNodes::VariableType::LocalVariable:
case ShaderNodes::VariableType::ParameterVariable:
default:
throw std::runtime_error("not yet implemented");
}
break;
}
case ShaderNodes::NodeType::SwizzleOp: //< TODO
default:
throw std::runtime_error("not yet implemented");
}
UInt32 memberPointerId = AllocateResultId();
UInt32 pointerType = RegisterPointerType(node.exprType, storage); //< FIXME
UInt32 typeId = GetTypeId(node.exprType);
m_currentState->instructions.AppendVariadic(SpirvOp::OpAccessChain, [&](const auto& appender)
{
appender(pointerType);
appender(memberPointerId);
appender(pointerId);
for (std::size_t index : node.memberIndices)
appender(GetConstantId(Int32(index)));
});
UInt32 resultId = AllocateResultId();
m_currentState->instructions.Append(SpirvOp::OpLoad, typeId, resultId, memberPointerId);
PushResultId(resultId);
}
void SpirvWriter::Visit(ShaderNodes::AssignOp& node)
{
UInt32 result = EvaluateExpression(node.right);
switch (node.left->GetType())
{
case ShaderNodes::NodeType::Identifier:
{
auto& identifier = static_cast<ShaderNodes::Identifier&>(*node.left);
switch (identifier.var->GetType())
{
case ShaderNodes::VariableType::BuiltinVariable:
{
auto& builtinvar = static_cast<ShaderNodes::BuiltinVariable&>(*identifier.var);
auto it = m_currentState->builtinIds.find(builtinvar.entry);
assert(it != m_currentState->builtinIds.end());
m_currentState->instructions.Append(SpirvOp::OpStore, it->second.varId, result);
PushResultId(result);
break;
}
case ShaderNodes::VariableType::OutputVariable:
{
auto& outputVar = static_cast<ShaderNodes::OutputVariable&>(*identifier.var);
auto it = m_currentState->outputIds.find(outputVar.name);
assert(it != m_currentState->outputIds.end());
m_currentState->instructions.Append(SpirvOp::OpStore, it->second.varId, result);
PushResultId(result);
break;
}
case ShaderNodes::VariableType::InputVariable:
case ShaderNodes::VariableType::LocalVariable:
case ShaderNodes::VariableType::ParameterVariable:
case ShaderNodes::VariableType::UniformVariable:
default:
throw std::runtime_error("not yet implemented");
}
break;
}
case ShaderNodes::NodeType::SwizzleOp: //< TODO
default:
throw std::runtime_error("not yet implemented");
}
}
void SpirvWriter::Visit(ShaderNodes::Branch& node)
{
throw std::runtime_error("not yet implemented");
}
void SpirvWriter::Visit(ShaderNodes::BinaryOp& node)
{
ShaderExpressionType resultExprType = node.GetExpressionType();
assert(std::holds_alternative<ShaderNodes::BasicType>(resultExprType));
const ShaderExpressionType& leftExprType = node.left->GetExpressionType();
assert(std::holds_alternative<ShaderNodes::BasicType>(leftExprType));
const ShaderExpressionType& rightExprType = node.right->GetExpressionType();
assert(std::holds_alternative<ShaderNodes::BasicType>(rightExprType));
ShaderNodes::BasicType resultType = std::get<ShaderNodes::BasicType>(resultExprType);
ShaderNodes::BasicType leftType = std::get<ShaderNodes::BasicType>(leftExprType);
ShaderNodes::BasicType rightType = std::get<ShaderNodes::BasicType>(rightExprType);
UInt32 leftOperand = EvaluateExpression(node.left);
UInt32 rightOperand = EvaluateExpression(node.right);
UInt32 resultId = 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_currentState->instructions.Append(op, GetTypeId(resultType), resultId, leftOperand, rightOperand);
PushResultId(resultId);
}
void SpirvWriter::Visit(ShaderNodes::Cast& node)
{
const ShaderExpressionType& targetExprType = node.exprType;
assert(std::holds_alternative<ShaderNodes::BasicType>(targetExprType));
ShaderNodes::BasicType targetType = std::get<ShaderNodes::BasicType>(targetExprType);
StackVector<UInt32> exprResults = NazaraStackVector(UInt32, node.expressions.size());
for (const auto& exprPtr : node.expressions)
{
if (!exprPtr)
break;
exprResults.push_back(EvaluateExpression(exprPtr));
}
UInt32 resultId = AllocateResultId();
m_currentState->instructions.AppendVariadic(SpirvOp::OpCompositeConstruct, [&](const auto& appender)
{
appender(GetTypeId(targetType));
appender(resultId);
for (UInt32 exprResultId : exprResults)
appender(exprResultId);
});
PushResultId(resultId);
}
void SpirvWriter::Visit(ShaderNodes::Constant& node)
{
std::visit([&] (const auto& value)
{
PushResultId(GetConstantId(value));
}, node.value);
}
void SpirvWriter::Visit(ShaderNodes::DeclareVariable& node)
{
if (node.expression)
{
assert(node.variable->GetType() == ShaderNodes::VariableType::LocalVariable);
const auto& localVar = static_cast<const ShaderNodes::LocalVariable&>(*node.variable);
m_currentState->varToResult[localVar.name] = EvaluateExpression(node.expression);
}
}
void SpirvWriter::Visit(ShaderNodes::ExpressionStatement& node)
{
Visit(node.expression);
PopResultId();
}
void SpirvWriter::Visit(ShaderNodes::Identifier& node)
{
Visit(node.var);
}
void SpirvWriter::Visit(ShaderNodes::IntrinsicCall& node)
{
switch (node.intrinsic)
{
case ShaderNodes::IntrinsicType::DotProduct:
{
const ShaderExpressionType& vecExprType = node.parameters[0]->GetExpressionType();
assert(std::holds_alternative<ShaderNodes::BasicType>(vecExprType));
ShaderNodes::BasicType vecType = std::get<ShaderNodes::BasicType>(vecExprType);
UInt32 typeId = GetTypeId(node.GetComponentType(vecType));
UInt32 vec1 = EvaluateExpression(node.parameters[0]);
UInt32 vec2 = EvaluateExpression(node.parameters[1]);
UInt32 resultId = AllocateResultId();
m_currentState->instructions.Append(SpirvOp::OpDot, typeId, resultId, vec1, vec2);
PushResultId(resultId);
break;
}
case ShaderNodes::IntrinsicType::CrossProduct:
default:
throw std::runtime_error("not yet implemented");
}
}
void SpirvWriter::Visit(ShaderNodes::Sample2D& node)
{
UInt32 typeId = GetTypeId(ShaderNodes::BasicType::Float4);
UInt32 samplerId = EvaluateExpression(node.sampler);
UInt32 coordinatesId = EvaluateExpression(node.coordinates);
UInt32 resultId = AllocateResultId();
m_currentState->instructions.Append(SpirvOp::OpImageSampleImplicitLod, typeId, resultId, samplerId, coordinatesId);
PushResultId(resultId);
}
void SpirvWriter::Visit(ShaderNodes::StatementBlock& node)
{
for (auto& statement : node.statements)
Visit(statement);
}
void SpirvWriter::Visit(ShaderNodes::SwizzleOp& node)
{
const ShaderExpressionType& targetExprType = node.GetExpressionType();
assert(std::holds_alternative<ShaderNodes::BasicType>(targetExprType));
ShaderNodes::BasicType targetType = std::get<ShaderNodes::BasicType>(targetExprType);
UInt32 exprResultId = EvaluateExpression(node.expression);
UInt32 resultId = AllocateResultId();
if (node.componentCount > 1)
{
// Swizzling is implemented via SpirvOp::OpVectorShuffle using the same vector twice as operands
m_currentState->instructions.AppendVariadic(SpirvOp::OpVectorShuffle, [&](const auto& appender)
{
appender(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_currentState->instructions.Append(SpirvOp::OpCompositeExtract, GetTypeId(targetType), resultId, exprResultId, UInt32(node.components[0]) - UInt32(ShaderNodes::SwizzleComponent::First) );
}
PushResultId(resultId);
}
void SpirvWriter::Visit(ShaderNodes::BuiltinVariable& var)
{
throw std::runtime_error("not implemented yet");
}
void SpirvWriter::Visit(ShaderNodes::InputVariable& var)
{
auto it = m_currentState->inputIds.find(var.name);
assert(it != m_currentState->inputIds.end());
PushResultId(ReadVariable(it.value()));
}
void SpirvWriter::Visit(ShaderNodes::LocalVariable& var)
{
auto it = m_currentState->varToResult.find(var.name);
assert(it != m_currentState->varToResult.end());
PushResultId(it->second);
}
void SpirvWriter::Visit(ShaderNodes::OutputVariable& var)
{
auto it = m_currentState->outputIds.find(var.name);
assert(it != m_currentState->outputIds.end());
PushResultId(ReadVariable(it.value()));
}
void SpirvWriter::Visit(ShaderNodes::ParameterVariable& var)
{
throw std::runtime_error("not implemented yet");
}
void SpirvWriter::Visit(ShaderNodes::UniformVariable& var)
{
auto it = m_currentState->uniformIds.find(var.name);
assert(it != m_currentState->uniformIds.end());
PushResultId(ReadVariable(it.value()));
assert(m_currentState);
m_currentState->varToResult.insert_or_assign(std::move(name), resultId);
}
void SpirvWriter::MergeBlocks(std::vector<UInt32>& output, const SpirvSection& from)