From 8c0d34313ee4e4286d0c27e910a1d53f379696c0 Mon Sep 17 00:00:00 2001 From: Lynix Date: Mon, 18 May 2020 19:55:00 +0200 Subject: [PATCH 001/105] GlslWriter: Fix bug --- src/Nazara/Renderer/GlslWriter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Nazara/Renderer/GlslWriter.cpp b/src/Nazara/Renderer/GlslWriter.cpp index 3d023993c..1c0752b85 100644 --- a/src/Nazara/Renderer/GlslWriter.cpp +++ b/src/Nazara/Renderer/GlslWriter.cpp @@ -245,7 +245,7 @@ namespace Nz break; case ShaderAst::ExpressionType::Float4: - Append("vec4(" + String::Number(node.values.vec4.x) + ", " + String::Number(node.values.vec4.y) + ", " + String::Number(node.values.vec4.z) + ", " + String::Number(node.values.vec4.z) + ")"); + Append("vec4(" + String::Number(node.values.vec4.x) + ", " + String::Number(node.values.vec4.y) + ", " + String::Number(node.values.vec4.z) + ", " + String::Number(node.values.vec4.w) + ")"); break; default: From c26f3b9b71b114e4ad3fc41d4c2a3cc3f55ee3f4 Mon Sep 17 00:00:00 2001 From: Lynix Date: Mon, 18 May 2020 19:55:12 +0200 Subject: [PATCH 002/105] Add shadernode (big WIP) --- .gitignore | 3 +- build/scripts/tools/shadernodes.lua | 42 ++++++ src/ShaderNode/DataModels/FragmentOutput.cpp | 44 +++++++ src/ShaderNode/DataModels/FragmentOutput.hpp | 31 +++++ src/ShaderNode/DataModels/FragmentOutput.inl | 1 + src/ShaderNode/DataModels/ShaderNode.cpp | 1 + src/ShaderNode/DataModels/ShaderNode.hpp | 17 +++ src/ShaderNode/DataModels/ShaderNode.inl | 1 + src/ShaderNode/DataModels/VecValue.cpp | 34 +++++ src/ShaderNode/DataModels/VecValue.hpp | 66 ++++++++++ src/ShaderNode/DataModels/VecValue.inl | 44 +++++++ src/ShaderNode/main.cpp | 127 +++++++++++++++++++ 12 files changed, 410 insertions(+), 1 deletion(-) create mode 100644 build/scripts/tools/shadernodes.lua create mode 100644 src/ShaderNode/DataModels/FragmentOutput.cpp create mode 100644 src/ShaderNode/DataModels/FragmentOutput.hpp create mode 100644 src/ShaderNode/DataModels/FragmentOutput.inl create mode 100644 src/ShaderNode/DataModels/ShaderNode.cpp create mode 100644 src/ShaderNode/DataModels/ShaderNode.hpp create mode 100644 src/ShaderNode/DataModels/ShaderNode.inl create mode 100644 src/ShaderNode/DataModels/VecValue.cpp create mode 100644 src/ShaderNode/DataModels/VecValue.hpp create mode 100644 src/ShaderNode/DataModels/VecValue.inl create mode 100644 src/ShaderNode/main.cpp diff --git a/.gitignore b/.gitignore index af2c0073f..2a1c7ff50 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,8 @@ # Nazara build build/config.lua -# Nazara libraries +# Nazara binaries +bin/* lib/* # Self-hosted thirdparty libraries binaries diff --git a/build/scripts/tools/shadernodes.lua b/build/scripts/tools/shadernodes.lua new file mode 100644 index 000000000..33f9628e9 --- /dev/null +++ b/build/scripts/tools/shadernodes.lua @@ -0,0 +1,42 @@ +TOOL.Name = "ShaderNodes" + +TOOL.ClientOnly = true +TOOL.EnableConsole = true +TOOL.Kind = "Application" +TOOL.TargetDirectory = "../bin" + +TOOL.Defines = { + "NODE_EDITOR_SHARED" +} + +TOOL.Includes = { + "../include", + "../extlibs/include", + "../src/ShaderNode", + [[E:\Qt\5.14.1\msvc2017_64\include]], + [[E:\Qt\5.14.1\msvc2017_64\include\QtCore]], + [[E:\Qt\5.14.1\msvc2017_64\include\QtGui]], + [[E:\Qt\5.14.1\msvc2017_64\include\QtWidgets]], + [[C:\Users\Lynix\Documents\GitHub\nodeeditor\include]], +} + +TOOL.Files = { + "../src/ShaderNode/**.hpp", + "../src/ShaderNode/**.inl", + "../src/ShaderNode/**.cpp" +} + +TOOL.Libraries = { + "NazaraCore", + "NazaraRenderer", + "NazaraUtility", + "Qt5Cored", + "Qt5Guid", + "Qt5Widgetsd", + "nodes" +} + +TOOL.LibraryPaths.x64 = { + [[E:\Qt\5.14.1\msvc2017_64\lib]], + [[C:\Users\Lynix\Documents\GitHub\nodeeditor\build\lib\Debug]] +} diff --git a/src/ShaderNode/DataModels/FragmentOutput.cpp b/src/ShaderNode/DataModels/FragmentOutput.cpp new file mode 100644 index 000000000..15244e0d8 --- /dev/null +++ b/src/ShaderNode/DataModels/FragmentOutput.cpp @@ -0,0 +1,44 @@ +#include +#include +#include + +Nz::ShaderAst::ExpressionPtr FragmentOutput::GetExpression(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count) const +{ + using namespace Nz::ShaderAst; + using namespace Nz::ShaderBuilder; + + assert(count == 1); + + auto output = Nz::ShaderBuilder::Output("RenderTarget0", ExpressionType::Float4); + + return Nz::ShaderBuilder::Assign(output, *expressions); +} + +QtNodes::NodeDataType FragmentOutput::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const +{ + assert(portType == QtNodes::PortType::In); + assert(portIndex == 0); + + return Vec4Data::Type(); +} + +QWidget* FragmentOutput::embeddedWidget() +{ + return nullptr; +} + +unsigned int FragmentOutput::nPorts(QtNodes::PortType portType) const +{ + switch (portType) + { + case QtNodes::PortType::In: return 1; + case QtNodes::PortType::Out: return 0; + } + + return 0; +} + +std::shared_ptr FragmentOutput::outData(QtNodes::PortIndex /*port*/) +{ + return {}; +} diff --git a/src/ShaderNode/DataModels/FragmentOutput.hpp b/src/ShaderNode/DataModels/FragmentOutput.hpp new file mode 100644 index 000000000..30aa74b90 --- /dev/null +++ b/src/ShaderNode/DataModels/FragmentOutput.hpp @@ -0,0 +1,31 @@ +#pragma once + +#ifndef NAZARA_SHADERNODES_FRAGMENTOUTPUT_HPP +#define NAZARA_SHADERNODES_FRAGMENTOUTPUT_HPP + +#include +#include +#include + +class FragmentOutput : public ShaderNode +{ + public: + Nz::ShaderAst::ExpressionPtr GetExpression(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count) const override; + + QString caption() const override { return "Fragment shader output"; } + QString name() const override { return "FragmentShaderOutput"; } + + QtNodes::NodeDataType dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; + + QWidget* embeddedWidget() override; + unsigned int nPorts(QtNodes::PortType portType) const override; + + std::shared_ptr outData(QtNodes::PortIndex port) override; + + void setInData(std::shared_ptr, int) override {}; + +}; + +#include + +#endif diff --git a/src/ShaderNode/DataModels/FragmentOutput.inl b/src/ShaderNode/DataModels/FragmentOutput.inl new file mode 100644 index 000000000..f8287a921 --- /dev/null +++ b/src/ShaderNode/DataModels/FragmentOutput.inl @@ -0,0 +1 @@ +#include diff --git a/src/ShaderNode/DataModels/ShaderNode.cpp b/src/ShaderNode/DataModels/ShaderNode.cpp new file mode 100644 index 000000000..fba232649 --- /dev/null +++ b/src/ShaderNode/DataModels/ShaderNode.cpp @@ -0,0 +1 @@ +#include diff --git a/src/ShaderNode/DataModels/ShaderNode.hpp b/src/ShaderNode/DataModels/ShaderNode.hpp new file mode 100644 index 000000000..5c8f6e7f8 --- /dev/null +++ b/src/ShaderNode/DataModels/ShaderNode.hpp @@ -0,0 +1,17 @@ +#pragma once + +#ifndef NAZARA_SHADERNODES_SHADERNODE_HPP +#define NAZARA_SHADERNODES_SHADERNODE_HPP + +#include +#include + +class ShaderNode : public QtNodes::NodeDataModel +{ + public: + virtual Nz::ShaderAst::ExpressionPtr GetExpression(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count) const = 0; +}; + +#include + +#endif diff --git a/src/ShaderNode/DataModels/ShaderNode.inl b/src/ShaderNode/DataModels/ShaderNode.inl new file mode 100644 index 000000000..fba232649 --- /dev/null +++ b/src/ShaderNode/DataModels/ShaderNode.inl @@ -0,0 +1 @@ +#include diff --git a/src/ShaderNode/DataModels/VecValue.cpp b/src/ShaderNode/DataModels/VecValue.cpp new file mode 100644 index 000000000..7986f0b9d --- /dev/null +++ b/src/ShaderNode/DataModels/VecValue.cpp @@ -0,0 +1,34 @@ +#include +#include + +Nz::ShaderAst::ExpressionPtr Vec4Value::GetExpression(Nz::ShaderAst::ExpressionPtr* /*expressions*/, std::size_t count) const +{ + assert(count == 0); + + return Nz::ShaderBuilder::Constant(GetValue()); +} + +auto Vec4Value::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const -> QtNodes::NodeDataType +{ + assert(portType == QtNodes::PortType::Out); + assert(portIndex == 0); + + return Vec4Data::Type(); +} + +std::shared_ptr Vec4Value::outData(QtNodes::PortIndex port) +{ + assert(port == 0); + + return std::make_shared(GetValue()); +} + +Nz::Vector4f Vec4Value::GetValue() const +{ + float x = float(m_values[0]->value()); + float y = float(m_values[1]->value()); + float z = float(m_values[2]->value()); + float w = float(m_values[3]->value()); + + return Nz::Vector4f(x, y, z, w); +} diff --git a/src/ShaderNode/DataModels/VecValue.hpp b/src/ShaderNode/DataModels/VecValue.hpp new file mode 100644 index 000000000..83bd8b3a8 --- /dev/null +++ b/src/ShaderNode/DataModels/VecValue.hpp @@ -0,0 +1,66 @@ +#pragma once + +#ifndef NAZARA_SHADERNODES_VECVALUE_HPP +#define NAZARA_SHADERNODES_VECVALUE_HPP + +#include +#include +#include +#include + +template +class VecValue : public ShaderNode +{ + public: + VecValue(); + ~VecValue() = default; + + QWidget* embeddedWidget() override; + unsigned int nPorts(QtNodes::PortType portType) const override; + + protected: + QWidget* m_widget; + QFormLayout* m_layout; + std::array m_values; +}; + +class Vec4Data : public QtNodes::NodeData +{ + public: + inline Vec4Data(const Nz::Vector4f& vec); + + QtNodes::NodeDataType type() const override + { + return Type(); + } + + static QtNodes::NodeDataType Type() + { + return { "vec4", "Vec4" }; + } + + Nz::Vector4f value; +}; + +class Vec4Value : public VecValue<4> +{ + public: + Nz::ShaderAst::ExpressionPtr GetExpression(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count) const override; + + QString caption() const override { return "Vec4 value"; } + bool captionVisible() const override { return true; } + QString name() const override { return "Vec4Value"; } + + QtNodes::NodeDataType dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; + + std::shared_ptr outData(QtNodes::PortIndex port) override; + + void setInData(std::shared_ptr, int) override {}; + + private: + Nz::Vector4f GetValue() const; +}; + +#include + +#endif diff --git a/src/ShaderNode/DataModels/VecValue.inl b/src/ShaderNode/DataModels/VecValue.inl new file mode 100644 index 000000000..7377fdbad --- /dev/null +++ b/src/ShaderNode/DataModels/VecValue.inl @@ -0,0 +1,44 @@ +#include +#include + +template +VecValue::VecValue() +{ + constexpr std::array componentName = { 'X', 'Y', 'Z', 'W' }; + static_assert(N <= componentName.size()); + + m_layout = new QFormLayout; + for (std::size_t i = 0; i < N; ++i) + { + m_values[i] = new QDoubleSpinBox; + m_values[i]->setStyleSheet("background-color: rgba(255,255,255,255)"); + m_layout->addRow(QString::fromUtf8(&componentName[i], 1), m_values[i]); + } + + m_widget = new QWidget; + m_widget->setStyleSheet("background-color: rgba(0,0,0,0)"); + m_widget->setLayout(m_layout); +} + +template +QWidget* VecValue::embeddedWidget() +{ + return m_widget; +} + +template +unsigned int VecValue::nPorts(QtNodes::PortType portType) const +{ + switch (portType) + { + case QtNodes::PortType::In: return 0; + case QtNodes::PortType::Out: return 1; + } + + return 0; +} + +Vec4Data::Vec4Data(const Nz::Vector4f& vec) : +value(vec) +{ +} diff --git a/src/ShaderNode/main.cpp b/src/ShaderNode/main.cpp new file mode 100644 index 000000000..34141730c --- /dev/null +++ b/src/ShaderNode/main.cpp @@ -0,0 +1,127 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +std::shared_ptr registerDataModels() +{ + auto ret = std::make_shared(); + ret->registerModel(); + ret->registerModel(); + + return ret; +} + +void GenerateGLSL(QtNodes::FlowScene* scene) +{ + /*using namespace ShaderBuilder; + using ShaderAst::BuiltinEntry; + using ShaderAst::ExpressionType; + + // Fragment shader + { + auto rt0 = Output("RenderTarget0", ExpressionType::Float4); + auto color = Uniform("Color", ExpressionType::Float4); + + fragmentShader = writer.Generate(ExprStatement(Assign(rt0, color))); + }*/ + + Nz::GlslWriter writer; + std::vector statements; + + std::function HandleNode; + HandleNode = [&](QtNodes::Node* node) -> Nz::ShaderAst::ExpressionPtr + { + ShaderNode* shaderNode = static_cast(node->nodeDataModel()); + + qDebug() << shaderNode->name(); + std::size_t inputCount = shaderNode->nPorts(QtNodes::PortType::In); + Nz::StackArray expressions = NazaraStackArray(Nz::ShaderAst::ExpressionPtr, inputCount); + std::size_t i = 0; + + for (const auto& connectionSet : node->nodeState().getEntries(QtNodes::PortType::In)) + { + for (const auto& [uuid, conn] : connectionSet) + { + assert(i < expressions.size()); + expressions[i] = HandleNode(conn->getNode(QtNodes::PortType::Out)); + i++; + } + } + + return shaderNode->GetExpression(expressions.data(), expressions.size()); + }; + + scene->iterateOverNodes([&](QtNodes::Node* node) + { + if (node->nodeDataModel()->nPorts(QtNodes::PortType::Out) == 0) + { + statements.emplace_back(Nz::ShaderBuilder::ExprStatement(HandleNode(node))); + //qDebug() << node->nodeDataModel()->name(); + } + }); + + Nz::String glsl = writer.Generate(std::make_shared(std::move(statements))); + + QTextEdit* output = new QTextEdit; + output->setText(QString::fromUtf8(glsl.GetConstBuffer(), glsl.GetSize())); + output->setAttribute(Qt::WA_DeleteOnClose, true); + output->setWindowTitle("GLSL Output"); + output->show(); + + std::cout << glsl << std::endl; +} + +void SetupTestScene(QtNodes::FlowScene* scene) +{ + auto& node1 = scene->createNode(std::make_unique()); + node1.nodeGraphicsObject().setPos(200, 200); + + auto& node2 = scene->createNode(std::make_unique()); + node2.nodeGraphicsObject().setPos(500, 300); + + scene->createConnection(node2, 0, node1, 0); +} + +int main(int argc, char* argv[]) +{ + QApplication app(argc, argv); + + QWidget mainWindow; + QVBoxLayout* layout = new QVBoxLayout; + layout->setContentsMargins(0, 0, 0, 0); + layout->setSpacing(0); + + QtNodes::FlowScene* scene = new QtNodes::FlowScene(registerDataModels()); + SetupTestScene(scene); + + QMenuBar* menuBar = new QMenuBar; + QAction* glslCode = menuBar->addAction("To GLSL"); + QObject::connect(glslCode, &QAction::triggered, [&](bool) { GenerateGLSL(scene); }); + + layout->addWidget(new QtNodes::FlowView(scene)); + layout->addWidget(menuBar); + + mainWindow.setLayout(layout); + mainWindow.setWindowTitle("Nazara Shader nodes"); + mainWindow.resize(1280, 720); + mainWindow.show(); + + return app.exec(); +} From e23eb74802ff5fe920a0971642e4ca956c5cecbc Mon Sep 17 00:00:00 2001 From: Lynix Date: Tue, 19 May 2020 20:06:11 +0200 Subject: [PATCH 003/105] Renderer/ShaderAst: Add Sample2D --- include/Nazara/Renderer/GlslWriter.hpp | 1 + include/Nazara/Renderer/ShaderAst.hpp | 28 ++++++++++++++++++----- include/Nazara/Renderer/ShaderAst.inl | 12 ++++++++++ include/Nazara/Renderer/ShaderBuilder.hpp | 1 + include/Nazara/Renderer/ShaderWriter.hpp | 1 + src/Nazara/Renderer/GlslWriter.cpp | 12 ++++++++++ src/Nazara/Renderer/ShaderAst.cpp | 20 ++++++++++++++-- 7 files changed, 67 insertions(+), 8 deletions(-) diff --git a/include/Nazara/Renderer/GlslWriter.hpp b/include/Nazara/Renderer/GlslWriter.hpp index 8a06a3fbe..d4042e882 100644 --- a/include/Nazara/Renderer/GlslWriter.hpp +++ b/include/Nazara/Renderer/GlslWriter.hpp @@ -40,6 +40,7 @@ namespace Nz void Write(const ShaderAst::ExpressionStatement& node) override; void Write(const ShaderAst::NamedVariable& node) override; void Write(const ShaderAst::NodePtr& node) override; + void Write(const ShaderAst::Sample2D& node) override; void Write(const ShaderAst::StatementBlock& node) override; void Write(const ShaderAst::SwizzleOp& node) override; diff --git a/include/Nazara/Renderer/ShaderAst.hpp b/include/Nazara/Renderer/ShaderAst.hpp index 549b45194..d6cc45789 100644 --- a/include/Nazara/Renderer/ShaderAst.hpp +++ b/include/Nazara/Renderer/ShaderAst.hpp @@ -42,12 +42,13 @@ namespace Nz enum class ExpressionType { - Boolean, // bool - Float1, // float - Float2, // vec2 - Float3, // vec3 - Float4, // vec4 - Mat4x4, // mat4 + Boolean, // bool + Float1, // float + Float2, // vec2 + Float3, // vec3 + Float4, // vec4 + Mat4x4, // mat4 + Sampler2D, // sampler2D Void // void }; @@ -284,6 +285,21 @@ namespace Nz std::size_t componentCount; ExpressionPtr expression; }; + + ////////////////////////////////////////////////////////////////////////// + + class NAZARA_RENDERER_API Sample2D : public Expression + { + public: + inline Sample2D(ExpressionPtr samplerPtr, ExpressionPtr coordinatesPtr); + + ExpressionType GetExpressionType() const override; + void Register(ShaderWriter& visitor) override; + void Visit(ShaderWriter& visitor) override; + + ExpressionPtr sampler; + ExpressionPtr coordinates; + }; } } diff --git a/include/Nazara/Renderer/ShaderAst.inl b/include/Nazara/Renderer/ShaderAst.inl index 2235c9a74..cb9024b48 100644 --- a/include/Nazara/Renderer/ShaderAst.inl +++ b/include/Nazara/Renderer/ShaderAst.inl @@ -2,6 +2,7 @@ // This file is part of the "Nazara Engine - Renderer module" // For conditions of distribution and use, see copyright notice in Config.hpp +#include #include namespace Nz @@ -225,6 +226,17 @@ namespace Nz std::copy(swizzleComponents.begin(), swizzleComponents.end(), components.begin()); } + + inline Sample2D::Sample2D(ExpressionPtr samplerPtr, ExpressionPtr coordinatesPtr) : + sampler(std::move(samplerPtr)), + coordinates(std::move(coordinatesPtr)) + { + if (sampler->GetExpressionType() != ExpressionType::Sampler2D) + throw std::runtime_error("Sampler must be a Sampler2D"); + + if (coordinates->GetExpressionType() != ExpressionType::Float2) + throw std::runtime_error("Coordinates must be a Float2"); + } } } diff --git a/include/Nazara/Renderer/ShaderBuilder.hpp b/include/Nazara/Renderer/ShaderBuilder.hpp index 79512e90f..b0ba09cc4 100644 --- a/include/Nazara/Renderer/ShaderBuilder.hpp +++ b/include/Nazara/Renderer/ShaderBuilder.hpp @@ -66,6 +66,7 @@ namespace Nz { namespace ShaderBuilder constexpr BinOpBuilder Multiply; constexpr VarBuilder Output; constexpr VarBuilder Parameter; + constexpr GenBuilder Sample2D; constexpr GenBuilder Swizzle; constexpr BinOpBuilder Substract; constexpr VarBuilder Uniform; diff --git a/include/Nazara/Renderer/ShaderWriter.hpp b/include/Nazara/Renderer/ShaderWriter.hpp index f20061e05..64dddcf9f 100644 --- a/include/Nazara/Renderer/ShaderWriter.hpp +++ b/include/Nazara/Renderer/ShaderWriter.hpp @@ -41,6 +41,7 @@ namespace Nz virtual void Write(const ShaderAst::ExpressionStatement& node) = 0; virtual void Write(const ShaderAst::NamedVariable& node) = 0; virtual void Write(const ShaderAst::NodePtr& node) = 0; + virtual void Write(const ShaderAst::Sample2D& node) = 0; virtual void Write(const ShaderAst::StatementBlock& node) = 0; virtual void Write(const ShaderAst::SwizzleOp& node) = 0; diff --git a/src/Nazara/Renderer/GlslWriter.cpp b/src/Nazara/Renderer/GlslWriter.cpp index 1c0752b85..badf3648f 100644 --- a/src/Nazara/Renderer/GlslWriter.cpp +++ b/src/Nazara/Renderer/GlslWriter.cpp @@ -128,6 +128,15 @@ namespace Nz node->Visit(*this); } + void GlslWriter::Write(const ShaderAst::Sample2D& node) + { + Append("texture("); + Write(node.sampler); + Append(", "); + Write(node.coordinates); + Append(")"); + } + void GlslWriter::Write(const ShaderAst::AssignOp& node) { Write(node.variable); @@ -338,6 +347,9 @@ namespace Nz case ShaderAst::ExpressionType::Mat4x4: Append("mat4"); break; + case ShaderAst::ExpressionType::Sampler2D: + Append("sampler2D"); + break; case ShaderAst::ExpressionType::Void: Append("void"); break; diff --git a/src/Nazara/Renderer/ShaderAst.cpp b/src/Nazara/Renderer/ShaderAst.cpp index 180930595..d45c8b739 100644 --- a/src/Nazara/Renderer/ShaderAst.cpp +++ b/src/Nazara/Renderer/ShaderAst.cpp @@ -6,7 +6,7 @@ #include #include -namespace Nz { namespace ShaderAst +namespace Nz::ShaderAst { void ExpressionStatement::Register(ShaderWriter& visitor) { @@ -192,5 +192,21 @@ namespace Nz { namespace ShaderAst { visitor.Write(*this); } -} + + + ExpressionType Sample2D::GetExpressionType() const + { + return ExpressionType::Float4; + } + + void Sample2D::Register(ShaderWriter& visitor) + { + sampler->Register(visitor); + coordinates->Register(visitor); + } + + void Sample2D::Visit(ShaderWriter& visitor) + { + visitor.Write(*this); + } } From effaa9b88fbf956d0e583a58a4433d8a7d174610 Mon Sep 17 00:00:00 2001 From: Lynix Date: Tue, 19 May 2020 20:06:32 +0200 Subject: [PATCH 004/105] Update ShaderNode --- src/ShaderNode/DataModels/FragmentOutput.hpp | 2 + src/ShaderNode/DataModels/FragmentOutput.inl | 5 + src/ShaderNode/DataModels/SampleTexture.cpp | 106 +++++++++++++++++++ src/ShaderNode/DataModels/SampleTexture.hpp | 47 ++++++++ src/ShaderNode/DataModels/SampleTexture.inl | 2 + src/ShaderNode/DataModels/ShaderNode.hpp | 11 ++ src/ShaderNode/DataModels/ShaderNode.inl | 15 +++ src/ShaderNode/DataModels/VecBinOp.cpp | 1 + src/ShaderNode/DataModels/VecBinOp.hpp | 60 +++++++++++ src/ShaderNode/DataModels/VecBinOp.inl | 93 ++++++++++++++++ src/ShaderNode/DataModels/VecValue.cpp | 55 ++++++++++ src/ShaderNode/DataModels/VecValue.hpp | 62 +++++++++-- src/ShaderNode/DataModels/VecValue.inl | 34 +++++- src/ShaderNode/ShaderGraph.cpp | 95 +++++++++++++++++ src/ShaderNode/ShaderGraph.hpp | 45 ++++++++ src/ShaderNode/ShaderGraph.inl | 11 ++ src/ShaderNode/main.cpp | 86 ++------------- 17 files changed, 646 insertions(+), 84 deletions(-) create mode 100644 src/ShaderNode/DataModels/SampleTexture.cpp create mode 100644 src/ShaderNode/DataModels/SampleTexture.hpp create mode 100644 src/ShaderNode/DataModels/SampleTexture.inl create mode 100644 src/ShaderNode/DataModels/VecBinOp.cpp create mode 100644 src/ShaderNode/DataModels/VecBinOp.hpp create mode 100644 src/ShaderNode/DataModels/VecBinOp.inl create mode 100644 src/ShaderNode/ShaderGraph.cpp create mode 100644 src/ShaderNode/ShaderGraph.hpp create mode 100644 src/ShaderNode/ShaderGraph.inl diff --git a/src/ShaderNode/DataModels/FragmentOutput.hpp b/src/ShaderNode/DataModels/FragmentOutput.hpp index 30aa74b90..a682d40a4 100644 --- a/src/ShaderNode/DataModels/FragmentOutput.hpp +++ b/src/ShaderNode/DataModels/FragmentOutput.hpp @@ -10,6 +10,8 @@ class FragmentOutput : public ShaderNode { public: + inline FragmentOutput(ShaderGraph& graph); + Nz::ShaderAst::ExpressionPtr GetExpression(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count) const override; QString caption() const override { return "Fragment shader output"; } diff --git a/src/ShaderNode/DataModels/FragmentOutput.inl b/src/ShaderNode/DataModels/FragmentOutput.inl index f8287a921..539b8091f 100644 --- a/src/ShaderNode/DataModels/FragmentOutput.inl +++ b/src/ShaderNode/DataModels/FragmentOutput.inl @@ -1 +1,6 @@ #include + +inline FragmentOutput::FragmentOutput(ShaderGraph& graph) : +ShaderNode(graph) +{ +} diff --git a/src/ShaderNode/DataModels/SampleTexture.cpp b/src/ShaderNode/DataModels/SampleTexture.cpp new file mode 100644 index 000000000..1f4bd4f80 --- /dev/null +++ b/src/ShaderNode/DataModels/SampleTexture.cpp @@ -0,0 +1,106 @@ +#include +#include +#include +#include + +SampleTexture::SampleTexture(ShaderGraph& graph) : +ShaderNode(graph) +{ + m_layout = new QVBoxLayout; + + m_textureSelection = new QComboBox; + m_textureSelection->setStyleSheet("background-color: rgba(255,255,255,255)"); + + m_layout->addWidget(m_textureSelection); + + m_pixmap = QPixmap(64, 64); + m_pixmap.fill(); + + m_pixmapLabel = new QLabel; + m_pixmapLabel->setPixmap(m_pixmap); + + m_layout->addWidget(m_pixmapLabel); + + m_widget = new QWidget; + m_widget->setStyleSheet("background-color: rgba(0,0,0,0)"); + m_widget->setLayout(m_layout); + + m_onTextureListUpdate.Connect(GetGraph().OnTextureListUpdate, [&](ShaderGraph*) { UpdateTextureList(); }); + UpdateTextureList(); +} + +QWidget* SampleTexture::embeddedWidget() +{ + return m_widget; +} + +unsigned int SampleTexture::nPorts(QtNodes::PortType portType) const +{ + switch (portType) + { + case QtNodes::PortType::In: return 1; + case QtNodes::PortType::Out: return 1; + } + + return 0; +} + +void SampleTexture::UpdatePreview() +{ + ComputePreview(m_pixmap); + m_pixmapLabel->setPixmap(m_pixmap); +} + +void SampleTexture::UpdateTextureList() +{ + QString currentTexture = m_textureSelection->currentText(); + m_textureSelection->clear(); + + for (const auto& textureEntry : GetGraph().GetTextures()) + m_textureSelection->addItem(QString::fromStdString(textureEntry.name)); + + m_textureSelection->setCurrentText(currentTexture); +} + +void SampleTexture::ComputePreview(QPixmap& pixmap) const +{ + pixmap.fill(); +} + +Nz::ShaderAst::ExpressionPtr SampleTexture::GetExpression(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count) const +{ + assert(count == 1); + + auto sampler = Nz::ShaderBuilder::Uniform("Texture0", Nz::ShaderAst::ExpressionType::Sampler2D); + + return Nz::ShaderBuilder::Sample2D(sampler, expressions[0]); +} + +auto SampleTexture::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const -> QtNodes::NodeDataType +{ + switch (portType) + { + case QtNodes::PortType::In: + { + assert(portIndex == 0); + return Vec2Data::Type(); + } + + case QtNodes::PortType::Out: + { + assert(portIndex == 0); + return Vec4Data::Type(); + } + + default: + assert(false); + throw std::runtime_error("Invalid PortType"); + } +} + +std::shared_ptr SampleTexture::outData(QtNodes::PortIndex port) +{ + assert(port == 0); + + return std::make_shared(Nz::Vector4f::Zero()); +} diff --git a/src/ShaderNode/DataModels/SampleTexture.hpp b/src/ShaderNode/DataModels/SampleTexture.hpp new file mode 100644 index 000000000..df107169c --- /dev/null +++ b/src/ShaderNode/DataModels/SampleTexture.hpp @@ -0,0 +1,47 @@ +#pragma once + +#ifndef NAZARA_SHADERNODES_SAMPLETEXTURE_HPP +#define NAZARA_SHADERNODES_SAMPLETEXTURE_HPP + +#include +#include +#include +#include +#include +#include + +class SampleTexture : public ShaderNode +{ + public: + SampleTexture(ShaderGraph& graph); + ~SampleTexture() = default; + + Nz::ShaderAst::ExpressionPtr GetExpression(Nz::ShaderAst::ExpressionPtr* /*expressions*/, std::size_t count) const override; + + QString caption() const override { return "Sample texture"; } + QString name() const override { return "SampleTexture"; } + + QWidget* embeddedWidget() override; + unsigned int nPorts(QtNodes::PortType portType) const override; + + QtNodes::NodeDataType dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; + std::shared_ptr outData(QtNodes::PortIndex port) override; + + protected: + void UpdatePreview(); + void UpdateTextureList(); + + void ComputePreview(QPixmap& pixmap) const; + + NazaraSlot(ShaderGraph, OnTextureListUpdate, m_onTextureListUpdate); + + QComboBox* m_textureSelection; + QLabel* m_pixmapLabel; + QPixmap m_pixmap; + QWidget* m_widget; + QVBoxLayout* m_layout; +}; + +#include + +#endif diff --git a/src/ShaderNode/DataModels/SampleTexture.inl b/src/ShaderNode/DataModels/SampleTexture.inl new file mode 100644 index 000000000..78d12b21d --- /dev/null +++ b/src/ShaderNode/DataModels/SampleTexture.inl @@ -0,0 +1,2 @@ +#include +#include diff --git a/src/ShaderNode/DataModels/ShaderNode.hpp b/src/ShaderNode/DataModels/ShaderNode.hpp index 5c8f6e7f8..71a279120 100644 --- a/src/ShaderNode/DataModels/ShaderNode.hpp +++ b/src/ShaderNode/DataModels/ShaderNode.hpp @@ -6,10 +6,21 @@ #include #include +class ShaderGraph; + class ShaderNode : public QtNodes::NodeDataModel { public: + inline ShaderNode(ShaderGraph& graph); + virtual Nz::ShaderAst::ExpressionPtr GetExpression(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count) const = 0; + inline ShaderGraph& GetGraph(); + inline const ShaderGraph& GetGraph() const; + + void setInData(std::shared_ptr, int) override {}; + + private: + ShaderGraph& m_graph; }; #include diff --git a/src/ShaderNode/DataModels/ShaderNode.inl b/src/ShaderNode/DataModels/ShaderNode.inl index fba232649..a244d78b5 100644 --- a/src/ShaderNode/DataModels/ShaderNode.inl +++ b/src/ShaderNode/DataModels/ShaderNode.inl @@ -1 +1,16 @@ #include + +inline ShaderNode::ShaderNode(ShaderGraph& graph) : +m_graph(graph) +{ +} + +inline ShaderGraph& ShaderNode::GetGraph() +{ + return m_graph; +} + +inline const ShaderGraph& ShaderNode::GetGraph() const +{ + return m_graph; +} diff --git a/src/ShaderNode/DataModels/VecBinOp.cpp b/src/ShaderNode/DataModels/VecBinOp.cpp new file mode 100644 index 000000000..dd13b5b56 --- /dev/null +++ b/src/ShaderNode/DataModels/VecBinOp.cpp @@ -0,0 +1 @@ +#include diff --git a/src/ShaderNode/DataModels/VecBinOp.hpp b/src/ShaderNode/DataModels/VecBinOp.hpp new file mode 100644 index 000000000..131a05f6d --- /dev/null +++ b/src/ShaderNode/DataModels/VecBinOp.hpp @@ -0,0 +1,60 @@ +#pragma once + +#ifndef NAZARA_SHADERNODES_VECBINOP_HPP +#define NAZARA_SHADERNODES_VECBINOP_HPP + +#include +#include + +template +class VecBinOp : public ShaderNode +{ + public: + VecBinOp(ShaderGraph& graph); + ~VecBinOp() = default; + + Nz::ShaderAst::ExpressionPtr GetExpression(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count) const override; + + QWidget* embeddedWidget() override; + unsigned int nPorts(QtNodes::PortType portType) const override; + + QtNodes::NodeDataType dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; + + std::shared_ptr outData(QtNodes::PortIndex port) override; + + void setInData(std::shared_ptr value, int index) override; + + private: + void UpdatePreview(); + + using InternalType = typename Data::InternalType; + + InternalType GetValue() const; + + QLabel* m_pixmapLabel; + QPixmap m_preview; + std::shared_ptr m_lhs; + std::shared_ptr m_rhs; +}; + +class Vec4Add : public VecBinOp +{ + public: + using VecBinOp::VecBinOp; + + QString caption() const override { return "Vec4 addition"; } + QString name() const override { return "Vec4Add"; } +}; + +class Vec4Mul : public VecBinOp +{ + public: + using VecBinOp::VecBinOp; + + QString caption() const override { return "Vec4 multiplication"; } + QString name() const override { return "Vec4Mul"; } +}; + +#include + +#endif diff --git a/src/ShaderNode/DataModels/VecBinOp.inl b/src/ShaderNode/DataModels/VecBinOp.inl new file mode 100644 index 000000000..371905221 --- /dev/null +++ b/src/ShaderNode/DataModels/VecBinOp.inl @@ -0,0 +1,93 @@ +#include +#include + +template +VecBinOp::VecBinOp(ShaderGraph& graph) : +ShaderNode(graph) +{ + m_preview = QPixmap(64, 64); + + m_pixmapLabel = new QLabel; + m_pixmapLabel->setPixmap(m_preview); +} + +template +Nz::ShaderAst::ExpressionPtr VecBinOp::GetExpression(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count) const +{ + assert(count == 2); + using BuilderType = typename Nz::ShaderBuilder::template BinOpBuilder; + constexpr BuilderType builder; + return builder(expressions[0], expressions[1]); +} + +template +QWidget* VecBinOp::embeddedWidget() +{ + return m_pixmapLabel; +} + +template +QtNodes::NodeDataType VecBinOp::dataType(QtNodes::PortType /*portType*/, QtNodes::PortIndex portIndex) const +{ + assert(portIndex == 0 || portIndex == 1); + + return Data::Type(); +} + +template +unsigned int VecBinOp::nPorts(QtNodes::PortType portType) const +{ + switch (portType) + { + case QtNodes::PortType::In: return 2; + case QtNodes::PortType::Out: return 1; + } + + return 0; +} + +template +std::shared_ptr VecBinOp::outData(QtNodes::PortIndex port) +{ + assert(port == 0); + return std::make_shared(GetValue()); +} + +template +void VecBinOp::setInData(std::shared_ptr value, int index) +{ + std::shared_ptr castedValue; + if (value) + { + assert(dynamic_cast(value.get()) != nullptr); + assert(index == 0 || index == 1); + + castedValue = std::static_pointer_cast(value); + } + + if (index == 0) + m_lhs = std::move(castedValue); + else + m_rhs = std::move(castedValue); + + UpdatePreview(); + + Q_EMIT dataUpdated(0); +} + +template +void VecBinOp::UpdatePreview() +{ + InternalType value = GetValue(); + m_preview.fill(QColor::fromRgbF(value.x, value.y, value.z, value.w)); + m_pixmapLabel->setPixmap(m_preview); +} + +template +auto VecBinOp::GetValue() const -> InternalType +{ + if (!m_lhs || !m_rhs) + return InternalType::Zero(); + + return m_lhs->value * m_rhs->value; +} diff --git a/src/ShaderNode/DataModels/VecValue.cpp b/src/ShaderNode/DataModels/VecValue.cpp index 7986f0b9d..84f1f4ea8 100644 --- a/src/ShaderNode/DataModels/VecValue.cpp +++ b/src/ShaderNode/DataModels/VecValue.cpp @@ -1,6 +1,55 @@ #include #include +Vec2Value::Vec2Value(ShaderGraph& graph) : +VecValue(graph) +{ + UpdatePreview(); +} + +Nz::ShaderAst::ExpressionPtr Vec2Value::GetExpression(Nz::ShaderAst::ExpressionPtr* /*expressions*/, std::size_t count) const +{ + assert(count == 0); + + return Nz::ShaderBuilder::Constant(GetValue()); +} + +auto Vec2Value::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const -> QtNodes::NodeDataType +{ + assert(portType == QtNodes::PortType::Out); + assert(portIndex == 0); + + return Vec2Data::Type(); +} + +std::shared_ptr Vec2Value::outData(QtNodes::PortIndex port) +{ + assert(port == 0); + + return std::make_shared(GetValue()); +} + +void Vec2Value::ComputePreview(QPixmap& pixmap) const +{ + Nz::Vector4f value = GetValue(); + pixmap.fill(QColor::fromRgbF(value.x, value.y, value.z, value.w)); +} + +Nz::Vector2f Vec2Value::GetValue() const +{ + float x = float(m_values[0]->value()); + float y = float(m_values[1]->value()); + + return Nz::Vector2f(x, y); +} + + +Vec4Value::Vec4Value(ShaderGraph& graph) : +VecValue(graph) +{ + UpdatePreview(); +} + Nz::ShaderAst::ExpressionPtr Vec4Value::GetExpression(Nz::ShaderAst::ExpressionPtr* /*expressions*/, std::size_t count) const { assert(count == 0); @@ -23,6 +72,12 @@ std::shared_ptr Vec4Value::outData(QtNodes::PortIndex port) return std::make_shared(GetValue()); } +void Vec4Value::ComputePreview(QPixmap& pixmap) const +{ + Nz::Vector4f value = GetValue(); + pixmap.fill(QColor::fromRgbF(value.x, value.y, value.z, value.w)); +} + Nz::Vector4f Vec4Value::GetValue() const { float x = float(m_values[0]->value()); diff --git a/src/ShaderNode/DataModels/VecValue.hpp b/src/ShaderNode/DataModels/VecValue.hpp index 83bd8b3a8..10e215971 100644 --- a/src/ShaderNode/DataModels/VecValue.hpp +++ b/src/ShaderNode/DataModels/VecValue.hpp @@ -5,6 +5,7 @@ #include #include +#include #include #include @@ -12,22 +13,50 @@ template class VecValue : public ShaderNode { public: - VecValue(); + VecValue(ShaderGraph& graph); ~VecValue() = default; QWidget* embeddedWidget() override; unsigned int nPorts(QtNodes::PortType portType) const override; protected: + void UpdatePreview(); + + virtual void ComputePreview(QPixmap& pixmap) const = 0; + + QLabel* m_pixmapLabel; + QPixmap m_pixmap; QWidget* m_widget; QFormLayout* m_layout; std::array m_values; }; +class Vec2Data : public QtNodes::NodeData +{ + public: + using InternalType = Nz::Vector2f; + + inline Vec2Data(const InternalType& vec); + + QtNodes::NodeDataType type() const override + { + return Type(); + } + + static QtNodes::NodeDataType Type() + { + return { "vec2", "Vec2" }; + } + + InternalType value; +}; + class Vec4Data : public QtNodes::NodeData { public: - inline Vec4Data(const Nz::Vector4f& vec); + using InternalType = Nz::Vector4f; + + inline Vec4Data(const InternalType& vec); QtNodes::NodeDataType type() const override { @@ -39,25 +68,46 @@ class Vec4Data : public QtNodes::NodeData return { "vec4", "Vec4" }; } - Nz::Vector4f value; + InternalType value; +}; + +class Vec2Value : public VecValue<2> +{ + public: + Vec2Value(ShaderGraph& graph); + + Nz::ShaderAst::ExpressionPtr GetExpression(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count) const override; + + QString caption() const override { return "Vec2 value"; } + QString name() const override { return "Vec2Value"; } + + QtNodes::NodeDataType dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; + + std::shared_ptr outData(QtNodes::PortIndex port) override; + + private: + void ComputePreview(QPixmap& pixmap) const override; + + Nz::Vector2f GetValue() const; }; class Vec4Value : public VecValue<4> { public: + Vec4Value(ShaderGraph& graph); + Nz::ShaderAst::ExpressionPtr GetExpression(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count) const override; QString caption() const override { return "Vec4 value"; } - bool captionVisible() const override { return true; } QString name() const override { return "Vec4Value"; } QtNodes::NodeDataType dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; std::shared_ptr outData(QtNodes::PortIndex port) override; - void setInData(std::shared_ptr, int) override {}; - private: + void ComputePreview(QPixmap& pixmap) const override; + Nz::Vector4f GetValue() const; }; diff --git a/src/ShaderNode/DataModels/VecValue.inl b/src/ShaderNode/DataModels/VecValue.inl index 7377fdbad..e79eef3dc 100644 --- a/src/ShaderNode/DataModels/VecValue.inl +++ b/src/ShaderNode/DataModels/VecValue.inl @@ -2,7 +2,8 @@ #include template -VecValue::VecValue() +VecValue::VecValue(ShaderGraph& graph) : +ShaderNode(graph) { constexpr std::array componentName = { 'X', 'Y', 'Z', 'W' }; static_assert(N <= componentName.size()); @@ -11,10 +12,27 @@ VecValue::VecValue() for (std::size_t i = 0; i < N; ++i) { m_values[i] = new QDoubleSpinBox; + m_values[i]->setDecimals(6); + m_values[i]->setValue(1.0); m_values[i]->setStyleSheet("background-color: rgba(255,255,255,255)"); + connect(m_values[i], qOverload(&QDoubleSpinBox::valueChanged), [this](double) + { + UpdatePreview(); + + Q_EMIT dataUpdated(0); + }); + m_layout->addRow(QString::fromUtf8(&componentName[i], 1), m_values[i]); } + m_pixmap = QPixmap(64, 64); + m_pixmap.fill(); + + m_pixmapLabel = new QLabel; + m_pixmapLabel->setPixmap(m_pixmap); + + m_layout->addWidget(m_pixmapLabel); + m_widget = new QWidget; m_widget->setStyleSheet("background-color: rgba(0,0,0,0)"); m_widget->setLayout(m_layout); @@ -38,7 +56,19 @@ unsigned int VecValue::nPorts(QtNodes::PortType portType) const return 0; } -Vec4Data::Vec4Data(const Nz::Vector4f& vec) : +template +void VecValue::UpdatePreview() +{ + ComputePreview(m_pixmap); + m_pixmapLabel->setPixmap(m_pixmap); +} + +Vec2Data::Vec2Data(const InternalType& vec) : +value(vec) +{ +} + +Vec4Data::Vec4Data(const InternalType& vec) : value(vec) { } diff --git a/src/ShaderNode/ShaderGraph.cpp b/src/ShaderNode/ShaderGraph.cpp new file mode 100644 index 000000000..478e99408 --- /dev/null +++ b/src/ShaderNode/ShaderGraph.cpp @@ -0,0 +1,95 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace +{ + template + void RegisterShaderNode(ShaderGraph& graph, std::shared_ptr registry) + { + auto creator = [&] { return std::make_unique(graph); }; + registry->registerModel(std::move(creator)); + } +} + +ShaderGraph::ShaderGraph() : +m_flowScene(BuildRegistry()) +{ + auto& node1 = m_flowScene.createNode(std::make_unique(*this)); + node1.nodeGraphicsObject().setPos(200, 200); + + auto& node2 = m_flowScene.createNode(std::make_unique(*this)); + node2.nodeGraphicsObject().setPos(500, 300); + + m_flowScene.createConnection(node2, 0, node1, 0); +} + +void ShaderGraph::AddTexture(std::string name, Nz::ShaderAst::ExpressionType type) +{ + auto& textureEntry = m_textures.emplace_back(); + textureEntry.name = std::move(name); + textureEntry.type = type; + + OnTextureListUpdate(this); +} + +Nz::ShaderAst::StatementPtr ShaderGraph::Generate() +{ + std::vector statements; + + std::function HandleNode; + HandleNode = [&](QtNodes::Node* node) -> Nz::ShaderAst::ExpressionPtr + { + ShaderNode* shaderNode = static_cast(node->nodeDataModel()); + + qDebug() << shaderNode->name(); + std::size_t inputCount = shaderNode->nPorts(QtNodes::PortType::In); + Nz::StackArray expressions = NazaraStackArray(Nz::ShaderAst::ExpressionPtr, inputCount); + std::size_t i = 0; + + for (const auto& connectionSet : node->nodeState().getEntries(QtNodes::PortType::In)) + { + for (const auto& [uuid, conn] : connectionSet) + { + assert(i < expressions.size()); + expressions[i] = HandleNode(conn->getNode(QtNodes::PortType::Out)); + i++; + } + } + + return shaderNode->GetExpression(expressions.data(), expressions.size()); + }; + + m_flowScene.iterateOverNodes([&](QtNodes::Node* node) + { + if (node->nodeDataModel()->nPorts(QtNodes::PortType::Out) == 0) + { + statements.emplace_back(Nz::ShaderBuilder::ExprStatement(HandleNode(node))); + } + }); + + return std::make_shared(std::move(statements)); +} + +std::shared_ptr ShaderGraph::BuildRegistry() +{ + auto registry = std::make_shared(); + RegisterShaderNode(*this, registry); + RegisterShaderNode(*this, registry); + RegisterShaderNode(*this, registry); + RegisterShaderNode(*this, registry); + RegisterShaderNode(*this, registry); + + return registry; +} diff --git a/src/ShaderNode/ShaderGraph.hpp b/src/ShaderNode/ShaderGraph.hpp new file mode 100644 index 000000000..8e61175f1 --- /dev/null +++ b/src/ShaderNode/ShaderGraph.hpp @@ -0,0 +1,45 @@ +#pragma once + +#ifndef NAZARA_SHADERNODES_SHADERGRAPH_HPP +#define NAZARA_SHADERNODES_SHADERGRAPH_HPP + +#include +#include +#include +#include +#include +#include + +class ShaderGraph +{ + public: + struct TextureEntry; + + ShaderGraph(); + ~ShaderGraph() = default; + + void AddTexture(std::string name, Nz::ShaderAst::ExpressionType type); + + Nz::ShaderAst::StatementPtr Generate(); + + inline QtNodes::FlowScene& GetScene(); + inline const std::vector& GetTextures(); + + NazaraSignal(OnTextureListUpdate, ShaderGraph*); + + struct TextureEntry + { + std::string name; + Nz::ShaderAst::ExpressionType type; + }; + + private: + std::shared_ptr BuildRegistry(); + + QtNodes::FlowScene m_flowScene; + std::vector m_textures; +}; + +#include + +#endif diff --git a/src/ShaderNode/ShaderGraph.inl b/src/ShaderNode/ShaderGraph.inl new file mode 100644 index 000000000..07c20a134 --- /dev/null +++ b/src/ShaderNode/ShaderGraph.inl @@ -0,0 +1,11 @@ +#include + +inline QtNodes::FlowScene& ShaderGraph::GetScene() +{ + return m_flowScene; +} + +inline auto ShaderGraph::GetTextures() -> const std::vector& +{ + return m_textures; +} diff --git a/src/ShaderNode/main.cpp b/src/ShaderNode/main.cpp index 34141730c..7878bec22 100644 --- a/src/ShaderNode/main.cpp +++ b/src/ShaderNode/main.cpp @@ -1,10 +1,6 @@ -#include #include #include #include -#include -#include -#include #include #include #include @@ -17,103 +13,41 @@ #include #include #include +#include #include -std::shared_ptr registerDataModels() +void GenerateGLSL(ShaderGraph& graph) { - auto ret = std::make_shared(); - ret->registerModel(); - ret->registerModel(); - - return ret; -} - -void GenerateGLSL(QtNodes::FlowScene* scene) -{ - /*using namespace ShaderBuilder; - using ShaderAst::BuiltinEntry; - using ShaderAst::ExpressionType; - - // Fragment shader - { - auto rt0 = Output("RenderTarget0", ExpressionType::Float4); - auto color = Uniform("Color", ExpressionType::Float4); - - fragmentShader = writer.Generate(ExprStatement(Assign(rt0, color))); - }*/ - Nz::GlslWriter writer; - std::vector statements; + Nz::String glsl = writer.Generate(graph.Generate()); - std::function HandleNode; - HandleNode = [&](QtNodes::Node* node) -> Nz::ShaderAst::ExpressionPtr - { - ShaderNode* shaderNode = static_cast(node->nodeDataModel()); - - qDebug() << shaderNode->name(); - std::size_t inputCount = shaderNode->nPorts(QtNodes::PortType::In); - Nz::StackArray expressions = NazaraStackArray(Nz::ShaderAst::ExpressionPtr, inputCount); - std::size_t i = 0; - - for (const auto& connectionSet : node->nodeState().getEntries(QtNodes::PortType::In)) - { - for (const auto& [uuid, conn] : connectionSet) - { - assert(i < expressions.size()); - expressions[i] = HandleNode(conn->getNode(QtNodes::PortType::Out)); - i++; - } - } - - return shaderNode->GetExpression(expressions.data(), expressions.size()); - }; - - scene->iterateOverNodes([&](QtNodes::Node* node) - { - if (node->nodeDataModel()->nPorts(QtNodes::PortType::Out) == 0) - { - statements.emplace_back(Nz::ShaderBuilder::ExprStatement(HandleNode(node))); - //qDebug() << node->nodeDataModel()->name(); - } - }); - - Nz::String glsl = writer.Generate(std::make_shared(std::move(statements))); + std::cout << glsl << std::endl; QTextEdit* output = new QTextEdit; + output->setReadOnly(true); output->setText(QString::fromUtf8(glsl.GetConstBuffer(), glsl.GetSize())); output->setAttribute(Qt::WA_DeleteOnClose, true); output->setWindowTitle("GLSL Output"); output->show(); - - std::cout << glsl << std::endl; -} - -void SetupTestScene(QtNodes::FlowScene* scene) -{ - auto& node1 = scene->createNode(std::make_unique()); - node1.nodeGraphicsObject().setPos(200, 200); - - auto& node2 = scene->createNode(std::make_unique()); - node2.nodeGraphicsObject().setPos(500, 300); - - scene->createConnection(node2, 0, node1, 0); } int main(int argc, char* argv[]) { QApplication app(argc, argv); + ShaderGraph shaderGraph; + shaderGraph.AddTexture("TextureMachin", Nz::ShaderAst::ExpressionType::Sampler2D); + QWidget mainWindow; QVBoxLayout* layout = new QVBoxLayout; layout->setContentsMargins(0, 0, 0, 0); layout->setSpacing(0); - QtNodes::FlowScene* scene = new QtNodes::FlowScene(registerDataModels()); - SetupTestScene(scene); + QtNodes::FlowScene* scene = &shaderGraph.GetScene(); QMenuBar* menuBar = new QMenuBar; QAction* glslCode = menuBar->addAction("To GLSL"); - QObject::connect(glslCode, &QAction::triggered, [&](bool) { GenerateGLSL(scene); }); + QObject::connect(glslCode, &QAction::triggered, [&](bool) { GenerateGLSL(shaderGraph); }); layout->addWidget(new QtNodes::FlowView(scene)); layout->addWidget(menuBar); From 33c8fe2562a87c684d80ca62a26b9247b4ebd8fe Mon Sep 17 00:00:00 2001 From: Lynix Date: Fri, 22 May 2020 15:39:10 +0200 Subject: [PATCH 005/105] ShaderNode: Add texture support --- src/ShaderNode/DataModels/SampleTexture.cpp | 36 +++++- src/ShaderNode/DataModels/SampleTexture.hpp | 7 +- src/ShaderNode/DataModels/ShaderNode.cpp | 4 + src/ShaderNode/DataModels/ShaderNode.hpp | 2 +- src/ShaderNode/DataModels/VecBinOp.cpp | 22 ++++ src/ShaderNode/DataModels/VecBinOp.hpp | 10 +- src/ShaderNode/DataModels/VecBinOp.inl | 54 ++++++--- src/ShaderNode/DataModels/VecValue.cpp | 88 -------------- src/ShaderNode/DataModels/VecValue.hpp | 125 ++++++++++---------- src/ShaderNode/DataModels/VecValue.inl | 104 ++++++++++++---- src/ShaderNode/ShaderGraph.cpp | 32 +++-- src/ShaderNode/ShaderGraph.hpp | 13 +- src/ShaderNode/ShaderGraph.inl | 7 ++ src/ShaderNode/Widgets/MainWindow.cpp | 50 ++++++++ src/ShaderNode/Widgets/MainWindow.hpp | 26 ++++ src/ShaderNode/Widgets/MainWindow.inl | 1 + src/ShaderNode/Widgets/TextureEditor.cpp | 81 +++++++++++++ src/ShaderNode/Widgets/TextureEditor.hpp | 40 +++++++ src/ShaderNode/Widgets/TextureEditor.inl | 1 + src/ShaderNode/main.cpp | 50 +------- 20 files changed, 493 insertions(+), 260 deletions(-) create mode 100644 src/ShaderNode/Widgets/MainWindow.cpp create mode 100644 src/ShaderNode/Widgets/MainWindow.hpp create mode 100644 src/ShaderNode/Widgets/MainWindow.inl create mode 100644 src/ShaderNode/Widgets/TextureEditor.cpp create mode 100644 src/ShaderNode/Widgets/TextureEditor.hpp create mode 100644 src/ShaderNode/Widgets/TextureEditor.inl diff --git a/src/ShaderNode/DataModels/SampleTexture.cpp b/src/ShaderNode/DataModels/SampleTexture.cpp index 1f4bd4f80..6d222abb6 100644 --- a/src/ShaderNode/DataModels/SampleTexture.cpp +++ b/src/ShaderNode/DataModels/SampleTexture.cpp @@ -4,12 +4,21 @@ #include SampleTexture::SampleTexture(ShaderGraph& graph) : -ShaderNode(graph) +ShaderNode(graph), +m_currentTextureIndex(0) { m_layout = new QVBoxLayout; m_textureSelection = new QComboBox; m_textureSelection->setStyleSheet("background-color: rgba(255,255,255,255)"); + connect(m_textureSelection, qOverload(&QComboBox::currentIndexChanged), [&](int index) + { + if (index < 0) + return; + + m_currentTextureIndex = static_cast(index); + UpdatePreview(); + }); m_layout->addWidget(m_textureSelection); @@ -25,8 +34,15 @@ ShaderNode(graph) m_widget->setStyleSheet("background-color: rgba(0,0,0,0)"); m_widget->setLayout(m_layout); - m_onTextureListUpdate.Connect(GetGraph().OnTextureListUpdate, [&](ShaderGraph*) { UpdateTextureList(); }); + m_onTextureListUpdateSlot.Connect(GetGraph().OnTextureListUpdate, [&](ShaderGraph*) { UpdateTextureList(); }); + m_onTexturePreviewUpdateSlot.Connect(GetGraph().OnTexturePreviewUpdate, [&](ShaderGraph*, std::size_t textureIndex) + { + if (m_currentTextureIndex == textureIndex) + UpdatePreview(); + }); + UpdateTextureList(); + UpdatePreview(); } QWidget* SampleTexture::embeddedWidget() @@ -47,8 +63,13 @@ unsigned int SampleTexture::nPorts(QtNodes::PortType portType) const void SampleTexture::UpdatePreview() { + if (m_textureSelection->count() == 0) + return; + ComputePreview(m_pixmap); m_pixmapLabel->setPixmap(m_pixmap); + + Q_EMIT dataUpdated(0); } void SampleTexture::UpdateTextureList() @@ -64,7 +85,9 @@ void SampleTexture::UpdateTextureList() void SampleTexture::ComputePreview(QPixmap& pixmap) const { - pixmap.fill(); + const auto& textureEntry = GetGraph().GetTexture(m_currentTextureIndex); + + pixmap = QPixmap::fromImage(textureEntry.preview).scaled(128, 128, Qt::KeepAspectRatio); } Nz::ShaderAst::ExpressionPtr SampleTexture::GetExpression(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count) const @@ -102,5 +125,10 @@ std::shared_ptr SampleTexture::outData(QtNodes::PortIndex por { assert(port == 0); - return std::make_shared(Nz::Vector4f::Zero()); + const auto& textureEntry = GetGraph().GetTexture(m_currentTextureIndex); + + auto vecData = std::make_shared(); + vecData->preview = textureEntry.preview; + + return vecData; } diff --git a/src/ShaderNode/DataModels/SampleTexture.hpp b/src/ShaderNode/DataModels/SampleTexture.hpp index df107169c..f717797f2 100644 --- a/src/ShaderNode/DataModels/SampleTexture.hpp +++ b/src/ShaderNode/DataModels/SampleTexture.hpp @@ -28,13 +28,14 @@ class SampleTexture : public ShaderNode std::shared_ptr outData(QtNodes::PortIndex port) override; protected: + void ComputePreview(QPixmap& pixmap) const; void UpdatePreview(); void UpdateTextureList(); - void ComputePreview(QPixmap& pixmap) const; - - NazaraSlot(ShaderGraph, OnTextureListUpdate, m_onTextureListUpdate); + NazaraSlot(ShaderGraph, OnTextureListUpdate, m_onTextureListUpdateSlot); + NazaraSlot(ShaderGraph, OnTexturePreviewUpdate, m_onTexturePreviewUpdateSlot); + std::size_t m_currentTextureIndex; QComboBox* m_textureSelection; QLabel* m_pixmapLabel; QPixmap m_pixmap; diff --git a/src/ShaderNode/DataModels/ShaderNode.cpp b/src/ShaderNode/DataModels/ShaderNode.cpp index fba232649..1f45d3ca5 100644 --- a/src/ShaderNode/DataModels/ShaderNode.cpp +++ b/src/ShaderNode/DataModels/ShaderNode.cpp @@ -1 +1,5 @@ #include + +void ShaderNode::setInData(std::shared_ptr, int) +{ +} diff --git a/src/ShaderNode/DataModels/ShaderNode.hpp b/src/ShaderNode/DataModels/ShaderNode.hpp index 71a279120..d33fc632d 100644 --- a/src/ShaderNode/DataModels/ShaderNode.hpp +++ b/src/ShaderNode/DataModels/ShaderNode.hpp @@ -17,7 +17,7 @@ class ShaderNode : public QtNodes::NodeDataModel inline ShaderGraph& GetGraph(); inline const ShaderGraph& GetGraph() const; - void setInData(std::shared_ptr, int) override {}; + void setInData(std::shared_ptr, int) override; private: ShaderGraph& m_graph; diff --git a/src/ShaderNode/DataModels/VecBinOp.cpp b/src/ShaderNode/DataModels/VecBinOp.cpp index dd13b5b56..7349b708f 100644 --- a/src/ShaderNode/DataModels/VecBinOp.cpp +++ b/src/ShaderNode/DataModels/VecBinOp.cpp @@ -1 +1,23 @@ #include + +void Vec4Add::ApplyOp(const std::uint8_t* left, const std::uint8_t* right, std::uint8_t* output, std::size_t pixelCount) +{ + for (std::size_t i = 0; i < pixelCount; ++i) + { + unsigned int lValue = left[i]; + unsigned int rValue = right[i]; + + output[i] = static_cast(std::min(lValue + rValue, 255U)); + } +} + +void Vec4Mul::ApplyOp(const std::uint8_t* left, const std::uint8_t* right, std::uint8_t* output, std::size_t pixelCount) +{ + for (std::size_t i = 0; i < pixelCount; ++i) + { + unsigned int lValue = left[i]; + unsigned int rValue = right[i]; + + output[i] = static_cast(lValue * rValue / 255); + } +} diff --git a/src/ShaderNode/DataModels/VecBinOp.hpp b/src/ShaderNode/DataModels/VecBinOp.hpp index 131a05f6d..97f433048 100644 --- a/src/ShaderNode/DataModels/VecBinOp.hpp +++ b/src/ShaderNode/DataModels/VecBinOp.hpp @@ -25,16 +25,14 @@ class VecBinOp : public ShaderNode void setInData(std::shared_ptr value, int index) override; private: + virtual void ApplyOp(const std::uint8_t* left, const std::uint8_t* right, std::uint8_t* output, std::size_t pixelCount) = 0; void UpdatePreview(); - using InternalType = typename Data::InternalType; - - InternalType GetValue() const; - QLabel* m_pixmapLabel; QPixmap m_preview; std::shared_ptr m_lhs; std::shared_ptr m_rhs; + std::shared_ptr m_output; }; class Vec4Add : public VecBinOp @@ -44,6 +42,8 @@ class Vec4Add : public VecBinOp QString caption() const override { return "Vec4 addition"; } QString name() const override { return "Vec4Add"; } + + void ApplyOp(const std::uint8_t* left, const std::uint8_t* right, std::uint8_t* output, std::size_t pixelCount) override; }; class Vec4Mul : public VecBinOp @@ -53,6 +53,8 @@ class Vec4Mul : public VecBinOp QString caption() const override { return "Vec4 multiplication"; } QString name() const override { return "Vec4Mul"; } + + void ApplyOp(const std::uint8_t* left, const std::uint8_t* right, std::uint8_t* output, std::size_t pixelCount) override; }; #include diff --git a/src/ShaderNode/DataModels/VecBinOp.inl b/src/ShaderNode/DataModels/VecBinOp.inl index 371905221..fea7837a7 100644 --- a/src/ShaderNode/DataModels/VecBinOp.inl +++ b/src/ShaderNode/DataModels/VecBinOp.inl @@ -5,10 +5,11 @@ template VecBinOp::VecBinOp(ShaderGraph& graph) : ShaderNode(graph) { - m_preview = QPixmap(64, 64); + m_output = std::make_shared(); m_pixmapLabel = new QLabel; - m_pixmapLabel->setPixmap(m_preview); + m_pixmapLabel->setStyleSheet("background-color: rgba(0,0,0,0)"); + UpdatePreview(); } template @@ -39,7 +40,7 @@ unsigned int VecBinOp::nPorts(QtNodes::PortType portType) const { switch (portType) { - case QtNodes::PortType::In: return 2; + case QtNodes::PortType::In: return 2; case QtNodes::PortType::Out: return 1; } @@ -50,17 +51,18 @@ template std::shared_ptr VecBinOp::outData(QtNodes::PortIndex port) { assert(port == 0); - return std::make_shared(GetValue()); + return m_output; } template void VecBinOp::setInData(std::shared_ptr value, int index) { + assert(index == 0 || index == 1); + std::shared_ptr castedValue; if (value) { assert(dynamic_cast(value.get()) != nullptr); - assert(index == 0 || index == 1); castedValue = std::static_pointer_cast(value); } @@ -78,16 +80,36 @@ void VecBinOp::setInData(std::shared_ptr value, template void VecBinOp::UpdatePreview() { - InternalType value = GetValue(); - m_preview.fill(QColor::fromRgbF(value.x, value.y, value.z, value.w)); + if (m_lhs && m_rhs) + { + const QImage& leftPreview = m_lhs->preview; + const QImage& rightPreview = m_rhs->preview; + int maxWidth = std::max(leftPreview.width(), rightPreview.width()); + int maxHeight = std::max(leftPreview.height(), rightPreview.height()); + + // Exploit COW + QImage leftResized = leftPreview; + if (leftResized.width() != maxWidth || leftResized.height() != maxHeight) + leftResized = leftResized.scaled(maxWidth, maxHeight); + + QImage rightResized = rightPreview; + if (rightResized.width() != maxWidth || rightResized.height() != maxHeight) + rightResized = rightResized.scaled(maxWidth, maxHeight); + + int w = m_output->preview.width(); + int h = m_output->preview.height(); + + m_output->preview = QImage(maxWidth, maxHeight, QImage::Format_RGBA8888); + ApplyOp(leftResized.constBits(), rightResized.constBits(), m_output->preview.bits(), maxWidth * maxHeight * 4); + m_output->preview = m_output->preview.scaled(w, h); + + m_preview = QPixmap::fromImage(m_output->preview, Qt::AutoColor | Qt::NoOpaqueDetection); + } + else + { + m_preview = QPixmap(64, 64); + m_preview.fill(QColor::fromRgb(255, 255, 0, 0)); + } + m_pixmapLabel->setPixmap(m_preview); } - -template -auto VecBinOp::GetValue() const -> InternalType -{ - if (!m_lhs || !m_rhs) - return InternalType::Zero(); - - return m_lhs->value * m_rhs->value; -} diff --git a/src/ShaderNode/DataModels/VecValue.cpp b/src/ShaderNode/DataModels/VecValue.cpp index 84f1f4ea8..807df2955 100644 --- a/src/ShaderNode/DataModels/VecValue.cpp +++ b/src/ShaderNode/DataModels/VecValue.cpp @@ -1,89 +1 @@ #include -#include - -Vec2Value::Vec2Value(ShaderGraph& graph) : -VecValue(graph) -{ - UpdatePreview(); -} - -Nz::ShaderAst::ExpressionPtr Vec2Value::GetExpression(Nz::ShaderAst::ExpressionPtr* /*expressions*/, std::size_t count) const -{ - assert(count == 0); - - return Nz::ShaderBuilder::Constant(GetValue()); -} - -auto Vec2Value::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const -> QtNodes::NodeDataType -{ - assert(portType == QtNodes::PortType::Out); - assert(portIndex == 0); - - return Vec2Data::Type(); -} - -std::shared_ptr Vec2Value::outData(QtNodes::PortIndex port) -{ - assert(port == 0); - - return std::make_shared(GetValue()); -} - -void Vec2Value::ComputePreview(QPixmap& pixmap) const -{ - Nz::Vector4f value = GetValue(); - pixmap.fill(QColor::fromRgbF(value.x, value.y, value.z, value.w)); -} - -Nz::Vector2f Vec2Value::GetValue() const -{ - float x = float(m_values[0]->value()); - float y = float(m_values[1]->value()); - - return Nz::Vector2f(x, y); -} - - -Vec4Value::Vec4Value(ShaderGraph& graph) : -VecValue(graph) -{ - UpdatePreview(); -} - -Nz::ShaderAst::ExpressionPtr Vec4Value::GetExpression(Nz::ShaderAst::ExpressionPtr* /*expressions*/, std::size_t count) const -{ - assert(count == 0); - - return Nz::ShaderBuilder::Constant(GetValue()); -} - -auto Vec4Value::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const -> QtNodes::NodeDataType -{ - assert(portType == QtNodes::PortType::Out); - assert(portIndex == 0); - - return Vec4Data::Type(); -} - -std::shared_ptr Vec4Value::outData(QtNodes::PortIndex port) -{ - assert(port == 0); - - return std::make_shared(GetValue()); -} - -void Vec4Value::ComputePreview(QPixmap& pixmap) const -{ - Nz::Vector4f value = GetValue(); - pixmap.fill(QColor::fromRgbF(value.x, value.y, value.z, value.w)); -} - -Nz::Vector4f Vec4Value::GetValue() const -{ - float x = float(m_values[0]->value()); - float y = float(m_values[1]->value()); - float z = float(m_values[2]->value()); - float w = float(m_values[3]->value()); - - return Nz::Vector4f(x, y, z, w); -} diff --git a/src/ShaderNode/DataModels/VecValue.hpp b/src/ShaderNode/DataModels/VecValue.hpp index 10e215971..ba7a61f08 100644 --- a/src/ShaderNode/DataModels/VecValue.hpp +++ b/src/ShaderNode/DataModels/VecValue.hpp @@ -3,6 +3,7 @@ #ifndef NAZARA_SHADERNODES_VECVALUE_HPP #define NAZARA_SHADERNODES_VECVALUE_HPP +#include #include #include #include @@ -10,105 +11,105 @@ #include template +struct VecTypeHelper; + +template<> +struct VecTypeHelper<2> +{ + using Type = Nz::Vector2f; +}; + +template<> +struct VecTypeHelper<3> +{ + using Type = Nz::Vector3f; +}; + +template<> +struct VecTypeHelper<4> +{ + using Type = Nz::Vector4f; +}; + +template using VecType = typename VecTypeHelper::template Type; + +template class VecValue : public ShaderNode { public: VecValue(ShaderGraph& graph); ~VecValue() = default; + QtNodes::NodeDataType dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; + QWidget* embeddedWidget() override; unsigned int nPorts(QtNodes::PortType portType) const override; - protected: - void UpdatePreview(); + std::shared_ptr outData(QtNodes::PortIndex port) override; - virtual void ComputePreview(QPixmap& pixmap) const = 0; + Nz::ShaderAst::ExpressionPtr GetExpression(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count) const override; + + protected: + QColor ToColor() const; + VecType ToVector() const; + void UpdatePreview(); QLabel* m_pixmapLabel; QPixmap m_pixmap; QWidget* m_widget; QFormLayout* m_layout; - std::array m_values; + std::array m_spinboxes; }; -class Vec2Data : public QtNodes::NodeData +struct VecData : public QtNodes::NodeData { - public: - using InternalType = Nz::Vector2f; + inline VecData(); - inline Vec2Data(const InternalType& vec); - - QtNodes::NodeDataType type() const override - { - return Type(); - } - - static QtNodes::NodeDataType Type() - { - return { "vec2", "Vec2" }; - } - - InternalType value; + QImage preview; }; -class Vec4Data : public QtNodes::NodeData +struct Vec2Data : public VecData { - public: - using InternalType = Nz::Vector4f; + QtNodes::NodeDataType type() const override + { + return Type(); + } - inline Vec4Data(const InternalType& vec); - - QtNodes::NodeDataType type() const override - { - return Type(); - } - - static QtNodes::NodeDataType Type() - { - return { "vec4", "Vec4" }; - } - - InternalType value; + static QtNodes::NodeDataType Type() + { + return { "vec2", "Vec2" }; + } }; -class Vec2Value : public VecValue<2> +struct Vec4Data : public VecData +{ + QtNodes::NodeDataType type() const override + { + return Type(); + } + + static QtNodes::NodeDataType Type() + { + return { "vec4", "Vec4" }; + } +}; + +class Vec2Value : public VecValue<2, Vec2Data> { public: - Vec2Value(ShaderGraph& graph); - - Nz::ShaderAst::ExpressionPtr GetExpression(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count) const override; + using VecValue::VecValue; QString caption() const override { return "Vec2 value"; } QString name() const override { return "Vec2Value"; } - - QtNodes::NodeDataType dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; - - std::shared_ptr outData(QtNodes::PortIndex port) override; - - private: - void ComputePreview(QPixmap& pixmap) const override; - - Nz::Vector2f GetValue() const; }; -class Vec4Value : public VecValue<4> +class Vec4Value : public VecValue<4, Vec4Data> { public: - Vec4Value(ShaderGraph& graph); - - Nz::ShaderAst::ExpressionPtr GetExpression(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count) const override; + using VecValue::VecValue; QString caption() const override { return "Vec4 value"; } QString name() const override { return "Vec4Value"; } - - QtNodes::NodeDataType dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; - - std::shared_ptr outData(QtNodes::PortIndex port) override; - - private: - void ComputePreview(QPixmap& pixmap) const override; - - Nz::Vector4f GetValue() const; }; #include diff --git a/src/ShaderNode/DataModels/VecValue.inl b/src/ShaderNode/DataModels/VecValue.inl index e79eef3dc..8f8a53fc7 100644 --- a/src/ShaderNode/DataModels/VecValue.inl +++ b/src/ShaderNode/DataModels/VecValue.inl @@ -1,8 +1,10 @@ +#include +#include #include #include -template -VecValue::VecValue(ShaderGraph& graph) : +template +VecValue::VecValue(ShaderGraph& graph) : ShaderNode(graph) { constexpr std::array componentName = { 'X', 'Y', 'Z', 'W' }; @@ -11,21 +13,21 @@ ShaderNode(graph) m_layout = new QFormLayout; for (std::size_t i = 0; i < N; ++i) { - m_values[i] = new QDoubleSpinBox; - m_values[i]->setDecimals(6); - m_values[i]->setValue(1.0); - m_values[i]->setStyleSheet("background-color: rgba(255,255,255,255)"); - connect(m_values[i], qOverload(&QDoubleSpinBox::valueChanged), [this](double) + m_spinboxes[i] = new QDoubleSpinBox; + m_spinboxes[i]->setDecimals(6); + m_spinboxes[i]->setValue(1.0); + m_spinboxes[i]->setStyleSheet("background-color: rgba(255,255,255,255)"); + connect(m_spinboxes[i], qOverload(&QDoubleSpinBox::valueChanged), [this](double) { UpdatePreview(); Q_EMIT dataUpdated(0); }); - m_layout->addRow(QString::fromUtf8(&componentName[i], 1), m_values[i]); + m_layout->addRow(QString::fromUtf8(&componentName[i], 1), m_spinboxes[i]); } - m_pixmap = QPixmap(64, 64); + m_pixmap = QPixmap(32, 32); m_pixmap.fill(); m_pixmapLabel = new QLabel; @@ -36,16 +38,27 @@ ShaderNode(graph) m_widget = new QWidget; m_widget->setStyleSheet("background-color: rgba(0,0,0,0)"); m_widget->setLayout(m_layout); + + UpdatePreview(); } -template -QWidget* VecValue::embeddedWidget() +template +QtNodes::NodeDataType VecValue::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const +{ + assert(portType == QtNodes::PortType::Out); + assert(portIndex == 0); + + return Data::Type(); +} + +template +QWidget* VecValue::embeddedWidget() { return m_widget; } -template -unsigned int VecValue::nPorts(QtNodes::PortType portType) const +template +unsigned int VecValue::nPorts(QtNodes::PortType portType) const { switch (portType) { @@ -56,19 +69,64 @@ unsigned int VecValue::nPorts(QtNodes::PortType portType) const return 0; } -template -void VecValue::UpdatePreview() +template +std::shared_ptr VecValue::outData(QtNodes::PortIndex port) { - ComputePreview(m_pixmap); + assert(port == 0); + + auto out = std::make_shared(); + out->preview = QImage(1, 1, QImage::Format_RGBA8888); + out->preview.fill(ToColor()); + + return out; +} + +template +Nz::ShaderAst::ExpressionPtr VecValue::GetExpression(Nz::ShaderAst::ExpressionPtr* /*expressions*/, std::size_t count) const +{ + assert(count == 0); + + return Nz::ShaderBuilder::Constant(ToVector()); +} + +template +QColor VecValue::ToColor() const +{ + std::array values = { 0.f, 0.f, 0.f, 1.f }; + + for (std::size_t i = 0; i < N; ++i) + values[i] = std::clamp(m_spinboxes[i]->value(), 0.0, 1.0); + + return QColor::fromRgbF(values[0], values[1], values[2], values[3]); +} + +template +VecType VecValue::ToVector() const +{ + std::array values = { 0.f, 0.f, 0.f, 1.f }; + + for (std::size_t i = 0; i < N; ++i) + values[i] = std::clamp(m_spinboxes[i]->value(), 0.0, 1.0); + + if constexpr (N == 2) + return Nz::Vector2f(values[0], values[1]); + else if constexpr (N == 3) + return Nz::Vector3f(values[0], values[1], values[2]); + else if constexpr (N == 4) + return Nz::Vector4f(values[0], values[1], values[2], values[3]); + else + static_assert(Nz::AlwaysFalse>(), "Unhandled vector size"); +} + +template +void VecValue::UpdatePreview() +{ + m_pixmap.fill(ToColor()); m_pixmapLabel->setPixmap(m_pixmap); } -Vec2Data::Vec2Data(const InternalType& vec) : -value(vec) -{ -} - -Vec4Data::Vec4Data(const InternalType& vec) : -value(vec) +inline VecData::VecData() : +preview(64, 64, QImage::Format_RGBA8888) { + preview.fill(QColor::fromRgb(255, 255, 255, 0)); } diff --git a/src/ShaderNode/ShaderGraph.cpp b/src/ShaderNode/ShaderGraph.cpp index 478e99408..ee02e6c11 100644 --- a/src/ShaderNode/ShaderGraph.cpp +++ b/src/ShaderNode/ShaderGraph.cpp @@ -16,10 +16,10 @@ namespace { template - void RegisterShaderNode(ShaderGraph& graph, std::shared_ptr registry) + void RegisterShaderNode(ShaderGraph& graph, std::shared_ptr registry, QString category = QString()) { auto creator = [&] { return std::make_unique(graph); }; - registry->registerModel(std::move(creator)); + registry->registerModel(category, std::move(creator)); } } @@ -35,16 +35,19 @@ m_flowScene(BuildRegistry()) m_flowScene.createConnection(node2, 0, node1, 0); } -void ShaderGraph::AddTexture(std::string name, Nz::ShaderAst::ExpressionType type) +std::size_t ShaderGraph::AddTexture(std::string name, Nz::ShaderAst::ExpressionType type) { + std::size_t index = m_textures.size(); auto& textureEntry = m_textures.emplace_back(); textureEntry.name = std::move(name); textureEntry.type = type; OnTextureListUpdate(this); + + return index; } -Nz::ShaderAst::StatementPtr ShaderGraph::Generate() +Nz::ShaderAst::StatementPtr ShaderGraph::ToAst() { std::vector statements; @@ -82,14 +85,25 @@ Nz::ShaderAst::StatementPtr ShaderGraph::Generate() return std::make_shared(std::move(statements)); } +void ShaderGraph::UpdateTexturePreview(std::size_t textureIndex, QImage preview) +{ + assert(textureIndex < m_textures.size()); + auto& textureEntry = m_textures[textureIndex]; + textureEntry.preview = std::move(preview); + textureEntry.preview.convertTo(QImage::Format_RGBA8888); + + OnTexturePreviewUpdate(this, textureIndex); +} + std::shared_ptr ShaderGraph::BuildRegistry() { auto registry = std::make_shared(); - RegisterShaderNode(*this, registry); - RegisterShaderNode(*this, registry); - RegisterShaderNode(*this, registry); - RegisterShaderNode(*this, registry); - RegisterShaderNode(*this, registry); + RegisterShaderNode(*this, registry, "Output"); + RegisterShaderNode(*this, registry, "Texture"); + RegisterShaderNode(*this, registry, "Vector operations"); + RegisterShaderNode(*this, registry, "Vector operations"); + RegisterShaderNode(*this, registry, "Constants"); + RegisterShaderNode(*this, registry, "Constants"); return registry; } diff --git a/src/ShaderNode/ShaderGraph.hpp b/src/ShaderNode/ShaderGraph.hpp index 8e61175f1..cac252802 100644 --- a/src/ShaderNode/ShaderGraph.hpp +++ b/src/ShaderNode/ShaderGraph.hpp @@ -18,21 +18,26 @@ class ShaderGraph ShaderGraph(); ~ShaderGraph() = default; - void AddTexture(std::string name, Nz::ShaderAst::ExpressionType type); - - Nz::ShaderAst::StatementPtr Generate(); + std::size_t AddTexture(std::string name, Nz::ShaderAst::ExpressionType type); inline QtNodes::FlowScene& GetScene(); + inline const TextureEntry& GetTexture(std::size_t textureIndex) const; inline const std::vector& GetTextures(); - NazaraSignal(OnTextureListUpdate, ShaderGraph*); + Nz::ShaderAst::StatementPtr ToAst(); + + void UpdateTexturePreview(std::size_t texture, QImage preview); struct TextureEntry { std::string name; Nz::ShaderAst::ExpressionType type; + QImage preview; }; + NazaraSignal(OnTextureListUpdate, ShaderGraph*); + NazaraSignal(OnTexturePreviewUpdate, ShaderGraph*, std::size_t /*textureIndex*/); + private: std::shared_ptr BuildRegistry(); diff --git a/src/ShaderNode/ShaderGraph.inl b/src/ShaderNode/ShaderGraph.inl index 07c20a134..1f0b463e9 100644 --- a/src/ShaderNode/ShaderGraph.inl +++ b/src/ShaderNode/ShaderGraph.inl @@ -5,7 +5,14 @@ inline QtNodes::FlowScene& ShaderGraph::GetScene() return m_flowScene; } +inline auto ShaderGraph::GetTexture(std::size_t textureIndex) const -> const TextureEntry& +{ + assert(textureIndex < m_textures.size()); + return m_textures[textureIndex]; +} + inline auto ShaderGraph::GetTextures() -> const std::vector& { return m_textures; } + diff --git a/src/ShaderNode/Widgets/MainWindow.cpp b/src/ShaderNode/Widgets/MainWindow.cpp new file mode 100644 index 000000000..d4a661790 --- /dev/null +++ b/src/ShaderNode/Widgets/MainWindow.cpp @@ -0,0 +1,50 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +MainWindow::MainWindow(ShaderGraph& graph) : +m_shaderGraph(graph) +{ + setWindowTitle("Nazara Shader nodes"); + + QtNodes::FlowScene* scene = &m_shaderGraph.GetScene(); + + QtNodes::FlowView* flowView = new QtNodes::FlowView(scene); + setCentralWidget(flowView); + + QDockWidget* textureDock = new QDockWidget(tr("&Textures")); + + TextureEditor* textureEditor = new TextureEditor(m_shaderGraph); + textureDock->setWidget(textureEditor); + + addDockWidget(Qt::LeftDockWidgetArea, textureDock); + + BuildMenu(); +} + +void MainWindow::BuildMenu() +{ + QMenu* compileMenu = menuBar()->addMenu(tr("&Compilation")); + QAction* compileToGlsl = compileMenu->addAction(tr("GLSL")); + connect(compileToGlsl, &QAction::triggered, [&](bool) { OnCompileToGLSL(); }); +} + +void MainWindow::OnCompileToGLSL() +{ + Nz::GlslWriter writer; + Nz::String glsl = writer.Generate(m_shaderGraph.ToAst()); + + std::cout << glsl << std::endl; + + QTextEdit* output = new QTextEdit; + output->setReadOnly(true); + output->setText(QString::fromUtf8(glsl.GetConstBuffer(), int(glsl.GetSize()))); + output->setAttribute(Qt::WA_DeleteOnClose, true); + output->setWindowTitle("GLSL Output"); + output->show(); +} diff --git a/src/ShaderNode/Widgets/MainWindow.hpp b/src/ShaderNode/Widgets/MainWindow.hpp new file mode 100644 index 000000000..fa8257bcf --- /dev/null +++ b/src/ShaderNode/Widgets/MainWindow.hpp @@ -0,0 +1,26 @@ +#pragma once + +#ifndef NAZARA_SHADERNODES_MAINWINDOW_HPP +#define NAZARA_SHADERNODES_MAINWINDOW_HPP + +#include +#include + +class ShaderGraph; + +class MainWindow : public QMainWindow +{ + public: + MainWindow(ShaderGraph& graph); + ~MainWindow() = default; + + private: + void BuildMenu(); + void OnCompileToGLSL(); + + ShaderGraph& m_shaderGraph; +}; + +#include + +#endif diff --git a/src/ShaderNode/Widgets/MainWindow.inl b/src/ShaderNode/Widgets/MainWindow.inl new file mode 100644 index 000000000..48dbe409e --- /dev/null +++ b/src/ShaderNode/Widgets/MainWindow.inl @@ -0,0 +1 @@ +#include diff --git a/src/ShaderNode/Widgets/TextureEditor.cpp b/src/ShaderNode/Widgets/TextureEditor.cpp new file mode 100644 index 000000000..594262c1a --- /dev/null +++ b/src/ShaderNode/Widgets/TextureEditor.cpp @@ -0,0 +1,81 @@ +#include +#include +#include +#include +#include +#include +#include + +TextureEditor::TextureEditor(ShaderGraph& graph) : +m_shaderGraph(graph) +{ + m_textureList = new QListWidget(this); + connect(m_textureList, &QListWidget::currentRowChanged, this, &TextureEditor::OnTextureSelectionUpdate); + + m_pixmapLabel = new QLabel; + + QPushButton* updateTextureButton = new QPushButton(tr("Load texture...")); + connect(updateTextureButton, &QPushButton::released, this, &TextureEditor::OnLoadTexture); + + m_layout = new QVBoxLayout; + m_layout->addWidget(m_textureList); + m_layout->addWidget(updateTextureButton); + m_layout->addWidget(m_pixmapLabel); + + setLayout(m_layout); + + m_onTextureListUpdateSlot.Connect(m_shaderGraph.OnTextureListUpdate, this, &TextureEditor::OnTextureListUpdate); + m_onTexturePreviewUpdateSlot.Connect(m_shaderGraph.OnTexturePreviewUpdate, this, &TextureEditor::OnTexturePreviewUpdate); + + RefreshTextures(); +} + +void TextureEditor::OnLoadTexture() +{ + if (!m_currentTextureIndex) + return; + + QString fileName = QFileDialog::getOpenFileName(nullptr, tr("Open Image"), QDir::homePath(), tr("Image Files (*.png *.jpg *.bmp)")); + if (fileName.isEmpty()) + return; + + m_shaderGraph.UpdateTexturePreview(m_currentTextureIndex.value(), QImage(fileName)); +} + +void TextureEditor::OnTextureSelectionUpdate(int textureIndex) +{ + if (textureIndex >= 0) + { + m_currentTextureIndex = textureIndex; + UpdateTexturePreview(); + } + else + m_currentTextureIndex.reset(); +} + +void TextureEditor::OnTextureListUpdate(ShaderGraph* graph) +{ + RefreshTextures(); +} + +void TextureEditor::OnTexturePreviewUpdate(ShaderGraph* /*graph*/, std::size_t textureIndex) +{ + if (m_currentTextureIndex && *m_currentTextureIndex == textureIndex) + UpdateTexturePreview(); +} + +void TextureEditor::RefreshTextures() +{ + m_textureList->clear(); + m_textureList->setCurrentRow(-1); + + for (const auto& textureEntry : m_shaderGraph.GetTextures()) + m_textureList->addItem(QString::fromStdString(textureEntry.name)); +} + +void TextureEditor::UpdateTexturePreview() +{ + assert(m_currentTextureIndex); + const auto& textureEntry = m_shaderGraph.GetTexture(*m_currentTextureIndex); + m_pixmapLabel->setPixmap(QPixmap::fromImage(textureEntry.preview).scaled(128, 128, Qt::KeepAspectRatio)); +} diff --git a/src/ShaderNode/Widgets/TextureEditor.hpp b/src/ShaderNode/Widgets/TextureEditor.hpp new file mode 100644 index 000000000..fcdbf3f7c --- /dev/null +++ b/src/ShaderNode/Widgets/TextureEditor.hpp @@ -0,0 +1,40 @@ +#pragma once + +#ifndef NAZARA_SHADERNODES_TEXTUREEDITOR_HPP +#define NAZARA_SHADERNODES_TEXTUREEDITOR_HPP + +#include +#include +#include + +class QLabel; +class QListWidget; +class QVBoxLayout; + +class TextureEditor : public QWidget +{ + public: + TextureEditor(ShaderGraph& graph); + ~TextureEditor() = default; + + private: + void OnLoadTexture(); + void OnTextureSelectionUpdate(int textureIndex); + void OnTextureListUpdate(ShaderGraph* graph); + void OnTexturePreviewUpdate(ShaderGraph* graph, std::size_t textureIndex); + void RefreshTextures(); + void UpdateTexturePreview(); + + NazaraSlot(ShaderGraph, OnTextureListUpdate, m_onTextureListUpdateSlot); + NazaraSlot(ShaderGraph, OnTexturePreviewUpdate, m_onTexturePreviewUpdateSlot); + + std::optional m_currentTextureIndex; + ShaderGraph& m_shaderGraph; + QLabel* m_pixmapLabel; + QListWidget* m_textureList; + QVBoxLayout* m_layout; +}; + +#include + +#endif diff --git a/src/ShaderNode/Widgets/TextureEditor.inl b/src/ShaderNode/Widgets/TextureEditor.inl new file mode 100644 index 000000000..d11298db1 --- /dev/null +++ b/src/ShaderNode/Widgets/TextureEditor.inl @@ -0,0 +1 @@ +#include diff --git a/src/ShaderNode/main.cpp b/src/ShaderNode/main.cpp index 7878bec22..648cbbbbc 100644 --- a/src/ShaderNode/main.cpp +++ b/src/ShaderNode/main.cpp @@ -1,59 +1,17 @@ -#include -#include -#include -#include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include +#include #include -void GenerateGLSL(ShaderGraph& graph) -{ - Nz::GlslWriter writer; - Nz::String glsl = writer.Generate(graph.Generate()); - - std::cout << glsl << std::endl; - - QTextEdit* output = new QTextEdit; - output->setReadOnly(true); - output->setText(QString::fromUtf8(glsl.GetConstBuffer(), glsl.GetSize())); - output->setAttribute(Qt::WA_DeleteOnClose, true); - output->setWindowTitle("GLSL Output"); - output->show(); -} - int main(int argc, char* argv[]) { QApplication app(argc, argv); ShaderGraph shaderGraph; - shaderGraph.AddTexture("TextureMachin", Nz::ShaderAst::ExpressionType::Sampler2D); + shaderGraph.AddTexture("Potato", Nz::ShaderAst::ExpressionType::Sampler2D); + shaderGraph.AddTexture("Blackbird", Nz::ShaderAst::ExpressionType::Sampler2D); - QWidget mainWindow; - QVBoxLayout* layout = new QVBoxLayout; - layout->setContentsMargins(0, 0, 0, 0); - layout->setSpacing(0); - - QtNodes::FlowScene* scene = &shaderGraph.GetScene(); - - QMenuBar* menuBar = new QMenuBar; - QAction* glslCode = menuBar->addAction("To GLSL"); - QObject::connect(glslCode, &QAction::triggered, [&](bool) { GenerateGLSL(shaderGraph); }); - - layout->addWidget(new QtNodes::FlowView(scene)); - layout->addWidget(menuBar); - - mainWindow.setLayout(layout); - mainWindow.setWindowTitle("Nazara Shader nodes"); + MainWindow mainWindow(shaderGraph); mainWindow.resize(1280, 720); mainWindow.show(); From 5169e0fe836d70b0346a4536b7aeff11c91ba12e Mon Sep 17 00:00:00 2001 From: Lynix Date: Fri, 22 May 2020 19:21:56 +0200 Subject: [PATCH 006/105] ShaderNode: Add captions --- src/ShaderNode/DataModels/SampleTexture.cpp | 27 +++++++++++++++++++++ src/ShaderNode/DataModels/SampleTexture.hpp | 5 ++++ 2 files changed, 32 insertions(+) diff --git a/src/ShaderNode/DataModels/SampleTexture.cpp b/src/ShaderNode/DataModels/SampleTexture.cpp index 6d222abb6..180989226 100644 --- a/src/ShaderNode/DataModels/SampleTexture.cpp +++ b/src/ShaderNode/DataModels/SampleTexture.cpp @@ -121,6 +121,33 @@ auto SampleTexture::dataType(QtNodes::PortType portType, QtNodes::PortIndex port } } +QString SampleTexture::portCaption(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const +{ + switch (portType) + { + case QtNodes::PortType::In: + { + assert(portIndex == 0); + return tr("UV"); + } + + case QtNodes::PortType::Out: + { + assert(portIndex == 0); + return tr("Sample"); + } + + default: + assert(false); + throw std::runtime_error("Invalid PortType"); + } +} + +bool SampleTexture::portCaptionVisible(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const +{ + return true; +} + std::shared_ptr SampleTexture::outData(QtNodes::PortIndex port) { assert(port == 0); diff --git a/src/ShaderNode/DataModels/SampleTexture.hpp b/src/ShaderNode/DataModels/SampleTexture.hpp index f717797f2..af11d14ec 100644 --- a/src/ShaderNode/DataModels/SampleTexture.hpp +++ b/src/ShaderNode/DataModels/SampleTexture.hpp @@ -25,6 +25,11 @@ class SampleTexture : public ShaderNode unsigned int nPorts(QtNodes::PortType portType) const override; QtNodes::NodeDataType dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; + + QString portCaption(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; + + bool portCaptionVisible(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; + std::shared_ptr outData(QtNodes::PortIndex port) override; protected: From 206724c911e008468b85749b8339b8b117bd1720 Mon Sep 17 00:00:00 2001 From: Lynix Date: Fri, 22 May 2020 23:50:46 +0200 Subject: [PATCH 007/105] ShaderNode: Add inputs --- src/ShaderNode/DataModels/InputValue.cpp | 132 ++++++++++++++++++++ src/ShaderNode/DataModels/InputValue.hpp | 47 +++++++ src/ShaderNode/DataModels/InputValue.inl | 2 + src/ShaderNode/DataModels/SampleTexture.cpp | 15 ++- src/ShaderNode/Enums.cpp | 42 +++++++ src/ShaderNode/Enums.hpp | 48 +++++++ src/ShaderNode/Enums.inl | 1 + src/ShaderNode/ShaderGraph.cpp | 32 ++++- src/ShaderNode/ShaderGraph.hpp | 24 +++- src/ShaderNode/ShaderGraph.inl | 13 +- src/ShaderNode/Widgets/InputEditDialog.cpp | 80 ++++++++++++ src/ShaderNode/Widgets/InputEditDialog.hpp | 41 ++++++ src/ShaderNode/Widgets/InputEditDialog.inl | 1 + src/ShaderNode/Widgets/InputEditor.cpp | 97 ++++++++++++++ src/ShaderNode/Widgets/InputEditor.hpp | 39 ++++++ src/ShaderNode/Widgets/InputEditor.inl | 1 + src/ShaderNode/Widgets/MainWindow.cpp | 9 ++ src/ShaderNode/Widgets/TextureEditor.cpp | 2 +- src/ShaderNode/Widgets/TextureEditor.hpp | 2 +- src/ShaderNode/main.cpp | 4 +- 20 files changed, 620 insertions(+), 12 deletions(-) create mode 100644 src/ShaderNode/DataModels/InputValue.cpp create mode 100644 src/ShaderNode/DataModels/InputValue.hpp create mode 100644 src/ShaderNode/DataModels/InputValue.inl create mode 100644 src/ShaderNode/Enums.cpp create mode 100644 src/ShaderNode/Enums.hpp create mode 100644 src/ShaderNode/Enums.inl create mode 100644 src/ShaderNode/Widgets/InputEditDialog.cpp create mode 100644 src/ShaderNode/Widgets/InputEditDialog.hpp create mode 100644 src/ShaderNode/Widgets/InputEditDialog.inl create mode 100644 src/ShaderNode/Widgets/InputEditor.cpp create mode 100644 src/ShaderNode/Widgets/InputEditor.hpp create mode 100644 src/ShaderNode/Widgets/InputEditor.inl diff --git a/src/ShaderNode/DataModels/InputValue.cpp b/src/ShaderNode/DataModels/InputValue.cpp new file mode 100644 index 000000000..f1cc97d0d --- /dev/null +++ b/src/ShaderNode/DataModels/InputValue.cpp @@ -0,0 +1,132 @@ +#include +#include +#include +#include + +InputValue::InputValue(ShaderGraph& graph) : +ShaderNode(graph), +m_currentInputIndex(0) +{ + m_layout = new QVBoxLayout; + + m_inputSelection = new QComboBox; + m_inputSelection->setStyleSheet("background-color: rgba(255,255,255,255)"); + connect(m_inputSelection, qOverload(&QComboBox::currentIndexChanged), [&](int index) + { + if (index < 0) + return; + + m_currentInputIndex = static_cast(index); + UpdatePreview(); + }); + + m_layout->addWidget(m_inputSelection); + + m_previewLabel = new QLabel; + + m_layout->addWidget(m_previewLabel); + + m_widget = new QWidget; + m_widget->setStyleSheet("background-color: rgba(0,0,0,0)"); + m_widget->setLayout(m_layout); + + m_onInputListUpdateSlot.Connect(GetGraph().OnInputListUpdate, [&](ShaderGraph*) { UpdateInputList(); }); + m_onInputUpdateSlot.Connect(GetGraph().OnInputUpdate, [&](ShaderGraph*, std::size_t inputIndex) + { + if (m_currentInputIndex == inputIndex) + UpdatePreview(); + }); + + UpdateInputList(); + UpdatePreview(); +} + +QWidget* InputValue::embeddedWidget() +{ + return m_widget; +} + +unsigned int InputValue::nPorts(QtNodes::PortType portType) const +{ + switch (portType) + { + case QtNodes::PortType::In: return 0; + case QtNodes::PortType::Out: return 1; + } + + return 0; +} + +void InputValue::UpdatePreview() +{ + if (m_inputSelection->count() == 0) + return; + + Q_EMIT dataUpdated(0); +} + +void InputValue::UpdateInputList() +{ + QString currentInput = m_inputSelection->currentText(); + m_inputSelection->clear(); + + for (const auto& inputEntry : GetGraph().GetInputs()) + m_inputSelection->addItem(QString::fromStdString(inputEntry.name)); + + m_inputSelection->setCurrentText(currentInput); +} + +Nz::ShaderAst::ExpressionPtr InputValue::GetExpression(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count) const +{ + assert(count == 0); + + const auto& inputEntry = GetGraph().GetInput(m_currentInputIndex); + + Nz::ShaderAst::ExpressionType expression = [&] + { + switch (inputEntry.type) + { + case InputType::Bool: return Nz::ShaderAst::ExpressionType::Boolean; + case InputType::Float1: return Nz::ShaderAst::ExpressionType::Float1; + case InputType::Float2: return Nz::ShaderAst::ExpressionType::Float2; + case InputType::Float3: return Nz::ShaderAst::ExpressionType::Float3; + case InputType::Float4: return Nz::ShaderAst::ExpressionType::Float4; + } + + assert(false); + throw std::runtime_error("Unhandled input type"); + }(); + + return Nz::ShaderBuilder::Input(inputEntry.name, expression); +} + +auto InputValue::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const -> QtNodes::NodeDataType +{ + assert(portType == QtNodes::PortType::Out); + assert(portIndex == 0); + + const auto& inputEntry = GetGraph().GetInput(m_currentInputIndex); + switch (inputEntry.type) + { + //case InputType::Bool: return Nz::ShaderAst::ExpressionType::Boolean; + //case InputType::Float1: return Nz::ShaderAst::ExpressionType::Float1; + case InputType::Float2: return Vec2Data::Type(); + //case InputType::Float3: return Nz::ShaderAst::ExpressionType::Float3; + case InputType::Float4: return Vec4Data::Type(); + } + + assert(false); + throw std::runtime_error("Unhandled input type"); +} + +std::shared_ptr InputValue::outData(QtNodes::PortIndex port) +{ + assert(port == 0); + + const auto& inputEntry = GetGraph().GetInput(m_currentInputIndex); + + auto vecData = std::make_shared(); + vecData->preview = QImage(); + + return vecData; +} diff --git a/src/ShaderNode/DataModels/InputValue.hpp b/src/ShaderNode/DataModels/InputValue.hpp new file mode 100644 index 000000000..63e896adf --- /dev/null +++ b/src/ShaderNode/DataModels/InputValue.hpp @@ -0,0 +1,47 @@ +#pragma once + +#ifndef NAZARA_SHADERNODES_INPUTVALUE_HPP +#define NAZARA_SHADERNODES_INPUTVALUE_HPP + +#include +#include +#include +#include +#include +#include + +class InputValue : public ShaderNode +{ + public: + InputValue(ShaderGraph& graph); + ~InputValue() = default; + + Nz::ShaderAst::ExpressionPtr GetExpression(Nz::ShaderAst::ExpressionPtr* /*expressions*/, std::size_t count) const override; + + QString caption() const override { return "Input"; } + QString name() const override { return "Input"; } + + QWidget* embeddedWidget() override; + unsigned int nPorts(QtNodes::PortType portType) const override; + + QtNodes::NodeDataType dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; + + std::shared_ptr outData(QtNodes::PortIndex port) override; + + protected: + void UpdatePreview(); + void UpdateInputList(); + + NazaraSlot(ShaderGraph, OnInputListUpdate, m_onInputListUpdateSlot); + NazaraSlot(ShaderGraph, OnInputUpdate, m_onInputUpdateSlot); + + std::size_t m_currentInputIndex; + QComboBox* m_inputSelection; + QLabel* m_previewLabel; + QWidget* m_widget; + QVBoxLayout* m_layout; +}; + +#include + +#endif diff --git a/src/ShaderNode/DataModels/InputValue.inl b/src/ShaderNode/DataModels/InputValue.inl new file mode 100644 index 000000000..ff350c7c4 --- /dev/null +++ b/src/ShaderNode/DataModels/InputValue.inl @@ -0,0 +1,2 @@ +#include +#include diff --git a/src/ShaderNode/DataModels/SampleTexture.cpp b/src/ShaderNode/DataModels/SampleTexture.cpp index 180989226..925094b6b 100644 --- a/src/ShaderNode/DataModels/SampleTexture.cpp +++ b/src/ShaderNode/DataModels/SampleTexture.cpp @@ -94,7 +94,20 @@ Nz::ShaderAst::ExpressionPtr SampleTexture::GetExpression(Nz::ShaderAst::Express { assert(count == 1); - auto sampler = Nz::ShaderBuilder::Uniform("Texture0", Nz::ShaderAst::ExpressionType::Sampler2D); + const auto& textureEntry = GetGraph().GetTexture(m_currentTextureIndex); + + Nz::ShaderAst::ExpressionType expression = [&] + { + switch (textureEntry.type) + { + case TextureType::Sampler2D: return Nz::ShaderAst::ExpressionType::Sampler2D; + } + + assert(false); + throw std::runtime_error("Unhandled texture type"); + }(); + + auto sampler = Nz::ShaderBuilder::Uniform(textureEntry.name, expression); return Nz::ShaderBuilder::Sample2D(sampler, expressions[0]); } diff --git a/src/ShaderNode/Enums.cpp b/src/ShaderNode/Enums.cpp new file mode 100644 index 000000000..f280ce793 --- /dev/null +++ b/src/ShaderNode/Enums.cpp @@ -0,0 +1,42 @@ +#include +#include + +const char* EnumToString(InputRole role) +{ + switch (role) + { + case InputRole::None: return "None"; + case InputRole::Normal: return "Normal"; + case InputRole::Position: return "Position"; + case InputRole::TexCoord: return "TexCoord"; + } + + assert(false); + return ""; +} + +const char* EnumToString(InputType input) +{ + switch (input) + { + case InputType::Bool: return "Bool"; + case InputType::Float1: return "Float"; + case InputType::Float2: return "Float2"; + case InputType::Float3: return "Float3"; + case InputType::Float4: return "Float4"; + } + + assert(false); + return ""; +} + +const char* EnumToString(TextureType textureType) +{ + switch (textureType) + { + case TextureType::Sampler2D: return "Sampler2D"; + } + + assert(false); + return ""; +} diff --git a/src/ShaderNode/Enums.hpp b/src/ShaderNode/Enums.hpp new file mode 100644 index 000000000..6a7a34336 --- /dev/null +++ b/src/ShaderNode/Enums.hpp @@ -0,0 +1,48 @@ +#pragma once + +#ifndef NAZARA_SHADERNODES_ENUMS_HPP +#define NAZARA_SHADERNODES_ENUMS_HPP + +#include + +enum class InputRole +{ + None, + Normal, + Position, + TexCoord, + + Max = TexCoord +}; + +constexpr std::size_t InputRoleCount = static_cast(InputRole::Max) + 1; + +enum class InputType +{ + Bool, + Float1, + Float2, + Float3, + Float4, + + Max = Float4 +}; + +constexpr std::size_t InputTypeCount = static_cast(InputType::Max) + 1; + +enum class TextureType +{ + Sampler2D, + + Max = Sampler2D +}; + +constexpr std::size_t TextureTypeCount = static_cast(TextureType::Max) + 1; + +const char* EnumToString(InputRole role); +const char* EnumToString(InputType input); +const char* EnumToString(TextureType textureType); + +#include + +#endif diff --git a/src/ShaderNode/Enums.inl b/src/ShaderNode/Enums.inl new file mode 100644 index 000000000..a23a54efb --- /dev/null +++ b/src/ShaderNode/Enums.inl @@ -0,0 +1 @@ +#include diff --git a/src/ShaderNode/ShaderGraph.cpp b/src/ShaderNode/ShaderGraph.cpp index ee02e6c11..0b95e137f 100644 --- a/src/ShaderNode/ShaderGraph.cpp +++ b/src/ShaderNode/ShaderGraph.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -35,7 +36,21 @@ m_flowScene(BuildRegistry()) m_flowScene.createConnection(node2, 0, node1, 0); } -std::size_t ShaderGraph::AddTexture(std::string name, Nz::ShaderAst::ExpressionType type) +std::size_t ShaderGraph::AddInput(std::string name, InputType type, InputRole role, std::size_t roleIndex) +{ + std::size_t index = m_inputs.size(); + auto& inputEntry = m_inputs.emplace_back(); + inputEntry.name = std::move(name); + inputEntry.role = role; + inputEntry.roleIndex = roleIndex; + inputEntry.type = type; + + OnInputListUpdate(this); + + return index; +} + +std::size_t ShaderGraph::AddTexture(std::string name, TextureType type) { std::size_t index = m_textures.size(); auto& textureEntry = m_textures.emplace_back(); @@ -85,6 +100,18 @@ Nz::ShaderAst::StatementPtr ShaderGraph::ToAst() return std::make_shared(std::move(statements)); } +void ShaderGraph::UpdateInput(std::size_t inputIndex, std::string name, InputType type, InputRole role, std::size_t roleIndex) +{ + assert(inputIndex < m_inputs.size()); + auto& inputEntry = m_inputs[inputIndex]; + inputEntry.name = std::move(name); + inputEntry.role = role; + inputEntry.roleIndex = roleIndex; + inputEntry.type = type; + + OnInputUpdate(this, inputIndex); +} + void ShaderGraph::UpdateTexturePreview(std::size_t textureIndex, QImage preview) { assert(textureIndex < m_textures.size()); @@ -98,7 +125,8 @@ void ShaderGraph::UpdateTexturePreview(std::size_t textureIndex, QImage preview) std::shared_ptr ShaderGraph::BuildRegistry() { auto registry = std::make_shared(); - RegisterShaderNode(*this, registry, "Output"); + RegisterShaderNode(*this, registry, "Outputs"); + RegisterShaderNode(*this, registry, "Inputs"); RegisterShaderNode(*this, registry, "Texture"); RegisterShaderNode(*this, registry, "Vector operations"); RegisterShaderNode(*this, registry, "Vector operations"); diff --git a/src/ShaderNode/ShaderGraph.hpp b/src/ShaderNode/ShaderGraph.hpp index cac252802..132c9c25b 100644 --- a/src/ShaderNode/ShaderGraph.hpp +++ b/src/ShaderNode/ShaderGraph.hpp @@ -6,35 +6,50 @@ #include #include #include -#include +#include #include #include class ShaderGraph { public: + struct InputEntry; struct TextureEntry; ShaderGraph(); ~ShaderGraph() = default; - std::size_t AddTexture(std::string name, Nz::ShaderAst::ExpressionType type); + std::size_t AddInput(std::string name, InputType type, InputRole role, std::size_t roleIndex); + std::size_t AddTexture(std::string name, TextureType type); + inline const InputEntry& GetInput(std::size_t inputIndex) const; + inline const std::vector& GetInputs() const; inline QtNodes::FlowScene& GetScene(); inline const TextureEntry& GetTexture(std::size_t textureIndex) const; - inline const std::vector& GetTextures(); + inline const std::vector& GetTextures() const; Nz::ShaderAst::StatementPtr ToAst(); + void UpdateInput(std::size_t inputIndex, std::string name, InputType type, InputRole role, std::size_t roleIndex); void UpdateTexturePreview(std::size_t texture, QImage preview); + struct InputEntry + { + std::size_t roleIndex; + std::string name; + InputRole role; + InputType type; + }; + struct TextureEntry { std::string name; - Nz::ShaderAst::ExpressionType type; + TextureType type; QImage preview; }; + NazaraSignal(OnInputListUpdate, ShaderGraph*); + NazaraSignal(OnInputUpdate, ShaderGraph*, std::size_t /*inputIndex*/); NazaraSignal(OnTextureListUpdate, ShaderGraph*); NazaraSignal(OnTexturePreviewUpdate, ShaderGraph*, std::size_t /*textureIndex*/); @@ -42,6 +57,7 @@ class ShaderGraph std::shared_ptr BuildRegistry(); QtNodes::FlowScene m_flowScene; + std::vector m_inputs; std::vector m_textures; }; diff --git a/src/ShaderNode/ShaderGraph.inl b/src/ShaderNode/ShaderGraph.inl index 1f0b463e9..bb39d44f3 100644 --- a/src/ShaderNode/ShaderGraph.inl +++ b/src/ShaderNode/ShaderGraph.inl @@ -1,5 +1,16 @@ #include +inline auto ShaderGraph::GetInput(std::size_t inputIndex) const -> const InputEntry& +{ + assert(inputIndex < m_inputs.size()); + return m_inputs[inputIndex]; +} + +inline auto ShaderGraph::GetInputs() const -> const std::vector& +{ + return m_inputs; +} + inline QtNodes::FlowScene& ShaderGraph::GetScene() { return m_flowScene; @@ -11,7 +22,7 @@ inline auto ShaderGraph::GetTexture(std::size_t textureIndex) const -> const Tex return m_textures[textureIndex]; } -inline auto ShaderGraph::GetTextures() -> const std::vector& +inline auto ShaderGraph::GetTextures() const -> const std::vector& { return m_textures; } diff --git a/src/ShaderNode/Widgets/InputEditDialog.cpp b/src/ShaderNode/Widgets/InputEditDialog.cpp new file mode 100644 index 000000000..d9642966c --- /dev/null +++ b/src/ShaderNode/Widgets/InputEditDialog.cpp @@ -0,0 +1,80 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +InputEditDialog::InputEditDialog(QWidget* parent) : +QDialog(parent) +{ + setWindowTitle(tr("Input edit dialog")); + setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); + + m_inputName = new QLineEdit; + + m_typeList = new QComboBox; + for (std::size_t i = 0; i < InputTypeCount; ++i) + m_typeList->addItem(EnumToString(static_cast(i))); + + m_roleList = new QComboBox; + for (std::size_t i = 0; i < InputRoleCount; ++i) + m_roleList->addItem(EnumToString(static_cast(i))); + + m_roleIndex = new QSpinBox; + + QFormLayout* formLayout = new QFormLayout; + formLayout->addRow(tr("Name"), m_inputName); + formLayout->addRow(tr("Type"), m_typeList); + formLayout->addRow(tr("Role"), m_roleList); + formLayout->addRow(tr("Role index"), m_roleIndex); + + QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); + connect(buttonBox, &QDialogButtonBox::accepted, this, &InputEditDialog::OnAccept); + connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); + + QVBoxLayout* verticalLayout = new QVBoxLayout; + verticalLayout->addLayout(formLayout); + verticalLayout->addWidget(buttonBox); + + setLayout(verticalLayout); +} + +InputEditDialog::InputEditDialog(const InputInfo& input, QWidget* parent) : +InputEditDialog(parent) +{ + m_inputName->setText(QString::fromStdString(input.name)); + m_roleIndex->setValue(int(input.roleIndex)); + m_roleList->setCurrentText(EnumToString(input.role)); + m_typeList->setCurrentText(EnumToString(input.type)); +} + +InputInfo InputEditDialog::GetInputInfo() const +{ + InputInfo inputInfo; + inputInfo.name = m_inputName->text().toStdString(); + inputInfo.role = static_cast(m_roleList->currentIndex()); + inputInfo.roleIndex = static_cast(m_roleIndex->value()); + inputInfo.type = static_cast(m_typeList->currentIndex()); + + return inputInfo; +} + +void InputEditDialog::OnAccept() +{ + if (m_inputName->text().isEmpty()) + { + QMessageBox::critical(this, tr("Empty name"), tr("Input name must be set"), QMessageBox::Ok); + return; + } + + if (m_typeList->currentIndex() < 0) + { + QMessageBox::critical(this, tr("Invalid type"), tr("You must select a type"), QMessageBox::Ok); + return; + } + + accept(); +} diff --git a/src/ShaderNode/Widgets/InputEditDialog.hpp b/src/ShaderNode/Widgets/InputEditDialog.hpp new file mode 100644 index 000000000..829697049 --- /dev/null +++ b/src/ShaderNode/Widgets/InputEditDialog.hpp @@ -0,0 +1,41 @@ +#pragma once + +#ifndef NAZARA_SHADERNODES_INPUTEDITDIALOG_HPP +#define NAZARA_SHADERNODES_INPUTEDITDIALOG_HPP + +#include +#include + +class QComboBox; +class QLineEdit; +class QSpinBox; + +struct InputInfo +{ + std::size_t roleIndex; + std::string name; + InputRole role; + InputType type; +}; + +class InputEditDialog : public QDialog +{ + public: + InputEditDialog(QWidget* parent = nullptr); + InputEditDialog(const InputInfo& input, QWidget* parent = nullptr); + ~InputEditDialog() = default; + + InputInfo GetInputInfo() const; + + private: + void OnAccept(); + + QComboBox* m_roleList; + QComboBox* m_typeList; + QLineEdit* m_inputName; + QSpinBox* m_roleIndex; +}; + +#include + +#endif diff --git a/src/ShaderNode/Widgets/InputEditDialog.inl b/src/ShaderNode/Widgets/InputEditDialog.inl new file mode 100644 index 000000000..a480716aa --- /dev/null +++ b/src/ShaderNode/Widgets/InputEditDialog.inl @@ -0,0 +1 @@ +#include diff --git a/src/ShaderNode/Widgets/InputEditor.cpp b/src/ShaderNode/Widgets/InputEditor.cpp new file mode 100644 index 000000000..86a28a2eb --- /dev/null +++ b/src/ShaderNode/Widgets/InputEditor.cpp @@ -0,0 +1,97 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +InputEditor::InputEditor(ShaderGraph& graph) : +m_shaderGraph(graph) +{ + m_inputList = new QListWidget(this); + connect(m_inputList, &QListWidget::currentRowChanged, this, &InputEditor::OnInputSelectionUpdate); + connect(m_inputList, &QListWidget::itemDoubleClicked, [this](QListWidgetItem* item) + { + OnEditInput(m_inputList->row(item)); + }); + + QPushButton* addInputButton = new QPushButton(tr("Add input...")); + connect(addInputButton, &QPushButton::released, this, &InputEditor::OnAddInput); + + m_layout = new QVBoxLayout; + m_layout->addWidget(m_inputList); + m_layout->addWidget(addInputButton); + + setLayout(m_layout); + + m_onInputListUpdateSlot.Connect(m_shaderGraph.OnInputListUpdate, this, &InputEditor::OnInputListUpdate); + m_onInputUpdateSlot.Connect(m_shaderGraph.OnInputUpdate, this, &InputEditor::OnInputUpdate); + + RefreshInputs(); +} + +void InputEditor::OnAddInput() +{ + InputEditDialog* dialog = new InputEditDialog(this); + dialog->setAttribute(Qt::WA_DeleteOnClose, true); + connect(dialog, &QDialog::accepted, [this, dialog] + { + InputInfo inputInfo = dialog->GetInputInfo(); + m_shaderGraph.AddInput(std::move(inputInfo.name), inputInfo.type, inputInfo.role, inputInfo.roleIndex); + }); + + dialog->open(); +} + +void InputEditor::OnEditInput(int inputIndex) +{ + const auto& input = m_shaderGraph.GetInput(inputIndex); + + InputInfo info; + info.name = input.name; + info.type = input.type; + info.role = input.role; + info.roleIndex = input.roleIndex; + + InputEditDialog* dialog = new InputEditDialog(std::move(info), this); + dialog->setAttribute(Qt::WA_DeleteOnClose, true); + connect(dialog, &QDialog::accepted, [this, dialog, inputIndex] + { + InputInfo inputInfo = dialog->GetInputInfo(); + m_shaderGraph.UpdateInput(inputIndex, std::move(inputInfo.name), inputInfo.type, inputInfo.role, inputInfo.roleIndex); + }); + + dialog->open(); +} + +void InputEditor::OnInputSelectionUpdate(int inputIndex) +{ + if (inputIndex >= 0) + { + m_currentInputIndex = inputIndex; + } + else + m_currentInputIndex.reset(); +} + +void InputEditor::OnInputListUpdate(ShaderGraph* /*graph*/) +{ + RefreshInputs(); +} + +void InputEditor::OnInputUpdate(ShaderGraph* /*graph*/, std::size_t inputIndex) +{ + const auto& inputEntry = m_shaderGraph.GetInput(inputIndex); + m_inputList->item(int(inputIndex))->setText(QString::fromStdString(inputEntry.name)); +} + +void InputEditor::RefreshInputs() +{ + m_inputList->clear(); + m_inputList->setCurrentRow(-1); + + for (const auto& inputEntry : m_shaderGraph.GetInputs()) + m_inputList->addItem(QString::fromStdString(inputEntry.name)); +} diff --git a/src/ShaderNode/Widgets/InputEditor.hpp b/src/ShaderNode/Widgets/InputEditor.hpp new file mode 100644 index 000000000..236f9069f --- /dev/null +++ b/src/ShaderNode/Widgets/InputEditor.hpp @@ -0,0 +1,39 @@ +#pragma once + +#ifndef NAZARA_SHADERNODES_INPUTEDITOR_HPP +#define NAZARA_SHADERNODES_INPUTEDITOR_HPP + +#include +#include +#include + +class QLabel; +class QListWidget; +class QVBoxLayout; + +class InputEditor : public QWidget +{ + public: + InputEditor(ShaderGraph& graph); + ~InputEditor() = default; + + private: + void OnAddInput(); + void OnEditInput(int inputIndex); + void OnInputSelectionUpdate(int inputIndex); + void OnInputListUpdate(ShaderGraph* graph); + void OnInputUpdate(ShaderGraph* graph, std::size_t inputIndex); + void RefreshInputs(); + + NazaraSlot(ShaderGraph, OnInputListUpdate, m_onInputListUpdateSlot); + NazaraSlot(ShaderGraph, OnInputUpdate, m_onInputUpdateSlot); + + std::optional m_currentInputIndex; + ShaderGraph& m_shaderGraph; + QListWidget* m_inputList; + QVBoxLayout* m_layout; +}; + +#include + +#endif diff --git a/src/ShaderNode/Widgets/InputEditor.inl b/src/ShaderNode/Widgets/InputEditor.inl new file mode 100644 index 000000000..a480716aa --- /dev/null +++ b/src/ShaderNode/Widgets/InputEditor.inl @@ -0,0 +1 @@ +#include diff --git a/src/ShaderNode/Widgets/MainWindow.cpp b/src/ShaderNode/Widgets/MainWindow.cpp index d4a661790..150770541 100644 --- a/src/ShaderNode/Widgets/MainWindow.cpp +++ b/src/ShaderNode/Widgets/MainWindow.cpp @@ -1,8 +1,10 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -17,6 +19,13 @@ m_shaderGraph(graph) QtNodes::FlowView* flowView = new QtNodes::FlowView(scene); setCentralWidget(flowView); + QDockWidget* inputDock = new QDockWidget(tr("&Inputs")); + + InputEditor* inputEditor = new InputEditor(m_shaderGraph); + inputDock->setWidget(inputEditor); + + addDockWidget(Qt::LeftDockWidgetArea, inputDock); + QDockWidget* textureDock = new QDockWidget(tr("&Textures")); TextureEditor* textureEditor = new TextureEditor(m_shaderGraph); diff --git a/src/ShaderNode/Widgets/TextureEditor.cpp b/src/ShaderNode/Widgets/TextureEditor.cpp index 594262c1a..44a68fec9 100644 --- a/src/ShaderNode/Widgets/TextureEditor.cpp +++ b/src/ShaderNode/Widgets/TextureEditor.cpp @@ -9,7 +9,7 @@ TextureEditor::TextureEditor(ShaderGraph& graph) : m_shaderGraph(graph) { - m_textureList = new QListWidget(this); + m_textureList = new QListWidget; connect(m_textureList, &QListWidget::currentRowChanged, this, &TextureEditor::OnTextureSelectionUpdate); m_pixmapLabel = new QLabel; diff --git a/src/ShaderNode/Widgets/TextureEditor.hpp b/src/ShaderNode/Widgets/TextureEditor.hpp index fcdbf3f7c..456b9b1d5 100644 --- a/src/ShaderNode/Widgets/TextureEditor.hpp +++ b/src/ShaderNode/Widgets/TextureEditor.hpp @@ -4,7 +4,7 @@ #define NAZARA_SHADERNODES_TEXTUREEDITOR_HPP #include -#include +#include #include class QLabel; diff --git a/src/ShaderNode/main.cpp b/src/ShaderNode/main.cpp index 648cbbbbc..a9554c8bd 100644 --- a/src/ShaderNode/main.cpp +++ b/src/ShaderNode/main.cpp @@ -8,8 +8,8 @@ int main(int argc, char* argv[]) QApplication app(argc, argv); ShaderGraph shaderGraph; - shaderGraph.AddTexture("Potato", Nz::ShaderAst::ExpressionType::Sampler2D); - shaderGraph.AddTexture("Blackbird", Nz::ShaderAst::ExpressionType::Sampler2D); + shaderGraph.AddInput("UV", InputType::Float2, InputRole::TexCoord, 0); + shaderGraph.AddTexture("Potato", TextureType::Sampler2D); MainWindow mainWindow(shaderGraph); mainWindow.resize(1280, 720); From 93e76a17c7ba2888e303db2fa8401e9abb105a4d Mon Sep 17 00:00:00 2001 From: Lynix Date: Sat, 23 May 2020 22:04:10 +0200 Subject: [PATCH 008/105] ShaderNode: Add preview / cast / texture sampling --- src/ShaderNode/DataModels/Cast.cpp | 0 src/ShaderNode/DataModels/Cast.hpp | 59 ++++++ src/ShaderNode/DataModels/Cast.inl | 201 ++++++++++++++++++++ src/ShaderNode/DataModels/InputValue.cpp | 18 +- src/ShaderNode/DataModels/SampleTexture.cpp | 65 ++++++- src/ShaderNode/DataModels/SampleTexture.hpp | 5 + src/ShaderNode/DataModels/VecBinOp.cpp | 22 --- src/ShaderNode/DataModels/VecBinOp.hpp | 48 +++-- src/ShaderNode/DataModels/VecBinOp.inl | 86 ++++++++- src/ShaderNode/DataModels/VecData.cpp | 1 + src/ShaderNode/DataModels/VecData.hpp | 67 +++++++ src/ShaderNode/DataModels/VecData.inl | 7 + src/ShaderNode/DataModels/VecValue.hpp | 65 ++----- src/ShaderNode/DataModels/VecValue.inl | 83 ++++---- src/ShaderNode/Previews/PreviewModel.cpp | 3 + src/ShaderNode/Previews/PreviewModel.hpp | 21 ++ src/ShaderNode/Previews/PreviewModel.inl | 1 + src/ShaderNode/Previews/QuadPreview.cpp | 24 +++ src/ShaderNode/Previews/QuadPreview.hpp | 20 ++ src/ShaderNode/Previews/QuadPreview.inl | 1 + src/ShaderNode/ShaderGraph.cpp | 23 +++ src/ShaderNode/ShaderGraph.hpp | 5 +- src/ShaderNode/ShaderGraph.inl | 5 + 23 files changed, 686 insertions(+), 144 deletions(-) create mode 100644 src/ShaderNode/DataModels/Cast.cpp create mode 100644 src/ShaderNode/DataModels/Cast.hpp create mode 100644 src/ShaderNode/DataModels/Cast.inl create mode 100644 src/ShaderNode/DataModels/VecData.cpp create mode 100644 src/ShaderNode/DataModels/VecData.hpp create mode 100644 src/ShaderNode/DataModels/VecData.inl create mode 100644 src/ShaderNode/Previews/PreviewModel.cpp create mode 100644 src/ShaderNode/Previews/PreviewModel.hpp create mode 100644 src/ShaderNode/Previews/PreviewModel.inl create mode 100644 src/ShaderNode/Previews/QuadPreview.cpp create mode 100644 src/ShaderNode/Previews/QuadPreview.hpp create mode 100644 src/ShaderNode/Previews/QuadPreview.inl diff --git a/src/ShaderNode/DataModels/Cast.cpp b/src/ShaderNode/DataModels/Cast.cpp new file mode 100644 index 000000000..e69de29bb diff --git a/src/ShaderNode/DataModels/Cast.hpp b/src/ShaderNode/DataModels/Cast.hpp new file mode 100644 index 000000000..f17cff625 --- /dev/null +++ b/src/ShaderNode/DataModels/Cast.hpp @@ -0,0 +1,59 @@ +#pragma once + +#ifndef NAZARA_SHADERNODES_CAST_HPP +#define NAZARA_SHADERNODES_CAST_HPP + +#include +#include +#include +#include +#include +#include +#include + +template +class CastVec : public ShaderNode +{ + public: + CastVec(ShaderGraph& graph); + ~CastVec() = default; + + Nz::ShaderAst::ExpressionPtr GetExpression(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count) const override; + + QString caption() const override; + QString name() const override; + + QtNodes::NodeDataType dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; + QWidget* embeddedWidget() override; + unsigned int nPorts(QtNodes::PortType portType) const override; + + std::shared_ptr outData(QtNodes::PortIndex port) override; + + void setInData(std::shared_ptr value, int index) override; + + private: + static constexpr std::size_t FromComponents = From::ComponentCount; + static constexpr std::size_t ToComponents = To::ComponentCount; + static constexpr std::size_t ComponentDiff = (ToComponents >= FromComponents) ? ToComponents - FromComponents : 0; + + void ComputePreview(QPixmap& pixmap) const; + void UpdatePreview(); + + QLabel* m_pixmapLabel; + QPixmap m_pixmap; + QWidget* m_widget; + std::array m_spinboxes; + std::shared_ptr m_input; + std::shared_ptr m_output; +}; + +using CastVec2ToVec3 = CastVec; +using CastVec2ToVec4 = CastVec; +using CastVec3ToVec2 = CastVec; +using CastVec3ToVec4 = CastVec; +using CastVec4ToVec2 = CastVec; +using CastVec4ToVec3 = CastVec; + +#include + +#endif diff --git a/src/ShaderNode/DataModels/Cast.inl b/src/ShaderNode/DataModels/Cast.inl new file mode 100644 index 000000000..9e70e9f8b --- /dev/null +++ b/src/ShaderNode/DataModels/Cast.inl @@ -0,0 +1,201 @@ +#include +#include +#include + +template +CastVec::CastVec(ShaderGraph& graph) : +ShaderNode(graph) +{ + constexpr std::array componentName = { 'X', 'Y', 'Z', 'W' }; + static_assert(ComponentDiff <= componentName.size()); + + QFormLayout* layout = new QFormLayout; + + if constexpr (ComponentDiff > 0) + { + for (std::size_t i = 0; i < ComponentDiff; ++i) + { + m_spinboxes[i] = new QDoubleSpinBox; + m_spinboxes[i]->setDecimals(6); + m_spinboxes[i]->setValue(1.0); + m_spinboxes[i]->setStyleSheet("background-color: rgba(255,255,255,255)"); + connect(m_spinboxes[i], qOverload(&QDoubleSpinBox::valueChanged), [this](double) + { + UpdatePreview(); + }); + + layout->addRow(QString::fromUtf8(&componentName[FromComponents + i], 1), m_spinboxes[i]); + } + } + + m_pixmap = QPixmap(64, 64); + m_pixmap.fill(); + + m_pixmapLabel = new QLabel; + m_pixmapLabel->setPixmap(m_pixmap); + + layout->addWidget(m_pixmapLabel); + + m_widget = new QWidget; + m_widget->setStyleSheet("background-color: rgba(0,0,0,0)"); + m_widget->setLayout(layout); + + m_output = std::make_shared(); +} + +template +Nz::ShaderAst::ExpressionPtr CastVec::GetExpression(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count) const +{ + assert(count == 1); + + if constexpr (ComponentDiff > 0) + { + std::array constants; + for (std::size_t i = 0; i < ComponentDiff; ++i) + constants[i] = Nz::ShaderBuilder::Constant(float(m_spinboxes[i]->value())); + + return std::apply([&](auto&&... values) + { + return Nz::ShaderBuilder::Cast(expressions[0], values...); //< TODO: Forward + }, constants); + } + else + { + std::array swizzleComponents; + for (std::size_t i = 0; i < ToComponents; ++i) + swizzleComponents[i] = static_cast(static_cast(Nz::ShaderAst::SwizzleComponent::First) + i); + + return std::apply([&](auto... components) + { + std::initializer_list componentList{ components... }; + return Nz::ShaderBuilder::Swizzle(expressions[0], componentList); + }, swizzleComponents); + } +} + +template +QString CastVec::caption() const +{ + static QString caption = From::Type().name + " to " + To::Type().name; + return caption; +} + +template +QString CastVec::name() const +{ + static QString name = From::Type().id + "to" + To::Type().id; + return name; +} + +template +QtNodes::NodeDataType CastVec::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const +{ + assert(portIndex == 0); + + switch (portType) + { + case QtNodes::PortType::In: return From::Type(); + case QtNodes::PortType::Out: return To::Type(); + } + + assert(false); + throw std::runtime_error("Invalid port type"); +} + +template +QWidget* CastVec::embeddedWidget() +{ + return m_widget; +} + +template +unsigned int CastVec::nPorts(QtNodes::PortType portType) const +{ + switch (portType) + { + case QtNodes::PortType::In: return 1; + case QtNodes::PortType::Out: return 1; + } + + return 0; +} + +template +std::shared_ptr CastVec::outData(QtNodes::PortIndex port) +{ + assert(port == 0); + return m_output; +} + +template +void CastVec::setInData(std::shared_ptr value, int index) +{ + assert(index == 0); + if (value) + { + assert(dynamic_cast(value.get()) != nullptr); + m_input = std::static_pointer_cast(value); + } + else + m_input.reset(); + + UpdatePreview(); +} + +template +void CastVec::ComputePreview(QPixmap& pixmap) const +{ + assert(m_input); + + const QImage& input = m_input->preview; + + int inputWidth = input.width(); + int inputHeight = input.height(); + + QImage& output = m_output->preview; + output = QImage(inputWidth, inputHeight, QImage::Format_RGBA8888); + + std::array constants; + for (std::size_t i = 0; i < ComponentDiff; ++i) + constants[i] = static_cast(std::clamp(int(m_spinboxes[i]->value() * 255), 0, 255)); + + std::uint8_t* outputPtr = output.bits(); + const std::uint8_t* inputPtr = input.constBits(); + for (int y = 0; y < inputHeight; ++y) + { + for (int x = 0; x < inputWidth; ++x) + { + constexpr std::size_t CommonComponents = std::min(FromComponents, ToComponents); + constexpr std::size_t VoidComponents = 4 - ComponentDiff - CommonComponents; + + for (std::size_t i = 0; i < CommonComponents; ++i) + *outputPtr++ = inputPtr[i]; + + for (std::size_t i = 0; i < ComponentDiff; ++i) + *outputPtr++ = constants[i]; + + for (std::size_t i = 0; i < VoidComponents; ++i) + *outputPtr++ = (i == VoidComponents - 1) ? 255 : 0; + + inputPtr += 4; + } + } + + pixmap = QPixmap::fromImage(output).scaled(64, 64); +} + +template +void CastVec::UpdatePreview() +{ + if (!m_input) + { + m_pixmap = QPixmap(64, 64); + m_pixmap.fill(QColor::fromRgb(255, 255, 255, 0)); + } + else + ComputePreview(m_pixmap); + + m_pixmapLabel->setPixmap(m_pixmap); + + Q_EMIT dataUpdated(0); +} diff --git a/src/ShaderNode/DataModels/InputValue.cpp b/src/ShaderNode/DataModels/InputValue.cpp index f1cc97d0d..1a1bdfb5a 100644 --- a/src/ShaderNode/DataModels/InputValue.cpp +++ b/src/ShaderNode/DataModels/InputValue.cpp @@ -62,6 +62,12 @@ void InputValue::UpdatePreview() if (m_inputSelection->count() == 0) return; + const ShaderGraph& graph = GetGraph(); + const auto& inputEntry = graph.GetInput(m_currentInputIndex); + const auto& preview = graph.GetPreviewModel(); + + m_previewLabel->setPixmap(QPixmap::fromImage(preview.GetImage(inputEntry.role, inputEntry.roleIndex))); + Q_EMIT dataUpdated(0); } @@ -76,7 +82,7 @@ void InputValue::UpdateInputList() m_inputSelection->setCurrentText(currentInput); } -Nz::ShaderAst::ExpressionPtr InputValue::GetExpression(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count) const +Nz::ShaderAst::ExpressionPtr InputValue::GetExpression(Nz::ShaderAst::ExpressionPtr* /*expressions*/, std::size_t count) const { assert(count == 0); @@ -111,7 +117,7 @@ auto InputValue::dataType(QtNodes::PortType portType, QtNodes::PortIndex portInd //case InputType::Bool: return Nz::ShaderAst::ExpressionType::Boolean; //case InputType::Float1: return Nz::ShaderAst::ExpressionType::Float1; case InputType::Float2: return Vec2Data::Type(); - //case InputType::Float3: return Nz::ShaderAst::ExpressionType::Float3; + case InputType::Float3: return Vec3Data::Type(); case InputType::Float4: return Vec4Data::Type(); } @@ -123,10 +129,12 @@ std::shared_ptr InputValue::outData(QtNodes::PortIndex port) { assert(port == 0); - const auto& inputEntry = GetGraph().GetInput(m_currentInputIndex); + const ShaderGraph& graph = GetGraph(); + const auto& inputEntry = graph.GetInput(m_currentInputIndex); + const auto& preview = graph.GetPreviewModel(); - auto vecData = std::make_shared(); - vecData->preview = QImage(); + auto vecData = std::make_shared(); + vecData->preview = preview.GetImage(inputEntry.role, inputEntry.roleIndex); return vecData; } diff --git a/src/ShaderNode/DataModels/SampleTexture.cpp b/src/ShaderNode/DataModels/SampleTexture.cpp index 925094b6b..d7ae63713 100644 --- a/src/ShaderNode/DataModels/SampleTexture.cpp +++ b/src/ShaderNode/DataModels/SampleTexture.cpp @@ -7,6 +7,8 @@ SampleTexture::SampleTexture(ShaderGraph& graph) : ShaderNode(graph), m_currentTextureIndex(0) { + m_output = std::make_shared(); + m_layout = new QVBoxLayout; m_textureSelection = new QComboBox; @@ -85,9 +87,45 @@ void SampleTexture::UpdateTextureList() void SampleTexture::ComputePreview(QPixmap& pixmap) const { + if (!m_uv) + return; + const auto& textureEntry = GetGraph().GetTexture(m_currentTextureIndex); - pixmap = QPixmap::fromImage(textureEntry.preview).scaled(128, 128, Qt::KeepAspectRatio); + int textureWidth = textureEntry.preview.width(); + int textureHeight = textureEntry.preview.height(); + + QImage& output = m_output->preview; + const QImage& uv = m_uv->preview; + + int uvWidth = uv.width(); + int uvHeight = uv.height(); + + output = QImage(uvWidth, uvHeight, QImage::Format_RGBA8888); + + std::uint8_t* outputPtr = output.bits(); + const std::uint8_t* uvPtr = uv.constBits(); + const std::uint8_t* texturePtr = textureEntry.preview.constBits(); + for (int y = 0; y < uvHeight; ++y) + { + for (int x = 0; x < uvWidth; ++x) + { + float u = float(uvPtr[0]) / 255; + float v = float(uvPtr[1]) / 255; + + int texX = std::clamp(int(u * textureWidth), 0, textureWidth - 1); + int texY = std::clamp(int(v * textureHeight), 0, textureHeight - 1); + int texPixel = (texY * textureWidth + texX) * 4; + + *outputPtr++ = texturePtr[texPixel + 0]; + *outputPtr++ = texturePtr[texPixel + 1]; + *outputPtr++ = texturePtr[texPixel + 2]; + *outputPtr++ = texturePtr[texPixel + 3]; + uvPtr += 4; + } + } + + pixmap = QPixmap::fromImage(output).scaled(128, 128, Qt::KeepAspectRatio); } Nz::ShaderAst::ExpressionPtr SampleTexture::GetExpression(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count) const @@ -156,7 +194,7 @@ QString SampleTexture::portCaption(QtNodes::PortType portType, QtNodes::PortInde } } -bool SampleTexture::portCaptionVisible(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const +bool SampleTexture::portCaptionVisible(QtNodes::PortType /*portType*/, QtNodes::PortIndex /*portIndex*/) const { return true; } @@ -165,10 +203,21 @@ std::shared_ptr SampleTexture::outData(QtNodes::PortIndex por { assert(port == 0); - const auto& textureEntry = GetGraph().GetTexture(m_currentTextureIndex); - - auto vecData = std::make_shared(); - vecData->preview = textureEntry.preview; - - return vecData; + return m_output; +} + +void SampleTexture::setInData(std::shared_ptr value, int index) +{ + assert(index == 0); + + if (value) + { + assert(dynamic_cast(value.get()) != nullptr); + + m_uv = std::static_pointer_cast(value); + } + else + m_uv.reset(); + + UpdatePreview(); } diff --git a/src/ShaderNode/DataModels/SampleTexture.hpp b/src/ShaderNode/DataModels/SampleTexture.hpp index af11d14ec..3621d0c14 100644 --- a/src/ShaderNode/DataModels/SampleTexture.hpp +++ b/src/ShaderNode/DataModels/SampleTexture.hpp @@ -8,6 +8,7 @@ #include #include #include +#include #include class SampleTexture : public ShaderNode @@ -32,6 +33,8 @@ class SampleTexture : public ShaderNode std::shared_ptr outData(QtNodes::PortIndex port) override; + void setInData(std::shared_ptr value, int index) override; + protected: void ComputePreview(QPixmap& pixmap) const; void UpdatePreview(); @@ -41,6 +44,8 @@ class SampleTexture : public ShaderNode NazaraSlot(ShaderGraph, OnTexturePreviewUpdate, m_onTexturePreviewUpdateSlot); std::size_t m_currentTextureIndex; + std::shared_ptr m_uv; + std::shared_ptr m_output; QComboBox* m_textureSelection; QLabel* m_pixmapLabel; QPixmap m_pixmap; diff --git a/src/ShaderNode/DataModels/VecBinOp.cpp b/src/ShaderNode/DataModels/VecBinOp.cpp index 7349b708f..dd13b5b56 100644 --- a/src/ShaderNode/DataModels/VecBinOp.cpp +++ b/src/ShaderNode/DataModels/VecBinOp.cpp @@ -1,23 +1 @@ #include - -void Vec4Add::ApplyOp(const std::uint8_t* left, const std::uint8_t* right, std::uint8_t* output, std::size_t pixelCount) -{ - for (std::size_t i = 0; i < pixelCount; ++i) - { - unsigned int lValue = left[i]; - unsigned int rValue = right[i]; - - output[i] = static_cast(std::min(lValue + rValue, 255U)); - } -} - -void Vec4Mul::ApplyOp(const std::uint8_t* left, const std::uint8_t* right, std::uint8_t* output, std::size_t pixelCount) -{ - for (std::size_t i = 0; i < pixelCount; ++i) - { - unsigned int lValue = left[i]; - unsigned int rValue = right[i]; - - output[i] = static_cast(lValue * rValue / 255); - } -} diff --git a/src/ShaderNode/DataModels/VecBinOp.hpp b/src/ShaderNode/DataModels/VecBinOp.hpp index 97f433048..31ae4732e 100644 --- a/src/ShaderNode/DataModels/VecBinOp.hpp +++ b/src/ShaderNode/DataModels/VecBinOp.hpp @@ -30,33 +30,59 @@ class VecBinOp : public ShaderNode QLabel* m_pixmapLabel; QPixmap m_preview; - std::shared_ptr m_lhs; - std::shared_ptr m_rhs; - std::shared_ptr m_output; + std::shared_ptr m_lhs; + std::shared_ptr m_rhs; + std::shared_ptr m_output; }; -class Vec4Add : public VecBinOp +template +class VecAdd : public VecBinOp { public: - using VecBinOp::VecBinOp; + using VecBinOp::VecBinOp; - QString caption() const override { return "Vec4 addition"; } - QString name() const override { return "Vec4Add"; } + QString caption() const override; + QString name() const override; void ApplyOp(const std::uint8_t* left, const std::uint8_t* right, std::uint8_t* output, std::size_t pixelCount) override; }; -class Vec4Mul : public VecBinOp +template +class VecMul : public VecBinOp { public: - using VecBinOp::VecBinOp; + using VecBinOp::VecBinOp; - QString caption() const override { return "Vec4 multiplication"; } - QString name() const override { return "Vec4Mul"; } + QString caption() const override; + QString name() const override; void ApplyOp(const std::uint8_t* left, const std::uint8_t* right, std::uint8_t* output, std::size_t pixelCount) override; }; +template +class VecSub : public VecBinOp +{ + public: + using VecBinOp::VecBinOp; + + QString caption() const override; + QString name() const override; + + void ApplyOp(const std::uint8_t* left, const std::uint8_t* right, std::uint8_t* output, std::size_t pixelCount) override; +}; + +using Vec2Add = VecAdd; +using Vec3Add = VecAdd; +using Vec4Add = VecAdd; + +using Vec2Mul = VecMul; +using Vec3Mul = VecMul; +using Vec4Mul = VecMul; + +using Vec2Sub = VecSub; +using Vec3Sub = VecSub; +using Vec4Sub = VecSub; + #include #endif diff --git a/src/ShaderNode/DataModels/VecBinOp.inl b/src/ShaderNode/DataModels/VecBinOp.inl index fea7837a7..5d5cfc251 100644 --- a/src/ShaderNode/DataModels/VecBinOp.inl +++ b/src/ShaderNode/DataModels/VecBinOp.inl @@ -96,14 +96,10 @@ void VecBinOp::UpdatePreview() if (rightResized.width() != maxWidth || rightResized.height() != maxHeight) rightResized = rightResized.scaled(maxWidth, maxHeight); - int w = m_output->preview.width(); - int h = m_output->preview.height(); - m_output->preview = QImage(maxWidth, maxHeight, QImage::Format_RGBA8888); ApplyOp(leftResized.constBits(), rightResized.constBits(), m_output->preview.bits(), maxWidth * maxHeight * 4); - m_output->preview = m_output->preview.scaled(w, h); - m_preview = QPixmap::fromImage(m_output->preview, Qt::AutoColor | Qt::NoOpaqueDetection); + m_preview = QPixmap::fromImage(m_output->preview).scaled(64, 64); } else { @@ -113,3 +109,83 @@ void VecBinOp::UpdatePreview() m_pixmapLabel->setPixmap(m_preview); } + +template +QString VecAdd::caption() const +{ + static QString caption = Data::Type().name + " addition"; + return caption; +} + +template +QString VecAdd::name() const +{ + static QString name = Data::Type().name + "add"; + return name; +} + +template +void VecAdd::ApplyOp(const std::uint8_t* left, const std::uint8_t* right, std::uint8_t* output, std::size_t pixelCount) +{ + for (std::size_t i = 0; i < pixelCount; ++i) + { + unsigned int lValue = left[i]; + unsigned int rValue = right[i]; + + output[i] = static_cast(std::min(lValue + rValue, 255U)); + } +} + +template +QString VecMul::caption() const +{ + static QString caption = Data::Type().name + " multiplication"; + return caption; +} + +template +QString VecMul::name() const +{ + static QString name = Data::Type().name + "mul"; + return name; +} + +template +void VecMul::ApplyOp(const std::uint8_t* left, const std::uint8_t* right, std::uint8_t* output, std::size_t pixelCount) +{ + for (std::size_t i = 0; i < pixelCount; ++i) + { + unsigned int lValue = left[i]; + unsigned int rValue = right[i]; + + output[i] = static_cast(lValue * rValue / 255); + } +} + +template +QString VecSub::caption() const +{ + static QString caption = Data::Type().name + " subtraction"; + return caption; +} + +template +QString VecSub::name() const +{ + static QString name = Data::Type().name + "sub"; + return name; +} + +template +void VecSub::ApplyOp(const std::uint8_t* left, const std::uint8_t* right, std::uint8_t* output, std::size_t pixelCount) +{ + for (std::size_t i = 0; i < pixelCount; ++i) + { + unsigned int lValue = left[i]; + unsigned int rValue = right[i]; + + unsigned int sub = (lValue >= rValue) ? lValue - rValue : 0u; + + output[i] = static_cast(sub); + } +} diff --git a/src/ShaderNode/DataModels/VecData.cpp b/src/ShaderNode/DataModels/VecData.cpp new file mode 100644 index 000000000..2cf74c1e6 --- /dev/null +++ b/src/ShaderNode/DataModels/VecData.cpp @@ -0,0 +1 @@ +#include diff --git a/src/ShaderNode/DataModels/VecData.hpp b/src/ShaderNode/DataModels/VecData.hpp new file mode 100644 index 000000000..ad44d68b1 --- /dev/null +++ b/src/ShaderNode/DataModels/VecData.hpp @@ -0,0 +1,67 @@ +#pragma once + +#ifndef NAZARA_SHADERNODES_VECDATA_HPP +#define NAZARA_SHADERNODES_VECDATA_HPP + +#include +#include +#include + +struct VecData : public QtNodes::NodeData +{ + inline VecData(); + + QImage preview; +}; + +struct Vec2Data : public VecData +{ + static constexpr std::size_t ComponentCount = 2; + static constexpr Nz::ShaderAst::ExpressionType ExpressionType = Nz::ShaderAst::ExpressionType::Float2; + + QtNodes::NodeDataType type() const override + { + return Type(); + } + + static QtNodes::NodeDataType Type() + { + return { "vec2", "Vec2" }; + } +}; + +struct Vec3Data : public VecData +{ + static constexpr std::size_t ComponentCount = 3; + static constexpr Nz::ShaderAst::ExpressionType ExpressionType = Nz::ShaderAst::ExpressionType::Float3; + + QtNodes::NodeDataType type() const override + { + return Type(); + } + + static QtNodes::NodeDataType Type() + { + return { "vec3", "Vec3" }; + } +}; + +struct Vec4Data : public VecData +{ + static constexpr std::size_t ComponentCount = 4; + static constexpr Nz::ShaderAst::ExpressionType ExpressionType = Nz::ShaderAst::ExpressionType::Float4; + + QtNodes::NodeDataType type() const override + { + return Type(); + } + + static QtNodes::NodeDataType Type() + { + return { "vec4", "Vec4" }; + } +}; + +#include + +#endif diff --git a/src/ShaderNode/DataModels/VecData.inl b/src/ShaderNode/DataModels/VecData.inl new file mode 100644 index 000000000..92765c835 --- /dev/null +++ b/src/ShaderNode/DataModels/VecData.inl @@ -0,0 +1,7 @@ +#include + +inline VecData::VecData() : +preview(64, 64, QImage::Format_RGBA8888) +{ + preview.fill(QColor::fromRgb(255, 255, 255, 0)); +} diff --git a/src/ShaderNode/DataModels/VecValue.hpp b/src/ShaderNode/DataModels/VecValue.hpp index ba7a61f08..77656f373 100644 --- a/src/ShaderNode/DataModels/VecValue.hpp +++ b/src/ShaderNode/DataModels/VecValue.hpp @@ -8,6 +8,7 @@ #include #include #include +#include #include template @@ -33,13 +34,16 @@ struct VecTypeHelper<4> template using VecType = typename VecTypeHelper::template Type; -template +template class VecValue : public ShaderNode { public: VecValue(ShaderGraph& graph); ~VecValue() = default; + QString caption() const override; + QString name() const override; + QtNodes::NodeDataType dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; QWidget* embeddedWidget() override; @@ -50,67 +54,22 @@ class VecValue : public ShaderNode Nz::ShaderAst::ExpressionPtr GetExpression(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count) const override; protected: + static constexpr std::size_t ComponentCount = Data::ComponentCount; + QColor ToColor() const; - VecType ToVector() const; + VecType ToVector() const; void UpdatePreview(); QLabel* m_pixmapLabel; QPixmap m_pixmap; QWidget* m_widget; QFormLayout* m_layout; - std::array m_spinboxes; + std::array m_spinboxes; }; -struct VecData : public QtNodes::NodeData -{ - inline VecData(); - - QImage preview; -}; - -struct Vec2Data : public VecData -{ - QtNodes::NodeDataType type() const override - { - return Type(); - } - - static QtNodes::NodeDataType Type() - { - return { "vec2", "Vec2" }; - } -}; - -struct Vec4Data : public VecData -{ - QtNodes::NodeDataType type() const override - { - return Type(); - } - - static QtNodes::NodeDataType Type() - { - return { "vec4", "Vec4" }; - } -}; - -class Vec2Value : public VecValue<2, Vec2Data> -{ - public: - using VecValue::VecValue; - - QString caption() const override { return "Vec2 value"; } - QString name() const override { return "Vec2Value"; } -}; - -class Vec4Value : public VecValue<4, Vec4Data> -{ - public: - using VecValue::VecValue; - - QString caption() const override { return "Vec4 value"; } - QString name() const override { return "Vec4Value"; } -}; +using Vec2Value = VecValue; +using Vec3Value = VecValue; +using Vec4Value = VecValue; #include diff --git a/src/ShaderNode/DataModels/VecValue.inl b/src/ShaderNode/DataModels/VecValue.inl index 8f8a53fc7..3ab11cd37 100644 --- a/src/ShaderNode/DataModels/VecValue.inl +++ b/src/ShaderNode/DataModels/VecValue.inl @@ -2,16 +2,17 @@ #include #include #include +#include -template -VecValue::VecValue(ShaderGraph& graph) : +template +VecValue::VecValue(ShaderGraph& graph) : ShaderNode(graph) { constexpr std::array componentName = { 'X', 'Y', 'Z', 'W' }; - static_assert(N <= componentName.size()); + static_assert(ComponentCount <= componentName.size()); m_layout = new QFormLayout; - for (std::size_t i = 0; i < N; ++i) + for (std::size_t i = 0; i < ComponentCount; ++i) { m_spinboxes[i] = new QDoubleSpinBox; m_spinboxes[i]->setDecimals(6); @@ -42,8 +43,22 @@ ShaderNode(graph) UpdatePreview(); } -template -QtNodes::NodeDataType VecValue::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const +template +QString VecValue::caption() const +{ + static QString caption = Data::Type().name + " constant"; + return caption; +} + +template +QString VecValue::name() const +{ + static QString name = Data::Type().id + "Value"; + return name; +} + +template +QtNodes::NodeDataType VecValue::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const { assert(portType == QtNodes::PortType::Out); assert(portIndex == 0); @@ -51,14 +66,14 @@ QtNodes::NodeDataType VecValue::dataType(QtNodes::PortType portType, Qt return Data::Type(); } -template -QWidget* VecValue::embeddedWidget() +template +QWidget* VecValue::embeddedWidget() { return m_widget; } -template -unsigned int VecValue::nPorts(QtNodes::PortType portType) const +template +unsigned int VecValue::nPorts(QtNodes::PortType portType) const { switch (portType) { @@ -69,8 +84,8 @@ unsigned int VecValue::nPorts(QtNodes::PortType portType) const return 0; } -template -std::shared_ptr VecValue::outData(QtNodes::PortIndex port) +template +std::shared_ptr VecValue::outData(QtNodes::PortIndex port) { assert(port == 0); @@ -81,52 +96,42 @@ std::shared_ptr VecValue::outData(QtNodes::PortIndex return out; } -template -Nz::ShaderAst::ExpressionPtr VecValue::GetExpression(Nz::ShaderAst::ExpressionPtr* /*expressions*/, std::size_t count) const +template +Nz::ShaderAst::ExpressionPtr VecValue::GetExpression(Nz::ShaderAst::ExpressionPtr* /*expressions*/, std::size_t count) const { assert(count == 0); return Nz::ShaderBuilder::Constant(ToVector()); } -template -QColor VecValue::ToColor() const +template +QColor VecValue::ToColor() const { std::array values = { 0.f, 0.f, 0.f, 1.f }; - for (std::size_t i = 0; i < N; ++i) - values[i] = std::clamp(m_spinboxes[i]->value(), 0.0, 1.0); + for (std::size_t i = 0; i < ComponentCount; ++i) + values[i] = std::clamp(float(m_spinboxes[i]->value()), 0.f, 1.f); return QColor::fromRgbF(values[0], values[1], values[2], values[3]); } -template -VecType VecValue::ToVector() const +template +auto VecValue::ToVector() const -> VecType { - std::array values = { 0.f, 0.f, 0.f, 1.f }; + std::array values; - for (std::size_t i = 0; i < N; ++i) - values[i] = std::clamp(m_spinboxes[i]->value(), 0.0, 1.0); + for (std::size_t i = 0; i < ComponentCount; ++i) + values[i] = std::clamp(float(m_spinboxes[i]->value()), 0.f, 1.f); - if constexpr (N == 2) - return Nz::Vector2f(values[0], values[1]); - else if constexpr (N == 3) - return Nz::Vector3f(values[0], values[1], values[2]); - else if constexpr (N == 4) - return Nz::Vector4f(values[0], values[1], values[2], values[3]); - else - static_assert(Nz::AlwaysFalse>(), "Unhandled vector size"); + return std::apply([](auto... values) + { + return VecType(values...); + }, values); } -template -void VecValue::UpdatePreview() +template +void VecValue::UpdatePreview() { m_pixmap.fill(ToColor()); m_pixmapLabel->setPixmap(m_pixmap); } - -inline VecData::VecData() : -preview(64, 64, QImage::Format_RGBA8888) -{ - preview.fill(QColor::fromRgb(255, 255, 255, 0)); -} diff --git a/src/ShaderNode/Previews/PreviewModel.cpp b/src/ShaderNode/Previews/PreviewModel.cpp new file mode 100644 index 000000000..845c19fe2 --- /dev/null +++ b/src/ShaderNode/Previews/PreviewModel.cpp @@ -0,0 +1,3 @@ +#include + +PreviewModel::~PreviewModel() = default; diff --git a/src/ShaderNode/Previews/PreviewModel.hpp b/src/ShaderNode/Previews/PreviewModel.hpp new file mode 100644 index 000000000..138374ea4 --- /dev/null +++ b/src/ShaderNode/Previews/PreviewModel.hpp @@ -0,0 +1,21 @@ +#pragma once + +#ifndef NAZARA_SHADERNODES_PREVIEWMODEL_HPP +#define NAZARA_SHADERNODES_PREVIEWMODEL_HPP + +#include + +class QImage; + +class PreviewModel +{ + public: + PreviewModel() = default; + virtual ~PreviewModel(); + + virtual QImage GetImage(InputRole role, std::size_t roleIndex) const = 0; +}; + +#include + +#endif diff --git a/src/ShaderNode/Previews/PreviewModel.inl b/src/ShaderNode/Previews/PreviewModel.inl new file mode 100644 index 000000000..d5f2e699b --- /dev/null +++ b/src/ShaderNode/Previews/PreviewModel.inl @@ -0,0 +1 @@ +#include diff --git a/src/ShaderNode/Previews/QuadPreview.cpp b/src/ShaderNode/Previews/QuadPreview.cpp new file mode 100644 index 000000000..a518287fd --- /dev/null +++ b/src/ShaderNode/Previews/QuadPreview.cpp @@ -0,0 +1,24 @@ +#include +#include + +QImage QuadPreview::GetImage(InputRole role, std::size_t roleIndex) const +{ + assert(role == InputRole::TexCoord); + assert(roleIndex == 0); + + QImage uv(128, 128, QImage::Format_RGBA8888); + + std::uint8_t* content = uv.bits(); + for (std::size_t y = 0; y < 128; ++y) + { + for (std::size_t x = 0; x < 128; ++x) + { + *content++ = (x * 255) / 128; + *content++ = (y * 255) / 128; + *content++ = 0; + *content++ = 255; + } + } + + return uv; +} diff --git a/src/ShaderNode/Previews/QuadPreview.hpp b/src/ShaderNode/Previews/QuadPreview.hpp new file mode 100644 index 000000000..f193e99d0 --- /dev/null +++ b/src/ShaderNode/Previews/QuadPreview.hpp @@ -0,0 +1,20 @@ +#pragma once + +#ifndef NAZARA_SHADERNODES_QUADPREVIEW_HPP +#define NAZARA_SHADERNODES_QUADPREVIEW_HPP + +#include +#include + +class QuadPreview : public PreviewModel +{ + public: + QuadPreview() = default; + ~QuadPreview() = default; + + QImage GetImage(InputRole role, std::size_t roleIndex) const override; +}; + +#include + +#endif diff --git a/src/ShaderNode/Previews/QuadPreview.inl b/src/ShaderNode/Previews/QuadPreview.inl new file mode 100644 index 000000000..01178d2d2 --- /dev/null +++ b/src/ShaderNode/Previews/QuadPreview.inl @@ -0,0 +1 @@ +#include diff --git a/src/ShaderNode/ShaderGraph.cpp b/src/ShaderNode/ShaderGraph.cpp index 0b95e137f..be77909de 100644 --- a/src/ShaderNode/ShaderGraph.cpp +++ b/src/ShaderNode/ShaderGraph.cpp @@ -1,11 +1,13 @@ #include #include +#include #include #include #include #include #include #include +#include #include #include #include @@ -34,6 +36,13 @@ m_flowScene(BuildRegistry()) node2.nodeGraphicsObject().setPos(500, 300); m_flowScene.createConnection(node2, 0, node1, 0); + + m_previewModel = std::make_unique(); +} + +ShaderGraph::~ShaderGraph() +{ + m_flowScene.clearScene(); } std::size_t ShaderGraph::AddInput(std::string name, InputType type, InputRole role, std::size_t roleIndex) @@ -125,12 +134,26 @@ void ShaderGraph::UpdateTexturePreview(std::size_t textureIndex, QImage preview) std::shared_ptr ShaderGraph::BuildRegistry() { auto registry = std::make_shared(); + RegisterShaderNode(*this, registry, "Casts"); + RegisterShaderNode(*this, registry, "Casts"); + RegisterShaderNode(*this, registry, "Casts"); + RegisterShaderNode(*this, registry, "Casts"); + RegisterShaderNode(*this, registry, "Casts"); + RegisterShaderNode(*this, registry, "Casts"); RegisterShaderNode(*this, registry, "Outputs"); RegisterShaderNode(*this, registry, "Inputs"); RegisterShaderNode(*this, registry, "Texture"); + RegisterShaderNode(*this, registry, "Vector operations"); + RegisterShaderNode(*this, registry, "Vector operations"); + RegisterShaderNode(*this, registry, "Vector operations"); + RegisterShaderNode(*this, registry, "Vector operations"); + RegisterShaderNode(*this, registry, "Vector operations"); + RegisterShaderNode(*this, registry, "Vector operations"); RegisterShaderNode(*this, registry, "Vector operations"); RegisterShaderNode(*this, registry, "Vector operations"); + RegisterShaderNode(*this, registry, "Vector operations"); RegisterShaderNode(*this, registry, "Constants"); + RegisterShaderNode(*this, registry, "Constants"); RegisterShaderNode(*this, registry, "Constants"); return registry; diff --git a/src/ShaderNode/ShaderGraph.hpp b/src/ShaderNode/ShaderGraph.hpp index 132c9c25b..dda8dba20 100644 --- a/src/ShaderNode/ShaderGraph.hpp +++ b/src/ShaderNode/ShaderGraph.hpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -17,13 +18,14 @@ class ShaderGraph struct TextureEntry; ShaderGraph(); - ~ShaderGraph() = default; + ~ShaderGraph(); std::size_t AddInput(std::string name, InputType type, InputRole role, std::size_t roleIndex); std::size_t AddTexture(std::string name, TextureType type); inline const InputEntry& GetInput(std::size_t inputIndex) const; inline const std::vector& GetInputs() const; + inline const PreviewModel& GetPreviewModel() const; inline QtNodes::FlowScene& GetScene(); inline const TextureEntry& GetTexture(std::size_t textureIndex) const; inline const std::vector& GetTextures() const; @@ -59,6 +61,7 @@ class ShaderGraph QtNodes::FlowScene m_flowScene; std::vector m_inputs; std::vector m_textures; + std::unique_ptr m_previewModel; }; #include diff --git a/src/ShaderNode/ShaderGraph.inl b/src/ShaderNode/ShaderGraph.inl index bb39d44f3..fb0a9e556 100644 --- a/src/ShaderNode/ShaderGraph.inl +++ b/src/ShaderNode/ShaderGraph.inl @@ -11,6 +11,11 @@ inline auto ShaderGraph::GetInputs() const -> const std::vector& return m_inputs; } +inline const PreviewModel& ShaderGraph::GetPreviewModel() const +{ + return *m_previewModel; +} + inline QtNodes::FlowScene& ShaderGraph::GetScene() { return m_flowScene; From fdeff2e9d08a3b3c6eb1a04703e9879e88311182 Mon Sep 17 00:00:00 2001 From: Lynix Date: Sat, 23 May 2020 22:05:37 +0200 Subject: [PATCH 009/105] ShaderAst: Fix SwizzleOp::GetExpressionType --- src/Nazara/Renderer/ShaderAst.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Nazara/Renderer/ShaderAst.cpp b/src/Nazara/Renderer/ShaderAst.cpp index d45c8b739..bb64f4475 100644 --- a/src/Nazara/Renderer/ShaderAst.cpp +++ b/src/Nazara/Renderer/ShaderAst.cpp @@ -180,7 +180,7 @@ namespace Nz::ShaderAst ExpressionType ShaderAst::SwizzleOp::GetExpressionType() const { - return GetComponentType(expression->GetExpressionType()); + return static_cast(UnderlyingCast(GetComponentType(expression->GetExpressionType())) + componentCount - 1); } void SwizzleOp::Register(ShaderWriter& visitor) From 1165093b4e627bc6a9426afba6c632c63039238e Mon Sep 17 00:00:00 2001 From: Lynix Date: Sat, 23 May 2020 22:08:12 +0200 Subject: [PATCH 010/105] Replace some insert by emplace --- src/Nazara/Renderer/GlslWriter.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Nazara/Renderer/GlslWriter.cpp b/src/Nazara/Renderer/GlslWriter.cpp index badf3648f..7cb734cc5 100644 --- a/src/Nazara/Renderer/GlslWriter.cpp +++ b/src/Nazara/Renderer/GlslWriter.cpp @@ -69,11 +69,11 @@ namespace Nz break; case ShaderAst::VariableType::Input: - m_currentState->inputs.insert(std::make_pair(type, name)); + m_currentState->inputs.emplace(type, name); break; case ShaderAst::VariableType::Output: - m_currentState->outputs.insert(std::make_pair(type, name)); + m_currentState->outputs.emplace(type, name); break; case ShaderAst::VariableType::Parameter: @@ -105,13 +105,13 @@ namespace Nz } case ShaderAst::VariableType::Uniform: - m_currentState->uniforms.insert(std::make_pair(type, name)); + m_currentState->uniforms.emplace(type, name); break; case ShaderAst::VariableType::Variable: { if (m_currentFunction) - m_currentFunction->variables.insert(std::make_pair(type, name)); + m_currentFunction->variables.emplace(type, name); break; } From 460222e71e5b767bdee5ffe7941ab1b089645187 Mon Sep 17 00:00:00 2001 From: Lynix Date: Mon, 25 May 2020 14:40:46 +0200 Subject: [PATCH 011/105] ShaderNode: Make #include explicit --- build/scripts/tools/shadernodes.lua | 2 +- src/ShaderNode/DataModels/Cast.hpp | 8 ++++---- src/ShaderNode/DataModels/Cast.inl | 2 +- src/ShaderNode/DataModels/FragmentOutput.cpp | 4 ++-- src/ShaderNode/DataModels/FragmentOutput.hpp | 4 ++-- src/ShaderNode/DataModels/FragmentOutput.inl | 2 +- src/ShaderNode/DataModels/InputValue.cpp | 6 +++--- src/ShaderNode/DataModels/InputValue.hpp | 6 +++--- src/ShaderNode/DataModels/InputValue.inl | 2 +- src/ShaderNode/DataModels/SampleTexture.cpp | 6 +++--- src/ShaderNode/DataModels/SampleTexture.hpp | 8 ++++---- src/ShaderNode/DataModels/SampleTexture.inl | 2 +- src/ShaderNode/DataModels/ShaderNode.cpp | 2 +- src/ShaderNode/DataModels/ShaderNode.hpp | 2 +- src/ShaderNode/DataModels/ShaderNode.inl | 2 +- src/ShaderNode/DataModels/VecBinOp.cpp | 2 +- src/ShaderNode/DataModels/VecBinOp.hpp | 6 +++--- src/ShaderNode/DataModels/VecBinOp.inl | 2 +- src/ShaderNode/DataModels/VecData.cpp | 2 +- src/ShaderNode/DataModels/VecData.hpp | 2 +- src/ShaderNode/DataModels/VecData.inl | 2 +- src/ShaderNode/DataModels/VecValue.cpp | 2 +- src/ShaderNode/DataModels/VecValue.hpp | 6 +++--- src/ShaderNode/DataModels/VecValue.inl | 2 +- src/ShaderNode/Enums.cpp | 2 +- src/ShaderNode/Enums.hpp | 2 +- src/ShaderNode/Enums.inl | 2 +- src/ShaderNode/Previews/PreviewModel.cpp | 2 +- src/ShaderNode/Previews/PreviewModel.hpp | 4 ++-- src/ShaderNode/Previews/PreviewModel.inl | 2 +- src/ShaderNode/Previews/QuadPreview.cpp | 2 +- src/ShaderNode/Previews/QuadPreview.hpp | 4 ++-- src/ShaderNode/Previews/QuadPreview.inl | 2 +- src/ShaderNode/ShaderGraph.cpp | 18 +++++++++--------- src/ShaderNode/ShaderGraph.hpp | 6 +++--- src/ShaderNode/ShaderGraph.inl | 2 +- src/ShaderNode/Widgets/InputEditDialog.cpp | 2 +- src/ShaderNode/Widgets/InputEditDialog.hpp | 4 ++-- src/ShaderNode/Widgets/InputEditDialog.inl | 2 +- src/ShaderNode/Widgets/InputEditor.cpp | 6 +++--- src/ShaderNode/Widgets/InputEditor.hpp | 4 ++-- src/ShaderNode/Widgets/InputEditor.inl | 2 +- src/ShaderNode/Widgets/MainWindow.cpp | 8 ++++---- src/ShaderNode/Widgets/MainWindow.hpp | 4 ++-- src/ShaderNode/Widgets/MainWindow.inl | 2 +- src/ShaderNode/Widgets/TextureEditor.cpp | 4 ++-- src/ShaderNode/Widgets/TextureEditor.hpp | 4 ++-- src/ShaderNode/Widgets/TextureEditor.inl | 2 +- src/ShaderNode/main.cpp | 4 ++-- 49 files changed, 90 insertions(+), 90 deletions(-) diff --git a/build/scripts/tools/shadernodes.lua b/build/scripts/tools/shadernodes.lua index 33f9628e9..415b71c75 100644 --- a/build/scripts/tools/shadernodes.lua +++ b/build/scripts/tools/shadernodes.lua @@ -12,7 +12,7 @@ TOOL.Defines = { TOOL.Includes = { "../include", "../extlibs/include", - "../src/ShaderNode", + "../src", [[E:\Qt\5.14.1\msvc2017_64\include]], [[E:\Qt\5.14.1\msvc2017_64\include\QtCore]], [[E:\Qt\5.14.1\msvc2017_64\include\QtGui]], diff --git a/src/ShaderNode/DataModels/Cast.hpp b/src/ShaderNode/DataModels/Cast.hpp index f17cff625..a6709bd2d 100644 --- a/src/ShaderNode/DataModels/Cast.hpp +++ b/src/ShaderNode/DataModels/Cast.hpp @@ -6,9 +6,9 @@ #include #include #include -#include -#include -#include +#include +#include +#include #include template @@ -54,6 +54,6 @@ using CastVec3ToVec4 = CastVec; using CastVec4ToVec2 = CastVec; using CastVec4ToVec3 = CastVec; -#include +#include #endif diff --git a/src/ShaderNode/DataModels/Cast.inl b/src/ShaderNode/DataModels/Cast.inl index 9e70e9f8b..0133d6cc7 100644 --- a/src/ShaderNode/DataModels/Cast.inl +++ b/src/ShaderNode/DataModels/Cast.inl @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/src/ShaderNode/DataModels/FragmentOutput.cpp b/src/ShaderNode/DataModels/FragmentOutput.cpp index 15244e0d8..86731a0f4 100644 --- a/src/ShaderNode/DataModels/FragmentOutput.cpp +++ b/src/ShaderNode/DataModels/FragmentOutput.cpp @@ -1,6 +1,6 @@ -#include +#include #include -#include +#include Nz::ShaderAst::ExpressionPtr FragmentOutput::GetExpression(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count) const { diff --git a/src/ShaderNode/DataModels/FragmentOutput.hpp b/src/ShaderNode/DataModels/FragmentOutput.hpp index a682d40a4..ab89ae419 100644 --- a/src/ShaderNode/DataModels/FragmentOutput.hpp +++ b/src/ShaderNode/DataModels/FragmentOutput.hpp @@ -3,7 +3,7 @@ #ifndef NAZARA_SHADERNODES_FRAGMENTOUTPUT_HPP #define NAZARA_SHADERNODES_FRAGMENTOUTPUT_HPP -#include +#include #include #include @@ -28,6 +28,6 @@ class FragmentOutput : public ShaderNode }; -#include +#include #endif diff --git a/src/ShaderNode/DataModels/FragmentOutput.inl b/src/ShaderNode/DataModels/FragmentOutput.inl index 539b8091f..c809a587d 100644 --- a/src/ShaderNode/DataModels/FragmentOutput.inl +++ b/src/ShaderNode/DataModels/FragmentOutput.inl @@ -1,4 +1,4 @@ -#include +#include inline FragmentOutput::FragmentOutput(ShaderGraph& graph) : ShaderNode(graph) diff --git a/src/ShaderNode/DataModels/InputValue.cpp b/src/ShaderNode/DataModels/InputValue.cpp index 1a1bdfb5a..f2ae0eaa8 100644 --- a/src/ShaderNode/DataModels/InputValue.cpp +++ b/src/ShaderNode/DataModels/InputValue.cpp @@ -1,6 +1,6 @@ -#include -#include -#include +#include +#include +#include #include InputValue::InputValue(ShaderGraph& graph) : diff --git a/src/ShaderNode/DataModels/InputValue.hpp b/src/ShaderNode/DataModels/InputValue.hpp index 63e896adf..273155cc4 100644 --- a/src/ShaderNode/DataModels/InputValue.hpp +++ b/src/ShaderNode/DataModels/InputValue.hpp @@ -6,8 +6,8 @@ #include #include #include -#include -#include +#include +#include #include class InputValue : public ShaderNode @@ -42,6 +42,6 @@ class InputValue : public ShaderNode QVBoxLayout* m_layout; }; -#include +#include #endif diff --git a/src/ShaderNode/DataModels/InputValue.inl b/src/ShaderNode/DataModels/InputValue.inl index ff350c7c4..344e3db41 100644 --- a/src/ShaderNode/DataModels/InputValue.inl +++ b/src/ShaderNode/DataModels/InputValue.inl @@ -1,2 +1,2 @@ -#include +#include #include diff --git a/src/ShaderNode/DataModels/SampleTexture.cpp b/src/ShaderNode/DataModels/SampleTexture.cpp index d7ae63713..81982c83a 100644 --- a/src/ShaderNode/DataModels/SampleTexture.cpp +++ b/src/ShaderNode/DataModels/SampleTexture.cpp @@ -1,6 +1,6 @@ -#include -#include -#include +#include +#include +#include #include SampleTexture::SampleTexture(ShaderGraph& graph) : diff --git a/src/ShaderNode/DataModels/SampleTexture.hpp b/src/ShaderNode/DataModels/SampleTexture.hpp index 3621d0c14..7697d296f 100644 --- a/src/ShaderNode/DataModels/SampleTexture.hpp +++ b/src/ShaderNode/DataModels/SampleTexture.hpp @@ -6,9 +6,9 @@ #include #include #include -#include -#include -#include +#include +#include +#include #include class SampleTexture : public ShaderNode @@ -53,6 +53,6 @@ class SampleTexture : public ShaderNode QVBoxLayout* m_layout; }; -#include +#include #endif diff --git a/src/ShaderNode/DataModels/SampleTexture.inl b/src/ShaderNode/DataModels/SampleTexture.inl index 78d12b21d..292805b16 100644 --- a/src/ShaderNode/DataModels/SampleTexture.inl +++ b/src/ShaderNode/DataModels/SampleTexture.inl @@ -1,2 +1,2 @@ -#include +#include #include diff --git a/src/ShaderNode/DataModels/ShaderNode.cpp b/src/ShaderNode/DataModels/ShaderNode.cpp index 1f45d3ca5..aeb143452 100644 --- a/src/ShaderNode/DataModels/ShaderNode.cpp +++ b/src/ShaderNode/DataModels/ShaderNode.cpp @@ -1,4 +1,4 @@ -#include +#include void ShaderNode::setInData(std::shared_ptr, int) { diff --git a/src/ShaderNode/DataModels/ShaderNode.hpp b/src/ShaderNode/DataModels/ShaderNode.hpp index d33fc632d..3d73d7330 100644 --- a/src/ShaderNode/DataModels/ShaderNode.hpp +++ b/src/ShaderNode/DataModels/ShaderNode.hpp @@ -23,6 +23,6 @@ class ShaderNode : public QtNodes::NodeDataModel ShaderGraph& m_graph; }; -#include +#include #endif diff --git a/src/ShaderNode/DataModels/ShaderNode.inl b/src/ShaderNode/DataModels/ShaderNode.inl index a244d78b5..defa5aea1 100644 --- a/src/ShaderNode/DataModels/ShaderNode.inl +++ b/src/ShaderNode/DataModels/ShaderNode.inl @@ -1,4 +1,4 @@ -#include +#include inline ShaderNode::ShaderNode(ShaderGraph& graph) : m_graph(graph) diff --git a/src/ShaderNode/DataModels/VecBinOp.cpp b/src/ShaderNode/DataModels/VecBinOp.cpp index dd13b5b56..fd2e0d5c1 100644 --- a/src/ShaderNode/DataModels/VecBinOp.cpp +++ b/src/ShaderNode/DataModels/VecBinOp.cpp @@ -1 +1 @@ -#include +#include diff --git a/src/ShaderNode/DataModels/VecBinOp.hpp b/src/ShaderNode/DataModels/VecBinOp.hpp index 31ae4732e..ef3ee4bca 100644 --- a/src/ShaderNode/DataModels/VecBinOp.hpp +++ b/src/ShaderNode/DataModels/VecBinOp.hpp @@ -3,8 +3,8 @@ #ifndef NAZARA_SHADERNODES_VECBINOP_HPP #define NAZARA_SHADERNODES_VECBINOP_HPP -#include -#include +#include +#include template class VecBinOp : public ShaderNode @@ -83,6 +83,6 @@ using Vec2Sub = VecSub; using Vec3Sub = VecSub; using Vec4Sub = VecSub; -#include +#include #endif diff --git a/src/ShaderNode/DataModels/VecBinOp.inl b/src/ShaderNode/DataModels/VecBinOp.inl index 5d5cfc251..4159193fb 100644 --- a/src/ShaderNode/DataModels/VecBinOp.inl +++ b/src/ShaderNode/DataModels/VecBinOp.inl @@ -1,4 +1,4 @@ -#include +#include #include template diff --git a/src/ShaderNode/DataModels/VecData.cpp b/src/ShaderNode/DataModels/VecData.cpp index 2cf74c1e6..376c8ea5c 100644 --- a/src/ShaderNode/DataModels/VecData.cpp +++ b/src/ShaderNode/DataModels/VecData.cpp @@ -1 +1 @@ -#include +#include diff --git a/src/ShaderNode/DataModels/VecData.hpp b/src/ShaderNode/DataModels/VecData.hpp index ad44d68b1..8a1b152f5 100644 --- a/src/ShaderNode/DataModels/VecData.hpp +++ b/src/ShaderNode/DataModels/VecData.hpp @@ -62,6 +62,6 @@ struct Vec4Data : public VecData } }; -#include +#include #endif diff --git a/src/ShaderNode/DataModels/VecData.inl b/src/ShaderNode/DataModels/VecData.inl index 92765c835..6c2d0379e 100644 --- a/src/ShaderNode/DataModels/VecData.inl +++ b/src/ShaderNode/DataModels/VecData.inl @@ -1,4 +1,4 @@ -#include +#include inline VecData::VecData() : preview(64, 64, QImage::Format_RGBA8888) diff --git a/src/ShaderNode/DataModels/VecValue.cpp b/src/ShaderNode/DataModels/VecValue.cpp index 807df2955..ede5bdfac 100644 --- a/src/ShaderNode/DataModels/VecValue.cpp +++ b/src/ShaderNode/DataModels/VecValue.cpp @@ -1 +1 @@ -#include +#include diff --git a/src/ShaderNode/DataModels/VecValue.hpp b/src/ShaderNode/DataModels/VecValue.hpp index 77656f373..7e8db4d88 100644 --- a/src/ShaderNode/DataModels/VecValue.hpp +++ b/src/ShaderNode/DataModels/VecValue.hpp @@ -7,8 +7,8 @@ #include #include #include -#include -#include +#include +#include #include template @@ -71,6 +71,6 @@ using Vec2Value = VecValue; using Vec3Value = VecValue; using Vec4Value = VecValue; -#include +#include #endif diff --git a/src/ShaderNode/DataModels/VecValue.inl b/src/ShaderNode/DataModels/VecValue.inl index 3ab11cd37..45138b83f 100644 --- a/src/ShaderNode/DataModels/VecValue.inl +++ b/src/ShaderNode/DataModels/VecValue.inl @@ -1,6 +1,6 @@ #include #include -#include +#include #include #include diff --git a/src/ShaderNode/Enums.cpp b/src/ShaderNode/Enums.cpp index f280ce793..22f21c972 100644 --- a/src/ShaderNode/Enums.cpp +++ b/src/ShaderNode/Enums.cpp @@ -1,4 +1,4 @@ -#include +#include #include const char* EnumToString(InputRole role) diff --git a/src/ShaderNode/Enums.hpp b/src/ShaderNode/Enums.hpp index 6a7a34336..b8e944c5c 100644 --- a/src/ShaderNode/Enums.hpp +++ b/src/ShaderNode/Enums.hpp @@ -43,6 +43,6 @@ const char* EnumToString(InputRole role); const char* EnumToString(InputType input); const char* EnumToString(TextureType textureType); -#include +#include #endif diff --git a/src/ShaderNode/Enums.inl b/src/ShaderNode/Enums.inl index a23a54efb..243d12205 100644 --- a/src/ShaderNode/Enums.inl +++ b/src/ShaderNode/Enums.inl @@ -1 +1 @@ -#include +#include diff --git a/src/ShaderNode/Previews/PreviewModel.cpp b/src/ShaderNode/Previews/PreviewModel.cpp index 845c19fe2..d4ab52386 100644 --- a/src/ShaderNode/Previews/PreviewModel.cpp +++ b/src/ShaderNode/Previews/PreviewModel.cpp @@ -1,3 +1,3 @@ -#include +#include PreviewModel::~PreviewModel() = default; diff --git a/src/ShaderNode/Previews/PreviewModel.hpp b/src/ShaderNode/Previews/PreviewModel.hpp index 138374ea4..6ed8ec3ef 100644 --- a/src/ShaderNode/Previews/PreviewModel.hpp +++ b/src/ShaderNode/Previews/PreviewModel.hpp @@ -3,7 +3,7 @@ #ifndef NAZARA_SHADERNODES_PREVIEWMODEL_HPP #define NAZARA_SHADERNODES_PREVIEWMODEL_HPP -#include +#include class QImage; @@ -16,6 +16,6 @@ class PreviewModel virtual QImage GetImage(InputRole role, std::size_t roleIndex) const = 0; }; -#include +#include #endif diff --git a/src/ShaderNode/Previews/PreviewModel.inl b/src/ShaderNode/Previews/PreviewModel.inl index d5f2e699b..f4dccb3fa 100644 --- a/src/ShaderNode/Previews/PreviewModel.inl +++ b/src/ShaderNode/Previews/PreviewModel.inl @@ -1 +1 @@ -#include +#include diff --git a/src/ShaderNode/Previews/QuadPreview.cpp b/src/ShaderNode/Previews/QuadPreview.cpp index a518287fd..55ae86a52 100644 --- a/src/ShaderNode/Previews/QuadPreview.cpp +++ b/src/ShaderNode/Previews/QuadPreview.cpp @@ -1,4 +1,4 @@ -#include +#include #include QImage QuadPreview::GetImage(InputRole role, std::size_t roleIndex) const diff --git a/src/ShaderNode/Previews/QuadPreview.hpp b/src/ShaderNode/Previews/QuadPreview.hpp index f193e99d0..6c980ae34 100644 --- a/src/ShaderNode/Previews/QuadPreview.hpp +++ b/src/ShaderNode/Previews/QuadPreview.hpp @@ -3,7 +3,7 @@ #ifndef NAZARA_SHADERNODES_QUADPREVIEW_HPP #define NAZARA_SHADERNODES_QUADPREVIEW_HPP -#include +#include #include class QuadPreview : public PreviewModel @@ -15,6 +15,6 @@ class QuadPreview : public PreviewModel QImage GetImage(InputRole role, std::size_t roleIndex) const override; }; -#include +#include #endif diff --git a/src/ShaderNode/Previews/QuadPreview.inl b/src/ShaderNode/Previews/QuadPreview.inl index 01178d2d2..b3e26a0ab 100644 --- a/src/ShaderNode/Previews/QuadPreview.inl +++ b/src/ShaderNode/Previews/QuadPreview.inl @@ -1 +1 @@ -#include +#include diff --git a/src/ShaderNode/ShaderGraph.cpp b/src/ShaderNode/ShaderGraph.cpp index be77909de..e29c0129f 100644 --- a/src/ShaderNode/ShaderGraph.cpp +++ b/src/ShaderNode/ShaderGraph.cpp @@ -1,13 +1,13 @@ -#include +#include #include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include diff --git a/src/ShaderNode/ShaderGraph.hpp b/src/ShaderNode/ShaderGraph.hpp index dda8dba20..aa2188f16 100644 --- a/src/ShaderNode/ShaderGraph.hpp +++ b/src/ShaderNode/ShaderGraph.hpp @@ -6,8 +6,8 @@ #include #include #include -#include -#include +#include +#include #include #include @@ -64,6 +64,6 @@ class ShaderGraph std::unique_ptr m_previewModel; }; -#include +#include #endif diff --git a/src/ShaderNode/ShaderGraph.inl b/src/ShaderNode/ShaderGraph.inl index fb0a9e556..100cd822e 100644 --- a/src/ShaderNode/ShaderGraph.inl +++ b/src/ShaderNode/ShaderGraph.inl @@ -1,4 +1,4 @@ -#include +#include inline auto ShaderGraph::GetInput(std::size_t inputIndex) const -> const InputEntry& { diff --git a/src/ShaderNode/Widgets/InputEditDialog.cpp b/src/ShaderNode/Widgets/InputEditDialog.cpp index d9642966c..71e6b2298 100644 --- a/src/ShaderNode/Widgets/InputEditDialog.cpp +++ b/src/ShaderNode/Widgets/InputEditDialog.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/src/ShaderNode/Widgets/InputEditDialog.hpp b/src/ShaderNode/Widgets/InputEditDialog.hpp index 829697049..ef96d118c 100644 --- a/src/ShaderNode/Widgets/InputEditDialog.hpp +++ b/src/ShaderNode/Widgets/InputEditDialog.hpp @@ -3,7 +3,7 @@ #ifndef NAZARA_SHADERNODES_INPUTEDITDIALOG_HPP #define NAZARA_SHADERNODES_INPUTEDITDIALOG_HPP -#include +#include #include class QComboBox; @@ -36,6 +36,6 @@ class InputEditDialog : public QDialog QSpinBox* m_roleIndex; }; -#include +#include #endif diff --git a/src/ShaderNode/Widgets/InputEditDialog.inl b/src/ShaderNode/Widgets/InputEditDialog.inl index a480716aa..db2681e5c 100644 --- a/src/ShaderNode/Widgets/InputEditDialog.inl +++ b/src/ShaderNode/Widgets/InputEditDialog.inl @@ -1 +1 @@ -#include +#include diff --git a/src/ShaderNode/Widgets/InputEditor.cpp b/src/ShaderNode/Widgets/InputEditor.cpp index 86a28a2eb..a0dee923d 100644 --- a/src/ShaderNode/Widgets/InputEditor.cpp +++ b/src/ShaderNode/Widgets/InputEditor.cpp @@ -1,6 +1,6 @@ -#include -#include -#include +#include +#include +#include #include #include #include diff --git a/src/ShaderNode/Widgets/InputEditor.hpp b/src/ShaderNode/Widgets/InputEditor.hpp index 236f9069f..561a7b362 100644 --- a/src/ShaderNode/Widgets/InputEditor.hpp +++ b/src/ShaderNode/Widgets/InputEditor.hpp @@ -3,7 +3,7 @@ #ifndef NAZARA_SHADERNODES_INPUTEDITOR_HPP #define NAZARA_SHADERNODES_INPUTEDITOR_HPP -#include +#include #include #include @@ -34,6 +34,6 @@ class InputEditor : public QWidget QVBoxLayout* m_layout; }; -#include +#include #endif diff --git a/src/ShaderNode/Widgets/InputEditor.inl b/src/ShaderNode/Widgets/InputEditor.inl index a480716aa..db2681e5c 100644 --- a/src/ShaderNode/Widgets/InputEditor.inl +++ b/src/ShaderNode/Widgets/InputEditor.inl @@ -1 +1 @@ -#include +#include diff --git a/src/ShaderNode/Widgets/MainWindow.cpp b/src/ShaderNode/Widgets/MainWindow.cpp index 150770541..8aa48c353 100644 --- a/src/ShaderNode/Widgets/MainWindow.cpp +++ b/src/ShaderNode/Widgets/MainWindow.cpp @@ -1,8 +1,8 @@ -#include +#include #include -#include -#include -#include +#include +#include +#include #include #include #include diff --git a/src/ShaderNode/Widgets/MainWindow.hpp b/src/ShaderNode/Widgets/MainWindow.hpp index fa8257bcf..3e68ec267 100644 --- a/src/ShaderNode/Widgets/MainWindow.hpp +++ b/src/ShaderNode/Widgets/MainWindow.hpp @@ -4,7 +4,7 @@ #define NAZARA_SHADERNODES_MAINWINDOW_HPP #include -#include +#include class ShaderGraph; @@ -21,6 +21,6 @@ class MainWindow : public QMainWindow ShaderGraph& m_shaderGraph; }; -#include +#include #endif diff --git a/src/ShaderNode/Widgets/MainWindow.inl b/src/ShaderNode/Widgets/MainWindow.inl index 48dbe409e..f10445799 100644 --- a/src/ShaderNode/Widgets/MainWindow.inl +++ b/src/ShaderNode/Widgets/MainWindow.inl @@ -1 +1 @@ -#include +#include diff --git a/src/ShaderNode/Widgets/TextureEditor.cpp b/src/ShaderNode/Widgets/TextureEditor.cpp index 44a68fec9..40cce4652 100644 --- a/src/ShaderNode/Widgets/TextureEditor.cpp +++ b/src/ShaderNode/Widgets/TextureEditor.cpp @@ -1,5 +1,5 @@ -#include -#include +#include +#include #include #include #include diff --git a/src/ShaderNode/Widgets/TextureEditor.hpp b/src/ShaderNode/Widgets/TextureEditor.hpp index 456b9b1d5..a3497f288 100644 --- a/src/ShaderNode/Widgets/TextureEditor.hpp +++ b/src/ShaderNode/Widgets/TextureEditor.hpp @@ -3,7 +3,7 @@ #ifndef NAZARA_SHADERNODES_TEXTUREEDITOR_HPP #define NAZARA_SHADERNODES_TEXTUREEDITOR_HPP -#include +#include #include #include @@ -35,6 +35,6 @@ class TextureEditor : public QWidget QVBoxLayout* m_layout; }; -#include +#include #endif diff --git a/src/ShaderNode/Widgets/TextureEditor.inl b/src/ShaderNode/Widgets/TextureEditor.inl index d11298db1..318a1e9a3 100644 --- a/src/ShaderNode/Widgets/TextureEditor.inl +++ b/src/ShaderNode/Widgets/TextureEditor.inl @@ -1 +1 @@ -#include +#include diff --git a/src/ShaderNode/main.cpp b/src/ShaderNode/main.cpp index a9554c8bd..a939e708a 100644 --- a/src/ShaderNode/main.cpp +++ b/src/ShaderNode/main.cpp @@ -1,6 +1,6 @@ #include -#include -#include +#include +#include #include int main(int argc, char* argv[]) From 3b440254daad157bf1cecead6adc93f73a56d3d5 Mon Sep 17 00:00:00 2001 From: Lynix Date: Tue, 26 May 2020 15:58:15 +0200 Subject: [PATCH 012/105] Math/Vector[I]: Set method: Replace array by pointer --- include/Nazara/Math/Vector2.hpp | 2 +- include/Nazara/Math/Vector2.inl | 3 +-- include/Nazara/Math/Vector3.hpp | 2 +- include/Nazara/Math/Vector3.inl | 2 +- include/Nazara/Math/Vector4.hpp | 2 +- include/Nazara/Math/Vector4.inl | 3 +-- 6 files changed, 6 insertions(+), 8 deletions(-) diff --git a/include/Nazara/Math/Vector2.hpp b/include/Nazara/Math/Vector2.hpp index c9dba6bfa..72c72da4c 100644 --- a/include/Nazara/Math/Vector2.hpp +++ b/include/Nazara/Math/Vector2.hpp @@ -54,7 +54,7 @@ namespace Nz Vector2& Set(T X, T Y); Vector2& Set(T scale); - Vector2& Set(const T vec[2]); + Vector2& Set(const T* vec); Vector2& Set(const Vector3& vec); Vector2& Set(const Vector4& vec); template Vector2& Set(const Vector2& vec); diff --git a/include/Nazara/Math/Vector2.inl b/include/Nazara/Math/Vector2.inl index e22e00bc2..7d2754955 100644 --- a/include/Nazara/Math/Vector2.inl +++ b/include/Nazara/Math/Vector2.inl @@ -363,9 +363,8 @@ namespace Nz * * \param vec[2] vec[0] is X component and vec[1] is Y component */ - template - Vector2& Vector2::Set(const T vec[2]) + Vector2& Vector2::Set(const T* vec) { x = vec[0]; y = vec[1]; diff --git a/include/Nazara/Math/Vector3.hpp b/include/Nazara/Math/Vector3.hpp index 99e3696df..1603f7d34 100644 --- a/include/Nazara/Math/Vector3.hpp +++ b/include/Nazara/Math/Vector3.hpp @@ -65,7 +65,7 @@ namespace Nz Vector3& Set(T X, T Y, T Z); Vector3& Set(T X, const Vector2& vec); Vector3& Set(T scale); - Vector3& Set(const T vec[3]); + Vector3& Set(const T* vec); Vector3& Set(const Vector2& vec, T Z = 0.0); template Vector3& Set(const Vector3& vec); Vector3& Set(const Vector4& vec); diff --git a/include/Nazara/Math/Vector3.inl b/include/Nazara/Math/Vector3.inl index 1dcf48fe7..a9602a248 100644 --- a/include/Nazara/Math/Vector3.inl +++ b/include/Nazara/Math/Vector3.inl @@ -498,7 +498,7 @@ namespace Nz * \param vec[3] vec[0] is X component, vec[1] is Y component and vec[2] is Z component */ template - Vector3& Vector3::Set(const T vec[3]) + Vector3& Vector3::Set(const T* vec) { x = vec[0]; y = vec[1]; diff --git a/include/Nazara/Math/Vector4.hpp b/include/Nazara/Math/Vector4.hpp index 2938df3bb..24893ee65 100644 --- a/include/Nazara/Math/Vector4.hpp +++ b/include/Nazara/Math/Vector4.hpp @@ -54,7 +54,7 @@ namespace Nz Vector4& Set(T X, const Vector2& vec, T W); Vector4& Set(T X, const Vector3& vec); Vector4& Set(T scale); - Vector4& Set(const T vec[4]); + Vector4& Set(const T* vec); Vector4& Set(const Vector2& vec, T Z = 0.0, T W = 1.0); Vector4& Set(const Vector3& vec, T W = 1.0); template Vector4& Set(const Vector4& vec); diff --git a/include/Nazara/Math/Vector4.inl b/include/Nazara/Math/Vector4.inl index 6deadf5f5..93003da9b 100644 --- a/include/Nazara/Math/Vector4.inl +++ b/include/Nazara/Math/Vector4.inl @@ -413,9 +413,8 @@ namespace Nz * * \param vec[4] vec[0] is X component, vec[1] is Y component, vec[2] is Z component and vec[3] is W component */ - template - Vector4& Vector4::Set(const T vec[4]) + Vector4& Vector4::Set(const T* vec) { x = vec[0]; y = vec[1]; From b1b90303598b5807bc32a2591f0f3d35b87716c0 Mon Sep 17 00:00:00 2001 From: Lynix Date: Tue, 26 May 2020 16:03:57 +0200 Subject: [PATCH 013/105] Math/Vector[I]: Replace implicit pointer conversion by [] operator overload --- include/Nazara/Math/Vector2.hpp | 4 ++-- include/Nazara/Math/Vector2.inl | 24 ++++++++++-------------- include/Nazara/Math/Vector3.hpp | 4 ++-- include/Nazara/Math/Vector3.inl | 22 ++++++++++------------ include/Nazara/Math/Vector4.hpp | 4 ++-- include/Nazara/Math/Vector4.inl | 24 ++++++++++-------------- src/Nazara/Utility/Formats/MD2Loader.cpp | 4 ++-- 7 files changed, 38 insertions(+), 48 deletions(-) diff --git a/include/Nazara/Math/Vector2.hpp b/include/Nazara/Math/Vector2.hpp index 72c72da4c..75e86f709 100644 --- a/include/Nazara/Math/Vector2.hpp +++ b/include/Nazara/Math/Vector2.hpp @@ -63,8 +63,8 @@ namespace Nz String ToString() const; - operator T* (); - operator const T* () const; + T& operator[](std::size_t i); + T operator[](std::size_t i) const; const Vector2& operator+() const; Vector2 operator-() const; diff --git a/include/Nazara/Math/Vector2.inl b/include/Nazara/Math/Vector2.inl index 7d2754955..22eb72566 100644 --- a/include/Nazara/Math/Vector2.inl +++ b/include/Nazara/Math/Vector2.inl @@ -450,29 +450,25 @@ namespace Nz } /*! - * \brief Converts vector to pointer to its own data - * \return A pointer to the own data - * - * \remark Access to index greather than 1 is undefined behavior + * \brief Access a vector component by index + * \return X, Y depending on index (0, 1) */ - template - Vector2::operator T* () + T& Vector2::operator[](std::size_t i) { - return &x; + NazaraAssert(i < 2, "index out of range"); + return *(&x + i); } /*! - * \brief Converts vector to const pointer to its own data - * \return A constant pointer to the own data - * - * \remark Access to index greather than 1 is undefined behavior + * \brief Access a vector component by index + * \return X, Y depending on index (0, 1) */ - template - Vector2::operator const T* () const + T Vector2::operator[](std::size_t i) const { - return &x; + NazaraAssert(i < 2, "index out of range"); + return *(&x + i); } /*! diff --git a/include/Nazara/Math/Vector3.hpp b/include/Nazara/Math/Vector3.hpp index 1603f7d34..4fd965484 100644 --- a/include/Nazara/Math/Vector3.hpp +++ b/include/Nazara/Math/Vector3.hpp @@ -74,8 +74,8 @@ namespace Nz String ToString() const; - operator T* (); - operator const T* () const; + T& operator[](std::size_t i); + T operator[](std::size_t i) const; const Vector3& operator+() const; Vector3 operator-() const; diff --git a/include/Nazara/Math/Vector3.inl b/include/Nazara/Math/Vector3.inl index a9602a248..f9585d91e 100644 --- a/include/Nazara/Math/Vector3.inl +++ b/include/Nazara/Math/Vector3.inl @@ -583,27 +583,25 @@ namespace Nz } /*! - * \brief Converts vector to pointer to its own data - * \return A pointer to the own data - * - * \remark Access to index greather than 2 is undefined behavior + * \brief Access a vector component by index + * \return X, Y, Z depending on index (0, 1, 2) */ template - Vector3::operator T* () + T& Vector3::operator[](std::size_t i) { - return &x; + NazaraAssert(i < 3, "index out of range"); + return *(&x + i); } /*! - * \brief Converts vector to const pointer to its own data - * \return A constant pointer to the own data - * - * \remark Access to index greather than 2 is undefined behavior + * \brief Access a vector component by index + * \return X, Y, Z depending on index (0, 1, 2) */ template - Vector3::operator const T* () const + T Vector3::operator[](std::size_t i) const { - return &x; + NazaraAssert(i < 3, "index out of range"); + return *(&x + i); } /*! diff --git a/include/Nazara/Math/Vector4.hpp b/include/Nazara/Math/Vector4.hpp index 24893ee65..5c5c9721f 100644 --- a/include/Nazara/Math/Vector4.hpp +++ b/include/Nazara/Math/Vector4.hpp @@ -61,8 +61,8 @@ namespace Nz String ToString() const; - operator T* (); - operator const T* () const; + T& operator[](std::size_t i); + T operator[](std::size_t i) const; const Vector4& operator+() const; Vector4 operator-() const; diff --git a/include/Nazara/Math/Vector4.inl b/include/Nazara/Math/Vector4.inl index 93003da9b..dfc39aafe 100644 --- a/include/Nazara/Math/Vector4.inl +++ b/include/Nazara/Math/Vector4.inl @@ -494,29 +494,25 @@ namespace Nz } /*! - * \brief Converts vector to pointer to its own data - * \return A pointer to the own data - * - * \remark Access to index greather than 3 is undefined behavior + * \brief Access a vector component by index + * \return X, Y, Z depending on index (0, 1, 2) */ - template - Vector4::operator T* () + T& Vector4::operator[](std::size_t i) { - return &x; + NazaraAssert(i < 4, "index out of range"); + return *(&x + i); } /*! - * \brief Converts vector to const pointer to its own data - * \return A constant pointer to the own data - * - * \remark Access to index greather than 3 is undefined behavior + * \brief Access a vector component by index + * \return X, Y, Z depending on index (0, 1, 2) */ - template - Vector4::operator const T* () const + T Vector4::operator[](std::size_t i) const { - return &x; + NazaraAssert(i < 4, "index out of range"); + return *(&x + i); } /*! diff --git a/src/Nazara/Utility/Formats/MD2Loader.cpp b/src/Nazara/Utility/Formats/MD2Loader.cpp index 0f369cfe5..890572d35 100644 --- a/src/Nazara/Utility/Formats/MD2Loader.cpp +++ b/src/Nazara/Utility/Formats/MD2Loader.cpp @@ -166,8 +166,8 @@ namespace Nz std::vector vertices(header.num_vertices); Vector3f scale, translate; - stream.Read(scale, sizeof(Vector3f)); - stream.Read(translate, sizeof(Vector3f)); + stream.Read(&scale, sizeof(Vector3f)); + stream.Read(&translate, sizeof(Vector3f)); stream.Read(nullptr, 16*sizeof(char)); //< Frame name, unused stream.Read(vertices.data(), header.num_vertices*sizeof(MD2_Vertex)); From 09e08255fbe4454d582ace7be86449ca0f07c59e Mon Sep 17 00:00:00 2001 From: Lynix Date: Tue, 26 May 2020 19:22:31 +0200 Subject: [PATCH 014/105] ShaderAst: Add node editor window --- src/ShaderNode/DataModels/Cast.hpp | 12 +- src/ShaderNode/DataModels/Cast.inl | 100 +++++++-------- src/ShaderNode/DataModels/FragmentOutput.cpp | 28 ++++- src/ShaderNode/DataModels/FragmentOutput.hpp | 8 +- src/ShaderNode/DataModels/FragmentOutput.inl | 2 + src/ShaderNode/DataModels/InputValue.cpp | 100 ++++++++------- src/ShaderNode/DataModels/InputValue.hpp | 17 ++- src/ShaderNode/DataModels/SampleTexture.cpp | 126 ++++++++++--------- src/ShaderNode/DataModels/SampleTexture.hpp | 17 ++- src/ShaderNode/DataModels/ShaderNode.cpp | 76 +++++++++++ src/ShaderNode/DataModels/ShaderNode.hpp | 24 +++- src/ShaderNode/DataModels/ShaderNode.inl | 11 +- src/ShaderNode/DataModels/VecBinOp.hpp | 7 +- src/ShaderNode/DataModels/VecBinOp.inl | 75 ++++++----- src/ShaderNode/DataModels/VecData.hpp | 39 ++++++ src/ShaderNode/DataModels/VecValue.hpp | 38 +----- src/ShaderNode/DataModels/VecValue.inl | 97 ++++++-------- src/ShaderNode/ShaderGraph.cpp | 13 +- src/ShaderNode/ShaderGraph.hpp | 3 + src/ShaderNode/Widgets/MainWindow.cpp | 33 ++++- src/ShaderNode/Widgets/MainWindow.hpp | 6 +- src/ShaderNode/Widgets/NodeEditor.cpp | 20 +++ src/ShaderNode/Widgets/NodeEditor.hpp | 27 ++++ src/ShaderNode/Widgets/NodeEditor.inl | 16 +++ 24 files changed, 558 insertions(+), 337 deletions(-) create mode 100644 src/ShaderNode/Widgets/NodeEditor.cpp create mode 100644 src/ShaderNode/Widgets/NodeEditor.hpp create mode 100644 src/ShaderNode/Widgets/NodeEditor.inl diff --git a/src/ShaderNode/DataModels/Cast.hpp b/src/ShaderNode/DataModels/Cast.hpp index a6709bd2d..19d6363af 100644 --- a/src/ShaderNode/DataModels/Cast.hpp +++ b/src/ShaderNode/DataModels/Cast.hpp @@ -18,13 +18,14 @@ class CastVec : public ShaderNode CastVec(ShaderGraph& graph); ~CastVec() = default; + void BuildNodeEdition(QVBoxLayout* layout) override; + Nz::ShaderAst::ExpressionPtr GetExpression(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count) const override; QString caption() const override; QString name() const override; QtNodes::NodeDataType dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; - QWidget* embeddedWidget() override; unsigned int nPorts(QtNodes::PortType portType) const override; std::shared_ptr outData(QtNodes::PortIndex port) override; @@ -36,13 +37,10 @@ class CastVec : public ShaderNode static constexpr std::size_t ToComponents = To::ComponentCount; static constexpr std::size_t ComponentDiff = (ToComponents >= FromComponents) ? ToComponents - FromComponents : 0; - void ComputePreview(QPixmap& pixmap) const; - void UpdatePreview(); + bool ComputePreview(QPixmap& pixmap) override; + void UpdateOutput(); - QLabel* m_pixmapLabel; - QPixmap m_pixmap; - QWidget* m_widget; - std::array m_spinboxes; + VecType m_overflowComponents; std::shared_ptr m_input; std::shared_ptr m_output; }; diff --git a/src/ShaderNode/DataModels/Cast.inl b/src/ShaderNode/DataModels/Cast.inl index 0133d6cc7..5c0600833 100644 --- a/src/ShaderNode/DataModels/Cast.inl +++ b/src/ShaderNode/DataModels/Cast.inl @@ -6,41 +6,35 @@ template CastVec::CastVec(ShaderGraph& graph) : ShaderNode(graph) { - constexpr std::array componentName = { 'X', 'Y', 'Z', 'W' }; - static_assert(ComponentDiff <= componentName.size()); + static_assert(ComponentDiff <= s_vectorComponents.size()); +} - QFormLayout* layout = new QFormLayout; +template +void CastVec::BuildNodeEdition(QVBoxLayout* layout) +{ + ShaderNode::BuildNodeEdition(layout); if constexpr (ComponentDiff > 0) { + QFormLayout* formLayout = new QFormLayout; + for (std::size_t i = 0; i < ComponentDiff; ++i) { - m_spinboxes[i] = new QDoubleSpinBox; - m_spinboxes[i]->setDecimals(6); - m_spinboxes[i]->setValue(1.0); - m_spinboxes[i]->setStyleSheet("background-color: rgba(255,255,255,255)"); - connect(m_spinboxes[i], qOverload(&QDoubleSpinBox::valueChanged), [this](double) + QDoubleSpinBox* spinbox = new QDoubleSpinBox; + spinbox->setDecimals(6); + spinbox->setValue(m_overflowComponents[i]); + + connect(spinbox, qOverload(&QDoubleSpinBox::valueChanged), [=](double) { - UpdatePreview(); + m_overflowComponents[i] = spinbox->value(); + UpdateOutput(); }); - layout->addRow(QString::fromUtf8(&componentName[FromComponents + i], 1), m_spinboxes[i]); + formLayout->addRow(QString::fromUtf8(&s_vectorComponents[FromComponents + i], 1), spinbox); } + + layout->addLayout(formLayout); } - - m_pixmap = QPixmap(64, 64); - m_pixmap.fill(); - - m_pixmapLabel = new QLabel; - m_pixmapLabel->setPixmap(m_pixmap); - - layout->addWidget(m_pixmapLabel); - - m_widget = new QWidget; - m_widget->setStyleSheet("background-color: rgba(0,0,0,0)"); - m_widget->setLayout(layout); - - m_output = std::make_shared(); } template @@ -52,7 +46,7 @@ Nz::ShaderAst::ExpressionPtr CastVec::GetExpression(Nz::ShaderAst::Exp { std::array constants; for (std::size_t i = 0; i < ComponentDiff; ++i) - constants[i] = Nz::ShaderBuilder::Constant(float(m_spinboxes[i]->value())); + constants[i] = Nz::ShaderBuilder::Constant(m_overflowComponents[i]); return std::apply([&](auto&&... values) { @@ -102,12 +96,6 @@ QtNodes::NodeDataType CastVec::dataType(QtNodes::PortType portType, Qt throw std::runtime_error("Invalid port type"); } -template -QWidget* CastVec::embeddedWidget() -{ - return m_widget; -} - template unsigned int CastVec::nPorts(QtNodes::PortType portType) const { @@ -124,6 +112,10 @@ template std::shared_ptr CastVec::outData(QtNodes::PortIndex port) { assert(port == 0); + + if (!m_input) + return nullptr; + return m_output; } @@ -139,13 +131,28 @@ void CastVec::setInData(std::shared_ptr value, int else m_input.reset(); - UpdatePreview(); + UpdateOutput(); } template -void CastVec::ComputePreview(QPixmap& pixmap) const +bool CastVec::ComputePreview(QPixmap& pixmap) { - assert(m_input); + if (!m_input) + return false; + + pixmap = QPixmap::fromImage(m_output->preview); + return true; +} + +template +void CastVec::UpdateOutput() +{ + if (!m_input) + { + m_output->preview = QImage(1, 1, QImage::Format_RGBA8888); + m_output->preview.fill(QColor::fromRgb(0, 0, 0, 0)); + return; + } const QImage& input = m_input->preview; @@ -156,8 +163,11 @@ void CastVec::ComputePreview(QPixmap& pixmap) const output = QImage(inputWidth, inputHeight, QImage::Format_RGBA8888); std::array constants; - for (std::size_t i = 0; i < ComponentDiff; ++i) - constants[i] = static_cast(std::clamp(int(m_spinboxes[i]->value() * 255), 0, 255)); + if constexpr (ComponentDiff > 0) + { + for (std::size_t i = 0; i < ComponentDiff; ++i) + constants[i] = static_cast(std::clamp(int(m_overflowComponents[i] * 255), 0, 255)); + } std::uint8_t* outputPtr = output.bits(); const std::uint8_t* inputPtr = input.constBits(); @@ -181,21 +191,7 @@ void CastVec::ComputePreview(QPixmap& pixmap) const } } - pixmap = QPixmap::fromImage(output).scaled(64, 64); -} - -template -void CastVec::UpdatePreview() -{ - if (!m_input) - { - m_pixmap = QPixmap(64, 64); - m_pixmap.fill(QColor::fromRgb(255, 255, 255, 0)); - } - else - ComputePreview(m_pixmap); - - m_pixmapLabel->setPixmap(m_pixmap); - Q_EMIT dataUpdated(0); + + UpdatePreview(); } diff --git a/src/ShaderNode/DataModels/FragmentOutput.cpp b/src/ShaderNode/DataModels/FragmentOutput.cpp index 86731a0f4..bfac47bee 100644 --- a/src/ShaderNode/DataModels/FragmentOutput.cpp +++ b/src/ShaderNode/DataModels/FragmentOutput.cpp @@ -22,11 +22,6 @@ QtNodes::NodeDataType FragmentOutput::dataType(QtNodes::PortType portType, QtNod return Vec4Data::Type(); } -QWidget* FragmentOutput::embeddedWidget() -{ - return nullptr; -} - unsigned int FragmentOutput::nPorts(QtNodes::PortType portType) const { switch (portType) @@ -42,3 +37,26 @@ std::shared_ptr FragmentOutput::outData(QtNodes::PortIndex /* { return {}; } + +void FragmentOutput::setInData(std::shared_ptr value, int index) +{ + assert(index == 0); + if (value) + { + assert(dynamic_cast(value.get()) != nullptr); + m_input = std::static_pointer_cast(value); + } + else + m_input.reset(); + + UpdatePreview(); +} + +bool FragmentOutput::ComputePreview(QPixmap& pixmap) +{ + if (!m_input) + return false; + + pixmap = QPixmap::fromImage(m_input->preview); + return true; +} diff --git a/src/ShaderNode/DataModels/FragmentOutput.hpp b/src/ShaderNode/DataModels/FragmentOutput.hpp index ab89ae419..c70f39ff6 100644 --- a/src/ShaderNode/DataModels/FragmentOutput.hpp +++ b/src/ShaderNode/DataModels/FragmentOutput.hpp @@ -4,6 +4,7 @@ #define NAZARA_SHADERNODES_FRAGMENTOUTPUT_HPP #include +#include #include #include @@ -19,13 +20,16 @@ class FragmentOutput : public ShaderNode QtNodes::NodeDataType dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; - QWidget* embeddedWidget() override; unsigned int nPorts(QtNodes::PortType portType) const override; std::shared_ptr outData(QtNodes::PortIndex port) override; - void setInData(std::shared_ptr, int) override {}; + void setInData(std::shared_ptr value, int index) override; + private: + bool ComputePreview(QPixmap& pixmap) override; + + std::shared_ptr m_input; }; #include diff --git a/src/ShaderNode/DataModels/FragmentOutput.inl b/src/ShaderNode/DataModels/FragmentOutput.inl index c809a587d..24fc6cbf9 100644 --- a/src/ShaderNode/DataModels/FragmentOutput.inl +++ b/src/ShaderNode/DataModels/FragmentOutput.inl @@ -3,4 +3,6 @@ inline FragmentOutput::FragmentOutput(ShaderGraph& graph) : ShaderNode(graph) { + SetPreviewSize({ 128, 128 }); + EnablePreview(true); } diff --git a/src/ShaderNode/DataModels/InputValue.cpp b/src/ShaderNode/DataModels/InputValue.cpp index f2ae0eaa8..a6044a229 100644 --- a/src/ShaderNode/DataModels/InputValue.cpp +++ b/src/ShaderNode/DataModels/InputValue.cpp @@ -4,48 +4,18 @@ #include InputValue::InputValue(ShaderGraph& graph) : -ShaderNode(graph), -m_currentInputIndex(0) +ShaderNode(graph) { - m_layout = new QVBoxLayout; - - m_inputSelection = new QComboBox; - m_inputSelection->setStyleSheet("background-color: rgba(255,255,255,255)"); - connect(m_inputSelection, qOverload(&QComboBox::currentIndexChanged), [&](int index) - { - if (index < 0) - return; - - m_currentInputIndex = static_cast(index); - UpdatePreview(); - }); - - m_layout->addWidget(m_inputSelection); - - m_previewLabel = new QLabel; - - m_layout->addWidget(m_previewLabel); - - m_widget = new QWidget; - m_widget->setStyleSheet("background-color: rgba(0,0,0,0)"); - m_widget->setLayout(m_layout); - - m_onInputListUpdateSlot.Connect(GetGraph().OnInputListUpdate, [&](ShaderGraph*) { UpdateInputList(); }); + m_onInputListUpdateSlot.Connect(GetGraph().OnInputListUpdate, [&](ShaderGraph*) { OnInputListUpdate(); }); m_onInputUpdateSlot.Connect(GetGraph().OnInputUpdate, [&](ShaderGraph*, std::size_t inputIndex) { if (m_currentInputIndex == inputIndex) UpdatePreview(); }); - UpdateInputList(); UpdatePreview(); } -QWidget* InputValue::embeddedWidget() -{ - return m_widget; -} - unsigned int InputValue::nPorts(QtNodes::PortType portType) const { switch (portType) @@ -57,36 +27,66 @@ unsigned int InputValue::nPorts(QtNodes::PortType portType) const return 0; } -void InputValue::UpdatePreview() +bool InputValue::ComputePreview(QPixmap& pixmap) { - if (m_inputSelection->count() == 0) - return; + if (!m_currentInputIndex) + return false; const ShaderGraph& graph = GetGraph(); - const auto& inputEntry = graph.GetInput(m_currentInputIndex); + const auto& inputEntry = graph.GetInput(*m_currentInputIndex); const auto& preview = graph.GetPreviewModel(); - m_previewLabel->setPixmap(QPixmap::fromImage(preview.GetImage(inputEntry.role, inputEntry.roleIndex))); - - Q_EMIT dataUpdated(0); + pixmap = QPixmap::fromImage(preview.GetImage(inputEntry.role, inputEntry.roleIndex)); + return true; } -void InputValue::UpdateInputList() +void InputValue::OnInputListUpdate() { - QString currentInput = m_inputSelection->currentText(); - m_inputSelection->clear(); + m_currentInputIndex.reset(); + + std::size_t inputIndex = 0; + for (const auto& inputEntry : GetGraph().GetInputs()) + { + if (inputEntry.name == m_currentInputText) + { + m_currentInputIndex = inputIndex; + break; + } + + inputIndex++; + } +} + +void InputValue::BuildNodeEdition(QVBoxLayout* layout) +{ + ShaderNode::BuildNodeEdition(layout); + + QComboBox* inputSelection = new QComboBox; + + connect(inputSelection, qOverload(&QComboBox::currentIndexChanged), [&](int index) + { + if (index >= 0) + m_currentInputIndex = static_cast(index); + else + m_currentInputIndex.reset(); + + UpdatePreview(); + }); for (const auto& inputEntry : GetGraph().GetInputs()) - m_inputSelection->addItem(QString::fromStdString(inputEntry.name)); + inputSelection->addItem(QString::fromStdString(inputEntry.name)); - m_inputSelection->setCurrentText(currentInput); + layout->addWidget(inputSelection); } Nz::ShaderAst::ExpressionPtr InputValue::GetExpression(Nz::ShaderAst::ExpressionPtr* /*expressions*/, std::size_t count) const { assert(count == 0); - const auto& inputEntry = GetGraph().GetInput(m_currentInputIndex); + if (!m_currentInputIndex) + throw std::runtime_error("no input"); + + const auto& inputEntry = GetGraph().GetInput(*m_currentInputIndex); Nz::ShaderAst::ExpressionType expression = [&] { @@ -108,10 +108,13 @@ Nz::ShaderAst::ExpressionPtr InputValue::GetExpression(Nz::ShaderAst::Expression auto InputValue::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const -> QtNodes::NodeDataType { + if (!m_currentInputIndex) + return Vec4Data::Type(); + assert(portType == QtNodes::PortType::Out); assert(portIndex == 0); - const auto& inputEntry = GetGraph().GetInput(m_currentInputIndex); + const auto& inputEntry = GetGraph().GetInput(*m_currentInputIndex); switch (inputEntry.type) { //case InputType::Bool: return Nz::ShaderAst::ExpressionType::Boolean; @@ -127,10 +130,13 @@ auto InputValue::dataType(QtNodes::PortType portType, QtNodes::PortIndex portInd std::shared_ptr InputValue::outData(QtNodes::PortIndex port) { + if (!m_currentInputIndex) + return nullptr; + assert(port == 0); const ShaderGraph& graph = GetGraph(); - const auto& inputEntry = graph.GetInput(m_currentInputIndex); + const auto& inputEntry = graph.GetInput(*m_currentInputIndex); const auto& preview = graph.GetPreviewModel(); auto vecData = std::make_shared(); diff --git a/src/ShaderNode/DataModels/InputValue.hpp b/src/ShaderNode/DataModels/InputValue.hpp index 273155cc4..84b7d6393 100644 --- a/src/ShaderNode/DataModels/InputValue.hpp +++ b/src/ShaderNode/DataModels/InputValue.hpp @@ -9,6 +9,7 @@ #include #include #include +#include class InputValue : public ShaderNode { @@ -16,30 +17,28 @@ class InputValue : public ShaderNode InputValue(ShaderGraph& graph); ~InputValue() = default; + void BuildNodeEdition(QVBoxLayout* layout) override; + Nz::ShaderAst::ExpressionPtr GetExpression(Nz::ShaderAst::ExpressionPtr* /*expressions*/, std::size_t count) const override; QString caption() const override { return "Input"; } QString name() const override { return "Input"; } - QWidget* embeddedWidget() override; unsigned int nPorts(QtNodes::PortType portType) const override; QtNodes::NodeDataType dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; std::shared_ptr outData(QtNodes::PortIndex port) override; - protected: - void UpdatePreview(); - void UpdateInputList(); + private: + bool ComputePreview(QPixmap& pixmap) override; + void OnInputListUpdate(); NazaraSlot(ShaderGraph, OnInputListUpdate, m_onInputListUpdateSlot); NazaraSlot(ShaderGraph, OnInputUpdate, m_onInputUpdateSlot); - std::size_t m_currentInputIndex; - QComboBox* m_inputSelection; - QLabel* m_previewLabel; - QWidget* m_widget; - QVBoxLayout* m_layout; + std::optional m_currentInputIndex; + std::string m_currentInputText; }; #include diff --git a/src/ShaderNode/DataModels/SampleTexture.cpp b/src/ShaderNode/DataModels/SampleTexture.cpp index 81982c83a..f299b6009 100644 --- a/src/ShaderNode/DataModels/SampleTexture.cpp +++ b/src/ShaderNode/DataModels/SampleTexture.cpp @@ -4,52 +4,16 @@ #include SampleTexture::SampleTexture(ShaderGraph& graph) : -ShaderNode(graph), -m_currentTextureIndex(0) +ShaderNode(graph) { m_output = std::make_shared(); - m_layout = new QVBoxLayout; - - m_textureSelection = new QComboBox; - m_textureSelection->setStyleSheet("background-color: rgba(255,255,255,255)"); - connect(m_textureSelection, qOverload(&QComboBox::currentIndexChanged), [&](int index) - { - if (index < 0) - return; - - m_currentTextureIndex = static_cast(index); - UpdatePreview(); - }); - - m_layout->addWidget(m_textureSelection); - - m_pixmap = QPixmap(64, 64); - m_pixmap.fill(); - - m_pixmapLabel = new QLabel; - m_pixmapLabel->setPixmap(m_pixmap); - - m_layout->addWidget(m_pixmapLabel); - - m_widget = new QWidget; - m_widget->setStyleSheet("background-color: rgba(0,0,0,0)"); - m_widget->setLayout(m_layout); - - m_onTextureListUpdateSlot.Connect(GetGraph().OnTextureListUpdate, [&](ShaderGraph*) { UpdateTextureList(); }); + m_onTextureListUpdateSlot.Connect(GetGraph().OnTextureListUpdate, [&](ShaderGraph*) { OnTextureListUpdate(); }); m_onTexturePreviewUpdateSlot.Connect(GetGraph().OnTexturePreviewUpdate, [&](ShaderGraph*, std::size_t textureIndex) { if (m_currentTextureIndex == textureIndex) UpdatePreview(); }); - - UpdateTextureList(); - UpdatePreview(); -} - -QWidget* SampleTexture::embeddedWidget() -{ - return m_widget; } unsigned int SampleTexture::nPorts(QtNodes::PortType portType) const @@ -63,39 +27,39 @@ unsigned int SampleTexture::nPorts(QtNodes::PortType portType) const return 0; } -void SampleTexture::UpdatePreview() +void SampleTexture::OnTextureListUpdate() { - if (m_textureSelection->count() == 0) - return; - - ComputePreview(m_pixmap); - m_pixmapLabel->setPixmap(m_pixmap); - - Q_EMIT dataUpdated(0); -} - -void SampleTexture::UpdateTextureList() -{ - QString currentTexture = m_textureSelection->currentText(); - m_textureSelection->clear(); + m_currentTextureIndex.reset(); + std::size_t inputIndex = 0; for (const auto& textureEntry : GetGraph().GetTextures()) - m_textureSelection->addItem(QString::fromStdString(textureEntry.name)); + { + if (textureEntry.name == m_currentTextureText) + { + m_currentTextureIndex = inputIndex; + break; + } - m_textureSelection->setCurrentText(currentTexture); + inputIndex++; + } } -void SampleTexture::ComputePreview(QPixmap& pixmap) const +void SampleTexture::UpdateOutput() { - if (!m_uv) - return; + QImage& output = m_output->preview; - const auto& textureEntry = GetGraph().GetTexture(m_currentTextureIndex); + if (!m_currentTextureIndex || !m_uv) + { + output = QImage(1, 1, QImage::Format_RGBA8888); + output.fill(QColor::fromRgb(0, 0, 0, 0)); + return; + } + + const auto& textureEntry = GetGraph().GetTexture(*m_currentTextureIndex); int textureWidth = textureEntry.preview.width(); int textureHeight = textureEntry.preview.height(); - QImage& output = m_output->preview; const QImage& uv = m_uv->preview; int uvWidth = uv.width(); @@ -125,14 +89,49 @@ void SampleTexture::ComputePreview(QPixmap& pixmap) const } } - pixmap = QPixmap::fromImage(output).scaled(128, 128, Qt::KeepAspectRatio); + Q_EMIT dataUpdated(0); + + UpdatePreview(); +} + +bool SampleTexture::ComputePreview(QPixmap& pixmap) +{ + if (!m_currentTextureIndex || !m_uv) + return false; + + pixmap = QPixmap::fromImage(m_output->preview); + return true; +} + +void SampleTexture::BuildNodeEdition(QVBoxLayout* layout) +{ + ShaderNode::BuildNodeEdition(layout); + + QComboBox* textureSelection = new QComboBox; + connect(textureSelection, qOverload(&QComboBox::currentIndexChanged), [&](int index) + { + if (index >= 0) + m_currentTextureIndex = static_cast(index); + else + m_currentTextureIndex.reset(); + + UpdateOutput(); + }); + + for (const auto& textureEntry : GetGraph().GetTextures()) + textureSelection->addItem(QString::fromStdString(textureEntry.name)); + + layout->addWidget(textureSelection); } Nz::ShaderAst::ExpressionPtr SampleTexture::GetExpression(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count) const { + if (!m_currentTextureIndex || !m_uv) + throw std::runtime_error("invalid inputs"); + assert(count == 1); - const auto& textureEntry = GetGraph().GetTexture(m_currentTextureIndex); + const auto& textureEntry = GetGraph().GetTexture(*m_currentTextureIndex); Nz::ShaderAst::ExpressionType expression = [&] { @@ -203,6 +202,9 @@ std::shared_ptr SampleTexture::outData(QtNodes::PortIndex por { assert(port == 0); + if (!m_currentTextureIndex) + return nullptr; + return m_output; } @@ -219,5 +221,5 @@ void SampleTexture::setInData(std::shared_ptr value, int inde else m_uv.reset(); - UpdatePreview(); + UpdateOutput(); } diff --git a/src/ShaderNode/DataModels/SampleTexture.hpp b/src/ShaderNode/DataModels/SampleTexture.hpp index 7697d296f..738047712 100644 --- a/src/ShaderNode/DataModels/SampleTexture.hpp +++ b/src/ShaderNode/DataModels/SampleTexture.hpp @@ -17,12 +17,13 @@ class SampleTexture : public ShaderNode SampleTexture(ShaderGraph& graph); ~SampleTexture() = default; + void BuildNodeEdition(QVBoxLayout* layout) override; + Nz::ShaderAst::ExpressionPtr GetExpression(Nz::ShaderAst::ExpressionPtr* /*expressions*/, std::size_t count) const override; QString caption() const override { return "Sample texture"; } QString name() const override { return "SampleTexture"; } - QWidget* embeddedWidget() override; unsigned int nPorts(QtNodes::PortType portType) const override; QtNodes::NodeDataType dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; @@ -36,21 +37,17 @@ class SampleTexture : public ShaderNode void setInData(std::shared_ptr value, int index) override; protected: - void ComputePreview(QPixmap& pixmap) const; - void UpdatePreview(); - void UpdateTextureList(); + bool ComputePreview(QPixmap& pixmap) override; + void OnTextureListUpdate(); + void UpdateOutput(); NazaraSlot(ShaderGraph, OnTextureListUpdate, m_onTextureListUpdateSlot); NazaraSlot(ShaderGraph, OnTexturePreviewUpdate, m_onTexturePreviewUpdateSlot); - std::size_t m_currentTextureIndex; + std::optional m_currentTextureIndex; std::shared_ptr m_uv; std::shared_ptr m_output; - QComboBox* m_textureSelection; - QLabel* m_pixmapLabel; - QPixmap m_pixmap; - QWidget* m_widget; - QVBoxLayout* m_layout; + std::string m_currentTextureText; }; #include diff --git a/src/ShaderNode/DataModels/ShaderNode.cpp b/src/ShaderNode/DataModels/ShaderNode.cpp index aeb143452..1221d1df6 100644 --- a/src/ShaderNode/DataModels/ShaderNode.cpp +++ b/src/ShaderNode/DataModels/ShaderNode.cpp @@ -1,5 +1,81 @@ #include +#include +#include +#include + +ShaderNode::ShaderNode(ShaderGraph& graph) : +m_previewSize(64, 64), +m_pixmapLabel(nullptr), +m_graph(graph), +m_isPreviewEnabled(false) +{ + m_pixmapLabel = new QLabel; + m_pixmapLabel->setStyleSheet("background-color: rgba(0,0,0,0)"); +} + +void ShaderNode::BuildNodeEdition(QVBoxLayout* layout) +{ + QCheckBox* checkbox = new QCheckBox(tr("Enable preview")); + checkbox->setCheckState((m_isPreviewEnabled) ? Qt::Checked : Qt::Unchecked); + + connect(checkbox, &QCheckBox::stateChanged, [&](int state) + { + EnablePreview(state == Qt::Checked); + }); + + layout->addWidget(checkbox); +} + +void ShaderNode::EnablePreview(bool enable) +{ + if (m_isPreviewEnabled != enable) + { + m_isPreviewEnabled = enable; + + if (m_isPreviewEnabled) + { + m_pixmap.emplace(m_previewSize.x, m_previewSize.y); + + UpdatePreview(); + } + else + { + m_pixmapLabel->clear(); + m_pixmap.reset(); + } + + embeddedWidgetSizeUpdated(); + } +} + +QWidget* ShaderNode::embeddedWidget() +{ + return m_pixmapLabel; +} void ShaderNode::setInData(std::shared_ptr, int) { } + +bool ShaderNode::ComputePreview(QPixmap& /*pixmap*/) +{ + return false; +} + +void ShaderNode::UpdatePreview() +{ + if (!m_pixmap) + return; + + QPixmap& pixmap = *m_pixmap; + + if (!ComputePreview(pixmap)) + { + pixmap = QPixmap(m_previewSize.x, m_previewSize.y); + pixmap.fill(QColor::fromRgb(255, 255, 255, 0)); + } + else + pixmap = pixmap.scaled(m_previewSize.x, m_previewSize.y); + + m_pixmapLabel->setPixmap(pixmap); +} diff --git a/src/ShaderNode/DataModels/ShaderNode.hpp b/src/ShaderNode/DataModels/ShaderNode.hpp index 3d73d7330..3cf16ea06 100644 --- a/src/ShaderNode/DataModels/ShaderNode.hpp +++ b/src/ShaderNode/DataModels/ShaderNode.hpp @@ -3,24 +3,46 @@ #ifndef NAZARA_SHADERNODES_SHADERNODE_HPP #define NAZARA_SHADERNODES_SHADERNODE_HPP +#include #include #include +#include +#include +class QLabel; +class QVBoxLayout; class ShaderGraph; class ShaderNode : public QtNodes::NodeDataModel { public: - inline ShaderNode(ShaderGraph& graph); + ShaderNode(ShaderGraph& graph); + + virtual void BuildNodeEdition(QVBoxLayout* layout); + + void EnablePreview(bool enable); virtual Nz::ShaderAst::ExpressionPtr GetExpression(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count) const = 0; inline ShaderGraph& GetGraph(); inline const ShaderGraph& GetGraph() const; + void SetPreviewSize(const Nz::Vector2i& size); + + QWidget* embeddedWidget() final; + void setInData(std::shared_ptr, int) override; + protected: + void UpdatePreview(); + private: + virtual bool ComputePreview(QPixmap& pixmap); + + Nz::Vector2i m_previewSize; + QLabel* m_pixmapLabel; + std::optional m_pixmap; ShaderGraph& m_graph; + bool m_isPreviewEnabled; }; #include diff --git a/src/ShaderNode/DataModels/ShaderNode.inl b/src/ShaderNode/DataModels/ShaderNode.inl index defa5aea1..7f80d00ff 100644 --- a/src/ShaderNode/DataModels/ShaderNode.inl +++ b/src/ShaderNode/DataModels/ShaderNode.inl @@ -1,9 +1,5 @@ #include -inline ShaderNode::ShaderNode(ShaderGraph& graph) : -m_graph(graph) -{ -} inline ShaderGraph& ShaderNode::GetGraph() { @@ -14,3 +10,10 @@ inline const ShaderGraph& ShaderNode::GetGraph() const { return m_graph; } + +inline void ShaderNode::SetPreviewSize(const Nz::Vector2i& size) +{ + m_previewSize = size; + if (m_isPreviewEnabled) + UpdatePreview(); +} diff --git a/src/ShaderNode/DataModels/VecBinOp.hpp b/src/ShaderNode/DataModels/VecBinOp.hpp index ef3ee4bca..e56c13461 100644 --- a/src/ShaderNode/DataModels/VecBinOp.hpp +++ b/src/ShaderNode/DataModels/VecBinOp.hpp @@ -15,7 +15,6 @@ class VecBinOp : public ShaderNode Nz::ShaderAst::ExpressionPtr GetExpression(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count) const override; - QWidget* embeddedWidget() override; unsigned int nPorts(QtNodes::PortType portType) const override; QtNodes::NodeDataType dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; @@ -26,10 +25,10 @@ class VecBinOp : public ShaderNode private: virtual void ApplyOp(const std::uint8_t* left, const std::uint8_t* right, std::uint8_t* output, std::size_t pixelCount) = 0; - void UpdatePreview(); - QLabel* m_pixmapLabel; - QPixmap m_preview; + bool ComputePreview(QPixmap& pixmap) override; + void UpdateOutput(); + std::shared_ptr m_lhs; std::shared_ptr m_rhs; std::shared_ptr m_output; diff --git a/src/ShaderNode/DataModels/VecBinOp.inl b/src/ShaderNode/DataModels/VecBinOp.inl index 4159193fb..2d33f65c6 100644 --- a/src/ShaderNode/DataModels/VecBinOp.inl +++ b/src/ShaderNode/DataModels/VecBinOp.inl @@ -7,9 +7,7 @@ ShaderNode(graph) { m_output = std::make_shared(); - m_pixmapLabel = new QLabel; - m_pixmapLabel->setStyleSheet("background-color: rgba(0,0,0,0)"); - UpdatePreview(); + UpdateOutput(); } template @@ -21,12 +19,6 @@ Nz::ShaderAst::ExpressionPtr VecBinOp::GetExpression(Nz::ShaderAst: return builder(expressions[0], expressions[1]); } -template -QWidget* VecBinOp::embeddedWidget() -{ - return m_pixmapLabel; -} - template QtNodes::NodeDataType VecBinOp::dataType(QtNodes::PortType /*portType*/, QtNodes::PortIndex portIndex) const { @@ -72,42 +64,49 @@ void VecBinOp::setInData(std::shared_ptr value, else m_rhs = std::move(castedValue); - UpdatePreview(); - - Q_EMIT dataUpdated(0); + UpdateOutput(); } template -void VecBinOp::UpdatePreview() +bool VecBinOp::ComputePreview(QPixmap& pixmap) { - if (m_lhs && m_rhs) + if (!m_lhs || !m_rhs) + return false; + + pixmap = QPixmap::fromImage(m_output->preview); + return true; +} + +template +void VecBinOp::UpdateOutput() +{ + if (!m_lhs || !m_rhs) { - const QImage& leftPreview = m_lhs->preview; - const QImage& rightPreview = m_rhs->preview; - int maxWidth = std::max(leftPreview.width(), rightPreview.width()); - int maxHeight = std::max(leftPreview.height(), rightPreview.height()); - - // Exploit COW - QImage leftResized = leftPreview; - if (leftResized.width() != maxWidth || leftResized.height() != maxHeight) - leftResized = leftResized.scaled(maxWidth, maxHeight); - - QImage rightResized = rightPreview; - if (rightResized.width() != maxWidth || rightResized.height() != maxHeight) - rightResized = rightResized.scaled(maxWidth, maxHeight); - - m_output->preview = QImage(maxWidth, maxHeight, QImage::Format_RGBA8888); - ApplyOp(leftResized.constBits(), rightResized.constBits(), m_output->preview.bits(), maxWidth * maxHeight * 4); - - m_preview = QPixmap::fromImage(m_output->preview).scaled(64, 64); - } - else - { - m_preview = QPixmap(64, 64); - m_preview.fill(QColor::fromRgb(255, 255, 0, 0)); + m_output->preview = QImage(1, 1, QImage::Format_RGBA8888); + m_output->preview.fill(QColor::fromRgb(0, 0, 0, 0)); + return; } - m_pixmapLabel->setPixmap(m_preview); + const QImage& leftPreview = m_lhs->preview; + const QImage& rightPreview = m_rhs->preview; + int maxWidth = std::max(leftPreview.width(), rightPreview.width()); + int maxHeight = std::max(leftPreview.height(), rightPreview.height()); + + // Exploit COW + QImage leftResized = leftPreview; + if (leftResized.width() != maxWidth || leftResized.height() != maxHeight) + leftResized = leftResized.scaled(maxWidth, maxHeight); + + QImage rightResized = rightPreview; + if (rightResized.width() != maxWidth || rightResized.height() != maxHeight) + rightResized = rightResized.scaled(maxWidth, maxHeight); + + m_output->preview = QImage(maxWidth, maxHeight, QImage::Format_RGBA8888); + ApplyOp(leftResized.constBits(), rightResized.constBits(), m_output->preview.bits(), maxWidth * maxHeight * 4); + + Q_EMIT dataUpdated(0); + + UpdatePreview(); } template diff --git a/src/ShaderNode/DataModels/VecData.hpp b/src/ShaderNode/DataModels/VecData.hpp index 8a1b152f5..3882f20f1 100644 --- a/src/ShaderNode/DataModels/VecData.hpp +++ b/src/ShaderNode/DataModels/VecData.hpp @@ -62,6 +62,45 @@ struct Vec4Data : public VecData } }; +struct VecTypeDummy {}; + +template +struct VecTypeHelper; + +template<> +struct VecTypeHelper<0> +{ + using Type = VecTypeDummy; +}; + +template<> +struct VecTypeHelper<1> +{ + using Type = std::array; +}; + +template<> +struct VecTypeHelper<2> +{ + using Type = Nz::Vector2f; +}; + +template<> +struct VecTypeHelper<3> +{ + using Type = Nz::Vector3f; +}; + +template<> +struct VecTypeHelper<4> +{ + using Type = Nz::Vector4f; +}; + +template using VecType = typename VecTypeHelper::template Type; + +constexpr std::array s_vectorComponents = { 'X', 'Y', 'Z', 'W' }; + #include #endif diff --git a/src/ShaderNode/DataModels/VecValue.hpp b/src/ShaderNode/DataModels/VecValue.hpp index 7e8db4d88..27df2757f 100644 --- a/src/ShaderNode/DataModels/VecValue.hpp +++ b/src/ShaderNode/DataModels/VecValue.hpp @@ -11,29 +11,6 @@ #include #include -template -struct VecTypeHelper; - -template<> -struct VecTypeHelper<2> -{ - using Type = Nz::Vector2f; -}; - -template<> -struct VecTypeHelper<3> -{ - using Type = Nz::Vector3f; -}; - -template<> -struct VecTypeHelper<4> -{ - using Type = Nz::Vector4f; -}; - -template using VecType = typename VecTypeHelper::template Type; - template class VecValue : public ShaderNode { @@ -46,25 +23,22 @@ class VecValue : public ShaderNode QtNodes::NodeDataType dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; - QWidget* embeddedWidget() override; unsigned int nPorts(QtNodes::PortType portType) const override; std::shared_ptr outData(QtNodes::PortIndex port) override; + void BuildNodeEdition(QVBoxLayout* layout) override; + Nz::ShaderAst::ExpressionPtr GetExpression(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count) const override; - protected: + private: + bool ComputePreview(QPixmap& pixmap) override; + static constexpr std::size_t ComponentCount = Data::ComponentCount; QColor ToColor() const; - VecType ToVector() const; - void UpdatePreview(); - QLabel* m_pixmapLabel; - QPixmap m_pixmap; - QWidget* m_widget; - QFormLayout* m_layout; - std::array m_spinboxes; + VecType m_value; }; using Vec2Value = VecValue; diff --git a/src/ShaderNode/DataModels/VecValue.inl b/src/ShaderNode/DataModels/VecValue.inl index 45138b83f..8f9212631 100644 --- a/src/ShaderNode/DataModels/VecValue.inl +++ b/src/ShaderNode/DataModels/VecValue.inl @@ -8,37 +8,14 @@ template VecValue::VecValue(ShaderGraph& graph) : ShaderNode(graph) { - constexpr std::array componentName = { 'X', 'Y', 'Z', 'W' }; - static_assert(ComponentCount <= componentName.size()); + static_assert(ComponentCount <= s_vectorComponents.size()); + + std::array defaultValues; - m_layout = new QFormLayout; for (std::size_t i = 0; i < ComponentCount; ++i) - { - m_spinboxes[i] = new QDoubleSpinBox; - m_spinboxes[i]->setDecimals(6); - m_spinboxes[i]->setValue(1.0); - m_spinboxes[i]->setStyleSheet("background-color: rgba(255,255,255,255)"); - connect(m_spinboxes[i], qOverload(&QDoubleSpinBox::valueChanged), [this](double) - { - UpdatePreview(); + defaultValues[i] = (i == 3) ? 1.f : 0.f; - Q_EMIT dataUpdated(0); - }); - - m_layout->addRow(QString::fromUtf8(&componentName[i], 1), m_spinboxes[i]); - } - - m_pixmap = QPixmap(32, 32); - m_pixmap.fill(); - - m_pixmapLabel = new QLabel; - m_pixmapLabel->setPixmap(m_pixmap); - - m_layout->addWidget(m_pixmapLabel); - - m_widget = new QWidget; - m_widget->setStyleSheet("background-color: rgba(0,0,0,0)"); - m_widget->setLayout(m_layout); + m_value.Set(defaultValues.data()); UpdatePreview(); } @@ -66,12 +43,6 @@ QtNodes::NodeDataType VecValue::dataType(QtNodes::PortType portType, QtNod return Data::Type(); } -template -QWidget* VecValue::embeddedWidget() -{ - return m_widget; -} - template unsigned int VecValue::nPorts(QtNodes::PortType portType) const { @@ -96,12 +67,45 @@ std::shared_ptr VecValue::outData(QtNodes::PortIndex po return out; } +template +void VecValue::BuildNodeEdition(QVBoxLayout* layout) +{ + ShaderNode::BuildNodeEdition(layout); + + QFormLayout* formLayout = new QFormLayout; + for (std::size_t i = 0; i < ComponentCount; ++i) + { + QDoubleSpinBox* spinbox = new QDoubleSpinBox; + spinbox->setDecimals(6); + spinbox->setValue(m_value[i]); + + connect(spinbox, qOverload(&QDoubleSpinBox::valueChanged), [=](double) + { + m_value[i] = spinbox->value(); + Q_EMIT dataUpdated(0); + + UpdatePreview(); + }); + + formLayout->addRow(QString::fromUtf8(&s_vectorComponents[i], 1), spinbox); + } + + layout->addLayout(formLayout); +} + template Nz::ShaderAst::ExpressionPtr VecValue::GetExpression(Nz::ShaderAst::ExpressionPtr* /*expressions*/, std::size_t count) const { assert(count == 0); - return Nz::ShaderBuilder::Constant(ToVector()); + return Nz::ShaderBuilder::Constant(m_value); +} + +template +bool VecValue::ComputePreview(QPixmap& pixmap) +{ + pixmap.fill(ToColor()); + return true; } template @@ -110,28 +114,7 @@ QColor VecValue::ToColor() const std::array values = { 0.f, 0.f, 0.f, 1.f }; for (std::size_t i = 0; i < ComponentCount; ++i) - values[i] = std::clamp(float(m_spinboxes[i]->value()), 0.f, 1.f); + values[i] = std::clamp(m_value[i], 0.f, 1.f); return QColor::fromRgbF(values[0], values[1], values[2], values[3]); } - -template -auto VecValue::ToVector() const -> VecType -{ - std::array values; - - for (std::size_t i = 0; i < ComponentCount; ++i) - values[i] = std::clamp(float(m_spinboxes[i]->value()), 0.f, 1.f); - - return std::apply([](auto... values) - { - return VecType(values...); - }, values); -} - -template -void VecValue::UpdatePreview() -{ - m_pixmap.fill(ToColor()); - m_pixmapLabel->setPixmap(m_pixmap); -} diff --git a/src/ShaderNode/ShaderGraph.cpp b/src/ShaderNode/ShaderGraph.cpp index e29c0129f..bc9d643fd 100644 --- a/src/ShaderNode/ShaderGraph.cpp +++ b/src/ShaderNode/ShaderGraph.cpp @@ -29,6 +29,17 @@ namespace ShaderGraph::ShaderGraph() : m_flowScene(BuildRegistry()) { + m_previewModel = std::make_unique(); + + QObject::connect(&m_flowScene, &QGraphicsScene::selectionChanged, [&] + { + auto selectedNodes = m_flowScene.selectedNodes(); + if (selectedNodes.size() == 1) + OnSelectedNodeUpdate(this, static_cast(selectedNodes.front()->nodeDataModel())); + else + OnSelectedNodeUpdate(this, nullptr); + }); + auto& node1 = m_flowScene.createNode(std::make_unique(*this)); node1.nodeGraphicsObject().setPos(200, 200); @@ -36,8 +47,6 @@ m_flowScene(BuildRegistry()) node2.nodeGraphicsObject().setPos(500, 300); m_flowScene.createConnection(node2, 0, node1, 0); - - m_previewModel = std::make_unique(); } ShaderGraph::~ShaderGraph() diff --git a/src/ShaderNode/ShaderGraph.hpp b/src/ShaderNode/ShaderGraph.hpp index aa2188f16..3ed906edd 100644 --- a/src/ShaderNode/ShaderGraph.hpp +++ b/src/ShaderNode/ShaderGraph.hpp @@ -11,6 +11,8 @@ #include #include +class ShaderNode; + class ShaderGraph { public: @@ -52,6 +54,7 @@ class ShaderGraph NazaraSignal(OnInputListUpdate, ShaderGraph*); NazaraSignal(OnInputUpdate, ShaderGraph*, std::size_t /*inputIndex*/); + NazaraSignal(OnSelectedNodeUpdate, ShaderGraph*, ShaderNode* /*node*/); NazaraSignal(OnTextureListUpdate, ShaderGraph*); NazaraSignal(OnTexturePreviewUpdate, ShaderGraph*, std::size_t /*textureIndex*/); diff --git a/src/ShaderNode/Widgets/MainWindow.cpp b/src/ShaderNode/Widgets/MainWindow.cpp index 8aa48c353..580e5b506 100644 --- a/src/ShaderNode/Widgets/MainWindow.cpp +++ b/src/ShaderNode/Widgets/MainWindow.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -19,20 +20,44 @@ m_shaderGraph(graph) QtNodes::FlowView* flowView = new QtNodes::FlowView(scene); setCentralWidget(flowView); - QDockWidget* inputDock = new QDockWidget(tr("&Inputs")); - InputEditor* inputEditor = new InputEditor(m_shaderGraph); + + QDockWidget* inputDock = new QDockWidget(tr("Inputs")); + inputDock->setFeatures(QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetMovable); inputDock->setWidget(inputEditor); addDockWidget(Qt::LeftDockWidgetArea, inputDock); - QDockWidget* textureDock = new QDockWidget(tr("&Textures")); - TextureEditor* textureEditor = new TextureEditor(m_shaderGraph); + + QDockWidget* textureDock = new QDockWidget(tr("Textures")); + textureDock->setFeatures(QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetMovable); textureDock->setWidget(textureEditor); addDockWidget(Qt::LeftDockWidgetArea, textureDock); + m_nodeEditor = new NodeEditor; + + QDockWidget* nodeEditorDock = new QDockWidget(tr("Node editor")); + nodeEditorDock->setFeatures(QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetMovable); + nodeEditorDock->setWidget(m_nodeEditor); + + addDockWidget(Qt::RightDockWidgetArea, nodeEditorDock); + + m_onSelectedNodeUpdate.Connect(m_shaderGraph.OnSelectedNodeUpdate, [&](ShaderGraph*, ShaderNode* node) + { + if (node) + { + m_nodeEditor->UpdateContent(node->caption(), [node](QVBoxLayout* layout) + { + node->BuildNodeEdition(layout); + }); + } + else + m_nodeEditor->Clear(); + }); + + BuildMenu(); } diff --git a/src/ShaderNode/Widgets/MainWindow.hpp b/src/ShaderNode/Widgets/MainWindow.hpp index 3e68ec267..777c3b92b 100644 --- a/src/ShaderNode/Widgets/MainWindow.hpp +++ b/src/ShaderNode/Widgets/MainWindow.hpp @@ -4,9 +4,10 @@ #define NAZARA_SHADERNODES_MAINWINDOW_HPP #include +#include #include -class ShaderGraph; +class NodeEditor; class MainWindow : public QMainWindow { @@ -18,6 +19,9 @@ class MainWindow : public QMainWindow void BuildMenu(); void OnCompileToGLSL(); + NazaraSlot(ShaderGraph, OnSelectedNodeUpdate, m_onSelectedNodeUpdate); + + NodeEditor* m_nodeEditor; ShaderGraph& m_shaderGraph; }; diff --git a/src/ShaderNode/Widgets/NodeEditor.cpp b/src/ShaderNode/Widgets/NodeEditor.cpp new file mode 100644 index 000000000..ee6b63e5a --- /dev/null +++ b/src/ShaderNode/Widgets/NodeEditor.cpp @@ -0,0 +1,20 @@ +#include +#include +#include + +NodeEditor::NodeEditor() : +m_layout(nullptr) +{ +} + +void NodeEditor::Clear() +{ + if (m_layout) + { + while (QWidget* w = findChild()) + delete w; + + delete m_layout; + m_layout = nullptr; + } +} diff --git a/src/ShaderNode/Widgets/NodeEditor.hpp b/src/ShaderNode/Widgets/NodeEditor.hpp new file mode 100644 index 000000000..65e73c107 --- /dev/null +++ b/src/ShaderNode/Widgets/NodeEditor.hpp @@ -0,0 +1,27 @@ +#pragma once + +#ifndef NAZARA_SHADERNODES_NODEEDITOR_HPP +#define NAZARA_SHADERNODES_NODEEDITOR_HPP + +#include +#include +#include +#include + +class NodeEditor : public QWidget +{ + public: + NodeEditor(); + ~NodeEditor() = default; + + void Clear(); + + template void UpdateContent(QString nodeName, F&& callback); + + private: + QVBoxLayout* m_layout; +}; + +#include + +#endif diff --git a/src/ShaderNode/Widgets/NodeEditor.inl b/src/ShaderNode/Widgets/NodeEditor.inl new file mode 100644 index 000000000..a7f916889 --- /dev/null +++ b/src/ShaderNode/Widgets/NodeEditor.inl @@ -0,0 +1,16 @@ +#include +#include + +template +void NodeEditor::UpdateContent(QString nodeName, F&& callback) +{ + Clear(); + + m_layout = new QVBoxLayout; + setLayout(m_layout); + + QLabel* label = new QLabel(nodeName); + m_layout->addWidget(label); + + callback(m_layout); +} From d96bc9db6e5531db5492d68f3a8fc34c0d0826a5 Mon Sep 17 00:00:00 2001 From: Lynix Date: Tue, 26 May 2020 20:30:24 +0200 Subject: [PATCH 015/105] ShaderNode: Add automatic variables --- include/Nazara/Renderer/ShaderAst.hpp | 13 +++- include/Nazara/Renderer/ShaderAst.inl | 7 +- include/Nazara/Renderer/ShaderBuilder.hpp | 2 +- include/Nazara/Renderer/ShaderBuilder.inl | 2 +- src/Nazara/Renderer/GlslWriter.cpp | 2 +- src/Nazara/Renderer/ShaderAst.cpp | 23 +++++- src/ShaderNode/DataModels/InputValue.cpp | 7 ++ src/ShaderNode/DataModels/SampleTexture.cpp | 9 +++ src/ShaderNode/ShaderGraph.cpp | 83 +++++++++++++++++++-- src/ShaderNode/ShaderGraph.hpp | 2 + src/ShaderNode/ShaderGraph.inl | 10 +++ src/ShaderNode/main.cpp | 2 - 12 files changed, 143 insertions(+), 19 deletions(-) diff --git a/include/Nazara/Renderer/ShaderAst.hpp b/include/Nazara/Renderer/ShaderAst.hpp index d6cc45789..dfe7639e4 100644 --- a/include/Nazara/Renderer/ShaderAst.hpp +++ b/include/Nazara/Renderer/ShaderAst.hpp @@ -40,6 +40,12 @@ namespace Nz VertexPosition, // gl_Position }; + enum class ExpressionCategory + { + LValue, + RValue + }; + enum class ExpressionType { Boolean, // bool @@ -104,6 +110,7 @@ namespace Nz class NAZARA_RENDERER_API Expression : public Node { public: + virtual ExpressionCategory GetExpressionCategory() const; virtual ExpressionType GetExpressionType() const = 0; }; @@ -152,6 +159,7 @@ namespace Nz public: inline Variable(VariableType varKind, ExpressionType varType); + ExpressionCategory GetExpressionCategory() const override; ExpressionType GetExpressionType() const override; ExpressionType type; @@ -191,14 +199,14 @@ namespace Nz class NAZARA_RENDERER_API AssignOp : public Expression { public: - inline AssignOp(AssignType Op, VariablePtr Var, ExpressionPtr Right); + inline AssignOp(AssignType Op, ExpressionPtr Left, ExpressionPtr Right); ExpressionType GetExpressionType() const override; void Register(ShaderWriter& visitor) override; void Visit(ShaderWriter& visitor) override; AssignType op; - VariablePtr variable; + ExpressionPtr left; ExpressionPtr right; }; @@ -277,6 +285,7 @@ namespace Nz public: inline SwizzleOp(ExpressionPtr expressionPtr, std::initializer_list swizzleComponents); + ExpressionCategory GetExpressionCategory() const override; ExpressionType GetExpressionType() const override; void Register(ShaderWriter& visitor) override; void Visit(ShaderWriter& visitor) override; diff --git a/include/Nazara/Renderer/ShaderAst.inl b/include/Nazara/Renderer/ShaderAst.inl index cb9024b48..b7d0a42d8 100644 --- a/include/Nazara/Renderer/ShaderAst.inl +++ b/include/Nazara/Renderer/ShaderAst.inl @@ -82,11 +82,14 @@ namespace Nz { } - inline AssignOp::AssignOp(AssignType Op, VariablePtr Var, ExpressionPtr Right) : + inline AssignOp::AssignOp(AssignType Op, ExpressionPtr Left, ExpressionPtr Right) : op(Op), - variable(std::move(Var)), + left(std::move(Left)), right(std::move(Right)) { + if (left->GetExpressionCategory() != ExpressionCategory::LValue) + //TODO: AstParseError + throw std::runtime_error("Assignation is only possible with lvalues"); } inline BinaryOp::BinaryOp(BinaryType Op, ExpressionPtr Left, ExpressionPtr Right) : diff --git a/include/Nazara/Renderer/ShaderBuilder.hpp b/include/Nazara/Renderer/ShaderBuilder.hpp index b0ba09cc4..b514b9c57 100644 --- a/include/Nazara/Renderer/ShaderBuilder.hpp +++ b/include/Nazara/Renderer/ShaderBuilder.hpp @@ -18,7 +18,7 @@ namespace Nz { namespace ShaderBuilder { constexpr AssignOpBuilder() {} - std::shared_ptr operator()(const ShaderAst::VariablePtr& left, const ShaderAst::ExpressionPtr& right) const; + std::shared_ptr operator()(const ShaderAst::ExpressionPtr& left, const ShaderAst::ExpressionPtr& right) const; }; template diff --git a/include/Nazara/Renderer/ShaderBuilder.inl b/include/Nazara/Renderer/ShaderBuilder.inl index 89fa14c35..772c56583 100644 --- a/include/Nazara/Renderer/ShaderBuilder.inl +++ b/include/Nazara/Renderer/ShaderBuilder.inl @@ -15,7 +15,7 @@ namespace Nz { namespace ShaderBuilder } template - std::shared_ptr AssignOpBuilder::operator()(const ShaderAst::VariablePtr& left, const ShaderAst::ExpressionPtr& right) const + std::shared_ptr AssignOpBuilder::operator()(const ShaderAst::ExpressionPtr& left, const ShaderAst::ExpressionPtr& right) const { return std::make_shared(op, left, right); } diff --git a/src/Nazara/Renderer/GlslWriter.cpp b/src/Nazara/Renderer/GlslWriter.cpp index 7cb734cc5..685fc64af 100644 --- a/src/Nazara/Renderer/GlslWriter.cpp +++ b/src/Nazara/Renderer/GlslWriter.cpp @@ -139,7 +139,7 @@ namespace Nz void GlslWriter::Write(const ShaderAst::AssignOp& node) { - Write(node.variable); + Write(node.left); switch (node.op) { diff --git a/src/Nazara/Renderer/ShaderAst.cpp b/src/Nazara/Renderer/ShaderAst.cpp index bb64f4475..96dd0c7f3 100644 --- a/src/Nazara/Renderer/ShaderAst.cpp +++ b/src/Nazara/Renderer/ShaderAst.cpp @@ -8,6 +8,11 @@ namespace Nz::ShaderAst { + ExpressionCategory Expression::GetExpressionCategory() const + { + return ExpressionCategory::RValue; + } + void ExpressionStatement::Register(ShaderWriter& visitor) { expression->Register(visitor); @@ -43,6 +48,10 @@ namespace Nz::ShaderAst visitor.Write(*this); } + ExpressionCategory Variable::GetExpressionCategory() const + { + return ExpressionCategory::LValue; + } ExpressionType Variable::GetExpressionType() const { @@ -60,7 +69,7 @@ namespace Nz::ShaderAst } - void BuiltinVariable::Register(ShaderWriter& visitor) + void BuiltinVariable::Register(ShaderWriter& /*visitor*/) { } @@ -72,12 +81,12 @@ namespace Nz::ShaderAst ExpressionType AssignOp::GetExpressionType() const { - return variable->GetExpressionType(); + return left->GetExpressionType(); } void AssignOp::Register(ShaderWriter& visitor) { - variable->Register(visitor); + left->Register(visitor); right->Register(visitor); } @@ -102,6 +111,7 @@ namespace Nz::ShaderAst case ShaderAst::BinaryType::Equality: exprType = ExpressionType::Boolean; + break; } NazaraAssert(exprType != ShaderAst::ExpressionType::Void, "Unhandled builtin"); @@ -178,7 +188,12 @@ namespace Nz::ShaderAst } - ExpressionType ShaderAst::SwizzleOp::GetExpressionType() const + ExpressionCategory SwizzleOp::GetExpressionCategory() const + { + return ExpressionCategory::LValue; + } + + ExpressionType SwizzleOp::GetExpressionType() const { return static_cast(UnderlyingCast(GetComponentType(expression->GetExpressionType())) + componentCount - 1); } diff --git a/src/ShaderNode/DataModels/InputValue.cpp b/src/ShaderNode/DataModels/InputValue.cpp index a6044a229..810c2862e 100644 --- a/src/ShaderNode/DataModels/InputValue.cpp +++ b/src/ShaderNode/DataModels/InputValue.cpp @@ -13,6 +13,13 @@ ShaderNode(graph) UpdatePreview(); }); + if (graph.GetInputCount() > 0) + { + auto& firstInput = graph.GetInput(0); + m_currentInputIndex = 0; + m_currentInputText = firstInput.name; + } + UpdatePreview(); } diff --git a/src/ShaderNode/DataModels/SampleTexture.cpp b/src/ShaderNode/DataModels/SampleTexture.cpp index f299b6009..7209a69b5 100644 --- a/src/ShaderNode/DataModels/SampleTexture.cpp +++ b/src/ShaderNode/DataModels/SampleTexture.cpp @@ -14,6 +14,15 @@ ShaderNode(graph) if (m_currentTextureIndex == textureIndex) UpdatePreview(); }); + + if (graph.GetTextureCount() > 0) + { + auto& firstInput = graph.GetTexture(0); + m_currentTextureIndex = 0; + m_currentTextureText = firstInput.name; + } + + UpdateOutput(); } unsigned int SampleTexture::nPorts(QtNodes::PortType portType) const diff --git a/src/ShaderNode/ShaderGraph.cpp b/src/ShaderNode/ShaderGraph.cpp index bc9d643fd..5bdfe0284 100644 --- a/src/ShaderNode/ShaderGraph.cpp +++ b/src/ShaderNode/ShaderGraph.cpp @@ -40,13 +40,28 @@ m_flowScene(BuildRegistry()) OnSelectedNodeUpdate(this, nullptr); }); - auto& node1 = m_flowScene.createNode(std::make_unique(*this)); - node1.nodeGraphicsObject().setPos(200, 200); + // Test + AddInput("UV", InputType::Float2, InputRole::TexCoord, 0); + AddTexture("Potato", TextureType::Sampler2D); - auto& node2 = m_flowScene.createNode(std::make_unique(*this)); - node2.nodeGraphicsObject().setPos(500, 300); + UpdateTexturePreview(0, QImage(R"(C:\Users\Lynix\Pictures\potatavril.png)")); + + auto& node1 = m_flowScene.createNode(std::make_unique(*this)); + node1.nodeGraphicsObject().setPos(0, 200); + + auto& node2 = m_flowScene.createNode(std::make_unique(*this)); + node2.nodeGraphicsObject().setPos(200, 200); + + auto& node3 = m_flowScene.createNode(std::make_unique(*this)); + node3.nodeGraphicsObject().setPos(400, 200); + + auto& node4 = m_flowScene.createNode(std::make_unique(*this)); + node4.nodeGraphicsObject().setPos(600, 300); m_flowScene.createConnection(node2, 0, node1, 0); + m_flowScene.createConnection(node3, 0, node2, 0); + m_flowScene.createConnection(node3, 1, node2, 0); + m_flowScene.createConnection(node4, 0, node3, 0); } ShaderGraph::~ShaderGraph() @@ -83,13 +98,51 @@ std::size_t ShaderGraph::AddTexture(std::string name, TextureType type) Nz::ShaderAst::StatementPtr ShaderGraph::ToAst() { std::vector statements; + QHash usageCount; + + unsigned int varCount = 0; + + std::function DetectVariables; + DetectVariables = [&](QtNodes::Node* node) + { + ShaderNode* shaderNode = static_cast(node->nodeDataModel()); + + qDebug() << shaderNode->name() << node->id(); + auto it = usageCount.find(node->id()); + if (it == usageCount.end()) + it = usageCount.insert(node->id(), 0); + + (*it)++; + + for (const auto& connectionSet : node->nodeState().getEntries(QtNodes::PortType::In)) + { + for (const auto& [uuid, conn] : connectionSet) + { + DetectVariables(conn->getNode(QtNodes::PortType::Out)); + } + } + }; + + m_flowScene.iterateOverNodes([&](QtNodes::Node* node) + { + if (node->nodeDataModel()->nPorts(QtNodes::PortType::Out) == 0) + DetectVariables(node); + }); + + QHash variableExpressions; std::function HandleNode; HandleNode = [&](QtNodes::Node* node) -> Nz::ShaderAst::ExpressionPtr { ShaderNode* shaderNode = static_cast(node->nodeDataModel()); - qDebug() << shaderNode->name(); + qDebug() << shaderNode->name() << node->id(); + if (auto it = variableExpressions.find(node->id()); it != variableExpressions.end()) + return *it; + + auto it = usageCount.find(node->id()); + assert(it != usageCount.end()); + std::size_t inputCount = shaderNode->nPorts(QtNodes::PortType::In); Nz::StackArray expressions = NazaraStackArray(Nz::ShaderAst::ExpressionPtr, inputCount); std::size_t i = 0; @@ -104,7 +157,25 @@ Nz::ShaderAst::StatementPtr ShaderGraph::ToAst() } } - return shaderNode->GetExpression(expressions.data(), expressions.size()); + auto expression = shaderNode->GetExpression(expressions.data(), expressions.size()); + + if (*it > 1) + { + Nz::ShaderAst::ExpressionPtr varExpression; + if (expression->GetExpressionCategory() == Nz::ShaderAst::ExpressionCategory::RValue) + { + varExpression = Nz::ShaderBuilder::Variable("var" + std::to_string(varCount++), expression->GetExpressionType()); + statements.emplace_back(Nz::ShaderBuilder::ExprStatement(Nz::ShaderBuilder::Assign(varExpression, expression))); + } + else + varExpression = expression; + + variableExpressions.insert(node->id(), varExpression); + + return varExpression; + } + else + return expression; }; m_flowScene.iterateOverNodes([&](QtNodes::Node* node) diff --git a/src/ShaderNode/ShaderGraph.hpp b/src/ShaderNode/ShaderGraph.hpp index 3ed906edd..ca29ff174 100644 --- a/src/ShaderNode/ShaderGraph.hpp +++ b/src/ShaderNode/ShaderGraph.hpp @@ -26,10 +26,12 @@ class ShaderGraph std::size_t AddTexture(std::string name, TextureType type); inline const InputEntry& GetInput(std::size_t inputIndex) const; + inline std::size_t GetInputCount() const; inline const std::vector& GetInputs() const; inline const PreviewModel& GetPreviewModel() const; inline QtNodes::FlowScene& GetScene(); inline const TextureEntry& GetTexture(std::size_t textureIndex) const; + inline std::size_t GetTextureCount() const; inline const std::vector& GetTextures() const; Nz::ShaderAst::StatementPtr ToAst(); diff --git a/src/ShaderNode/ShaderGraph.inl b/src/ShaderNode/ShaderGraph.inl index 100cd822e..97184906e 100644 --- a/src/ShaderNode/ShaderGraph.inl +++ b/src/ShaderNode/ShaderGraph.inl @@ -6,6 +6,11 @@ inline auto ShaderGraph::GetInput(std::size_t inputIndex) const -> const InputEn return m_inputs[inputIndex]; } +inline std::size_t ShaderGraph::GetInputCount() const +{ + return m_inputs.size(); +} + inline auto ShaderGraph::GetInputs() const -> const std::vector& { return m_inputs; @@ -27,6 +32,11 @@ inline auto ShaderGraph::GetTexture(std::size_t textureIndex) const -> const Tex return m_textures[textureIndex]; } +inline std::size_t ShaderGraph::GetTextureCount() const +{ + return m_textures.size(); +} + inline auto ShaderGraph::GetTextures() const -> const std::vector& { return m_textures; diff --git a/src/ShaderNode/main.cpp b/src/ShaderNode/main.cpp index a939e708a..8cea2a20f 100644 --- a/src/ShaderNode/main.cpp +++ b/src/ShaderNode/main.cpp @@ -8,8 +8,6 @@ int main(int argc, char* argv[]) QApplication app(argc, argv); ShaderGraph shaderGraph; - shaderGraph.AddInput("UV", InputType::Float2, InputRole::TexCoord, 0); - shaderGraph.AddTexture("Potato", TextureType::Sampler2D); MainWindow mainWindow(shaderGraph); mainWindow.resize(1280, 720); From 1d033aabfd2fdfc8d0a7a5bf7d4e2eeb585e98ff Mon Sep 17 00:00:00 2001 From: Lynix Date: Wed, 27 May 2020 10:00:52 +0200 Subject: [PATCH 016/105] ShaderNode: Fix useless variables generation --- src/ShaderNode/ShaderGraph.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/ShaderNode/ShaderGraph.cpp b/src/ShaderNode/ShaderGraph.cpp index 5bdfe0284..6abfe5379 100644 --- a/src/ShaderNode/ShaderGraph.cpp +++ b/src/ShaderNode/ShaderGraph.cpp @@ -110,17 +110,19 @@ Nz::ShaderAst::StatementPtr ShaderGraph::ToAst() qDebug() << shaderNode->name() << node->id(); auto it = usageCount.find(node->id()); if (it == usageCount.end()) + { + for (const auto& connectionSet : node->nodeState().getEntries(QtNodes::PortType::In)) + { + for (const auto& [uuid, conn] : connectionSet) + { + DetectVariables(conn->getNode(QtNodes::PortType::Out)); + } + } + it = usageCount.insert(node->id(), 0); + } (*it)++; - - for (const auto& connectionSet : node->nodeState().getEntries(QtNodes::PortType::In)) - { - for (const auto& [uuid, conn] : connectionSet) - { - DetectVariables(conn->getNode(QtNodes::PortType::Out)); - } - } }; m_flowScene.iterateOverNodes([&](QtNodes::Node* node) From 3fc4de26e3d2d5b0a040104fbee52a2ec30c2168 Mon Sep 17 00:00:00 2001 From: Lynix Date: Wed, 27 May 2020 20:08:41 +0200 Subject: [PATCH 017/105] ShaderGraph: Improve GLSL generation by introducing DeclareVariable statement --- include/Nazara/Renderer/GlslWriter.hpp | 2 +- include/Nazara/Renderer/ShaderAst.hpp | 12 ++++++++++ include/Nazara/Renderer/ShaderAst.inl | 6 +++++ include/Nazara/Renderer/ShaderBuilder.hpp | 7 +++--- include/Nazara/Renderer/ShaderBuilder.inl | 2 +- include/Nazara/Renderer/ShaderWriter.hpp | 1 + src/Nazara/Renderer/GlslWriter.cpp | 27 ++++++++++++++--------- src/Nazara/Renderer/ShaderAst.cpp | 13 +++++++++++ src/ShaderNode/ShaderGraph.cpp | 7 +++--- 9 files changed, 59 insertions(+), 18 deletions(-) diff --git a/include/Nazara/Renderer/GlslWriter.hpp b/include/Nazara/Renderer/GlslWriter.hpp index d4042e882..13d7c8459 100644 --- a/include/Nazara/Renderer/GlslWriter.hpp +++ b/include/Nazara/Renderer/GlslWriter.hpp @@ -37,6 +37,7 @@ namespace Nz void Write(const ShaderAst::BuiltinVariable& node) override; void Write(const ShaderAst::Cast& node) override; void Write(const ShaderAst::Constant& node) override; + void Write(const ShaderAst::DeclareVariable& node) override; void Write(const ShaderAst::ExpressionStatement& node) override; void Write(const ShaderAst::NamedVariable& node) override; void Write(const ShaderAst::NodePtr& node) override; @@ -63,7 +64,6 @@ namespace Nz struct Function { - VariableContainer variables; std::vector parameters; ShaderAst::ExpressionType retType; ShaderAst::StatementPtr node; diff --git a/include/Nazara/Renderer/ShaderAst.hpp b/include/Nazara/Renderer/ShaderAst.hpp index dfe7639e4..28b808d6c 100644 --- a/include/Nazara/Renderer/ShaderAst.hpp +++ b/include/Nazara/Renderer/ShaderAst.hpp @@ -193,6 +193,18 @@ namespace Nz Nz::String name; }; + + class NAZARA_RENDERER_API DeclareVariable : public Statement + { + public: + inline DeclareVariable(NamedVariablePtr Variable, ExpressionPtr Expression = nullptr); + + void Register(ShaderWriter& visitor) override; + void Visit(ShaderWriter& visitor) override; + + NamedVariablePtr variable; + ExpressionPtr expression; + }; ////////////////////////////////////////////////////////////////////////// diff --git a/include/Nazara/Renderer/ShaderAst.inl b/include/Nazara/Renderer/ShaderAst.inl index b7d0a42d8..ea9e5cddf 100644 --- a/include/Nazara/Renderer/ShaderAst.inl +++ b/include/Nazara/Renderer/ShaderAst.inl @@ -82,6 +82,12 @@ namespace Nz { } + inline DeclareVariable::DeclareVariable(NamedVariablePtr Variable, ExpressionPtr Expression) : + expression(std::move(Expression)), + variable(std::move(Variable)) + { + } + inline AssignOp::AssignOp(AssignType Op, ExpressionPtr Left, ExpressionPtr Right) : op(Op), left(std::move(Left)), diff --git a/include/Nazara/Renderer/ShaderBuilder.hpp b/include/Nazara/Renderer/ShaderBuilder.hpp index b514b9c57..f8140ab42 100644 --- a/include/Nazara/Renderer/ShaderBuilder.hpp +++ b/include/Nazara/Renderer/ShaderBuilder.hpp @@ -11,7 +11,7 @@ #include #include -namespace Nz { namespace ShaderBuilder +namespace Nz::ShaderBuilder { template struct AssignOpBuilder @@ -49,7 +49,7 @@ namespace Nz { namespace ShaderBuilder { constexpr VarBuilder() {} - template std::shared_ptr operator()(Args&&... args) const; + template ShaderAst::NamedVariablePtr operator()(Args&&... args) const; }; constexpr BinOpBuilder Add; @@ -59,6 +59,7 @@ namespace Nz { namespace ShaderBuilder constexpr GenBuilder Branch; constexpr GenBuilder ConditionalStatement; constexpr GenBuilder Constant; + constexpr GenBuilder DeclareVariable; constexpr BinOpBuilder Divide; constexpr BinOpBuilder Equal; constexpr GenBuilder ExprStatement; @@ -73,7 +74,7 @@ namespace Nz { namespace ShaderBuilder constexpr VarBuilder Variable; template std::shared_ptr Cast(Args&&... args); -} } +} #include diff --git a/include/Nazara/Renderer/ShaderBuilder.inl b/include/Nazara/Renderer/ShaderBuilder.inl index 772c56583..76f00d394 100644 --- a/include/Nazara/Renderer/ShaderBuilder.inl +++ b/include/Nazara/Renderer/ShaderBuilder.inl @@ -44,7 +44,7 @@ namespace Nz { namespace ShaderBuilder template template - std::shared_ptr VarBuilder::operator()(Args&&... args) const + ShaderAst::NamedVariablePtr VarBuilder::operator()(Args&&... args) const { return std::make_shared(type, std::forward(args)...); } diff --git a/include/Nazara/Renderer/ShaderWriter.hpp b/include/Nazara/Renderer/ShaderWriter.hpp index 64dddcf9f..634c335ec 100644 --- a/include/Nazara/Renderer/ShaderWriter.hpp +++ b/include/Nazara/Renderer/ShaderWriter.hpp @@ -38,6 +38,7 @@ namespace Nz virtual void Write(const ShaderAst::BuiltinVariable& node) = 0; virtual void Write(const ShaderAst::Cast& node) = 0; virtual void Write(const ShaderAst::Constant& node) = 0; + virtual void Write(const ShaderAst::DeclareVariable& node) = 0; virtual void Write(const ShaderAst::ExpressionStatement& node) = 0; virtual void Write(const ShaderAst::NamedVariable& node) = 0; virtual void Write(const ShaderAst::NodePtr& node) = 0; diff --git a/src/Nazara/Renderer/GlslWriter.cpp b/src/Nazara/Renderer/GlslWriter.cpp index 685fc64af..73abec55f 100644 --- a/src/Nazara/Renderer/GlslWriter.cpp +++ b/src/Nazara/Renderer/GlslWriter.cpp @@ -66,6 +66,7 @@ namespace Nz switch (kind) { case ShaderAst::VariableType::Builtin: //< Only there to make compiler happy + case ShaderAst::VariableType::Variable: break; case ShaderAst::VariableType::Input: @@ -107,14 +108,6 @@ namespace Nz case ShaderAst::VariableType::Uniform: m_currentState->uniforms.emplace(type, name); break; - - case ShaderAst::VariableType::Variable: - { - if (m_currentFunction) - m_currentFunction->variables.emplace(type, name); - - break; - } } } @@ -262,6 +255,22 @@ namespace Nz } } + void GlslWriter::Write(const ShaderAst::DeclareVariable& node) + { + Append(node.variable->GetExpressionType()); + Append(" "); + Append(node.variable->name); + if (node.expression) + { + Append(" "); + Append("="); + Append(" "); + Write(node.expression); + } + + AppendLine(";"); + } + void GlslWriter::Write(const ShaderAst::ExpressionStatement& node) { Write(node.expression); @@ -404,8 +413,6 @@ namespace Nz EnterScope(); { - DeclareVariables(func.variables); - Write(func.node); } LeaveScope(); diff --git a/src/Nazara/Renderer/ShaderAst.cpp b/src/Nazara/Renderer/ShaderAst.cpp index 96dd0c7f3..0899cbdc7 100644 --- a/src/Nazara/Renderer/ShaderAst.cpp +++ b/src/Nazara/Renderer/ShaderAst.cpp @@ -69,6 +69,19 @@ namespace Nz::ShaderAst } + void DeclareVariable::Register(ShaderWriter& visitor) + { + variable->Register(visitor); + + if (expression) + expression->Register(visitor); + } + + void DeclareVariable::Visit(ShaderWriter& visitor) + { + visitor.Write(*this); + } + void BuiltinVariable::Register(ShaderWriter& /*visitor*/) { } diff --git a/src/ShaderNode/ShaderGraph.cpp b/src/ShaderNode/ShaderGraph.cpp index 6abfe5379..3ddffe365 100644 --- a/src/ShaderNode/ShaderGraph.cpp +++ b/src/ShaderNode/ShaderGraph.cpp @@ -107,7 +107,6 @@ Nz::ShaderAst::StatementPtr ShaderGraph::ToAst() { ShaderNode* shaderNode = static_cast(node->nodeDataModel()); - qDebug() << shaderNode->name() << node->id(); auto it = usageCount.find(node->id()); if (it == usageCount.end()) { @@ -166,8 +165,10 @@ Nz::ShaderAst::StatementPtr ShaderGraph::ToAst() Nz::ShaderAst::ExpressionPtr varExpression; if (expression->GetExpressionCategory() == Nz::ShaderAst::ExpressionCategory::RValue) { - varExpression = Nz::ShaderBuilder::Variable("var" + std::to_string(varCount++), expression->GetExpressionType()); - statements.emplace_back(Nz::ShaderBuilder::ExprStatement(Nz::ShaderBuilder::Assign(varExpression, expression))); + auto variable = Nz::ShaderBuilder::Variable("var" + std::to_string(varCount++), expression->GetExpressionType()); + statements.emplace_back(Nz::ShaderBuilder::DeclareVariable(variable, expression)); + + varExpression = variable; } else varExpression = expression; From 0ec927b82e918a638531e0224459b4a03ff748e3 Mon Sep 17 00:00:00 2001 From: Lynix Date: Thu, 28 May 2020 00:11:16 +0200 Subject: [PATCH 018/105] ShaderNode/NodeEditor: Replace QVBoxLayout by QFormLayout --- src/ShaderNode/DataModels/Cast.hpp | 2 +- src/ShaderNode/DataModels/Cast.inl | 8 ++------ src/ShaderNode/DataModels/InputValue.cpp | 4 ++-- src/ShaderNode/DataModels/InputValue.hpp | 2 +- src/ShaderNode/DataModels/SampleTexture.cpp | 4 ++-- src/ShaderNode/DataModels/SampleTexture.hpp | 2 +- src/ShaderNode/DataModels/ShaderNode.cpp | 10 ++++++---- src/ShaderNode/DataModels/ShaderNode.hpp | 7 +++++-- src/ShaderNode/DataModels/ShaderNode.inl | 9 ++++++++- src/ShaderNode/DataModels/VecValue.hpp | 2 +- src/ShaderNode/DataModels/VecValue.inl | 7 ++----- src/ShaderNode/Widgets/MainWindow.cpp | 2 +- src/ShaderNode/Widgets/NodeEditor.hpp | 4 ++-- src/ShaderNode/Widgets/NodeEditor.inl | 2 +- 14 files changed, 35 insertions(+), 30 deletions(-) diff --git a/src/ShaderNode/DataModels/Cast.hpp b/src/ShaderNode/DataModels/Cast.hpp index 19d6363af..3c90f7e99 100644 --- a/src/ShaderNode/DataModels/Cast.hpp +++ b/src/ShaderNode/DataModels/Cast.hpp @@ -18,7 +18,7 @@ class CastVec : public ShaderNode CastVec(ShaderGraph& graph); ~CastVec() = default; - void BuildNodeEdition(QVBoxLayout* layout) override; + void BuildNodeEdition(QFormLayout* layout) override; Nz::ShaderAst::ExpressionPtr GetExpression(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count) const override; diff --git a/src/ShaderNode/DataModels/Cast.inl b/src/ShaderNode/DataModels/Cast.inl index 5c0600833..bf852a5c0 100644 --- a/src/ShaderNode/DataModels/Cast.inl +++ b/src/ShaderNode/DataModels/Cast.inl @@ -10,14 +10,12 @@ ShaderNode(graph) } template -void CastVec::BuildNodeEdition(QVBoxLayout* layout) +void CastVec::BuildNodeEdition(QFormLayout* layout) { ShaderNode::BuildNodeEdition(layout); if constexpr (ComponentDiff > 0) { - QFormLayout* formLayout = new QFormLayout; - for (std::size_t i = 0; i < ComponentDiff; ++i) { QDoubleSpinBox* spinbox = new QDoubleSpinBox; @@ -30,10 +28,8 @@ void CastVec::BuildNodeEdition(QVBoxLayout* layout) UpdateOutput(); }); - formLayout->addRow(QString::fromUtf8(&s_vectorComponents[FromComponents + i], 1), spinbox); + layout->addRow(QString::fromUtf8(&s_vectorComponents[FromComponents + i], 1), spinbox); } - - layout->addLayout(formLayout); } } diff --git a/src/ShaderNode/DataModels/InputValue.cpp b/src/ShaderNode/DataModels/InputValue.cpp index 810c2862e..9962a101b 100644 --- a/src/ShaderNode/DataModels/InputValue.cpp +++ b/src/ShaderNode/DataModels/InputValue.cpp @@ -64,7 +64,7 @@ void InputValue::OnInputListUpdate() } } -void InputValue::BuildNodeEdition(QVBoxLayout* layout) +void InputValue::BuildNodeEdition(QFormLayout* layout) { ShaderNode::BuildNodeEdition(layout); @@ -83,7 +83,7 @@ void InputValue::BuildNodeEdition(QVBoxLayout* layout) for (const auto& inputEntry : GetGraph().GetInputs()) inputSelection->addItem(QString::fromStdString(inputEntry.name)); - layout->addWidget(inputSelection); + layout->addRow(tr("Input"), inputSelection); } Nz::ShaderAst::ExpressionPtr InputValue::GetExpression(Nz::ShaderAst::ExpressionPtr* /*expressions*/, std::size_t count) const diff --git a/src/ShaderNode/DataModels/InputValue.hpp b/src/ShaderNode/DataModels/InputValue.hpp index 84b7d6393..0170221f5 100644 --- a/src/ShaderNode/DataModels/InputValue.hpp +++ b/src/ShaderNode/DataModels/InputValue.hpp @@ -17,7 +17,7 @@ class InputValue : public ShaderNode InputValue(ShaderGraph& graph); ~InputValue() = default; - void BuildNodeEdition(QVBoxLayout* layout) override; + void BuildNodeEdition(QFormLayout* layout) override; Nz::ShaderAst::ExpressionPtr GetExpression(Nz::ShaderAst::ExpressionPtr* /*expressions*/, std::size_t count) const override; diff --git a/src/ShaderNode/DataModels/SampleTexture.cpp b/src/ShaderNode/DataModels/SampleTexture.cpp index 7209a69b5..2ec25b2be 100644 --- a/src/ShaderNode/DataModels/SampleTexture.cpp +++ b/src/ShaderNode/DataModels/SampleTexture.cpp @@ -112,7 +112,7 @@ bool SampleTexture::ComputePreview(QPixmap& pixmap) return true; } -void SampleTexture::BuildNodeEdition(QVBoxLayout* layout) +void SampleTexture::BuildNodeEdition(QFormLayout* layout) { ShaderNode::BuildNodeEdition(layout); @@ -130,7 +130,7 @@ void SampleTexture::BuildNodeEdition(QVBoxLayout* layout) for (const auto& textureEntry : GetGraph().GetTextures()) textureSelection->addItem(QString::fromStdString(textureEntry.name)); - layout->addWidget(textureSelection); + layout->addRow(tr("Texture"), textureSelection); } Nz::ShaderAst::ExpressionPtr SampleTexture::GetExpression(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count) const diff --git a/src/ShaderNode/DataModels/SampleTexture.hpp b/src/ShaderNode/DataModels/SampleTexture.hpp index 738047712..fc2550f80 100644 --- a/src/ShaderNode/DataModels/SampleTexture.hpp +++ b/src/ShaderNode/DataModels/SampleTexture.hpp @@ -17,7 +17,7 @@ class SampleTexture : public ShaderNode SampleTexture(ShaderGraph& graph); ~SampleTexture() = default; - void BuildNodeEdition(QVBoxLayout* layout) override; + void BuildNodeEdition(QFormLayout* layout) override; Nz::ShaderAst::ExpressionPtr GetExpression(Nz::ShaderAst::ExpressionPtr* /*expressions*/, std::size_t count) const override; diff --git a/src/ShaderNode/DataModels/ShaderNode.cpp b/src/ShaderNode/DataModels/ShaderNode.cpp index 1221d1df6..9daad003b 100644 --- a/src/ShaderNode/DataModels/ShaderNode.cpp +++ b/src/ShaderNode/DataModels/ShaderNode.cpp @@ -1,21 +1,23 @@ #include #include +#include +#include #include -#include ShaderNode::ShaderNode(ShaderGraph& graph) : m_previewSize(64, 64), m_pixmapLabel(nullptr), m_graph(graph), +m_forceVariable(false), m_isPreviewEnabled(false) { m_pixmapLabel = new QLabel; m_pixmapLabel->setStyleSheet("background-color: rgba(0,0,0,0)"); } -void ShaderNode::BuildNodeEdition(QVBoxLayout* layout) +void ShaderNode::BuildNodeEdition(QFormLayout* layout) { - QCheckBox* checkbox = new QCheckBox(tr("Enable preview")); + QCheckBox* checkbox = new QCheckBox; checkbox->setCheckState((m_isPreviewEnabled) ? Qt::Checked : Qt::Unchecked); connect(checkbox, &QCheckBox::stateChanged, [&](int state) @@ -23,7 +25,7 @@ void ShaderNode::BuildNodeEdition(QVBoxLayout* layout) EnablePreview(state == Qt::Checked); }); - layout->addWidget(checkbox); + layout->addRow(tr("Enable preview"), checkbox); } void ShaderNode::EnablePreview(bool enable) diff --git a/src/ShaderNode/DataModels/ShaderNode.hpp b/src/ShaderNode/DataModels/ShaderNode.hpp index 3cf16ea06..6d64c33bd 100644 --- a/src/ShaderNode/DataModels/ShaderNode.hpp +++ b/src/ShaderNode/DataModels/ShaderNode.hpp @@ -10,7 +10,7 @@ #include class QLabel; -class QVBoxLayout; +class QFormLayout; class ShaderGraph; class ShaderNode : public QtNodes::NodeDataModel @@ -18,13 +18,14 @@ class ShaderNode : public QtNodes::NodeDataModel public: ShaderNode(ShaderGraph& graph); - virtual void BuildNodeEdition(QVBoxLayout* layout); + virtual void BuildNodeEdition(QFormLayout* layout); void EnablePreview(bool enable); virtual Nz::ShaderAst::ExpressionPtr GetExpression(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count) const = 0; inline ShaderGraph& GetGraph(); inline const ShaderGraph& GetGraph() const; + inline const std::string& GetVariableName() const; void SetPreviewSize(const Nz::Vector2i& size); @@ -41,7 +42,9 @@ class ShaderNode : public QtNodes::NodeDataModel Nz::Vector2i m_previewSize; QLabel* m_pixmapLabel; std::optional m_pixmap; + std::string m_variableName; ShaderGraph& m_graph; + bool m_forceVariable; bool m_isPreviewEnabled; }; diff --git a/src/ShaderNode/DataModels/ShaderNode.inl b/src/ShaderNode/DataModels/ShaderNode.inl index 7f80d00ff..d1a92bf73 100644 --- a/src/ShaderNode/DataModels/ShaderNode.inl +++ b/src/ShaderNode/DataModels/ShaderNode.inl @@ -1,6 +1,5 @@ #include - inline ShaderGraph& ShaderNode::GetGraph() { return m_graph; @@ -11,9 +10,17 @@ inline const ShaderGraph& ShaderNode::GetGraph() const return m_graph; } +inline const std::string& ShaderNode::GetVariableName() const +{ + return m_variableName; +} + inline void ShaderNode::SetPreviewSize(const Nz::Vector2i& size) { m_previewSize = size; if (m_isPreviewEnabled) + { UpdatePreview(); + embeddedWidgetSizeUpdated(); + } } diff --git a/src/ShaderNode/DataModels/VecValue.hpp b/src/ShaderNode/DataModels/VecValue.hpp index 27df2757f..ad190f8b1 100644 --- a/src/ShaderNode/DataModels/VecValue.hpp +++ b/src/ShaderNode/DataModels/VecValue.hpp @@ -27,7 +27,7 @@ class VecValue : public ShaderNode std::shared_ptr outData(QtNodes::PortIndex port) override; - void BuildNodeEdition(QVBoxLayout* layout) override; + void BuildNodeEdition(QFormLayout* layout) override; Nz::ShaderAst::ExpressionPtr GetExpression(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count) const override; diff --git a/src/ShaderNode/DataModels/VecValue.inl b/src/ShaderNode/DataModels/VecValue.inl index 8f9212631..f576bbb4e 100644 --- a/src/ShaderNode/DataModels/VecValue.inl +++ b/src/ShaderNode/DataModels/VecValue.inl @@ -68,11 +68,10 @@ std::shared_ptr VecValue::outData(QtNodes::PortIndex po } template -void VecValue::BuildNodeEdition(QVBoxLayout* layout) +void VecValue::BuildNodeEdition(QFormLayout* layout) { ShaderNode::BuildNodeEdition(layout); - QFormLayout* formLayout = new QFormLayout; for (std::size_t i = 0; i < ComponentCount; ++i) { QDoubleSpinBox* spinbox = new QDoubleSpinBox; @@ -87,10 +86,8 @@ void VecValue::BuildNodeEdition(QVBoxLayout* layout) UpdatePreview(); }); - formLayout->addRow(QString::fromUtf8(&s_vectorComponents[i], 1), spinbox); + layout->addRow(QString::fromUtf8(&s_vectorComponents[i], 1), spinbox); } - - layout->addLayout(formLayout); } template diff --git a/src/ShaderNode/Widgets/MainWindow.cpp b/src/ShaderNode/Widgets/MainWindow.cpp index 580e5b506..6f3d8a5f4 100644 --- a/src/ShaderNode/Widgets/MainWindow.cpp +++ b/src/ShaderNode/Widgets/MainWindow.cpp @@ -48,7 +48,7 @@ m_shaderGraph(graph) { if (node) { - m_nodeEditor->UpdateContent(node->caption(), [node](QVBoxLayout* layout) + m_nodeEditor->UpdateContent(node->caption(), [node](QFormLayout* layout) { node->BuildNodeEdition(layout); }); diff --git a/src/ShaderNode/Widgets/NodeEditor.hpp b/src/ShaderNode/Widgets/NodeEditor.hpp index 65e73c107..1bdb36c77 100644 --- a/src/ShaderNode/Widgets/NodeEditor.hpp +++ b/src/ShaderNode/Widgets/NodeEditor.hpp @@ -4,7 +4,7 @@ #define NAZARA_SHADERNODES_NODEEDITOR_HPP #include -#include +#include #include #include @@ -19,7 +19,7 @@ class NodeEditor : public QWidget template void UpdateContent(QString nodeName, F&& callback); private: - QVBoxLayout* m_layout; + QFormLayout* m_layout; }; #include diff --git a/src/ShaderNode/Widgets/NodeEditor.inl b/src/ShaderNode/Widgets/NodeEditor.inl index a7f916889..3c26b8fe8 100644 --- a/src/ShaderNode/Widgets/NodeEditor.inl +++ b/src/ShaderNode/Widgets/NodeEditor.inl @@ -6,7 +6,7 @@ void NodeEditor::UpdateContent(QString nodeName, F&& callback) { Clear(); - m_layout = new QVBoxLayout; + m_layout = new QFormLayout; setLayout(m_layout); QLabel* label = new QLabel(nodeName); From bc7ffb6ff3bdf4966d72909efe8e9ab2550a0e7b Mon Sep 17 00:00:00 2001 From: Lynix Date: Thu, 28 May 2020 00:11:34 +0200 Subject: [PATCH 019/105] ShaderNode: Add preview size option --- src/ShaderNode/DataModels/ShaderNode.cpp | 25 ++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/ShaderNode/DataModels/ShaderNode.cpp b/src/ShaderNode/DataModels/ShaderNode.cpp index 9daad003b..62236ddc0 100644 --- a/src/ShaderNode/DataModels/ShaderNode.cpp +++ b/src/ShaderNode/DataModels/ShaderNode.cpp @@ -26,6 +26,31 @@ void ShaderNode::BuildNodeEdition(QFormLayout* layout) }); layout->addRow(tr("Enable preview"), checkbox); + + QComboBox* previewSize = new QComboBox; + + int index = 0; + for (int size : { 32, 64, 128, 256, 512 }) + { + QString sizeStr = QString::number(size); + previewSize->addItem(sizeStr + "x" + sizeStr, size); + + if (m_previewSize.x == size) + previewSize->setCurrentIndex(index); + + index++; + } + + connect(previewSize, qOverload(&QComboBox::currentIndexChanged), [=](int index) + { + if (index < 0) + return; + + int size = previewSize->itemData(index).toInt(); + SetPreviewSize({ size, size }); + }); + + layout->addRow(tr("Preview size"), previewSize); } void ShaderNode::EnablePreview(bool enable) From 6ff670f13feab24ccd1ae52b3686b57685b0d591 Mon Sep 17 00:00:00 2001 From: Lynix Date: Thu, 28 May 2020 10:47:49 +0200 Subject: [PATCH 020/105] ShaderNode: Move VecData to DataTypes folder --- src/ShaderNode/DataModels/Cast.hpp | 3 +-- src/ShaderNode/DataModels/Cast.inl | 2 ++ src/ShaderNode/DataModels/FragmentOutput.cpp | 2 +- src/ShaderNode/DataModels/FragmentOutput.hpp | 2 +- src/ShaderNode/DataModels/InputValue.cpp | 3 ++- src/ShaderNode/DataModels/SampleTexture.cpp | 1 - src/ShaderNode/DataModels/SampleTexture.hpp | 3 +-- src/ShaderNode/DataModels/VecBinOp.hpp | 2 +- src/ShaderNode/DataModels/VecData.cpp | 1 - src/ShaderNode/DataModels/VecValue.hpp | 2 +- src/ShaderNode/DataModels/VecValue.inl | 3 ++- src/ShaderNode/DataTypes/VecData.cpp | 1 + src/ShaderNode/{DataModels => DataTypes}/VecData.hpp | 2 +- src/ShaderNode/{DataModels => DataTypes}/VecData.inl | 2 +- 14 files changed, 15 insertions(+), 14 deletions(-) delete mode 100644 src/ShaderNode/DataModels/VecData.cpp create mode 100644 src/ShaderNode/DataTypes/VecData.cpp rename src/ShaderNode/{DataModels => DataTypes}/VecData.hpp (97%) rename src/ShaderNode/{DataModels => DataTypes}/VecData.inl (73%) diff --git a/src/ShaderNode/DataModels/Cast.hpp b/src/ShaderNode/DataModels/Cast.hpp index 3c90f7e99..c1b63e8e0 100644 --- a/src/ShaderNode/DataModels/Cast.hpp +++ b/src/ShaderNode/DataModels/Cast.hpp @@ -8,8 +8,7 @@ #include #include #include -#include -#include +#include template class CastVec : public ShaderNode diff --git a/src/ShaderNode/DataModels/Cast.inl b/src/ShaderNode/DataModels/Cast.inl index bf852a5c0..56866aa3e 100644 --- a/src/ShaderNode/DataModels/Cast.inl +++ b/src/ShaderNode/DataModels/Cast.inl @@ -1,5 +1,7 @@ #include #include +#include +#include #include template diff --git a/src/ShaderNode/DataModels/FragmentOutput.cpp b/src/ShaderNode/DataModels/FragmentOutput.cpp index bfac47bee..b3938151b 100644 --- a/src/ShaderNode/DataModels/FragmentOutput.cpp +++ b/src/ShaderNode/DataModels/FragmentOutput.cpp @@ -1,6 +1,6 @@ #include #include -#include +#include Nz::ShaderAst::ExpressionPtr FragmentOutput::GetExpression(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count) const { diff --git a/src/ShaderNode/DataModels/FragmentOutput.hpp b/src/ShaderNode/DataModels/FragmentOutput.hpp index c70f39ff6..eb9b18bf9 100644 --- a/src/ShaderNode/DataModels/FragmentOutput.hpp +++ b/src/ShaderNode/DataModels/FragmentOutput.hpp @@ -4,7 +4,7 @@ #define NAZARA_SHADERNODES_FRAGMENTOUTPUT_HPP #include -#include +#include #include #include diff --git a/src/ShaderNode/DataModels/InputValue.cpp b/src/ShaderNode/DataModels/InputValue.cpp index 9962a101b..c36c4a256 100644 --- a/src/ShaderNode/DataModels/InputValue.cpp +++ b/src/ShaderNode/DataModels/InputValue.cpp @@ -1,7 +1,8 @@ #include #include -#include +#include #include +#include InputValue::InputValue(ShaderGraph& graph) : ShaderNode(graph) diff --git a/src/ShaderNode/DataModels/SampleTexture.cpp b/src/ShaderNode/DataModels/SampleTexture.cpp index 2ec25b2be..aa2b9d858 100644 --- a/src/ShaderNode/DataModels/SampleTexture.cpp +++ b/src/ShaderNode/DataModels/SampleTexture.cpp @@ -1,6 +1,5 @@ #include #include -#include #include SampleTexture::SampleTexture(ShaderGraph& graph) : diff --git a/src/ShaderNode/DataModels/SampleTexture.hpp b/src/ShaderNode/DataModels/SampleTexture.hpp index fc2550f80..3b463bb3b 100644 --- a/src/ShaderNode/DataModels/SampleTexture.hpp +++ b/src/ShaderNode/DataModels/SampleTexture.hpp @@ -8,8 +8,7 @@ #include #include #include -#include -#include +#include class SampleTexture : public ShaderNode { diff --git a/src/ShaderNode/DataModels/VecBinOp.hpp b/src/ShaderNode/DataModels/VecBinOp.hpp index e56c13461..6fa8fe875 100644 --- a/src/ShaderNode/DataModels/VecBinOp.hpp +++ b/src/ShaderNode/DataModels/VecBinOp.hpp @@ -4,7 +4,7 @@ #define NAZARA_SHADERNODES_VECBINOP_HPP #include -#include +#include template class VecBinOp : public ShaderNode diff --git a/src/ShaderNode/DataModels/VecData.cpp b/src/ShaderNode/DataModels/VecData.cpp deleted file mode 100644 index 376c8ea5c..000000000 --- a/src/ShaderNode/DataModels/VecData.cpp +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/src/ShaderNode/DataModels/VecValue.hpp b/src/ShaderNode/DataModels/VecValue.hpp index ad190f8b1..50ff1f4e1 100644 --- a/src/ShaderNode/DataModels/VecValue.hpp +++ b/src/ShaderNode/DataModels/VecValue.hpp @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include template diff --git a/src/ShaderNode/DataModels/VecValue.inl b/src/ShaderNode/DataModels/VecValue.inl index f576bbb4e..7f3a9dc5e 100644 --- a/src/ShaderNode/DataModels/VecValue.inl +++ b/src/ShaderNode/DataModels/VecValue.inl @@ -1,6 +1,7 @@ +#include #include #include -#include +#include #include #include diff --git a/src/ShaderNode/DataTypes/VecData.cpp b/src/ShaderNode/DataTypes/VecData.cpp new file mode 100644 index 000000000..0b1f99d61 --- /dev/null +++ b/src/ShaderNode/DataTypes/VecData.cpp @@ -0,0 +1 @@ +#include diff --git a/src/ShaderNode/DataModels/VecData.hpp b/src/ShaderNode/DataTypes/VecData.hpp similarity index 97% rename from src/ShaderNode/DataModels/VecData.hpp rename to src/ShaderNode/DataTypes/VecData.hpp index 3882f20f1..447d37686 100644 --- a/src/ShaderNode/DataModels/VecData.hpp +++ b/src/ShaderNode/DataTypes/VecData.hpp @@ -101,6 +101,6 @@ template using VecType = typename VecTypeHelper::template Type constexpr std::array s_vectorComponents = { 'X', 'Y', 'Z', 'W' }; -#include +#include #endif diff --git a/src/ShaderNode/DataModels/VecData.inl b/src/ShaderNode/DataTypes/VecData.inl similarity index 73% rename from src/ShaderNode/DataModels/VecData.inl rename to src/ShaderNode/DataTypes/VecData.inl index 6c2d0379e..255fbd9ab 100644 --- a/src/ShaderNode/DataModels/VecData.inl +++ b/src/ShaderNode/DataTypes/VecData.inl @@ -1,4 +1,4 @@ -#include +#include inline VecData::VecData() : preview(64, 64, QImage::Format_RGBA8888) From eabb8a630d708dd444274e892c72f4776f0184da Mon Sep 17 00:00:00 2001 From: Lynix Date: Thu, 28 May 2020 10:50:38 +0200 Subject: [PATCH 021/105] ShaderNode: Extract texture from SampleTexture Add TextureData and TextureValue node --- src/ShaderNode/DataModels/SampleTexture.cpp | 150 ++++++++------------ src/ShaderNode/DataModels/SampleTexture.hpp | 10 +- src/ShaderNode/DataModels/TextureValue.cpp | 146 +++++++++++++++++++ src/ShaderNode/DataModels/TextureValue.hpp | 45 ++++++ src/ShaderNode/DataModels/TextureValue.inl | 1 + src/ShaderNode/DataTypes/TextureData.cpp | 1 + src/ShaderNode/DataTypes/TextureData.hpp | 32 +++++ src/ShaderNode/DataTypes/TextureData.inl | 7 + src/ShaderNode/ShaderGraph.cpp | 26 ++-- 9 files changed, 307 insertions(+), 111 deletions(-) create mode 100644 src/ShaderNode/DataModels/TextureValue.cpp create mode 100644 src/ShaderNode/DataModels/TextureValue.hpp create mode 100644 src/ShaderNode/DataModels/TextureValue.inl create mode 100644 src/ShaderNode/DataTypes/TextureData.cpp create mode 100644 src/ShaderNode/DataTypes/TextureData.hpp create mode 100644 src/ShaderNode/DataTypes/TextureData.inl diff --git a/src/ShaderNode/DataModels/SampleTexture.cpp b/src/ShaderNode/DataModels/SampleTexture.cpp index aa2b9d858..e0fa852c3 100644 --- a/src/ShaderNode/DataModels/SampleTexture.cpp +++ b/src/ShaderNode/DataModels/SampleTexture.cpp @@ -7,20 +7,6 @@ ShaderNode(graph) { m_output = std::make_shared(); - m_onTextureListUpdateSlot.Connect(GetGraph().OnTextureListUpdate, [&](ShaderGraph*) { OnTextureListUpdate(); }); - m_onTexturePreviewUpdateSlot.Connect(GetGraph().OnTexturePreviewUpdate, [&](ShaderGraph*, std::size_t textureIndex) - { - if (m_currentTextureIndex == textureIndex) - UpdatePreview(); - }); - - if (graph.GetTextureCount() > 0) - { - auto& firstInput = graph.GetTexture(0); - m_currentTextureIndex = 0; - m_currentTextureText = firstInput.name; - } - UpdateOutput(); } @@ -28,45 +14,28 @@ unsigned int SampleTexture::nPorts(QtNodes::PortType portType) const { switch (portType) { - case QtNodes::PortType::In: return 1; + case QtNodes::PortType::In: return 2; case QtNodes::PortType::Out: return 1; } return 0; } -void SampleTexture::OnTextureListUpdate() -{ - m_currentTextureIndex.reset(); - - std::size_t inputIndex = 0; - for (const auto& textureEntry : GetGraph().GetTextures()) - { - if (textureEntry.name == m_currentTextureText) - { - m_currentTextureIndex = inputIndex; - break; - } - - inputIndex++; - } -} - void SampleTexture::UpdateOutput() { QImage& output = m_output->preview; - if (!m_currentTextureIndex || !m_uv) + if (!m_texture || !m_uv) { output = QImage(1, 1, QImage::Format_RGBA8888); output.fill(QColor::fromRgb(0, 0, 0, 0)); return; } - const auto& textureEntry = GetGraph().GetTexture(*m_currentTextureIndex); + const QImage& texturePreview = m_texture->preview; - int textureWidth = textureEntry.preview.width(); - int textureHeight = textureEntry.preview.height(); + int textureWidth = texturePreview.width(); + int textureHeight = texturePreview.height(); const QImage& uv = m_uv->preview; @@ -77,7 +46,7 @@ void SampleTexture::UpdateOutput() std::uint8_t* outputPtr = output.bits(); const std::uint8_t* uvPtr = uv.constBits(); - const std::uint8_t* texturePtr = textureEntry.preview.constBits(); + const std::uint8_t* texturePtr = texturePreview.constBits(); for (int y = 0; y < uvHeight; ++y) { for (int x = 0; x < uvWidth; ++x) @@ -104,57 +73,21 @@ void SampleTexture::UpdateOutput() bool SampleTexture::ComputePreview(QPixmap& pixmap) { - if (!m_currentTextureIndex || !m_uv) + if (!m_texture || !m_uv) return false; pixmap = QPixmap::fromImage(m_output->preview); return true; } -void SampleTexture::BuildNodeEdition(QFormLayout* layout) -{ - ShaderNode::BuildNodeEdition(layout); - - QComboBox* textureSelection = new QComboBox; - connect(textureSelection, qOverload(&QComboBox::currentIndexChanged), [&](int index) - { - if (index >= 0) - m_currentTextureIndex = static_cast(index); - else - m_currentTextureIndex.reset(); - - UpdateOutput(); - }); - - for (const auto& textureEntry : GetGraph().GetTextures()) - textureSelection->addItem(QString::fromStdString(textureEntry.name)); - - layout->addRow(tr("Texture"), textureSelection); -} - Nz::ShaderAst::ExpressionPtr SampleTexture::GetExpression(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count) const { - if (!m_currentTextureIndex || !m_uv) + if (!m_texture || !m_uv) throw std::runtime_error("invalid inputs"); - assert(count == 1); + assert(count == 2); - const auto& textureEntry = GetGraph().GetTexture(*m_currentTextureIndex); - - Nz::ShaderAst::ExpressionType expression = [&] - { - switch (textureEntry.type) - { - case TextureType::Sampler2D: return Nz::ShaderAst::ExpressionType::Sampler2D; - } - - assert(false); - throw std::runtime_error("Unhandled texture type"); - }(); - - auto sampler = Nz::ShaderBuilder::Uniform(textureEntry.name, expression); - - return Nz::ShaderBuilder::Sample2D(sampler, expressions[0]); + return Nz::ShaderBuilder::Sample2D(expressions[0], expressions[1]); } auto SampleTexture::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const -> QtNodes::NodeDataType @@ -163,8 +96,14 @@ auto SampleTexture::dataType(QtNodes::PortType portType, QtNodes::PortIndex port { case QtNodes::PortType::In: { - assert(portIndex == 0); - return Vec2Data::Type(); + switch (portIndex) + { + case 0: return Texture2Data::Type(); + case 1: return Vec2Data::Type(); + } + + assert(false); + throw std::runtime_error("invalid port index"); } case QtNodes::PortType::Out: @@ -175,7 +114,7 @@ auto SampleTexture::dataType(QtNodes::PortType portType, QtNodes::PortIndex port default: assert(false); - throw std::runtime_error("Invalid PortType"); + throw std::runtime_error("invalid PortType"); } } @@ -185,8 +124,14 @@ QString SampleTexture::portCaption(QtNodes::PortType portType, QtNodes::PortInde { case QtNodes::PortType::In: { - assert(portIndex == 0); - return tr("UV"); + switch (portIndex) + { + case 0: return tr("Texture"); + case 1: return tr("UV"); + } + + assert(false); + throw std::runtime_error("invalid port index"); } case QtNodes::PortType::Out: @@ -210,24 +155,45 @@ std::shared_ptr SampleTexture::outData(QtNodes::PortIndex por { assert(port == 0); - if (!m_currentTextureIndex) - return nullptr; - return m_output; } void SampleTexture::setInData(std::shared_ptr value, int index) { - assert(index == 0); - - if (value) + switch (index) { - assert(dynamic_cast(value.get()) != nullptr); + case 0: + { + if (value) + { + assert(dynamic_cast(value.get()) != nullptr); - m_uv = std::static_pointer_cast(value); + m_texture = std::static_pointer_cast(value); + } + else + m_texture.reset(); + + break; + } + + case 1: + { + if (value) + { + assert(dynamic_cast(value.get()) != nullptr); + + m_uv = std::static_pointer_cast(value); + } + else + m_uv.reset(); + + break; + } + + default: + assert(false); + throw std::runtime_error("Invalid PortType"); } - else - m_uv.reset(); UpdateOutput(); } diff --git a/src/ShaderNode/DataModels/SampleTexture.hpp b/src/ShaderNode/DataModels/SampleTexture.hpp index 3b463bb3b..7a24409d0 100644 --- a/src/ShaderNode/DataModels/SampleTexture.hpp +++ b/src/ShaderNode/DataModels/SampleTexture.hpp @@ -8,6 +8,7 @@ #include #include #include +#include #include class SampleTexture : public ShaderNode @@ -16,8 +17,6 @@ class SampleTexture : public ShaderNode SampleTexture(ShaderGraph& graph); ~SampleTexture() = default; - void BuildNodeEdition(QFormLayout* layout) override; - Nz::ShaderAst::ExpressionPtr GetExpression(Nz::ShaderAst::ExpressionPtr* /*expressions*/, std::size_t count) const override; QString caption() const override { return "Sample texture"; } @@ -37,16 +36,11 @@ class SampleTexture : public ShaderNode protected: bool ComputePreview(QPixmap& pixmap) override; - void OnTextureListUpdate(); void UpdateOutput(); - NazaraSlot(ShaderGraph, OnTextureListUpdate, m_onTextureListUpdateSlot); - NazaraSlot(ShaderGraph, OnTexturePreviewUpdate, m_onTexturePreviewUpdateSlot); - - std::optional m_currentTextureIndex; + std::shared_ptr m_texture; std::shared_ptr m_uv; std::shared_ptr m_output; - std::string m_currentTextureText; }; #include diff --git a/src/ShaderNode/DataModels/TextureValue.cpp b/src/ShaderNode/DataModels/TextureValue.cpp new file mode 100644 index 000000000..57127005b --- /dev/null +++ b/src/ShaderNode/DataModels/TextureValue.cpp @@ -0,0 +1,146 @@ +#include +#include +#include +#include +#include +#include + +TextureValue::TextureValue(ShaderGraph& graph) : +ShaderNode(graph) +{ + m_onTextureListUpdateSlot.Connect(GetGraph().OnTextureListUpdate, [&](ShaderGraph*) { OnTextureListUpdate(); }); + m_onTexturePreviewUpdateSlot.Connect(GetGraph().OnTexturePreviewUpdate, [&](ShaderGraph*, std::size_t textureIndex) + { + if (m_currentTextureIndex == textureIndex) + UpdatePreview(); + }); + + if (graph.GetTextureCount() > 0) + { + auto& firstInput = graph.GetTexture(0); + m_currentTextureIndex = 0; + m_currentTextureText = firstInput.name; + } + + EnablePreview(true); +} + +unsigned int TextureValue::nPorts(QtNodes::PortType portType) const +{ + switch (portType) + { + case QtNodes::PortType::In: return 0; + case QtNodes::PortType::Out: return 1; + } + + return 0; +} + +void TextureValue::OnTextureListUpdate() +{ + m_currentTextureIndex.reset(); + + std::size_t inputIndex = 0; + for (const auto& textureEntry : GetGraph().GetTextures()) + { + if (textureEntry.name == m_currentTextureText) + { + m_currentTextureIndex = inputIndex; + break; + } + + inputIndex++; + } +} + +bool TextureValue::ComputePreview(QPixmap& pixmap) +{ + if (!m_currentTextureIndex) + return false; + + const ShaderGraph& graph = GetGraph(); + const auto& textureEntry = graph.GetTexture(*m_currentTextureIndex); + + pixmap = QPixmap::fromImage(textureEntry.preview); + return true; +} + +void TextureValue::BuildNodeEdition(QFormLayout* layout) +{ + ShaderNode::BuildNodeEdition(layout); + + QComboBox* textureSelection = new QComboBox; + connect(textureSelection, qOverload(&QComboBox::currentIndexChanged), [&](int index) + { + if (index >= 0) + m_currentTextureIndex = static_cast(index); + else + m_currentTextureIndex.reset(); + + UpdatePreview(); + + Q_EMIT dataUpdated(0); + }); + + for (const auto& textureEntry : GetGraph().GetTextures()) + textureSelection->addItem(QString::fromStdString(textureEntry.name)); + + layout->addRow(tr("Texture"), textureSelection); +} + +Nz::ShaderAst::ExpressionPtr TextureValue::GetExpression(Nz::ShaderAst::ExpressionPtr* /*expressions*/, std::size_t count) const +{ + if (!m_currentTextureIndex) + throw std::runtime_error("invalid inputs"); + + assert(count == 0); + + const auto& textureEntry = GetGraph().GetTexture(*m_currentTextureIndex); + + Nz::ShaderAst::ExpressionType expression = [&] + { + switch (textureEntry.type) + { + case TextureType::Sampler2D: return Nz::ShaderAst::ExpressionType::Sampler2D; + } + + assert(false); + throw std::runtime_error("Unhandled texture type"); + }(); + + return Nz::ShaderBuilder::Uniform(textureEntry.name, expression); +} + +auto TextureValue::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const -> QtNodes::NodeDataType +{ + assert(portType == QtNodes::PortType::Out); + assert(portIndex == 0); + + return Vec4Data::Type(); +} + +std::shared_ptr TextureValue::outData(QtNodes::PortIndex port) +{ + assert(port == 0); + + if (!m_currentTextureIndex) + return nullptr; + + const ShaderGraph& graph = GetGraph(); + const auto& textureEntry = graph.GetTexture(*m_currentTextureIndex); + + std::shared_ptr textureData; + + switch (textureEntry.type) + { + case TextureType::Sampler2D: + textureData = std::make_shared(); + break; + } + + assert(textureData); + + textureData->preview = textureEntry.preview; + + return textureData; +} diff --git a/src/ShaderNode/DataModels/TextureValue.hpp b/src/ShaderNode/DataModels/TextureValue.hpp new file mode 100644 index 000000000..27ae9474a --- /dev/null +++ b/src/ShaderNode/DataModels/TextureValue.hpp @@ -0,0 +1,45 @@ +#pragma once + +#ifndef NAZARA_SHADERNODES_TEXTUREVALUE_HPP +#define NAZARA_SHADERNODES_TEXTUREVALUE_HPP + +#include +#include +#include +#include +#include +#include + +class TextureValue : public ShaderNode +{ + public: + TextureValue(ShaderGraph& graph); + ~TextureValue() = default; + + void BuildNodeEdition(QFormLayout* layout) override; + + Nz::ShaderAst::ExpressionPtr GetExpression(Nz::ShaderAst::ExpressionPtr* /*expressions*/, std::size_t count) const override; + + QString caption() const override { return "Texture"; } + QString name() const override { return "Texture"; } + + unsigned int nPorts(QtNodes::PortType portType) const override; + + QtNodes::NodeDataType dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; + + std::shared_ptr outData(QtNodes::PortIndex port) override; + + protected: + bool ComputePreview(QPixmap& pixmap) override; + void OnTextureListUpdate(); + + NazaraSlot(ShaderGraph, OnTextureListUpdate, m_onTextureListUpdateSlot); + NazaraSlot(ShaderGraph, OnTexturePreviewUpdate, m_onTexturePreviewUpdateSlot); + + std::optional m_currentTextureIndex; + std::string m_currentTextureText; +}; + +#include + +#endif diff --git a/src/ShaderNode/DataModels/TextureValue.inl b/src/ShaderNode/DataModels/TextureValue.inl new file mode 100644 index 000000000..f28a64549 --- /dev/null +++ b/src/ShaderNode/DataModels/TextureValue.inl @@ -0,0 +1 @@ +#include diff --git a/src/ShaderNode/DataTypes/TextureData.cpp b/src/ShaderNode/DataTypes/TextureData.cpp new file mode 100644 index 000000000..ad29d24f1 --- /dev/null +++ b/src/ShaderNode/DataTypes/TextureData.cpp @@ -0,0 +1 @@ +#include diff --git a/src/ShaderNode/DataTypes/TextureData.hpp b/src/ShaderNode/DataTypes/TextureData.hpp new file mode 100644 index 000000000..778e66e05 --- /dev/null +++ b/src/ShaderNode/DataTypes/TextureData.hpp @@ -0,0 +1,32 @@ +#pragma once + +#ifndef NAZARA_SHADERNODES_TEXTUREDATA_HPP +#define NAZARA_SHADERNODES_TEXTUREDATA_HPP + +#include +#include +#include + +struct TextureData : public QtNodes::NodeData +{ + inline TextureData(); + + QImage preview; +}; + +struct Texture2Data : public TextureData +{ + QtNodes::NodeDataType type() const override + { + return Type(); + } + + static QtNodes::NodeDataType Type() + { + return { "tex2d", "Texture2D" }; + } +}; + +#include + +#endif diff --git a/src/ShaderNode/DataTypes/TextureData.inl b/src/ShaderNode/DataTypes/TextureData.inl new file mode 100644 index 000000000..e3ae7014f --- /dev/null +++ b/src/ShaderNode/DataTypes/TextureData.inl @@ -0,0 +1,7 @@ +#include + +inline TextureData::TextureData() : +preview(64, 64, QImage::Format_RGBA8888) +{ + preview.fill(QColor::fromRgb(255, 255, 255, 0)); +} diff --git a/src/ShaderNode/ShaderGraph.cpp b/src/ShaderNode/ShaderGraph.cpp index 3ddffe365..6db88c2f0 100644 --- a/src/ShaderNode/ShaderGraph.cpp +++ b/src/ShaderNode/ShaderGraph.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -46,22 +47,26 @@ m_flowScene(BuildRegistry()) UpdateTexturePreview(0, QImage(R"(C:\Users\Lynix\Pictures\potatavril.png)")); - auto& node1 = m_flowScene.createNode(std::make_unique(*this)); + auto& node1 = m_flowScene.createNode(std::make_unique(*this)); node1.nodeGraphicsObject().setPos(0, 200); - auto& node2 = m_flowScene.createNode(std::make_unique(*this)); - node2.nodeGraphicsObject().setPos(200, 200); + auto& node2 = m_flowScene.createNode(std::make_unique(*this)); + node2.nodeGraphicsObject().setPos(50, 350); - auto& node3 = m_flowScene.createNode(std::make_unique(*this)); - node3.nodeGraphicsObject().setPos(400, 200); + auto& node3 = m_flowScene.createNode(std::make_unique(*this)); + node3.nodeGraphicsObject().setPos(200, 200); - auto& node4 = m_flowScene.createNode(std::make_unique(*this)); - node4.nodeGraphicsObject().setPos(600, 300); + auto& node4 = m_flowScene.createNode(std::make_unique(*this)); + node4.nodeGraphicsObject().setPos(400, 200); - m_flowScene.createConnection(node2, 0, node1, 0); - m_flowScene.createConnection(node3, 0, node2, 0); + auto& node5 = m_flowScene.createNode(std::make_unique(*this)); + node5.nodeGraphicsObject().setPos(600, 300); + + m_flowScene.createConnection(node3, 0, node1, 0); m_flowScene.createConnection(node3, 1, node2, 0); m_flowScene.createConnection(node4, 0, node3, 0); + m_flowScene.createConnection(node4, 1, node3, 0); + m_flowScene.createConnection(node5, 0, node4, 0); } ShaderGraph::~ShaderGraph() @@ -105,8 +110,6 @@ Nz::ShaderAst::StatementPtr ShaderGraph::ToAst() std::function DetectVariables; DetectVariables = [&](QtNodes::Node* node) { - ShaderNode* shaderNode = static_cast(node->nodeDataModel()); - auto it = usageCount.find(node->id()); if (it == usageCount.end()) { @@ -226,6 +229,7 @@ std::shared_ptr ShaderGraph::BuildRegistry() RegisterShaderNode(*this, registry, "Outputs"); RegisterShaderNode(*this, registry, "Inputs"); RegisterShaderNode(*this, registry, "Texture"); + RegisterShaderNode(*this, registry, "Texture"); RegisterShaderNode(*this, registry, "Vector operations"); RegisterShaderNode(*this, registry, "Vector operations"); RegisterShaderNode(*this, registry, "Vector operations"); From 0a0dce4109a5a49270d1ed2a2f496e1529d94cab Mon Sep 17 00:00:00 2001 From: Lynix Date: Fri, 29 May 2020 18:22:58 +0200 Subject: [PATCH 022/105] ShaderNode: Add possibility to set variable name (+ force variables) --- src/ShaderNode/DataModels/FragmentOutput.inl | 1 + src/ShaderNode/DataModels/InputValue.cpp | 1 + src/ShaderNode/DataModels/ShaderNode.cpp | 13 +++++++++++- src/ShaderNode/DataModels/ShaderNode.hpp | 7 +++++-- src/ShaderNode/DataModels/ShaderNode.inl | 17 +++++++++++++++ src/ShaderNode/DataModels/TextureValue.cpp | 1 + src/ShaderNode/ShaderGraph.cpp | 22 ++++++++++++++++---- 7 files changed, 55 insertions(+), 7 deletions(-) diff --git a/src/ShaderNode/DataModels/FragmentOutput.inl b/src/ShaderNode/DataModels/FragmentOutput.inl index 24fc6cbf9..5b93f6699 100644 --- a/src/ShaderNode/DataModels/FragmentOutput.inl +++ b/src/ShaderNode/DataModels/FragmentOutput.inl @@ -4,5 +4,6 @@ inline FragmentOutput::FragmentOutput(ShaderGraph& graph) : ShaderNode(graph) { SetPreviewSize({ 128, 128 }); + DisableCustomVariableName(); EnablePreview(true); } diff --git a/src/ShaderNode/DataModels/InputValue.cpp b/src/ShaderNode/DataModels/InputValue.cpp index c36c4a256..fb53ba0a8 100644 --- a/src/ShaderNode/DataModels/InputValue.cpp +++ b/src/ShaderNode/DataModels/InputValue.cpp @@ -21,6 +21,7 @@ ShaderNode(graph) m_currentInputText = firstInput.name; } + DisableCustomVariableName(); UpdatePreview(); } diff --git a/src/ShaderNode/DataModels/ShaderNode.cpp b/src/ShaderNode/DataModels/ShaderNode.cpp index 62236ddc0..b955c3c42 100644 --- a/src/ShaderNode/DataModels/ShaderNode.cpp +++ b/src/ShaderNode/DataModels/ShaderNode.cpp @@ -3,12 +3,13 @@ #include #include #include +#include ShaderNode::ShaderNode(ShaderGraph& graph) : m_previewSize(64, 64), m_pixmapLabel(nullptr), m_graph(graph), -m_forceVariable(false), +m_enableCustomVariableName(true), m_isPreviewEnabled(false) { m_pixmapLabel = new QLabel; @@ -51,6 +52,16 @@ void ShaderNode::BuildNodeEdition(QFormLayout* layout) }); layout->addRow(tr("Preview size"), previewSize); + + if (m_enableCustomVariableName) + { + QLineEdit* lineEdit = new QLineEdit(QString::fromStdString(m_variableName)); + connect(lineEdit, &QLineEdit::textChanged, [&](const QString& text) + { + SetVariableName(text.toStdString()); + }); + layout->addRow(tr("Variable name"), lineEdit); + } } void ShaderNode::EnablePreview(bool enable) diff --git a/src/ShaderNode/DataModels/ShaderNode.hpp b/src/ShaderNode/DataModels/ShaderNode.hpp index 6d64c33bd..9d82851e2 100644 --- a/src/ShaderNode/DataModels/ShaderNode.hpp +++ b/src/ShaderNode/DataModels/ShaderNode.hpp @@ -27,13 +27,16 @@ class ShaderNode : public QtNodes::NodeDataModel inline const ShaderGraph& GetGraph() const; inline const std::string& GetVariableName() const; - void SetPreviewSize(const Nz::Vector2i& size); + inline void SetPreviewSize(const Nz::Vector2i& size); + inline void SetVariableName(std::string variableName); QWidget* embeddedWidget() final; void setInData(std::shared_ptr, int) override; protected: + inline void DisableCustomVariableName(); + inline void EnableCustomVariableName(bool enable = true); void UpdatePreview(); private: @@ -44,7 +47,7 @@ class ShaderNode : public QtNodes::NodeDataModel std::optional m_pixmap; std::string m_variableName; ShaderGraph& m_graph; - bool m_forceVariable; + bool m_enableCustomVariableName; bool m_isPreviewEnabled; }; diff --git a/src/ShaderNode/DataModels/ShaderNode.inl b/src/ShaderNode/DataModels/ShaderNode.inl index d1a92bf73..1fb9bf67a 100644 --- a/src/ShaderNode/DataModels/ShaderNode.inl +++ b/src/ShaderNode/DataModels/ShaderNode.inl @@ -24,3 +24,20 @@ inline void ShaderNode::SetPreviewSize(const Nz::Vector2i& size) embeddedWidgetSizeUpdated(); } } + +inline void ShaderNode::SetVariableName(std::string variableName) +{ + m_variableName = std::move(variableName); +} + +inline void ShaderNode::DisableCustomVariableName() +{ + return EnableCustomVariableName(false); +} + +inline void ShaderNode::EnableCustomVariableName(bool enable) +{ + m_enableCustomVariableName = enable; + if (!m_enableCustomVariableName) + m_variableName.clear(); +} diff --git a/src/ShaderNode/DataModels/TextureValue.cpp b/src/ShaderNode/DataModels/TextureValue.cpp index 57127005b..976ec7dd7 100644 --- a/src/ShaderNode/DataModels/TextureValue.cpp +++ b/src/ShaderNode/DataModels/TextureValue.cpp @@ -22,6 +22,7 @@ ShaderNode(graph) m_currentTextureText = firstInput.name; } + DisableCustomVariableName(); EnablePreview(true); } diff --git a/src/ShaderNode/ShaderGraph.cpp b/src/ShaderNode/ShaderGraph.cpp index 6db88c2f0..1a80b9cbe 100644 --- a/src/ShaderNode/ShaderGraph.cpp +++ b/src/ShaderNode/ShaderGraph.cpp @@ -16,6 +16,7 @@ #include #include #include +#include namespace { @@ -105,8 +106,6 @@ Nz::ShaderAst::StatementPtr ShaderGraph::ToAst() std::vector statements; QHash usageCount; - unsigned int varCount = 0; - std::function DetectVariables; DetectVariables = [&](QtNodes::Node* node) { @@ -135,6 +134,9 @@ Nz::ShaderAst::StatementPtr ShaderGraph::ToAst() QHash variableExpressions; + unsigned int varCount = 0; + std::unordered_set usedVariableNames; + std::function HandleNode; HandleNode = [&](QtNodes::Node* node) -> Nz::ShaderAst::ExpressionPtr { @@ -163,12 +165,24 @@ Nz::ShaderAst::StatementPtr ShaderGraph::ToAst() auto expression = shaderNode->GetExpression(expressions.data(), expressions.size()); - if (*it > 1) + const std::string& variableName = shaderNode->GetVariableName(); + if (*it > 1 || !variableName.empty()) { Nz::ShaderAst::ExpressionPtr varExpression; if (expression->GetExpressionCategory() == Nz::ShaderAst::ExpressionCategory::RValue) { - auto variable = Nz::ShaderBuilder::Variable("var" + std::to_string(varCount++), expression->GetExpressionType()); + std::string name; + if (variableName.empty()) + name = "var" + std::to_string(varCount++); + else + name = variableName; + + if (usedVariableNames.find(name) != usedVariableNames.end()) + throw std::runtime_error("duplicate variable found: " + name); + + usedVariableNames.insert(name); + + auto variable = Nz::ShaderBuilder::Variable(std::move(name), expression->GetExpressionType()); statements.emplace_back(Nz::ShaderBuilder::DeclareVariable(variable, expression)); varExpression = variable; From 2ecc624fe4fcccc1eb0def852f2d80e50ac741ee Mon Sep 17 00:00:00 2001 From: Lynix Date: Sat, 30 May 2020 14:31:11 +0200 Subject: [PATCH 023/105] ShaderNode: Add custom output support --- src/ShaderNode/DataModels/FragmentOutput.cpp | 62 ------- src/ShaderNode/DataModels/FragmentOutput.inl | 9 - src/ShaderNode/DataModels/InputValue.cpp | 22 +-- src/ShaderNode/DataModels/OutputValue.cpp | 160 ++++++++++++++++++ .../{FragmentOutput.hpp => OutputValue.hpp} | 25 ++- src/ShaderNode/DataModels/OutputValue.inl | 1 + src/ShaderNode/DataModels/ShaderNode.hpp | 3 +- src/ShaderNode/DataModels/ShaderNode.inl | 5 + src/ShaderNode/Enums.cpp | 12 +- src/ShaderNode/Enums.hpp | 6 +- src/ShaderNode/ShaderGraph.cpp | 53 ++++-- src/ShaderNode/ShaderGraph.hpp | 21 ++- src/ShaderNode/ShaderGraph.inl | 16 ++ src/ShaderNode/Widgets/InputEditDialog.cpp | 6 +- src/ShaderNode/Widgets/InputEditDialog.hpp | 2 +- src/ShaderNode/Widgets/MainWindow.cpp | 13 ++ src/ShaderNode/Widgets/OutputEditDialog.cpp | 67 ++++++++ src/ShaderNode/Widgets/OutputEditDialog.hpp | 36 ++++ src/ShaderNode/Widgets/OutputEditDialog.inl | 1 + src/ShaderNode/Widgets/OutputEditor.cpp | 95 +++++++++++ src/ShaderNode/Widgets/OutputEditor.hpp | 39 +++++ src/ShaderNode/Widgets/OutputEditor.inl | 1 + 22 files changed, 537 insertions(+), 118 deletions(-) delete mode 100644 src/ShaderNode/DataModels/FragmentOutput.cpp delete mode 100644 src/ShaderNode/DataModels/FragmentOutput.inl create mode 100644 src/ShaderNode/DataModels/OutputValue.cpp rename src/ShaderNode/DataModels/{FragmentOutput.hpp => OutputValue.hpp} (54%) create mode 100644 src/ShaderNode/DataModels/OutputValue.inl create mode 100644 src/ShaderNode/Widgets/OutputEditDialog.cpp create mode 100644 src/ShaderNode/Widgets/OutputEditDialog.hpp create mode 100644 src/ShaderNode/Widgets/OutputEditDialog.inl create mode 100644 src/ShaderNode/Widgets/OutputEditor.cpp create mode 100644 src/ShaderNode/Widgets/OutputEditor.hpp create mode 100644 src/ShaderNode/Widgets/OutputEditor.inl diff --git a/src/ShaderNode/DataModels/FragmentOutput.cpp b/src/ShaderNode/DataModels/FragmentOutput.cpp deleted file mode 100644 index b3938151b..000000000 --- a/src/ShaderNode/DataModels/FragmentOutput.cpp +++ /dev/null @@ -1,62 +0,0 @@ -#include -#include -#include - -Nz::ShaderAst::ExpressionPtr FragmentOutput::GetExpression(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count) const -{ - using namespace Nz::ShaderAst; - using namespace Nz::ShaderBuilder; - - assert(count == 1); - - auto output = Nz::ShaderBuilder::Output("RenderTarget0", ExpressionType::Float4); - - return Nz::ShaderBuilder::Assign(output, *expressions); -} - -QtNodes::NodeDataType FragmentOutput::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const -{ - assert(portType == QtNodes::PortType::In); - assert(portIndex == 0); - - return Vec4Data::Type(); -} - -unsigned int FragmentOutput::nPorts(QtNodes::PortType portType) const -{ - switch (portType) - { - case QtNodes::PortType::In: return 1; - case QtNodes::PortType::Out: return 0; - } - - return 0; -} - -std::shared_ptr FragmentOutput::outData(QtNodes::PortIndex /*port*/) -{ - return {}; -} - -void FragmentOutput::setInData(std::shared_ptr value, int index) -{ - assert(index == 0); - if (value) - { - assert(dynamic_cast(value.get()) != nullptr); - m_input = std::static_pointer_cast(value); - } - else - m_input.reset(); - - UpdatePreview(); -} - -bool FragmentOutput::ComputePreview(QPixmap& pixmap) -{ - if (!m_input) - return false; - - pixmap = QPixmap::fromImage(m_input->preview); - return true; -} diff --git a/src/ShaderNode/DataModels/FragmentOutput.inl b/src/ShaderNode/DataModels/FragmentOutput.inl deleted file mode 100644 index 5b93f6699..000000000 --- a/src/ShaderNode/DataModels/FragmentOutput.inl +++ /dev/null @@ -1,9 +0,0 @@ -#include - -inline FragmentOutput::FragmentOutput(ShaderGraph& graph) : -ShaderNode(graph) -{ - SetPreviewSize({ 128, 128 }); - DisableCustomVariableName(); - EnablePreview(true); -} diff --git a/src/ShaderNode/DataModels/InputValue.cpp b/src/ShaderNode/DataModels/InputValue.cpp index fb53ba0a8..9ff7fd207 100644 --- a/src/ShaderNode/DataModels/InputValue.cpp +++ b/src/ShaderNode/DataModels/InputValue.cpp @@ -101,11 +101,11 @@ Nz::ShaderAst::ExpressionPtr InputValue::GetExpression(Nz::ShaderAst::Expression { switch (inputEntry.type) { - case InputType::Bool: return Nz::ShaderAst::ExpressionType::Boolean; - case InputType::Float1: return Nz::ShaderAst::ExpressionType::Float1; - case InputType::Float2: return Nz::ShaderAst::ExpressionType::Float2; - case InputType::Float3: return Nz::ShaderAst::ExpressionType::Float3; - case InputType::Float4: return Nz::ShaderAst::ExpressionType::Float4; + case InOutType::Bool: return Nz::ShaderAst::ExpressionType::Boolean; + case InOutType::Float1: return Nz::ShaderAst::ExpressionType::Float1; + case InOutType::Float2: return Nz::ShaderAst::ExpressionType::Float2; + case InOutType::Float3: return Nz::ShaderAst::ExpressionType::Float3; + case InOutType::Float4: return Nz::ShaderAst::ExpressionType::Float4; } assert(false); @@ -117,20 +117,20 @@ Nz::ShaderAst::ExpressionPtr InputValue::GetExpression(Nz::ShaderAst::Expression auto InputValue::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const -> QtNodes::NodeDataType { - if (!m_currentInputIndex) - return Vec4Data::Type(); - assert(portType == QtNodes::PortType::Out); assert(portIndex == 0); + if (!m_currentInputIndex) + return Vec4Data::Type(); + const auto& inputEntry = GetGraph().GetInput(*m_currentInputIndex); switch (inputEntry.type) { //case InputType::Bool: return Nz::ShaderAst::ExpressionType::Boolean; //case InputType::Float1: return Nz::ShaderAst::ExpressionType::Float1; - case InputType::Float2: return Vec2Data::Type(); - case InputType::Float3: return Vec3Data::Type(); - case InputType::Float4: return Vec4Data::Type(); + case InOutType::Float2: return Vec2Data::Type(); + case InOutType::Float3: return Vec3Data::Type(); + case InOutType::Float4: return Vec4Data::Type(); } assert(false); diff --git a/src/ShaderNode/DataModels/OutputValue.cpp b/src/ShaderNode/DataModels/OutputValue.cpp new file mode 100644 index 000000000..2d3a8dc14 --- /dev/null +++ b/src/ShaderNode/DataModels/OutputValue.cpp @@ -0,0 +1,160 @@ +#include +#include +#include +#include +#include +#include + +OutputValue::OutputValue(ShaderGraph& graph) : +ShaderNode(graph) +{ + m_onOutputListUpdateSlot.Connect(GetGraph().OnOutputListUpdate, [&](ShaderGraph*) { OnOutputListUpdate(); }); + m_onOutputUpdateSlot.Connect(GetGraph().OnOutputUpdate, [&](ShaderGraph*, std::size_t inputIndex) + { + if (m_currentOutputIndex == inputIndex) + UpdatePreview(); + }); + + if (graph.GetOutputCount() > 0) + { + auto& firstOutput = graph.GetOutput(0); + m_currentOutputIndex = 0; + m_currentOutputText = firstOutput.name; + } + + EnablePreview(); + SetPreviewSize({ 128, 128 }); + DisableCustomVariableName(); +} + +void OutputValue::BuildNodeEdition(QFormLayout* layout) +{ + ShaderNode::BuildNodeEdition(layout); + + QComboBox* outputSelection = new QComboBox; + + connect(outputSelection, qOverload(&QComboBox::currentIndexChanged), [&](int index) + { + if (index >= 0) + m_currentOutputIndex = static_cast(index); + else + m_currentOutputIndex.reset(); + + UpdatePreview(); + }); + + for (const auto& outputEntry : GetGraph().GetOutputs()) + outputSelection->addItem(QString::fromStdString(outputEntry.name)); + + layout->addRow(tr("Output"), outputSelection); +} + +Nz::ShaderAst::ExpressionPtr OutputValue::GetExpression(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count) const +{ + using namespace Nz::ShaderAst; + using namespace Nz::ShaderBuilder; + + assert(count == 1); + + if (!m_currentOutputIndex) + throw std::runtime_error("no output"); + + const auto& outputEntry = GetGraph().GetOutput(*m_currentOutputIndex); + + Nz::ShaderAst::ExpressionType expression = [&] + { + switch (outputEntry.type) + { + case InOutType::Bool: return Nz::ShaderAst::ExpressionType::Boolean; + case InOutType::Float1: return Nz::ShaderAst::ExpressionType::Float1; + case InOutType::Float2: return Nz::ShaderAst::ExpressionType::Float2; + case InOutType::Float3: return Nz::ShaderAst::ExpressionType::Float3; + case InOutType::Float4: return Nz::ShaderAst::ExpressionType::Float4; + } + + assert(false); + throw std::runtime_error("Unhandled output type"); + }(); + + auto output = Nz::ShaderBuilder::Output(outputEntry.name, expression); + + return Nz::ShaderBuilder::Assign(std::move(output), *expressions); +} + +QtNodes::NodeDataType OutputValue::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const +{ + assert(portType == QtNodes::PortType::In); + assert(portIndex == 0); + + if (!m_currentOutputIndex) + return Vec4Data::Type(); + + const auto& outputEntry = GetGraph().GetOutput(*m_currentOutputIndex); + switch (outputEntry.type) + { + //case InOutType::Bool: return Nz::ShaderAst::ExpressionType::Boolean; + //case InOutType::Float1: return Nz::ShaderAst::ExpressionType::Float1; + case InOutType::Float2: return Vec2Data::Type(); + case InOutType::Float3: return Vec3Data::Type(); + case InOutType::Float4: return Vec4Data::Type(); + } + + assert(false); + throw std::runtime_error("Unhandled output type"); +} + +unsigned int OutputValue::nPorts(QtNodes::PortType portType) const +{ + switch (portType) + { + case QtNodes::PortType::In: return 1; + case QtNodes::PortType::Out: return 0; + } + + return 0; +} + +std::shared_ptr OutputValue::outData(QtNodes::PortIndex /*port*/) +{ + return {}; +} + +void OutputValue::setInData(std::shared_ptr value, int index) +{ + assert(index == 0); + if (value) + { + assert(dynamic_cast(value.get()) != nullptr); + m_input = std::static_pointer_cast(value); + } + else + m_input.reset(); + + UpdatePreview(); +} + +bool OutputValue::ComputePreview(QPixmap& pixmap) +{ + if (!m_input) + return false; + + pixmap = QPixmap::fromImage(m_input->preview); + return true; +} + +void OutputValue::OnOutputListUpdate() +{ + m_currentOutputIndex.reset(); + + std::size_t inputIndex = 0; + for (const auto& inputEntry : GetGraph().GetOutputs()) + { + if (inputEntry.name == m_currentOutputText) + { + m_currentOutputIndex = inputIndex; + break; + } + + inputIndex++; + } +} diff --git a/src/ShaderNode/DataModels/FragmentOutput.hpp b/src/ShaderNode/DataModels/OutputValue.hpp similarity index 54% rename from src/ShaderNode/DataModels/FragmentOutput.hpp rename to src/ShaderNode/DataModels/OutputValue.hpp index eb9b18bf9..8db611056 100644 --- a/src/ShaderNode/DataModels/FragmentOutput.hpp +++ b/src/ShaderNode/DataModels/OutputValue.hpp @@ -3,20 +3,23 @@ #ifndef NAZARA_SHADERNODES_FRAGMENTOUTPUT_HPP #define NAZARA_SHADERNODES_FRAGMENTOUTPUT_HPP +#include #include #include -#include -#include -class FragmentOutput : public ShaderNode +class QFormLayout; + +class OutputValue : public ShaderNode { public: - inline FragmentOutput(ShaderGraph& graph); + OutputValue(ShaderGraph& graph); + + void BuildNodeEdition(QFormLayout* layout) override; Nz::ShaderAst::ExpressionPtr GetExpression(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count) const override; - QString caption() const override { return "Fragment shader output"; } - QString name() const override { return "FragmentShaderOutput"; } + QString caption() const override { return "Output"; } + QString name() const override { return "Output"; } QtNodes::NodeDataType dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; @@ -28,10 +31,16 @@ class FragmentOutput : public ShaderNode private: bool ComputePreview(QPixmap& pixmap) override; + void OnOutputListUpdate(); - std::shared_ptr m_input; + NazaraSlot(ShaderGraph, OnOutputListUpdate, m_onOutputListUpdateSlot); + NazaraSlot(ShaderGraph, OnOutputUpdate, m_onOutputUpdateSlot); + + std::optional m_currentOutputIndex; + std::shared_ptr m_input; + std::string m_currentOutputText; }; -#include +#include #endif diff --git a/src/ShaderNode/DataModels/OutputValue.inl b/src/ShaderNode/DataModels/OutputValue.inl new file mode 100644 index 000000000..585e40a7f --- /dev/null +++ b/src/ShaderNode/DataModels/OutputValue.inl @@ -0,0 +1 @@ +#include diff --git a/src/ShaderNode/DataModels/ShaderNode.hpp b/src/ShaderNode/DataModels/ShaderNode.hpp index 9d82851e2..91f6dc0d3 100644 --- a/src/ShaderNode/DataModels/ShaderNode.hpp +++ b/src/ShaderNode/DataModels/ShaderNode.hpp @@ -20,7 +20,8 @@ class ShaderNode : public QtNodes::NodeDataModel virtual void BuildNodeEdition(QFormLayout* layout); - void EnablePreview(bool enable); + inline void DisablePreview(); + void EnablePreview(bool enable = true); virtual Nz::ShaderAst::ExpressionPtr GetExpression(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count) const = 0; inline ShaderGraph& GetGraph(); diff --git a/src/ShaderNode/DataModels/ShaderNode.inl b/src/ShaderNode/DataModels/ShaderNode.inl index 1fb9bf67a..558a86165 100644 --- a/src/ShaderNode/DataModels/ShaderNode.inl +++ b/src/ShaderNode/DataModels/ShaderNode.inl @@ -1,5 +1,10 @@ #include +inline void ShaderNode::DisablePreview() +{ + return EnablePreview(false); +} + inline ShaderGraph& ShaderNode::GetGraph() { return m_graph; diff --git a/src/ShaderNode/Enums.cpp b/src/ShaderNode/Enums.cpp index 22f21c972..fd99c5562 100644 --- a/src/ShaderNode/Enums.cpp +++ b/src/ShaderNode/Enums.cpp @@ -15,15 +15,15 @@ const char* EnumToString(InputRole role) return ""; } -const char* EnumToString(InputType input) +const char* EnumToString(InOutType input) { switch (input) { - case InputType::Bool: return "Bool"; - case InputType::Float1: return "Float"; - case InputType::Float2: return "Float2"; - case InputType::Float3: return "Float3"; - case InputType::Float4: return "Float4"; + case InOutType::Bool: return "Bool"; + case InOutType::Float1: return "Float"; + case InOutType::Float2: return "Float2"; + case InOutType::Float3: return "Float3"; + case InOutType::Float4: return "Float4"; } assert(false); diff --git a/src/ShaderNode/Enums.hpp b/src/ShaderNode/Enums.hpp index b8e944c5c..ba990fdcf 100644 --- a/src/ShaderNode/Enums.hpp +++ b/src/ShaderNode/Enums.hpp @@ -17,7 +17,7 @@ enum class InputRole constexpr std::size_t InputRoleCount = static_cast(InputRole::Max) + 1; -enum class InputType +enum class InOutType { Bool, Float1, @@ -28,7 +28,7 @@ enum class InputType Max = Float4 }; -constexpr std::size_t InputTypeCount = static_cast(InputType::Max) + 1; +constexpr std::size_t InOutTypeCount = static_cast(InOutType::Max) + 1; enum class TextureType { @@ -40,7 +40,7 @@ enum class TextureType constexpr std::size_t TextureTypeCount = static_cast(TextureType::Max) + 1; const char* EnumToString(InputRole role); -const char* EnumToString(InputType input); +const char* EnumToString(InOutType input); const char* EnumToString(TextureType textureType); #include diff --git a/src/ShaderNode/ShaderGraph.cpp b/src/ShaderNode/ShaderGraph.cpp index 1a80b9cbe..876b0f1a3 100644 --- a/src/ShaderNode/ShaderGraph.cpp +++ b/src/ShaderNode/ShaderGraph.cpp @@ -1,8 +1,8 @@ #include #include #include -#include #include +#include #include #include #include @@ -43,7 +43,8 @@ m_flowScene(BuildRegistry()) }); // Test - AddInput("UV", InputType::Float2, InputRole::TexCoord, 0); + AddInput("UV", InOutType::Float2, InputRole::TexCoord, 0); + AddOutput("RenderTarget0", InOutType::Float4); AddTexture("Potato", TextureType::Sampler2D); UpdateTexturePreview(0, QImage(R"(C:\Users\Lynix\Pictures\potatavril.png)")); @@ -60,7 +61,7 @@ m_flowScene(BuildRegistry()) auto& node4 = m_flowScene.createNode(std::make_unique(*this)); node4.nodeGraphicsObject().setPos(400, 200); - auto& node5 = m_flowScene.createNode(std::make_unique(*this)); + auto& node5 = m_flowScene.createNode(std::make_unique(*this)); node5.nodeGraphicsObject().setPos(600, 300); m_flowScene.createConnection(node3, 0, node1, 0); @@ -75,7 +76,7 @@ ShaderGraph::~ShaderGraph() m_flowScene.clearScene(); } -std::size_t ShaderGraph::AddInput(std::string name, InputType type, InputRole role, std::size_t roleIndex) +std::size_t ShaderGraph::AddInput(std::string name, InOutType type, InputRole role, std::size_t roleIndex) { std::size_t index = m_inputs.size(); auto& inputEntry = m_inputs.emplace_back(); @@ -89,6 +90,18 @@ std::size_t ShaderGraph::AddInput(std::string name, InputType type, InputRole ro return index; } +std::size_t ShaderGraph::AddOutput(std::string name, InOutType type) +{ + std::size_t index = m_outputs.size(); + auto& outputEntry = m_outputs.emplace_back(); + outputEntry.name = std::move(name); + outputEntry.type = type; + + OnOutputListUpdate(this); + + return index; +} + std::size_t ShaderGraph::AddTexture(std::string name, TextureType type) { std::size_t index = m_textures.size(); @@ -198,18 +211,26 @@ Nz::ShaderAst::StatementPtr ShaderGraph::ToAst() return expression; }; - m_flowScene.iterateOverNodes([&](QtNodes::Node* node) + try { - if (node->nodeDataModel()->nPorts(QtNodes::PortType::Out) == 0) + m_flowScene.iterateOverNodes([&](QtNodes::Node* node) { - statements.emplace_back(Nz::ShaderBuilder::ExprStatement(HandleNode(node))); - } - }); + if (node->nodeDataModel()->nPorts(QtNodes::PortType::Out) == 0) + { + statements.emplace_back(Nz::ShaderBuilder::ExprStatement(HandleNode(node))); + } + }); + } + catch (const std::exception&) + { + + return nullptr; + } return std::make_shared(std::move(statements)); } -void ShaderGraph::UpdateInput(std::size_t inputIndex, std::string name, InputType type, InputRole role, std::size_t roleIndex) +void ShaderGraph::UpdateInput(std::size_t inputIndex, std::string name, InOutType type, InputRole role, std::size_t roleIndex) { assert(inputIndex < m_inputs.size()); auto& inputEntry = m_inputs[inputIndex]; @@ -221,6 +242,16 @@ void ShaderGraph::UpdateInput(std::size_t inputIndex, std::string name, InputTyp OnInputUpdate(this, inputIndex); } +void ShaderGraph::UpdateOutput(std::size_t outputIndex, std::string name, InOutType type) +{ + assert(outputIndex < m_outputs.size()); + auto& outputEntry = m_outputs[outputIndex]; + outputEntry.name = std::move(name); + outputEntry.type = type; + + OnOutputUpdate(this, outputIndex); +} + void ShaderGraph::UpdateTexturePreview(std::size_t textureIndex, QImage preview) { assert(textureIndex < m_textures.size()); @@ -240,8 +271,8 @@ std::shared_ptr ShaderGraph::BuildRegistry() RegisterShaderNode(*this, registry, "Casts"); RegisterShaderNode(*this, registry, "Casts"); RegisterShaderNode(*this, registry, "Casts"); - RegisterShaderNode(*this, registry, "Outputs"); RegisterShaderNode(*this, registry, "Inputs"); + RegisterShaderNode(*this, registry, "Outputs"); RegisterShaderNode(*this, registry, "Texture"); RegisterShaderNode(*this, registry, "Texture"); RegisterShaderNode(*this, registry, "Vector operations"); diff --git a/src/ShaderNode/ShaderGraph.hpp b/src/ShaderNode/ShaderGraph.hpp index ca29ff174..854d5cfb7 100644 --- a/src/ShaderNode/ShaderGraph.hpp +++ b/src/ShaderNode/ShaderGraph.hpp @@ -17,17 +17,22 @@ class ShaderGraph { public: struct InputEntry; + struct OutputEntry; struct TextureEntry; ShaderGraph(); ~ShaderGraph(); - std::size_t AddInput(std::string name, InputType type, InputRole role, std::size_t roleIndex); + std::size_t AddInput(std::string name, InOutType type, InputRole role, std::size_t roleIndex); + std::size_t AddOutput(std::string name, InOutType type); std::size_t AddTexture(std::string name, TextureType type); inline const InputEntry& GetInput(std::size_t inputIndex) const; inline std::size_t GetInputCount() const; inline const std::vector& GetInputs() const; + inline const OutputEntry& GetOutput(std::size_t outputIndex) const; + inline std::size_t GetOutputCount() const; + inline const std::vector& GetOutputs() const; inline const PreviewModel& GetPreviewModel() const; inline QtNodes::FlowScene& GetScene(); inline const TextureEntry& GetTexture(std::size_t textureIndex) const; @@ -36,7 +41,8 @@ class ShaderGraph Nz::ShaderAst::StatementPtr ToAst(); - void UpdateInput(std::size_t inputIndex, std::string name, InputType type, InputRole role, std::size_t roleIndex); + void UpdateInput(std::size_t inputIndex, std::string name, InOutType type, InputRole role, std::size_t roleIndex); + void UpdateOutput(std::size_t outputIndex, std::string name, InOutType type); void UpdateTexturePreview(std::size_t texture, QImage preview); struct InputEntry @@ -44,7 +50,13 @@ class ShaderGraph std::size_t roleIndex; std::string name; InputRole role; - InputType type; + InOutType type; + }; + + struct OutputEntry + { + std::string name; + InOutType type; }; struct TextureEntry @@ -56,6 +68,8 @@ class ShaderGraph NazaraSignal(OnInputListUpdate, ShaderGraph*); NazaraSignal(OnInputUpdate, ShaderGraph*, std::size_t /*inputIndex*/); + NazaraSignal(OnOutputListUpdate, ShaderGraph*); + NazaraSignal(OnOutputUpdate, ShaderGraph*, std::size_t /*outputIndex*/); NazaraSignal(OnSelectedNodeUpdate, ShaderGraph*, ShaderNode* /*node*/); NazaraSignal(OnTextureListUpdate, ShaderGraph*); NazaraSignal(OnTexturePreviewUpdate, ShaderGraph*, std::size_t /*textureIndex*/); @@ -65,6 +79,7 @@ class ShaderGraph QtNodes::FlowScene m_flowScene; std::vector m_inputs; + std::vector m_outputs; std::vector m_textures; std::unique_ptr m_previewModel; }; diff --git a/src/ShaderNode/ShaderGraph.inl b/src/ShaderNode/ShaderGraph.inl index 97184906e..3f839534c 100644 --- a/src/ShaderNode/ShaderGraph.inl +++ b/src/ShaderNode/ShaderGraph.inl @@ -16,6 +16,22 @@ inline auto ShaderGraph::GetInputs() const -> const std::vector& return m_inputs; } +inline auto ShaderGraph::GetOutput(std::size_t outputIndex) const -> const OutputEntry& +{ + assert(outputIndex < m_outputs.size()); + return m_outputs[outputIndex]; +} + +inline std::size_t ShaderGraph::GetOutputCount() const +{ + return m_outputs.size(); +} + +inline auto ShaderGraph::GetOutputs() const -> const std::vector& +{ + return m_outputs; +} + inline const PreviewModel& ShaderGraph::GetPreviewModel() const { return *m_previewModel; diff --git a/src/ShaderNode/Widgets/InputEditDialog.cpp b/src/ShaderNode/Widgets/InputEditDialog.cpp index 71e6b2298..09f711f3d 100644 --- a/src/ShaderNode/Widgets/InputEditDialog.cpp +++ b/src/ShaderNode/Widgets/InputEditDialog.cpp @@ -16,8 +16,8 @@ QDialog(parent) m_inputName = new QLineEdit; m_typeList = new QComboBox; - for (std::size_t i = 0; i < InputTypeCount; ++i) - m_typeList->addItem(EnumToString(static_cast(i))); + for (std::size_t i = 0; i < InOutTypeCount; ++i) + m_typeList->addItem(EnumToString(static_cast(i))); m_roleList = new QComboBox; for (std::size_t i = 0; i < InputRoleCount; ++i) @@ -57,7 +57,7 @@ InputInfo InputEditDialog::GetInputInfo() const inputInfo.name = m_inputName->text().toStdString(); inputInfo.role = static_cast(m_roleList->currentIndex()); inputInfo.roleIndex = static_cast(m_roleIndex->value()); - inputInfo.type = static_cast(m_typeList->currentIndex()); + inputInfo.type = static_cast(m_typeList->currentIndex()); return inputInfo; } diff --git a/src/ShaderNode/Widgets/InputEditDialog.hpp b/src/ShaderNode/Widgets/InputEditDialog.hpp index ef96d118c..633b9c99d 100644 --- a/src/ShaderNode/Widgets/InputEditDialog.hpp +++ b/src/ShaderNode/Widgets/InputEditDialog.hpp @@ -15,7 +15,7 @@ struct InputInfo std::size_t roleIndex; std::string name; InputRole role; - InputType type; + InOutType type; }; class InputEditDialog : public QDialog diff --git a/src/ShaderNode/Widgets/MainWindow.cpp b/src/ShaderNode/Widgets/MainWindow.cpp index 6f3d8a5f4..ca0bd4c0a 100644 --- a/src/ShaderNode/Widgets/MainWindow.cpp +++ b/src/ShaderNode/Widgets/MainWindow.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -20,6 +21,7 @@ m_shaderGraph(graph) QtNodes::FlowView* flowView = new QtNodes::FlowView(scene); setCentralWidget(flowView); + // Input editor InputEditor* inputEditor = new InputEditor(m_shaderGraph); QDockWidget* inputDock = new QDockWidget(tr("Inputs")); @@ -28,6 +30,16 @@ m_shaderGraph(graph) addDockWidget(Qt::LeftDockWidgetArea, inputDock); + // Output editor + OutputEditor* outputEditor = new OutputEditor(m_shaderGraph); + + QDockWidget* outputDock = new QDockWidget(tr("Outputs")); + outputDock->setFeatures(QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetMovable); + outputDock->setWidget(outputEditor); + + addDockWidget(Qt::LeftDockWidgetArea, outputDock); + + // Texture editor TextureEditor* textureEditor = new TextureEditor(m_shaderGraph); QDockWidget* textureDock = new QDockWidget(tr("Textures")); @@ -36,6 +48,7 @@ m_shaderGraph(graph) addDockWidget(Qt::LeftDockWidgetArea, textureDock); + // Node editor m_nodeEditor = new NodeEditor; QDockWidget* nodeEditorDock = new QDockWidget(tr("Node editor")); diff --git a/src/ShaderNode/Widgets/OutputEditDialog.cpp b/src/ShaderNode/Widgets/OutputEditDialog.cpp new file mode 100644 index 000000000..23f092f75 --- /dev/null +++ b/src/ShaderNode/Widgets/OutputEditDialog.cpp @@ -0,0 +1,67 @@ +#include +#include +#include +#include +#include +#include +#include + +OutputEditDialog::OutputEditDialog(QWidget* parent) : +QDialog(parent) +{ + setWindowTitle(tr("Output edit dialog")); + setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); + + m_outputName = new QLineEdit; + + m_typeList = new QComboBox; + for (std::size_t i = 0; i < InOutTypeCount; ++i) + m_typeList->addItem(EnumToString(static_cast(i))); + + QFormLayout* formLayout = new QFormLayout; + formLayout->addRow(tr("Name"), m_outputName); + formLayout->addRow(tr("Type"), m_typeList); + + QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); + connect(buttonBox, &QDialogButtonBox::accepted, this, &OutputEditDialog::OnAccept); + connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); + + QVBoxLayout* verticalLayout = new QVBoxLayout; + verticalLayout->addLayout(formLayout); + verticalLayout->addWidget(buttonBox); + + setLayout(verticalLayout); +} + +OutputEditDialog::OutputEditDialog(const OutputInfo& input, QWidget* parent) : +OutputEditDialog(parent) +{ + m_outputName->setText(QString::fromStdString(input.name)); + m_typeList->setCurrentText(EnumToString(input.type)); +} + +OutputInfo OutputEditDialog::GetOutputInfo() const +{ + OutputInfo inputInfo; + inputInfo.name = m_outputName->text().toStdString(); + inputInfo.type = static_cast(m_typeList->currentIndex()); + + return inputInfo; +} + +void OutputEditDialog::OnAccept() +{ + if (m_outputName->text().isEmpty()) + { + QMessageBox::critical(this, tr("Empty name"), tr("Output name must be set"), QMessageBox::Ok); + return; + } + + if (m_typeList->currentIndex() < 0) + { + QMessageBox::critical(this, tr("Invalid type"), tr("You must select a type"), QMessageBox::Ok); + return; + } + + accept(); +} diff --git a/src/ShaderNode/Widgets/OutputEditDialog.hpp b/src/ShaderNode/Widgets/OutputEditDialog.hpp new file mode 100644 index 000000000..3c06323dd --- /dev/null +++ b/src/ShaderNode/Widgets/OutputEditDialog.hpp @@ -0,0 +1,36 @@ +#pragma once + +#ifndef NAZARA_SHADERNODES_OUTPUTEDITDIALOG_HPP +#define NAZARA_SHADERNODES_OUTPUTEDITDIALOG_HPP + +#include +#include + +class QComboBox; +class QLineEdit; + +struct OutputInfo +{ + std::string name; + InOutType type; +}; + +class OutputEditDialog : public QDialog +{ + public: + OutputEditDialog(QWidget* parent = nullptr); + OutputEditDialog(const OutputInfo& input, QWidget* parent = nullptr); + ~OutputEditDialog() = default; + + OutputInfo GetOutputInfo() const; + + private: + void OnAccept(); + + QComboBox* m_typeList; + QLineEdit* m_outputName; +}; + +#include + +#endif diff --git a/src/ShaderNode/Widgets/OutputEditDialog.inl b/src/ShaderNode/Widgets/OutputEditDialog.inl new file mode 100644 index 000000000..9c2c2892b --- /dev/null +++ b/src/ShaderNode/Widgets/OutputEditDialog.inl @@ -0,0 +1 @@ +#include diff --git a/src/ShaderNode/Widgets/OutputEditor.cpp b/src/ShaderNode/Widgets/OutputEditor.cpp new file mode 100644 index 000000000..ba317de07 --- /dev/null +++ b/src/ShaderNode/Widgets/OutputEditor.cpp @@ -0,0 +1,95 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +OutputEditor::OutputEditor(ShaderGraph& graph) : +m_shaderGraph(graph) +{ + m_outputList = new QListWidget(this); + connect(m_outputList, &QListWidget::currentRowChanged, this, &OutputEditor::OnOutputSelectionUpdate); + connect(m_outputList, &QListWidget::itemDoubleClicked, [this](QListWidgetItem* item) + { + OnEditOutput(m_outputList->row(item)); + }); + + QPushButton* addOutputButton = new QPushButton(tr("Add output...")); + connect(addOutputButton, &QPushButton::released, this, &OutputEditor::OnAddOutput); + + m_layout = new QVBoxLayout; + m_layout->addWidget(m_outputList); + m_layout->addWidget(addOutputButton); + + setLayout(m_layout); + + m_onOutputListUpdateSlot.Connect(m_shaderGraph.OnOutputListUpdate, this, &OutputEditor::OnOutputListUpdate); + m_onOutputUpdateSlot.Connect(m_shaderGraph.OnOutputUpdate, this, &OutputEditor::OnOutputUpdate); + + RefreshOutputs(); +} + +void OutputEditor::OnAddOutput() +{ + OutputEditDialog* dialog = new OutputEditDialog(this); + dialog->setAttribute(Qt::WA_DeleteOnClose, true); + connect(dialog, &QDialog::accepted, [this, dialog] + { + OutputInfo inputInfo = dialog->GetOutputInfo(); + m_shaderGraph.AddOutput(std::move(inputInfo.name), inputInfo.type); + }); + + dialog->open(); +} + +void OutputEditor::OnEditOutput(int inputIndex) +{ + const auto& input = m_shaderGraph.GetOutput(inputIndex); + + OutputInfo info; + info.name = input.name; + info.type = input.type; + + OutputEditDialog* dialog = new OutputEditDialog(std::move(info), this); + dialog->setAttribute(Qt::WA_DeleteOnClose, true); + connect(dialog, &QDialog::accepted, [this, dialog, inputIndex] + { + OutputInfo inputInfo = dialog->GetOutputInfo(); + m_shaderGraph.UpdateOutput(inputIndex, std::move(inputInfo.name), inputInfo.type); + }); + + dialog->open(); +} + +void OutputEditor::OnOutputSelectionUpdate(int inputIndex) +{ + if (inputIndex >= 0) + { + m_currentOutputIndex = inputIndex; + } + else + m_currentOutputIndex.reset(); +} + +void OutputEditor::OnOutputListUpdate(ShaderGraph* /*graph*/) +{ + RefreshOutputs(); +} + +void OutputEditor::OnOutputUpdate(ShaderGraph* /*graph*/, std::size_t inputIndex) +{ + const auto& inputEntry = m_shaderGraph.GetOutput(inputIndex); + m_outputList->item(int(inputIndex))->setText(QString::fromStdString(inputEntry.name)); +} + +void OutputEditor::RefreshOutputs() +{ + m_outputList->clear(); + m_outputList->setCurrentRow(-1); + + for (const auto& inputEntry : m_shaderGraph.GetOutputs()) + m_outputList->addItem(QString::fromStdString(inputEntry.name)); +} diff --git a/src/ShaderNode/Widgets/OutputEditor.hpp b/src/ShaderNode/Widgets/OutputEditor.hpp new file mode 100644 index 000000000..6aa53eda0 --- /dev/null +++ b/src/ShaderNode/Widgets/OutputEditor.hpp @@ -0,0 +1,39 @@ +#pragma once + +#ifndef NAZARA_SHADERNODES_OUTPUTEDITOR_HPP +#define NAZARA_SHADERNODES_OUTPUTEDITOR_HPP + +#include +#include +#include + +class QLabel; +class QListWidget; +class QVBoxLayout; + +class OutputEditor : public QWidget +{ + public: + OutputEditor(ShaderGraph& graph); + ~OutputEditor() = default; + + private: + void OnAddOutput(); + void OnEditOutput(int inputIndex); + void OnOutputSelectionUpdate(int inputIndex); + void OnOutputListUpdate(ShaderGraph* graph); + void OnOutputUpdate(ShaderGraph* graph, std::size_t inputIndex); + void RefreshOutputs(); + + NazaraSlot(ShaderGraph, OnOutputListUpdate, m_onOutputListUpdateSlot); + NazaraSlot(ShaderGraph, OnOutputUpdate, m_onOutputUpdateSlot); + + std::optional m_currentOutputIndex; + ShaderGraph& m_shaderGraph; + QListWidget* m_outputList; + QVBoxLayout* m_layout; +}; + +#include + +#endif diff --git a/src/ShaderNode/Widgets/OutputEditor.inl b/src/ShaderNode/Widgets/OutputEditor.inl new file mode 100644 index 000000000..10ed1238b --- /dev/null +++ b/src/ShaderNode/Widgets/OutputEditor.inl @@ -0,0 +1 @@ +#include From effd1b45529115689feab513f12fe897ae503385 Mon Sep 17 00:00:00 2001 From: Lynix Date: Sun, 31 May 2020 18:39:28 +0200 Subject: [PATCH 024/105] ShaderNode: Handle vector component count at runtime --- include/Nazara/Renderer/ShaderAst.hpp | 4 + include/Nazara/Renderer/ShaderAst.inl | 19 ++- src/Nazara/Renderer/ShaderAst.cpp | 17 +++ src/ShaderNode/DataModels/Cast.hpp | 24 ++-- src/ShaderNode/DataModels/Cast.inl | 148 ++++++++++++-------- src/ShaderNode/DataModels/InputValue.cpp | 27 +++- src/ShaderNode/DataModels/InputValue.hpp | 3 + src/ShaderNode/DataModels/OutputValue.cpp | 42 +++++- src/ShaderNode/DataModels/OutputValue.hpp | 3 + src/ShaderNode/DataModels/SampleTexture.cpp | 40 ++++-- src/ShaderNode/DataModels/SampleTexture.hpp | 7 +- src/ShaderNode/DataModels/TextureValue.cpp | 20 ++- src/ShaderNode/DataModels/TextureValue.hpp | 3 + src/ShaderNode/DataModels/VecBinOp.cpp | 72 ++++++++++ src/ShaderNode/DataModels/VecBinOp.hpp | 35 ++--- src/ShaderNode/DataModels/VecBinOp.inl | 127 ++++------------- src/ShaderNode/DataModels/VecValue.hpp | 10 +- src/ShaderNode/DataModels/VecValue.inl | 50 +++---- src/ShaderNode/DataTypes/FloatData.cpp | 1 + src/ShaderNode/DataTypes/FloatData.hpp | 28 ++++ src/ShaderNode/DataTypes/FloatData.inl | 7 + src/ShaderNode/DataTypes/VecData.cpp | 17 +++ src/ShaderNode/DataTypes/VecData.hpp | 65 ++++----- src/ShaderNode/DataTypes/VecData.inl | 13 +- src/ShaderNode/Enums.cpp | 15 ++ src/ShaderNode/Enums.hpp | 2 + src/ShaderNode/ShaderGraph.cpp | 43 ++---- src/ShaderNode/Widgets/MainWindow.cpp | 26 ++-- 28 files changed, 529 insertions(+), 339 deletions(-) create mode 100644 src/ShaderNode/DataTypes/FloatData.cpp create mode 100644 src/ShaderNode/DataTypes/FloatData.hpp create mode 100644 src/ShaderNode/DataTypes/FloatData.inl diff --git a/include/Nazara/Renderer/ShaderAst.hpp b/include/Nazara/Renderer/ShaderAst.hpp index 28b808d6c..08e8e20b2 100644 --- a/include/Nazara/Renderer/ShaderAst.hpp +++ b/include/Nazara/Renderer/ShaderAst.hpp @@ -258,6 +258,7 @@ namespace Nz { public: inline Cast(ExpressionType castTo, ExpressionPtr first, ExpressionPtr second = nullptr, ExpressionPtr third = nullptr, ExpressionPtr fourth = nullptr); + inline Cast(ExpressionType castTo, ExpressionPtr* expressions, std::size_t expressionCount); ExpressionType GetExpressionType() const override; void Register(ShaderWriter& visitor) override; @@ -265,6 +266,9 @@ namespace Nz ExpressionType exprType; std::array expressions; + + private: + void Validate() const; }; class NAZARA_RENDERER_API Constant : public Expression diff --git a/include/Nazara/Renderer/ShaderAst.inl b/include/Nazara/Renderer/ShaderAst.inl index ea9e5cddf..e837cbdb4 100644 --- a/include/Nazara/Renderer/ShaderAst.inl +++ b/include/Nazara/Renderer/ShaderAst.inl @@ -169,19 +169,16 @@ namespace Nz exprType(castTo), expressions({ {first, second, third, fourth} }) { - unsigned int componentCount = 0; - unsigned int requiredComponents = GetComponentCount(exprType); - for (const auto& exprPtr : expressions) - { - if (!exprPtr) - break; + Validate(); + } - componentCount += GetComponentCount(exprPtr->GetExpressionType()); - } + inline Cast::Cast(ExpressionType castTo, ExpressionPtr* Expressions, std::size_t expressionCount) : + exprType(castTo) + { + for (std::size_t i = 0; i < expressionCount; ++i) + expressions[i] = Expressions[i]; - //TODO: AstParseError - if (componentCount != requiredComponents) - throw std::runtime_error("Component count doesn't match required component count"); + Validate(); } inline Constant::Constant(bool value) : diff --git a/src/Nazara/Renderer/ShaderAst.cpp b/src/Nazara/Renderer/ShaderAst.cpp index 0899cbdc7..a0a0cc031 100644 --- a/src/Nazara/Renderer/ShaderAst.cpp +++ b/src/Nazara/Renderer/ShaderAst.cpp @@ -200,6 +200,23 @@ namespace Nz::ShaderAst visitor.Write(*this); } + void Cast::Validate() const + { + unsigned int componentCount = 0; + unsigned int requiredComponents = GetComponentCount(exprType); + for (const auto& exprPtr : expressions) + { + if (!exprPtr) + break; + + componentCount += GetComponentCount(exprPtr->GetExpressionType()); + } + + //TODO: AstParseError + if (componentCount != requiredComponents) + throw std::runtime_error("Component count doesn't match required component count"); + } + ExpressionCategory SwizzleOp::GetExpressionCategory() const { diff --git a/src/ShaderNode/DataModels/Cast.hpp b/src/ShaderNode/DataModels/Cast.hpp index c1b63e8e0..90dad931e 100644 --- a/src/ShaderNode/DataModels/Cast.hpp +++ b/src/ShaderNode/DataModels/Cast.hpp @@ -10,7 +10,7 @@ #include #include -template +template class CastVec : public ShaderNode { public: @@ -31,25 +31,21 @@ class CastVec : public ShaderNode void setInData(std::shared_ptr value, int index) override; - private: - static constexpr std::size_t FromComponents = From::ComponentCount; - static constexpr std::size_t ToComponents = To::ComponentCount; - static constexpr std::size_t ComponentDiff = (ToComponents >= FromComponents) ? ToComponents - FromComponents : 0; + QtNodes::NodeValidationState validationState() const override; + QString validationMessage() const override; + private: bool ComputePreview(QPixmap& pixmap) override; void UpdateOutput(); - VecType m_overflowComponents; - std::shared_ptr m_input; - std::shared_ptr m_output; + std::shared_ptr m_input; + std::shared_ptr m_output; + VecType m_overflowComponents; }; -using CastVec2ToVec3 = CastVec; -using CastVec2ToVec4 = CastVec; -using CastVec3ToVec2 = CastVec; -using CastVec3ToVec4 = CastVec; -using CastVec4ToVec2 = CastVec; -using CastVec4ToVec3 = CastVec; +using CastToVec2 = CastVec<2>; +using CastToVec3 = CastVec<3>; +using CastToVec4 = CastVec<4>; #include diff --git a/src/ShaderNode/DataModels/Cast.inl b/src/ShaderNode/DataModels/Cast.inl index 56866aa3e..64ed934a2 100644 --- a/src/ShaderNode/DataModels/Cast.inl +++ b/src/ShaderNode/DataModels/Cast.inl @@ -4,21 +4,32 @@ #include #include -template -CastVec::CastVec(ShaderGraph& graph) : +template +CastVec::CastVec(ShaderGraph& graph) : ShaderNode(graph) { - static_assert(ComponentDiff <= s_vectorComponents.size()); + static_assert(ToComponentCount <= s_vectorComponents.size()); + + m_overflowComponents.fill(0.f); + + m_output = std::make_shared(ToComponentCount); } -template -void CastVec::BuildNodeEdition(QFormLayout* layout) +template +void CastVec::BuildNodeEdition(QFormLayout* layout) { ShaderNode::BuildNodeEdition(layout); - if constexpr (ComponentDiff > 0) + if (!m_input) + return; + + std::size_t fromComponentCount = m_input->componentCount; + + if (ToComponentCount > fromComponentCount) { - for (std::size_t i = 0; i < ComponentDiff; ++i) + std::size_t overflowComponentCount = ToComponentCount - fromComponentCount; + + for (std::size_t i = 0; i < overflowComponentCount; ++i) { QDoubleSpinBox* spinbox = new QDoubleSpinBox; spinbox->setDecimals(6); @@ -30,31 +41,36 @@ void CastVec::BuildNodeEdition(QFormLayout* layout) UpdateOutput(); }); - layout->addRow(QString::fromUtf8(&s_vectorComponents[FromComponents + i], 1), spinbox); + layout->addRow(QString::fromUtf8(&s_vectorComponents[fromComponentCount + i], 1), spinbox); } } } -template -Nz::ShaderAst::ExpressionPtr CastVec::GetExpression(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count) const +template +Nz::ShaderAst::ExpressionPtr CastVec::GetExpression(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count) const { + assert(m_input); assert(count == 1); - if constexpr (ComponentDiff > 0) - { - std::array constants; - for (std::size_t i = 0; i < ComponentDiff; ++i) - constants[i] = Nz::ShaderBuilder::Constant(m_overflowComponents[i]); + std::size_t fromComponentCount = m_input->componentCount; - return std::apply([&](auto&&... values) - { - return Nz::ShaderBuilder::Cast(expressions[0], values...); //< TODO: Forward - }, constants); - } - else + if (ToComponentCount > fromComponentCount) { - std::array swizzleComponents; - for (std::size_t i = 0; i < ToComponents; ++i) + std::size_t overflowComponentCount = ToComponentCount - fromComponentCount; + + std::array expr; + expr[0] = expressions[0]; + for (std::size_t i = 0; i < overflowComponentCount; ++i) + expr[i + 1] = Nz::ShaderBuilder::Constant(m_overflowComponents[i]); + + constexpr auto ExpressionType = VecExpressionType; + + return Nz::ShaderBuilder::Cast(expr.data(), overflowComponentCount); + } + else if (ToComponentCount < fromComponentCount) + { + std::array swizzleComponents; + for (std::size_t i = 0; i < ToComponentCount; ++i) swizzleComponents[i] = static_cast(static_cast(Nz::ShaderAst::SwizzleComponent::First) + i); return std::apply([&](auto... components) @@ -63,39 +79,41 @@ Nz::ShaderAst::ExpressionPtr CastVec::GetExpression(Nz::ShaderAst::Exp return Nz::ShaderBuilder::Swizzle(expressions[0], componentList); }, swizzleComponents); } + else + return expressions[0]; //< no-op } -template -QString CastVec::caption() const +template +QString CastVec::caption() const { - static QString caption = From::Type().name + " to " + To::Type().name; + static QString caption = "To Vector" + QString::number(ToComponentCount); return caption; } -template -QString CastVec::name() const +template +QString CastVec::name() const { - static QString name = From::Type().id + "to" + To::Type().id; + static QString name = "cast_vec" + QString::number(ToComponentCount); return name; } -template -QtNodes::NodeDataType CastVec::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const +template +QtNodes::NodeDataType CastVec::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const { assert(portIndex == 0); switch (portType) { - case QtNodes::PortType::In: return From::Type(); - case QtNodes::PortType::Out: return To::Type(); + case QtNodes::PortType::In: return VecData::Type(); + case QtNodes::PortType::Out: return VecData::Type(); } assert(false); throw std::runtime_error("Invalid port type"); } -template -unsigned int CastVec::nPorts(QtNodes::PortType portType) const +template +unsigned int CastVec::nPorts(QtNodes::PortType portType) const { switch (portType) { @@ -106,8 +124,8 @@ unsigned int CastVec::nPorts(QtNodes::PortType portType) const return 0; } -template -std::shared_ptr CastVec::outData(QtNodes::PortIndex port) +template +std::shared_ptr CastVec::outData(QtNodes::PortIndex port) { assert(port == 0); @@ -117,14 +135,14 @@ std::shared_ptr CastVec::outData(QtNodes::PortIndex return m_output; } -template -void CastVec::setInData(std::shared_ptr value, int index) +template +void CastVec::setInData(std::shared_ptr value, int index) { assert(index == 0); if (value) { - assert(dynamic_cast(value.get()) != nullptr); - m_input = std::static_pointer_cast(value); + assert(dynamic_cast(value.get()) != nullptr); + m_input = std::static_pointer_cast(value); } else m_input.reset(); @@ -132,8 +150,26 @@ void CastVec::setInData(std::shared_ptr value, int UpdateOutput(); } -template -bool CastVec::ComputePreview(QPixmap& pixmap) +template +QtNodes::NodeValidationState CastVec::validationState() const +{ + if (!m_input) + return QtNodes::NodeValidationState::Error; + + return QtNodes::NodeValidationState::Valid; +} + +template +QString CastVec::validationMessage() const +{ + if (!m_input) + return "Missing input"; + + return QString(); +} + +template +bool CastVec::ComputePreview(QPixmap& pixmap) { if (!m_input) return false; @@ -142,8 +178,8 @@ bool CastVec::ComputePreview(QPixmap& pixmap) return true; } -template -void CastVec::UpdateOutput() +template +void CastVec::UpdateOutput() { if (!m_input) { @@ -160,10 +196,15 @@ void CastVec::UpdateOutput() QImage& output = m_output->preview; output = QImage(inputWidth, inputHeight, QImage::Format_RGBA8888); - std::array constants; - if constexpr (ComponentDiff > 0) + std::size_t fromComponentCount = m_input->componentCount; + std::size_t commonComponents = std::min(fromComponentCount, ToComponentCount); + std::size_t overflowComponentCount = (ToComponentCount > fromComponentCount) ? ToComponentCount - fromComponentCount : 0; + std::size_t voidComponents = 4 - overflowComponentCount - commonComponents; + + std::array constants; + if (ToComponentCount > fromComponentCount) { - for (std::size_t i = 0; i < ComponentDiff; ++i) + for (std::size_t i = 0; i < overflowComponentCount; ++i) constants[i] = static_cast(std::clamp(int(m_overflowComponents[i] * 255), 0, 255)); } @@ -173,17 +214,14 @@ void CastVec::UpdateOutput() { for (int x = 0; x < inputWidth; ++x) { - constexpr std::size_t CommonComponents = std::min(FromComponents, ToComponents); - constexpr std::size_t VoidComponents = 4 - ComponentDiff - CommonComponents; - - for (std::size_t i = 0; i < CommonComponents; ++i) + for (std::size_t i = 0; i < commonComponents; ++i) *outputPtr++ = inputPtr[i]; - for (std::size_t i = 0; i < ComponentDiff; ++i) + for (std::size_t i = 0; i < overflowComponentCount; ++i) *outputPtr++ = constants[i]; - for (std::size_t i = 0; i < VoidComponents; ++i) - *outputPtr++ = (i == VoidComponents - 1) ? 255 : 0; + for (std::size_t i = 0; i < voidComponents; ++i) + *outputPtr++ = (i == voidComponents - 1) ? 255 : 0; inputPtr += 4; } diff --git a/src/ShaderNode/DataModels/InputValue.cpp b/src/ShaderNode/DataModels/InputValue.cpp index 9ff7fd207..6defcb30f 100644 --- a/src/ShaderNode/DataModels/InputValue.cpp +++ b/src/ShaderNode/DataModels/InputValue.cpp @@ -121,16 +121,17 @@ auto InputValue::dataType(QtNodes::PortType portType, QtNodes::PortIndex portInd assert(portIndex == 0); if (!m_currentInputIndex) - return Vec4Data::Type(); + return VecData::Type(); const auto& inputEntry = GetGraph().GetInput(*m_currentInputIndex); switch (inputEntry.type) { //case InputType::Bool: return Nz::ShaderAst::ExpressionType::Boolean; //case InputType::Float1: return Nz::ShaderAst::ExpressionType::Float1; - case InOutType::Float2: return Vec2Data::Type(); - case InOutType::Float3: return Vec3Data::Type(); - case InOutType::Float4: return Vec4Data::Type(); + case InOutType::Float2: + case InOutType::Float3: + case InOutType::Float4: + return VecData::Type(); } assert(false); @@ -148,8 +149,24 @@ std::shared_ptr InputValue::outData(QtNodes::PortIndex port) const auto& inputEntry = graph.GetInput(*m_currentInputIndex); const auto& preview = graph.GetPreviewModel(); - auto vecData = std::make_shared(); + auto vecData = std::make_shared(GetComponentCount(inputEntry.type)); vecData->preview = preview.GetImage(inputEntry.role, inputEntry.roleIndex); return vecData; } + +QtNodes::NodeValidationState InputValue::validationState() const +{ + if (!m_currentInputIndex) + return QtNodes::NodeValidationState::Error; + + return QtNodes::NodeValidationState::Valid; +} + +QString InputValue::validationMessage() const +{ + if (!m_currentInputIndex) + return "No input selected"; + + return QString(); +} diff --git a/src/ShaderNode/DataModels/InputValue.hpp b/src/ShaderNode/DataModels/InputValue.hpp index 0170221f5..4b4c1b31c 100644 --- a/src/ShaderNode/DataModels/InputValue.hpp +++ b/src/ShaderNode/DataModels/InputValue.hpp @@ -30,6 +30,9 @@ class InputValue : public ShaderNode std::shared_ptr outData(QtNodes::PortIndex port) override; + QtNodes::NodeValidationState validationState() const override; + QString validationMessage() const override; + private: bool ComputePreview(QPixmap& pixmap) override; void OnInputListUpdate(); diff --git a/src/ShaderNode/DataModels/OutputValue.cpp b/src/ShaderNode/DataModels/OutputValue.cpp index 2d3a8dc14..04eeafd48 100644 --- a/src/ShaderNode/DataModels/OutputValue.cpp +++ b/src/ShaderNode/DataModels/OutputValue.cpp @@ -87,16 +87,17 @@ QtNodes::NodeDataType OutputValue::dataType(QtNodes::PortType portType, QtNodes: assert(portIndex == 0); if (!m_currentOutputIndex) - return Vec4Data::Type(); + return VecData::Type(); const auto& outputEntry = GetGraph().GetOutput(*m_currentOutputIndex); switch (outputEntry.type) { //case InOutType::Bool: return Nz::ShaderAst::ExpressionType::Boolean; //case InOutType::Float1: return Nz::ShaderAst::ExpressionType::Float1; - case InOutType::Float2: return Vec2Data::Type(); - case InOutType::Float3: return Vec3Data::Type(); - case InOutType::Float4: return Vec4Data::Type(); + case InOutType::Float2: + case InOutType::Float3: + case InOutType::Float4: + return VecData::Type(); } assert(false); @@ -124,8 +125,8 @@ void OutputValue::setInData(std::shared_ptr value, int index) assert(index == 0); if (value) { - assert(dynamic_cast(value.get()) != nullptr); - m_input = std::static_pointer_cast(value); + assert(dynamic_cast(value.get()) != nullptr); + m_input = std::static_pointer_cast(value); } else m_input.reset(); @@ -133,6 +134,35 @@ void OutputValue::setInData(std::shared_ptr value, int index) UpdatePreview(); } +QtNodes::NodeValidationState OutputValue::validationState() const +{ + if (!m_currentOutputIndex || !m_input) + return QtNodes::NodeValidationState::Error; + + const auto& outputEntry = GetGraph().GetOutput(*m_currentOutputIndex); + if (GetComponentCount(outputEntry.type) != m_input->componentCount) + return QtNodes::NodeValidationState::Error; + + return QtNodes::NodeValidationState::Valid; +} + +QString OutputValue::validationMessage() const +{ + if (!m_currentOutputIndex) + return "No output selected"; + + if (!m_input) + return "Missing input"; + + const auto& outputEntry = GetGraph().GetOutput(*m_currentOutputIndex); + std::size_t outputComponentCount = GetComponentCount(outputEntry.type); + + if (m_input->componentCount != outputComponentCount) + return "Incompatible component count (expected " + QString::number(outputComponentCount) + ", got " + QString::number(m_input->componentCount) + ")"; + + return QString(); +} + bool OutputValue::ComputePreview(QPixmap& pixmap) { if (!m_input) diff --git a/src/ShaderNode/DataModels/OutputValue.hpp b/src/ShaderNode/DataModels/OutputValue.hpp index 8db611056..1e7055da5 100644 --- a/src/ShaderNode/DataModels/OutputValue.hpp +++ b/src/ShaderNode/DataModels/OutputValue.hpp @@ -29,6 +29,9 @@ class OutputValue : public ShaderNode void setInData(std::shared_ptr value, int index) override; + QtNodes::NodeValidationState validationState() const override; + QString validationMessage() const override; + private: bool ComputePreview(QPixmap& pixmap) override; void OnOutputListUpdate(); diff --git a/src/ShaderNode/DataModels/SampleTexture.cpp b/src/ShaderNode/DataModels/SampleTexture.cpp index e0fa852c3..970e8a965 100644 --- a/src/ShaderNode/DataModels/SampleTexture.cpp +++ b/src/ShaderNode/DataModels/SampleTexture.cpp @@ -5,7 +5,7 @@ SampleTexture::SampleTexture(ShaderGraph& graph) : ShaderNode(graph) { - m_output = std::make_shared(); + m_output = std::make_shared(4); UpdateOutput(); } @@ -82,9 +82,8 @@ bool SampleTexture::ComputePreview(QPixmap& pixmap) Nz::ShaderAst::ExpressionPtr SampleTexture::GetExpression(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count) const { - if (!m_texture || !m_uv) - throw std::runtime_error("invalid inputs"); - + assert(m_texture); + assert(m_uv); assert(count == 2); return Nz::ShaderBuilder::Sample2D(expressions[0], expressions[1]); @@ -99,7 +98,7 @@ auto SampleTexture::dataType(QtNodes::PortType portType, QtNodes::PortIndex port switch (portIndex) { case 0: return Texture2Data::Type(); - case 1: return Vec2Data::Type(); + case 1: return VecData::Type(); } assert(false); @@ -109,7 +108,7 @@ auto SampleTexture::dataType(QtNodes::PortType portType, QtNodes::PortIndex port case QtNodes::PortType::Out: { assert(portIndex == 0); - return Vec4Data::Type(); + return VecData::Type(); } default: @@ -180,9 +179,9 @@ void SampleTexture::setInData(std::shared_ptr value, int inde { if (value) { - assert(dynamic_cast(value.get()) != nullptr); + assert(dynamic_cast(value.get()) != nullptr); - m_uv = std::static_pointer_cast(value); + m_uv = std::static_pointer_cast(value); } else m_uv.reset(); @@ -197,3 +196,28 @@ void SampleTexture::setInData(std::shared_ptr value, int inde UpdateOutput(); } + +QtNodes::NodeValidationState SampleTexture::validationState() const +{ + if (!m_texture || !m_uv) + return QtNodes::NodeValidationState::Error; + + if (m_uv->componentCount != 2) + return QtNodes::NodeValidationState::Error; + + return QtNodes::NodeValidationState::Valid; +} + +QString SampleTexture::validationMessage() const +{ + if (!m_texture) + return "Missing texture"; + + if (!m_uv) + return "Missing uv"; + + if (m_uv->componentCount != 2) + return "Incompatible UV (expected 2, got " + QString::number(m_uv->componentCount) + ")"; + + return QString(); +} diff --git a/src/ShaderNode/DataModels/SampleTexture.hpp b/src/ShaderNode/DataModels/SampleTexture.hpp index 7a24409d0..7afb77e0f 100644 --- a/src/ShaderNode/DataModels/SampleTexture.hpp +++ b/src/ShaderNode/DataModels/SampleTexture.hpp @@ -34,13 +34,16 @@ class SampleTexture : public ShaderNode void setInData(std::shared_ptr value, int index) override; + QtNodes::NodeValidationState validationState() const override; + QString validationMessage() const override; + protected: bool ComputePreview(QPixmap& pixmap) override; void UpdateOutput(); std::shared_ptr m_texture; - std::shared_ptr m_uv; - std::shared_ptr m_output; + std::shared_ptr m_uv; + std::shared_ptr m_output; }; #include diff --git a/src/ShaderNode/DataModels/TextureValue.cpp b/src/ShaderNode/DataModels/TextureValue.cpp index 976ec7dd7..f78a610a9 100644 --- a/src/ShaderNode/DataModels/TextureValue.cpp +++ b/src/ShaderNode/DataModels/TextureValue.cpp @@ -92,7 +92,7 @@ void TextureValue::BuildNodeEdition(QFormLayout* layout) Nz::ShaderAst::ExpressionPtr TextureValue::GetExpression(Nz::ShaderAst::ExpressionPtr* /*expressions*/, std::size_t count) const { if (!m_currentTextureIndex) - throw std::runtime_error("invalid inputs"); + throw std::runtime_error("invalid texture input"); assert(count == 0); @@ -117,7 +117,7 @@ auto TextureValue::dataType(QtNodes::PortType portType, QtNodes::PortIndex portI assert(portType == QtNodes::PortType::Out); assert(portIndex == 0); - return Vec4Data::Type(); + return VecData::Type(); } std::shared_ptr TextureValue::outData(QtNodes::PortIndex port) @@ -145,3 +145,19 @@ std::shared_ptr TextureValue::outData(QtNodes::PortIndex port return textureData; } + +QtNodes::NodeValidationState TextureValue::validationState() const +{ + if (!m_currentTextureIndex) + return QtNodes::NodeValidationState::Error; + + return QtNodes::NodeValidationState::Valid; +} + +QString TextureValue::validationMessage() const +{ + if (!m_currentTextureIndex) + return "No texture selected"; + + return QString(); +} diff --git a/src/ShaderNode/DataModels/TextureValue.hpp b/src/ShaderNode/DataModels/TextureValue.hpp index 27ae9474a..fdf355828 100644 --- a/src/ShaderNode/DataModels/TextureValue.hpp +++ b/src/ShaderNode/DataModels/TextureValue.hpp @@ -29,6 +29,9 @@ class TextureValue : public ShaderNode std::shared_ptr outData(QtNodes::PortIndex port) override; + QtNodes::NodeValidationState validationState() const override; + QString validationMessage() const override; + protected: bool ComputePreview(QPixmap& pixmap) override; void OnTextureListUpdate(); diff --git a/src/ShaderNode/DataModels/VecBinOp.cpp b/src/ShaderNode/DataModels/VecBinOp.cpp index fd2e0d5c1..8f63c2642 100644 --- a/src/ShaderNode/DataModels/VecBinOp.cpp +++ b/src/ShaderNode/DataModels/VecBinOp.cpp @@ -1 +1,73 @@ #include + +QString VecAdd::caption() const +{ + static QString caption = "Vector addition"; + return caption; +} + +QString VecAdd::name() const +{ + static QString name = "vec_add"; + return name; +} + +void VecAdd::ApplyOp(const std::uint8_t* left, const std::uint8_t* right, std::uint8_t* output, std::size_t pixelCount) +{ + for (std::size_t i = 0; i < pixelCount; ++i) + { + unsigned int lValue = left[i]; + unsigned int rValue = right[i]; + + output[i] = static_cast(std::min(lValue + rValue, 255U)); + } +} + +QString VecMul::caption() const +{ + static QString caption = "Vector multiplication"; + return caption; +} + +QString VecMul::name() const +{ + static QString name = "vec_mul"; + return name; +} + +void VecMul::ApplyOp(const std::uint8_t* left, const std::uint8_t* right, std::uint8_t* output, std::size_t pixelCount) +{ + for (std::size_t i = 0; i < pixelCount; ++i) + { + unsigned int lValue = left[i]; + unsigned int rValue = right[i]; + + output[i] = static_cast(lValue * rValue / 255); + } +} + +QString VecSub::caption() const +{ + static QString caption = "Vector subtraction"; + return caption; +} + + +QString VecSub::name() const +{ + static QString name = "vec_sub"; + return name; +} + +void VecSub::ApplyOp(const std::uint8_t* left, const std::uint8_t* right, std::uint8_t* output, std::size_t pixelCount) +{ + for (std::size_t i = 0; i < pixelCount; ++i) + { + unsigned int lValue = left[i]; + unsigned int rValue = right[i]; + + unsigned int sub = (lValue >= rValue) ? lValue - rValue : 0u; + + output[i] = static_cast(sub); + } +} diff --git a/src/ShaderNode/DataModels/VecBinOp.hpp b/src/ShaderNode/DataModels/VecBinOp.hpp index 6fa8fe875..f8bebc667 100644 --- a/src/ShaderNode/DataModels/VecBinOp.hpp +++ b/src/ShaderNode/DataModels/VecBinOp.hpp @@ -6,7 +6,7 @@ #include #include -template +template class VecBinOp : public ShaderNode { public: @@ -29,16 +29,15 @@ class VecBinOp : public ShaderNode bool ComputePreview(QPixmap& pixmap) override; void UpdateOutput(); - std::shared_ptr m_lhs; - std::shared_ptr m_rhs; - std::shared_ptr m_output; + std::shared_ptr m_lhs; + std::shared_ptr m_rhs; + std::shared_ptr m_output; }; -template -class VecAdd : public VecBinOp +class VecAdd : public VecBinOp { public: - using VecBinOp::VecBinOp; + using VecBinOp::VecBinOp; QString caption() const override; QString name() const override; @@ -46,11 +45,10 @@ class VecAdd : public VecBinOp void ApplyOp(const std::uint8_t* left, const std::uint8_t* right, std::uint8_t* output, std::size_t pixelCount) override; }; -template -class VecMul : public VecBinOp +class VecMul : public VecBinOp { public: - using VecBinOp::VecBinOp; + using VecBinOp::VecBinOp; QString caption() const override; QString name() const override; @@ -58,11 +56,10 @@ class VecMul : public VecBinOp void ApplyOp(const std::uint8_t* left, const std::uint8_t* right, std::uint8_t* output, std::size_t pixelCount) override; }; -template -class VecSub : public VecBinOp +class VecSub : public VecBinOp { public: - using VecBinOp::VecBinOp; + using VecBinOp::VecBinOp; QString caption() const override; QString name() const override; @@ -70,18 +67,6 @@ class VecSub : public VecBinOp void ApplyOp(const std::uint8_t* left, const std::uint8_t* right, std::uint8_t* output, std::size_t pixelCount) override; }; -using Vec2Add = VecAdd; -using Vec3Add = VecAdd; -using Vec4Add = VecAdd; - -using Vec2Mul = VecMul; -using Vec3Mul = VecMul; -using Vec4Mul = VecMul; - -using Vec2Sub = VecSub; -using Vec3Sub = VecSub; -using Vec4Sub = VecSub; - #include #endif diff --git a/src/ShaderNode/DataModels/VecBinOp.inl b/src/ShaderNode/DataModels/VecBinOp.inl index 2d33f65c6..7d3cf1e12 100644 --- a/src/ShaderNode/DataModels/VecBinOp.inl +++ b/src/ShaderNode/DataModels/VecBinOp.inl @@ -1,17 +1,15 @@ #include #include -template -VecBinOp::VecBinOp(ShaderGraph& graph) : +template +VecBinOp::VecBinOp(ShaderGraph& graph) : ShaderNode(graph) { - m_output = std::make_shared(); - UpdateOutput(); } -template -Nz::ShaderAst::ExpressionPtr VecBinOp::GetExpression(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count) const +template +Nz::ShaderAst::ExpressionPtr VecBinOp::GetExpression(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count) const { assert(count == 2); using BuilderType = typename Nz::ShaderBuilder::template BinOpBuilder; @@ -19,16 +17,16 @@ Nz::ShaderAst::ExpressionPtr VecBinOp::GetExpression(Nz::ShaderAst: return builder(expressions[0], expressions[1]); } -template -QtNodes::NodeDataType VecBinOp::dataType(QtNodes::PortType /*portType*/, QtNodes::PortIndex portIndex) const +template +QtNodes::NodeDataType VecBinOp::dataType(QtNodes::PortType /*portType*/, QtNodes::PortIndex portIndex) const { assert(portIndex == 0 || portIndex == 1); - return Data::Type(); + return VecData::Type(); } -template -unsigned int VecBinOp::nPorts(QtNodes::PortType portType) const +template +unsigned int VecBinOp::nPorts(QtNodes::PortType portType) const { switch (portType) { @@ -39,24 +37,24 @@ unsigned int VecBinOp::nPorts(QtNodes::PortType portType) const return 0; } -template -std::shared_ptr VecBinOp::outData(QtNodes::PortIndex port) +template +std::shared_ptr VecBinOp::outData(QtNodes::PortIndex port) { assert(port == 0); return m_output; } -template -void VecBinOp::setInData(std::shared_ptr value, int index) +template +void VecBinOp::setInData(std::shared_ptr value, int index) { assert(index == 0 || index == 1); - std::shared_ptr castedValue; + std::shared_ptr castedValue; if (value) { - assert(dynamic_cast(value.get()) != nullptr); + assert(dynamic_cast(value.get()) != nullptr); - castedValue = std::static_pointer_cast(value); + castedValue = std::static_pointer_cast(value); } if (index == 0) @@ -67,8 +65,8 @@ void VecBinOp::setInData(std::shared_ptr value, UpdateOutput(); } -template -bool VecBinOp::ComputePreview(QPixmap& pixmap) +template +bool VecBinOp::ComputePreview(QPixmap& pixmap) { if (!m_lhs || !m_rhs) return false; @@ -77,16 +75,19 @@ bool VecBinOp::ComputePreview(QPixmap& pixmap) return true; } -template -void VecBinOp::UpdateOutput() +template +void VecBinOp::UpdateOutput() { - if (!m_lhs || !m_rhs) + if (!m_lhs || !m_rhs || m_lhs->componentCount != m_rhs->componentCount) { + m_output = std::make_shared(4); m_output->preview = QImage(1, 1, QImage::Format_RGBA8888); m_output->preview.fill(QColor::fromRgb(0, 0, 0, 0)); return; } + m_output = std::make_shared(m_lhs->componentCount); + const QImage& leftPreview = m_lhs->preview; const QImage& rightPreview = m_rhs->preview; int maxWidth = std::max(leftPreview.width(), rightPreview.width()); @@ -108,83 +109,3 @@ void VecBinOp::UpdateOutput() UpdatePreview(); } - -template -QString VecAdd::caption() const -{ - static QString caption = Data::Type().name + " addition"; - return caption; -} - -template -QString VecAdd::name() const -{ - static QString name = Data::Type().name + "add"; - return name; -} - -template -void VecAdd::ApplyOp(const std::uint8_t* left, const std::uint8_t* right, std::uint8_t* output, std::size_t pixelCount) -{ - for (std::size_t i = 0; i < pixelCount; ++i) - { - unsigned int lValue = left[i]; - unsigned int rValue = right[i]; - - output[i] = static_cast(std::min(lValue + rValue, 255U)); - } -} - -template -QString VecMul::caption() const -{ - static QString caption = Data::Type().name + " multiplication"; - return caption; -} - -template -QString VecMul::name() const -{ - static QString name = Data::Type().name + "mul"; - return name; -} - -template -void VecMul::ApplyOp(const std::uint8_t* left, const std::uint8_t* right, std::uint8_t* output, std::size_t pixelCount) -{ - for (std::size_t i = 0; i < pixelCount; ++i) - { - unsigned int lValue = left[i]; - unsigned int rValue = right[i]; - - output[i] = static_cast(lValue * rValue / 255); - } -} - -template -QString VecSub::caption() const -{ - static QString caption = Data::Type().name + " subtraction"; - return caption; -} - -template -QString VecSub::name() const -{ - static QString name = Data::Type().name + "sub"; - return name; -} - -template -void VecSub::ApplyOp(const std::uint8_t* left, const std::uint8_t* right, std::uint8_t* output, std::size_t pixelCount) -{ - for (std::size_t i = 0; i < pixelCount; ++i) - { - unsigned int lValue = left[i]; - unsigned int rValue = right[i]; - - unsigned int sub = (lValue >= rValue) ? lValue - rValue : 0u; - - output[i] = static_cast(sub); - } -} diff --git a/src/ShaderNode/DataModels/VecValue.hpp b/src/ShaderNode/DataModels/VecValue.hpp index 50ff1f4e1..b115477e3 100644 --- a/src/ShaderNode/DataModels/VecValue.hpp +++ b/src/ShaderNode/DataModels/VecValue.hpp @@ -11,7 +11,7 @@ #include #include -template +template class VecValue : public ShaderNode { public: @@ -34,16 +34,14 @@ class VecValue : public ShaderNode private: bool ComputePreview(QPixmap& pixmap) override; - static constexpr std::size_t ComponentCount = Data::ComponentCount; - QColor ToColor() const; VecType m_value; }; -using Vec2Value = VecValue; -using Vec3Value = VecValue; -using Vec4Value = VecValue; +using Vec2Value = VecValue<2>; +using Vec3Value = VecValue<3>; +using Vec4Value = VecValue<4>; #include diff --git a/src/ShaderNode/DataModels/VecValue.inl b/src/ShaderNode/DataModels/VecValue.inl index 7f3a9dc5e..fd6d31be1 100644 --- a/src/ShaderNode/DataModels/VecValue.inl +++ b/src/ShaderNode/DataModels/VecValue.inl @@ -5,8 +5,8 @@ #include #include -template -VecValue::VecValue(ShaderGraph& graph) : +template +VecValue::VecValue(ShaderGraph& graph) : ShaderNode(graph) { static_assert(ComponentCount <= s_vectorComponents.size()); @@ -21,55 +21,55 @@ ShaderNode(graph) UpdatePreview(); } -template -QString VecValue::caption() const +template +QString VecValue::caption() const { - static QString caption = Data::Type().name + " constant"; + static QString caption = "Vector" + QString::number(ComponentCount) + " constant"; return caption; } -template -QString VecValue::name() const +template +QString VecValue::name() const { - static QString name = Data::Type().id + "Value"; + static QString name = "vec" + QString::number(ComponentCount) + "_constant"; return name; } -template -QtNodes::NodeDataType VecValue::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const +template +QtNodes::NodeDataType VecValue::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const { assert(portType == QtNodes::PortType::Out); assert(portIndex == 0); - return Data::Type(); + return VecData::Type(); } -template -unsigned int VecValue::nPorts(QtNodes::PortType portType) const +template +unsigned int VecValue::nPorts(QtNodes::PortType portType) const { switch (portType) { - case QtNodes::PortType::In: return 0; + case QtNodes::PortType::In: return 0; case QtNodes::PortType::Out: return 1; } return 0; } -template -std::shared_ptr VecValue::outData(QtNodes::PortIndex port) +template +std::shared_ptr VecValue::outData(QtNodes::PortIndex port) { assert(port == 0); - auto out = std::make_shared(); + auto out = std::make_shared(ComponentCount); out->preview = QImage(1, 1, QImage::Format_RGBA8888); out->preview.fill(ToColor()); return out; } -template -void VecValue::BuildNodeEdition(QFormLayout* layout) +template +void VecValue::BuildNodeEdition(QFormLayout* layout) { ShaderNode::BuildNodeEdition(layout); @@ -91,23 +91,23 @@ void VecValue::BuildNodeEdition(QFormLayout* layout) } } -template -Nz::ShaderAst::ExpressionPtr VecValue::GetExpression(Nz::ShaderAst::ExpressionPtr* /*expressions*/, std::size_t count) const +template +Nz::ShaderAst::ExpressionPtr VecValue::GetExpression(Nz::ShaderAst::ExpressionPtr* /*expressions*/, std::size_t count) const { assert(count == 0); return Nz::ShaderBuilder::Constant(m_value); } -template -bool VecValue::ComputePreview(QPixmap& pixmap) +template +bool VecValue::ComputePreview(QPixmap& pixmap) { pixmap.fill(ToColor()); return true; } -template -QColor VecValue::ToColor() const +template +QColor VecValue::ToColor() const { std::array values = { 0.f, 0.f, 0.f, 1.f }; diff --git a/src/ShaderNode/DataTypes/FloatData.cpp b/src/ShaderNode/DataTypes/FloatData.cpp new file mode 100644 index 000000000..0b1f99d61 --- /dev/null +++ b/src/ShaderNode/DataTypes/FloatData.cpp @@ -0,0 +1 @@ +#include diff --git a/src/ShaderNode/DataTypes/FloatData.hpp b/src/ShaderNode/DataTypes/FloatData.hpp new file mode 100644 index 000000000..e0f0451d2 --- /dev/null +++ b/src/ShaderNode/DataTypes/FloatData.hpp @@ -0,0 +1,28 @@ +#pragma once + +#ifndef NAZARA_SHADERNODES_FLOATDATA_HPP +#define NAZARA_SHADERNODES_FLOATDATA_HPP + +#include +#include + +struct FloatData : public QtNodes::NodeData +{ + inline FloatData(); + + QtNodes::NodeDataType type() const override + { + return Type(); + } + + static QtNodes::NodeDataType Type() + { + return { "float", "Float" }; + } + + QImage preview; +}; + +#include + +#endif diff --git a/src/ShaderNode/DataTypes/FloatData.inl b/src/ShaderNode/DataTypes/FloatData.inl new file mode 100644 index 000000000..3960c5811 --- /dev/null +++ b/src/ShaderNode/DataTypes/FloatData.inl @@ -0,0 +1,7 @@ +#include + +inline FloatData::FloatData() : +preview(1, 1, QImage::Format_RGBA8888) +{ + preview.fill(QColor::fromRgb(255, 255, 255, 0)); +} diff --git a/src/ShaderNode/DataTypes/VecData.cpp b/src/ShaderNode/DataTypes/VecData.cpp index 0b1f99d61..c1f883079 100644 --- a/src/ShaderNode/DataTypes/VecData.cpp +++ b/src/ShaderNode/DataTypes/VecData.cpp @@ -1 +1,18 @@ #include +#include +#include + +Nz::ShaderAst::ExpressionType VecData::GetExpressionType() const +{ + switch (componentCount) + { + case 2: return Nz::ShaderAst::ExpressionType::Float2; + case 3: return Nz::ShaderAst::ExpressionType::Float3; + case 4: return Nz::ShaderAst::ExpressionType::Float4; + default: + break; + } + + assert(false); + throw std::runtime_error("invalid component count"); +} diff --git a/src/ShaderNode/DataTypes/VecData.hpp b/src/ShaderNode/DataTypes/VecData.hpp index 447d37686..5c19be942 100644 --- a/src/ShaderNode/DataTypes/VecData.hpp +++ b/src/ShaderNode/DataTypes/VecData.hpp @@ -9,59 +9,48 @@ struct VecData : public QtNodes::NodeData { - inline VecData(); + inline VecData(std::size_t componentCount); + inline QtNodes::NodeDataType type() const override; + + Nz::ShaderAst::ExpressionType GetExpressionType() const; + + static inline QtNodes::NodeDataType Type(); + + std::size_t componentCount; QImage preview; }; -struct Vec2Data : public VecData +template +struct VecExpressionTypeHelper; + +template<> +struct VecExpressionTypeHelper<1> +{ + static constexpr Nz::ShaderAst::ExpressionType ExpressionType = Nz::ShaderAst::ExpressionType::Float1; +}; + +template<> +struct VecExpressionTypeHelper<2> { - static constexpr std::size_t ComponentCount = 2; static constexpr Nz::ShaderAst::ExpressionType ExpressionType = Nz::ShaderAst::ExpressionType::Float2; - - QtNodes::NodeDataType type() const override - { - return Type(); - } - - static QtNodes::NodeDataType Type() - { - return { "vec2", "Vec2" }; - } }; -struct Vec3Data : public VecData +template<> +struct VecExpressionTypeHelper<3> { - static constexpr std::size_t ComponentCount = 3; static constexpr Nz::ShaderAst::ExpressionType ExpressionType = Nz::ShaderAst::ExpressionType::Float3; - - QtNodes::NodeDataType type() const override - { - return Type(); - } - - static QtNodes::NodeDataType Type() - { - return { "vec3", "Vec3" }; - } }; -struct Vec4Data : public VecData +template<> +struct VecExpressionTypeHelper<4> { - static constexpr std::size_t ComponentCount = 4; static constexpr Nz::ShaderAst::ExpressionType ExpressionType = Nz::ShaderAst::ExpressionType::Float4; - - QtNodes::NodeDataType type() const override - { - return Type(); - } - - static QtNodes::NodeDataType Type() - { - return { "vec4", "Vec4" }; - } }; +template constexpr Nz::ShaderAst::ExpressionType VecExpressionType = VecExpressionTypeHelper::template ExpressionType; + + struct VecTypeDummy {}; template @@ -76,7 +65,7 @@ struct VecTypeHelper<0> template<> struct VecTypeHelper<1> { - using Type = std::array; + using Type = std::array; //< To allow [0] }; template<> diff --git a/src/ShaderNode/DataTypes/VecData.inl b/src/ShaderNode/DataTypes/VecData.inl index 255fbd9ab..a84b5c344 100644 --- a/src/ShaderNode/DataTypes/VecData.inl +++ b/src/ShaderNode/DataTypes/VecData.inl @@ -1,7 +1,18 @@ #include -inline VecData::VecData() : +inline VecData::VecData(std::size_t ComponentCount) : +componentCount(ComponentCount), preview(64, 64, QImage::Format_RGBA8888) { preview.fill(QColor::fromRgb(255, 255, 255, 0)); } + +inline QtNodes::NodeDataType VecData::type() const +{ + return Type(); +} + +inline QtNodes::NodeDataType VecData::Type() +{ + return { "vector", "Vector" }; +} diff --git a/src/ShaderNode/Enums.cpp b/src/ShaderNode/Enums.cpp index fd99c5562..1f756b8de 100644 --- a/src/ShaderNode/Enums.cpp +++ b/src/ShaderNode/Enums.cpp @@ -1,6 +1,21 @@ #include #include +std::size_t GetComponentCount(InOutType type) +{ + switch (type) + { + case InOutType::Bool: return 1; + case InOutType::Float1: return 1; + case InOutType::Float2: return 2; + case InOutType::Float3: return 3; + case InOutType::Float4: return 4; + } + + assert(false); + return 0; +} + const char* EnumToString(InputRole role) { switch (role) diff --git a/src/ShaderNode/Enums.hpp b/src/ShaderNode/Enums.hpp index ba990fdcf..f67623a3f 100644 --- a/src/ShaderNode/Enums.hpp +++ b/src/ShaderNode/Enums.hpp @@ -39,6 +39,8 @@ enum class TextureType constexpr std::size_t TextureTypeCount = static_cast(TextureType::Max) + 1; + +std::size_t GetComponentCount(InOutType type); const char* EnumToString(InputRole role); const char* EnumToString(InOutType input); const char* EnumToString(TextureType textureType); diff --git a/src/ShaderNode/ShaderGraph.cpp b/src/ShaderNode/ShaderGraph.cpp index 876b0f1a3..63a29a6a0 100644 --- a/src/ShaderNode/ShaderGraph.cpp +++ b/src/ShaderNode/ShaderGraph.cpp @@ -58,7 +58,7 @@ m_flowScene(BuildRegistry()) auto& node3 = m_flowScene.createNode(std::make_unique(*this)); node3.nodeGraphicsObject().setPos(200, 200); - auto& node4 = m_flowScene.createNode(std::make_unique(*this)); + auto& node4 = m_flowScene.createNode(std::make_unique(*this)); node4.nodeGraphicsObject().setPos(400, 200); auto& node5 = m_flowScene.createNode(std::make_unique(*this)); @@ -154,6 +154,8 @@ Nz::ShaderAst::StatementPtr ShaderGraph::ToAst() HandleNode = [&](QtNodes::Node* node) -> Nz::ShaderAst::ExpressionPtr { ShaderNode* shaderNode = static_cast(node->nodeDataModel()); + if (shaderNode->validationState() != QtNodes::NodeValidationState::Valid) + throw std::runtime_error(shaderNode->validationMessage().toStdString()); qDebug() << shaderNode->name() << node->id(); if (auto it = variableExpressions.find(node->id()); it != variableExpressions.end()) @@ -211,21 +213,13 @@ Nz::ShaderAst::StatementPtr ShaderGraph::ToAst() return expression; }; - try + m_flowScene.iterateOverNodes([&](QtNodes::Node* node) { - m_flowScene.iterateOverNodes([&](QtNodes::Node* node) + if (node->nodeDataModel()->nPorts(QtNodes::PortType::Out) == 0) { - if (node->nodeDataModel()->nPorts(QtNodes::PortType::Out) == 0) - { - statements.emplace_back(Nz::ShaderBuilder::ExprStatement(HandleNode(node))); - } - }); - } - catch (const std::exception&) - { - - return nullptr; - } + statements.emplace_back(Nz::ShaderBuilder::ExprStatement(HandleNode(node))); + } + }); return std::make_shared(std::move(statements)); } @@ -265,25 +259,16 @@ void ShaderGraph::UpdateTexturePreview(std::size_t textureIndex, QImage preview) std::shared_ptr ShaderGraph::BuildRegistry() { auto registry = std::make_shared(); - RegisterShaderNode(*this, registry, "Casts"); - RegisterShaderNode(*this, registry, "Casts"); - RegisterShaderNode(*this, registry, "Casts"); - RegisterShaderNode(*this, registry, "Casts"); - RegisterShaderNode(*this, registry, "Casts"); - RegisterShaderNode(*this, registry, "Casts"); + RegisterShaderNode(*this, registry, "Casts"); + RegisterShaderNode(*this, registry, "Casts"); + RegisterShaderNode(*this, registry, "Casts"); RegisterShaderNode(*this, registry, "Inputs"); RegisterShaderNode(*this, registry, "Outputs"); RegisterShaderNode(*this, registry, "Texture"); RegisterShaderNode(*this, registry, "Texture"); - RegisterShaderNode(*this, registry, "Vector operations"); - RegisterShaderNode(*this, registry, "Vector operations"); - RegisterShaderNode(*this, registry, "Vector operations"); - RegisterShaderNode(*this, registry, "Vector operations"); - RegisterShaderNode(*this, registry, "Vector operations"); - RegisterShaderNode(*this, registry, "Vector operations"); - RegisterShaderNode(*this, registry, "Vector operations"); - RegisterShaderNode(*this, registry, "Vector operations"); - RegisterShaderNode(*this, registry, "Vector operations"); + RegisterShaderNode(*this, registry, "Vector operations"); + RegisterShaderNode(*this, registry, "Vector operations"); + RegisterShaderNode(*this, registry, "Vector operations"); RegisterShaderNode(*this, registry, "Constants"); RegisterShaderNode(*this, registry, "Constants"); RegisterShaderNode(*this, registry, "Constants"); diff --git a/src/ShaderNode/Widgets/MainWindow.cpp b/src/ShaderNode/Widgets/MainWindow.cpp index ca0bd4c0a..505c1f285 100644 --- a/src/ShaderNode/Widgets/MainWindow.cpp +++ b/src/ShaderNode/Widgets/MainWindow.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -83,15 +84,22 @@ void MainWindow::BuildMenu() void MainWindow::OnCompileToGLSL() { - Nz::GlslWriter writer; - Nz::String glsl = writer.Generate(m_shaderGraph.ToAst()); + try + { + Nz::GlslWriter writer; + Nz::String glsl = writer.Generate(m_shaderGraph.ToAst()); - std::cout << glsl << std::endl; + std::cout << glsl << std::endl; - QTextEdit* output = new QTextEdit; - output->setReadOnly(true); - output->setText(QString::fromUtf8(glsl.GetConstBuffer(), int(glsl.GetSize()))); - output->setAttribute(Qt::WA_DeleteOnClose, true); - output->setWindowTitle("GLSL Output"); - output->show(); + QTextEdit* output = new QTextEdit; + output->setReadOnly(true); + output->setText(QString::fromUtf8(glsl.GetConstBuffer(), int(glsl.GetSize()))); + output->setAttribute(Qt::WA_DeleteOnClose, true); + output->setWindowTitle("GLSL Output"); + output->show(); + } + catch (const std::exception& e) + { + QMessageBox::critical(this, tr("Compilation failed"), QString("Compilation failed: ") + e.what()); + } } From 41b50eeac3939b7eb6ce23f2c27134aa3af71e32 Mon Sep 17 00:00:00 2001 From: Lynix Date: Wed, 3 Jun 2020 19:09:51 +0200 Subject: [PATCH 025/105] Fix compilation --- src/ShaderNode/DataModels/Cast.inl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ShaderNode/DataModels/Cast.inl b/src/ShaderNode/DataModels/Cast.inl index 64ed934a2..f8870201a 100644 --- a/src/ShaderNode/DataModels/Cast.inl +++ b/src/ShaderNode/DataModels/Cast.inl @@ -10,7 +10,8 @@ ShaderNode(graph) { static_assert(ToComponentCount <= s_vectorComponents.size()); - m_overflowComponents.fill(0.f); + for (std::size_t i = 0; i < ToComponentCount; ++i) + m_overflowComponents[i] = 0.f; m_output = std::make_shared(ToComponentCount); } From 25562a5856315a70fe5ceab57065a6d1ff108bfc Mon Sep 17 00:00:00 2001 From: Lynix Date: Thu, 4 Jun 2020 18:29:50 +0200 Subject: [PATCH 026/105] Renderer/ShaderAst: Add BinaryFunc --- include/Nazara/Renderer/GlslWriter.hpp | 1 + include/Nazara/Renderer/ShaderAst.hpp | 25 +++++++++++++++++++++++- include/Nazara/Renderer/ShaderAst.inl | 23 ++++++++++++++++++++++ src/Nazara/Renderer/ShaderAst.cpp | 27 ++++++++++++++++++++++++++ 4 files changed, 75 insertions(+), 1 deletion(-) diff --git a/include/Nazara/Renderer/GlslWriter.hpp b/include/Nazara/Renderer/GlslWriter.hpp index 13d7c8459..373a9950e 100644 --- a/include/Nazara/Renderer/GlslWriter.hpp +++ b/include/Nazara/Renderer/GlslWriter.hpp @@ -33,6 +33,7 @@ namespace Nz void Write(const ShaderAst::AssignOp& node) override; void Write(const ShaderAst::Branch& node) override; + void Write(const ShaderAst::BinaryFunc& node) override; void Write(const ShaderAst::BinaryOp& node) override; void Write(const ShaderAst::BuiltinVariable& node) override; void Write(const ShaderAst::Cast& node) override; diff --git a/include/Nazara/Renderer/ShaderAst.hpp b/include/Nazara/Renderer/ShaderAst.hpp index 08e8e20b2..6dd43ea89 100644 --- a/include/Nazara/Renderer/ShaderAst.hpp +++ b/include/Nazara/Renderer/ShaderAst.hpp @@ -26,13 +26,20 @@ namespace Nz Simple //< = }; + enum class BinaryIntrinsic + { + CrossProduct, + DotProduct + }; + enum class BinaryType { Add, //< + Substract, //< - Multiply, //< * Divide, //< / - Equality //< == + + Equality //< == }; enum class BuiltinEntry @@ -325,6 +332,22 @@ namespace Nz ExpressionPtr sampler; ExpressionPtr coordinates; }; + + ////////////////////////////////////////////////////////////////////////// + + class NAZARA_RENDERER_API BinaryFunc : public Expression + { + public: + inline BinaryFunc(BinaryIntrinsic Op, ExpressionPtr Left, ExpressionPtr Right); + + ExpressionType GetExpressionType() const override; + void Register(ShaderWriter& visitor) override; + void Visit(ShaderWriter& visitor) override; + + BinaryIntrinsic intrinsic; + ExpressionPtr left; + ExpressionPtr right; + }; } } diff --git a/include/Nazara/Renderer/ShaderAst.inl b/include/Nazara/Renderer/ShaderAst.inl index e837cbdb4..958baecfe 100644 --- a/include/Nazara/Renderer/ShaderAst.inl +++ b/include/Nazara/Renderer/ShaderAst.inl @@ -243,6 +243,29 @@ namespace Nz if (coordinates->GetExpressionType() != ExpressionType::Float2) throw std::runtime_error("Coordinates must be a Float2"); } + + inline BinaryFunc::BinaryFunc(BinaryIntrinsic Op, ExpressionPtr Left, ExpressionPtr Right) : + intrinsic(Op), + left(Left), + right(Right) + { + ExpressionType leftType = left->GetExpressionType(); + ExpressionType rightType = right->GetExpressionType(); + + if (leftType != rightType) + //TODO: AstParseError + throw std::runtime_error("Left expression type must match right expression type"); + + switch (intrinsic) + { + case BinaryIntrinsic::CrossProduct: + { + if (leftType != ExpressionType::Float3) + //TODO: AstParseError + throw std::runtime_error("CrossProduct only works with Float3 expressions"); + } + } + } } } diff --git a/src/Nazara/Renderer/ShaderAst.cpp b/src/Nazara/Renderer/ShaderAst.cpp index a0a0cc031..0a2373d17 100644 --- a/src/Nazara/Renderer/ShaderAst.cpp +++ b/src/Nazara/Renderer/ShaderAst.cpp @@ -254,4 +254,31 @@ namespace Nz::ShaderAst { visitor.Write(*this); } + + + ExpressionType BinaryFunc::GetExpressionType() const + { + switch (intrinsic) + { + case BinaryIntrinsic::CrossProduct: + return left->GetExpressionType(); + + case BinaryIntrinsic::DotProduct: + return ExpressionType::Float1; + } + + NazaraAssert(false, "Unhandled builtin"); + return ExpressionType::Void; + } + + void BinaryFunc::Register(ShaderWriter& visitor) + { + left->Register(visitor); + right->Register(visitor); + } + + void BinaryFunc::Visit(ShaderWriter& visitor) + { + visitor.Write(*this); + } } From 725ecc76069a14c7f1fda2e99aa2cbc931ba9358 Mon Sep 17 00:00:00 2001 From: Lynix Date: Thu, 4 Jun 2020 18:30:40 +0200 Subject: [PATCH 027/105] ShaderNode: Add FloatValue --- src/ShaderNode/DataModels/FloatValue.cpp | 106 +++++++++++++++++++++++ src/ShaderNode/DataModels/FloatValue.hpp | 45 ++++++++++ src/ShaderNode/DataModels/FloatValue.inl | 1 + src/ShaderNode/DataModels/InputValue.cpp | 4 +- src/ShaderNode/ShaderGraph.cpp | 1 + 5 files changed, 156 insertions(+), 1 deletion(-) create mode 100644 src/ShaderNode/DataModels/FloatValue.cpp create mode 100644 src/ShaderNode/DataModels/FloatValue.hpp create mode 100644 src/ShaderNode/DataModels/FloatValue.inl diff --git a/src/ShaderNode/DataModels/FloatValue.cpp b/src/ShaderNode/DataModels/FloatValue.cpp new file mode 100644 index 000000000..23d5a30d3 --- /dev/null +++ b/src/ShaderNode/DataModels/FloatValue.cpp @@ -0,0 +1,106 @@ +#include +#include +#include +#include + +FloatValue::FloatValue(ShaderGraph& graph) : +ShaderNode(graph), +m_value(1.f) +{ + UpdatePreview(); +} + +QString FloatValue::caption() const +{ + static QString caption = "Float constant"; + return caption; +} + +QString FloatValue::name() const +{ + static QString name = "float_constant"; + return name; +} + +QtNodes::NodeDataType FloatValue::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const +{ + assert(portType == QtNodes::PortType::Out); + assert(portIndex == 0); + + return FloatData::Type(); +} + +unsigned int FloatValue::nPorts(QtNodes::PortType portType) const +{ + switch (portType) + { + case QtNodes::PortType::In: return 0; + case QtNodes::PortType::Out: return 1; + } + + return 0; +} + +std::shared_ptr FloatValue::outData(QtNodes::PortIndex port) +{ + assert(port == 0); + + auto out = std::make_shared(); + out->preview.fill(ToColor()); + + return out; +} + +void FloatValue::BuildNodeEdition(QFormLayout* layout) +{ + ShaderNode::BuildNodeEdition(layout); + + QDoubleSpinBox* spinbox = new QDoubleSpinBox; + spinbox->setDecimals(6); + spinbox->setValue(m_value); + + connect(spinbox, qOverload(&QDoubleSpinBox::valueChanged), [=](double) + { + m_value = spinbox->value(); + Q_EMIT dataUpdated(0); + + UpdatePreview(); + }); + + layout->addRow(tr("Value"), spinbox); +} + +Nz::ShaderAst::ExpressionPtr FloatValue::GetExpression(Nz::ShaderAst::ExpressionPtr* /*expressions*/, std::size_t count) const +{ + assert(count == 0); + + return Nz::ShaderBuilder::Constant(m_value); +} + +bool FloatValue::ComputePreview(QPixmap& pixmap) +{ + pixmap.fill(ToColor()); + return true; +} + +QColor FloatValue::ToColor() const +{ + float value = std::clamp(m_value, 0.f, 1.f); + + return QColor::fromRgbF(value, value, value, value); +} + +void FloatValue::restore(const QJsonObject& data) +{ + m_value = float(data["value"].toDouble(m_value)); + + ShaderNode::restore(data); +} + +QJsonObject FloatValue::save() const +{ + QJsonObject data = ShaderNode::save(); + data["value"] = m_value; + + return data; +} diff --git a/src/ShaderNode/DataModels/FloatValue.hpp b/src/ShaderNode/DataModels/FloatValue.hpp new file mode 100644 index 000000000..44244cd46 --- /dev/null +++ b/src/ShaderNode/DataModels/FloatValue.hpp @@ -0,0 +1,45 @@ +#pragma once + +#ifndef NAZARA_SHADERNODES_FLOATVALUE_HPP +#define NAZARA_SHADERNODES_FLOATVALUE_HPP + +#include +#include +#include +#include +#include +#include +#include + +class FloatValue : public ShaderNode +{ + public: + FloatValue(ShaderGraph& graph); + ~FloatValue() = default; + + QString caption() const override; + QString name() const override; + + QtNodes::NodeDataType dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; + + unsigned int nPorts(QtNodes::PortType portType) const override; + + std::shared_ptr outData(QtNodes::PortIndex port) override; + + void BuildNodeEdition(QFormLayout* layout) override; + + Nz::ShaderAst::ExpressionPtr GetExpression(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count) const override; + + private: + bool ComputePreview(QPixmap& pixmap) override; + QColor ToColor() const; + + void restore(const QJsonObject& data) override; + QJsonObject save() const override; + + float m_value; +}; + +#include + +#endif diff --git a/src/ShaderNode/DataModels/FloatValue.inl b/src/ShaderNode/DataModels/FloatValue.inl new file mode 100644 index 000000000..9f520e6ba --- /dev/null +++ b/src/ShaderNode/DataModels/FloatValue.inl @@ -0,0 +1 @@ +#include diff --git a/src/ShaderNode/DataModels/InputValue.cpp b/src/ShaderNode/DataModels/InputValue.cpp index 6defcb30f..f6b6bf2e4 100644 --- a/src/ShaderNode/DataModels/InputValue.cpp +++ b/src/ShaderNode/DataModels/InputValue.cpp @@ -127,7 +127,9 @@ auto InputValue::dataType(QtNodes::PortType portType, QtNodes::PortIndex portInd switch (inputEntry.type) { //case InputType::Bool: return Nz::ShaderAst::ExpressionType::Boolean; - //case InputType::Float1: return Nz::ShaderAst::ExpressionType::Float1; + case InOutType::Float1: + return FloatData::Type(); + case InOutType::Float2: case InOutType::Float3: case InOutType::Float4: diff --git a/src/ShaderNode/ShaderGraph.cpp b/src/ShaderNode/ShaderGraph.cpp index 63a29a6a0..fd530e504 100644 --- a/src/ShaderNode/ShaderGraph.cpp +++ b/src/ShaderNode/ShaderGraph.cpp @@ -262,6 +262,7 @@ std::shared_ptr ShaderGraph::BuildRegistry() RegisterShaderNode(*this, registry, "Casts"); RegisterShaderNode(*this, registry, "Casts"); RegisterShaderNode(*this, registry, "Casts"); + RegisterShaderNode(*this, registry, "Constants"); RegisterShaderNode(*this, registry, "Inputs"); RegisterShaderNode(*this, registry, "Outputs"); RegisterShaderNode(*this, registry, "Texture"); From 5790b502f772811c0563815fe6ca1f142ef1feb5 Mon Sep 17 00:00:00 2001 From: Lynix Date: Thu, 4 Jun 2020 18:30:54 +0200 Subject: [PATCH 028/105] ShaderNode: Add VecDiv --- src/ShaderNode/DataModels/VecBinOp.cpp | 32 ++++++++++++++++++++++++++ src/ShaderNode/DataModels/VecBinOp.hpp | 11 +++++++++ src/ShaderNode/ShaderGraph.cpp | 1 + 3 files changed, 44 insertions(+) diff --git a/src/ShaderNode/DataModels/VecBinOp.cpp b/src/ShaderNode/DataModels/VecBinOp.cpp index 8f63c2642..3ea2838f3 100644 --- a/src/ShaderNode/DataModels/VecBinOp.cpp +++ b/src/ShaderNode/DataModels/VecBinOp.cpp @@ -71,3 +71,35 @@ void VecSub::ApplyOp(const std::uint8_t* left, const std::uint8_t* right, std::u output[i] = static_cast(sub); } } + +QString VecDiv::caption() const +{ + static QString caption = "Vector divide"; + return caption; +} + + +QString VecDiv::name() const +{ + static QString name = "vec_div"; + return name; +} + +void VecDiv::ApplyOp(const std::uint8_t* left, const std::uint8_t* right, std::uint8_t* output, std::size_t pixelCount) +{ + for (std::size_t i = 0; i < pixelCount; ++i) + { + unsigned int lValue = left[i]; + unsigned int rValue = right[i]; + + unsigned res; + if (rValue != 0) + res = lValue / rValue; + else if (lValue != 0) + res = 0xFF; //< positive / 0 = +inf, which we clamp to 0xFF + else + res = 0; //< 0 / 0 = NaN, which we set to zero + + output[i] = static_cast(res); + } +} diff --git a/src/ShaderNode/DataModels/VecBinOp.hpp b/src/ShaderNode/DataModels/VecBinOp.hpp index f8bebc667..0fbb93f9c 100644 --- a/src/ShaderNode/DataModels/VecBinOp.hpp +++ b/src/ShaderNode/DataModels/VecBinOp.hpp @@ -67,6 +67,17 @@ class VecSub : public VecBinOp void ApplyOp(const std::uint8_t* left, const std::uint8_t* right, std::uint8_t* output, std::size_t pixelCount) override; }; +class VecDiv : public VecBinOp +{ + public: + using VecBinOp::VecBinOp; + + QString caption() const override; + QString name() const override; + + void ApplyOp(const std::uint8_t* left, const std::uint8_t* right, std::uint8_t* output, std::size_t pixelCount) override; +}; + #include #endif diff --git a/src/ShaderNode/ShaderGraph.cpp b/src/ShaderNode/ShaderGraph.cpp index fd530e504..38d1a8dcb 100644 --- a/src/ShaderNode/ShaderGraph.cpp +++ b/src/ShaderNode/ShaderGraph.cpp @@ -268,6 +268,7 @@ std::shared_ptr ShaderGraph::BuildRegistry() RegisterShaderNode(*this, registry, "Texture"); RegisterShaderNode(*this, registry, "Texture"); RegisterShaderNode(*this, registry, "Vector operations"); + RegisterShaderNode(*this, registry, "Vector operations"); RegisterShaderNode(*this, registry, "Vector operations"); RegisterShaderNode(*this, registry, "Vector operations"); RegisterShaderNode(*this, registry, "Constants"); From 088858971600e0e6d4fb875581fcd4cf39de72c7 Mon Sep 17 00:00:00 2001 From: Lynix Date: Thu, 4 Jun 2020 18:31:35 +0200 Subject: [PATCH 029/105] ShaderNode: Add save/load --- src/ShaderNode/DataModels/InputValue.cpp | 20 +++ src/ShaderNode/DataModels/InputValue.hpp | 3 + src/ShaderNode/DataModels/OutputValue.cpp | 16 +++ src/ShaderNode/DataModels/OutputValue.hpp | 3 + src/ShaderNode/DataModels/SampleTexture.cpp | 25 ++-- src/ShaderNode/DataModels/ShaderNode.cpp | 30 ++++- src/ShaderNode/DataModels/ShaderNode.hpp | 3 + src/ShaderNode/DataModels/TextureValue.cpp | 19 +++ src/ShaderNode/DataModels/TextureValue.hpp | 3 + src/ShaderNode/DataModels/VecValue.hpp | 4 +- src/ShaderNode/DataModels/VecValue.inl | 25 ++++ src/ShaderNode/Enums.hpp | 5 +- src/ShaderNode/Enums.inl | 14 +++ src/ShaderNode/ShaderGraph.cpp | 131 ++++++++++++++++++++ src/ShaderNode/ShaderGraph.hpp | 5 + src/ShaderNode/Widgets/MainWindow.cpp | 62 ++++++++- src/ShaderNode/Widgets/MainWindow.hpp | 2 + 17 files changed, 358 insertions(+), 12 deletions(-) diff --git a/src/ShaderNode/DataModels/InputValue.cpp b/src/ShaderNode/DataModels/InputValue.cpp index f6b6bf2e4..3f8d2fbdc 100644 --- a/src/ShaderNode/DataModels/InputValue.cpp +++ b/src/ShaderNode/DataModels/InputValue.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -11,7 +12,10 @@ ShaderNode(graph) m_onInputUpdateSlot.Connect(GetGraph().OnInputUpdate, [&](ShaderGraph*, std::size_t inputIndex) { if (m_currentInputIndex == inputIndex) + { UpdatePreview(); + Q_EMIT dataUpdated(0); + } }); if (graph.GetInputCount() > 0) @@ -172,3 +176,19 @@ QString InputValue::validationMessage() const return QString(); } + +void InputValue::restore(const QJsonObject& data) +{ + m_currentInputText = data["input"].toString().toStdString(); + OnInputListUpdate(); + + ShaderNode::restore(data); +} + +QJsonObject InputValue::save() const +{ + QJsonObject data = ShaderNode::save(); + data["input"] = QString::fromStdString(m_currentInputText); + + return data; +} diff --git a/src/ShaderNode/DataModels/InputValue.hpp b/src/ShaderNode/DataModels/InputValue.hpp index 4b4c1b31c..681a85e8d 100644 --- a/src/ShaderNode/DataModels/InputValue.hpp +++ b/src/ShaderNode/DataModels/InputValue.hpp @@ -37,6 +37,9 @@ class InputValue : public ShaderNode bool ComputePreview(QPixmap& pixmap) override; void OnInputListUpdate(); + void restore(const QJsonObject& data) override; + QJsonObject save() const override; + NazaraSlot(ShaderGraph, OnInputListUpdate, m_onInputListUpdateSlot); NazaraSlot(ShaderGraph, OnInputUpdate, m_onInputUpdateSlot); diff --git a/src/ShaderNode/DataModels/OutputValue.cpp b/src/ShaderNode/DataModels/OutputValue.cpp index 04eeafd48..538884706 100644 --- a/src/ShaderNode/DataModels/OutputValue.cpp +++ b/src/ShaderNode/DataModels/OutputValue.cpp @@ -188,3 +188,19 @@ void OutputValue::OnOutputListUpdate() inputIndex++; } } + +void OutputValue::restore(const QJsonObject& data) +{ + m_currentOutputText = data["input"].toString().toStdString(); + OnOutputListUpdate(); + + ShaderNode::restore(data); +} + +QJsonObject OutputValue::save() const +{ + QJsonObject data = ShaderNode::save(); + data["input"] = QString::fromStdString(m_currentOutputText); + + return data; +} diff --git a/src/ShaderNode/DataModels/OutputValue.hpp b/src/ShaderNode/DataModels/OutputValue.hpp index 1e7055da5..4cc523b66 100644 --- a/src/ShaderNode/DataModels/OutputValue.hpp +++ b/src/ShaderNode/DataModels/OutputValue.hpp @@ -36,6 +36,9 @@ class OutputValue : public ShaderNode bool ComputePreview(QPixmap& pixmap) override; void OnOutputListUpdate(); + void restore(const QJsonObject& data) override; + QJsonObject save() const override; + NazaraSlot(ShaderGraph, OnOutputListUpdate, m_onOutputListUpdateSlot); NazaraSlot(ShaderGraph, OnOutputUpdate, m_onOutputUpdateSlot); diff --git a/src/ShaderNode/DataModels/SampleTexture.cpp b/src/ShaderNode/DataModels/SampleTexture.cpp index 970e8a965..3f0036519 100644 --- a/src/ShaderNode/DataModels/SampleTexture.cpp +++ b/src/ShaderNode/DataModels/SampleTexture.cpp @@ -54,14 +54,25 @@ void SampleTexture::UpdateOutput() float u = float(uvPtr[0]) / 255; float v = float(uvPtr[1]) / 255; - int texX = std::clamp(int(u * textureWidth), 0, textureWidth - 1); - int texY = std::clamp(int(v * textureHeight), 0, textureHeight - 1); - int texPixel = (texY * textureWidth + texX) * 4; + if (textureWidth > 0 && textureHeight > 0) + { + int texX = std::clamp(int(u * textureWidth), 0, textureWidth - 1); + int texY = std::clamp(int(v * textureHeight), 0, textureHeight - 1); + int texPixel = (texY * textureWidth + texX) * 4; + + *outputPtr++ = texturePtr[texPixel + 0]; + *outputPtr++ = texturePtr[texPixel + 1]; + *outputPtr++ = texturePtr[texPixel + 2]; + *outputPtr++ = texturePtr[texPixel + 3]; + } + else + { + *outputPtr++ = 0; + *outputPtr++ = 0; + *outputPtr++ = 0; + *outputPtr++ = 0xFF; + } - *outputPtr++ = texturePtr[texPixel + 0]; - *outputPtr++ = texturePtr[texPixel + 1]; - *outputPtr++ = texturePtr[texPixel + 2]; - *outputPtr++ = texturePtr[texPixel + 3]; uvPtr += 4; } } diff --git a/src/ShaderNode/DataModels/ShaderNode.cpp b/src/ShaderNode/DataModels/ShaderNode.cpp index b955c3c42..a9b06adf8 100644 --- a/src/ShaderNode/DataModels/ShaderNode.cpp +++ b/src/ShaderNode/DataModels/ShaderNode.cpp @@ -81,8 +81,6 @@ void ShaderNode::EnablePreview(bool enable) m_pixmapLabel->clear(); m_pixmap.reset(); } - - embeddedWidgetSizeUpdated(); } } @@ -95,6 +93,29 @@ void ShaderNode::setInData(std::shared_ptr, int) { } +void ShaderNode::restore(const QJsonObject& data) +{ + NodeDataModel::restore(data); + + bool isPreviewEnabled = data["preview_enabled"].toBool(m_isPreviewEnabled); + m_previewSize.x = data["preview_width"].toInt(m_previewSize.x); + m_previewSize.y = data["preview_height"].toInt(m_previewSize.y); + m_variableName = data["variable_name"].toString().toStdString(); + + EnablePreview(isPreviewEnabled); +} + +QJsonObject ShaderNode::save() const +{ + QJsonObject data = NodeDataModel::save(); + data["preview_enabled"] = m_isPreviewEnabled; + data["preview_width"] = m_previewSize.x; + data["preview_height"] = m_previewSize.y; + data["variable_name"] = QString::fromStdString(m_variableName); + + return data; +} + bool ShaderNode::ComputePreview(QPixmap& /*pixmap*/) { return false; @@ -103,7 +124,10 @@ bool ShaderNode::ComputePreview(QPixmap& /*pixmap*/) void ShaderNode::UpdatePreview() { if (!m_pixmap) + { + embeddedWidgetSizeUpdated(); return; + } QPixmap& pixmap = *m_pixmap; @@ -116,4 +140,6 @@ void ShaderNode::UpdatePreview() pixmap = pixmap.scaled(m_previewSize.x, m_previewSize.y); m_pixmapLabel->setPixmap(pixmap); + + embeddedWidgetSizeUpdated(); } diff --git a/src/ShaderNode/DataModels/ShaderNode.hpp b/src/ShaderNode/DataModels/ShaderNode.hpp index 91f6dc0d3..e7ac130c9 100644 --- a/src/ShaderNode/DataModels/ShaderNode.hpp +++ b/src/ShaderNode/DataModels/ShaderNode.hpp @@ -40,6 +40,9 @@ class ShaderNode : public QtNodes::NodeDataModel inline void EnableCustomVariableName(bool enable = true); void UpdatePreview(); + void restore(const QJsonObject& data) override; + QJsonObject save() const override; + private: virtual bool ComputePreview(QPixmap& pixmap); diff --git a/src/ShaderNode/DataModels/TextureValue.cpp b/src/ShaderNode/DataModels/TextureValue.cpp index f78a610a9..78f7df761 100644 --- a/src/ShaderNode/DataModels/TextureValue.cpp +++ b/src/ShaderNode/DataModels/TextureValue.cpp @@ -12,7 +12,10 @@ ShaderNode(graph) m_onTexturePreviewUpdateSlot.Connect(GetGraph().OnTexturePreviewUpdate, [&](ShaderGraph*, std::size_t textureIndex) { if (m_currentTextureIndex == textureIndex) + { UpdatePreview(); + Q_EMIT dataUpdated(0); + } }); if (graph.GetTextureCount() > 0) @@ -161,3 +164,19 @@ QString TextureValue::validationMessage() const return QString(); } + +void TextureValue::restore(const QJsonObject& data) +{ + m_currentTextureText = data["texture"].toString().toStdString(); + OnTextureListUpdate(); + + ShaderNode::restore(data); +} + +QJsonObject TextureValue::save() const +{ + QJsonObject data = ShaderNode::save(); + data["texture"] = QString::fromStdString(m_currentTextureText); + + return data; +} diff --git a/src/ShaderNode/DataModels/TextureValue.hpp b/src/ShaderNode/DataModels/TextureValue.hpp index fdf355828..4b46be4d6 100644 --- a/src/ShaderNode/DataModels/TextureValue.hpp +++ b/src/ShaderNode/DataModels/TextureValue.hpp @@ -36,6 +36,9 @@ class TextureValue : public ShaderNode bool ComputePreview(QPixmap& pixmap) override; void OnTextureListUpdate(); + void restore(const QJsonObject& data) override; + QJsonObject save() const override; + NazaraSlot(ShaderGraph, OnTextureListUpdate, m_onTextureListUpdateSlot); NazaraSlot(ShaderGraph, OnTexturePreviewUpdate, m_onTexturePreviewUpdateSlot); diff --git a/src/ShaderNode/DataModels/VecValue.hpp b/src/ShaderNode/DataModels/VecValue.hpp index b115477e3..fe94e67cb 100644 --- a/src/ShaderNode/DataModels/VecValue.hpp +++ b/src/ShaderNode/DataModels/VecValue.hpp @@ -33,9 +33,11 @@ class VecValue : public ShaderNode private: bool ComputePreview(QPixmap& pixmap) override; - QColor ToColor() const; + void restore(const QJsonObject& data) override; + QJsonObject save() const override; + VecType m_value; }; diff --git a/src/ShaderNode/DataModels/VecValue.inl b/src/ShaderNode/DataModels/VecValue.inl index fd6d31be1..a35a95686 100644 --- a/src/ShaderNode/DataModels/VecValue.inl +++ b/src/ShaderNode/DataModels/VecValue.inl @@ -2,6 +2,7 @@ #include #include #include +#include #include #include @@ -116,3 +117,27 @@ QColor VecValue::ToColor() const return QColor::fromRgbF(values[0], values[1], values[2], values[3]); } + +template +void VecValue::restore(const QJsonObject& data) +{ + QJsonArray vecValues = data["value"].toArray(); + for (std::size_t i = 0; i < ComponentCount; ++i) + m_value[i] = vecValues[int(i)].toInt(m_value[i]); + + ShaderNode::restore(data); +} + +template +QJsonObject VecValue::save() const +{ + QJsonObject data = ShaderNode::save(); + + QJsonArray vecValues; + for (std::size_t i = 0; i < ComponentCount; ++i) + vecValues.push_back(m_value[i]); + + data["value"] = vecValues; + + return data; +} diff --git a/src/ShaderNode/Enums.hpp b/src/ShaderNode/Enums.hpp index f67623a3f..72a5443f7 100644 --- a/src/ShaderNode/Enums.hpp +++ b/src/ShaderNode/Enums.hpp @@ -4,6 +4,8 @@ #define NAZARA_SHADERNODES_ENUMS_HPP #include +#include +#include enum class InputRole { @@ -40,10 +42,11 @@ enum class TextureType constexpr std::size_t TextureTypeCount = static_cast(TextureType::Max) + 1; -std::size_t GetComponentCount(InOutType type); +template std::optional DecodeEnum(const std::string_view& str); const char* EnumToString(InputRole role); const char* EnumToString(InOutType input); const char* EnumToString(TextureType textureType); +std::size_t GetComponentCount(InOutType type); #include diff --git a/src/ShaderNode/Enums.inl b/src/ShaderNode/Enums.inl index 243d12205..f54d0801f 100644 --- a/src/ShaderNode/Enums.inl +++ b/src/ShaderNode/Enums.inl @@ -1 +1,15 @@ #include + +template +std::optional DecodeEnum(const std::string_view& str) +{ + constexpr std::size_t ValueCount = static_cast(T::Max) + 1; + for (std::size_t i = 0; i < ValueCount; ++i) + { + T value = static_cast(i); + if (str == EnumToString(value)) + return value; + } + + return {}; +} diff --git a/src/ShaderNode/ShaderGraph.cpp b/src/ShaderNode/ShaderGraph.cpp index 38d1a8dcb..6fc2fe6aa 100644 --- a/src/ShaderNode/ShaderGraph.cpp +++ b/src/ShaderNode/ShaderGraph.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -114,6 +115,136 @@ std::size_t ShaderGraph::AddTexture(std::string name, TextureType type) return index; } +void ShaderGraph::Clear() +{ + m_flowScene.clearScene(); + m_flowScene.clear(); + + m_inputs.clear(); + m_outputs.clear(); + m_textures.clear(); + + OnInputListUpdate(this); + OnOutputListUpdate(this); + OnTextureListUpdate(this); +} + +void ShaderGraph::Load(const QJsonObject& data) +{ + Clear(); + + QJsonArray inputArray = data["inputs"].toArray(); + for (const auto& inputDocRef : inputArray) + { + QJsonObject inputDoc = inputDocRef.toObject(); + + InputEntry& input = m_inputs.emplace_back(); + input.name = inputDoc["name"].toString().toStdString(); + input.role = DecodeEnum(inputDoc["role"].toString().toStdString()).value(); + input.roleIndex = static_cast(inputDoc["roleIndex"].toInt(0)); + input.type = DecodeEnum(inputDoc["type"].toString().toStdString()).value(); + } + + OnInputListUpdate(this); + + QJsonArray outputArray = data["outputs"].toArray(); + for (const auto& outputDocRef : outputArray) + { + QJsonObject outputDoc = outputDocRef.toObject(); + + OutputEntry& output = m_outputs.emplace_back(); + output.name = outputDoc["name"].toString().toStdString(); + output.type = DecodeEnum(outputDoc["type"].toString().toStdString()).value(); + } + + OnOutputListUpdate(this); + + QJsonArray textureArray = data["textures"].toArray(); + for (const auto& textureDocRef : textureArray) + { + QJsonObject textureDoc = textureDocRef.toObject(); + + TextureEntry& texture = m_textures.emplace_back(); + texture.name = textureDoc["name"].toString().toStdString(); + texture.type = DecodeEnum(textureDoc["type"].toString().toStdString()).value(); + } + + OnTextureListUpdate(this); + + for (QJsonValueRef node : data["nodes"].toArray()) + m_flowScene.restoreNode(node.toObject()); + + for (QJsonValueRef connection : data["connections"].toArray()) + m_flowScene.restoreConnection(connection.toObject()); +} + +QJsonObject ShaderGraph::Save() +{ + QJsonObject sceneJson; + + QJsonArray inputArray; + { + for (const auto& input : m_inputs) + { + QJsonObject inputDoc; + inputDoc["name"] = QString::fromStdString(input.name); + inputDoc["role"] = QString(EnumToString(input.role)); + inputDoc["roleIndex"] = int(input.roleIndex); + inputDoc["type"] = QString(EnumToString(input.type)); + + inputArray.append(inputDoc); + } + } + sceneJson["inputs"] = inputArray; + + QJsonArray outputArray; + { + for (const auto& output : m_outputs) + { + QJsonObject outputDoc; + outputDoc["name"] = QString::fromStdString(output.name); + outputDoc["type"] = QString(EnumToString(output.type)); + + outputArray.append(outputDoc); + } + } + sceneJson["outputs"] = outputArray; + + QJsonArray textureArray; + { + for (const auto& texture : m_textures) + { + QJsonObject textureDoc; + textureDoc["name"] = QString::fromStdString(texture.name); + textureDoc["type"] = QString(EnumToString(texture.type)); + + textureArray.append(textureDoc); + } + } + sceneJson["textures"] = textureArray; + + QJsonArray nodesJsonArray; + { + for (auto&& [uuid, node] : m_flowScene.nodes()) + nodesJsonArray.append(node->save()); + } + sceneJson["nodes"] = nodesJsonArray; + + QJsonArray connectionJsonArray; + { + for (auto&& [uuid, connection] : m_flowScene.connections()) + { + QJsonObject connectionJson = connection->save(); + + if (!connectionJson.isEmpty()) + connectionJsonArray.append(connectionJson); + } + } + sceneJson["connections"] = connectionJsonArray; + + return sceneJson; +} + Nz::ShaderAst::StatementPtr ShaderGraph::ToAst() { std::vector statements; diff --git a/src/ShaderNode/ShaderGraph.hpp b/src/ShaderNode/ShaderGraph.hpp index 854d5cfb7..536a01dcc 100644 --- a/src/ShaderNode/ShaderGraph.hpp +++ b/src/ShaderNode/ShaderGraph.hpp @@ -27,6 +27,8 @@ class ShaderGraph std::size_t AddOutput(std::string name, InOutType type); std::size_t AddTexture(std::string name, TextureType type); + void Clear(); + inline const InputEntry& GetInput(std::size_t inputIndex) const; inline std::size_t GetInputCount() const; inline const std::vector& GetInputs() const; @@ -39,6 +41,9 @@ class ShaderGraph inline std::size_t GetTextureCount() const; inline const std::vector& GetTextures() const; + void Load(const QJsonObject& data); + QJsonObject Save(); + Nz::ShaderAst::StatementPtr ToAst(); void UpdateInput(std::size_t inputIndex, std::string name, InOutType type, InputRole role, std::size_t roleIndex); diff --git a/src/ShaderNode/Widgets/MainWindow.cpp b/src/ShaderNode/Widgets/MainWindow.cpp index 505c1f285..c30007f14 100644 --- a/src/ShaderNode/Widgets/MainWindow.cpp +++ b/src/ShaderNode/Widgets/MainWindow.cpp @@ -6,7 +6,10 @@ #include #include #include +#include +#include #include +#include #include #include #include @@ -77,7 +80,19 @@ m_shaderGraph(graph) void MainWindow::BuildMenu() { - QMenu* compileMenu = menuBar()->addMenu(tr("&Compilation")); + QMenuBar* menu = menuBar(); + + QMenu* shader = menu->addMenu(tr("&Shader")); + { + QtNodes::FlowScene* scene = &m_shaderGraph.GetScene(); + + QAction* loadShader = shader->addAction(tr("Load...")); + QObject::connect(loadShader, &QAction::triggered, this, &MainWindow::OnLoad); + QAction* saveShader = shader->addAction(tr("Save...")); + QObject::connect(saveShader, &QAction::triggered, this, &MainWindow::OnSave); + } + + QMenu* compileMenu = menu->addMenu(tr("&Compilation")); QAction* compileToGlsl = compileMenu->addAction(tr("GLSL")); connect(compileToGlsl, &QAction::triggered, [&](bool) { OnCompileToGLSL(); }); } @@ -103,3 +118,48 @@ void MainWindow::OnCompileToGLSL() QMessageBox::critical(this, tr("Compilation failed"), QString("Compilation failed: ") + e.what()); } } + +void MainWindow::OnLoad() +{ + QString fileName = QFileDialog::getOpenFileName(this, tr("Open shader flow"), QDir::homePath(), tr("Shader Flow Files (*.shaderflow)")); + if (fileName.isEmpty()) + return; + + QFile file(fileName); + if (!file.open(QIODevice::ReadOnly)) + { + QMessageBox::critical(this, tr("Failed to open file"), QString("Failed to open shader flow file: ") + file.errorString()); + return; + } + + QJsonObject jsonDocument = QJsonDocument::fromJson(file.readAll()).object(); + if (jsonDocument.isEmpty()) + { + QMessageBox::critical(this, tr("Invalid file"), tr("Invalid shader flow file")); + return; + } + + try + { + m_shaderGraph.Load(jsonDocument); + } + catch (const std::exception& e) + { + QMessageBox::critical(this, tr("Invalid file"), tr("Invalid shader flow file: ") + e.what()); + return; + } +} + +void MainWindow::OnSave() +{ + QString fileName = QFileDialog::getSaveFileName(nullptr, tr("Open shader flow"), QDir::homePath(), tr("Shader Flow Files (*.shaderflow)")); + if (fileName.isEmpty()) + return; + + if (!fileName.endsWith("flow", Qt::CaseInsensitive)) + fileName += ".shaderflow"; + + QFile file(fileName); + if (file.open(QIODevice::WriteOnly)) + file.write(QJsonDocument(m_shaderGraph.Save()).toJson()); +} diff --git a/src/ShaderNode/Widgets/MainWindow.hpp b/src/ShaderNode/Widgets/MainWindow.hpp index 777c3b92b..ff8b307c1 100644 --- a/src/ShaderNode/Widgets/MainWindow.hpp +++ b/src/ShaderNode/Widgets/MainWindow.hpp @@ -18,6 +18,8 @@ class MainWindow : public QMainWindow private: void BuildMenu(); void OnCompileToGLSL(); + void OnLoad(); + void OnSave(); NazaraSlot(ShaderGraph, OnSelectedNodeUpdate, m_onSelectedNodeUpdate); From de1c64253e6b9b49d426d96c602c5902373e5259 Mon Sep 17 00:00:00 2001 From: Lynix Date: Thu, 4 Jun 2020 18:31:43 +0200 Subject: [PATCH 030/105] Fix missing files --- include/Nazara/Renderer/ShaderWriter.hpp | 1 + src/Nazara/Renderer/GlslWriter.cpp | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/include/Nazara/Renderer/ShaderWriter.hpp b/include/Nazara/Renderer/ShaderWriter.hpp index 634c335ec..1058fa924 100644 --- a/include/Nazara/Renderer/ShaderWriter.hpp +++ b/include/Nazara/Renderer/ShaderWriter.hpp @@ -34,6 +34,7 @@ namespace Nz virtual void Write(const ShaderAst::AssignOp& node) = 0; virtual void Write(const ShaderAst::Branch& node) = 0; + virtual void Write(const ShaderAst::BinaryFunc& node) = 0; virtual void Write(const ShaderAst::BinaryOp& node) = 0; virtual void Write(const ShaderAst::BuiltinVariable& node) = 0; virtual void Write(const ShaderAst::Cast& node) = 0; diff --git a/src/Nazara/Renderer/GlslWriter.cpp b/src/Nazara/Renderer/GlslWriter.cpp index 73abec55f..b37b9deff 100644 --- a/src/Nazara/Renderer/GlslWriter.cpp +++ b/src/Nazara/Renderer/GlslWriter.cpp @@ -173,6 +173,26 @@ namespace Nz } } + void GlslWriter::Write(const ShaderAst::BinaryFunc& node) + { + switch (node.intrinsic) + { + case ShaderAst::BinaryIntrinsic::CrossProduct: + Append("cross"); + break; + + case ShaderAst::BinaryIntrinsic::DotProduct: + Append("dot"); + break; + } + + Append("("); + Write(node.left); + Append(", "); + Write(node.right); + Append(")"); + } + void GlslWriter::Write(const ShaderAst::BinaryOp& node) { Write(node.left); From 8467c79021982804d951191ced9a36b6ac28698a Mon Sep 17 00:00:00 2001 From: Lynix Date: Fri, 5 Jun 2020 19:47:29 +0200 Subject: [PATCH 031/105] Renderer: Add shader serialization --- include/Nazara/Renderer/GlslWriter.hpp | 28 +- include/Nazara/Renderer/ShaderAst.hpp | 318 +++++++++------- include/Nazara/Renderer/ShaderAst.inl | 364 ++++++++++-------- include/Nazara/Renderer/ShaderBuilder.inl | 16 +- include/Nazara/Renderer/ShaderSerializer.hpp | 111 ++++++ include/Nazara/Renderer/ShaderSerializer.inl | 79 ++++ include/Nazara/Renderer/ShaderVisitor.hpp | 50 +++ include/Nazara/Renderer/ShaderWriter.hpp | 29 +- src/Nazara/Renderer/GlslWriter.cpp | 65 ++-- src/Nazara/Renderer/Renderer.cpp | 2 +- src/Nazara/Renderer/ShaderAst.cpp | 91 ++--- src/Nazara/Renderer/ShaderSerializer.cpp | 376 +++++++++++++++++++ src/Nazara/Renderer/ShaderVisitor.cpp | 29 ++ src/Nazara/Renderer/ShaderWriter.cpp | 14 - src/ShaderNode/ShaderGraph.cpp | 2 +- 15 files changed, 1131 insertions(+), 443 deletions(-) create mode 100644 include/Nazara/Renderer/ShaderSerializer.hpp create mode 100644 include/Nazara/Renderer/ShaderSerializer.inl create mode 100644 include/Nazara/Renderer/ShaderVisitor.hpp create mode 100644 src/Nazara/Renderer/ShaderSerializer.cpp create mode 100644 src/Nazara/Renderer/ShaderVisitor.cpp diff --git a/include/Nazara/Renderer/GlslWriter.hpp b/include/Nazara/Renderer/GlslWriter.hpp index 373a9950e..2caaa6a75 100644 --- a/include/Nazara/Renderer/GlslWriter.hpp +++ b/include/Nazara/Renderer/GlslWriter.hpp @@ -31,20 +31,20 @@ namespace Nz void SetGlslVersion(unsigned int version); - void Write(const ShaderAst::AssignOp& node) override; - void Write(const ShaderAst::Branch& node) override; - void Write(const ShaderAst::BinaryFunc& node) override; - void Write(const ShaderAst::BinaryOp& node) override; - void Write(const ShaderAst::BuiltinVariable& node) override; - void Write(const ShaderAst::Cast& node) override; - void Write(const ShaderAst::Constant& node) override; - void Write(const ShaderAst::DeclareVariable& node) override; - void Write(const ShaderAst::ExpressionStatement& node) override; - void Write(const ShaderAst::NamedVariable& node) override; - void Write(const ShaderAst::NodePtr& node) override; - void Write(const ShaderAst::Sample2D& node) override; - void Write(const ShaderAst::StatementBlock& node) override; - void Write(const ShaderAst::SwizzleOp& node) override; + using ShaderWriter::Visit; + void Visit(const ShaderAst::AssignOp& node) override; + void Visit(const ShaderAst::Branch& node) override; + void Visit(const ShaderAst::BinaryFunc& node) override; + void Visit(const ShaderAst::BinaryOp& node) override; + void Visit(const ShaderAst::BuiltinVariable& node) override; + void Visit(const ShaderAst::Cast& node) override; + void Visit(const ShaderAst::Constant& node) override; + void Visit(const ShaderAst::DeclareVariable& node) override; + void Visit(const ShaderAst::ExpressionStatement& node) override; + void Visit(const ShaderAst::NamedVariable& node) override; + void Visit(const ShaderAst::Sample2D& node) override; + void Visit(const ShaderAst::StatementBlock& node) override; + void Visit(const ShaderAst::SwizzleOp& node) override; private: struct Function; diff --git a/include/Nazara/Renderer/ShaderAst.hpp b/include/Nazara/Renderer/ShaderAst.hpp index 6dd43ea89..0bbaec9f3 100644 --- a/include/Nazara/Renderer/ShaderAst.hpp +++ b/include/Nazara/Renderer/ShaderAst.hpp @@ -17,6 +17,8 @@ namespace Nz { + class ByteStream; + class ShaderVisitor; class ShaderWriter; namespace ShaderAst @@ -66,6 +68,26 @@ namespace Nz Void // void }; + enum class NodeType + { + None = -1, + + AssignOp, + BinaryFunc, + BinaryOp, + Branch, + BuiltinVariable, + Cast, + Constant, + ConditionalStatement, + DeclareVariable, + ExpressionStatement, + NamedVariable, + Sample2D, + SwizzleOp, + StatementBlock + }; + enum class SwizzleComponent { First, @@ -93,13 +115,21 @@ namespace Nz class NAZARA_RENDERER_API Node { public: - virtual ~Node() = default; + virtual ~Node(); + + inline NodeType GetType() const; virtual void Register(ShaderWriter& visitor) = 0; - virtual void Visit(ShaderWriter& visitor) = 0; + virtual void Visit(ShaderVisitor& visitor) = 0; static inline unsigned int GetComponentCount(ExpressionType type); static inline ExpressionType GetComponentType(ExpressionType type); + + protected: + inline Node(NodeType type); + + private: + NodeType m_type; }; class Statement; @@ -108,6 +138,8 @@ namespace Nz class NAZARA_RENDERER_API Statement : public Node { + public: + using Node::Node; }; class Expression; @@ -117,236 +149,250 @@ namespace Nz class NAZARA_RENDERER_API Expression : public Node { public: + using Node::Node; + virtual ExpressionCategory GetExpressionCategory() const; virtual ExpressionType GetExpressionType() const = 0; }; - class NAZARA_RENDERER_API ExpressionStatement : public Statement + struct NAZARA_RENDERER_API ExpressionStatement : public Statement { - public: - inline explicit ExpressionStatement(ExpressionPtr expr); + inline ExpressionStatement(); - void Register(ShaderWriter& visitor) override; - void Visit(ShaderWriter& visitor) override; + void Register(ShaderWriter& visitor) override; + void Visit(ShaderVisitor& visitor) override; - ExpressionPtr expression; + ExpressionPtr expression; + + static inline std::shared_ptr Build(ExpressionPtr expr); }; ////////////////////////////////////////////////////////////////////////// - class NAZARA_RENDERER_API ConditionalStatement : public Statement + struct NAZARA_RENDERER_API ConditionalStatement : public Statement { - public: - inline ConditionalStatement(const String& condition, StatementPtr statementPtr); + inline ConditionalStatement(); - void Register(ShaderWriter& visitor) override; - void Visit(ShaderWriter& visitor) override; + void Register(ShaderWriter& visitor) override; + void Visit(ShaderVisitor& visitor) override; - String conditionName; - StatementPtr statement; + std::string conditionName; + StatementPtr statement; + + static inline std::shared_ptr Build(std::string condition, StatementPtr statementPtr); }; - class NAZARA_RENDERER_API StatementBlock : public Statement + struct NAZARA_RENDERER_API StatementBlock : public Statement { - public: - template explicit StatementBlock(Args&&... args); + inline StatementBlock(); - void Register(ShaderWriter& visitor) override; - void Visit(ShaderWriter& visitor) override; + void Register(ShaderWriter& visitor) override; + void Visit(ShaderVisitor& visitor) override; - std::vector statements; + std::vector statements; + + template static std::shared_ptr Build(Args&&... args); }; - class Variable; + struct Variable; using VariablePtr = std::shared_ptr; - class NAZARA_RENDERER_API Variable : public Expression + struct NAZARA_RENDERER_API Variable : public Expression { - public: - inline Variable(VariableType varKind, ExpressionType varType); + using Expression::Expression; - ExpressionCategory GetExpressionCategory() const override; - ExpressionType GetExpressionType() const override; + ExpressionCategory GetExpressionCategory() const override; + ExpressionType GetExpressionType() const override; - ExpressionType type; - VariableType kind; + ExpressionType type; + VariableType kind; }; - class NAZARA_RENDERER_API BuiltinVariable : public Variable + struct NAZARA_RENDERER_API BuiltinVariable : public Variable { - public: - inline BuiltinVariable(BuiltinEntry variable, ExpressionType varType); + inline BuiltinVariable(); - void Register(ShaderWriter& visitor) override; - void Visit(ShaderWriter& visitor) override; + void Register(ShaderWriter& visitor) override; + void Visit(ShaderVisitor& visitor) override; - BuiltinEntry var; + BuiltinEntry var; + + static inline std::shared_ptr Build(BuiltinEntry variable, ExpressionType varType); }; - class NamedVariable; + struct NamedVariable; using NamedVariablePtr = std::shared_ptr; - class NAZARA_RENDERER_API NamedVariable : public Variable + struct NAZARA_RENDERER_API NamedVariable : public Variable { - public: - inline NamedVariable(VariableType varKind, const Nz::String& varName, ExpressionType varType); + inline NamedVariable(); - void Register(ShaderWriter& visitor) override; - void Visit(ShaderWriter& visitor) override; + void Register(ShaderWriter& visitor) override; + void Visit(ShaderVisitor& visitor) override; - Nz::String name; + std::string name; + + static inline std::shared_ptr Build(VariableType varType, std::string varName, ExpressionType expressionType); }; - class NAZARA_RENDERER_API DeclareVariable : public Statement + struct NAZARA_RENDERER_API DeclareVariable : public Statement { - public: - inline DeclareVariable(NamedVariablePtr Variable, ExpressionPtr Expression = nullptr); + inline DeclareVariable(); - void Register(ShaderWriter& visitor) override; - void Visit(ShaderWriter& visitor) override; + void Register(ShaderWriter& visitor) override; + void Visit(ShaderVisitor& visitor) override; - NamedVariablePtr variable; - ExpressionPtr expression; + NamedVariablePtr variable; + ExpressionPtr expression; + + static inline std::shared_ptr Build(NamedVariablePtr variable, ExpressionPtr expression = nullptr); }; ////////////////////////////////////////////////////////////////////////// - class NAZARA_RENDERER_API AssignOp : public Expression + struct NAZARA_RENDERER_API AssignOp : public Expression { - public: - inline AssignOp(AssignType Op, ExpressionPtr Left, ExpressionPtr Right); + inline AssignOp(); - ExpressionType GetExpressionType() const override; - void Register(ShaderWriter& visitor) override; - void Visit(ShaderWriter& visitor) override; + ExpressionType GetExpressionType() const override; + void Register(ShaderWriter& visitor) override; + void Visit(ShaderVisitor& visitor) override; - AssignType op; - ExpressionPtr left; - ExpressionPtr right; + AssignType op; + ExpressionPtr left; + ExpressionPtr right; + + static inline std::shared_ptr Build(AssignType op, ExpressionPtr left, ExpressionPtr right); }; - class NAZARA_RENDERER_API BinaryOp : public Expression + struct NAZARA_RENDERER_API BinaryOp : public Expression { - public: - inline BinaryOp(BinaryType Op, ExpressionPtr Left, ExpressionPtr Right); + inline BinaryOp(); - ExpressionType GetExpressionType() const override; - void Register(ShaderWriter& visitor) override; - void Visit(ShaderWriter& visitor) override; + ExpressionType GetExpressionType() const override; + void Register(ShaderWriter& visitor) override; + void Visit(ShaderVisitor& visitor) override; - BinaryType op; - ExpressionPtr left; - ExpressionPtr right; + BinaryType op; + ExpressionPtr left; + ExpressionPtr right; + + static inline std::shared_ptr Build(BinaryType op, ExpressionPtr left, ExpressionPtr right); }; - class NAZARA_RENDERER_API Branch : public Statement + struct NAZARA_RENDERER_API Branch : public Statement { - public: - inline Branch(ExpressionPtr condition, StatementPtr trueStatement, StatementPtr falseStatement = nullptr); + struct ConditionalStatement; - void Register(ShaderWriter& visitor) override; - void Visit(ShaderWriter& visitor) override; + inline Branch(); - struct ConditionalStatement - { - ExpressionPtr condition; - StatementPtr statement; - }; + void Register(ShaderWriter& visitor) override; + void Visit(ShaderVisitor& visitor) override; - std::vector condStatements; - StatementPtr elseStatement; + std::vector condStatements; + StatementPtr elseStatement; + + struct ConditionalStatement + { + ExpressionPtr condition; + StatementPtr statement; + }; + + inline std::shared_ptr Build(ExpressionPtr condition, StatementPtr trueStatement, StatementPtr falseStatement = nullptr); }; - class NAZARA_RENDERER_API Cast : public Expression + struct NAZARA_RENDERER_API Cast : public Expression { - public: - inline Cast(ExpressionType castTo, ExpressionPtr first, ExpressionPtr second = nullptr, ExpressionPtr third = nullptr, ExpressionPtr fourth = nullptr); - inline Cast(ExpressionType castTo, ExpressionPtr* expressions, std::size_t expressionCount); + inline Cast(); - ExpressionType GetExpressionType() const override; - void Register(ShaderWriter& visitor) override; - void Visit(ShaderWriter& visitor) override; + ExpressionType GetExpressionType() const override; + void Register(ShaderWriter& visitor) override; + void Visit(ShaderVisitor& visitor) override; - ExpressionType exprType; - std::array expressions; + ExpressionType exprType; + std::array expressions; - private: - void Validate() const; + static inline std::shared_ptr Build(ExpressionType castTo, ExpressionPtr first, ExpressionPtr second = nullptr, ExpressionPtr third = nullptr, ExpressionPtr fourth = nullptr); + static inline std::shared_ptr Build(ExpressionType castTo, ExpressionPtr* expressions, std::size_t expressionCount); }; - class NAZARA_RENDERER_API Constant : public Expression + struct NAZARA_RENDERER_API Constant : public Expression { - public: - inline explicit Constant(bool value); - inline explicit Constant(float value); - inline explicit Constant(const Vector2f& value); - inline explicit Constant(const Vector3f& value); - inline explicit Constant(const Vector4f& value); + inline Constant(); - ExpressionType GetExpressionType() const override; - void Register(ShaderWriter& visitor) override; - void Visit(ShaderWriter& visitor) override; + ExpressionType GetExpressionType() const override; + void Register(ShaderWriter& visitor) override; + void Visit(ShaderVisitor& visitor) override; - ExpressionType exprType; + ExpressionType exprType; - union - { - bool bool1; - float vec1; - Vector2f vec2; - Vector3f vec3; - Vector4f vec4; - } values; + union + { + bool bool1; + float vec1; + Vector2f vec2; + Vector3f vec3; + Vector4f vec4; + } values; + + static inline std::shared_ptr Build(bool value); + static inline std::shared_ptr Build(float value); + static inline std::shared_ptr Build(const Vector2f& value); + static inline std::shared_ptr Build(const Vector3f& value); + static inline std::shared_ptr Build(const Vector4f& value); }; - class NAZARA_RENDERER_API SwizzleOp : public Expression + struct NAZARA_RENDERER_API SwizzleOp : public Expression { - public: - inline SwizzleOp(ExpressionPtr expressionPtr, std::initializer_list swizzleComponents); + inline SwizzleOp(); - ExpressionCategory GetExpressionCategory() const override; - ExpressionType GetExpressionType() const override; - void Register(ShaderWriter& visitor) override; - void Visit(ShaderWriter& visitor) override; + ExpressionCategory GetExpressionCategory() const override; + ExpressionType GetExpressionType() const override; + void Register(ShaderWriter& visitor) override; + void Visit(ShaderVisitor& visitor) override; - std::array components; - std::size_t componentCount; - ExpressionPtr expression; + std::array components; + std::size_t componentCount; + ExpressionPtr expression; + + static inline std::shared_ptr Build(ExpressionPtr expressionPtr, std::initializer_list swizzleComponents); }; ////////////////////////////////////////////////////////////////////////// - class NAZARA_RENDERER_API Sample2D : public Expression + struct NAZARA_RENDERER_API Sample2D : public Expression { - public: - inline Sample2D(ExpressionPtr samplerPtr, ExpressionPtr coordinatesPtr); + inline Sample2D(); - ExpressionType GetExpressionType() const override; - void Register(ShaderWriter& visitor) override; - void Visit(ShaderWriter& visitor) override; + ExpressionType GetExpressionType() const override; + void Register(ShaderWriter& visitor) override; + void Visit(ShaderVisitor& visitor) override; - ExpressionPtr sampler; - ExpressionPtr coordinates; + ExpressionPtr sampler; + ExpressionPtr coordinates; + + static inline std::shared_ptr Build(ExpressionPtr samplerPtr, ExpressionPtr coordinatesPtr); }; ////////////////////////////////////////////////////////////////////////// - class NAZARA_RENDERER_API BinaryFunc : public Expression + struct NAZARA_RENDERER_API BinaryFunc : public Expression { - public: - inline BinaryFunc(BinaryIntrinsic Op, ExpressionPtr Left, ExpressionPtr Right); + inline BinaryFunc(); - ExpressionType GetExpressionType() const override; - void Register(ShaderWriter& visitor) override; - void Visit(ShaderWriter& visitor) override; + ExpressionType GetExpressionType() const override; + void Register(ShaderWriter& visitor) override; + void Visit(ShaderVisitor& visitor) override; - BinaryIntrinsic intrinsic; - ExpressionPtr left; - ExpressionPtr right; + BinaryIntrinsic intrinsic; + ExpressionPtr left; + ExpressionPtr right; + + static inline std::shared_ptr Build(BinaryIntrinsic intrinsic, ExpressionPtr left, ExpressionPtr right); }; } } diff --git a/include/Nazara/Renderer/ShaderAst.inl b/include/Nazara/Renderer/ShaderAst.inl index 958baecfe..536758832 100644 --- a/include/Nazara/Renderer/ShaderAst.inl +++ b/include/Nazara/Renderer/ShaderAst.inl @@ -9,6 +9,16 @@ namespace Nz { namespace ShaderAst { + inline Node::Node(NodeType type) : + m_type(type) + { + } + + inline NodeType ShaderAst::Node::GetType() const + { + return m_type; + } + inline unsigned int Node::GetComponentCount(ExpressionType type) { switch (type) @@ -47,224 +57,264 @@ namespace Nz } } - inline ExpressionStatement::ExpressionStatement(ExpressionPtr expr) : - expression(std::move(expr)) + inline ExpressionStatement::ExpressionStatement() : + Statement(NodeType::ExpressionStatement) + { + } + + inline std::shared_ptr ExpressionStatement::Build(ExpressionPtr expr) + { + auto node = std::make_shared(); + node->expression = std::move(expr); + + return node; + } + + inline ConditionalStatement::ConditionalStatement() : + Statement(NodeType::ConditionalStatement) { } - inline ConditionalStatement::ConditionalStatement(const String& condition, StatementPtr statementPtr) : - conditionName(condition), - statement(std::move(statementPtr)) + inline std::shared_ptr ConditionalStatement::Build(std::string condition, StatementPtr statementPtr) + { + auto node = std::make_shared(); + node->conditionName = std::move(condition); + node->statement = std::move(statementPtr); + + return node; + } + + + inline StatementBlock::StatementBlock() : + Statement(NodeType::StatementBlock) { } template - StatementBlock::StatementBlock(Args&& ...args) : - statements({std::forward(args)...}) + std::shared_ptr StatementBlock::Build(Args&&... args) + { + auto node = std::make_shared(); + node->statements = std::vector({ std::forward(args)... }); + + return node; + } + + + inline BuiltinVariable::BuiltinVariable() : + Variable(NodeType::BuiltinVariable) + { + kind = VariableType::Builtin; + } + + inline std::shared_ptr BuiltinVariable::Build(BuiltinEntry variable, ExpressionType varType) + { + auto node = std::make_shared(); + node->type = varType; + node->var = variable; + + return node; + } + + + inline NamedVariable::NamedVariable() : + Variable(NodeType::NamedVariable) { } - inline Variable::Variable(VariableType varKind, ExpressionType varType) : - type(varType), - kind(varKind) + inline std::shared_ptr NamedVariable::Build(VariableType type, std::string varName, ExpressionType expressionType) + { + auto node = std::make_shared(); + node->kind = type; + node->name = std::move(varName); + node->type = expressionType; + + return node; + } + + + inline DeclareVariable::DeclareVariable() : + Statement(NodeType::DeclareVariable) { } - inline BuiltinVariable::BuiltinVariable(BuiltinEntry variable, ExpressionType varType) : - Variable(VariableType::Builtin, varType), - var(variable) + inline std::shared_ptr DeclareVariable::Build(NamedVariablePtr variable, ExpressionPtr expression) + { + auto node = std::make_shared(); + node->expression = std::move(expression); + node->variable = std::move(variable); + + return node; + } + + + inline AssignOp::AssignOp() : + Expression(NodeType::AssignOp) { } - inline NamedVariable::NamedVariable(VariableType varKind, const Nz::String& varName, ExpressionType varType) : - Variable(varKind, varType), - name(varName) + inline std::shared_ptr AssignOp::Build(AssignType op, ExpressionPtr left, ExpressionPtr right) + { + auto node = std::make_shared(); + node->op = op; + node->left = std::move(left); + node->right = std::move(right); + + return node; + } + + + inline BinaryOp::BinaryOp() : + Expression(NodeType::BinaryOp) { } - inline DeclareVariable::DeclareVariable(NamedVariablePtr Variable, ExpressionPtr Expression) : - expression(std::move(Expression)), - variable(std::move(Variable)) + inline std::shared_ptr BinaryOp::Build(BinaryType op, ExpressionPtr left, ExpressionPtr right) + { + auto node = std::make_shared(); + node->op = op; + node->left = std::move(left); + node->right = std::move(right); + + return node; + } + + + inline Branch::Branch() : + Statement(NodeType::Branch) { } - inline AssignOp::AssignOp(AssignType Op, ExpressionPtr Left, ExpressionPtr Right) : - op(Op), - left(std::move(Left)), - right(std::move(Right)) + inline std::shared_ptr Branch::Build(ExpressionPtr condition, StatementPtr trueStatement, StatementPtr falseStatement) { - if (left->GetExpressionCategory() != ExpressionCategory::LValue) - //TODO: AstParseError - throw std::runtime_error("Assignation is only possible with lvalues"); + auto node = std::make_shared(); + node->condStatements.emplace_back(ConditionalStatement{ std::move(condition), std::move(trueStatement) }); + node->elseStatement = std::move(falseStatement); + + return node; } - inline BinaryOp::BinaryOp(BinaryType Op, ExpressionPtr Left, ExpressionPtr Right) : - op(Op), - left(std::move(Left)), - right(std::move(Right)) + + inline Cast::Cast() : + Expression(NodeType::Cast) { - ExpressionType leftType = left->GetExpressionType(); - ExpressionType rightType = right->GetExpressionType(); - - if (leftType != rightType) - { - switch (op) - { - case BinaryType::Add: - case BinaryType::Equality: - case BinaryType::Substract: - { - //TODO: AstParseError - throw std::runtime_error("Left expression type must match right expression type"); - } - - case BinaryType::Multiply: - case BinaryType::Divide: - { - switch (leftType) - { - case ExpressionType::Float2: - case ExpressionType::Float3: - case ExpressionType::Float4: - { - if (rightType != ExpressionType::Float1) - throw std::runtime_error("Left expression type is not compatible with right expression type"); - - break; - } - - case ExpressionType::Mat4x4: - { - switch (rightType) - { - case ExpressionType::Float1: - case ExpressionType::Float4: - case ExpressionType::Mat4x4: - break; - - //TODO: AstParseError - default: - throw std::runtime_error("Left expression type is not compatible with right expression type"); - } - - break; - } - - default: - //TODO: AstParseError - throw std::runtime_error("Left expression type must match right expression type"); - } - } - } - } } - inline Branch::Branch(ExpressionPtr condition, StatementPtr trueStatement, StatementPtr falseStatement) + inline std::shared_ptr Cast::Build(ExpressionType castTo, ExpressionPtr first, ExpressionPtr second, ExpressionPtr third, ExpressionPtr fourth) { - condStatements.emplace_back(ConditionalStatement{ std::move(condition), std::move(trueStatement) }); - elseStatement = std::move(falseStatement); + auto node = std::make_shared(); + node->exprType = castTo; + node->expressions = { {first, second, third, fourth} }; + + return node; } - inline Cast::Cast(ExpressionType castTo, ExpressionPtr first, ExpressionPtr second, ExpressionPtr third, ExpressionPtr fourth) : - exprType(castTo), - expressions({ {first, second, third, fourth} }) - { - Validate(); - } - - inline Cast::Cast(ExpressionType castTo, ExpressionPtr* Expressions, std::size_t expressionCount) : - exprType(castTo) + inline std::shared_ptr Cast::Build(ExpressionType castTo, ExpressionPtr* Expressions, std::size_t expressionCount) { + auto node = std::make_shared(); + node->exprType = castTo; for (std::size_t i = 0; i < expressionCount; ++i) - expressions[i] = Expressions[i]; + node->expressions[i] = Expressions[i]; - Validate(); + return node; } - inline Constant::Constant(bool value) : - exprType(ExpressionType::Boolean) + + inline Constant::Constant() : + Expression(NodeType::Constant) { - values.bool1 = value; } - inline Constant::Constant(float value) : - exprType(ExpressionType::Float1) + inline std::shared_ptr Constant::Build(bool value) { - values.vec1 = value; + auto node = std::make_shared(); + node->exprType = ExpressionType::Boolean; + node->values.bool1 = value; + + return node; } - inline Constant::Constant(const Vector2f& value) : - exprType(ExpressionType::Float2) + inline std::shared_ptr Constant::Build(float value) { - values.vec2 = value; + auto node = std::make_shared(); + node->exprType = ExpressionType::Float1; + node->values.vec1 = value; + + return node; } - inline Constant::Constant(const Vector3f& value) : - exprType(ExpressionType::Float3) + inline std::shared_ptr Constant::Build(const Vector2f& value) { - values.vec3 = value; + auto node = std::make_shared(); + node->exprType = ExpressionType::Float2; + node->values.vec2 = value; + + return node; } - inline Constant::Constant(const Vector4f& value) : - exprType(ExpressionType::Float4) + inline std::shared_ptr Constant::Build(const Vector3f& value) { - values.vec4 = value; + auto node = std::make_shared(); + node->exprType = ExpressionType::Float3; + node->values.vec3 = value; + + return node; } - inline SwizzleOp::SwizzleOp(ExpressionPtr expressionPtr, std::initializer_list swizzleComponents) : - componentCount(swizzleComponents.size()), - expression(expressionPtr) + inline std::shared_ptr Constant::Build(const Vector4f& value) { - if (componentCount > 4) - throw std::runtime_error("Cannot swizzle more than four elements"); + auto node = std::make_shared(); + node->exprType = ExpressionType::Float4; + node->values.vec4 = value; - switch (expressionPtr->GetExpressionType()) - { - case ExpressionType::Float1: - case ExpressionType::Float2: - case ExpressionType::Float3: - case ExpressionType::Float4: - break; - - default: - throw std::runtime_error("Cannot swizzle this type"); - } - - std::copy(swizzleComponents.begin(), swizzleComponents.end(), components.begin()); + return node; } - inline Sample2D::Sample2D(ExpressionPtr samplerPtr, ExpressionPtr coordinatesPtr) : - sampler(std::move(samplerPtr)), - coordinates(std::move(coordinatesPtr)) - { - if (sampler->GetExpressionType() != ExpressionType::Sampler2D) - throw std::runtime_error("Sampler must be a Sampler2D"); - if (coordinates->GetExpressionType() != ExpressionType::Float2) - throw std::runtime_error("Coordinates must be a Float2"); + inline SwizzleOp::SwizzleOp() : + Expression(NodeType::SwizzleOp) + { } - inline BinaryFunc::BinaryFunc(BinaryIntrinsic Op, ExpressionPtr Left, ExpressionPtr Right) : - intrinsic(Op), - left(Left), - right(Right) + inline std::shared_ptr SwizzleOp::Build(ExpressionPtr expressionPtr, std::initializer_list swizzleComponents) { - ExpressionType leftType = left->GetExpressionType(); - ExpressionType rightType = right->GetExpressionType(); + auto node = std::make_shared(); + node->componentCount = swizzleComponents.size(); + node->expression = std::move(expressionPtr); - if (leftType != rightType) - //TODO: AstParseError - throw std::runtime_error("Left expression type must match right expression type"); + std::copy(swizzleComponents.begin(), swizzleComponents.end(), node->components.begin()); - switch (intrinsic) - { - case BinaryIntrinsic::CrossProduct: - { - if (leftType != ExpressionType::Float3) - //TODO: AstParseError - throw std::runtime_error("CrossProduct only works with Float3 expressions"); - } - } + return node; + } + + + inline Sample2D::Sample2D() : + Expression(NodeType::Sample2D) + { + } + + inline std::shared_ptr Sample2D::Build(ExpressionPtr samplerPtr, ExpressionPtr coordinatesPtr) + { + auto node = std::make_shared(); + node->coordinates = std::move(coordinatesPtr); + node->sampler = std::move(samplerPtr); + + return node; + } + + + inline BinaryFunc::BinaryFunc() : + Expression(NodeType::BinaryFunc) + { + } + + inline std::shared_ptr BinaryFunc::Build(BinaryIntrinsic intrinsic, ExpressionPtr left, ExpressionPtr right) + { + auto node = std::make_shared(); + node->intrinsic = intrinsic; + node->left = std::move(left); + node->right = std::move(right); + + return node; } } } diff --git a/include/Nazara/Renderer/ShaderBuilder.inl b/include/Nazara/Renderer/ShaderBuilder.inl index 76f00d394..7f9612a11 100644 --- a/include/Nazara/Renderer/ShaderBuilder.inl +++ b/include/Nazara/Renderer/ShaderBuilder.inl @@ -5,25 +5,25 @@ #include #include -namespace Nz { namespace ShaderBuilder +namespace Nz::ShaderBuilder { template template std::shared_ptr GenBuilder::operator()(Args&&... args) const { - return std::make_shared(std::forward(args)...); + return T::Build(std::forward(args)...); } template std::shared_ptr AssignOpBuilder::operator()(const ShaderAst::ExpressionPtr& left, const ShaderAst::ExpressionPtr& right) const { - return std::make_shared(op, left, right); + return ShaderAst::AssignOp::Build(op, left, right); } template std::shared_ptr BinOpBuilder::operator()(const ShaderAst::ExpressionPtr& left, const ShaderAst::ExpressionPtr& right) const { - return std::make_shared(op, left, right); + return ShaderAst::BinaryOp::Build(op, left, right); } inline std::shared_ptr BuiltinBuilder::operator()(ShaderAst::BuiltinEntry builtin) const @@ -39,21 +39,21 @@ namespace Nz { namespace ShaderBuilder NazaraAssert(exprType != ShaderAst::ExpressionType::Void, "Unhandled builtin"); - return std::make_shared(builtin, exprType); + return ShaderAst::BuiltinVariable::Build(builtin, exprType); } template template ShaderAst::NamedVariablePtr VarBuilder::operator()(Args&&... args) const { - return std::make_shared(type, std::forward(args)...); + return ShaderAst::NamedVariable::Build(type, std::forward(args)...); } template std::shared_ptr Cast(Args&&... args) { - return std::make_shared(Type, std::forward(args)...); + return ShaderAst::Cast::Build(Type, std::forward(args)...); } -} } +} #include diff --git a/include/Nazara/Renderer/ShaderSerializer.hpp b/include/Nazara/Renderer/ShaderSerializer.hpp new file mode 100644 index 000000000..521284370 --- /dev/null +++ b/include/Nazara/Renderer/ShaderSerializer.hpp @@ -0,0 +1,111 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Renderer module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_SHADERSERIALIZER_HPP +#define NAZARA_SHADERSERIALIZER_HPP + +#include +#include +#include +#include +#include + +namespace Nz::ShaderAst +{ + class NAZARA_RENDERER_API ShaderSerializerBase + { + public: + ShaderSerializerBase() = default; + ShaderSerializerBase(const ShaderSerializerBase&) = delete; + ShaderSerializerBase(ShaderSerializerBase&&) = delete; + ~ShaderSerializerBase() = default; + + void Serialize(AssignOp& node); + void Serialize(BinaryFunc& node); + void Serialize(BinaryOp& node); + void Serialize(Branch& node); + void Serialize(BuiltinVariable& node); + void Serialize(Cast& node); + void Serialize(Constant& node); + void Serialize(DeclareVariable& node); + void Serialize(ExpressionStatement& node); + void Serialize(NamedVariable& node); + void Serialize(Sample2D& node); + void Serialize(StatementBlock& node); + void Serialize(SwizzleOp& node); + + protected: + template void Container(T& container); + template void Enum(T& enumVal); + + virtual bool IsWriting() const = 0; + + virtual void Node(NodePtr& node) = 0; + template void Node(std::shared_ptr& node); + + virtual void Value(bool& val) = 0; + virtual void Value(float& val) = 0; + virtual void Value(std::string& val) = 0; + virtual void Value(Vector2f& val) = 0; + virtual void Value(Vector3f& val) = 0; + virtual void Value(Vector4f& val) = 0; + virtual void Value(UInt32& val) = 0; + inline void Value(std::size_t& val); + }; + + class NAZARA_RENDERER_API ShaderSerializer final : public ShaderSerializerBase + { + public: + inline ShaderSerializer(ByteArray& byteArray); + ~ShaderSerializer() = default; + + void Serialize(const StatementPtr& shader); + + private: + bool IsWriting() const override; + void Node(NodePtr& node) override; + void Value(bool& val) override; + void Value(float& val) override; + void Value(std::string& val) override; + void Value(Vector2f& val) override; + void Value(Vector3f& val) override; + void Value(Vector4f& val) override; + void Value(UInt32& val) override; + + ByteArray& m_byteArray; + ByteStream m_stream; + }; + + class NAZARA_RENDERER_API ShaderUnserializer final : public ShaderSerializerBase + { + public: + ShaderUnserializer(const ByteArray& byteArray); + ~ShaderUnserializer() = default; + + StatementPtr Unserialize(); + + private: + bool IsWriting() const override; + void Node(NodePtr & node) override; + void Value(bool& val) override; + void Value(float& val) override; + void Value(std::string& val) override; + void Value(Vector2f& val) override; + void Value(Vector3f& val) override; + void Value(Vector4f& val) override; + void Value(UInt32& val) override; + + const ByteArray& m_byteArray; + ByteStream m_stream; + }; + + NAZARA_RENDERER_API ByteArray Serialize(const StatementPtr& shader); + NAZARA_RENDERER_API StatementPtr Unserialize(const ByteArray& data); +} + +#include + +#endif diff --git a/include/Nazara/Renderer/ShaderSerializer.inl b/include/Nazara/Renderer/ShaderSerializer.inl new file mode 100644 index 000000000..2d8f5bc85 --- /dev/null +++ b/include/Nazara/Renderer/ShaderSerializer.inl @@ -0,0 +1,79 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Renderer module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include + +namespace Nz::ShaderAst +{ + template + void ShaderSerializerBase::Container(T& container) + { + bool isWriting = IsWriting(); + + UInt32 size; + if (isWriting) + size = UInt32(container.size()); + + Value(size); + if (!isWriting) + container.resize(size); + } + + + template + void ShaderSerializerBase::Enum(T& enumVal) + { + bool isWriting = IsWriting(); + + UInt32 value; + if (isWriting) + value = static_cast(enumVal); + + Value(value); + if (!isWriting) + enumVal = static_cast(value); + } + + template + inline void ShaderSerializerBase::Node(std::shared_ptr& node) + { + bool isWriting = IsWriting(); + + NodePtr value; + if (isWriting) + value = node; + + Node(value); + if (!isWriting) + node = std::static_pointer_cast(value); + } + + inline void ShaderSerializerBase::Value(std::size_t& val) + { + bool isWriting = IsWriting(); + + UInt32 value; + if (isWriting) + value = static_cast(val); + + Value(value); + if (!isWriting) + val = static_cast(value); + } + + inline ShaderSerializer::ShaderSerializer(ByteArray& byteArray) : + m_byteArray(byteArray), + m_stream(&m_byteArray, OpenModeFlags(OpenMode_WriteOnly)) + { + } + + inline ShaderUnserializer::ShaderUnserializer(const ByteArray& byteArray) : + m_byteArray(byteArray), + m_stream(const_cast(&m_byteArray), OpenModeFlags(OpenMode_ReadOnly)) + { + } +} + +#include diff --git a/include/Nazara/Renderer/ShaderVisitor.hpp b/include/Nazara/Renderer/ShaderVisitor.hpp new file mode 100644 index 000000000..47a5741f4 --- /dev/null +++ b/include/Nazara/Renderer/ShaderVisitor.hpp @@ -0,0 +1,50 @@ +// Copyright (C) 2015 Jérôme Leclercq +// This file is part of the "Nazara Engine - Renderer module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_SHADERVISITOR_HPP +#define NAZARA_SHADERVISITOR_HPP + +#include +#include +#include +#include +#include + +namespace Nz +{ + class NAZARA_RENDERER_API ShaderVisitor + { + public: + ShaderVisitor() = default; + ShaderVisitor(const ShaderVisitor&) = delete; + ShaderVisitor(ShaderVisitor&&) = delete; + virtual ~ShaderVisitor(); + + void EnableCondition(const String& name, bool cond); + + bool IsConditionEnabled(const String& name) const; + + virtual void Visit(const ShaderAst::AssignOp& node) = 0; + virtual void Visit(const ShaderAst::BinaryFunc& node) = 0; + virtual void Visit(const ShaderAst::BinaryOp& node) = 0; + virtual void Visit(const ShaderAst::Branch& node) = 0; + virtual void Visit(const ShaderAst::BuiltinVariable& node) = 0; + virtual void Visit(const ShaderAst::Cast& node) = 0; + virtual void Visit(const ShaderAst::Constant& node) = 0; + virtual void Visit(const ShaderAst::DeclareVariable& node) = 0; + virtual void Visit(const ShaderAst::ExpressionStatement& node) = 0; + virtual void Visit(const ShaderAst::NamedVariable& node) = 0; + void Visit(const ShaderAst::NodePtr& node); + virtual void Visit(const ShaderAst::Sample2D& node) = 0; + virtual void Visit(const ShaderAst::StatementBlock& node) = 0; + virtual void Visit(const ShaderAst::SwizzleOp& node) = 0; + + private: + std::unordered_set m_conditions; + }; +} + +#endif diff --git a/include/Nazara/Renderer/ShaderWriter.hpp b/include/Nazara/Renderer/ShaderWriter.hpp index 1058fa924..ae00f2fa5 100644 --- a/include/Nazara/Renderer/ShaderWriter.hpp +++ b/include/Nazara/Renderer/ShaderWriter.hpp @@ -10,45 +10,22 @@ #include #include #include -#include -#include +#include namespace Nz { - class NAZARA_RENDERER_API ShaderWriter + class NAZARA_RENDERER_API ShaderWriter : public ShaderVisitor { public: ShaderWriter() = default; ShaderWriter(const ShaderWriter&) = delete; ShaderWriter(ShaderWriter&&) = delete; - virtual ~ShaderWriter(); - - void EnableCondition(const String& name, bool cond); - - bool IsConditionEnabled(const String& name) const; + ~ShaderWriter() = default; virtual Nz::String Generate(const ShaderAst::StatementPtr& node) = 0; virtual void RegisterFunction(const String& name, ShaderAst::StatementPtr node, std::initializer_list parameters, ShaderAst::ExpressionType ret) = 0; virtual void RegisterVariable(ShaderAst::VariableType kind, const String& name, ShaderAst::ExpressionType type) = 0; - - virtual void Write(const ShaderAst::AssignOp& node) = 0; - virtual void Write(const ShaderAst::Branch& node) = 0; - virtual void Write(const ShaderAst::BinaryFunc& node) = 0; - virtual void Write(const ShaderAst::BinaryOp& node) = 0; - virtual void Write(const ShaderAst::BuiltinVariable& node) = 0; - virtual void Write(const ShaderAst::Cast& node) = 0; - virtual void Write(const ShaderAst::Constant& node) = 0; - virtual void Write(const ShaderAst::DeclareVariable& node) = 0; - virtual void Write(const ShaderAst::ExpressionStatement& node) = 0; - virtual void Write(const ShaderAst::NamedVariable& node) = 0; - virtual void Write(const ShaderAst::NodePtr& node) = 0; - virtual void Write(const ShaderAst::Sample2D& node) = 0; - virtual void Write(const ShaderAst::StatementBlock& node) = 0; - virtual void Write(const ShaderAst::SwizzleOp& node) = 0; - - private: - std::unordered_set m_conditions; }; } diff --git a/src/Nazara/Renderer/GlslWriter.cpp b/src/Nazara/Renderer/GlslWriter.cpp index b37b9deff..e7b8f6155 100644 --- a/src/Nazara/Renderer/GlslWriter.cpp +++ b/src/Nazara/Renderer/GlslWriter.cpp @@ -116,23 +116,18 @@ namespace Nz m_glslVersion = version; } - void GlslWriter::Write(const ShaderAst::NodePtr& node) - { - node->Visit(*this); - } - - void GlslWriter::Write(const ShaderAst::Sample2D& node) + void GlslWriter::Visit(const ShaderAst::Sample2D& node) { Append("texture("); - Write(node.sampler); + Visit(node.sampler); Append(", "); - Write(node.coordinates); + Visit(node.coordinates); Append(")"); } - void GlslWriter::Write(const ShaderAst::AssignOp& node) + void GlslWriter::Visit(const ShaderAst::AssignOp& node) { - Write(node.left); + Visit(node.left); switch (node.op) { @@ -141,10 +136,10 @@ namespace Nz break; } - Write(node.right); + Visit(node.right); } - void GlslWriter::Write(const ShaderAst::Branch& node) + void GlslWriter::Visit(const ShaderAst::Branch& node) { bool first = true; for (const auto& statement : node.condStatements) @@ -153,11 +148,11 @@ namespace Nz Append("else "); Append("if ("); - Write(statement.condition); + Visit(statement.condition); AppendLine(")"); EnterScope(); - Write(statement.statement); + Visit(statement.statement); LeaveScope(); first = false; @@ -168,12 +163,12 @@ namespace Nz AppendLine("else"); EnterScope(); - Write(node.elseStatement); + Visit(node.elseStatement); LeaveScope(); } } - void GlslWriter::Write(const ShaderAst::BinaryFunc& node) + void GlslWriter::Visit(const ShaderAst::BinaryFunc& node) { switch (node.intrinsic) { @@ -187,15 +182,15 @@ namespace Nz } Append("("); - Write(node.left); + Visit(node.left); Append(", "); - Write(node.right); + Visit(node.right); Append(")"); } - void GlslWriter::Write(const ShaderAst::BinaryOp& node) + void GlslWriter::Visit(const ShaderAst::BinaryOp& node) { - Write(node.left); + Visit(node.left); switch (node.op) { @@ -216,15 +211,15 @@ namespace Nz break; } - Write(node.right); + Visit(node.right); } - void GlslWriter::Write(const ShaderAst::BuiltinVariable& node) + void GlslWriter::Visit(const ShaderAst::BuiltinVariable& node) { Append(node.var); } - void GlslWriter::Write(const ShaderAst::Cast& node) + void GlslWriter::Visit(const ShaderAst::Cast& node) { Append(node.exprType); Append("("); @@ -239,14 +234,14 @@ namespace Nz const auto& exprPtr = node.expressions[i++]; NazaraAssert(exprPtr, "Invalid expression"); - Write(exprPtr); + Visit(exprPtr); requiredComponents -= ShaderAst::Node::GetComponentCount(exprPtr->GetExpressionType()); } Append(")"); } - void GlslWriter::Write(const ShaderAst::Constant& node) + void GlslWriter::Visit(const ShaderAst::Constant& node) { switch (node.exprType) { @@ -275,7 +270,7 @@ namespace Nz } } - void GlslWriter::Write(const ShaderAst::DeclareVariable& node) + void GlslWriter::Visit(const ShaderAst::DeclareVariable& node) { Append(node.variable->GetExpressionType()); Append(" "); @@ -285,24 +280,24 @@ namespace Nz Append(" "); Append("="); Append(" "); - Write(node.expression); + Visit(node.expression); } AppendLine(";"); } - void GlslWriter::Write(const ShaderAst::ExpressionStatement& node) + void GlslWriter::Visit(const ShaderAst::ExpressionStatement& node) { - Write(node.expression); + Visit(node.expression); Append(";"); } - void GlslWriter::Write(const ShaderAst::NamedVariable& node) + void GlslWriter::Visit(const ShaderAst::NamedVariable& node) { Append(node.name); } - void GlslWriter::Write(const ShaderAst::StatementBlock& node) + void GlslWriter::Visit(const ShaderAst::StatementBlock& node) { bool first = true; for (const ShaderAst::StatementPtr& statement : node.statements) @@ -310,15 +305,15 @@ namespace Nz if (!first) AppendLine(); - Write(statement); + Visit(statement); first = false; } } - void GlslWriter::Write(const ShaderAst::SwizzleOp& node) + void GlslWriter::Visit(const ShaderAst::SwizzleOp& node) { - Write(node.expression); + Visit(node.expression); Append("."); for (std::size_t i = 0; i < node.componentCount; ++i) @@ -433,7 +428,7 @@ namespace Nz EnterScope(); { - Write(func.node); + Visit(func.node); } LeaveScope(); } diff --git a/src/Nazara/Renderer/Renderer.cpp b/src/Nazara/Renderer/Renderer.cpp index 6954f5cf0..9df137326 100644 --- a/src/Nazara/Renderer/Renderer.cpp +++ b/src/Nazara/Renderer/Renderer.cpp @@ -69,7 +69,7 @@ namespace Nz }; RegisterImpl("NazaraOpenGLRenderer" NazaraRendererDebugSuffix, [] { return 50; }); - RegisterImpl("NazaraVulkanRenderer" NazaraRendererDebugSuffix, [] { return 100; }); + //RegisterImpl("NazaraVulkanRenderer" NazaraRendererDebugSuffix, [] { return 100; }); std::sort(implementations.begin(), implementations.end(), [](const auto& lhs, const auto& rhs) { return lhs.score > rhs.score; }); diff --git a/src/Nazara/Renderer/ShaderAst.cpp b/src/Nazara/Renderer/ShaderAst.cpp index 0a2373d17..d60ebab6a 100644 --- a/src/Nazara/Renderer/ShaderAst.cpp +++ b/src/Nazara/Renderer/ShaderAst.cpp @@ -3,11 +3,15 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include +#include +#include #include #include namespace Nz::ShaderAst { + Node::~Node() = default; + ExpressionCategory Expression::GetExpressionCategory() const { return ExpressionCategory::RValue; @@ -18,9 +22,9 @@ namespace Nz::ShaderAst expression->Register(visitor); } - void ExpressionStatement::Visit(ShaderWriter& visitor) + void ExpressionStatement::Visit(ShaderVisitor& visitor) { - visitor.Write(*this); + visitor.Visit(*this); } @@ -30,7 +34,7 @@ namespace Nz::ShaderAst statement->Register(visitor); } - void ConditionalStatement::Visit(ShaderWriter& visitor) + void ConditionalStatement::Visit(ShaderVisitor& visitor) { if (visitor.IsConditionEnabled(conditionName)) statement->Visit(visitor); @@ -43,9 +47,9 @@ namespace Nz::ShaderAst statementPtr->Register(visitor); } - void StatementBlock::Visit(ShaderWriter& visitor) + void StatementBlock::Visit(ShaderVisitor& visitor) { - visitor.Write(*this); + visitor.Visit(*this); } ExpressionCategory Variable::GetExpressionCategory() const @@ -58,14 +62,25 @@ namespace Nz::ShaderAst return type; } + + void BuiltinVariable::Register(ShaderWriter& /*visitor*/) + { + } + + void BuiltinVariable::Visit(ShaderVisitor& visitor) + { + visitor.Visit(*this); + } + + void NamedVariable::Register(ShaderWriter& visitor) { visitor.RegisterVariable(kind, name, type); } - void NamedVariable::Visit(ShaderWriter& visitor) + void NamedVariable::Visit(ShaderVisitor& visitor) { - visitor.Write(*this); + visitor.Visit(*this); } @@ -77,18 +92,9 @@ namespace Nz::ShaderAst expression->Register(visitor); } - void DeclareVariable::Visit(ShaderWriter& visitor) + void DeclareVariable::Visit(ShaderVisitor& visitor) { - visitor.Write(*this); - } - - void BuiltinVariable::Register(ShaderWriter& /*visitor*/) - { - } - - void BuiltinVariable::Visit(ShaderWriter& visitor) - { - visitor.Write(*this); + visitor.Visit(*this); } @@ -103,9 +109,9 @@ namespace Nz::ShaderAst right->Register(visitor); } - void AssignOp::Visit(ShaderWriter& visitor) + void AssignOp::Visit(ShaderVisitor& visitor) { - visitor.Write(*this); + visitor.Visit(*this); } @@ -138,9 +144,9 @@ namespace Nz::ShaderAst right->Register(visitor); } - void BinaryOp::Visit(ShaderWriter& visitor) + void BinaryOp::Visit(ShaderVisitor& visitor) { - visitor.Write(*this); + visitor.Visit(*this); } @@ -156,9 +162,9 @@ namespace Nz::ShaderAst elseStatement->Register(visitor); } - void Branch::Visit(ShaderWriter& visitor) + void Branch::Visit(ShaderVisitor& visitor) { - visitor.Write(*this); + visitor.Visit(*this); } @@ -171,9 +177,9 @@ namespace Nz::ShaderAst { } - void Constant::Visit(ShaderWriter& visitor) + void Constant::Visit(ShaderVisitor& visitor) { - visitor.Write(*this); + visitor.Visit(*this); } ExpressionType Cast::GetExpressionType() const @@ -195,26 +201,9 @@ namespace Nz::ShaderAst } } - void Cast::Visit(ShaderWriter& visitor) + void Cast::Visit(ShaderVisitor& visitor) { - visitor.Write(*this); - } - - void Cast::Validate() const - { - unsigned int componentCount = 0; - unsigned int requiredComponents = GetComponentCount(exprType); - for (const auto& exprPtr : expressions) - { - if (!exprPtr) - break; - - componentCount += GetComponentCount(exprPtr->GetExpressionType()); - } - - //TODO: AstParseError - if (componentCount != requiredComponents) - throw std::runtime_error("Component count doesn't match required component count"); + visitor.Visit(*this); } @@ -233,9 +222,9 @@ namespace Nz::ShaderAst expression->Register(visitor); } - void SwizzleOp::Visit(ShaderWriter& visitor) + void SwizzleOp::Visit(ShaderVisitor& visitor) { - visitor.Write(*this); + visitor.Visit(*this); } @@ -250,9 +239,9 @@ namespace Nz::ShaderAst coordinates->Register(visitor); } - void Sample2D::Visit(ShaderWriter& visitor) + void Sample2D::Visit(ShaderVisitor& visitor) { - visitor.Write(*this); + visitor.Visit(*this); } @@ -277,8 +266,8 @@ namespace Nz::ShaderAst right->Register(visitor); } - void BinaryFunc::Visit(ShaderWriter& visitor) + void BinaryFunc::Visit(ShaderVisitor& visitor) { - visitor.Write(*this); + visitor.Visit(*this); } } diff --git a/src/Nazara/Renderer/ShaderSerializer.cpp b/src/Nazara/Renderer/ShaderSerializer.cpp new file mode 100644 index 000000000..6e6e3e8ff --- /dev/null +++ b/src/Nazara/Renderer/ShaderSerializer.cpp @@ -0,0 +1,376 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Renderer module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include + +namespace Nz::ShaderAst +{ + namespace + { + class ShaderSerializerVisitor : public ShaderVisitor + { + public: + ShaderSerializerVisitor(ShaderSerializerBase& serializer) : + m_serializer(serializer) + { + } + + void Visit(const AssignOp& node) override + { + Serialize(node); + } + + void Visit(const BinaryFunc& node) override + { + Serialize(node); + } + + void Visit(const BinaryOp& node) override + { + Serialize(node); + } + + void Visit(const Branch& node) override + { + Serialize(node); + } + + void Visit(const BuiltinVariable& node) override + { + Serialize(node); + } + + void Visit(const Cast& node) override + { + Serialize(node); + } + + void Visit(const Constant& node) override + { + Serialize(node); + } + + void Visit(const DeclareVariable& node) override + { + Serialize(node); + } + + void Visit(const ExpressionStatement& node) override + { + Serialize(node); + } + + void Visit(const NamedVariable& node) override + { + Serialize(node); + } + + void Visit(const Sample2D& node) override + { + Serialize(node); + } + + void Visit(const StatementBlock& node) override + { + Serialize(node); + } + + void Visit(const SwizzleOp& node) override + { + Serialize(node); + } + + private: + template + void Serialize(const T& node) + { + // I know const_cast is evil but I don't have a better solution here (it's not used to write) + m_serializer.Serialize(const_cast(node)); + } + + ShaderSerializerBase& m_serializer; + }; + } + + void ShaderSerializerBase::Serialize(AssignOp& node) + { + Enum(node.op); + Node(node.left); + Node(node.right); + } + + void ShaderSerializerBase::Serialize(BinaryFunc& node) + { + Enum(node.intrinsic); + Node(node.left); + Node(node.right); + } + + void ShaderSerializerBase::Serialize(BinaryOp& node) + { + Enum(node.op); + Node(node.left); + Node(node.right); + } + + void ShaderSerializerBase::Serialize(Branch& node) + { + Container(node.condStatements); + for (auto& condStatement : node.condStatements) + { + Node(condStatement.condition); + Node(condStatement.statement); + } + + Node(node.elseStatement); + } + + void ShaderSerializerBase::Serialize(BuiltinVariable& node) + { + Enum(node.var); + Enum(node.type); + } + + void ShaderSerializerBase::Serialize(Cast& node) + { + Enum(node.exprType); + for (auto& expr : node.expressions) + Node(expr); + } + + void ShaderSerializerBase::Serialize(Constant& node) + { + Enum(node.exprType); + + switch (node.exprType) + { + case ExpressionType::Boolean: + Value(node.values.bool1); + break; + + case ExpressionType::Float1: + Value(node.values.vec1); + break; + + case ExpressionType::Float2: + Value(node.values.vec2); + break; + + case ExpressionType::Float3: + Value(node.values.vec3); + break; + + case ExpressionType::Float4: + Value(node.values.vec4); + break; + } + } + + void ShaderSerializerBase::Serialize(DeclareVariable& node) + { + Node(node.variable); + Node(node.expression); + } + + void ShaderSerializerBase::Serialize(ExpressionStatement& node) + { + Node(node.expression); + } + + void ShaderSerializerBase::Serialize(NamedVariable& node) + { + Value(node.name); + Enum(node.kind); + Enum(node.type); + } + + void ShaderSerializerBase::Serialize(Sample2D& node) + { + Node(node.sampler); + Node(node.coordinates); + } + + void ShaderSerializerBase::Serialize(StatementBlock& node) + { + Container(node.statements); + for (auto& statement : node.statements) + Node(statement); + } + + void ShaderSerializerBase::Serialize(SwizzleOp& node) + { + Value(node.componentCount); + Node(node.expression); + + for (std::size_t i = 0; i < node.componentCount; ++i) + Enum(node.components[i]); + } + + + void ShaderSerializer::Serialize(const StatementPtr& shader) + { + assert(shader); + m_stream << static_cast(shader->GetType()); + + ShaderSerializerVisitor visitor(*this); + shader->Visit(visitor); + + m_stream.FlushBits(); + } + + bool ShaderSerializer::IsWriting() const + { + return true; + } + + void ShaderSerializer::Node(NodePtr& node) + { + NodeType nodeType = (node) ? node->GetType() : NodeType::None; + m_stream << static_cast(nodeType); + + if (node) + { + ShaderSerializerVisitor visitor(*this); + node->Visit(visitor); + } + } + + void ShaderSerializer::Value(bool& val) + { + m_stream << val; + } + + void ShaderSerializer::Value(float& val) + { + m_stream << val; + } + + void ShaderSerializer::Value(std::string& val) + { + m_stream << val; + } + + void ShaderSerializer::Value(Vector2f& val) + { + m_stream << val; + } + + void ShaderSerializer::Value(Vector3f& val) + { + m_stream << val; + } + + void ShaderSerializer::Value(Vector4f& val) + { + m_stream << val; + } + + void ShaderSerializer::Value(UInt32& val) + { + m_stream << val; + } + + ByteArray Serialize(const StatementPtr& shader) + { + ByteArray byteArray; + ShaderSerializer serializer(byteArray); + serializer.Serialize(shader); + + return byteArray; + } + + StatementPtr Unserialize(const ByteArray& data) + { + ShaderUnserializer unserializer(data); + return unserializer.Unserialize(); + } + + StatementPtr ShaderUnserializer::Unserialize() + { + NodePtr statement; + Node(statement); + if (!statement || statement->GetType() != NodeType::StatementBlock) + throw std::runtime_error("Invalid shader"); + + return std::static_pointer_cast(statement); + } + + bool ShaderUnserializer::IsWriting() const + { + return false; + } + + void ShaderUnserializer::Node(NodePtr& node) + { + Int32 nodeTypeInt; + m_stream >> nodeTypeInt; + + NodeType nodeType = static_cast(nodeTypeInt); + +#define HandleNodeType(Type) case NodeType:: Type : node = std::make_shared(); break + switch (nodeType) + { + case NodeType::None: break; + + HandleNodeType(AssignOp); + HandleNodeType(BinaryFunc); + HandleNodeType(BinaryOp); + HandleNodeType(Branch); + HandleNodeType(BuiltinVariable); + HandleNodeType(Cast); + HandleNodeType(Constant); + HandleNodeType(ConditionalStatement); + HandleNodeType(DeclareVariable); + HandleNodeType(ExpressionStatement); + HandleNodeType(NamedVariable); + HandleNodeType(Sample2D); + HandleNodeType(SwizzleOp); + HandleNodeType(StatementBlock); + } +#undef HandleNodeType + + if (node) + { + ShaderSerializerVisitor visitor(*this); + node->Visit(visitor); + } + } + + void ShaderUnserializer::Value(bool& val) + { + m_stream >> val; + } + + void ShaderUnserializer::Value(float& val) + { + m_stream >> val; + } + + void ShaderUnserializer::Value(std::string& val) + { + m_stream >> val; + } + + void ShaderUnserializer::Value(Vector2f& val) + { + m_stream >> val; + } + + void ShaderUnserializer::Value(Vector3f& val) + { + m_stream >> val; + } + + void ShaderUnserializer::Value(Vector4f& val) + { + m_stream >> val; + } + + void ShaderUnserializer::Value(UInt32& val) + { + m_stream >> val; + } +} + diff --git a/src/Nazara/Renderer/ShaderVisitor.cpp b/src/Nazara/Renderer/ShaderVisitor.cpp new file mode 100644 index 000000000..2b5a590bd --- /dev/null +++ b/src/Nazara/Renderer/ShaderVisitor.cpp @@ -0,0 +1,29 @@ +// Copyright (C) 2015 Jérôme Leclercq +// This file is part of the "Nazara Engine - Renderer module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include + +namespace Nz +{ + ShaderVisitor::~ShaderVisitor() = default; + + void ShaderVisitor::EnableCondition(const String& name, bool cond) + { + if (cond) + m_conditions.insert(name); + else + m_conditions.erase(name); + } + + bool ShaderVisitor::IsConditionEnabled(const String& name) const + { + return m_conditions.count(name) != 0; + } + + void ShaderVisitor::Visit(const ShaderAst::NodePtr& node) + { + node->Visit(*this); + } +} diff --git a/src/Nazara/Renderer/ShaderWriter.cpp b/src/Nazara/Renderer/ShaderWriter.cpp index c862572ab..982251556 100644 --- a/src/Nazara/Renderer/ShaderWriter.cpp +++ b/src/Nazara/Renderer/ShaderWriter.cpp @@ -7,18 +7,4 @@ namespace Nz { - ShaderWriter::~ShaderWriter() = default; - - void ShaderWriter::EnableCondition(const String& name, bool cond) - { - if (cond) - m_conditions.insert(name); - else - m_conditions.erase(name); - } - - bool ShaderWriter::IsConditionEnabled(const String & name) const - { - return m_conditions.count(name) != 0; - } } diff --git a/src/ShaderNode/ShaderGraph.cpp b/src/ShaderNode/ShaderGraph.cpp index 6fc2fe6aa..01b5c6cf9 100644 --- a/src/ShaderNode/ShaderGraph.cpp +++ b/src/ShaderNode/ShaderGraph.cpp @@ -352,7 +352,7 @@ Nz::ShaderAst::StatementPtr ShaderGraph::ToAst() } }); - return std::make_shared(std::move(statements)); + return Nz::ShaderAst::StatementBlock::Build(std::move(statements)); } void ShaderGraph::UpdateInput(std::size_t inputIndex, std::string name, InOutType type, InputRole role, std::size_t roleIndex) From 2258a4f87f27ce98f0719234c4474023f5d263bb Mon Sep 17 00:00:00 2001 From: Lynix Date: Sat, 6 Jun 2020 16:44:17 +0200 Subject: [PATCH 032/105] Add ShaderValidator --- include/Nazara/Renderer/ShaderValidator.hpp | 54 +++++ include/Nazara/Renderer/ShaderValidator.inl | 12 + src/Nazara/Renderer/GlslWriter.cpp | 6 + src/Nazara/Renderer/ShaderValidator.cpp | 234 ++++++++++++++++++++ 4 files changed, 306 insertions(+) create mode 100644 include/Nazara/Renderer/ShaderValidator.hpp create mode 100644 include/Nazara/Renderer/ShaderValidator.inl create mode 100644 src/Nazara/Renderer/ShaderValidator.cpp diff --git a/include/Nazara/Renderer/ShaderValidator.hpp b/include/Nazara/Renderer/ShaderValidator.hpp new file mode 100644 index 000000000..50075aaf0 --- /dev/null +++ b/include/Nazara/Renderer/ShaderValidator.hpp @@ -0,0 +1,54 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Renderer module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_SHADERVALIDATOR_HPP +#define NAZARA_SHADERVALIDATOR_HPP + +#include +#include +#include +#include +#include + +namespace Nz::ShaderAst +{ + class NAZARA_RENDERER_API ShaderValidator : public ShaderVisitor + { + public: + ShaderValidator() = default; + ShaderValidator(const ShaderValidator&) = delete; + ShaderValidator(ShaderValidator&&) = delete; + ~ShaderValidator() = default; + + bool Validate(const StatementPtr& shader, std::string* error = nullptr); + + private: + const ExpressionPtr& MandatoryExpr(const ExpressionPtr& node); + const NodePtr& MandatoryNode(const NodePtr& node); + void TypeMustMatch(const ExpressionPtr& left, const ExpressionPtr& right); + + using ShaderVisitor::Visit; + void Visit(const AssignOp& node) override; + void Visit(const BinaryFunc& node) override; + void Visit(const BinaryOp& node) override; + void Visit(const Branch& node) override; + void Visit(const BuiltinVariable& node) override; + void Visit(const Cast& node) override; + void Visit(const Constant& node) override; + void Visit(const DeclareVariable& node) override; + void Visit(const ExpressionStatement& node) override; + void Visit(const NamedVariable& node) override; + void Visit(const Sample2D& node) override; + void Visit(const StatementBlock& node) override; + void Visit(const SwizzleOp& node) override; + }; + + NAZARA_RENDERER_API bool Validate(const StatementPtr& shader, std::string* error = nullptr); +} + +#include + +#endif diff --git a/include/Nazara/Renderer/ShaderValidator.inl b/include/Nazara/Renderer/ShaderValidator.inl new file mode 100644 index 000000000..2fb43d576 --- /dev/null +++ b/include/Nazara/Renderer/ShaderValidator.inl @@ -0,0 +1,12 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Renderer module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include + +namespace Nz::ShaderAst +{ +} + +#include diff --git a/src/Nazara/Renderer/GlslWriter.cpp b/src/Nazara/Renderer/GlslWriter.cpp index e7b8f6155..b982dab90 100644 --- a/src/Nazara/Renderer/GlslWriter.cpp +++ b/src/Nazara/Renderer/GlslWriter.cpp @@ -4,6 +4,8 @@ #include #include +#include +#include #include namespace Nz @@ -17,6 +19,10 @@ namespace Nz String GlslWriter::Generate(const ShaderAst::StatementPtr& node) { + std::string error; + if (!ShaderAst::Validate(node, &error)) + throw std::runtime_error("Invalid shader AST: " + error); + State state; m_currentState = &state; CallOnExit onExit([this]() diff --git a/src/Nazara/Renderer/ShaderValidator.cpp b/src/Nazara/Renderer/ShaderValidator.cpp new file mode 100644 index 000000000..2a4d38f25 --- /dev/null +++ b/src/Nazara/Renderer/ShaderValidator.cpp @@ -0,0 +1,234 @@ +// Copyright (C) 2015 Jérôme Leclercq +// This file is part of the "Nazara Engine - Renderer module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include + +namespace Nz::ShaderAst +{ + struct AstError + { + std::string errMsg; + }; + + bool ShaderValidator::Validate(const StatementPtr& shader, std::string* error) + { + try + { + shader->Visit(*this); + return true; + } + catch (const AstError& e) + { + if (error) + *error = e.errMsg; + + return false; + } + } + + const ExpressionPtr& ShaderValidator::MandatoryExpr(const ExpressionPtr& node) + { + MandatoryNode(node); + + return node; + } + + const NodePtr& ShaderValidator::MandatoryNode(const NodePtr& node) + { + if (!node) + throw AstError{ "Invalid node" }; + + return node; + } + + void ShaderValidator::TypeMustMatch(const ExpressionPtr& left, const ExpressionPtr& right) + { + if (left->GetExpressionType() != right->GetExpressionType()) + throw AstError{ "Left expression type must match right expression type" }; + } + + void ShaderValidator::Visit(const AssignOp& node) + { + MandatoryNode(node.left); + MandatoryNode(node.right); + TypeMustMatch(node.left, node.right); + + Visit(node.left); + Visit(node.right); + } + + void ShaderValidator::Visit(const BinaryFunc& node) + { + MandatoryNode(node.left); + MandatoryNode(node.right); + TypeMustMatch(node.left, node.right); + + switch (node.intrinsic) + { + case BinaryIntrinsic::CrossProduct: + { + if (node.left->GetExpressionType() != ExpressionType::Float3) + throw AstError{ "CrossProduct only works with Float3 expressions" }; + } + + case BinaryIntrinsic::DotProduct: + break; + } + + Visit(node.left); + Visit(node.right); + } + + void ShaderValidator::Visit(const BinaryOp& node) + { + MandatoryNode(node.left); + MandatoryNode(node.right); + + ExpressionType leftType = node.left->GetExpressionType(); + ExpressionType rightType = node.right->GetExpressionType(); + + switch (node.op) + { + case BinaryType::Add: + case BinaryType::Equality: + case BinaryType::Substract: + TypeMustMatch(node.left, node.right); + break; + + case BinaryType::Multiply: + case BinaryType::Divide: + { + switch (leftType) + { + case ExpressionType::Float2: + case ExpressionType::Float3: + case ExpressionType::Float4: + { + if (leftType != rightType && rightType != ExpressionType::Float1) + throw AstError{ "Left expression type is not compatible with right expression type" }; + + break; + } + + case ExpressionType::Mat4x4: + { + switch (rightType) + { + case ExpressionType::Float1: + case ExpressionType::Float4: + case ExpressionType::Mat4x4: + break; + + default: + TypeMustMatch(node.left, node.right); + } + + break; + } + + default: + TypeMustMatch(node.left, node.right); + } + } + } + + Visit(node.left); + Visit(node.right); + } + + void ShaderValidator::Visit(const Branch& node) + { + for (const auto& condStatement : node.condStatements) + { + Visit(MandatoryNode(condStatement.condition)); + Visit(MandatoryNode(condStatement.statement)); + } + } + + void ShaderValidator::Visit(const BuiltinVariable& /*node*/) + { + } + + void ShaderValidator::Visit(const Cast& node) + { + unsigned int componentCount = 0; + unsigned int requiredComponents = node.GetComponentCount(node.exprType); + for (const auto& exprPtr : node.expressions) + { + if (!exprPtr) + break; + + componentCount += node.GetComponentCount(exprPtr->GetExpressionType()); + Visit(exprPtr); + } + + if (componentCount != requiredComponents) + throw AstError{ "Component count doesn't match required component count" }; + } + + void ShaderValidator::Visit(const Constant& /*node*/) + { + } + + void ShaderValidator::Visit(const DeclareVariable& node) + { + Visit(MandatoryNode(node.expression)); + } + + void ShaderValidator::Visit(const ExpressionStatement& node) + { + Visit(MandatoryNode(node.expression)); + } + + void ShaderValidator::Visit(const NamedVariable& node) + { + if (node.name.empty()) + throw AstError{ "Variable has empty name" }; + } + + void ShaderValidator::Visit(const Sample2D& node) + { + if (MandatoryExpr(node.sampler)->GetExpressionType() != ExpressionType::Sampler2D) + throw AstError{ "Sampler must be a Sampler2D" }; + + if (MandatoryExpr(node.coordinates)->GetExpressionType() != ExpressionType::Float2) + throw AstError{ "Coordinates must be a Float2" }; + + Visit(node.sampler); + Visit(node.coordinates); + } + + void ShaderValidator::Visit(const StatementBlock& node) + { + for (const auto& statement : node.statements) + Visit(MandatoryNode(statement)); + } + + void ShaderValidator::Visit(const SwizzleOp& node) + { + if (node.componentCount > 4) + throw AstError{ "Cannot swizzle more than four elements" }; + + switch (MandatoryExpr(node.expression)->GetExpressionType()) + { + case ExpressionType::Float1: + case ExpressionType::Float2: + case ExpressionType::Float3: + case ExpressionType::Float4: + break; + + default: + throw AstError{ "Cannot swizzle this type" }; + } + + Visit(node.expression); + } + + bool Validate(const StatementPtr& shader, std::string* error) + { + ShaderValidator validator; + return validator.Validate(shader, error); + } +} From 90abb52e4e97cc3402cf11f5e2169bae9a382eef Mon Sep 17 00:00:00 2001 From: Lynix Date: Tue, 16 Jun 2020 17:44:20 +0200 Subject: [PATCH 033/105] ShaderEditor: Fixes --- src/ShaderNode/DataModels/Cast.hpp | 3 +++ src/ShaderNode/DataModels/Cast.inl | 29 +++++++++++++++++++++- src/ShaderNode/DataModels/FloatValue.cpp | 1 + src/ShaderNode/DataModels/InputValue.cpp | 25 +++++++++++++++---- src/ShaderNode/DataModels/InputValue.hpp | 1 + src/ShaderNode/DataModels/OutputValue.cpp | 27 ++++++++++++++------ src/ShaderNode/DataModels/OutputValue.hpp | 1 + src/ShaderNode/DataModels/TextureValue.cpp | 26 ++++++++++++++----- src/ShaderNode/DataModels/TextureValue.hpp | 1 + src/ShaderNode/DataModels/VecValue.inl | 7 ++++-- src/ShaderNode/Previews/QuadPreview.cpp | 8 ++++-- 11 files changed, 106 insertions(+), 23 deletions(-) diff --git a/src/ShaderNode/DataModels/Cast.hpp b/src/ShaderNode/DataModels/Cast.hpp index 90dad931e..bb287555c 100644 --- a/src/ShaderNode/DataModels/Cast.hpp +++ b/src/ShaderNode/DataModels/Cast.hpp @@ -38,6 +38,9 @@ class CastVec : public ShaderNode bool ComputePreview(QPixmap& pixmap) override; void UpdateOutput(); + void restore(const QJsonObject& data) override; + QJsonObject save() const override; + std::shared_ptr m_input; std::shared_ptr m_output; VecType m_overflowComponents; diff --git a/src/ShaderNode/DataModels/Cast.inl b/src/ShaderNode/DataModels/Cast.inl index f8870201a..1a304c2c7 100644 --- a/src/ShaderNode/DataModels/Cast.inl +++ b/src/ShaderNode/DataModels/Cast.inl @@ -34,6 +34,7 @@ void CastVec::BuildNodeEdition(QFormLayout* layout) { QDoubleSpinBox* spinbox = new QDoubleSpinBox; spinbox->setDecimals(6); + spinbox->setRange(std::numeric_limits::lowest(), std::numeric_limits::max()); spinbox->setValue(m_overflowComponents[i]); connect(spinbox, qOverload(&QDoubleSpinBox::valueChanged), [=](double) @@ -66,7 +67,7 @@ Nz::ShaderAst::ExpressionPtr CastVec::GetExpression(Nz::Shader constexpr auto ExpressionType = VecExpressionType; - return Nz::ShaderBuilder::Cast(expr.data(), overflowComponentCount); + return Nz::ShaderBuilder::Cast(expr.data(), 1 + overflowComponentCount); } else if (ToComponentCount < fromComponentCount) { @@ -232,3 +233,29 @@ void CastVec::UpdateOutput() UpdatePreview(); } + +template +void CastVec::restore(const QJsonObject& data) +{ + QJsonArray vecValues = data["value"].toArray(); + std::size_t commonValues = std::min(static_cast(vecValues.size()), ToComponentCount); + + for (std::size_t i = 0; i < commonValues; ++i) + m_overflowComponents[i] = float(vecValues[int(i)].toDouble(m_overflowComponents[i])); + + ShaderNode::restore(data); +} + +template +QJsonObject CastVec::save() const +{ + QJsonObject data = ShaderNode::save(); + + QJsonArray vecValues; + for (std::size_t i = 0; i < ToComponentCount; ++i) + vecValues.push_back(m_overflowComponents[i]); + + data["value"] = vecValues; + + return data; +} diff --git a/src/ShaderNode/DataModels/FloatValue.cpp b/src/ShaderNode/DataModels/FloatValue.cpp index 23d5a30d3..3da83982e 100644 --- a/src/ShaderNode/DataModels/FloatValue.cpp +++ b/src/ShaderNode/DataModels/FloatValue.cpp @@ -57,6 +57,7 @@ void FloatValue::BuildNodeEdition(QFormLayout* layout) QDoubleSpinBox* spinbox = new QDoubleSpinBox; spinbox->setDecimals(6); + spinbox->setRange(std::numeric_limits::lowest(), std::numeric_limits::max()); spinbox->setValue(m_value); connect(spinbox, qOverload(&QDoubleSpinBox::valueChanged), [=](double) diff --git a/src/ShaderNode/DataModels/InputValue.cpp b/src/ShaderNode/DataModels/InputValue.cpp index 3f8d2fbdc..92d08ba3e 100644 --- a/src/ShaderNode/DataModels/InputValue.cpp +++ b/src/ShaderNode/DataModels/InputValue.cpp @@ -20,9 +20,8 @@ ShaderNode(graph) if (graph.GetInputCount() > 0) { - auto& firstInput = graph.GetInput(0); m_currentInputIndex = 0; - m_currentInputText = firstInput.name; + UpdateInputText(); } DisableCustomVariableName(); @@ -70,11 +69,27 @@ void InputValue::OnInputListUpdate() } } +void InputValue::UpdateInputText() +{ + if (m_currentInputIndex) + { + auto& input = GetGraph().GetInput(*m_currentInputIndex); + m_currentInputText = input.name; + } + else + m_currentInputText.clear(); +} + void InputValue::BuildNodeEdition(QFormLayout* layout) { ShaderNode::BuildNodeEdition(layout); QComboBox* inputSelection = new QComboBox; + for (const auto& inputEntry : GetGraph().GetInputs()) + inputSelection->addItem(QString::fromStdString(inputEntry.name)); + + if (m_currentInputIndex) + inputSelection->setCurrentIndex(int(*m_currentInputIndex)); connect(inputSelection, qOverload(&QComboBox::currentIndexChanged), [&](int index) { @@ -83,11 +98,11 @@ void InputValue::BuildNodeEdition(QFormLayout* layout) else m_currentInputIndex.reset(); + UpdateInputText(); UpdatePreview(); - }); - for (const auto& inputEntry : GetGraph().GetInputs()) - inputSelection->addItem(QString::fromStdString(inputEntry.name)); + Q_EMIT dataUpdated(0); + }); layout->addRow(tr("Input"), inputSelection); } diff --git a/src/ShaderNode/DataModels/InputValue.hpp b/src/ShaderNode/DataModels/InputValue.hpp index 681a85e8d..a5eaabf01 100644 --- a/src/ShaderNode/DataModels/InputValue.hpp +++ b/src/ShaderNode/DataModels/InputValue.hpp @@ -36,6 +36,7 @@ class InputValue : public ShaderNode private: bool ComputePreview(QPixmap& pixmap) override; void OnInputListUpdate(); + void UpdateInputText(); void restore(const QJsonObject& data) override; QJsonObject save() const override; diff --git a/src/ShaderNode/DataModels/OutputValue.cpp b/src/ShaderNode/DataModels/OutputValue.cpp index 538884706..09d7aff78 100644 --- a/src/ShaderNode/DataModels/OutputValue.cpp +++ b/src/ShaderNode/DataModels/OutputValue.cpp @@ -17,9 +17,8 @@ ShaderNode(graph) if (graph.GetOutputCount() > 0) { - auto& firstOutput = graph.GetOutput(0); m_currentOutputIndex = 0; - m_currentOutputText = firstOutput.name; + UpdateOutputText(); } EnablePreview(); @@ -32,7 +31,12 @@ void OutputValue::BuildNodeEdition(QFormLayout* layout) ShaderNode::BuildNodeEdition(layout); QComboBox* outputSelection = new QComboBox; + for (const auto& outputEntry : GetGraph().GetOutputs()) + outputSelection->addItem(QString::fromStdString(outputEntry.name)); + if (m_currentOutputIndex) + outputSelection->setCurrentIndex(int(*m_currentOutputIndex)); + connect(outputSelection, qOverload(&QComboBox::currentIndexChanged), [&](int index) { if (index >= 0) @@ -40,12 +44,10 @@ void OutputValue::BuildNodeEdition(QFormLayout* layout) else m_currentOutputIndex.reset(); + UpdateOutputText(); UpdatePreview(); }); - for (const auto& outputEntry : GetGraph().GetOutputs()) - outputSelection->addItem(QString::fromStdString(outputEntry.name)); - layout->addRow(tr("Output"), outputSelection); } @@ -189,9 +191,20 @@ void OutputValue::OnOutputListUpdate() } } +void OutputValue::UpdateOutputText() +{ + if (m_currentOutputIndex) + { + auto& output = GetGraph().GetOutput(*m_currentOutputIndex); + m_currentOutputText = output.name; + } + else + m_currentOutputText.clear(); +} + void OutputValue::restore(const QJsonObject& data) { - m_currentOutputText = data["input"].toString().toStdString(); + m_currentOutputText = data["output"].toString().toStdString(); OnOutputListUpdate(); ShaderNode::restore(data); @@ -200,7 +213,7 @@ void OutputValue::restore(const QJsonObject& data) QJsonObject OutputValue::save() const { QJsonObject data = ShaderNode::save(); - data["input"] = QString::fromStdString(m_currentOutputText); + data["output"] = QString::fromStdString(m_currentOutputText); return data; } diff --git a/src/ShaderNode/DataModels/OutputValue.hpp b/src/ShaderNode/DataModels/OutputValue.hpp index 4cc523b66..320b2bacb 100644 --- a/src/ShaderNode/DataModels/OutputValue.hpp +++ b/src/ShaderNode/DataModels/OutputValue.hpp @@ -35,6 +35,7 @@ class OutputValue : public ShaderNode private: bool ComputePreview(QPixmap& pixmap) override; void OnOutputListUpdate(); + void UpdateOutputText(); void restore(const QJsonObject& data) override; QJsonObject save() const override; diff --git a/src/ShaderNode/DataModels/TextureValue.cpp b/src/ShaderNode/DataModels/TextureValue.cpp index 78f7df761..d543a502e 100644 --- a/src/ShaderNode/DataModels/TextureValue.cpp +++ b/src/ShaderNode/DataModels/TextureValue.cpp @@ -20,9 +20,8 @@ ShaderNode(graph) if (graph.GetTextureCount() > 0) { - auto& firstInput = graph.GetTexture(0); m_currentTextureIndex = 0; - m_currentTextureText = firstInput.name; + UpdateOutputTexture(); } DisableCustomVariableName(); @@ -57,6 +56,17 @@ void TextureValue::OnTextureListUpdate() } } +void TextureValue::UpdateOutputTexture() +{ + if (m_currentTextureIndex) + { + auto& texture = GetGraph().GetTexture(*m_currentTextureIndex); + m_currentTextureText = texture.name; + } + else + m_currentTextureText.clear(); +} + bool TextureValue::ComputePreview(QPixmap& pixmap) { if (!m_currentTextureIndex) @@ -74,6 +84,12 @@ void TextureValue::BuildNodeEdition(QFormLayout* layout) ShaderNode::BuildNodeEdition(layout); QComboBox* textureSelection = new QComboBox; + for (const auto& textureEntry : GetGraph().GetTextures()) + textureSelection->addItem(QString::fromStdString(textureEntry.name)); + + if (m_currentTextureIndex) + textureSelection->setCurrentIndex(int(*m_currentTextureIndex)); + connect(textureSelection, qOverload(&QComboBox::currentIndexChanged), [&](int index) { if (index >= 0) @@ -81,14 +97,12 @@ void TextureValue::BuildNodeEdition(QFormLayout* layout) else m_currentTextureIndex.reset(); + UpdateOutputTexture(); UpdatePreview(); Q_EMIT dataUpdated(0); }); - for (const auto& textureEntry : GetGraph().GetTextures()) - textureSelection->addItem(QString::fromStdString(textureEntry.name)); - layout->addRow(tr("Texture"), textureSelection); } @@ -120,7 +134,7 @@ auto TextureValue::dataType(QtNodes::PortType portType, QtNodes::PortIndex portI assert(portType == QtNodes::PortType::Out); assert(portIndex == 0); - return VecData::Type(); + return Texture2Data::Type(); } std::shared_ptr TextureValue::outData(QtNodes::PortIndex port) diff --git a/src/ShaderNode/DataModels/TextureValue.hpp b/src/ShaderNode/DataModels/TextureValue.hpp index 4b46be4d6..89cfcff21 100644 --- a/src/ShaderNode/DataModels/TextureValue.hpp +++ b/src/ShaderNode/DataModels/TextureValue.hpp @@ -35,6 +35,7 @@ class TextureValue : public ShaderNode protected: bool ComputePreview(QPixmap& pixmap) override; void OnTextureListUpdate(); + void UpdateOutputTexture(); void restore(const QJsonObject& data) override; QJsonObject save() const override; diff --git a/src/ShaderNode/DataModels/VecValue.inl b/src/ShaderNode/DataModels/VecValue.inl index a35a95686..a3ea2068e 100644 --- a/src/ShaderNode/DataModels/VecValue.inl +++ b/src/ShaderNode/DataModels/VecValue.inl @@ -78,6 +78,7 @@ void VecValue::BuildNodeEdition(QFormLayout* layout) { QDoubleSpinBox* spinbox = new QDoubleSpinBox; spinbox->setDecimals(6); + spinbox->setRange(std::numeric_limits::lowest(), std::numeric_limits::max()); spinbox->setValue(m_value[i]); connect(spinbox, qOverload(&QDoubleSpinBox::valueChanged), [=](double) @@ -122,8 +123,10 @@ template void VecValue::restore(const QJsonObject& data) { QJsonArray vecValues = data["value"].toArray(); - for (std::size_t i = 0; i < ComponentCount; ++i) - m_value[i] = vecValues[int(i)].toInt(m_value[i]); + std::size_t commonValues = std::min(static_cast(vecValues.size()), ComponentCount); + + for (std::size_t i = 0; i < commonValues; ++i) + m_value[i] = float(vecValues[int(i)].toDouble(m_value[i])); ShaderNode::restore(data); } diff --git a/src/ShaderNode/Previews/QuadPreview.cpp b/src/ShaderNode/Previews/QuadPreview.cpp index 55ae86a52..ef064417d 100644 --- a/src/ShaderNode/Previews/QuadPreview.cpp +++ b/src/ShaderNode/Previews/QuadPreview.cpp @@ -3,8 +3,12 @@ QImage QuadPreview::GetImage(InputRole role, std::size_t roleIndex) const { - assert(role == InputRole::TexCoord); - assert(roleIndex == 0); + if (role != InputRole::TexCoord) + { + QImage dummy(1, 1, QImage::Format_RGBA8888); + dummy.fill(QColor::fromRgb(0, 0, 0, 0)); + return dummy; + } QImage uv(128, 128, QImage::Format_RGBA8888); From 9b911ac4bc4df86cceb16f9455befffdc78d0b1a Mon Sep 17 00:00:00 2001 From: Lynix Date: Tue, 16 Jun 2020 17:44:54 +0200 Subject: [PATCH 034/105] Renderer/ShaderAst: Minor fixes relative to float/vec multiplication --- src/Nazara/Renderer/ShaderAst.cpp | 8 ++++++-- src/Nazara/Renderer/ShaderValidator.cpp | 8 ++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/Nazara/Renderer/ShaderAst.cpp b/src/Nazara/Renderer/ShaderAst.cpp index d60ebab6a..b6623cc48 100644 --- a/src/Nazara/Renderer/ShaderAst.cpp +++ b/src/Nazara/Renderer/ShaderAst.cpp @@ -122,12 +122,16 @@ namespace Nz::ShaderAst switch (op) { case ShaderAst::BinaryType::Add: - case ShaderAst::BinaryType::Divide: - case ShaderAst::BinaryType::Multiply: case ShaderAst::BinaryType::Substract: exprType = left->GetExpressionType(); break; + case ShaderAst::BinaryType::Divide: + case ShaderAst::BinaryType::Multiply: + //FIXME + exprType = static_cast(std::max(UnderlyingCast(left->GetExpressionType()), UnderlyingCast(right->GetExpressionType()))); + break; + case ShaderAst::BinaryType::Equality: exprType = ExpressionType::Boolean; break; diff --git a/src/Nazara/Renderer/ShaderValidator.cpp b/src/Nazara/Renderer/ShaderValidator.cpp index 2a4d38f25..c7a25989f 100644 --- a/src/Nazara/Renderer/ShaderValidator.cpp +++ b/src/Nazara/Renderer/ShaderValidator.cpp @@ -102,6 +102,14 @@ namespace Nz::ShaderAst { switch (leftType) { + case ExpressionType::Float1: + { + if (Node::GetComponentType(rightType) != ExpressionType::Float1) + throw AstError{ "Left expression type is not compatible with right expression type" }; + + break; + } + case ExpressionType::Float2: case ExpressionType::Float3: case ExpressionType::Float4: From d3db22ce224fa659cf19b49910aea348010e316d Mon Sep 17 00:00:00 2001 From: Lynix Date: Tue, 16 Jun 2020 17:45:21 +0200 Subject: [PATCH 035/105] ShaderEditor/VecBinOp: Add component check --- src/ShaderNode/DataModels/VecBinOp.hpp | 3 +++ src/ShaderNode/DataModels/VecBinOp.inl | 26 +++++++++++++++++++++++++- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/src/ShaderNode/DataModels/VecBinOp.hpp b/src/ShaderNode/DataModels/VecBinOp.hpp index 0fbb93f9c..977b0d3ba 100644 --- a/src/ShaderNode/DataModels/VecBinOp.hpp +++ b/src/ShaderNode/DataModels/VecBinOp.hpp @@ -23,6 +23,9 @@ class VecBinOp : public ShaderNode void setInData(std::shared_ptr value, int index) override; + QtNodes::NodeValidationState validationState() const override; + QString validationMessage() const override; + private: virtual void ApplyOp(const std::uint8_t* left, const std::uint8_t* right, std::uint8_t* output, std::size_t pixelCount) = 0; diff --git a/src/ShaderNode/DataModels/VecBinOp.inl b/src/ShaderNode/DataModels/VecBinOp.inl index 7d3cf1e12..5a12aff08 100644 --- a/src/ShaderNode/DataModels/VecBinOp.inl +++ b/src/ShaderNode/DataModels/VecBinOp.inl @@ -65,6 +65,30 @@ void VecBinOp::setInData(std::shared_ptr value, int in UpdateOutput(); } +template +QtNodes::NodeValidationState VecBinOp::validationState() const +{ + if (!m_lhs || !m_rhs) + return QtNodes::NodeValidationState::Error; + + if (m_lhs->componentCount != m_rhs->componentCount) + return QtNodes::NodeValidationState::Error; + + return QtNodes::NodeValidationState::Valid; +} + +template +QString VecBinOp::validationMessage() const +{ + if (!m_lhs || !m_rhs) + return "Missing operands"; + + if (m_lhs->componentCount != m_rhs->componentCount) + return "Incompatible components count (left has " + QString::number(m_lhs->componentCount) + ", right has " + QString::number(m_rhs->componentCount) + ")"; + + return QString(); +} + template bool VecBinOp::ComputePreview(QPixmap& pixmap) { @@ -78,7 +102,7 @@ bool VecBinOp::ComputePreview(QPixmap& pixmap) template void VecBinOp::UpdateOutput() { - if (!m_lhs || !m_rhs || m_lhs->componentCount != m_rhs->componentCount) + if (validationState() != QtNodes::NodeValidationState::Valid) { m_output = std::make_shared(4); m_output->preview = QImage(1, 1, QImage::Format_RGBA8888); From 80527dec3e832d37c6ef60242d361a1626ccaa12 Mon Sep 17 00:00:00 2001 From: Lynix Date: Tue, 16 Jun 2020 17:45:36 +0200 Subject: [PATCH 036/105] ShaderEditor: Add VecDot --- src/ShaderNode/DataModels/VecDot.cpp | 167 +++++++++++++++++++++++++++ src/ShaderNode/DataModels/VecDot.hpp | 43 +++++++ src/ShaderNode/DataModels/VecDot.inl | 1 + src/ShaderNode/ShaderGraph.cpp | 2 + 4 files changed, 213 insertions(+) create mode 100644 src/ShaderNode/DataModels/VecDot.cpp create mode 100644 src/ShaderNode/DataModels/VecDot.hpp create mode 100644 src/ShaderNode/DataModels/VecDot.inl diff --git a/src/ShaderNode/DataModels/VecDot.cpp b/src/ShaderNode/DataModels/VecDot.cpp new file mode 100644 index 000000000..47b67b72c --- /dev/null +++ b/src/ShaderNode/DataModels/VecDot.cpp @@ -0,0 +1,167 @@ +#include +#include + +VecDot::VecDot(ShaderGraph& graph) : +ShaderNode(graph) +{ + m_output = std::make_shared(); + UpdateOutput(); +} + +Nz::ShaderAst::ExpressionPtr VecDot::GetExpression(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count) const +{ + assert(count == 2); + using namespace Nz::ShaderAst; + return BinaryFunc::Build(BinaryIntrinsic::DotProduct, expressions[0], expressions[1]); +} + +QString VecDot::caption() const +{ + static QString caption = "Vector dot"; + return caption; +} + +QString VecDot::name() const +{ + static QString name = "vec_dot"; + return name; +} + +QtNodes::NodeDataType VecDot::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const +{ + switch (portType) + { + case QtNodes::PortType::In: + { + assert(portIndex == 0 || portIndex == 1); + return VecData::Type(); + } + + case QtNodes::PortType::Out: + { + assert(portIndex == 0); + return FloatData::Type(); + } + } + + assert(false); + throw std::runtime_error("Invalid port type"); +} + +unsigned int VecDot::nPorts(QtNodes::PortType portType) const +{ + switch (portType) + { + case QtNodes::PortType::In: return 2; + case QtNodes::PortType::Out: return 1; + } + + assert(false); + throw std::runtime_error("Invalid port type"); +} + +std::shared_ptr VecDot::outData(QtNodes::PortIndex port) +{ + assert(port == 0); + return m_output; +} + +void VecDot::setInData(std::shared_ptr value, int index) +{ + assert(index == 0 || index == 1); + + std::shared_ptr castedValue; + if (value) + { + assert(dynamic_cast(value.get()) != nullptr); + + castedValue = std::static_pointer_cast(value); + } + + if (index == 0) + m_lhs = std::move(castedValue); + else + m_rhs = std::move(castedValue); + + UpdateOutput(); +} + +QtNodes::NodeValidationState VecDot::validationState() const +{ + if (!m_lhs || !m_rhs) + return QtNodes::NodeValidationState::Error; + + if (m_lhs->componentCount != m_rhs->componentCount) + return QtNodes::NodeValidationState::Error; + + return QtNodes::NodeValidationState::Valid; +} + +QString VecDot::validationMessage() const +{ + if (!m_lhs || !m_rhs) + return "Missing operands"; + + if (m_lhs->componentCount != m_rhs->componentCount) + return "Incompatible components count (left has " + QString::number(m_lhs->componentCount) + ", right has " + QString::number(m_rhs->componentCount) + ")"; + + return QString(); +} +bool VecDot::ComputePreview(QPixmap& pixmap) +{ + if (validationState() != QtNodes::NodeValidationState::Valid) + return false; + + pixmap = QPixmap::fromImage(m_output->preview); + return true; +} + +void VecDot::UpdateOutput() +{ + if (validationState() != QtNodes::NodeValidationState::Valid) + { + m_output->preview = QImage(1, 1, QImage::Format_RGBA8888); + m_output->preview.fill(QColor::fromRgb(0, 0, 0, 0)); + return; + } + + const QImage& leftPreview = m_lhs->preview; + const QImage& rightPreview = m_rhs->preview; + int maxWidth = std::max(leftPreview.width(), rightPreview.width()); + int maxHeight = std::max(leftPreview.height(), rightPreview.height()); + + // Exploit COW + QImage leftResized = leftPreview; + if (leftResized.width() != maxWidth || leftResized.height() != maxHeight) + leftResized = leftResized.scaled(maxWidth, maxHeight); + + QImage rightResized = rightPreview; + if (rightResized.width() != maxWidth || rightResized.height() != maxHeight) + rightResized = rightResized.scaled(maxWidth, maxHeight); + + m_output->preview = QImage(maxWidth, maxHeight, QImage::Format_RGBA8888); + + const uchar* left = leftResized.constBits(); + const uchar* right = rightPreview.constBits(); + uchar* output = m_output->preview.bits(); + + std::size_t pixelCount = maxWidth * maxHeight; + for (std::size_t i = 0; i < pixelCount; ++i) + { + unsigned int acc = 0; + for (std::size_t j = 0; j < m_lhs->componentCount; ++j) + acc += left[j] * right[j] / 255; + + unsigned int result = static_cast(std::min(acc, 255U)); + for (std::size_t j = 0; j < 3; ++j) + *output++ = result; + *output++ = 255; //< leave alpha at maximum + + left += 4; + right += 4; + } + + Q_EMIT dataUpdated(0); + + UpdatePreview(); +} diff --git a/src/ShaderNode/DataModels/VecDot.hpp b/src/ShaderNode/DataModels/VecDot.hpp new file mode 100644 index 000000000..dc92bb5c8 --- /dev/null +++ b/src/ShaderNode/DataModels/VecDot.hpp @@ -0,0 +1,43 @@ +#pragma once + +#ifndef NAZARA_SHADERNODES_VECDOT_HPP +#define NAZARA_SHADERNODES_VECDOT_HPP + +#include +#include +#include + +class VecDot : public ShaderNode +{ + public: + VecDot(ShaderGraph& graph); + ~VecDot() = default; + + Nz::ShaderAst::ExpressionPtr GetExpression(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count) const override; + + QString caption() const override; + QString name() const override; + + unsigned int nPorts(QtNodes::PortType portType) const override; + + QtNodes::NodeDataType dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; + + std::shared_ptr outData(QtNodes::PortIndex port) override; + + void setInData(std::shared_ptr value, int index) override; + + QtNodes::NodeValidationState validationState() const override; + QString validationMessage() const override; + + private: + bool ComputePreview(QPixmap& pixmap) override; + void UpdateOutput(); + + std::shared_ptr m_lhs; + std::shared_ptr m_rhs; + std::shared_ptr m_output; +}; + +#include + +#endif diff --git a/src/ShaderNode/DataModels/VecDot.inl b/src/ShaderNode/DataModels/VecDot.inl new file mode 100644 index 000000000..ba9301bc9 --- /dev/null +++ b/src/ShaderNode/DataModels/VecDot.inl @@ -0,0 +1 @@ +#include diff --git a/src/ShaderNode/ShaderGraph.cpp b/src/ShaderNode/ShaderGraph.cpp index 01b5c6cf9..57b9429e3 100644 --- a/src/ShaderNode/ShaderGraph.cpp +++ b/src/ShaderNode/ShaderGraph.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -400,6 +401,7 @@ std::shared_ptr ShaderGraph::BuildRegistry() RegisterShaderNode(*this, registry, "Texture"); RegisterShaderNode(*this, registry, "Vector operations"); RegisterShaderNode(*this, registry, "Vector operations"); + RegisterShaderNode(*this, registry, "Vector operations"); RegisterShaderNode(*this, registry, "Vector operations"); RegisterShaderNode(*this, registry, "Vector operations"); RegisterShaderNode(*this, registry, "Constants"); From 463b54073957c8ac8a4c59af6e23e0d342324eef Mon Sep 17 00:00:00 2001 From: Lynix Date: Tue, 16 Jun 2020 17:46:03 +0200 Subject: [PATCH 037/105] ShaderEditor: Add VecFloatMul --- src/ShaderNode/DataModels/VecFloatMul.cpp | 183 ++++++++++++++++++++++ src/ShaderNode/DataModels/VecFloatMul.hpp | 43 +++++ src/ShaderNode/DataModels/VecFloatMul.inl | 1 + src/ShaderNode/ShaderGraph.cpp | 2 + 4 files changed, 229 insertions(+) create mode 100644 src/ShaderNode/DataModels/VecFloatMul.cpp create mode 100644 src/ShaderNode/DataModels/VecFloatMul.hpp create mode 100644 src/ShaderNode/DataModels/VecFloatMul.inl diff --git a/src/ShaderNode/DataModels/VecFloatMul.cpp b/src/ShaderNode/DataModels/VecFloatMul.cpp new file mode 100644 index 000000000..f4ec6f957 --- /dev/null +++ b/src/ShaderNode/DataModels/VecFloatMul.cpp @@ -0,0 +1,183 @@ +#include +#include + +VecFloatMul::VecFloatMul(ShaderGraph& graph) : +ShaderNode(graph) +{ + UpdateOutput(); +} + +Nz::ShaderAst::ExpressionPtr VecFloatMul::GetExpression(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count) const +{ + assert(count == 2); + using namespace Nz::ShaderAst; + return BinaryOp::Build(BinaryType::Multiply, expressions[0], expressions[1]); +} + +QString VecFloatMul::caption() const +{ + static QString caption = "Float/vector multiplication"; + return caption; +} + +QString VecFloatMul::name() const +{ + static QString name = "vecfloat_mul"; + return name; +} + +QtNodes::NodeDataType VecFloatMul::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const +{ + switch (portType) + { + case QtNodes::PortType::In: + { + assert(portIndex == 0 || portIndex == 1); + switch (portIndex) + { + case 0: return FloatData::Type(); + case 1: return VecData::Type(); + } + } + + case QtNodes::PortType::Out: + { + assert(portIndex == 0); + return VecData::Type(); + } + } + + assert(false); + throw std::runtime_error("Invalid port type"); +} + +unsigned int VecFloatMul::nPorts(QtNodes::PortType portType) const +{ + switch (portType) + { + case QtNodes::PortType::In: return 2; + case QtNodes::PortType::Out: return 1; + } + + assert(false); + throw std::runtime_error("Invalid port type"); +} + +std::shared_ptr VecFloatMul::outData(QtNodes::PortIndex port) +{ + assert(port == 0); + return m_output; +} + +void VecFloatMul::setInData(std::shared_ptr value, int index) +{ + assert(index == 0 || index == 1); + + switch (index) + { + case 0: + { + if (value) + { + assert(dynamic_cast(value.get()) != nullptr); + + m_lhs = std::static_pointer_cast(value); + } + else + m_lhs.reset(); + + break; + } + + case 1: + { + if (value) + { + assert(dynamic_cast(value.get()) != nullptr); + + m_rhs = std::static_pointer_cast(value); + } + else + m_rhs.reset(); + + break; + } + + default: + assert(false); + throw std::runtime_error("Invalid PortType"); + } + + UpdateOutput(); +} + +QtNodes::NodeValidationState VecFloatMul::validationState() const +{ + if (!m_lhs || !m_rhs) + return QtNodes::NodeValidationState::Error; + + return QtNodes::NodeValidationState::Valid; +} + +QString VecFloatMul::validationMessage() const +{ + if (!m_lhs || !m_rhs) + return "Missing operands"; + + return QString(); +} + +bool VecFloatMul::ComputePreview(QPixmap& pixmap) +{ + if (validationState() != QtNodes::NodeValidationState::Valid) + return false; + + pixmap = QPixmap::fromImage(m_output->preview); + return true; +} + +void VecFloatMul::UpdateOutput() +{ + if (validationState() != QtNodes::NodeValidationState::Valid) + { + m_output = std::make_shared(4); + m_output->preview = QImage(1, 1, QImage::Format_RGBA8888); + m_output->preview.fill(QColor::fromRgb(0, 0, 0, 0)); + return; + } + + m_output = std::make_shared(m_rhs->componentCount); + + const QImage& leftPreview = m_lhs->preview; + const QImage& rightPreview = m_rhs->preview; + int maxWidth = std::max(leftPreview.width(), rightPreview.width()); + int maxHeight = std::max(leftPreview.height(), rightPreview.height()); + + // Exploit COW + QImage leftResized = leftPreview; + if (leftResized.width() != maxWidth || leftResized.height() != maxHeight) + leftResized = leftResized.scaled(maxWidth, maxHeight); + + QImage rightResized = rightPreview; + if (rightResized.width() != maxWidth || rightResized.height() != maxHeight) + rightResized = rightResized.scaled(maxWidth, maxHeight); + + m_output->preview = QImage(maxWidth, maxHeight, QImage::Format_RGBA8888); + + const uchar* left = leftResized.constBits(); + const uchar* right = rightPreview.constBits(); + uchar* output = m_output->preview.bits(); + + std::size_t pixelCount = maxWidth * maxHeight * 4; + for (std::size_t i = 0; i < pixelCount; ++i) + { + unsigned int lValue = left[i]; + unsigned int rValue = right[i]; + + output[i] = static_cast(lValue * rValue / 255); + } + + Q_EMIT dataUpdated(0); + + UpdatePreview(); +} diff --git a/src/ShaderNode/DataModels/VecFloatMul.hpp b/src/ShaderNode/DataModels/VecFloatMul.hpp new file mode 100644 index 000000000..c4a9a97f7 --- /dev/null +++ b/src/ShaderNode/DataModels/VecFloatMul.hpp @@ -0,0 +1,43 @@ +#pragma once + +#ifndef NAZARA_SHADERNODES_VECFLOATMUL_HPP +#define NAZARA_SHADERNODES_VECFLOATMUL_HPP + +#include +#include +#include + +class VecFloatMul : public ShaderNode +{ + public: + VecFloatMul(ShaderGraph& graph); + ~VecFloatMul() = default; + + Nz::ShaderAst::ExpressionPtr GetExpression(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count) const override; + + QString caption() const override; + QString name() const override; + + unsigned int nPorts(QtNodes::PortType portType) const override; + + QtNodes::NodeDataType dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; + + std::shared_ptr outData(QtNodes::PortIndex port) override; + + void setInData(std::shared_ptr value, int index) override; + + QtNodes::NodeValidationState validationState() const override; + QString validationMessage() const override; + + private: + bool ComputePreview(QPixmap& pixmap) override; + void UpdateOutput(); + + std::shared_ptr m_lhs; + std::shared_ptr m_rhs; + std::shared_ptr m_output; +}; + +#include + +#endif diff --git a/src/ShaderNode/DataModels/VecFloatMul.inl b/src/ShaderNode/DataModels/VecFloatMul.inl new file mode 100644 index 000000000..a798943a8 --- /dev/null +++ b/src/ShaderNode/DataModels/VecFloatMul.inl @@ -0,0 +1 @@ +#include diff --git a/src/ShaderNode/ShaderGraph.cpp b/src/ShaderNode/ShaderGraph.cpp index 57b9429e3..06b0ddea0 100644 --- a/src/ShaderNode/ShaderGraph.cpp +++ b/src/ShaderNode/ShaderGraph.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -402,6 +403,7 @@ std::shared_ptr ShaderGraph::BuildRegistry() RegisterShaderNode(*this, registry, "Vector operations"); RegisterShaderNode(*this, registry, "Vector operations"); RegisterShaderNode(*this, registry, "Vector operations"); + RegisterShaderNode(*this, registry, "Vector operations"); RegisterShaderNode(*this, registry, "Vector operations"); RegisterShaderNode(*this, registry, "Vector operations"); RegisterShaderNode(*this, registry, "Constants"); From f38bfdde8a0a43de8a3ba47f153e00111a798f7f Mon Sep 17 00:00:00 2001 From: Lynix Date: Wed, 17 Jun 2020 16:00:03 +0200 Subject: [PATCH 038/105] ShaderAst: Big refactor + add binding/location support --- SDK/include/NDK/Components.hpp | 9 + SDK/include/NDK/Systems.hpp | 9 + SDK/include/NDK/Widgets.hpp | 9 + include/Nazara/Renderer/GlslWriter.hpp | 86 +-- include/Nazara/Renderer/GlslWriter.inl | 65 +++ include/Nazara/Renderer/ShaderAst.hpp | 434 +++------------ include/Nazara/Renderer/ShaderAst.inl | 369 +++---------- include/Nazara/Renderer/ShaderBuilder.hpp | 70 ++- include/Nazara/Renderer/ShaderBuilder.inl | 37 +- include/Nazara/Renderer/ShaderEnums.hpp | 99 ++++ include/Nazara/Renderer/ShaderNodes.hpp | 272 ++++++++++ include/Nazara/Renderer/ShaderNodes.inl | 300 +++++++++++ include/Nazara/Renderer/ShaderSerializer.hpp | 19 +- include/Nazara/Renderer/ShaderSerializer.inl | 18 +- include/Nazara/Renderer/ShaderValidator.hpp | 47 +- include/Nazara/Renderer/ShaderValidator.inl | 6 +- include/Nazara/Renderer/ShaderVarVisitor.hpp | 34 ++ include/Nazara/Renderer/ShaderVariables.hpp | 127 +++++ include/Nazara/Renderer/ShaderVariables.inl | 65 +++ include/Nazara/Renderer/ShaderVisitor.hpp | 37 +- include/Nazara/Renderer/ShaderWriter.hpp | 14 +- src/Nazara/Renderer/GlslWriter.cpp | 529 +++++++++---------- src/Nazara/Renderer/ShaderAst.cpp | 279 +--------- src/Nazara/Renderer/ShaderNodes.cpp | 179 +++++++ src/Nazara/Renderer/ShaderSerializer.cpp | 149 ++++-- src/Nazara/Renderer/ShaderValidator.cpp | 303 ++++++++--- src/Nazara/Renderer/ShaderVarVisitor.cpp | 16 + src/Nazara/Renderer/ShaderVariables.cpp | 77 +++ src/Nazara/Renderer/ShaderVisitor.cpp | 6 +- src/Nazara/Renderer/ShaderWriter.cpp | 1 + src/ShaderNode/DataModels/Cast.hpp | 2 +- src/ShaderNode/DataModels/Cast.inl | 10 +- src/ShaderNode/DataModels/FloatValue.cpp | 2 +- src/ShaderNode/DataModels/FloatValue.hpp | 2 +- src/ShaderNode/DataModels/InputValue.cpp | 18 +- src/ShaderNode/DataModels/InputValue.hpp | 2 +- src/ShaderNode/DataModels/OutputValue.cpp | 22 +- src/ShaderNode/DataModels/OutputValue.hpp | 2 +- src/ShaderNode/DataModels/SampleTexture.cpp | 2 +- src/ShaderNode/DataModels/SampleTexture.hpp | 2 +- src/ShaderNode/DataModels/ShaderNode.hpp | 4 +- src/ShaderNode/DataModels/TextureValue.cpp | 8 +- src/ShaderNode/DataModels/TextureValue.hpp | 2 +- src/ShaderNode/DataModels/VecBinOp.hpp | 20 +- src/ShaderNode/DataModels/VecBinOp.inl | 22 +- src/ShaderNode/DataModels/VecDot.cpp | 8 +- src/ShaderNode/DataModels/VecDot.hpp | 2 +- src/ShaderNode/DataModels/VecFloatMul.cpp | 6 +- src/ShaderNode/DataModels/VecFloatMul.hpp | 2 +- src/ShaderNode/DataModels/VecValue.hpp | 2 +- src/ShaderNode/DataModels/VecValue.inl | 2 +- src/ShaderNode/DataTypes/TextureData.hpp | 2 +- src/ShaderNode/DataTypes/VecData.cpp | 8 +- src/ShaderNode/DataTypes/VecData.hpp | 14 +- src/ShaderNode/ShaderGraph.cpp | 49 +- src/ShaderNode/ShaderGraph.hpp | 17 +- src/ShaderNode/Widgets/InputEditDialog.cpp | 5 + src/ShaderNode/Widgets/InputEditDialog.hpp | 2 + src/ShaderNode/Widgets/InputEditor.cpp | 4 +- src/ShaderNode/Widgets/MainWindow.cpp | 50 +- src/ShaderNode/Widgets/OutputEditDialog.cpp | 12 +- src/ShaderNode/Widgets/OutputEditDialog.hpp | 5 +- src/ShaderNode/Widgets/OutputEditor.cpp | 8 +- 63 files changed, 2380 insertions(+), 1603 deletions(-) create mode 100644 SDK/include/NDK/Components.hpp create mode 100644 SDK/include/NDK/Systems.hpp create mode 100644 SDK/include/NDK/Widgets.hpp create mode 100644 include/Nazara/Renderer/GlslWriter.inl create mode 100644 include/Nazara/Renderer/ShaderEnums.hpp create mode 100644 include/Nazara/Renderer/ShaderNodes.hpp create mode 100644 include/Nazara/Renderer/ShaderNodes.inl create mode 100644 include/Nazara/Renderer/ShaderVarVisitor.hpp create mode 100644 include/Nazara/Renderer/ShaderVariables.hpp create mode 100644 include/Nazara/Renderer/ShaderVariables.inl create mode 100644 src/Nazara/Renderer/ShaderNodes.cpp create mode 100644 src/Nazara/Renderer/ShaderVarVisitor.cpp create mode 100644 src/Nazara/Renderer/ShaderVariables.cpp diff --git a/SDK/include/NDK/Components.hpp b/SDK/include/NDK/Components.hpp new file mode 100644 index 000000000..97f597990 --- /dev/null +++ b/SDK/include/NDK/Components.hpp @@ -0,0 +1,9 @@ +// This file was automatically generated + +#pragma once + +#ifndef NDK_COMPONENTS_GLOBAL_HPP +#define NDK_COMPONENTS_GLOBAL_HPP + + +#endif // NDK_COMPONENTS_GLOBAL_HPP diff --git a/SDK/include/NDK/Systems.hpp b/SDK/include/NDK/Systems.hpp new file mode 100644 index 000000000..33edfc17a --- /dev/null +++ b/SDK/include/NDK/Systems.hpp @@ -0,0 +1,9 @@ +// This file was automatically generated + +#pragma once + +#ifndef NDK_SYSTEMS_GLOBAL_HPP +#define NDK_SYSTEMS_GLOBAL_HPP + + +#endif // NDK_SYSTEMS_GLOBAL_HPP diff --git a/SDK/include/NDK/Widgets.hpp b/SDK/include/NDK/Widgets.hpp new file mode 100644 index 000000000..b009f3a17 --- /dev/null +++ b/SDK/include/NDK/Widgets.hpp @@ -0,0 +1,9 @@ +// This file was automatically generated + +#pragma once + +#ifndef NDK_WIDGETS_GLOBAL_HPP +#define NDK_WIDGETS_GLOBAL_HPP + + +#endif // NDK_WIDGETS_GLOBAL_HPP diff --git a/include/Nazara/Renderer/GlslWriter.hpp b/include/Nazara/Renderer/GlslWriter.hpp index 2caaa6a75..22d6544f2 100644 --- a/include/Nazara/Renderer/GlslWriter.hpp +++ b/include/Nazara/Renderer/GlslWriter.hpp @@ -8,15 +8,19 @@ #define NAZARA_GLSLWRITER_HPP #include -#include #include +#include +#include +#include #include #include +#include +#include #include namespace Nz { - class NAZARA_RENDERER_API GlslWriter : public ShaderWriter + class NAZARA_RENDERER_API GlslWriter : public ShaderWriter, public ShaderVarVisitor, public ShaderVisitor { public: GlslWriter(); @@ -24,67 +28,65 @@ namespace Nz GlslWriter(GlslWriter&&) = delete; ~GlslWriter() = default; - Nz::String Generate(const ShaderAst::StatementPtr& node) override; - - void RegisterFunction(const String& name, ShaderAst::StatementPtr statement, std::initializer_list parameters, ShaderAst::ExpressionType ret) override; - void RegisterVariable(ShaderAst::VariableType kind, const String& name, ShaderAst::ExpressionType type) override; + std::string Generate(const ShaderAst& shader) override; void SetGlslVersion(unsigned int version); - using ShaderWriter::Visit; - void Visit(const ShaderAst::AssignOp& node) override; - void Visit(const ShaderAst::Branch& node) override; - void Visit(const ShaderAst::BinaryFunc& node) override; - void Visit(const ShaderAst::BinaryOp& node) override; - void Visit(const ShaderAst::BuiltinVariable& node) override; - void Visit(const ShaderAst::Cast& node) override; - void Visit(const ShaderAst::Constant& node) override; - void Visit(const ShaderAst::DeclareVariable& node) override; - void Visit(const ShaderAst::ExpressionStatement& node) override; - void Visit(const ShaderAst::NamedVariable& node) override; - void Visit(const ShaderAst::Sample2D& node) override; - void Visit(const ShaderAst::StatementBlock& node) override; - void Visit(const ShaderAst::SwizzleOp& node) override; - private: - struct Function; - using VariableContainer = std::set>; + void Append(ShaderNodes::BuiltinEntry builtin); + void Append(ShaderNodes::ExpressionType type); + template void Append(const T& param); + void AppendCommentSection(const std::string& section); + void AppendFunction(const ShaderAst::Function& func); + void AppendFunctionPrototype(const ShaderAst::Function& func); + void AppendLine(const std::string& txt = {}); - void Append(ShaderAst::BuiltinEntry builtin); - void Append(ShaderAst::ExpressionType type); - void Append(const String& txt); - void AppendCommentSection(const String& section); - void AppendFunction(Function& func); - void AppendLine(const String& txt = String()); - - void DeclareVariables(const VariableContainer& variables, const String& keyword = String(), const String& section = String()); + template void DeclareVariables(const std::vector& variables, const std::string& keyword = {}, const std::string& section = {}); void EnterScope(); void LeaveScope(); + using ShaderVarVisitor::Visit; + using ShaderVisitor::Visit; + void Visit(const ShaderNodes::AssignOp& node) override; + void Visit(const ShaderNodes::Branch& node) override; + void Visit(const ShaderNodes::BinaryOp& node) override; + void Visit(const ShaderNodes::BuiltinVariable& var) override; + void Visit(const ShaderNodes::Cast& node) override; + void Visit(const ShaderNodes::Constant& node) override; + void Visit(const ShaderNodes::DeclareVariable& node) override; + void Visit(const ShaderNodes::ExpressionStatement& node) override; + void Visit(const ShaderNodes::Identifier& node) override; + void Visit(const ShaderNodes::InputVariable& var) override; + void Visit(const ShaderNodes::IntrinsicCall& node) override; + void Visit(const ShaderNodes::LocalVariable& var) override; + void Visit(const ShaderNodes::ParameterVariable& var) override; + void Visit(const ShaderNodes::OutputVariable& var) override; + void Visit(const ShaderNodes::Sample2D& node) override; + void Visit(const ShaderNodes::StatementBlock& node) override; + void Visit(const ShaderNodes::SwizzleOp& node) override; + void Visit(const ShaderNodes::UniformVariable& var) override; - struct Function + static bool HasExplicitBinding(const ShaderAst& shader); + static bool HasExplicitLocation(const ShaderAst& shader); + + struct Context { - std::vector parameters; - ShaderAst::ExpressionType retType; - ShaderAst::StatementPtr node; - String name; + const ShaderAst::Function* currentFunction = nullptr; }; struct State { - VariableContainer inputs; - VariableContainer outputs; - VariableContainer uniforms; - StringStream stream; + std::stringstream stream; unsigned int indentLevel = 0; }; - std::unordered_map m_functions; - Function* m_currentFunction; + Context m_context; State* m_currentState; unsigned int m_glslVersion; }; } +#include + #endif // NAZARA_GLSLWRITER_HPP diff --git a/include/Nazara/Renderer/GlslWriter.inl b/include/Nazara/Renderer/GlslWriter.inl new file mode 100644 index 000000000..fcaca4b98 --- /dev/null +++ b/include/Nazara/Renderer/GlslWriter.inl @@ -0,0 +1,65 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Renderer module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include + +namespace Nz +{ + template + void GlslWriter::Append(const T& param) + { + NazaraAssert(m_currentState, "This function should only be called while processing an AST"); + + m_currentState->stream << param; + } + + template + void GlslWriter::DeclareVariables(const std::vector& variables, const std::string& keyword, const std::string& section) + { + if (!variables.empty()) + { + if (!section.empty()) + AppendCommentSection(section); + + for (const auto& var : variables) + { + if constexpr (std::is_same_v) + { + if (var.locationIndex) + { + Append("layout(location = "); + Append(*var.locationIndex); + Append(") "); + } + } + else if constexpr (std::is_same_v) + { + if (var.bindingIndex) + { + Append("layout(binding = "); + Append(*var.bindingIndex); + Append(") "); + } + } + + if (!keyword.empty()) + { + Append(keyword); + Append(" "); + } + + Append(var.type); + Append(" "); + Append(var.name); + AppendLine(";"); + } + + AppendLine(); + } + } +} + +#include diff --git a/include/Nazara/Renderer/ShaderAst.hpp b/include/Nazara/Renderer/ShaderAst.hpp index 0bbaec9f3..0aa094a10 100644 --- a/include/Nazara/Renderer/ShaderAst.hpp +++ b/include/Nazara/Renderer/ShaderAst.hpp @@ -8,393 +8,77 @@ #define NAZARA_SHADER_AST_HPP #include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include namespace Nz { - class ByteStream; - class ShaderVisitor; - class ShaderWriter; - - namespace ShaderAst + class NAZARA_RENDERER_API ShaderAst { - enum class AssignType - { - Simple //< = - }; - - enum class BinaryIntrinsic - { - CrossProduct, - DotProduct - }; - - enum class BinaryType - { - Add, //< + - Substract, //< - - Multiply, //< * - Divide, //< / - - Equality //< == - }; - - enum class BuiltinEntry - { - VertexPosition, // gl_Position - }; - - enum class ExpressionCategory - { - LValue, - RValue - }; - - enum class ExpressionType - { - Boolean, // bool - Float1, // float - Float2, // vec2 - Float3, // vec3 - Float4, // vec4 - Mat4x4, // mat4 - Sampler2D, // sampler2D - - Void // void - }; - - enum class NodeType - { - None = -1, - - AssignOp, - BinaryFunc, - BinaryOp, - Branch, - BuiltinVariable, - Cast, - Constant, - ConditionalStatement, - DeclareVariable, - ExpressionStatement, - NamedVariable, - Sample2D, - SwizzleOp, - StatementBlock - }; - - enum class SwizzleComponent - { - First, - Second, - Third, - Fourth - }; - - enum class VariableType - { - Builtin, - Input, - Output, - Parameter, - Uniform, - Variable - }; - - ////////////////////////////////////////////////////////////////////////// - - class Node; - - using NodePtr = std::shared_ptr; - - class NAZARA_RENDERER_API Node - { - public: - virtual ~Node(); - - inline NodeType GetType() const; - - virtual void Register(ShaderWriter& visitor) = 0; - virtual void Visit(ShaderVisitor& visitor) = 0; - - static inline unsigned int GetComponentCount(ExpressionType type); - static inline ExpressionType GetComponentType(ExpressionType type); - - protected: - inline Node(NodeType type); - - private: - NodeType m_type; - }; - - class Statement; - - using StatementPtr = std::shared_ptr; - - class NAZARA_RENDERER_API Statement : public Node - { - public: - using Node::Node; - }; - - class Expression; - - using ExpressionPtr = std::shared_ptr; - - class NAZARA_RENDERER_API Expression : public Node - { - public: - using Node::Node; - - virtual ExpressionCategory GetExpressionCategory() const; - virtual ExpressionType GetExpressionType() const = 0; - }; - - struct NAZARA_RENDERER_API ExpressionStatement : public Statement - { - inline ExpressionStatement(); - - void Register(ShaderWriter& visitor) override; - void Visit(ShaderVisitor& visitor) override; - - ExpressionPtr expression; - - static inline std::shared_ptr Build(ExpressionPtr expr); - }; - - ////////////////////////////////////////////////////////////////////////// - - struct NAZARA_RENDERER_API ConditionalStatement : public Statement - { - inline ConditionalStatement(); - - void Register(ShaderWriter& visitor) override; - void Visit(ShaderVisitor& visitor) override; - - std::string conditionName; - StatementPtr statement; - - static inline std::shared_ptr Build(std::string condition, StatementPtr statementPtr); - }; - - struct NAZARA_RENDERER_API StatementBlock : public Statement - { - inline StatementBlock(); - - void Register(ShaderWriter& visitor) override; - void Visit(ShaderVisitor& visitor) override; - - std::vector statements; - - template static std::shared_ptr Build(Args&&... args); - }; - - struct Variable; - - using VariablePtr = std::shared_ptr; - - struct NAZARA_RENDERER_API Variable : public Expression - { - using Expression::Expression; - - ExpressionCategory GetExpressionCategory() const override; - ExpressionType GetExpressionType() const override; - - ExpressionType type; - VariableType kind; - }; - - - struct NAZARA_RENDERER_API BuiltinVariable : public Variable - { - inline BuiltinVariable(); - - void Register(ShaderWriter& visitor) override; - void Visit(ShaderVisitor& visitor) override; - - BuiltinEntry var; - - static inline std::shared_ptr Build(BuiltinEntry variable, ExpressionType varType); - }; - - - struct NamedVariable; - - using NamedVariablePtr = std::shared_ptr; - - struct NAZARA_RENDERER_API NamedVariable : public Variable - { - inline NamedVariable(); - - void Register(ShaderWriter& visitor) override; - void Visit(ShaderVisitor& visitor) override; - - std::string name; - - static inline std::shared_ptr Build(VariableType varType, std::string varName, ExpressionType expressionType); - }; - - struct NAZARA_RENDERER_API DeclareVariable : public Statement - { - inline DeclareVariable(); - - void Register(ShaderWriter& visitor) override; - void Visit(ShaderVisitor& visitor) override; - - NamedVariablePtr variable; - ExpressionPtr expression; - - static inline std::shared_ptr Build(NamedVariablePtr variable, ExpressionPtr expression = nullptr); - }; - - ////////////////////////////////////////////////////////////////////////// - - struct NAZARA_RENDERER_API AssignOp : public Expression - { - inline AssignOp(); - - ExpressionType GetExpressionType() const override; - void Register(ShaderWriter& visitor) override; - void Visit(ShaderVisitor& visitor) override; - - AssignType op; - ExpressionPtr left; - ExpressionPtr right; - - static inline std::shared_ptr Build(AssignType op, ExpressionPtr left, ExpressionPtr right); - }; - - struct NAZARA_RENDERER_API BinaryOp : public Expression - { - inline BinaryOp(); - - ExpressionType GetExpressionType() const override; - void Register(ShaderWriter& visitor) override; - void Visit(ShaderVisitor& visitor) override; - - BinaryType op; - ExpressionPtr left; - ExpressionPtr right; - - static inline std::shared_ptr Build(BinaryType op, ExpressionPtr left, ExpressionPtr right); - }; - - struct NAZARA_RENDERER_API Branch : public Statement - { - struct ConditionalStatement; - - inline Branch(); - - void Register(ShaderWriter& visitor) override; - void Visit(ShaderVisitor& visitor) override; - - std::vector condStatements; - StatementPtr elseStatement; - - struct ConditionalStatement + public: + struct Function; + struct FunctionParameter; + struct InputOutput; + struct VariableBase; + struct Uniform; + + ShaderAst() = default; + ~ShaderAst() = default; + + void AddFunction(std::string name, ShaderNodes::StatementPtr statement, std::vector parameters = {}, ShaderNodes::ExpressionType returnType = ShaderNodes::ExpressionType::Void); + void AddInput(std::string name, ShaderNodes::ExpressionType type, std::optional locationIndex); + void AddOutput(std::string name, ShaderNodes::ExpressionType type, std::optional locationIndex); + void AddUniform(std::string name, ShaderNodes::ExpressionType type, std::optional bindingIndex); + + inline const Function& GetFunction(std::size_t i) const; + inline std::size_t GetFunctionCount() const; + inline const std::vector& GetFunctions() const; + inline const InputOutput& GetInput(std::size_t i) const; + inline std::size_t GetInputCount() const; + inline const std::vector& GetInputs() const; + inline const InputOutput& GetOutput(std::size_t i) const; + inline std::size_t GetOutputCount() const; + inline const std::vector& GetOutputs() const; + inline const Uniform& GetUniform(std::size_t i) const; + inline std::size_t GetUniformCount() const; + inline const std::vector& GetUniforms() const; + + struct VariableBase { - ExpressionPtr condition; - StatementPtr statement; + std::string name; + ShaderNodes::ExpressionType type; }; - inline std::shared_ptr Build(ExpressionPtr condition, StatementPtr trueStatement, StatementPtr falseStatement = nullptr); - }; - - struct NAZARA_RENDERER_API Cast : public Expression - { - inline Cast(); - - ExpressionType GetExpressionType() const override; - void Register(ShaderWriter& visitor) override; - void Visit(ShaderVisitor& visitor) override; - - ExpressionType exprType; - std::array expressions; - - static inline std::shared_ptr Build(ExpressionType castTo, ExpressionPtr first, ExpressionPtr second = nullptr, ExpressionPtr third = nullptr, ExpressionPtr fourth = nullptr); - static inline std::shared_ptr Build(ExpressionType castTo, ExpressionPtr* expressions, std::size_t expressionCount); - }; - - struct NAZARA_RENDERER_API Constant : public Expression - { - inline Constant(); - - ExpressionType GetExpressionType() const override; - void Register(ShaderWriter& visitor) override; - void Visit(ShaderVisitor& visitor) override; - - ExpressionType exprType; - - union + struct FunctionParameter : VariableBase { - bool bool1; - float vec1; - Vector2f vec2; - Vector3f vec3; - Vector4f vec4; - } values; + }; - static inline std::shared_ptr Build(bool value); - static inline std::shared_ptr Build(float value); - static inline std::shared_ptr Build(const Vector2f& value); - static inline std::shared_ptr Build(const Vector3f& value); - static inline std::shared_ptr Build(const Vector4f& value); - }; + struct Function + { + std::string name; + std::vector parameters; + ShaderNodes::ExpressionType returnType; + ShaderNodes::StatementPtr statement; + }; - struct NAZARA_RENDERER_API SwizzleOp : public Expression - { - inline SwizzleOp(); + struct InputOutput : VariableBase + { + std::optional locationIndex; + }; - ExpressionCategory GetExpressionCategory() const override; - ExpressionType GetExpressionType() const override; - void Register(ShaderWriter& visitor) override; - void Visit(ShaderVisitor& visitor) override; + struct Uniform : VariableBase + { + std::optional bindingIndex; + }; - std::array components; - std::size_t componentCount; - ExpressionPtr expression; - - static inline std::shared_ptr Build(ExpressionPtr expressionPtr, std::initializer_list swizzleComponents); - }; - - ////////////////////////////////////////////////////////////////////////// - - struct NAZARA_RENDERER_API Sample2D : public Expression - { - inline Sample2D(); - - ExpressionType GetExpressionType() const override; - void Register(ShaderWriter& visitor) override; - void Visit(ShaderVisitor& visitor) override; - - ExpressionPtr sampler; - ExpressionPtr coordinates; - - static inline std::shared_ptr Build(ExpressionPtr samplerPtr, ExpressionPtr coordinatesPtr); - }; - - ////////////////////////////////////////////////////////////////////////// - - struct NAZARA_RENDERER_API BinaryFunc : public Expression - { - inline BinaryFunc(); - - ExpressionType GetExpressionType() const override; - void Register(ShaderWriter& visitor) override; - void Visit(ShaderVisitor& visitor) override; - - BinaryIntrinsic intrinsic; - ExpressionPtr left; - ExpressionPtr right; - - static inline std::shared_ptr Build(BinaryIntrinsic intrinsic, ExpressionPtr left, ExpressionPtr right); - }; - } + private: + std::vector m_functions; + std::vector m_inputs; + std::vector m_outputs; + std::vector m_uniforms; + }; } #include diff --git a/include/Nazara/Renderer/ShaderAst.inl b/include/Nazara/Renderer/ShaderAst.inl index 536758832..d9f8f88aa 100644 --- a/include/Nazara/Renderer/ShaderAst.inl +++ b/include/Nazara/Renderer/ShaderAst.inl @@ -7,315 +7,68 @@ namespace Nz { - namespace ShaderAst + inline auto ShaderAst::GetFunction(std::size_t i) const -> const Function& { - inline Node::Node(NodeType type) : - m_type(type) - { - } - - inline NodeType ShaderAst::Node::GetType() const - { - return m_type; - } - - inline unsigned int Node::GetComponentCount(ExpressionType type) - { - switch (type) - { - case ExpressionType::Float2: - return 2; - - case ExpressionType::Float3: - return 3; - - case ExpressionType::Float4: - return 4; - - case ExpressionType::Mat4x4: - return 4; - - default: - return 1; - } - } - - inline ExpressionType Node::GetComponentType(ExpressionType type) - { - switch (type) - { - case ExpressionType::Float2: - case ExpressionType::Float3: - case ExpressionType::Float4: - return ExpressionType::Float1; - - case ExpressionType::Mat4x4: - return ExpressionType::Float4; - - default: - return type; - } - } - - inline ExpressionStatement::ExpressionStatement() : - Statement(NodeType::ExpressionStatement) - { - } - - inline std::shared_ptr ExpressionStatement::Build(ExpressionPtr expr) - { - auto node = std::make_shared(); - node->expression = std::move(expr); - - return node; - } - - inline ConditionalStatement::ConditionalStatement() : - Statement(NodeType::ConditionalStatement) - { - } - - inline std::shared_ptr ConditionalStatement::Build(std::string condition, StatementPtr statementPtr) - { - auto node = std::make_shared(); - node->conditionName = std::move(condition); - node->statement = std::move(statementPtr); - - return node; - } - - - inline StatementBlock::StatementBlock() : - Statement(NodeType::StatementBlock) - { - } - - template - std::shared_ptr StatementBlock::Build(Args&&... args) - { - auto node = std::make_shared(); - node->statements = std::vector({ std::forward(args)... }); - - return node; - } - - - inline BuiltinVariable::BuiltinVariable() : - Variable(NodeType::BuiltinVariable) - { - kind = VariableType::Builtin; - } - - inline std::shared_ptr BuiltinVariable::Build(BuiltinEntry variable, ExpressionType varType) - { - auto node = std::make_shared(); - node->type = varType; - node->var = variable; - - return node; - } - - - inline NamedVariable::NamedVariable() : - Variable(NodeType::NamedVariable) - { - } - - inline std::shared_ptr NamedVariable::Build(VariableType type, std::string varName, ExpressionType expressionType) - { - auto node = std::make_shared(); - node->kind = type; - node->name = std::move(varName); - node->type = expressionType; - - return node; - } - - - inline DeclareVariable::DeclareVariable() : - Statement(NodeType::DeclareVariable) - { - } - - inline std::shared_ptr DeclareVariable::Build(NamedVariablePtr variable, ExpressionPtr expression) - { - auto node = std::make_shared(); - node->expression = std::move(expression); - node->variable = std::move(variable); - - return node; - } - - - inline AssignOp::AssignOp() : - Expression(NodeType::AssignOp) - { - } - - inline std::shared_ptr AssignOp::Build(AssignType op, ExpressionPtr left, ExpressionPtr right) - { - auto node = std::make_shared(); - node->op = op; - node->left = std::move(left); - node->right = std::move(right); - - return node; - } - - - inline BinaryOp::BinaryOp() : - Expression(NodeType::BinaryOp) - { - } - - inline std::shared_ptr BinaryOp::Build(BinaryType op, ExpressionPtr left, ExpressionPtr right) - { - auto node = std::make_shared(); - node->op = op; - node->left = std::move(left); - node->right = std::move(right); - - return node; - } - - - inline Branch::Branch() : - Statement(NodeType::Branch) - { - } - - inline std::shared_ptr Branch::Build(ExpressionPtr condition, StatementPtr trueStatement, StatementPtr falseStatement) - { - auto node = std::make_shared(); - node->condStatements.emplace_back(ConditionalStatement{ std::move(condition), std::move(trueStatement) }); - node->elseStatement = std::move(falseStatement); - - return node; - } - - - inline Cast::Cast() : - Expression(NodeType::Cast) - { - } - - inline std::shared_ptr Cast::Build(ExpressionType castTo, ExpressionPtr first, ExpressionPtr second, ExpressionPtr third, ExpressionPtr fourth) - { - auto node = std::make_shared(); - node->exprType = castTo; - node->expressions = { {first, second, third, fourth} }; - - return node; - } - - inline std::shared_ptr Cast::Build(ExpressionType castTo, ExpressionPtr* Expressions, std::size_t expressionCount) - { - auto node = std::make_shared(); - node->exprType = castTo; - for (std::size_t i = 0; i < expressionCount; ++i) - node->expressions[i] = Expressions[i]; - - return node; - } - - - inline Constant::Constant() : - Expression(NodeType::Constant) - { - } - - inline std::shared_ptr Constant::Build(bool value) - { - auto node = std::make_shared(); - node->exprType = ExpressionType::Boolean; - node->values.bool1 = value; - - return node; - } - - inline std::shared_ptr Constant::Build(float value) - { - auto node = std::make_shared(); - node->exprType = ExpressionType::Float1; - node->values.vec1 = value; - - return node; - } - - inline std::shared_ptr Constant::Build(const Vector2f& value) - { - auto node = std::make_shared(); - node->exprType = ExpressionType::Float2; - node->values.vec2 = value; - - return node; - } - - inline std::shared_ptr Constant::Build(const Vector3f& value) - { - auto node = std::make_shared(); - node->exprType = ExpressionType::Float3; - node->values.vec3 = value; - - return node; - } - - inline std::shared_ptr Constant::Build(const Vector4f& value) - { - auto node = std::make_shared(); - node->exprType = ExpressionType::Float4; - node->values.vec4 = value; - - return node; - } - - - inline SwizzleOp::SwizzleOp() : - Expression(NodeType::SwizzleOp) - { - } - - inline std::shared_ptr SwizzleOp::Build(ExpressionPtr expressionPtr, std::initializer_list swizzleComponents) - { - auto node = std::make_shared(); - node->componentCount = swizzleComponents.size(); - node->expression = std::move(expressionPtr); - - std::copy(swizzleComponents.begin(), swizzleComponents.end(), node->components.begin()); - - return node; - } - - - inline Sample2D::Sample2D() : - Expression(NodeType::Sample2D) - { - } - - inline std::shared_ptr Sample2D::Build(ExpressionPtr samplerPtr, ExpressionPtr coordinatesPtr) - { - auto node = std::make_shared(); - node->coordinates = std::move(coordinatesPtr); - node->sampler = std::move(samplerPtr); - - return node; - } - - - inline BinaryFunc::BinaryFunc() : - Expression(NodeType::BinaryFunc) - { - } - - inline std::shared_ptr BinaryFunc::Build(BinaryIntrinsic intrinsic, ExpressionPtr left, ExpressionPtr right) - { - auto node = std::make_shared(); - node->intrinsic = intrinsic; - node->left = std::move(left); - node->right = std::move(right); - - return node; - } + assert(i < m_functions.size()); + return m_functions[i]; + } + + inline std::size_t ShaderAst::GetFunctionCount() const + { + return m_functions.size(); + } + + inline auto ShaderAst::GetFunctions() const -> const std::vector& + { + return m_functions; + } + + inline auto ShaderAst::GetInput(std::size_t i) const -> const InputOutput& + { + assert(i < m_inputs.size()); + return m_inputs[i]; + } + + inline std::size_t ShaderAst::GetInputCount() const + { + return m_inputs.size(); + } + + inline auto ShaderAst::GetInputs() const -> const std::vector& + { + return m_inputs; + } + + inline auto ShaderAst::GetOutput(std::size_t i) const -> const InputOutput& + { + assert(i < m_outputs.size()); + return m_outputs[i]; + } + + inline std::size_t ShaderAst::GetOutputCount() const + { + return m_outputs.size(); + } + + inline auto ShaderAst::GetOutputs() const -> const std::vector& + { + return m_outputs; + } + + inline auto ShaderAst::GetUniform(std::size_t i) const -> const Uniform& + { + assert(i < m_uniforms.size()); + return m_uniforms[i]; + } + + inline std::size_t ShaderAst::GetUniformCount() const + { + return m_uniforms.size(); + } + + inline auto ShaderAst::GetUniforms() const -> const std::vector& + { + return m_uniforms; } } diff --git a/include/Nazara/Renderer/ShaderBuilder.hpp b/include/Nazara/Renderer/ShaderBuilder.hpp index f8140ab42..cc437f45f 100644 --- a/include/Nazara/Renderer/ShaderBuilder.hpp +++ b/include/Nazara/Renderer/ShaderBuilder.hpp @@ -8,72 +8,66 @@ #define NAZARA_SHADER_BUILDER_HPP #include -#include +#include #include namespace Nz::ShaderBuilder { - template + template struct AssignOpBuilder { - constexpr AssignOpBuilder() {} + constexpr AssignOpBuilder() = default; - std::shared_ptr operator()(const ShaderAst::ExpressionPtr& left, const ShaderAst::ExpressionPtr& right) const; + std::shared_ptr operator()(const ShaderNodes::ExpressionPtr& left, const ShaderNodes::ExpressionPtr& right) const; }; - template + template struct BinOpBuilder { - constexpr BinOpBuilder() {} + constexpr BinOpBuilder() = default; - std::shared_ptr operator()(const ShaderAst::ExpressionPtr& left, const ShaderAst::ExpressionPtr& right) const; + std::shared_ptr operator()(const ShaderNodes::ExpressionPtr& left, const ShaderNodes::ExpressionPtr& right) const; }; struct BuiltinBuilder { - constexpr BuiltinBuilder() {} + constexpr BuiltinBuilder() = default; - inline std::shared_ptr operator()(ShaderAst::BuiltinEntry builtin) const; + inline std::shared_ptr operator()(ShaderNodes::BuiltinEntry builtin) const; }; template struct GenBuilder { - constexpr GenBuilder() {} + constexpr GenBuilder() = default; template std::shared_ptr operator()(Args&&... args) const; }; - template - struct VarBuilder - { - constexpr VarBuilder() {} - - template ShaderAst::NamedVariablePtr operator()(Args&&... args) const; - }; - - constexpr BinOpBuilder Add; - constexpr AssignOpBuilder Assign; + constexpr BinOpBuilder Add; + constexpr AssignOpBuilder Assign; constexpr BuiltinBuilder Builtin; - constexpr GenBuilder Block; - constexpr GenBuilder Branch; - constexpr GenBuilder ConditionalStatement; - constexpr GenBuilder Constant; - constexpr GenBuilder DeclareVariable; - constexpr BinOpBuilder Divide; - constexpr BinOpBuilder Equal; - constexpr GenBuilder ExprStatement; - constexpr VarBuilder Input; - constexpr BinOpBuilder Multiply; - constexpr VarBuilder Output; - constexpr VarBuilder Parameter; - constexpr GenBuilder Sample2D; - constexpr GenBuilder Swizzle; - constexpr BinOpBuilder Substract; - constexpr VarBuilder Uniform; - constexpr VarBuilder Variable; + constexpr GenBuilder Block; + constexpr GenBuilder Branch; + constexpr GenBuilder ConditionalStatement; + constexpr GenBuilder Constant; + constexpr GenBuilder DeclareVariable; + constexpr BinOpBuilder Divide; + constexpr BinOpBuilder Equal; + constexpr GenBuilder ExprStatement; + constexpr GenBuilder Identifier; + constexpr GenBuilder IntrinsicCall; + constexpr GenBuilder Input; + constexpr GenBuilder Local; + constexpr BinOpBuilder Multiply; + constexpr GenBuilder Output; + constexpr GenBuilder Parameter; + constexpr GenBuilder Sample2D; + constexpr GenBuilder Swizzle; + constexpr BinOpBuilder Substract; + constexpr GenBuilder Uniform; - template std::shared_ptr Cast(Args&&... args); + template std::shared_ptr Cast(Args&&... args); } #include diff --git a/include/Nazara/Renderer/ShaderBuilder.inl b/include/Nazara/Renderer/ShaderBuilder.inl index 7f9612a11..dda1d730b 100644 --- a/include/Nazara/Renderer/ShaderBuilder.inl +++ b/include/Nazara/Renderer/ShaderBuilder.inl @@ -14,45 +14,38 @@ namespace Nz::ShaderBuilder return T::Build(std::forward(args)...); } - template - std::shared_ptr AssignOpBuilder::operator()(const ShaderAst::ExpressionPtr& left, const ShaderAst::ExpressionPtr& right) const + template + std::shared_ptr AssignOpBuilder::operator()(const ShaderNodes::ExpressionPtr& left, const ShaderNodes::ExpressionPtr& right) const { - return ShaderAst::AssignOp::Build(op, left, right); + return ShaderNodes::AssignOp::Build(op, left, right); } - template - std::shared_ptr BinOpBuilder::operator()(const ShaderAst::ExpressionPtr& left, const ShaderAst::ExpressionPtr& right) const + template + std::shared_ptr BinOpBuilder::operator()(const ShaderNodes::ExpressionPtr& left, const ShaderNodes::ExpressionPtr& right) const { - return ShaderAst::BinaryOp::Build(op, left, right); + return ShaderNodes::BinaryOp::Build(op, left, right); } - inline std::shared_ptr BuiltinBuilder::operator()(ShaderAst::BuiltinEntry builtin) const + inline std::shared_ptr BuiltinBuilder::operator()(ShaderNodes::BuiltinEntry builtin) const { - ShaderAst::ExpressionType exprType = ShaderAst::ExpressionType::Void; + ShaderNodes::ExpressionType exprType = ShaderNodes::ExpressionType::Void; switch (builtin) { - case ShaderAst::BuiltinEntry::VertexPosition: - exprType = ShaderAst::ExpressionType::Float4; + case ShaderNodes::BuiltinEntry::VertexPosition: + exprType = ShaderNodes::ExpressionType::Float4; break; } - NazaraAssert(exprType != ShaderAst::ExpressionType::Void, "Unhandled builtin"); + NazaraAssert(exprType != ShaderNodes::ExpressionType::Void, "Unhandled builtin"); - return ShaderAst::BuiltinVariable::Build(builtin, exprType); + return ShaderNodes::BuiltinVariable::Build(builtin, exprType); } - template - template - ShaderAst::NamedVariablePtr VarBuilder::operator()(Args&&... args) const + template + std::shared_ptr Cast(Args&&... args) { - return ShaderAst::NamedVariable::Build(type, std::forward(args)...); - } - - template - std::shared_ptr Cast(Args&&... args) - { - return ShaderAst::Cast::Build(Type, std::forward(args)...); + return ShaderNodes::Cast::Build(Type, std::forward(args)...); } } diff --git a/include/Nazara/Renderer/ShaderEnums.hpp b/include/Nazara/Renderer/ShaderEnums.hpp new file mode 100644 index 000000000..f400c7516 --- /dev/null +++ b/include/Nazara/Renderer/ShaderEnums.hpp @@ -0,0 +1,99 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Renderer module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_SHADER_ENUMS_HPP +#define NAZARA_SHADER_ENUMS_HPP + +#include + +namespace Nz::ShaderNodes +{ + enum class AssignType + { + Simple //< = + }; + + enum class BinaryType + { + Add, //< + + Substract, //< - + Multiply, //< * + Divide, //< / + + Equality //< == + }; + + enum class BuiltinEntry + { + VertexPosition, // gl_Position + }; + + enum class ExpressionCategory + { + LValue, + RValue + }; + + enum class ExpressionType + { + Boolean, // bool + Float1, // float + Float2, // vec2 + Float3, // vec3 + Float4, // vec4 + Mat4x4, // mat4 + Sampler2D, // sampler2D + + Void // void + }; + + enum class IntrinsicType + { + CrossProduct, + DotProduct + }; + + enum class NodeType + { + None = -1, + + AssignOp, + BinaryOp, + Branch, + Cast, + Constant, + ConditionalStatement, + DeclareVariable, + ExpressionStatement, + Identifier, + IntrinsicCall, + Sample2D, + SwizzleOp, + StatementBlock + }; + + enum class SwizzleComponent + { + First, + Second, + Third, + Fourth + }; + + enum class VariableType + { + None = -1, + + BuiltinVariable, + InputVariable, + LocalVariable, + OutputVariable, + ParameterVariable, + UniformVariable + }; +} + +#endif // NAZARA_SHADER_ENUMS_HPP diff --git a/include/Nazara/Renderer/ShaderNodes.hpp b/include/Nazara/Renderer/ShaderNodes.hpp new file mode 100644 index 000000000..d6bafc911 --- /dev/null +++ b/include/Nazara/Renderer/ShaderNodes.hpp @@ -0,0 +1,272 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Renderer module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_SHADER_NODES_HPP +#define NAZARA_SHADER_NODES_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + class ShaderVisitor; + + namespace ShaderNodes + { + class Node; + + using NodePtr = std::shared_ptr; + + class NAZARA_RENDERER_API Node + { + public: + virtual ~Node(); + + inline NodeType GetType() const; + + virtual void Visit(ShaderVisitor& visitor) = 0; + + static inline unsigned int GetComponentCount(ExpressionType type); + static inline ExpressionType GetComponentType(ExpressionType type); + + protected: + inline Node(NodeType type); + + private: + NodeType m_type; + }; + + class Statement; + + using StatementPtr = std::shared_ptr; + + class NAZARA_RENDERER_API Statement : public Node + { + public: + using Node::Node; + }; + + class Expression; + + using ExpressionPtr = std::shared_ptr; + + class NAZARA_RENDERER_API Expression : public Node + { + public: + using Node::Node; + + virtual ExpressionCategory GetExpressionCategory() const; + virtual ExpressionType GetExpressionType() const = 0; + }; + + struct NAZARA_RENDERER_API ExpressionStatement : public Statement + { + inline ExpressionStatement(); + + void Visit(ShaderVisitor& visitor) override; + + ExpressionPtr expression; + + static inline std::shared_ptr Build(ExpressionPtr expr); + }; + + ////////////////////////////////////////////////////////////////////////// + + struct NAZARA_RENDERER_API ConditionalStatement : public Statement + { + inline ConditionalStatement(); + + void Visit(ShaderVisitor& visitor) override; + + std::string conditionName; + StatementPtr statement; + + static inline std::shared_ptr Build(std::string condition, StatementPtr statementPtr); + }; + + struct NAZARA_RENDERER_API StatementBlock : public Statement + { + inline StatementBlock(); + + void Visit(ShaderVisitor& visitor) override; + + std::vector statements; + + template static std::shared_ptr Build(Args&&... args); + }; + + struct NAZARA_RENDERER_API DeclareVariable : public Statement + { + inline DeclareVariable(); + + void Visit(ShaderVisitor& visitor) override; + + LocalVariablePtr variable; + ExpressionPtr expression; + + static inline std::shared_ptr Build(LocalVariablePtr variable, ExpressionPtr expression = nullptr); + }; + + struct NAZARA_RENDERER_API Identifier : public Expression + { + inline Identifier(); + + ExpressionCategory GetExpressionCategory() const override; + ExpressionType GetExpressionType() const override; + void Visit(ShaderVisitor& visitor) override; + + VariablePtr var; + + static inline std::shared_ptr Build(VariablePtr variable); + }; + + ////////////////////////////////////////////////////////////////////////// + + struct NAZARA_RENDERER_API AssignOp : public Expression + { + inline AssignOp(); + + ExpressionType GetExpressionType() const override; + void Visit(ShaderVisitor& visitor) override; + + AssignType op; + ExpressionPtr left; + ExpressionPtr right; + + static inline std::shared_ptr Build(AssignType op, ExpressionPtr left, ExpressionPtr right); + }; + + struct NAZARA_RENDERER_API BinaryOp : public Expression + { + inline BinaryOp(); + + ExpressionType GetExpressionType() const override; + void Visit(ShaderVisitor& visitor) override; + + BinaryType op; + ExpressionPtr left; + ExpressionPtr right; + + static inline std::shared_ptr Build(BinaryType op, ExpressionPtr left, ExpressionPtr right); + }; + + struct NAZARA_RENDERER_API Branch : public Statement + { + struct ConditionalStatement; + + inline Branch(); + + void Visit(ShaderVisitor& visitor) override; + + std::vector condStatements; + StatementPtr elseStatement; + + struct ConditionalStatement + { + ExpressionPtr condition; + StatementPtr statement; + }; + + inline std::shared_ptr Build(ExpressionPtr condition, StatementPtr trueStatement, StatementPtr falseStatement = nullptr); + }; + + struct NAZARA_RENDERER_API Cast : public Expression + { + inline Cast(); + + ExpressionType GetExpressionType() const override; + void Visit(ShaderVisitor& visitor) override; + + ExpressionType exprType; + std::array expressions; + + static inline std::shared_ptr Build(ExpressionType castTo, ExpressionPtr first, ExpressionPtr second = nullptr, ExpressionPtr third = nullptr, ExpressionPtr fourth = nullptr); + static inline std::shared_ptr Build(ExpressionType castTo, ExpressionPtr* expressions, std::size_t expressionCount); + }; + + struct NAZARA_RENDERER_API Constant : public Expression + { + inline Constant(); + + ExpressionType GetExpressionType() const override; + void Visit(ShaderVisitor& visitor) override; + + ExpressionType exprType; + + union + { + bool bool1; + float vec1; + Vector2f vec2; + Vector3f vec3; + Vector4f vec4; + } values; + + static inline std::shared_ptr Build(bool value); + static inline std::shared_ptr Build(float value); + static inline std::shared_ptr Build(const Vector2f& value); + static inline std::shared_ptr Build(const Vector3f& value); + static inline std::shared_ptr Build(const Vector4f& value); + }; + + struct NAZARA_RENDERER_API SwizzleOp : public Expression + { + inline SwizzleOp(); + + ExpressionCategory GetExpressionCategory() const override; + ExpressionType GetExpressionType() const override; + void Visit(ShaderVisitor& visitor) override; + + std::array components; + std::size_t componentCount; + ExpressionPtr expression; + + static inline std::shared_ptr Build(ExpressionPtr expressionPtr, std::initializer_list swizzleComponents); + }; + + ////////////////////////////////////////////////////////////////////////// + + struct NAZARA_RENDERER_API Sample2D : public Expression + { + inline Sample2D(); + + ExpressionType GetExpressionType() const override; + void Visit(ShaderVisitor& visitor) override; + + ExpressionPtr sampler; + ExpressionPtr coordinates; + + static inline std::shared_ptr Build(ExpressionPtr samplerPtr, ExpressionPtr coordinatesPtr); + }; + + ////////////////////////////////////////////////////////////////////////// + + struct NAZARA_RENDERER_API IntrinsicCall : public Expression + { + inline IntrinsicCall(); + + ExpressionType GetExpressionType() const override; + void Visit(ShaderVisitor& visitor) override; + + IntrinsicType intrinsic; + std::vector parameters; + + static inline std::shared_ptr Build(IntrinsicType intrinsic, std::vector parameters); + }; + } +} + +#include + +#endif diff --git a/include/Nazara/Renderer/ShaderNodes.inl b/include/Nazara/Renderer/ShaderNodes.inl new file mode 100644 index 000000000..1bcf4effa --- /dev/null +++ b/include/Nazara/Renderer/ShaderNodes.inl @@ -0,0 +1,300 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Renderer module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include + +namespace Nz::ShaderNodes +{ + inline Node::Node(NodeType type) : + m_type(type) + { + } + + inline NodeType ShaderNodes::Node::GetType() const + { + return m_type; + } + + inline unsigned int Node::GetComponentCount(ExpressionType type) + { + switch (type) + { + case ExpressionType::Float2: + return 2; + + case ExpressionType::Float3: + return 3; + + case ExpressionType::Float4: + return 4; + + case ExpressionType::Mat4x4: + return 4; + + default: + return 1; + } + } + + inline ExpressionType Node::GetComponentType(ExpressionType type) + { + switch (type) + { + case ExpressionType::Float2: + case ExpressionType::Float3: + case ExpressionType::Float4: + return ExpressionType::Float1; + + case ExpressionType::Mat4x4: + return ExpressionType::Float4; + + default: + return type; + } + } + + inline ExpressionStatement::ExpressionStatement() : + Statement(NodeType::ExpressionStatement) + { + } + + inline std::shared_ptr ExpressionStatement::Build(ExpressionPtr expr) + { + auto node = std::make_shared(); + node->expression = std::move(expr); + + return node; + } + + inline ConditionalStatement::ConditionalStatement() : + Statement(NodeType::ConditionalStatement) + { + } + + inline std::shared_ptr ConditionalStatement::Build(std::string condition, StatementPtr statementPtr) + { + auto node = std::make_shared(); + node->conditionName = std::move(condition); + node->statement = std::move(statementPtr); + + return node; + } + + + inline StatementBlock::StatementBlock() : + Statement(NodeType::StatementBlock) + { + } + + template + std::shared_ptr StatementBlock::Build(Args&&... args) + { + auto node = std::make_shared(); + node->statements = std::vector({ std::forward(args)... }); + + return node; + } + + + inline DeclareVariable::DeclareVariable() : + Statement(NodeType::DeclareVariable) + { + } + + inline std::shared_ptr DeclareVariable::Build(LocalVariablePtr variable, ExpressionPtr expression) + { + auto node = std::make_shared(); + node->expression = std::move(expression); + node->variable = std::move(variable); + + return node; + } + + + inline Identifier::Identifier() : + Expression(NodeType::Identifier) + { + } + + inline std::shared_ptr Identifier::Build(VariablePtr variable) + { + auto node = std::make_shared(); + node->var = std::move(variable); + + return node; + } + + + inline AssignOp::AssignOp() : + Expression(NodeType::AssignOp) + { + } + + inline std::shared_ptr AssignOp::Build(AssignType op, ExpressionPtr left, ExpressionPtr right) + { + auto node = std::make_shared(); + node->op = op; + node->left = std::move(left); + node->right = std::move(right); + + return node; + } + + + inline BinaryOp::BinaryOp() : + Expression(NodeType::BinaryOp) + { + } + + inline std::shared_ptr BinaryOp::Build(BinaryType op, ExpressionPtr left, ExpressionPtr right) + { + auto node = std::make_shared(); + node->op = op; + node->left = std::move(left); + node->right = std::move(right); + + return node; + } + + + inline Branch::Branch() : + Statement(NodeType::Branch) + { + } + + inline std::shared_ptr Branch::Build(ExpressionPtr condition, StatementPtr trueStatement, StatementPtr falseStatement) + { + auto node = std::make_shared(); + node->condStatements.emplace_back(ConditionalStatement{ std::move(condition), std::move(trueStatement) }); + node->elseStatement = std::move(falseStatement); + + return node; + } + + + inline Cast::Cast() : + Expression(NodeType::Cast) + { + } + + inline std::shared_ptr Cast::Build(ExpressionType castTo, ExpressionPtr first, ExpressionPtr second, ExpressionPtr third, ExpressionPtr fourth) + { + auto node = std::make_shared(); + node->exprType = castTo; + node->expressions = { {first, second, third, fourth} }; + + return node; + } + + inline std::shared_ptr Cast::Build(ExpressionType castTo, ExpressionPtr* Expressions, std::size_t expressionCount) + { + auto node = std::make_shared(); + node->exprType = castTo; + for (std::size_t i = 0; i < expressionCount; ++i) + node->expressions[i] = Expressions[i]; + + return node; + } + + + inline Constant::Constant() : + Expression(NodeType::Constant) + { + } + + inline std::shared_ptr Constant::Build(bool value) + { + auto node = std::make_shared(); + node->exprType = ExpressionType::Boolean; + node->values.bool1 = value; + + return node; + } + + inline std::shared_ptr Constant::Build(float value) + { + auto node = std::make_shared(); + node->exprType = ExpressionType::Float1; + node->values.vec1 = value; + + return node; + } + + inline std::shared_ptr Constant::Build(const Vector2f& value) + { + auto node = std::make_shared(); + node->exprType = ExpressionType::Float2; + node->values.vec2 = value; + + return node; + } + + inline std::shared_ptr Constant::Build(const Vector3f& value) + { + auto node = std::make_shared(); + node->exprType = ExpressionType::Float3; + node->values.vec3 = value; + + return node; + } + + inline std::shared_ptr Constant::Build(const Vector4f& value) + { + auto node = std::make_shared(); + node->exprType = ExpressionType::Float4; + node->values.vec4 = value; + + return node; + } + + + inline SwizzleOp::SwizzleOp() : + Expression(NodeType::SwizzleOp) + { + } + + inline std::shared_ptr SwizzleOp::Build(ExpressionPtr expressionPtr, std::initializer_list swizzleComponents) + { + auto node = std::make_shared(); + node->componentCount = swizzleComponents.size(); + node->expression = std::move(expressionPtr); + + std::copy(swizzleComponents.begin(), swizzleComponents.end(), node->components.begin()); + + return node; + } + + + inline Sample2D::Sample2D() : + Expression(NodeType::Sample2D) + { + } + + inline std::shared_ptr Sample2D::Build(ExpressionPtr samplerPtr, ExpressionPtr coordinatesPtr) + { + auto node = std::make_shared(); + node->coordinates = std::move(coordinatesPtr); + node->sampler = std::move(samplerPtr); + + return node; + } + + + inline IntrinsicCall::IntrinsicCall() : + Expression(NodeType::IntrinsicCall) + { + } + + inline std::shared_ptr IntrinsicCall::Build(IntrinsicType intrinsic, std::vector parameters) + { + auto node = std::make_shared(); + node->intrinsic = intrinsic; + node->parameters = std::move(parameters); + + return node; + } +} + +#include diff --git a/include/Nazara/Renderer/ShaderSerializer.hpp b/include/Nazara/Renderer/ShaderSerializer.hpp index 521284370..daeb13e73 100644 --- a/include/Nazara/Renderer/ShaderSerializer.hpp +++ b/include/Nazara/Renderer/ShaderSerializer.hpp @@ -11,9 +11,10 @@ #include #include #include -#include +#include +#include -namespace Nz::ShaderAst +namespace Nz::ShaderNodes { class NAZARA_RENDERER_API ShaderSerializerBase { @@ -24,15 +25,16 @@ namespace Nz::ShaderAst ~ShaderSerializerBase() = default; void Serialize(AssignOp& node); - void Serialize(BinaryFunc& node); void Serialize(BinaryOp& node); + void Serialize(BuiltinVariable& var); void Serialize(Branch& node); - void Serialize(BuiltinVariable& node); void Serialize(Cast& node); void Serialize(Constant& node); void Serialize(DeclareVariable& node); void Serialize(ExpressionStatement& node); - void Serialize(NamedVariable& node); + void Serialize(Identifier& node); + void Serialize(IntrinsicCall& node); + void Serialize(NamedVariable& var); void Serialize(Sample2D& node); void Serialize(StatementBlock& node); void Serialize(SwizzleOp& node); @@ -54,6 +56,9 @@ namespace Nz::ShaderAst virtual void Value(Vector4f& val) = 0; virtual void Value(UInt32& val) = 0; inline void Value(std::size_t& val); + + virtual void Variable(VariablePtr& var) = 0; + template void Variable(std::shared_ptr& var); }; class NAZARA_RENDERER_API ShaderSerializer final : public ShaderSerializerBase @@ -74,6 +79,7 @@ namespace Nz::ShaderAst void Value(Vector3f& val) override; void Value(Vector4f& val) override; void Value(UInt32& val) override; + void Variable(VariablePtr& var) override; ByteArray& m_byteArray; ByteStream m_stream; @@ -89,7 +95,7 @@ namespace Nz::ShaderAst private: bool IsWriting() const override; - void Node(NodePtr & node) override; + void Node(NodePtr& node) override; void Value(bool& val) override; void Value(float& val) override; void Value(std::string& val) override; @@ -97,6 +103,7 @@ namespace Nz::ShaderAst void Value(Vector3f& val) override; void Value(Vector4f& val) override; void Value(UInt32& val) override; + void Variable(VariablePtr& var) override; const ByteArray& m_byteArray; ByteStream m_stream; diff --git a/include/Nazara/Renderer/ShaderSerializer.inl b/include/Nazara/Renderer/ShaderSerializer.inl index 2d8f5bc85..354986bb1 100644 --- a/include/Nazara/Renderer/ShaderSerializer.inl +++ b/include/Nazara/Renderer/ShaderSerializer.inl @@ -5,7 +5,7 @@ #include #include -namespace Nz::ShaderAst +namespace Nz::ShaderNodes { template void ShaderSerializerBase::Container(T& container) @@ -37,7 +37,7 @@ namespace Nz::ShaderAst } template - inline void ShaderSerializerBase::Node(std::shared_ptr& node) + void ShaderSerializerBase::Node(std::shared_ptr& node) { bool isWriting = IsWriting(); @@ -50,6 +50,20 @@ namespace Nz::ShaderAst node = std::static_pointer_cast(value); } + template + void ShaderSerializerBase::Variable(std::shared_ptr& var) + { + bool isWriting = IsWriting(); + + VariablePtr value; + if (isWriting) + value = var; + + Variable(value); + if (!isWriting) + var = std::static_pointer_cast(value); + } + inline void ShaderSerializerBase::Value(std::size_t& val) { bool isWriting = IsWriting(); diff --git a/include/Nazara/Renderer/ShaderValidator.hpp b/include/Nazara/Renderer/ShaderValidator.hpp index 50075aaf0..bfdab9844 100644 --- a/include/Nazara/Renderer/ShaderValidator.hpp +++ b/include/Nazara/Renderer/ShaderValidator.hpp @@ -13,40 +13,47 @@ #include #include -namespace Nz::ShaderAst +namespace Nz { + class ShaderAst; + class NAZARA_RENDERER_API ShaderValidator : public ShaderVisitor { public: - ShaderValidator() = default; + inline ShaderValidator(const ShaderAst& shader); ShaderValidator(const ShaderValidator&) = delete; ShaderValidator(ShaderValidator&&) = delete; ~ShaderValidator() = default; - bool Validate(const StatementPtr& shader, std::string* error = nullptr); + bool Validate(std::string* error = nullptr); private: - const ExpressionPtr& MandatoryExpr(const ExpressionPtr& node); - const NodePtr& MandatoryNode(const NodePtr& node); - void TypeMustMatch(const ExpressionPtr& left, const ExpressionPtr& right); + const ShaderNodes::ExpressionPtr& MandatoryExpr(const ShaderNodes::ExpressionPtr& node); + const ShaderNodes::NodePtr& MandatoryNode(const ShaderNodes::NodePtr& node); + void TypeMustMatch(const ShaderNodes::ExpressionPtr& left, const ShaderNodes::ExpressionPtr& right); + void TypeMustMatch(ShaderNodes::ExpressionType left, ShaderNodes::ExpressionType right); using ShaderVisitor::Visit; - void Visit(const AssignOp& node) override; - void Visit(const BinaryFunc& node) override; - void Visit(const BinaryOp& node) override; - void Visit(const Branch& node) override; - void Visit(const BuiltinVariable& node) override; - void Visit(const Cast& node) override; - void Visit(const Constant& node) override; - void Visit(const DeclareVariable& node) override; - void Visit(const ExpressionStatement& node) override; - void Visit(const NamedVariable& node) override; - void Visit(const Sample2D& node) override; - void Visit(const StatementBlock& node) override; - void Visit(const SwizzleOp& node) override; + void Visit(const ShaderNodes::AssignOp& node) override; + void Visit(const ShaderNodes::BinaryOp& node) override; + void Visit(const ShaderNodes::Branch& node) override; + void Visit(const ShaderNodes::Cast& node) override; + void Visit(const ShaderNodes::Constant& node) override; + void Visit(const ShaderNodes::DeclareVariable& node) override; + void Visit(const ShaderNodes::ExpressionStatement& node) override; + void Visit(const ShaderNodes::Identifier& node) override; + void Visit(const ShaderNodes::IntrinsicCall& node) override; + void Visit(const ShaderNodes::Sample2D& node) override; + void Visit(const ShaderNodes::StatementBlock& node) override; + void Visit(const ShaderNodes::SwizzleOp& node) override; + + struct Context; + + const ShaderAst& m_shader; + Context* m_context; }; - NAZARA_RENDERER_API bool Validate(const StatementPtr& shader, std::string* error = nullptr); + NAZARA_RENDERER_API bool ValidateShader(const ShaderAst& shader, std::string* error = nullptr); } #include diff --git a/include/Nazara/Renderer/ShaderValidator.inl b/include/Nazara/Renderer/ShaderValidator.inl index 2fb43d576..e609a144a 100644 --- a/include/Nazara/Renderer/ShaderValidator.inl +++ b/include/Nazara/Renderer/ShaderValidator.inl @@ -5,8 +5,12 @@ #include #include -namespace Nz::ShaderAst +namespace Nz { + ShaderValidator::ShaderValidator(const ShaderAst& shader) : + m_shader(shader) + { + } } #include diff --git a/include/Nazara/Renderer/ShaderVarVisitor.hpp b/include/Nazara/Renderer/ShaderVarVisitor.hpp new file mode 100644 index 000000000..6df035d74 --- /dev/null +++ b/include/Nazara/Renderer/ShaderVarVisitor.hpp @@ -0,0 +1,34 @@ +// Copyright (C) 2015 Jérôme Leclercq +// This file is part of the "Nazara Engine - Renderer module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_SHADERVARVISITOR_HPP +#define NAZARA_SHADERVARVISITOR_HPP + +#include +#include +#include + +namespace Nz +{ + class NAZARA_RENDERER_API ShaderVarVisitor + { + public: + ShaderVarVisitor() = default; + ShaderVarVisitor(const ShaderVarVisitor&) = delete; + ShaderVarVisitor(ShaderVarVisitor&&) = delete; + virtual ~ShaderVarVisitor(); + + virtual void Visit(const ShaderNodes::BuiltinVariable& var) = 0; + virtual void Visit(const ShaderNodes::InputVariable& var) = 0; + virtual void Visit(const ShaderNodes::LocalVariable& var) = 0; + virtual void Visit(const ShaderNodes::OutputVariable& var) = 0; + virtual void Visit(const ShaderNodes::ParameterVariable& var) = 0; + virtual void Visit(const ShaderNodes::UniformVariable& var) = 0; + void Visit(const ShaderNodes::VariablePtr& node); + }; +} + +#endif diff --git a/include/Nazara/Renderer/ShaderVariables.hpp b/include/Nazara/Renderer/ShaderVariables.hpp new file mode 100644 index 000000000..242f129db --- /dev/null +++ b/include/Nazara/Renderer/ShaderVariables.hpp @@ -0,0 +1,127 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Renderer module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_SHADER_VARIABLES_HPP +#define NAZARA_SHADER_VARIABLES_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + class ShaderVarVisitor; + + namespace ShaderNodes + { + struct Variable; + + using VariablePtr = std::shared_ptr; + + struct NAZARA_RENDERER_API Variable + { + virtual ~Variable(); + + virtual VariableType GetType() const = 0; + virtual void Visit(ShaderVarVisitor& visitor) = 0; + + ExpressionType type; + }; + + struct BuiltinVariable; + + using BuiltinVariablePtr = std::shared_ptr; + + struct NAZARA_RENDERER_API BuiltinVariable : public Variable + { + BuiltinEntry entry; + + VariableType GetType() const override; + void Visit(ShaderVarVisitor& visitor) override; + + static inline std::shared_ptr Build(BuiltinEntry entry, ExpressionType varType); + }; + + struct NamedVariable; + + using NamedVariablePtr = std::shared_ptr; + + struct NAZARA_RENDERER_API NamedVariable : public Variable + { + std::string name; + }; + + struct InputVariable; + + using InputVariablePtr = std::shared_ptr; + + struct NAZARA_RENDERER_API InputVariable : public NamedVariable + { + VariableType GetType() const override; + void Visit(ShaderVarVisitor& visitor) override; + + static inline std::shared_ptr Build(std::string varName, ExpressionType varType); + }; + + struct LocalVariable; + + using LocalVariablePtr = std::shared_ptr; + + struct NAZARA_RENDERER_API LocalVariable : public NamedVariable + { + VariableType GetType() const override; + void Visit(ShaderVarVisitor& visitor) override; + + static inline std::shared_ptr Build(std::string varName, ExpressionType varType); + }; + + struct OutputVariable; + + using OutputVariablePtr = std::shared_ptr; + + struct NAZARA_RENDERER_API OutputVariable : public NamedVariable + { + VariableType GetType() const override; + void Visit(ShaderVarVisitor& visitor) override; + + static inline std::shared_ptr Build(std::string varName, ExpressionType varType); + }; + + struct ParameterVariable; + + using ParameterVariablePtr = std::shared_ptr; + + struct NAZARA_RENDERER_API ParameterVariable : public NamedVariable + { + VariableType GetType() const override; + void Visit(ShaderVarVisitor& visitor) override; + + static inline std::shared_ptr Build(std::string varName, ExpressionType varType); + }; + + struct UniformVariable; + + using UniformVariablePtr = std::shared_ptr; + + struct NAZARA_RENDERER_API UniformVariable : public NamedVariable + { + VariableType GetType() const override; + void Visit(ShaderVarVisitor& visitor) override; + + static inline std::shared_ptr Build(std::string varName, ExpressionType varType); + }; + } +} + +#include + +#endif diff --git a/include/Nazara/Renderer/ShaderVariables.inl b/include/Nazara/Renderer/ShaderVariables.inl new file mode 100644 index 000000000..d20c9d6ea --- /dev/null +++ b/include/Nazara/Renderer/ShaderVariables.inl @@ -0,0 +1,65 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Renderer module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include + +namespace Nz::ShaderNodes +{ + inline std::shared_ptr BuiltinVariable::Build(BuiltinEntry variable, ExpressionType varType) + { + auto node = std::make_shared(); + node->entry = variable; + node->type = varType; + + return node; + } + + inline std::shared_ptr InputVariable::Build(std::string varName, ExpressionType varType) + { + auto node = std::make_shared(); + node->name = std::move(varName); + node->type = varType; + + return node; + } + + inline std::shared_ptr LocalVariable::Build(std::string varName, ExpressionType varType) + { + auto node = std::make_shared(); + node->name = std::move(varName); + node->type = varType; + + return node; + } + + inline std::shared_ptr OutputVariable::Build(std::string varName, ExpressionType varType) + { + auto node = std::make_shared(); + node->name = std::move(varName); + node->type = varType; + + return node; + } + + inline std::shared_ptr ParameterVariable::Build(std::string varName, ExpressionType varType) + { + auto node = std::make_shared(); + node->name = std::move(varName); + node->type = varType; + + return node; + } + + inline std::shared_ptr UniformVariable::Build(std::string varName, ExpressionType varType) + { + auto node = std::make_shared(); + node->name = std::move(varName); + node->type = varType; + + return node; + } +} + +#include diff --git a/include/Nazara/Renderer/ShaderVisitor.hpp b/include/Nazara/Renderer/ShaderVisitor.hpp index 47a5741f4..9db22882c 100644 --- a/include/Nazara/Renderer/ShaderVisitor.hpp +++ b/include/Nazara/Renderer/ShaderVisitor.hpp @@ -8,9 +8,9 @@ #define NAZARA_SHADERVISITOR_HPP #include -#include #include -#include +#include +#include #include namespace Nz @@ -23,27 +23,26 @@ namespace Nz ShaderVisitor(ShaderVisitor&&) = delete; virtual ~ShaderVisitor(); - void EnableCondition(const String& name, bool cond); + void EnableCondition(const std::string& name, bool cond); - bool IsConditionEnabled(const String& name) const; + bool IsConditionEnabled(const std::string& name) const; - virtual void Visit(const ShaderAst::AssignOp& node) = 0; - virtual void Visit(const ShaderAst::BinaryFunc& node) = 0; - virtual void Visit(const ShaderAst::BinaryOp& node) = 0; - virtual void Visit(const ShaderAst::Branch& node) = 0; - virtual void Visit(const ShaderAst::BuiltinVariable& node) = 0; - virtual void Visit(const ShaderAst::Cast& node) = 0; - virtual void Visit(const ShaderAst::Constant& node) = 0; - virtual void Visit(const ShaderAst::DeclareVariable& node) = 0; - virtual void Visit(const ShaderAst::ExpressionStatement& node) = 0; - virtual void Visit(const ShaderAst::NamedVariable& node) = 0; - void Visit(const ShaderAst::NodePtr& node); - virtual void Visit(const ShaderAst::Sample2D& node) = 0; - virtual void Visit(const ShaderAst::StatementBlock& node) = 0; - virtual void Visit(const ShaderAst::SwizzleOp& node) = 0; + virtual void Visit(const ShaderNodes::AssignOp& node) = 0; + virtual void Visit(const ShaderNodes::BinaryOp& node) = 0; + virtual void Visit(const ShaderNodes::Branch& node) = 0; + virtual void Visit(const ShaderNodes::Cast& node) = 0; + virtual void Visit(const ShaderNodes::Constant& node) = 0; + virtual void Visit(const ShaderNodes::DeclareVariable& node) = 0; + virtual void Visit(const ShaderNodes::ExpressionStatement& node) = 0; + virtual void Visit(const ShaderNodes::Identifier& node) = 0; + virtual void Visit(const ShaderNodes::IntrinsicCall& node) = 0; + void Visit(const ShaderNodes::NodePtr& node); + virtual void Visit(const ShaderNodes::Sample2D& node) = 0; + virtual void Visit(const ShaderNodes::StatementBlock& node) = 0; + virtual void Visit(const ShaderNodes::SwizzleOp& node) = 0; private: - std::unordered_set m_conditions; + std::unordered_set m_conditions; }; } diff --git a/include/Nazara/Renderer/ShaderWriter.hpp b/include/Nazara/Renderer/ShaderWriter.hpp index ae00f2fa5..6c2655226 100644 --- a/include/Nazara/Renderer/ShaderWriter.hpp +++ b/include/Nazara/Renderer/ShaderWriter.hpp @@ -8,24 +8,22 @@ #define NAZARA_SHADERWRITER_HPP #include -#include #include -#include +#include namespace Nz { - class NAZARA_RENDERER_API ShaderWriter : public ShaderVisitor + class ShaderAst; + + class NAZARA_RENDERER_API ShaderWriter { public: ShaderWriter() = default; ShaderWriter(const ShaderWriter&) = delete; ShaderWriter(ShaderWriter&&) = delete; - ~ShaderWriter() = default; + virtual ~ShaderWriter(); - virtual Nz::String Generate(const ShaderAst::StatementPtr& node) = 0; - - virtual void RegisterFunction(const String& name, ShaderAst::StatementPtr node, std::initializer_list parameters, ShaderAst::ExpressionType ret) = 0; - virtual void RegisterVariable(ShaderAst::VariableType kind, const String& name, ShaderAst::ExpressionType type) = 0; + virtual std::string Generate(const ShaderAst& shader) = 0; }; } diff --git a/src/Nazara/Renderer/GlslWriter.cpp b/src/Nazara/Renderer/GlslWriter.cpp index b982dab90..8d8e024e7 100644 --- a/src/Nazara/Renderer/GlslWriter.cpp +++ b/src/Nazara/Renderer/GlslWriter.cpp @@ -11,16 +11,15 @@ namespace Nz { GlslWriter::GlslWriter() : - m_currentFunction(nullptr), m_currentState(nullptr), m_glslVersion(110) { } - String GlslWriter::Generate(const ShaderAst::StatementPtr& node) + std::string GlslWriter::Generate(const ShaderAst& shader) { std::string error; - if (!ShaderAst::Validate(node, &error)) + if (!ValidateShader(shader, &error)) throw std::runtime_error("Invalid shader AST: " + error); State state; @@ -30,91 +29,54 @@ namespace Nz m_currentState = nullptr; }); - // Register global variables (uniforms, varying, ..) - node->Register(*this); - // Header Append("#version "); - AppendLine(String::Number(m_glslVersion)); + AppendLine(std::to_string(m_glslVersion)); AppendLine(); - // Global variables (uniforms, input and outputs) - DeclareVariables(state.uniforms, "uniform", "Uniforms"); - DeclareVariables(state.inputs, "in", "Inputs"); - DeclareVariables(state.outputs, "out", "Outputs"); + // Extensions - Function entryPoint; - entryPoint.name = "main"; //< GLSL has only one entry point name possible - entryPoint.node = node; - entryPoint.retType = ShaderAst::ExpressionType::Void; + std::vector requiredExtensions; - AppendFunction(entryPoint); + // GL_ARB_shading_language_420pack (required for layout(binding = X)) + if (m_glslVersion < 420 && HasExplicitBinding(shader)) + requiredExtensions.emplace_back("GL_ARB_shading_language_420pack"); - return state.stream; - } + // GL_ARB_explicit_uniform_location (required for layout(location = X)) + if (m_glslVersion < 430 && HasExplicitLocation(shader)) + requiredExtensions.emplace_back("GL_ARB_explicit_uniform_location"); - void GlslWriter::RegisterFunction(const String& name, ShaderAst::StatementPtr statement, std::initializer_list parameters, ShaderAst::ExpressionType retType) - { - Function func; - func.retType = retType; - func.name = name; - func.node = std::move(statement); - func.parameters.assign(parameters); - - m_functions[name] = std::move(func); - } - - void GlslWriter::RegisterVariable(ShaderAst::VariableType kind, const String& name, ShaderAst::ExpressionType type) - { - NazaraAssert(m_currentState, "This function should only be called while processing an AST"); - NazaraAssert(kind != ShaderAst::VariableType::Builtin, "Builtin variables should not be registered"); - - switch (kind) + if (!requiredExtensions.empty()) { - case ShaderAst::VariableType::Builtin: //< Only there to make compiler happy - case ShaderAst::VariableType::Variable: - break; + for (const std::string& ext : requiredExtensions) + AppendLine("#extension " + ext + " : require"); - case ShaderAst::VariableType::Input: - m_currentState->inputs.emplace(type, name); - break; - - case ShaderAst::VariableType::Output: - m_currentState->outputs.emplace(type, name); - break; - - case ShaderAst::VariableType::Parameter: - { - if (m_currentFunction) - { - bool found = false; - for (const auto& varPtr : m_currentFunction->parameters) - { - if (varPtr->name == name) - { - found = true; - if (varPtr->type != type) - { - //TODO: AstParseError - throw std::runtime_error("Function uses parameter \"" + name.ToStdString() + "\" with a different type than specified in the function arguments"); - } - - break; - } - } - - if (!found) - //TODO: AstParseError - throw std::runtime_error("Function has no parameter \"" + name.ToStdString() + "\""); - } - - break; - } - - case ShaderAst::VariableType::Uniform: - m_currentState->uniforms.emplace(type, name); - break; + AppendLine(); } + + // Global variables (uniforms, input and outputs) + DeclareVariables(shader.GetUniforms(), "uniform", "Uniforms"); + DeclareVariables(shader.GetInputs(), "in", "Inputs"); + DeclareVariables(shader.GetOutputs(), "out", "Outputs"); + + std::size_t functionCount = shader.GetFunctionCount(); + if (functionCount > 1) + { + AppendCommentSection("Prototypes"); + for (const auto& func : shader.GetFunctions()) + { + if (func.name != "main") + { + AppendFunctionPrototype(func); + AppendLine(";"); + } + } + } + + for (const auto& func : shader.GetFunctions()) + AppendFunction(func); + + return state.stream.str(); } void GlslWriter::SetGlslVersion(unsigned int version) @@ -122,22 +84,127 @@ namespace Nz m_glslVersion = version; } - void GlslWriter::Visit(const ShaderAst::Sample2D& node) + void GlslWriter::Append(ShaderNodes::BuiltinEntry builtin) { - Append("texture("); - Visit(node.sampler); - Append(", "); - Visit(node.coordinates); - Append(")"); + switch (builtin) + { + case ShaderNodes::BuiltinEntry::VertexPosition: + Append("gl_Position"); + break; + } } - void GlslWriter::Visit(const ShaderAst::AssignOp& node) + void GlslWriter::Append(ShaderNodes::ExpressionType type) + { + switch (type) + { + case ShaderNodes::ExpressionType::Boolean: + Append("bool"); + break; + case ShaderNodes::ExpressionType::Float1: + Append("float"); + break; + case ShaderNodes::ExpressionType::Float2: + Append("vec2"); + break; + case ShaderNodes::ExpressionType::Float3: + Append("vec3"); + break; + case ShaderNodes::ExpressionType::Float4: + Append("vec4"); + break; + case ShaderNodes::ExpressionType::Mat4x4: + Append("mat4"); + break; + case ShaderNodes::ExpressionType::Sampler2D: + Append("sampler2D"); + break; + case ShaderNodes::ExpressionType::Void: + Append("void"); + break; + } + } + + void GlslWriter::AppendCommentSection(const std::string& section) + { + NazaraAssert(m_currentState, "This function should only be called while processing an AST"); + + String stars((section.size() < 33) ? (36 - section.size()) / 2 : 3, '*'); + m_currentState->stream << "/*" << stars << ' ' << section << ' ' << stars << "*/"; + AppendLine(); + } + + void GlslWriter::AppendFunction(const ShaderAst::Function& func) + { + NazaraAssert(!m_context.currentFunction, "A function is already being processed"); + NazaraAssert(m_currentState, "This function should only be called while processing an AST"); + + AppendFunctionPrototype(func); + + m_context.currentFunction = &func; + CallOnExit onExit([this] () + { + m_context.currentFunction = nullptr; + }); + + EnterScope(); + { + Visit(func.statement); + } + LeaveScope(); + } + + void GlslWriter::AppendFunctionPrototype(const ShaderAst::Function& func) + { + Append(func.returnType); + + Append(" "); + Append(func.name); + + Append("("); + for (std::size_t i = 0; i < func.parameters.size(); ++i) + { + if (i != 0) + Append(", "); + + Append(func.parameters[i].type); + Append(" "); + Append(func.parameters[i].name); + } + Append(")\n"); + } + + void GlslWriter::AppendLine(const std::string& txt) + { + NazaraAssert(m_currentState, "This function should only be called while processing an AST"); + + m_currentState->stream << txt << '\n' << std::string(m_currentState->indentLevel, '\t'); + } + + void GlslWriter::EnterScope() + { + NazaraAssert(m_currentState, "This function should only be called while processing an AST"); + + m_currentState->indentLevel++; + AppendLine("{"); + } + + void GlslWriter::LeaveScope() + { + NazaraAssert(m_currentState, "This function should only be called while processing an AST"); + + m_currentState->indentLevel--; + AppendLine(); + AppendLine("}"); + } + + void GlslWriter::Visit(const ShaderNodes::AssignOp& node) { Visit(node.left); switch (node.op) { - case ShaderAst::AssignType::Simple: + case ShaderNodes::AssignType::Simple: Append(" = "); break; } @@ -145,7 +212,7 @@ namespace Nz Visit(node.right); } - void GlslWriter::Visit(const ShaderAst::Branch& node) + void GlslWriter::Visit(const ShaderNodes::Branch& node) { bool first = true; for (const auto& statement : node.condStatements) @@ -174,45 +241,25 @@ namespace Nz } } - void GlslWriter::Visit(const ShaderAst::BinaryFunc& node) - { - switch (node.intrinsic) - { - case ShaderAst::BinaryIntrinsic::CrossProduct: - Append("cross"); - break; - - case ShaderAst::BinaryIntrinsic::DotProduct: - Append("dot"); - break; - } - - Append("("); - Visit(node.left); - Append(", "); - Visit(node.right); - Append(")"); - } - - void GlslWriter::Visit(const ShaderAst::BinaryOp& node) + void GlslWriter::Visit(const ShaderNodes::BinaryOp& node) { Visit(node.left); switch (node.op) { - case ShaderAst::BinaryType::Add: + case ShaderNodes::BinaryType::Add: Append(" + "); break; - case ShaderAst::BinaryType::Substract: + case ShaderNodes::BinaryType::Substract: Append(" - "); break; - case ShaderAst::BinaryType::Multiply: + case ShaderNodes::BinaryType::Multiply: Append(" * "); break; - case ShaderAst::BinaryType::Divide: + case ShaderNodes::BinaryType::Divide: Append(" / "); break; - case ShaderAst::BinaryType::Equality: + case ShaderNodes::BinaryType::Equality: Append(" == "); break; } @@ -220,18 +267,18 @@ namespace Nz Visit(node.right); } - void GlslWriter::Visit(const ShaderAst::BuiltinVariable& node) + void GlslWriter::Visit(const ShaderNodes::BuiltinVariable& var) { - Append(node.var); + Append(var.type); } - void GlslWriter::Visit(const ShaderAst::Cast& node) + void GlslWriter::Visit(const ShaderNodes::Cast& node) { Append(node.exprType); Append("("); unsigned int i = 0; - unsigned int requiredComponents = ShaderAst::Node::GetComponentCount(node.exprType); + unsigned int requiredComponents = ShaderNodes::Node::GetComponentCount(node.exprType); while (requiredComponents > 0) { if (i != 0) @@ -241,34 +288,34 @@ namespace Nz NazaraAssert(exprPtr, "Invalid expression"); Visit(exprPtr); - requiredComponents -= ShaderAst::Node::GetComponentCount(exprPtr->GetExpressionType()); + requiredComponents -= ShaderNodes::Node::GetComponentCount(exprPtr->GetExpressionType()); } Append(")"); } - void GlslWriter::Visit(const ShaderAst::Constant& node) + void GlslWriter::Visit(const ShaderNodes::Constant& node) { switch (node.exprType) { - case ShaderAst::ExpressionType::Boolean: + case ShaderNodes::ExpressionType::Boolean: Append((node.values.bool1) ? "true" : "false"); break; - case ShaderAst::ExpressionType::Float1: - Append(String::Number(node.values.vec1)); + case ShaderNodes::ExpressionType::Float1: + Append(std::to_string(node.values.vec1)); break; - case ShaderAst::ExpressionType::Float2: - Append("vec2(" + String::Number(node.values.vec2.x) + ", " + String::Number(node.values.vec2.y) + ")"); + case ShaderNodes::ExpressionType::Float2: + Append("vec2(" + std::to_string(node.values.vec2.x) + ", " + std::to_string(node.values.vec2.y) + ")"); break; - case ShaderAst::ExpressionType::Float3: - Append("vec3(" + String::Number(node.values.vec3.x) + ", " + String::Number(node.values.vec3.y) + ", " + String::Number(node.values.vec3.z) + ")"); + case ShaderNodes::ExpressionType::Float3: + Append("vec3(" + std::to_string(node.values.vec3.x) + ", " + std::to_string(node.values.vec3.y) + ", " + std::to_string(node.values.vec3.z) + ")"); break; - case ShaderAst::ExpressionType::Float4: - Append("vec4(" + String::Number(node.values.vec4.x) + ", " + String::Number(node.values.vec4.y) + ", " + String::Number(node.values.vec4.z) + ", " + String::Number(node.values.vec4.w) + ")"); + case ShaderNodes::ExpressionType::Float4: + Append("vec4(" + std::to_string(node.values.vec4.x) + ", " + std::to_string(node.values.vec4.y) + ", " + std::to_string(node.values.vec4.z) + ", " + std::to_string(node.values.vec4.w) + ")"); break; default: @@ -276,9 +323,9 @@ namespace Nz } } - void GlslWriter::Visit(const ShaderAst::DeclareVariable& node) + void GlslWriter::Visit(const ShaderNodes::DeclareVariable& node) { - Append(node.variable->GetExpressionType()); + Append(node.variable->type); Append(" "); Append(node.variable->name); if (node.expression) @@ -292,21 +339,76 @@ namespace Nz AppendLine(";"); } - void GlslWriter::Visit(const ShaderAst::ExpressionStatement& node) + void GlslWriter::Visit(const ShaderNodes::ExpressionStatement& node) { Visit(node.expression); Append(";"); } - void GlslWriter::Visit(const ShaderAst::NamedVariable& node) + void GlslWriter::Visit(const ShaderNodes::Identifier& node) { - Append(node.name); + Visit(node.var); } - void GlslWriter::Visit(const ShaderAst::StatementBlock& node) + void GlslWriter::Visit(const ShaderNodes::InputVariable& var) + { + Append(var.name); + } + + void GlslWriter::Visit(const ShaderNodes::IntrinsicCall& node) + { + switch (node.intrinsic) + { + case ShaderNodes::IntrinsicType::CrossProduct: + Append("cross"); + break; + + case ShaderNodes::IntrinsicType::DotProduct: + Append("dot"); + break; + } + + m_currentState->stream << '('; + for (std::size_t i = 0; i < node.parameters.size(); ++i) + { + if (i != 0) + m_currentState->stream << ", "; + + Visit(node.parameters[i]); + m_currentState->stream << ' '; + Visit(node.parameters[i]); + } + m_currentState->stream << ")\n"; + } + + void GlslWriter::Visit(const ShaderNodes::LocalVariable& var) + { + Append(var.name); + } + + void GlslWriter::Visit(const ShaderNodes::ParameterVariable& var) + { + Append(var.name); + } + + void GlslWriter::Visit(const ShaderNodes::OutputVariable& var) + { + Append(var.name); + } + + void GlslWriter::Visit(const ShaderNodes::Sample2D& node) + { + Append("texture("); + Visit(node.sampler); + Append(", "); + Visit(node.coordinates); + Append(")"); + } + + void GlslWriter::Visit(const ShaderNodes::StatementBlock& node) { bool first = true; - for (const ShaderAst::StatementPtr& statement : node.statements) + for (const ShaderNodes::StatementPtr& statement : node.statements) { if (!first) AppendLine(); @@ -317,7 +419,7 @@ namespace Nz } } - void GlslWriter::Visit(const ShaderAst::SwizzleOp& node) + void GlslWriter::Visit(const ShaderNodes::SwizzleOp& node) { Visit(node.expression); Append("."); @@ -326,166 +428,55 @@ namespace Nz { switch (node.components[i]) { - case ShaderAst::SwizzleComponent::First: + case ShaderNodes::SwizzleComponent::First: Append("x"); break; - case ShaderAst::SwizzleComponent::Second: + case ShaderNodes::SwizzleComponent::Second: Append("y"); break; - case ShaderAst::SwizzleComponent::Third: + case ShaderNodes::SwizzleComponent::Third: Append("z"); break; - case ShaderAst::SwizzleComponent::Fourth: + case ShaderNodes::SwizzleComponent::Fourth: Append("w"); break; } } } - void GlslWriter::Append(ShaderAst::BuiltinEntry builtin) + void GlslWriter::Visit(const ShaderNodes::UniformVariable& var) { - switch (builtin) + Append(var.name); + } + + bool GlslWriter::HasExplicitBinding(const ShaderAst& shader) + { + for (const auto& uniform : shader.GetUniforms()) { - case ShaderAst::BuiltinEntry::VertexPosition: - Append("gl_Position"); - break; + if (uniform.bindingIndex.has_value()) + return true; } + + return false; } - void GlslWriter::Append(ShaderAst::ExpressionType type) + bool GlslWriter::HasExplicitLocation(const ShaderAst& shader) { - switch (type) + for (const auto& input : shader.GetInputs()) { - case ShaderAst::ExpressionType::Boolean: - Append("bool"); - break; - case ShaderAst::ExpressionType::Float1: - Append("float"); - break; - case ShaderAst::ExpressionType::Float2: - Append("vec2"); - break; - case ShaderAst::ExpressionType::Float3: - Append("vec3"); - break; - case ShaderAst::ExpressionType::Float4: - Append("vec4"); - break; - case ShaderAst::ExpressionType::Mat4x4: - Append("mat4"); - break; - case ShaderAst::ExpressionType::Sampler2D: - Append("sampler2D"); - break; - case ShaderAst::ExpressionType::Void: - Append("void"); - break; + if (input.locationIndex.has_value()) + return true; } - } - void GlslWriter::Append(const String& txt) - { - NazaraAssert(m_currentState, "This function should only be called while processing an AST"); - - m_currentState->stream << txt; - } - - void GlslWriter::AppendCommentSection(const String& section) - { - NazaraAssert(m_currentState, "This function should only be called while processing an AST"); - - String stars((section.GetSize() < 33) ? (36 - section.GetSize()) / 2 : 3, '*'); - m_currentState->stream << "/*" << stars << ' ' << section << ' ' << stars << "*/"; - AppendLine(); - } - - void GlslWriter::AppendFunction(Function& func) - { - NazaraAssert(!m_currentFunction, "A function is already being processed"); - NazaraAssert(m_currentState, "This function should only be called while processing an AST"); - - m_currentFunction = &func; - CallOnExit onExit([this] () + for (const auto& output : shader.GetOutputs()) { - m_currentFunction = nullptr; - }); - - func.node->Register(*this); - - Append(func.retType); - - m_currentState->stream << ' '; - Append(func.name); - - m_currentState->stream << '('; - for (std::size_t i = 0; i < func.parameters.size(); ++i) - { - if (i != 0) - m_currentState->stream << ", "; - - Append(func.parameters[i]->type); - m_currentState->stream << ' '; - Append(func.parameters[i]->name); + if (output.locationIndex.has_value()) + return true; } - m_currentState->stream << ")\n"; - EnterScope(); - { - Visit(func.node); - } - LeaveScope(); + return false; } - - void GlslWriter::AppendLine(const String& txt) - { - NazaraAssert(m_currentState, "This function should only be called while processing an AST"); - - m_currentState->stream << txt << '\n' << String(m_currentState->indentLevel, '\t'); - } - - void GlslWriter::DeclareVariables(const VariableContainer& variables, const String& keyword, const String& section) - { - if (!variables.empty()) - { - if (!section.IsEmpty()) - AppendCommentSection(section); - - for (const auto& pair : variables) - { - if (!keyword.IsEmpty()) - { - Append(keyword); - Append(" "); - } - - Append(pair.first); - Append(" "); - Append(pair.second); - AppendLine(";"); - } - - AppendLine(); - } - } - - void GlslWriter::EnterScope() - { - NazaraAssert(m_currentState, "This function should only be called while processing an AST"); - - m_currentState->indentLevel++; - AppendLine("{"); - } - - void GlslWriter::LeaveScope() - { - NazaraAssert(m_currentState, "This function should only be called while processing an AST"); - - m_currentState->indentLevel--; - AppendLine(); - AppendLine("}"); - } - } diff --git a/src/Nazara/Renderer/ShaderAst.cpp b/src/Nazara/Renderer/ShaderAst.cpp index b6623cc48..a52cca657 100644 --- a/src/Nazara/Renderer/ShaderAst.cpp +++ b/src/Nazara/Renderer/ShaderAst.cpp @@ -3,275 +3,40 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include -#include -#include -#include #include -namespace Nz::ShaderAst +namespace Nz { - Node::~Node() = default; - - ExpressionCategory Expression::GetExpressionCategory() const + void ShaderAst::AddFunction(std::string name, ShaderNodes::StatementPtr statement, std::vector parameters, ShaderNodes::ExpressionType returnType) { - return ExpressionCategory::RValue; + auto& functionEntry = m_functions.emplace_back(); + functionEntry.name = std::move(name); + functionEntry.parameters = std::move(parameters); + functionEntry.returnType = returnType; + functionEntry.statement = std::move(statement); } - void ExpressionStatement::Register(ShaderWriter& visitor) + void ShaderAst::AddInput(std::string name, ShaderNodes::ExpressionType type, std::optional locationIndex) { - expression->Register(visitor); + auto& inputEntry = m_inputs.emplace_back(); + inputEntry.name = std::move(name); + inputEntry.locationIndex = std::move(locationIndex); + inputEntry.type = type; } - void ExpressionStatement::Visit(ShaderVisitor& visitor) + void ShaderAst::AddOutput(std::string name, ShaderNodes::ExpressionType type, std::optional locationIndex) { - visitor.Visit(*this); + auto& outputEntry = m_outputs.emplace_back(); + outputEntry.name = std::move(name); + outputEntry.locationIndex = std::move(locationIndex); + outputEntry.type = type; } - - void ConditionalStatement::Register(ShaderWriter& visitor) + void ShaderAst::AddUniform(std::string name, ShaderNodes::ExpressionType type, std::optional bindingIndex) { - if (visitor.IsConditionEnabled(conditionName)) - statement->Register(visitor); - } - - void ConditionalStatement::Visit(ShaderVisitor& visitor) - { - if (visitor.IsConditionEnabled(conditionName)) - statement->Visit(visitor); - } - - - void StatementBlock::Register(ShaderWriter& visitor) - { - for (auto& statementPtr : statements) - statementPtr->Register(visitor); - } - - void StatementBlock::Visit(ShaderVisitor& visitor) - { - visitor.Visit(*this); - } - - ExpressionCategory Variable::GetExpressionCategory() const - { - return ExpressionCategory::LValue; - } - - ExpressionType Variable::GetExpressionType() const - { - return type; - } - - - void BuiltinVariable::Register(ShaderWriter& /*visitor*/) - { - } - - void BuiltinVariable::Visit(ShaderVisitor& visitor) - { - visitor.Visit(*this); - } - - - void NamedVariable::Register(ShaderWriter& visitor) - { - visitor.RegisterVariable(kind, name, type); - } - - void NamedVariable::Visit(ShaderVisitor& visitor) - { - visitor.Visit(*this); - } - - - void DeclareVariable::Register(ShaderWriter& visitor) - { - variable->Register(visitor); - - if (expression) - expression->Register(visitor); - } - - void DeclareVariable::Visit(ShaderVisitor& visitor) - { - visitor.Visit(*this); - } - - - ExpressionType AssignOp::GetExpressionType() const - { - return left->GetExpressionType(); - } - - void AssignOp::Register(ShaderWriter& visitor) - { - left->Register(visitor); - right->Register(visitor); - } - - void AssignOp::Visit(ShaderVisitor& visitor) - { - visitor.Visit(*this); - } - - - ExpressionType BinaryOp::GetExpressionType() const - { - ShaderAst::ExpressionType exprType = ShaderAst::ExpressionType::Void; - - switch (op) - { - case ShaderAst::BinaryType::Add: - case ShaderAst::BinaryType::Substract: - exprType = left->GetExpressionType(); - break; - - case ShaderAst::BinaryType::Divide: - case ShaderAst::BinaryType::Multiply: - //FIXME - exprType = static_cast(std::max(UnderlyingCast(left->GetExpressionType()), UnderlyingCast(right->GetExpressionType()))); - break; - - case ShaderAst::BinaryType::Equality: - exprType = ExpressionType::Boolean; - break; - } - - NazaraAssert(exprType != ShaderAst::ExpressionType::Void, "Unhandled builtin"); - - return exprType; - } - - void BinaryOp::Register(ShaderWriter& visitor) - { - left->Register(visitor); - right->Register(visitor); - } - - void BinaryOp::Visit(ShaderVisitor& visitor) - { - visitor.Visit(*this); - } - - - void Branch::Register(ShaderWriter& visitor) - { - for (ConditionalStatement& statement : condStatements) - { - statement.condition->Register(visitor); - statement.statement->Register(visitor); - } - - if (elseStatement) - elseStatement->Register(visitor); - } - - void Branch::Visit(ShaderVisitor& visitor) - { - visitor.Visit(*this); - } - - - ExpressionType Constant::GetExpressionType() const - { - return exprType; - } - - void Constant::Register(ShaderWriter&) - { - } - - void Constant::Visit(ShaderVisitor& visitor) - { - visitor.Visit(*this); - } - - ExpressionType Cast::GetExpressionType() const - { - return exprType; - } - - void Cast::Register(ShaderWriter& visitor) - { - auto it = expressions.begin(); - (*it)->Register(visitor); - - for (; it != expressions.end(); ++it) - { - if (!*it) - break; - - (*it)->Register(visitor); - } - } - - void Cast::Visit(ShaderVisitor& visitor) - { - visitor.Visit(*this); - } - - - ExpressionCategory SwizzleOp::GetExpressionCategory() const - { - return ExpressionCategory::LValue; - } - - ExpressionType SwizzleOp::GetExpressionType() const - { - return static_cast(UnderlyingCast(GetComponentType(expression->GetExpressionType())) + componentCount - 1); - } - - void SwizzleOp::Register(ShaderWriter& visitor) - { - expression->Register(visitor); - } - - void SwizzleOp::Visit(ShaderVisitor& visitor) - { - visitor.Visit(*this); - } - - - ExpressionType Sample2D::GetExpressionType() const - { - return ExpressionType::Float4; - } - - void Sample2D::Register(ShaderWriter& visitor) - { - sampler->Register(visitor); - coordinates->Register(visitor); - } - - void Sample2D::Visit(ShaderVisitor& visitor) - { - visitor.Visit(*this); - } - - - ExpressionType BinaryFunc::GetExpressionType() const - { - switch (intrinsic) - { - case BinaryIntrinsic::CrossProduct: - return left->GetExpressionType(); - - case BinaryIntrinsic::DotProduct: - return ExpressionType::Float1; - } - - NazaraAssert(false, "Unhandled builtin"); - return ExpressionType::Void; - } - - void BinaryFunc::Register(ShaderWriter& visitor) - { - left->Register(visitor); - right->Register(visitor); - } - - void BinaryFunc::Visit(ShaderVisitor& visitor) - { - visitor.Visit(*this); + auto& uniformEntry = m_uniforms.emplace_back(); + uniformEntry.bindingIndex = std::move(bindingIndex); + uniformEntry.name = std::move(name); + uniformEntry.type = type; } } diff --git a/src/Nazara/Renderer/ShaderNodes.cpp b/src/Nazara/Renderer/ShaderNodes.cpp new file mode 100644 index 000000000..eb4f59160 --- /dev/null +++ b/src/Nazara/Renderer/ShaderNodes.cpp @@ -0,0 +1,179 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Renderer module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include +#include + +namespace Nz::ShaderNodes +{ + Node::~Node() = default; + + ExpressionCategory Expression::GetExpressionCategory() const + { + return ExpressionCategory::RValue; + } + + void ExpressionStatement::Visit(ShaderVisitor& visitor) + { + visitor.Visit(*this); + } + + + void ConditionalStatement::Visit(ShaderVisitor& visitor) + { + if (visitor.IsConditionEnabled(conditionName)) + statement->Visit(visitor); + } + + + void StatementBlock::Visit(ShaderVisitor& visitor) + { + visitor.Visit(*this); + } + + + void DeclareVariable::Visit(ShaderVisitor& visitor) + { + visitor.Visit(*this); + } + + + ExpressionCategory Identifier::GetExpressionCategory() const + { + return ExpressionCategory::LValue; + } + + ExpressionType Identifier::GetExpressionType() const + { + assert(var); + return var->type; + } + + void Identifier::Visit(ShaderVisitor& visitor) + { + visitor.Visit(*this); + } + + + ExpressionType AssignOp::GetExpressionType() const + { + return left->GetExpressionType(); + } + + void AssignOp::Visit(ShaderVisitor& visitor) + { + visitor.Visit(*this); + } + + + ExpressionType BinaryOp::GetExpressionType() const + { + ShaderNodes::ExpressionType exprType = ShaderNodes::ExpressionType::Void; + + switch (op) + { + case ShaderNodes::BinaryType::Add: + case ShaderNodes::BinaryType::Substract: + exprType = left->GetExpressionType(); + break; + + case ShaderNodes::BinaryType::Divide: + case ShaderNodes::BinaryType::Multiply: + //FIXME + exprType = static_cast(std::max(UnderlyingCast(left->GetExpressionType()), UnderlyingCast(right->GetExpressionType()))); + break; + + case ShaderNodes::BinaryType::Equality: + exprType = ExpressionType::Boolean; + break; + } + + NazaraAssert(exprType != ShaderNodes::ExpressionType::Void, "Unhandled builtin"); + + return exprType; + } + + void BinaryOp::Visit(ShaderVisitor& visitor) + { + visitor.Visit(*this); + } + + + void Branch::Visit(ShaderVisitor& visitor) + { + visitor.Visit(*this); + } + + + ExpressionType Constant::GetExpressionType() const + { + return exprType; + } + + void Constant::Visit(ShaderVisitor& visitor) + { + visitor.Visit(*this); + } + + ExpressionType Cast::GetExpressionType() const + { + return exprType; + } + + void Cast::Visit(ShaderVisitor& visitor) + { + visitor.Visit(*this); + } + + + ExpressionCategory SwizzleOp::GetExpressionCategory() const + { + return ExpressionCategory::LValue; + } + + ExpressionType SwizzleOp::GetExpressionType() const + { + return static_cast(UnderlyingCast(GetComponentType(expression->GetExpressionType())) + componentCount - 1); + } + + void SwizzleOp::Visit(ShaderVisitor& visitor) + { + visitor.Visit(*this); + } + + + ExpressionType Sample2D::GetExpressionType() const + { + return ExpressionType::Float4; + } + + void Sample2D::Visit(ShaderVisitor& visitor) + { + visitor.Visit(*this); + } + + + ExpressionType IntrinsicCall::GetExpressionType() const + { + switch (intrinsic) + { + case IntrinsicType::CrossProduct: + return parameters.front()->GetExpressionType(); + + case IntrinsicType::DotProduct: + return ExpressionType::Float1; + } + + NazaraAssert(false, "Unhandled builtin"); + return ExpressionType::Void; + } + + void IntrinsicCall::Visit(ShaderVisitor& visitor) + { + visitor.Visit(*this); + } +} diff --git a/src/Nazara/Renderer/ShaderSerializer.cpp b/src/Nazara/Renderer/ShaderSerializer.cpp index 6e6e3e8ff..909422f52 100644 --- a/src/Nazara/Renderer/ShaderSerializer.cpp +++ b/src/Nazara/Renderer/ShaderSerializer.cpp @@ -3,13 +3,15 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include +#include +#include #include -namespace Nz::ShaderAst +namespace Nz::ShaderNodes { namespace { - class ShaderSerializerVisitor : public ShaderVisitor + class ShaderSerializerVisitor : public ShaderVisitor, public ShaderVarVisitor { public: ShaderSerializerVisitor(ShaderSerializerBase& serializer) : @@ -22,11 +24,6 @@ namespace Nz::ShaderAst Serialize(node); } - void Visit(const BinaryFunc& node) override - { - Serialize(node); - } - void Visit(const BinaryOp& node) override { Serialize(node); @@ -37,11 +34,6 @@ namespace Nz::ShaderAst Serialize(node); } - void Visit(const BuiltinVariable& node) override - { - Serialize(node); - } - void Visit(const Cast& node) override { Serialize(node); @@ -62,7 +54,12 @@ namespace Nz::ShaderAst Serialize(node); } - void Visit(const NamedVariable& node) override + void Visit(const Identifier& node) override + { + Serialize(node); + } + + void Visit(const IntrinsicCall& node) override { Serialize(node); } @@ -82,6 +79,37 @@ namespace Nz::ShaderAst Serialize(node); } + + void Visit(const ShaderNodes::BuiltinVariable& var) override + { + Serialize(var); + } + + void Visit(const ShaderNodes::InputVariable& var) override + { + Serialize(var); + } + + void Visit(const ShaderNodes::LocalVariable& var) override + { + Serialize(var); + } + + void Visit(const ShaderNodes::OutputVariable& var) override + { + Serialize(var); + } + + void Visit(const ShaderNodes::ParameterVariable& var) override + { + Serialize(var); + } + + void Visit(const ShaderNodes::UniformVariable& var) override + { + Serialize(var); + } + private: template void Serialize(const T& node) @@ -101,13 +129,6 @@ namespace Nz::ShaderAst Node(node.right); } - void ShaderSerializerBase::Serialize(BinaryFunc& node) - { - Enum(node.intrinsic); - Node(node.left); - Node(node.right); - } - void ShaderSerializerBase::Serialize(BinaryOp& node) { Enum(node.op); @@ -129,7 +150,7 @@ namespace Nz::ShaderAst void ShaderSerializerBase::Serialize(BuiltinVariable& node) { - Enum(node.var); + Enum(node.type); Enum(node.type); } @@ -170,7 +191,7 @@ namespace Nz::ShaderAst void ShaderSerializerBase::Serialize(DeclareVariable& node) { - Node(node.variable); + Variable(node.variable); Node(node.expression); } @@ -179,10 +200,22 @@ namespace Nz::ShaderAst Node(node.expression); } + void ShaderSerializerBase::Serialize(Identifier& node) + { + Variable(node.var); + } + + void ShaderSerializerBase::Serialize(IntrinsicCall& node) + { + Enum(node.intrinsic); + Container(node.parameters); + for (auto& param : node.parameters) + Node(param); + } + void ShaderSerializerBase::Serialize(NamedVariable& node) { Value(node.name); - Enum(node.kind); Enum(node.type); } @@ -272,6 +305,18 @@ namespace Nz::ShaderAst m_stream << val; } + void ShaderSerializer::Variable(VariablePtr& var) + { + VariableType nodeType = (var) ? var->GetType() : VariableType::None; + m_stream << static_cast(nodeType); + + if (var) + { + ShaderSerializerVisitor visitor(*this); + var->Visit(visitor); + } + } + ByteArray Serialize(const StatementPtr& shader) { ByteArray byteArray; @@ -309,27 +354,26 @@ namespace Nz::ShaderAst NodeType nodeType = static_cast(nodeTypeInt); -#define HandleNodeType(Type) case NodeType:: Type : node = std::make_shared(); break +#define HandleType(Type) case NodeType:: Type : node = std::make_shared(); break switch (nodeType) { case NodeType::None: break; - HandleNodeType(AssignOp); - HandleNodeType(BinaryFunc); - HandleNodeType(BinaryOp); - HandleNodeType(Branch); - HandleNodeType(BuiltinVariable); - HandleNodeType(Cast); - HandleNodeType(Constant); - HandleNodeType(ConditionalStatement); - HandleNodeType(DeclareVariable); - HandleNodeType(ExpressionStatement); - HandleNodeType(NamedVariable); - HandleNodeType(Sample2D); - HandleNodeType(SwizzleOp); - HandleNodeType(StatementBlock); + HandleType(AssignOp); + HandleType(BinaryOp); + HandleType(Branch); + HandleType(Cast); + HandleType(Constant); + HandleType(ConditionalStatement); + HandleType(DeclareVariable); + HandleType(ExpressionStatement); + HandleType(Identifier); + HandleType(IntrinsicCall); + HandleType(Sample2D); + HandleType(SwizzleOp); + HandleType(StatementBlock); } -#undef HandleNodeType +#undef HandleType if (node) { @@ -372,5 +416,32 @@ namespace Nz::ShaderAst { m_stream >> val; } + + void ShaderUnserializer::Variable(VariablePtr& var) + { + Int32 nodeTypeInt; + m_stream >> nodeTypeInt; + + VariableType nodeType = static_cast(nodeTypeInt); + +#define HandleType(Type) case VariableType:: Type : var = std::make_shared(); break + switch (nodeType) + { + case VariableType::None: break; + + HandleType(BuiltinVariable); + HandleType(InputVariable); + HandleType(LocalVariable); + HandleType(OutputVariable); + HandleType(UniformVariable); + } +#undef HandleType + + if (var) + { + ShaderSerializerVisitor visitor(*this); + var->Visit(visitor); + } + } } diff --git a/src/Nazara/Renderer/ShaderValidator.cpp b/src/Nazara/Renderer/ShaderValidator.cpp index c7a25989f..aab559a61 100644 --- a/src/Nazara/Renderer/ShaderValidator.cpp +++ b/src/Nazara/Renderer/ShaderValidator.cpp @@ -3,20 +3,49 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include +#include +#include +#include +#include #include -namespace Nz::ShaderAst +namespace Nz { struct AstError { std::string errMsg; }; - bool ShaderValidator::Validate(const StatementPtr& shader, std::string* error) + struct ShaderValidator::Context + { + struct Local + { + std::string name; + ShaderNodes::ExpressionType type; + }; + + const ShaderAst::Function* currentFunction; + std::vector declaredLocals; + std::vector blockLocalIndex; + }; + + bool ShaderValidator::Validate(std::string* error) { try { - shader->Visit(*this); + for (std::size_t i = 0; i < m_shader.GetFunctionCount(); ++i) + { + const auto& func = m_shader.GetFunction(i); + + Context currentContext; + currentContext.currentFunction = &func; + + m_context = ¤tContext; + CallOnExit resetContext([&] { m_context = nullptr; }); + + func.statement->Visit(*this); + } + return true; } catch (const AstError& e) @@ -28,14 +57,14 @@ namespace Nz::ShaderAst } } - const ExpressionPtr& ShaderValidator::MandatoryExpr(const ExpressionPtr& node) + const ShaderNodes::ExpressionPtr& ShaderValidator::MandatoryExpr(const ShaderNodes::ExpressionPtr& node) { MandatoryNode(node); return node; } - const NodePtr& ShaderValidator::MandatoryNode(const NodePtr& node) + const ShaderNodes::NodePtr& ShaderValidator::MandatoryNode(const ShaderNodes::NodePtr& node) { if (!node) throw AstError{ "Invalid node" }; @@ -43,90 +72,76 @@ namespace Nz::ShaderAst return node; } - void ShaderValidator::TypeMustMatch(const ExpressionPtr& left, const ExpressionPtr& right) + void ShaderValidator::TypeMustMatch(const ShaderNodes::ExpressionPtr& left, const ShaderNodes::ExpressionPtr& right) { - if (left->GetExpressionType() != right->GetExpressionType()) + return TypeMustMatch(left->GetExpressionType(), right->GetExpressionType()); + } + + void ShaderValidator::TypeMustMatch(ShaderNodes::ExpressionType left, ShaderNodes::ExpressionType right) + { + if (left != right) throw AstError{ "Left expression type must match right expression type" }; } - void ShaderValidator::Visit(const AssignOp& node) + void ShaderValidator::Visit(const ShaderNodes::AssignOp& node) { MandatoryNode(node.left); MandatoryNode(node.right); TypeMustMatch(node.left, node.right); - Visit(node.left); - Visit(node.right); - } - - void ShaderValidator::Visit(const BinaryFunc& node) - { - MandatoryNode(node.left); - MandatoryNode(node.right); - TypeMustMatch(node.left, node.right); - - switch (node.intrinsic) - { - case BinaryIntrinsic::CrossProduct: - { - if (node.left->GetExpressionType() != ExpressionType::Float3) - throw AstError{ "CrossProduct only works with Float3 expressions" }; - } - - case BinaryIntrinsic::DotProduct: - break; - } + if (node.left->GetExpressionCategory() != ShaderNodes::ExpressionCategory::LValue) + throw AstError { "Assignation is only possible with a l-value" }; Visit(node.left); Visit(node.right); } - void ShaderValidator::Visit(const BinaryOp& node) + void ShaderValidator::Visit(const ShaderNodes::BinaryOp& node) { MandatoryNode(node.left); MandatoryNode(node.right); - ExpressionType leftType = node.left->GetExpressionType(); - ExpressionType rightType = node.right->GetExpressionType(); + ShaderNodes::ExpressionType leftType = node.left->GetExpressionType(); + ShaderNodes::ExpressionType rightType = node.right->GetExpressionType(); switch (node.op) { - case BinaryType::Add: - case BinaryType::Equality: - case BinaryType::Substract: + case ShaderNodes::BinaryType::Add: + case ShaderNodes::BinaryType::Equality: + case ShaderNodes::BinaryType::Substract: TypeMustMatch(node.left, node.right); break; - case BinaryType::Multiply: - case BinaryType::Divide: + case ShaderNodes::BinaryType::Multiply: + case ShaderNodes::BinaryType::Divide: { switch (leftType) { - case ExpressionType::Float1: + case ShaderNodes::ExpressionType::Float1: { - if (Node::GetComponentType(rightType) != ExpressionType::Float1) + if (ShaderNodes::Node::GetComponentType(rightType) != ShaderNodes::ExpressionType::Float1) throw AstError{ "Left expression type is not compatible with right expression type" }; break; } - case ExpressionType::Float2: - case ExpressionType::Float3: - case ExpressionType::Float4: + case ShaderNodes::ExpressionType::Float2: + case ShaderNodes::ExpressionType::Float3: + case ShaderNodes::ExpressionType::Float4: { - if (leftType != rightType && rightType != ExpressionType::Float1) + if (leftType != rightType && rightType != ShaderNodes::ExpressionType::Float1) throw AstError{ "Left expression type is not compatible with right expression type" }; break; } - case ExpressionType::Mat4x4: + case ShaderNodes::ExpressionType::Mat4x4: { switch (rightType) { - case ExpressionType::Float1: - case ExpressionType::Float4: - case ExpressionType::Mat4x4: + case ShaderNodes::ExpressionType::Float1: + case ShaderNodes::ExpressionType::Float4: + case ShaderNodes::ExpressionType::Mat4x4: break; default: @@ -146,7 +161,7 @@ namespace Nz::ShaderAst Visit(node.right); } - void ShaderValidator::Visit(const Branch& node) + void ShaderValidator::Visit(const ShaderNodes::Branch& node) { for (const auto& condStatement : node.condStatements) { @@ -155,11 +170,7 @@ namespace Nz::ShaderAst } } - void ShaderValidator::Visit(const BuiltinVariable& /*node*/) - { - } - - void ShaderValidator::Visit(const Cast& node) + void ShaderValidator::Visit(const ShaderNodes::Cast& node) { unsigned int componentCount = 0; unsigned int requiredComponents = node.GetComponentCount(node.exprType); @@ -176,55 +187,203 @@ namespace Nz::ShaderAst throw AstError{ "Component count doesn't match required component count" }; } - void ShaderValidator::Visit(const Constant& /*node*/) + void ShaderValidator::Visit(const ShaderNodes::Constant& /*node*/) { } - void ShaderValidator::Visit(const DeclareVariable& node) + void ShaderValidator::Visit(const ShaderNodes::DeclareVariable& node) + { + assert(m_context); + + if (node.expression) + Visit(node.expression); + + auto& local = m_context->declaredLocals.emplace_back(); + local.name = node.variable->name; + local.type = node.variable->type; + } + + void ShaderValidator::Visit(const ShaderNodes::ExpressionStatement& node) { Visit(MandatoryNode(node.expression)); } - void ShaderValidator::Visit(const ExpressionStatement& node) + void ShaderValidator::Visit(const ShaderNodes::Identifier& node) { - Visit(MandatoryNode(node.expression)); + assert(m_context); + + if (!node.var) + throw AstError{ "Invalid variable" }; + + //< FIXME: Use variable visitor + switch (node.var->GetType()) + { + case ShaderNodes::VariableType::BuiltinVariable: + break; + + case ShaderNodes::VariableType::InputVariable: + { + auto& namedVar = static_cast(*node.var); + + for (std::size_t i = 0; i < m_shader.GetInputCount(); ++i) + { + const auto& input = m_shader.GetInput(i); + if (input.name == namedVar.name) + { + TypeMustMatch(input.type, namedVar.type); + return; + } + } + + throw AstError{ "Input not found" }; + } + + case ShaderNodes::VariableType::LocalVariable: + { + auto& localVar = static_cast(*node.var); + const auto& vars = m_context->declaredLocals; + + auto it = std::find_if(vars.begin(), vars.end(), [&](const auto& var) { return var.name == localVar.name; }); + if (it == vars.end()) + throw AstError{ "Local variable not found in this block" }; + + TypeMustMatch(it->type, localVar.type); + break; + } + + case ShaderNodes::VariableType::OutputVariable: + { + auto& outputVar = static_cast(*node.var); + + for (std::size_t i = 0; i < m_shader.GetOutputCount(); ++i) + { + const auto& input = m_shader.GetOutput(i); + if (input.name == outputVar.name) + { + TypeMustMatch(input.type, outputVar.type); + return; + } + } + + throw AstError{ "Output not found" }; + } + + case ShaderNodes::VariableType::ParameterVariable: + { + assert(m_context->currentFunction); + + auto& parameter = static_cast(*node.var); + const auto& parameters = m_context->currentFunction->parameters; + + auto it = std::find_if(parameters.begin(), parameters.end(), [&](const auto& parameter) { return parameter.name == parameter.name; }); + if (it == parameters.end()) + throw AstError{ "Parameter not found in function" }; + + TypeMustMatch(it->type, parameter.type); + break; + } + + case ShaderNodes::VariableType::UniformVariable: + { + auto& uniformVar = static_cast(*node.var); + + for (std::size_t i = 0; i < m_shader.GetUniformCount(); ++i) + { + const auto& uniform = m_shader.GetUniform(i); + if (uniform.name == uniformVar.name) + { + TypeMustMatch(uniform.type, uniformVar.type); + return; + } + } + + throw AstError{ "Uniform not found" }; + } + + default: + break; + } } - void ShaderValidator::Visit(const NamedVariable& node) + void ShaderValidator::Visit(const ShaderNodes::IntrinsicCall& node) { - if (node.name.empty()) - throw AstError{ "Variable has empty name" }; + switch (node.intrinsic) + { + case ShaderNodes::IntrinsicType::CrossProduct: + case ShaderNodes::IntrinsicType::DotProduct: + { + if (node.parameters.size() != 2) + throw AstError { "Expected 2 parameters" }; + + for (auto& param : node.parameters) + MandatoryNode(param); + + ShaderNodes::ExpressionType type = node.parameters.front()->GetExpressionType(); + for (std::size_t i = 1; i < node.parameters.size(); ++i) + { + if (type != node.parameters[i]->GetExpressionType()) + throw AstError{ "All type must match" }; + } + + break; + } + } + + switch (node.intrinsic) + { + case ShaderNodes::IntrinsicType::CrossProduct: + { + if (node.parameters[0]->GetExpressionType() != ShaderNodes::ExpressionType::Float3) + throw AstError{ "CrossProduct only works with Float3 expressions" }; + + break; + } + + case ShaderNodes::IntrinsicType::DotProduct: + break; + } + + for (auto& param : node.parameters) + Visit(param); } - void ShaderValidator::Visit(const Sample2D& node) + void ShaderValidator::Visit(const ShaderNodes::Sample2D& node) { - if (MandatoryExpr(node.sampler)->GetExpressionType() != ExpressionType::Sampler2D) + if (MandatoryExpr(node.sampler)->GetExpressionType() != ShaderNodes::ExpressionType::Sampler2D) throw AstError{ "Sampler must be a Sampler2D" }; - if (MandatoryExpr(node.coordinates)->GetExpressionType() != ExpressionType::Float2) + if (MandatoryExpr(node.coordinates)->GetExpressionType() != ShaderNodes::ExpressionType::Float2) throw AstError{ "Coordinates must be a Float2" }; Visit(node.sampler); Visit(node.coordinates); } - void ShaderValidator::Visit(const StatementBlock& node) + void ShaderValidator::Visit(const ShaderNodes::StatementBlock& node) { + assert(m_context); + + m_context->blockLocalIndex.push_back(m_context->declaredLocals.size()); + for (const auto& statement : node.statements) Visit(MandatoryNode(statement)); + + assert(m_context->declaredLocals.size() >= m_context->blockLocalIndex.back()); + m_context->declaredLocals.resize(m_context->blockLocalIndex.back()); + m_context->blockLocalIndex.pop_back(); } - void ShaderValidator::Visit(const SwizzleOp& node) + void ShaderValidator::Visit(const ShaderNodes::SwizzleOp& node) { if (node.componentCount > 4) throw AstError{ "Cannot swizzle more than four elements" }; switch (MandatoryExpr(node.expression)->GetExpressionType()) { - case ExpressionType::Float1: - case ExpressionType::Float2: - case ExpressionType::Float3: - case ExpressionType::Float4: + case ShaderNodes::ExpressionType::Float1: + case ShaderNodes::ExpressionType::Float2: + case ShaderNodes::ExpressionType::Float3: + case ShaderNodes::ExpressionType::Float4: break; default: @@ -234,9 +393,9 @@ namespace Nz::ShaderAst Visit(node.expression); } - bool Validate(const StatementPtr& shader, std::string* error) + bool ValidateShader(const ShaderAst& shader, std::string* error) { - ShaderValidator validator; - return validator.Validate(shader, error); + ShaderValidator validator(shader); + return validator.Validate(error); } } diff --git a/src/Nazara/Renderer/ShaderVarVisitor.cpp b/src/Nazara/Renderer/ShaderVarVisitor.cpp new file mode 100644 index 000000000..6f3838f26 --- /dev/null +++ b/src/Nazara/Renderer/ShaderVarVisitor.cpp @@ -0,0 +1,16 @@ +// Copyright (C) 2015 Jérôme Leclercq +// This file is part of the "Nazara Engine - Renderer module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include + +namespace Nz +{ + ShaderVarVisitor::~ShaderVarVisitor() = default; + + void ShaderVarVisitor::Visit(const ShaderNodes::VariablePtr& node) + { + node->Visit(*this); + } +} diff --git a/src/Nazara/Renderer/ShaderVariables.cpp b/src/Nazara/Renderer/ShaderVariables.cpp new file mode 100644 index 000000000..93701c4ef --- /dev/null +++ b/src/Nazara/Renderer/ShaderVariables.cpp @@ -0,0 +1,77 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Renderer module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include + +namespace Nz::ShaderNodes +{ + ShaderNodes::Variable::~Variable() = default; + + VariableType BuiltinVariable::GetType() const + { + return VariableType::BuiltinVariable; + } + + void BuiltinVariable::Visit(ShaderVarVisitor& visitor) + { + visitor.Visit(*this); + } + + + VariableType InputVariable::GetType() const + { + return VariableType::InputVariable; + } + + void InputVariable::Visit(ShaderVarVisitor& visitor) + { + visitor.Visit(*this); + } + + + VariableType LocalVariable::GetType() const + { + return VariableType::LocalVariable; + } + + void LocalVariable::Visit(ShaderVarVisitor& visitor) + { + visitor.Visit(*this); + } + + + VariableType OutputVariable::GetType() const + { + return VariableType::OutputVariable; + } + + void OutputVariable::Visit(ShaderVarVisitor& visitor) + { + visitor.Visit(*this); + } + + + VariableType ParameterVariable::GetType() const + { + return VariableType::ParameterVariable; + } + + void ParameterVariable::Visit(ShaderVarVisitor& visitor) + { + visitor.Visit(*this); + } + + + VariableType UniformVariable::GetType() const + { + return VariableType::UniformVariable; + } + + void UniformVariable::Visit(ShaderVarVisitor& visitor) + { + visitor.Visit(*this); + } +} diff --git a/src/Nazara/Renderer/ShaderVisitor.cpp b/src/Nazara/Renderer/ShaderVisitor.cpp index 2b5a590bd..dd7e01542 100644 --- a/src/Nazara/Renderer/ShaderVisitor.cpp +++ b/src/Nazara/Renderer/ShaderVisitor.cpp @@ -9,7 +9,7 @@ namespace Nz { ShaderVisitor::~ShaderVisitor() = default; - void ShaderVisitor::EnableCondition(const String& name, bool cond) + void ShaderVisitor::EnableCondition(const std::string& name, bool cond) { if (cond) m_conditions.insert(name); @@ -17,12 +17,12 @@ namespace Nz m_conditions.erase(name); } - bool ShaderVisitor::IsConditionEnabled(const String& name) const + bool ShaderVisitor::IsConditionEnabled(const std::string& name) const { return m_conditions.count(name) != 0; } - void ShaderVisitor::Visit(const ShaderAst::NodePtr& node) + void ShaderVisitor::Visit(const ShaderNodes::NodePtr& node) { node->Visit(*this); } diff --git a/src/Nazara/Renderer/ShaderWriter.cpp b/src/Nazara/Renderer/ShaderWriter.cpp index 982251556..8ca48da3e 100644 --- a/src/Nazara/Renderer/ShaderWriter.cpp +++ b/src/Nazara/Renderer/ShaderWriter.cpp @@ -7,4 +7,5 @@ namespace Nz { + ShaderWriter::~ShaderWriter() = default; } diff --git a/src/ShaderNode/DataModels/Cast.hpp b/src/ShaderNode/DataModels/Cast.hpp index bb287555c..c30f3eadc 100644 --- a/src/ShaderNode/DataModels/Cast.hpp +++ b/src/ShaderNode/DataModels/Cast.hpp @@ -19,7 +19,7 @@ class CastVec : public ShaderNode void BuildNodeEdition(QFormLayout* layout) override; - Nz::ShaderAst::ExpressionPtr GetExpression(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count) const override; + Nz::ShaderNodes::ExpressionPtr GetExpression(Nz::ShaderNodes::ExpressionPtr* expressions, std::size_t count) const override; QString caption() const override; QString name() const override; diff --git a/src/ShaderNode/DataModels/Cast.inl b/src/ShaderNode/DataModels/Cast.inl index 1a304c2c7..ccb15385c 100644 --- a/src/ShaderNode/DataModels/Cast.inl +++ b/src/ShaderNode/DataModels/Cast.inl @@ -49,7 +49,7 @@ void CastVec::BuildNodeEdition(QFormLayout* layout) } template -Nz::ShaderAst::ExpressionPtr CastVec::GetExpression(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count) const +Nz::ShaderNodes::ExpressionPtr CastVec::GetExpression(Nz::ShaderNodes::ExpressionPtr* expressions, std::size_t count) const { assert(m_input); assert(count == 1); @@ -60,7 +60,7 @@ Nz::ShaderAst::ExpressionPtr CastVec::GetExpression(Nz::Shader { std::size_t overflowComponentCount = ToComponentCount - fromComponentCount; - std::array expr; + std::array expr; expr[0] = expressions[0]; for (std::size_t i = 0; i < overflowComponentCount; ++i) expr[i + 1] = Nz::ShaderBuilder::Constant(m_overflowComponents[i]); @@ -71,13 +71,13 @@ Nz::ShaderAst::ExpressionPtr CastVec::GetExpression(Nz::Shader } else if (ToComponentCount < fromComponentCount) { - std::array swizzleComponents; + std::array swizzleComponents; for (std::size_t i = 0; i < ToComponentCount; ++i) - swizzleComponents[i] = static_cast(static_cast(Nz::ShaderAst::SwizzleComponent::First) + i); + swizzleComponents[i] = static_cast(static_cast(Nz::ShaderNodes::SwizzleComponent::First) + i); return std::apply([&](auto... components) { - std::initializer_list componentList{ components... }; + std::initializer_list componentList{ components... }; return Nz::ShaderBuilder::Swizzle(expressions[0], componentList); }, swizzleComponents); } diff --git a/src/ShaderNode/DataModels/FloatValue.cpp b/src/ShaderNode/DataModels/FloatValue.cpp index 3da83982e..f9c25074b 100644 --- a/src/ShaderNode/DataModels/FloatValue.cpp +++ b/src/ShaderNode/DataModels/FloatValue.cpp @@ -71,7 +71,7 @@ void FloatValue::BuildNodeEdition(QFormLayout* layout) layout->addRow(tr("Value"), spinbox); } -Nz::ShaderAst::ExpressionPtr FloatValue::GetExpression(Nz::ShaderAst::ExpressionPtr* /*expressions*/, std::size_t count) const +Nz::ShaderNodes::ExpressionPtr FloatValue::GetExpression(Nz::ShaderNodes::ExpressionPtr* /*expressions*/, std::size_t count) const { assert(count == 0); diff --git a/src/ShaderNode/DataModels/FloatValue.hpp b/src/ShaderNode/DataModels/FloatValue.hpp index 44244cd46..fe77e5464 100644 --- a/src/ShaderNode/DataModels/FloatValue.hpp +++ b/src/ShaderNode/DataModels/FloatValue.hpp @@ -28,7 +28,7 @@ class FloatValue : public ShaderNode void BuildNodeEdition(QFormLayout* layout) override; - Nz::ShaderAst::ExpressionPtr GetExpression(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count) const override; + Nz::ShaderNodes::ExpressionPtr GetExpression(Nz::ShaderNodes::ExpressionPtr* expressions, std::size_t count) const override; private: bool ComputePreview(QPixmap& pixmap) override; diff --git a/src/ShaderNode/DataModels/InputValue.cpp b/src/ShaderNode/DataModels/InputValue.cpp index 92d08ba3e..5a2b088dd 100644 --- a/src/ShaderNode/DataModels/InputValue.cpp +++ b/src/ShaderNode/DataModels/InputValue.cpp @@ -107,7 +107,7 @@ void InputValue::BuildNodeEdition(QFormLayout* layout) layout->addRow(tr("Input"), inputSelection); } -Nz::ShaderAst::ExpressionPtr InputValue::GetExpression(Nz::ShaderAst::ExpressionPtr* /*expressions*/, std::size_t count) const +Nz::ShaderNodes::ExpressionPtr InputValue::GetExpression(Nz::ShaderNodes::ExpressionPtr* /*expressions*/, std::size_t count) const { assert(count == 0); @@ -116,22 +116,22 @@ Nz::ShaderAst::ExpressionPtr InputValue::GetExpression(Nz::ShaderAst::Expression const auto& inputEntry = GetGraph().GetInput(*m_currentInputIndex); - Nz::ShaderAst::ExpressionType expression = [&] + Nz::ShaderNodes::ExpressionType expression = [&] { switch (inputEntry.type) { - case InOutType::Bool: return Nz::ShaderAst::ExpressionType::Boolean; - case InOutType::Float1: return Nz::ShaderAst::ExpressionType::Float1; - case InOutType::Float2: return Nz::ShaderAst::ExpressionType::Float2; - case InOutType::Float3: return Nz::ShaderAst::ExpressionType::Float3; - case InOutType::Float4: return Nz::ShaderAst::ExpressionType::Float4; + case InOutType::Bool: return Nz::ShaderNodes::ExpressionType::Boolean; + case InOutType::Float1: return Nz::ShaderNodes::ExpressionType::Float1; + case InOutType::Float2: return Nz::ShaderNodes::ExpressionType::Float2; + case InOutType::Float3: return Nz::ShaderNodes::ExpressionType::Float3; + case InOutType::Float4: return Nz::ShaderNodes::ExpressionType::Float4; } assert(false); throw std::runtime_error("Unhandled input type"); }(); - return Nz::ShaderBuilder::Input(inputEntry.name, expression); + return Nz::ShaderBuilder::Identifier(Nz::ShaderBuilder::Input(inputEntry.name, expression)); } auto InputValue::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const -> QtNodes::NodeDataType @@ -145,7 +145,7 @@ auto InputValue::dataType(QtNodes::PortType portType, QtNodes::PortIndex portInd const auto& inputEntry = GetGraph().GetInput(*m_currentInputIndex); switch (inputEntry.type) { - //case InputType::Bool: return Nz::ShaderAst::ExpressionType::Boolean; + //case InputType::Bool: return Nz::ShaderNodes::ExpressionType::Boolean; case InOutType::Float1: return FloatData::Type(); diff --git a/src/ShaderNode/DataModels/InputValue.hpp b/src/ShaderNode/DataModels/InputValue.hpp index a5eaabf01..d0e1593b9 100644 --- a/src/ShaderNode/DataModels/InputValue.hpp +++ b/src/ShaderNode/DataModels/InputValue.hpp @@ -19,7 +19,7 @@ class InputValue : public ShaderNode void BuildNodeEdition(QFormLayout* layout) override; - Nz::ShaderAst::ExpressionPtr GetExpression(Nz::ShaderAst::ExpressionPtr* /*expressions*/, std::size_t count) const override; + Nz::ShaderNodes::ExpressionPtr GetExpression(Nz::ShaderNodes::ExpressionPtr* /*expressions*/, std::size_t count) const override; QString caption() const override { return "Input"; } QString name() const override { return "Input"; } diff --git a/src/ShaderNode/DataModels/OutputValue.cpp b/src/ShaderNode/DataModels/OutputValue.cpp index 09d7aff78..7cf6fedec 100644 --- a/src/ShaderNode/DataModels/OutputValue.cpp +++ b/src/ShaderNode/DataModels/OutputValue.cpp @@ -51,10 +51,10 @@ void OutputValue::BuildNodeEdition(QFormLayout* layout) layout->addRow(tr("Output"), outputSelection); } -Nz::ShaderAst::ExpressionPtr OutputValue::GetExpression(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count) const +Nz::ShaderNodes::ExpressionPtr OutputValue::GetExpression(Nz::ShaderNodes::ExpressionPtr* expressions, std::size_t count) const { - using namespace Nz::ShaderAst; using namespace Nz::ShaderBuilder; + using namespace Nz::ShaderNodes; assert(count == 1); @@ -63,22 +63,22 @@ Nz::ShaderAst::ExpressionPtr OutputValue::GetExpression(Nz::ShaderAst::Expressio const auto& outputEntry = GetGraph().GetOutput(*m_currentOutputIndex); - Nz::ShaderAst::ExpressionType expression = [&] + Nz::ShaderNodes::ExpressionType expression = [&] { switch (outputEntry.type) { - case InOutType::Bool: return Nz::ShaderAst::ExpressionType::Boolean; - case InOutType::Float1: return Nz::ShaderAst::ExpressionType::Float1; - case InOutType::Float2: return Nz::ShaderAst::ExpressionType::Float2; - case InOutType::Float3: return Nz::ShaderAst::ExpressionType::Float3; - case InOutType::Float4: return Nz::ShaderAst::ExpressionType::Float4; + case InOutType::Bool: return Nz::ShaderNodes::ExpressionType::Boolean; + case InOutType::Float1: return Nz::ShaderNodes::ExpressionType::Float1; + case InOutType::Float2: return Nz::ShaderNodes::ExpressionType::Float2; + case InOutType::Float3: return Nz::ShaderNodes::ExpressionType::Float3; + case InOutType::Float4: return Nz::ShaderNodes::ExpressionType::Float4; } assert(false); throw std::runtime_error("Unhandled output type"); }(); - auto output = Nz::ShaderBuilder::Output(outputEntry.name, expression); + auto output = Nz::ShaderBuilder::Identifier(Nz::ShaderBuilder::Output(outputEntry.name, expression)); return Nz::ShaderBuilder::Assign(std::move(output), *expressions); } @@ -94,8 +94,8 @@ QtNodes::NodeDataType OutputValue::dataType(QtNodes::PortType portType, QtNodes: const auto& outputEntry = GetGraph().GetOutput(*m_currentOutputIndex); switch (outputEntry.type) { - //case InOutType::Bool: return Nz::ShaderAst::ExpressionType::Boolean; - //case InOutType::Float1: return Nz::ShaderAst::ExpressionType::Float1; + //case InOutType::Bool: return Nz::ShaderNodes::ExpressionType::Boolean; + //case InOutType::Float1: return Nz::ShaderNodes::ExpressionType::Float1; case InOutType::Float2: case InOutType::Float3: case InOutType::Float4: diff --git a/src/ShaderNode/DataModels/OutputValue.hpp b/src/ShaderNode/DataModels/OutputValue.hpp index 320b2bacb..284e302ea 100644 --- a/src/ShaderNode/DataModels/OutputValue.hpp +++ b/src/ShaderNode/DataModels/OutputValue.hpp @@ -16,7 +16,7 @@ class OutputValue : public ShaderNode void BuildNodeEdition(QFormLayout* layout) override; - Nz::ShaderAst::ExpressionPtr GetExpression(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count) const override; + Nz::ShaderNodes::ExpressionPtr GetExpression(Nz::ShaderNodes::ExpressionPtr* expressions, std::size_t count) const override; QString caption() const override { return "Output"; } QString name() const override { return "Output"; } diff --git a/src/ShaderNode/DataModels/SampleTexture.cpp b/src/ShaderNode/DataModels/SampleTexture.cpp index 3f0036519..2c9e2dcac 100644 --- a/src/ShaderNode/DataModels/SampleTexture.cpp +++ b/src/ShaderNode/DataModels/SampleTexture.cpp @@ -91,7 +91,7 @@ bool SampleTexture::ComputePreview(QPixmap& pixmap) return true; } -Nz::ShaderAst::ExpressionPtr SampleTexture::GetExpression(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count) const +Nz::ShaderNodes::ExpressionPtr SampleTexture::GetExpression(Nz::ShaderNodes::ExpressionPtr* expressions, std::size_t count) const { assert(m_texture); assert(m_uv); diff --git a/src/ShaderNode/DataModels/SampleTexture.hpp b/src/ShaderNode/DataModels/SampleTexture.hpp index 7afb77e0f..5b1dd98fd 100644 --- a/src/ShaderNode/DataModels/SampleTexture.hpp +++ b/src/ShaderNode/DataModels/SampleTexture.hpp @@ -17,7 +17,7 @@ class SampleTexture : public ShaderNode SampleTexture(ShaderGraph& graph); ~SampleTexture() = default; - Nz::ShaderAst::ExpressionPtr GetExpression(Nz::ShaderAst::ExpressionPtr* /*expressions*/, std::size_t count) const override; + Nz::ShaderNodes::ExpressionPtr GetExpression(Nz::ShaderNodes::ExpressionPtr* /*expressions*/, std::size_t count) const override; QString caption() const override { return "Sample texture"; } QString name() const override { return "SampleTexture"; } diff --git a/src/ShaderNode/DataModels/ShaderNode.hpp b/src/ShaderNode/DataModels/ShaderNode.hpp index e7ac130c9..30e2504ca 100644 --- a/src/ShaderNode/DataModels/ShaderNode.hpp +++ b/src/ShaderNode/DataModels/ShaderNode.hpp @@ -4,7 +4,7 @@ #define NAZARA_SHADERNODES_SHADERNODE_HPP #include -#include +#include #include #include #include @@ -23,7 +23,7 @@ class ShaderNode : public QtNodes::NodeDataModel inline void DisablePreview(); void EnablePreview(bool enable = true); - virtual Nz::ShaderAst::ExpressionPtr GetExpression(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count) const = 0; + virtual Nz::ShaderNodes::ExpressionPtr GetExpression(Nz::ShaderNodes::ExpressionPtr* expressions, std::size_t count) const = 0; inline ShaderGraph& GetGraph(); inline const ShaderGraph& GetGraph() const; inline const std::string& GetVariableName() const; diff --git a/src/ShaderNode/DataModels/TextureValue.cpp b/src/ShaderNode/DataModels/TextureValue.cpp index d543a502e..2e25eaa03 100644 --- a/src/ShaderNode/DataModels/TextureValue.cpp +++ b/src/ShaderNode/DataModels/TextureValue.cpp @@ -106,7 +106,7 @@ void TextureValue::BuildNodeEdition(QFormLayout* layout) layout->addRow(tr("Texture"), textureSelection); } -Nz::ShaderAst::ExpressionPtr TextureValue::GetExpression(Nz::ShaderAst::ExpressionPtr* /*expressions*/, std::size_t count) const +Nz::ShaderNodes::ExpressionPtr TextureValue::GetExpression(Nz::ShaderNodes::ExpressionPtr* /*expressions*/, std::size_t count) const { if (!m_currentTextureIndex) throw std::runtime_error("invalid texture input"); @@ -115,18 +115,18 @@ Nz::ShaderAst::ExpressionPtr TextureValue::GetExpression(Nz::ShaderAst::Expressi const auto& textureEntry = GetGraph().GetTexture(*m_currentTextureIndex); - Nz::ShaderAst::ExpressionType expression = [&] + Nz::ShaderNodes::ExpressionType expression = [&] { switch (textureEntry.type) { - case TextureType::Sampler2D: return Nz::ShaderAst::ExpressionType::Sampler2D; + case TextureType::Sampler2D: return Nz::ShaderNodes::ExpressionType::Sampler2D; } assert(false); throw std::runtime_error("Unhandled texture type"); }(); - return Nz::ShaderBuilder::Uniform(textureEntry.name, expression); + return Nz::ShaderBuilder::Identifier(Nz::ShaderBuilder::Uniform(textureEntry.name, expression)); } auto TextureValue::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const -> QtNodes::NodeDataType diff --git a/src/ShaderNode/DataModels/TextureValue.hpp b/src/ShaderNode/DataModels/TextureValue.hpp index 89cfcff21..dfb7efaff 100644 --- a/src/ShaderNode/DataModels/TextureValue.hpp +++ b/src/ShaderNode/DataModels/TextureValue.hpp @@ -18,7 +18,7 @@ class TextureValue : public ShaderNode void BuildNodeEdition(QFormLayout* layout) override; - Nz::ShaderAst::ExpressionPtr GetExpression(Nz::ShaderAst::ExpressionPtr* /*expressions*/, std::size_t count) const override; + Nz::ShaderNodes::ExpressionPtr GetExpression(Nz::ShaderNodes::ExpressionPtr* /*expressions*/, std::size_t count) const override; QString caption() const override { return "Texture"; } QString name() const override { return "Texture"; } diff --git a/src/ShaderNode/DataModels/VecBinOp.hpp b/src/ShaderNode/DataModels/VecBinOp.hpp index 977b0d3ba..d00049c04 100644 --- a/src/ShaderNode/DataModels/VecBinOp.hpp +++ b/src/ShaderNode/DataModels/VecBinOp.hpp @@ -6,14 +6,14 @@ #include #include -template +template class VecBinOp : public ShaderNode { public: VecBinOp(ShaderGraph& graph); ~VecBinOp() = default; - Nz::ShaderAst::ExpressionPtr GetExpression(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count) const override; + Nz::ShaderNodes::ExpressionPtr GetExpression(Nz::ShaderNodes::ExpressionPtr* expressions, std::size_t count) const override; unsigned int nPorts(QtNodes::PortType portType) const override; @@ -37,10 +37,10 @@ class VecBinOp : public ShaderNode std::shared_ptr m_output; }; -class VecAdd : public VecBinOp +class VecAdd : public VecBinOp { public: - using VecBinOp::VecBinOp; + using VecBinOp::VecBinOp; QString caption() const override; QString name() const override; @@ -48,10 +48,10 @@ class VecAdd : public VecBinOp void ApplyOp(const std::uint8_t* left, const std::uint8_t* right, std::uint8_t* output, std::size_t pixelCount) override; }; -class VecMul : public VecBinOp +class VecMul : public VecBinOp { public: - using VecBinOp::VecBinOp; + using VecBinOp::VecBinOp; QString caption() const override; QString name() const override; @@ -59,10 +59,10 @@ class VecMul : public VecBinOp void ApplyOp(const std::uint8_t* left, const std::uint8_t* right, std::uint8_t* output, std::size_t pixelCount) override; }; -class VecSub : public VecBinOp +class VecSub : public VecBinOp { public: - using VecBinOp::VecBinOp; + using VecBinOp::VecBinOp; QString caption() const override; QString name() const override; @@ -70,10 +70,10 @@ class VecSub : public VecBinOp void ApplyOp(const std::uint8_t* left, const std::uint8_t* right, std::uint8_t* output, std::size_t pixelCount) override; }; -class VecDiv : public VecBinOp +class VecDiv : public VecBinOp { public: - using VecBinOp::VecBinOp; + using VecBinOp::VecBinOp; QString caption() const override; QString name() const override; diff --git a/src/ShaderNode/DataModels/VecBinOp.inl b/src/ShaderNode/DataModels/VecBinOp.inl index 5a12aff08..255946543 100644 --- a/src/ShaderNode/DataModels/VecBinOp.inl +++ b/src/ShaderNode/DataModels/VecBinOp.inl @@ -1,15 +1,15 @@ #include #include -template +template VecBinOp::VecBinOp(ShaderGraph& graph) : ShaderNode(graph) { UpdateOutput(); } -template -Nz::ShaderAst::ExpressionPtr VecBinOp::GetExpression(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count) const +template +Nz::ShaderNodes::ExpressionPtr VecBinOp::GetExpression(Nz::ShaderNodes::ExpressionPtr* expressions, std::size_t count) const { assert(count == 2); using BuilderType = typename Nz::ShaderBuilder::template BinOpBuilder; @@ -17,7 +17,7 @@ Nz::ShaderAst::ExpressionPtr VecBinOp::GetExpression(Nz::ShaderAst::Expre return builder(expressions[0], expressions[1]); } -template +template QtNodes::NodeDataType VecBinOp::dataType(QtNodes::PortType /*portType*/, QtNodes::PortIndex portIndex) const { assert(portIndex == 0 || portIndex == 1); @@ -25,7 +25,7 @@ QtNodes::NodeDataType VecBinOp::dataType(QtNodes::PortType /*portType*/, return VecData::Type(); } -template +template unsigned int VecBinOp::nPorts(QtNodes::PortType portType) const { switch (portType) @@ -37,14 +37,14 @@ unsigned int VecBinOp::nPorts(QtNodes::PortType portType) const return 0; } -template +template std::shared_ptr VecBinOp::outData(QtNodes::PortIndex port) { assert(port == 0); return m_output; } -template +template void VecBinOp::setInData(std::shared_ptr value, int index) { assert(index == 0 || index == 1); @@ -65,7 +65,7 @@ void VecBinOp::setInData(std::shared_ptr value, int in UpdateOutput(); } -template +template QtNodes::NodeValidationState VecBinOp::validationState() const { if (!m_lhs || !m_rhs) @@ -77,7 +77,7 @@ QtNodes::NodeValidationState VecBinOp::validationState() const return QtNodes::NodeValidationState::Valid; } -template +template QString VecBinOp::validationMessage() const { if (!m_lhs || !m_rhs) @@ -89,7 +89,7 @@ QString VecBinOp::validationMessage() const return QString(); } -template +template bool VecBinOp::ComputePreview(QPixmap& pixmap) { if (!m_lhs || !m_rhs) @@ -99,7 +99,7 @@ bool VecBinOp::ComputePreview(QPixmap& pixmap) return true; } -template +template void VecBinOp::UpdateOutput() { if (validationState() != QtNodes::NodeValidationState::Valid) diff --git a/src/ShaderNode/DataModels/VecDot.cpp b/src/ShaderNode/DataModels/VecDot.cpp index 47b67b72c..48aac108c 100644 --- a/src/ShaderNode/DataModels/VecDot.cpp +++ b/src/ShaderNode/DataModels/VecDot.cpp @@ -1,5 +1,5 @@ #include -#include +#include VecDot::VecDot(ShaderGraph& graph) : ShaderNode(graph) @@ -8,11 +8,11 @@ ShaderNode(graph) UpdateOutput(); } -Nz::ShaderAst::ExpressionPtr VecDot::GetExpression(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count) const +Nz::ShaderNodes::ExpressionPtr VecDot::GetExpression(Nz::ShaderNodes::ExpressionPtr* expressions, std::size_t count) const { assert(count == 2); - using namespace Nz::ShaderAst; - return BinaryFunc::Build(BinaryIntrinsic::DotProduct, expressions[0], expressions[1]); + using namespace Nz::ShaderNodes; + return IntrinsicCall::Build(IntrinsicType::DotProduct, { expressions[0], expressions[1] }); } QString VecDot::caption() const diff --git a/src/ShaderNode/DataModels/VecDot.hpp b/src/ShaderNode/DataModels/VecDot.hpp index dc92bb5c8..74e6a7266 100644 --- a/src/ShaderNode/DataModels/VecDot.hpp +++ b/src/ShaderNode/DataModels/VecDot.hpp @@ -13,7 +13,7 @@ class VecDot : public ShaderNode VecDot(ShaderGraph& graph); ~VecDot() = default; - Nz::ShaderAst::ExpressionPtr GetExpression(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count) const override; + Nz::ShaderNodes::ExpressionPtr GetExpression(Nz::ShaderNodes::ExpressionPtr* expressions, std::size_t count) const override; QString caption() const override; QString name() const override; diff --git a/src/ShaderNode/DataModels/VecFloatMul.cpp b/src/ShaderNode/DataModels/VecFloatMul.cpp index f4ec6f957..3c10d08e2 100644 --- a/src/ShaderNode/DataModels/VecFloatMul.cpp +++ b/src/ShaderNode/DataModels/VecFloatMul.cpp @@ -1,5 +1,5 @@ #include -#include +#include VecFloatMul::VecFloatMul(ShaderGraph& graph) : ShaderNode(graph) @@ -7,10 +7,10 @@ ShaderNode(graph) UpdateOutput(); } -Nz::ShaderAst::ExpressionPtr VecFloatMul::GetExpression(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count) const +Nz::ShaderNodes::ExpressionPtr VecFloatMul::GetExpression(Nz::ShaderNodes::ExpressionPtr* expressions, std::size_t count) const { assert(count == 2); - using namespace Nz::ShaderAst; + using namespace Nz::ShaderNodes; return BinaryOp::Build(BinaryType::Multiply, expressions[0], expressions[1]); } diff --git a/src/ShaderNode/DataModels/VecFloatMul.hpp b/src/ShaderNode/DataModels/VecFloatMul.hpp index c4a9a97f7..dd1fbd1af 100644 --- a/src/ShaderNode/DataModels/VecFloatMul.hpp +++ b/src/ShaderNode/DataModels/VecFloatMul.hpp @@ -13,7 +13,7 @@ class VecFloatMul : public ShaderNode VecFloatMul(ShaderGraph& graph); ~VecFloatMul() = default; - Nz::ShaderAst::ExpressionPtr GetExpression(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count) const override; + Nz::ShaderNodes::ExpressionPtr GetExpression(Nz::ShaderNodes::ExpressionPtr* expressions, std::size_t count) const override; QString caption() const override; QString name() const override; diff --git a/src/ShaderNode/DataModels/VecValue.hpp b/src/ShaderNode/DataModels/VecValue.hpp index fe94e67cb..86cd93692 100644 --- a/src/ShaderNode/DataModels/VecValue.hpp +++ b/src/ShaderNode/DataModels/VecValue.hpp @@ -29,7 +29,7 @@ class VecValue : public ShaderNode void BuildNodeEdition(QFormLayout* layout) override; - Nz::ShaderAst::ExpressionPtr GetExpression(Nz::ShaderAst::ExpressionPtr* expressions, std::size_t count) const override; + Nz::ShaderNodes::ExpressionPtr GetExpression(Nz::ShaderNodes::ExpressionPtr* expressions, std::size_t count) const override; private: bool ComputePreview(QPixmap& pixmap) override; diff --git a/src/ShaderNode/DataModels/VecValue.inl b/src/ShaderNode/DataModels/VecValue.inl index a3ea2068e..8e158b94b 100644 --- a/src/ShaderNode/DataModels/VecValue.inl +++ b/src/ShaderNode/DataModels/VecValue.inl @@ -94,7 +94,7 @@ void VecValue::BuildNodeEdition(QFormLayout* layout) } template -Nz::ShaderAst::ExpressionPtr VecValue::GetExpression(Nz::ShaderAst::ExpressionPtr* /*expressions*/, std::size_t count) const +Nz::ShaderNodes::ExpressionPtr VecValue::GetExpression(Nz::ShaderNodes::ExpressionPtr* /*expressions*/, std::size_t count) const { assert(count == 0); diff --git a/src/ShaderNode/DataTypes/TextureData.hpp b/src/ShaderNode/DataTypes/TextureData.hpp index 778e66e05..632fa5bde 100644 --- a/src/ShaderNode/DataTypes/TextureData.hpp +++ b/src/ShaderNode/DataTypes/TextureData.hpp @@ -3,7 +3,7 @@ #ifndef NAZARA_SHADERNODES_TEXTUREDATA_HPP #define NAZARA_SHADERNODES_TEXTUREDATA_HPP -#include +#include #include #include diff --git a/src/ShaderNode/DataTypes/VecData.cpp b/src/ShaderNode/DataTypes/VecData.cpp index c1f883079..2d4a38001 100644 --- a/src/ShaderNode/DataTypes/VecData.cpp +++ b/src/ShaderNode/DataTypes/VecData.cpp @@ -2,13 +2,13 @@ #include #include -Nz::ShaderAst::ExpressionType VecData::GetExpressionType() const +Nz::ShaderNodes::ExpressionType VecData::GetExpressionType() const { switch (componentCount) { - case 2: return Nz::ShaderAst::ExpressionType::Float2; - case 3: return Nz::ShaderAst::ExpressionType::Float3; - case 4: return Nz::ShaderAst::ExpressionType::Float4; + case 2: return Nz::ShaderNodes::ExpressionType::Float2; + case 3: return Nz::ShaderNodes::ExpressionType::Float3; + case 4: return Nz::ShaderNodes::ExpressionType::Float4; default: break; } diff --git a/src/ShaderNode/DataTypes/VecData.hpp b/src/ShaderNode/DataTypes/VecData.hpp index 5c19be942..f333f9483 100644 --- a/src/ShaderNode/DataTypes/VecData.hpp +++ b/src/ShaderNode/DataTypes/VecData.hpp @@ -3,7 +3,7 @@ #ifndef NAZARA_SHADERNODES_VECDATA_HPP #define NAZARA_SHADERNODES_VECDATA_HPP -#include +#include #include #include @@ -13,7 +13,7 @@ struct VecData : public QtNodes::NodeData inline QtNodes::NodeDataType type() const override; - Nz::ShaderAst::ExpressionType GetExpressionType() const; + Nz::ShaderNodes::ExpressionType GetExpressionType() const; static inline QtNodes::NodeDataType Type(); @@ -27,28 +27,28 @@ struct VecExpressionTypeHelper; template<> struct VecExpressionTypeHelper<1> { - static constexpr Nz::ShaderAst::ExpressionType ExpressionType = Nz::ShaderAst::ExpressionType::Float1; + static constexpr Nz::ShaderNodes::ExpressionType ExpressionType = Nz::ShaderNodes::ExpressionType::Float1; }; template<> struct VecExpressionTypeHelper<2> { - static constexpr Nz::ShaderAst::ExpressionType ExpressionType = Nz::ShaderAst::ExpressionType::Float2; + static constexpr Nz::ShaderNodes::ExpressionType ExpressionType = Nz::ShaderNodes::ExpressionType::Float2; }; template<> struct VecExpressionTypeHelper<3> { - static constexpr Nz::ShaderAst::ExpressionType ExpressionType = Nz::ShaderAst::ExpressionType::Float3; + static constexpr Nz::ShaderNodes::ExpressionType ExpressionType = Nz::ShaderNodes::ExpressionType::Float3; }; template<> struct VecExpressionTypeHelper<4> { - static constexpr Nz::ShaderAst::ExpressionType ExpressionType = Nz::ShaderAst::ExpressionType::Float4; + static constexpr Nz::ShaderNodes::ExpressionType ExpressionType = Nz::ShaderNodes::ExpressionType::Float4; }; -template constexpr Nz::ShaderAst::ExpressionType VecExpressionType = VecExpressionTypeHelper::template ExpressionType; +template constexpr Nz::ShaderNodes::ExpressionType VecExpressionType = VecExpressionTypeHelper::template ExpressionType; struct VecTypeDummy {}; diff --git a/src/ShaderNode/ShaderGraph.cpp b/src/ShaderNode/ShaderGraph.cpp index 06b0ddea0..880afb2a9 100644 --- a/src/ShaderNode/ShaderGraph.cpp +++ b/src/ShaderNode/ShaderGraph.cpp @@ -46,9 +46,9 @@ m_flowScene(BuildRegistry()) }); // Test - AddInput("UV", InOutType::Float2, InputRole::TexCoord, 0); - AddOutput("RenderTarget0", InOutType::Float4); - AddTexture("Potato", TextureType::Sampler2D); + AddInput("UV", InOutType::Float2, InputRole::TexCoord, 0, 0); + AddOutput("RenderTarget0", InOutType::Float4, 0); + AddTexture("Potato", TextureType::Sampler2D, 1); UpdateTexturePreview(0, QImage(R"(C:\Users\Lynix\Pictures\potatavril.png)")); @@ -79,10 +79,11 @@ ShaderGraph::~ShaderGraph() m_flowScene.clearScene(); } -std::size_t ShaderGraph::AddInput(std::string name, InOutType type, InputRole role, std::size_t roleIndex) +std::size_t ShaderGraph::AddInput(std::string name, InOutType type, InputRole role, std::size_t roleIndex, std::size_t locationIndex) { std::size_t index = m_inputs.size(); auto& inputEntry = m_inputs.emplace_back(); + inputEntry.locationIndex = locationIndex; inputEntry.name = std::move(name); inputEntry.role = role; inputEntry.roleIndex = roleIndex; @@ -93,10 +94,11 @@ std::size_t ShaderGraph::AddInput(std::string name, InOutType type, InputRole ro return index; } -std::size_t ShaderGraph::AddOutput(std::string name, InOutType type) +std::size_t ShaderGraph::AddOutput(std::string name, InOutType type, std::size_t locationIndex) { std::size_t index = m_outputs.size(); auto& outputEntry = m_outputs.emplace_back(); + outputEntry.locationIndex = locationIndex; outputEntry.name = std::move(name); outputEntry.type = type; @@ -105,10 +107,11 @@ std::size_t ShaderGraph::AddOutput(std::string name, InOutType type) return index; } -std::size_t ShaderGraph::AddTexture(std::string name, TextureType type) +std::size_t ShaderGraph::AddTexture(std::string name, TextureType type, std::size_t bindingIndex) { std::size_t index = m_textures.size(); auto& textureEntry = m_textures.emplace_back(); + textureEntry.bindingIndex = bindingIndex; textureEntry.name = std::move(name); textureEntry.type = type; @@ -141,6 +144,7 @@ void ShaderGraph::Load(const QJsonObject& data) QJsonObject inputDoc = inputDocRef.toObject(); InputEntry& input = m_inputs.emplace_back(); + input.locationIndex = static_cast(inputDoc["locationIndex"].toInt(0)); input.name = inputDoc["name"].toString().toStdString(); input.role = DecodeEnum(inputDoc["role"].toString().toStdString()).value(); input.roleIndex = static_cast(inputDoc["roleIndex"].toInt(0)); @@ -155,6 +159,7 @@ void ShaderGraph::Load(const QJsonObject& data) QJsonObject outputDoc = outputDocRef.toObject(); OutputEntry& output = m_outputs.emplace_back(); + output.locationIndex = static_cast(outputDoc["locationIndex"].toInt(0)); output.name = outputDoc["name"].toString().toStdString(); output.type = DecodeEnum(outputDoc["type"].toString().toStdString()).value(); } @@ -167,6 +172,7 @@ void ShaderGraph::Load(const QJsonObject& data) QJsonObject textureDoc = textureDocRef.toObject(); TextureEntry& texture = m_textures.emplace_back(); + texture.bindingIndex = static_cast(textureDoc["bindingIndex"].toInt(0)); texture.name = textureDoc["name"].toString().toStdString(); texture.type = DecodeEnum(textureDoc["type"].toString().toStdString()).value(); } @@ -189,6 +195,7 @@ QJsonObject ShaderGraph::Save() for (const auto& input : m_inputs) { QJsonObject inputDoc; + inputDoc["locationIndex"] = int(input.locationIndex); inputDoc["name"] = QString::fromStdString(input.name); inputDoc["role"] = QString(EnumToString(input.role)); inputDoc["roleIndex"] = int(input.roleIndex); @@ -204,6 +211,7 @@ QJsonObject ShaderGraph::Save() for (const auto& output : m_outputs) { QJsonObject outputDoc; + outputDoc["locationIndex"] = int(output.locationIndex); outputDoc["name"] = QString::fromStdString(output.name); outputDoc["type"] = QString(EnumToString(output.type)); @@ -217,6 +225,7 @@ QJsonObject ShaderGraph::Save() for (const auto& texture : m_textures) { QJsonObject textureDoc; + textureDoc["bindingIndex"] = int(texture.bindingIndex); textureDoc["name"] = QString::fromStdString(texture.name); textureDoc["type"] = QString(EnumToString(texture.type)); @@ -247,9 +256,9 @@ QJsonObject ShaderGraph::Save() return sceneJson; } -Nz::ShaderAst::StatementPtr ShaderGraph::ToAst() +Nz::ShaderNodes::StatementPtr ShaderGraph::ToAst() { - std::vector statements; + std::vector statements; QHash usageCount; std::function DetectVariables; @@ -278,13 +287,13 @@ Nz::ShaderAst::StatementPtr ShaderGraph::ToAst() DetectVariables(node); }); - QHash variableExpressions; + QHash variableExpressions; unsigned int varCount = 0; std::unordered_set usedVariableNames; - std::function HandleNode; - HandleNode = [&](QtNodes::Node* node) -> Nz::ShaderAst::ExpressionPtr + std::function HandleNode; + HandleNode = [&](QtNodes::Node* node) -> Nz::ShaderNodes::ExpressionPtr { ShaderNode* shaderNode = static_cast(node->nodeDataModel()); if (shaderNode->validationState() != QtNodes::NodeValidationState::Valid) @@ -298,7 +307,7 @@ Nz::ShaderAst::StatementPtr ShaderGraph::ToAst() assert(it != usageCount.end()); std::size_t inputCount = shaderNode->nPorts(QtNodes::PortType::In); - Nz::StackArray expressions = NazaraStackArray(Nz::ShaderAst::ExpressionPtr, inputCount); + Nz::StackArray expressions = NazaraStackArray(Nz::ShaderNodes::ExpressionPtr, inputCount); std::size_t i = 0; for (const auto& connectionSet : node->nodeState().getEntries(QtNodes::PortType::In)) @@ -316,8 +325,8 @@ Nz::ShaderAst::StatementPtr ShaderGraph::ToAst() const std::string& variableName = shaderNode->GetVariableName(); if (*it > 1 || !variableName.empty()) { - Nz::ShaderAst::ExpressionPtr varExpression; - if (expression->GetExpressionCategory() == Nz::ShaderAst::ExpressionCategory::RValue) + Nz::ShaderNodes::ExpressionPtr varExpression; + if (expression->GetExpressionCategory() == Nz::ShaderNodes::ExpressionCategory::RValue) { std::string name; if (variableName.empty()) @@ -330,10 +339,10 @@ Nz::ShaderAst::StatementPtr ShaderGraph::ToAst() usedVariableNames.insert(name); - auto variable = Nz::ShaderBuilder::Variable(std::move(name), expression->GetExpressionType()); + auto variable = Nz::ShaderBuilder::Local(std::move(name), expression->GetExpressionType()); statements.emplace_back(Nz::ShaderBuilder::DeclareVariable(variable, expression)); - varExpression = variable; + varExpression = Nz::ShaderBuilder::Identifier(variable); } else varExpression = expression; @@ -354,13 +363,14 @@ Nz::ShaderAst::StatementPtr ShaderGraph::ToAst() } }); - return Nz::ShaderAst::StatementBlock::Build(std::move(statements)); + return Nz::ShaderNodes::StatementBlock::Build(std::move(statements)); } -void ShaderGraph::UpdateInput(std::size_t inputIndex, std::string name, InOutType type, InputRole role, std::size_t roleIndex) +void ShaderGraph::UpdateInput(std::size_t inputIndex, std::string name, InOutType type, InputRole role, std::size_t roleIndex, std::size_t locationIndex) { assert(inputIndex < m_inputs.size()); auto& inputEntry = m_inputs[inputIndex]; + inputEntry.locationIndex = locationIndex; inputEntry.name = std::move(name); inputEntry.role = role; inputEntry.roleIndex = roleIndex; @@ -369,10 +379,11 @@ void ShaderGraph::UpdateInput(std::size_t inputIndex, std::string name, InOutTyp OnInputUpdate(this, inputIndex); } -void ShaderGraph::UpdateOutput(std::size_t outputIndex, std::string name, InOutType type) +void ShaderGraph::UpdateOutput(std::size_t outputIndex, std::string name, InOutType type, std::size_t locationIndex) { assert(outputIndex < m_outputs.size()); auto& outputEntry = m_outputs[outputIndex]; + outputEntry.locationIndex = locationIndex; outputEntry.name = std::move(name); outputEntry.type = type; diff --git a/src/ShaderNode/ShaderGraph.hpp b/src/ShaderNode/ShaderGraph.hpp index 536a01dcc..add7e52ab 100644 --- a/src/ShaderNode/ShaderGraph.hpp +++ b/src/ShaderNode/ShaderGraph.hpp @@ -4,7 +4,7 @@ #define NAZARA_SHADERNODES_SHADERGRAPH_HPP #include -#include +#include #include #include #include @@ -23,9 +23,9 @@ class ShaderGraph ShaderGraph(); ~ShaderGraph(); - std::size_t AddInput(std::string name, InOutType type, InputRole role, std::size_t roleIndex); - std::size_t AddOutput(std::string name, InOutType type); - std::size_t AddTexture(std::string name, TextureType type); + std::size_t AddInput(std::string name, InOutType type, InputRole role, std::size_t roleIndex, std::size_t locationIndex); + std::size_t AddOutput(std::string name, InOutType type, std::size_t locationIndex); + std::size_t AddTexture(std::string name, TextureType type, std::size_t bindingIndex); void Clear(); @@ -44,14 +44,15 @@ class ShaderGraph void Load(const QJsonObject& data); QJsonObject Save(); - Nz::ShaderAst::StatementPtr ToAst(); + Nz::ShaderNodes::StatementPtr ToAst(); - void UpdateInput(std::size_t inputIndex, std::string name, InOutType type, InputRole role, std::size_t roleIndex); - void UpdateOutput(std::size_t outputIndex, std::string name, InOutType type); + void UpdateInput(std::size_t inputIndex, std::string name, InOutType type, InputRole role, std::size_t roleIndex, std::size_t locationIndex); + void UpdateOutput(std::size_t outputIndex, std::string name, InOutType type, std::size_t locationIndex); void UpdateTexturePreview(std::size_t texture, QImage preview); struct InputEntry { + std::size_t locationIndex; std::size_t roleIndex; std::string name; InputRole role; @@ -60,12 +61,14 @@ class ShaderGraph struct OutputEntry { + std::size_t locationIndex; std::string name; InOutType type; }; struct TextureEntry { + std::size_t bindingIndex; std::string name; TextureType type; QImage preview; diff --git a/src/ShaderNode/Widgets/InputEditDialog.cpp b/src/ShaderNode/Widgets/InputEditDialog.cpp index 09f711f3d..bd56fd598 100644 --- a/src/ShaderNode/Widgets/InputEditDialog.cpp +++ b/src/ShaderNode/Widgets/InputEditDialog.cpp @@ -23,6 +23,8 @@ QDialog(parent) for (std::size_t i = 0; i < InputRoleCount; ++i) m_roleList->addItem(EnumToString(static_cast(i))); + m_locationIndex = new QSpinBox; + m_roleIndex = new QSpinBox; QFormLayout* formLayout = new QFormLayout; @@ -30,6 +32,7 @@ QDialog(parent) formLayout->addRow(tr("Type"), m_typeList); formLayout->addRow(tr("Role"), m_roleList); formLayout->addRow(tr("Role index"), m_roleIndex); + formLayout->addRow(tr("Input index"), m_locationIndex); QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); connect(buttonBox, &QDialogButtonBox::accepted, this, &InputEditDialog::OnAccept); @@ -46,6 +49,7 @@ InputEditDialog::InputEditDialog(const InputInfo& input, QWidget* parent) : InputEditDialog(parent) { m_inputName->setText(QString::fromStdString(input.name)); + m_locationIndex->setValue(int(input.locationIndex)); m_roleIndex->setValue(int(input.roleIndex)); m_roleList->setCurrentText(EnumToString(input.role)); m_typeList->setCurrentText(EnumToString(input.type)); @@ -54,6 +58,7 @@ InputEditDialog(parent) InputInfo InputEditDialog::GetInputInfo() const { InputInfo inputInfo; + inputInfo.locationIndex = static_cast(m_locationIndex->value()); inputInfo.name = m_inputName->text().toStdString(); inputInfo.role = static_cast(m_roleList->currentIndex()); inputInfo.roleIndex = static_cast(m_roleIndex->value()); diff --git a/src/ShaderNode/Widgets/InputEditDialog.hpp b/src/ShaderNode/Widgets/InputEditDialog.hpp index 633b9c99d..0f6655088 100644 --- a/src/ShaderNode/Widgets/InputEditDialog.hpp +++ b/src/ShaderNode/Widgets/InputEditDialog.hpp @@ -12,6 +12,7 @@ class QSpinBox; struct InputInfo { + std::size_t locationIndex; std::size_t roleIndex; std::string name; InputRole role; @@ -33,6 +34,7 @@ class InputEditDialog : public QDialog QComboBox* m_roleList; QComboBox* m_typeList; QLineEdit* m_inputName; + QSpinBox* m_locationIndex; QSpinBox* m_roleIndex; }; diff --git a/src/ShaderNode/Widgets/InputEditor.cpp b/src/ShaderNode/Widgets/InputEditor.cpp index a0dee923d..f281c327a 100644 --- a/src/ShaderNode/Widgets/InputEditor.cpp +++ b/src/ShaderNode/Widgets/InputEditor.cpp @@ -39,7 +39,7 @@ void InputEditor::OnAddInput() connect(dialog, &QDialog::accepted, [this, dialog] { InputInfo inputInfo = dialog->GetInputInfo(); - m_shaderGraph.AddInput(std::move(inputInfo.name), inputInfo.type, inputInfo.role, inputInfo.roleIndex); + m_shaderGraph.AddInput(std::move(inputInfo.name), inputInfo.type, inputInfo.role, inputInfo.roleIndex, inputInfo.locationIndex); }); dialog->open(); @@ -60,7 +60,7 @@ void InputEditor::OnEditInput(int inputIndex) connect(dialog, &QDialog::accepted, [this, dialog, inputIndex] { InputInfo inputInfo = dialog->GetInputInfo(); - m_shaderGraph.UpdateInput(inputIndex, std::move(inputInfo.name), inputInfo.type, inputInfo.role, inputInfo.roleIndex); + m_shaderGraph.UpdateInput(inputIndex, std::move(inputInfo.name), inputInfo.type, inputInfo.role, inputInfo.roleIndex, inputInfo.locationIndex); }); dialog->open(); diff --git a/src/ShaderNode/Widgets/MainWindow.cpp b/src/ShaderNode/Widgets/MainWindow.cpp index c30007f14..c59a59254 100644 --- a/src/ShaderNode/Widgets/MainWindow.cpp +++ b/src/ShaderNode/Widgets/MainWindow.cpp @@ -1,5 +1,7 @@ #include +#include #include +#include #include #include #include @@ -84,8 +86,6 @@ void MainWindow::BuildMenu() QMenu* shader = menu->addMenu(tr("&Shader")); { - QtNodes::FlowScene* scene = &m_shaderGraph.GetScene(); - QAction* loadShader = shader->addAction(tr("Load...")); QObject::connect(loadShader, &QAction::triggered, this, &MainWindow::OnLoad); QAction* saveShader = shader->addAction(tr("Save...")); @@ -101,8 +101,52 @@ void MainWindow::OnCompileToGLSL() { try { + Nz::ShaderNodes::StatementPtr shaderAst = m_shaderGraph.ToAst(); + + Nz::File file("shader.shader", Nz::OpenMode_WriteOnly); + file.Write(Nz::ShaderNodes::Serialize(shaderAst)); + + //TODO: Put in another function + auto GetExpressionFromInOut = [&] (InOutType type) + { + switch (type) + { + case InOutType::Bool: return Nz::ShaderNodes::ExpressionType::Boolean; + case InOutType::Float1: return Nz::ShaderNodes::ExpressionType::Float1; + case InOutType::Float2: return Nz::ShaderNodes::ExpressionType::Float2; + case InOutType::Float3: return Nz::ShaderNodes::ExpressionType::Float3; + case InOutType::Float4: return Nz::ShaderNodes::ExpressionType::Float4; + } + + assert(false); + throw std::runtime_error("Unhandled input type"); + }; + + auto GetExpressionFromTexture = [&](TextureType type) + { + switch (type) + { + case TextureType::Sampler2D: return Nz::ShaderNodes::ExpressionType::Sampler2D; + } + + assert(false); + throw std::runtime_error("Unhandled texture type"); + }; + + Nz::ShaderAst shader; + for (const auto& input : m_shaderGraph.GetInputs()) + shader.AddInput(input.name, GetExpressionFromInOut(input.type), input.locationIndex); + + for (const auto& output : m_shaderGraph.GetOutputs()) + shader.AddOutput(output.name, GetExpressionFromInOut(output.type), output.locationIndex); + + for (const auto& uniform : m_shaderGraph.GetTextures()) + shader.AddUniform(uniform.name, GetExpressionFromTexture(uniform.type), uniform.bindingIndex); + + shader.AddFunction("main", shaderAst); + Nz::GlslWriter writer; - Nz::String glsl = writer.Generate(m_shaderGraph.ToAst()); + Nz::String glsl = writer.Generate(shader); std::cout << glsl << std::endl; diff --git a/src/ShaderNode/Widgets/OutputEditDialog.cpp b/src/ShaderNode/Widgets/OutputEditDialog.cpp index 23f092f75..d2c83e58e 100644 --- a/src/ShaderNode/Widgets/OutputEditDialog.cpp +++ b/src/ShaderNode/Widgets/OutputEditDialog.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include OutputEditDialog::OutputEditDialog(QWidget* parent) : @@ -18,9 +19,12 @@ QDialog(parent) for (std::size_t i = 0; i < InOutTypeCount; ++i) m_typeList->addItem(EnumToString(static_cast(i))); + m_locationIndex = new QSpinBox; + QFormLayout* formLayout = new QFormLayout; formLayout->addRow(tr("Name"), m_outputName); formLayout->addRow(tr("Type"), m_typeList); + formLayout->addRow(tr("Output index"), m_locationIndex); QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); connect(buttonBox, &QDialogButtonBox::accepted, this, &OutputEditDialog::OnAccept); @@ -33,16 +37,18 @@ QDialog(parent) setLayout(verticalLayout); } -OutputEditDialog::OutputEditDialog(const OutputInfo& input, QWidget* parent) : +OutputEditDialog::OutputEditDialog(const OutputInfo& output, QWidget* parent) : OutputEditDialog(parent) { - m_outputName->setText(QString::fromStdString(input.name)); - m_typeList->setCurrentText(EnumToString(input.type)); + m_locationIndex->setValue(int(output.locationIndex)); + m_outputName->setText(QString::fromStdString(output.name)); + m_typeList->setCurrentText(EnumToString(output.type)); } OutputInfo OutputEditDialog::GetOutputInfo() const { OutputInfo inputInfo; + inputInfo.locationIndex = static_cast(m_locationIndex->value()); inputInfo.name = m_outputName->text().toStdString(); inputInfo.type = static_cast(m_typeList->currentIndex()); diff --git a/src/ShaderNode/Widgets/OutputEditDialog.hpp b/src/ShaderNode/Widgets/OutputEditDialog.hpp index 3c06323dd..6a8cc68fb 100644 --- a/src/ShaderNode/Widgets/OutputEditDialog.hpp +++ b/src/ShaderNode/Widgets/OutputEditDialog.hpp @@ -8,9 +8,11 @@ class QComboBox; class QLineEdit; +class QSpinBox; struct OutputInfo { + std::size_t locationIndex; std::string name; InOutType type; }; @@ -19,7 +21,7 @@ class OutputEditDialog : public QDialog { public: OutputEditDialog(QWidget* parent = nullptr); - OutputEditDialog(const OutputInfo& input, QWidget* parent = nullptr); + OutputEditDialog(const OutputInfo& output, QWidget* parent = nullptr); ~OutputEditDialog() = default; OutputInfo GetOutputInfo() const; @@ -29,6 +31,7 @@ class OutputEditDialog : public QDialog QComboBox* m_typeList; QLineEdit* m_outputName; + QSpinBox* m_locationIndex; }; #include diff --git a/src/ShaderNode/Widgets/OutputEditor.cpp b/src/ShaderNode/Widgets/OutputEditor.cpp index ba317de07..868168c8a 100644 --- a/src/ShaderNode/Widgets/OutputEditor.cpp +++ b/src/ShaderNode/Widgets/OutputEditor.cpp @@ -38,8 +38,8 @@ void OutputEditor::OnAddOutput() dialog->setAttribute(Qt::WA_DeleteOnClose, true); connect(dialog, &QDialog::accepted, [this, dialog] { - OutputInfo inputInfo = dialog->GetOutputInfo(); - m_shaderGraph.AddOutput(std::move(inputInfo.name), inputInfo.type); + OutputInfo outputInfo = dialog->GetOutputInfo(); + m_shaderGraph.AddOutput(std::move(outputInfo.name), outputInfo.type, outputInfo.locationIndex); }); dialog->open(); @@ -57,8 +57,8 @@ void OutputEditor::OnEditOutput(int inputIndex) dialog->setAttribute(Qt::WA_DeleteOnClose, true); connect(dialog, &QDialog::accepted, [this, dialog, inputIndex] { - OutputInfo inputInfo = dialog->GetOutputInfo(); - m_shaderGraph.UpdateOutput(inputIndex, std::move(inputInfo.name), inputInfo.type); + OutputInfo outputInfo = dialog->GetOutputInfo(); + m_shaderGraph.UpdateOutput(inputIndex, std::move(outputInfo.name), outputInfo.type, outputInfo.locationIndex); }); dialog->open(); From 40ade49767d901b73f84b4812b2e48c68a17f10f Mon Sep 17 00:00:00 2001 From: Lynix Date: Wed, 17 Jun 2020 16:00:16 +0200 Subject: [PATCH 039/105] Update global headers --- include/Nazara/Core.hpp | 1 + include/Nazara/OpenGLRenderer.hpp | 56 +++++++++++++++++++++++++++++++ include/Nazara/Renderer.hpp | 7 ++++ 3 files changed, 64 insertions(+) create mode 100644 include/Nazara/OpenGLRenderer.hpp diff --git a/include/Nazara/Core.hpp b/include/Nazara/Core.hpp index 579a0c267..0bcef73cf 100644 --- a/include/Nazara/Core.hpp +++ b/include/Nazara/Core.hpp @@ -62,6 +62,7 @@ #include #include #include +#include #include #include #include diff --git a/include/Nazara/OpenGLRenderer.hpp b/include/Nazara/OpenGLRenderer.hpp new file mode 100644 index 000000000..e74b11c6a --- /dev/null +++ b/include/Nazara/OpenGLRenderer.hpp @@ -0,0 +1,56 @@ +// This file was automatically generated + +/* + Nazara Engine - OpenGL + + Copyright (C) 2015 Jérôme "Lynix" Leclercq (Lynix680@gmail.com) + + Permission is hereby granted, free of charge, to any person obtaining a copy of + this software and associated documentation files (the "Software"), to deal in + the Software without restriction, including without limitation the rights to + use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is furnished to do + so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ + +#pragma once + +#ifndef NAZARA_GLOBAL_OPENGLRENDERER_HPP +#define NAZARA_GLOBAL_OPENGLRENDERER_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#endif // NAZARA_GLOBAL_OPENGLRENDERER_HPP diff --git a/include/Nazara/Renderer.hpp b/include/Nazara/Renderer.hpp index fad7760fc..32e4f43de 100644 --- a/include/Nazara/Renderer.hpp +++ b/include/Nazara/Renderer.hpp @@ -55,7 +55,14 @@ #include #include #include +#include +#include +#include #include +#include +#include +#include +#include #include #include #include From 0ff10bf1e2978cc53bd749c895c54c1a2dee4ab7 Mon Sep 17 00:00:00 2001 From: Lynix Date: Wed, 17 Jun 2020 16:07:58 +0200 Subject: [PATCH 040/105] Improve GLSL output when using intrinsic --- src/Nazara/Renderer/GlslWriter.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Nazara/Renderer/GlslWriter.cpp b/src/Nazara/Renderer/GlslWriter.cpp index 8d8e024e7..f32239663 100644 --- a/src/Nazara/Renderer/GlslWriter.cpp +++ b/src/Nazara/Renderer/GlslWriter.cpp @@ -368,17 +368,17 @@ namespace Nz break; } - m_currentState->stream << '('; + Append("("); for (std::size_t i = 0; i < node.parameters.size(); ++i) { if (i != 0) - m_currentState->stream << ", "; + Append(", "); Visit(node.parameters[i]); - m_currentState->stream << ' '; + Append(" "); Visit(node.parameters[i]); } - m_currentState->stream << ")\n"; + Append(")"); } void GlslWriter::Visit(const ShaderNodes::LocalVariable& var) From 736ca1c409ef0f81df0cd39b7f10cb9b13562cfa Mon Sep 17 00:00:00 2001 From: Lynix Date: Wed, 17 Jun 2020 20:09:21 +0200 Subject: [PATCH 041/105] Renderer/ShaderAst: Add serialization --- include/Nazara/Renderer/ShaderNodes.hpp | 32 +-- include/Nazara/Renderer/ShaderNodes.inl | 23 +- include/Nazara/Renderer/ShaderSerializer.hpp | 54 ++-- include/Nazara/Renderer/ShaderSerializer.inl | 24 +- src/Nazara/Renderer/GlslWriter.cpp | 4 +- src/Nazara/Renderer/ShaderSerializer.cpp | 260 ++++++++++++++----- src/ShaderNode/Widgets/MainWindow.cpp | 6 +- 7 files changed, 285 insertions(+), 118 deletions(-) diff --git a/include/Nazara/Renderer/ShaderNodes.hpp b/include/Nazara/Renderer/ShaderNodes.hpp index d6bafc911..659e643a3 100644 --- a/include/Nazara/Renderer/ShaderNodes.hpp +++ b/include/Nazara/Renderer/ShaderNodes.hpp @@ -34,6 +34,7 @@ namespace Nz virtual ~Node(); inline NodeType GetType() const; + inline bool IsStatement() const; virtual void Visit(ShaderVisitor& visitor) = 0; @@ -41,10 +42,24 @@ namespace Nz static inline ExpressionType GetComponentType(ExpressionType type); protected: - inline Node(NodeType type); + inline Node(NodeType type, bool isStatement); private: NodeType m_type; + bool m_isStatement; + }; + + class Expression; + + using ExpressionPtr = std::shared_ptr; + + class NAZARA_RENDERER_API Expression : public Node + { + public: + inline Expression(NodeType type); + + virtual ExpressionCategory GetExpressionCategory() const; + virtual ExpressionType GetExpressionType() const = 0; }; class Statement; @@ -54,20 +69,7 @@ namespace Nz class NAZARA_RENDERER_API Statement : public Node { public: - using Node::Node; - }; - - class Expression; - - using ExpressionPtr = std::shared_ptr; - - class NAZARA_RENDERER_API Expression : public Node - { - public: - using Node::Node; - - virtual ExpressionCategory GetExpressionCategory() const; - virtual ExpressionType GetExpressionType() const = 0; + inline Statement(NodeType type); }; struct NAZARA_RENDERER_API ExpressionStatement : public Statement diff --git a/include/Nazara/Renderer/ShaderNodes.inl b/include/Nazara/Renderer/ShaderNodes.inl index 1bcf4effa..bafad38f5 100644 --- a/include/Nazara/Renderer/ShaderNodes.inl +++ b/include/Nazara/Renderer/ShaderNodes.inl @@ -7,8 +7,9 @@ namespace Nz::ShaderNodes { - inline Node::Node(NodeType type) : - m_type(type) + inline Node::Node(NodeType type, bool isStatement) : + m_type(type), + m_isStatement(isStatement) { } @@ -17,6 +18,11 @@ namespace Nz::ShaderNodes return m_type; } + inline bool Node::IsStatement() const + { + return m_isStatement; + } + inline unsigned int Node::GetComponentCount(ExpressionType type) { switch (type) @@ -55,6 +61,19 @@ namespace Nz::ShaderNodes } } + + inline Expression::Expression(NodeType type) : + Node(type, false) + { + } + + inline Statement::Statement(NodeType type) : + Node(type, true) + { + } + + + inline ExpressionStatement::ExpressionStatement() : Statement(NodeType::ExpressionStatement) { diff --git a/include/Nazara/Renderer/ShaderSerializer.hpp b/include/Nazara/Renderer/ShaderSerializer.hpp index daeb13e73..a5e012a9c 100644 --- a/include/Nazara/Renderer/ShaderSerializer.hpp +++ b/include/Nazara/Renderer/ShaderSerializer.hpp @@ -14,8 +14,10 @@ #include #include -namespace Nz::ShaderNodes +namespace Nz { + class ShaderAst; + class NAZARA_RENDERER_API ShaderSerializerBase { public: @@ -24,28 +26,29 @@ namespace Nz::ShaderNodes ShaderSerializerBase(ShaderSerializerBase&&) = delete; ~ShaderSerializerBase() = default; - void Serialize(AssignOp& node); - void Serialize(BinaryOp& node); - void Serialize(BuiltinVariable& var); - void Serialize(Branch& node); - void Serialize(Cast& node); - void Serialize(Constant& node); - void Serialize(DeclareVariable& node); - void Serialize(ExpressionStatement& node); - void Serialize(Identifier& node); - void Serialize(IntrinsicCall& node); - void Serialize(NamedVariable& var); - void Serialize(Sample2D& node); - void Serialize(StatementBlock& node); - void Serialize(SwizzleOp& node); + void Serialize(ShaderNodes::AssignOp& node); + void Serialize(ShaderNodes::BinaryOp& node); + void Serialize(ShaderNodes::BuiltinVariable& var); + void Serialize(ShaderNodes::Branch& node); + void Serialize(ShaderNodes::Cast& node); + void Serialize(ShaderNodes::Constant& node); + void Serialize(ShaderNodes::DeclareVariable& node); + void Serialize(ShaderNodes::ExpressionStatement& node); + void Serialize(ShaderNodes::Identifier& node); + void Serialize(ShaderNodes::IntrinsicCall& node); + void Serialize(ShaderNodes::NamedVariable& var); + void Serialize(ShaderNodes::Sample2D& node); + void Serialize(ShaderNodes::StatementBlock& node); + void Serialize(ShaderNodes::SwizzleOp& node); protected: template void Container(T& container); template void Enum(T& enumVal); + template void OptVal(std::optional& optVal); virtual bool IsWriting() const = 0; - virtual void Node(NodePtr& node) = 0; + virtual void Node(ShaderNodes::NodePtr& node) = 0; template void Node(std::shared_ptr& node); virtual void Value(bool& val) = 0; @@ -57,7 +60,7 @@ namespace Nz::ShaderNodes virtual void Value(UInt32& val) = 0; inline void Value(std::size_t& val); - virtual void Variable(VariablePtr& var) = 0; + virtual void Variable(ShaderNodes::VariablePtr& var) = 0; template void Variable(std::shared_ptr& var); }; @@ -67,11 +70,12 @@ namespace Nz::ShaderNodes inline ShaderSerializer(ByteArray& byteArray); ~ShaderSerializer() = default; - void Serialize(const StatementPtr& shader); + void Serialize(const ShaderAst& shader); private: bool IsWriting() const override; - void Node(NodePtr& node) override; + void Node(const ShaderNodes::NodePtr& node); + void Node(ShaderNodes::NodePtr& node) override; void Value(bool& val) override; void Value(float& val) override; void Value(std::string& val) override; @@ -79,7 +83,7 @@ namespace Nz::ShaderNodes void Value(Vector3f& val) override; void Value(Vector4f& val) override; void Value(UInt32& val) override; - void Variable(VariablePtr& var) override; + void Variable(ShaderNodes::VariablePtr& var) override; ByteArray& m_byteArray; ByteStream m_stream; @@ -91,11 +95,11 @@ namespace Nz::ShaderNodes ShaderUnserializer(const ByteArray& byteArray); ~ShaderUnserializer() = default; - StatementPtr Unserialize(); + ShaderAst Unserialize(); private: bool IsWriting() const override; - void Node(NodePtr& node) override; + void Node(ShaderNodes::NodePtr& node) override; void Value(bool& val) override; void Value(float& val) override; void Value(std::string& val) override; @@ -103,14 +107,14 @@ namespace Nz::ShaderNodes void Value(Vector3f& val) override; void Value(Vector4f& val) override; void Value(UInt32& val) override; - void Variable(VariablePtr& var) override; + void Variable(ShaderNodes::VariablePtr& var) override; const ByteArray& m_byteArray; ByteStream m_stream; }; - NAZARA_RENDERER_API ByteArray Serialize(const StatementPtr& shader); - NAZARA_RENDERER_API StatementPtr Unserialize(const ByteArray& data); + NAZARA_RENDERER_API ByteArray SerializeShader(const ShaderAst& shader); + NAZARA_RENDERER_API ShaderAst UnserializeShader(const ByteArray& data); } #include diff --git a/include/Nazara/Renderer/ShaderSerializer.inl b/include/Nazara/Renderer/ShaderSerializer.inl index 354986bb1..a2b680b95 100644 --- a/include/Nazara/Renderer/ShaderSerializer.inl +++ b/include/Nazara/Renderer/ShaderSerializer.inl @@ -5,7 +5,7 @@ #include #include -namespace Nz::ShaderNodes +namespace Nz { template void ShaderSerializerBase::Container(T& container) @@ -36,12 +36,30 @@ namespace Nz::ShaderNodes enumVal = static_cast(value); } + template + void ShaderSerializerBase::OptVal(std::optional& optVal) + { + bool isWriting = IsWriting(); + + bool hasValue; + if (isWriting) + hasValue = optVal.has_value(); + + Value(hasValue); + + if (!isWriting && hasValue) + optVal.emplace(); + + if (optVal.has_value()) + Value(optVal.value()); + } + template void ShaderSerializerBase::Node(std::shared_ptr& node) { bool isWriting = IsWriting(); - NodePtr value; + ShaderNodes::NodePtr value; if (isWriting) value = node; @@ -55,7 +73,7 @@ namespace Nz::ShaderNodes { bool isWriting = IsWriting(); - VariablePtr value; + ShaderNodes::VariablePtr value; if (isWriting) value = var; diff --git a/src/Nazara/Renderer/GlslWriter.cpp b/src/Nazara/Renderer/GlslWriter.cpp index f32239663..8617c522e 100644 --- a/src/Nazara/Renderer/GlslWriter.cpp +++ b/src/Nazara/Renderer/GlslWriter.cpp @@ -330,9 +330,7 @@ namespace Nz Append(node.variable->name); if (node.expression) { - Append(" "); - Append("="); - Append(" "); + Append(" = "); Visit(node.expression); } diff --git a/src/Nazara/Renderer/ShaderSerializer.cpp b/src/Nazara/Renderer/ShaderSerializer.cpp index 909422f52..7d1b7ac2e 100644 --- a/src/Nazara/Renderer/ShaderSerializer.cpp +++ b/src/Nazara/Renderer/ShaderSerializer.cpp @@ -3,14 +3,18 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include +#include #include #include #include -namespace Nz::ShaderNodes +namespace Nz { namespace { + constexpr UInt32 s_magicNumber = 0x4E534852; + constexpr UInt32 s_currentVersion = 1; + class ShaderSerializerVisitor : public ShaderVisitor, public ShaderVarVisitor { public: @@ -19,62 +23,62 @@ namespace Nz::ShaderNodes { } - void Visit(const AssignOp& node) override + void Visit(const ShaderNodes::AssignOp& node) override { Serialize(node); } - void Visit(const BinaryOp& node) override + void Visit(const ShaderNodes::BinaryOp& node) override { Serialize(node); } - void Visit(const Branch& node) override + void Visit(const ShaderNodes::Branch& node) override { Serialize(node); } - void Visit(const Cast& node) override + void Visit(const ShaderNodes::Cast& node) override { Serialize(node); } - void Visit(const Constant& node) override + void Visit(const ShaderNodes::Constant& node) override { Serialize(node); } - void Visit(const DeclareVariable& node) override + void Visit(const ShaderNodes::DeclareVariable& node) override { Serialize(node); } - void Visit(const ExpressionStatement& node) override + void Visit(const ShaderNodes::ExpressionStatement& node) override { Serialize(node); } - void Visit(const Identifier& node) override + void Visit(const ShaderNodes::Identifier& node) override { Serialize(node); } - void Visit(const IntrinsicCall& node) override + void Visit(const ShaderNodes::IntrinsicCall& node) override { Serialize(node); } - void Visit(const Sample2D& node) override + void Visit(const ShaderNodes::Sample2D& node) override { Serialize(node); } - void Visit(const StatementBlock& node) override + void Visit(const ShaderNodes::StatementBlock& node) override { Serialize(node); } - void Visit(const SwizzleOp& node) override + void Visit(const ShaderNodes::SwizzleOp& node) override { Serialize(node); } @@ -122,21 +126,21 @@ namespace Nz::ShaderNodes }; } - void ShaderSerializerBase::Serialize(AssignOp& node) + void ShaderSerializerBase::Serialize(ShaderNodes::AssignOp& node) { Enum(node.op); Node(node.left); Node(node.right); } - void ShaderSerializerBase::Serialize(BinaryOp& node) + void ShaderSerializerBase::Serialize(ShaderNodes::BinaryOp& node) { Enum(node.op); Node(node.left); Node(node.right); } - void ShaderSerializerBase::Serialize(Branch& node) + void ShaderSerializerBase::Serialize(ShaderNodes::Branch& node) { Container(node.condStatements); for (auto& condStatement : node.condStatements) @@ -148,64 +152,64 @@ namespace Nz::ShaderNodes Node(node.elseStatement); } - void ShaderSerializerBase::Serialize(BuiltinVariable& node) + void ShaderSerializerBase::Serialize(ShaderNodes::BuiltinVariable& node) { Enum(node.type); Enum(node.type); } - void ShaderSerializerBase::Serialize(Cast& node) + void ShaderSerializerBase::Serialize(ShaderNodes::Cast& node) { Enum(node.exprType); for (auto& expr : node.expressions) Node(expr); } - void ShaderSerializerBase::Serialize(Constant& node) + void ShaderSerializerBase::Serialize(ShaderNodes::Constant& node) { Enum(node.exprType); switch (node.exprType) { - case ExpressionType::Boolean: + case ShaderNodes::ExpressionType::Boolean: Value(node.values.bool1); break; - case ExpressionType::Float1: + case ShaderNodes::ExpressionType::Float1: Value(node.values.vec1); break; - case ExpressionType::Float2: + case ShaderNodes::ExpressionType::Float2: Value(node.values.vec2); break; - case ExpressionType::Float3: + case ShaderNodes::ExpressionType::Float3: Value(node.values.vec3); break; - case ExpressionType::Float4: + case ShaderNodes::ExpressionType::Float4: Value(node.values.vec4); break; } } - void ShaderSerializerBase::Serialize(DeclareVariable& node) + void ShaderSerializerBase::Serialize(ShaderNodes::DeclareVariable& node) { Variable(node.variable); Node(node.expression); } - void ShaderSerializerBase::Serialize(ExpressionStatement& node) + void ShaderSerializerBase::Serialize(ShaderNodes::ExpressionStatement& node) { Node(node.expression); } - void ShaderSerializerBase::Serialize(Identifier& node) + void ShaderSerializerBase::Serialize(ShaderNodes::Identifier& node) { Variable(node.var); } - void ShaderSerializerBase::Serialize(IntrinsicCall& node) + void ShaderSerializerBase::Serialize(ShaderNodes::IntrinsicCall& node) { Enum(node.intrinsic); Container(node.parameters); @@ -213,26 +217,26 @@ namespace Nz::ShaderNodes Node(param); } - void ShaderSerializerBase::Serialize(NamedVariable& node) + void ShaderSerializerBase::Serialize(ShaderNodes::NamedVariable& node) { Value(node.name); Enum(node.type); } - void ShaderSerializerBase::Serialize(Sample2D& node) + void ShaderSerializerBase::Serialize(ShaderNodes::Sample2D& node) { Node(node.sampler); Node(node.coordinates); } - void ShaderSerializerBase::Serialize(StatementBlock& node) + void ShaderSerializerBase::Serialize(ShaderNodes::StatementBlock& node) { Container(node.statements); for (auto& statement : node.statements) Node(statement); } - void ShaderSerializerBase::Serialize(SwizzleOp& node) + void ShaderSerializerBase::Serialize(ShaderNodes::SwizzleOp& node) { Value(node.componentCount); Node(node.expression); @@ -242,13 +246,50 @@ namespace Nz::ShaderNodes } - void ShaderSerializer::Serialize(const StatementPtr& shader) + void ShaderSerializer::Serialize(const ShaderAst& shader) { - assert(shader); - m_stream << static_cast(shader->GetType()); + UInt32 magicNumber = s_magicNumber; + UInt32 version = s_currentVersion; - ShaderSerializerVisitor visitor(*this); - shader->Visit(visitor); + m_stream << s_magicNumber << s_currentVersion; + + auto SerializeInputOutput = [&](auto& inout) + { + m_stream << UInt32(inout.size()); + for (const auto& data : inout) + { + m_stream << data.name << UInt32(data.type); + + m_stream << data.locationIndex.has_value(); + if (data.locationIndex) + m_stream << UInt32(data.locationIndex.value()); + } + }; + + SerializeInputOutput(shader.GetInputs()); + SerializeInputOutput(shader.GetOutputs()); + + m_stream << UInt32(shader.GetUniformCount()); + for (const auto& uniform : shader.GetUniforms()) + { + m_stream << uniform.name << UInt32(uniform.type); + + m_stream << uniform.bindingIndex.has_value(); + if (uniform.bindingIndex) + m_stream << UInt32(uniform.bindingIndex.value()); + } + + m_stream << UInt32(shader.GetFunctionCount()); + for (const auto& func : shader.GetFunctions()) + { + m_stream << func.name << UInt32(func.returnType); + + m_stream << UInt32(func.parameters.size()); + for (const auto& param : func.parameters) + m_stream << param.name << UInt32(param.type); + + Node(func.statement); + } m_stream.FlushBits(); } @@ -258,9 +299,9 @@ namespace Nz::ShaderNodes return true; } - void ShaderSerializer::Node(NodePtr& node) + void ShaderSerializer::Node(ShaderNodes::NodePtr& node) { - NodeType nodeType = (node) ? node->GetType() : NodeType::None; + ShaderNodes::NodeType nodeType = (node) ? node->GetType() : ShaderNodes::NodeType::None; m_stream << static_cast(nodeType); if (node) @@ -270,6 +311,11 @@ namespace Nz::ShaderNodes } } + void ShaderSerializer::Node(const ShaderNodes::NodePtr& node) + { + Node(const_cast(node)); //< Yes const_cast is ugly but it won't be used for writing + } + void ShaderSerializer::Value(bool& val) { m_stream << val; @@ -305,9 +351,9 @@ namespace Nz::ShaderNodes m_stream << val; } - void ShaderSerializer::Variable(VariablePtr& var) + void ShaderSerializer::Variable(ShaderNodes::VariablePtr& var) { - VariableType nodeType = (var) ? var->GetType() : VariableType::None; + ShaderNodes::VariableType nodeType = (var) ? var->GetType() : ShaderNodes::VariableType::None; m_stream << static_cast(nodeType); if (var) @@ -317,29 +363,93 @@ namespace Nz::ShaderNodes } } - ByteArray Serialize(const StatementPtr& shader) + ShaderAst ShaderUnserializer::Unserialize() { - ByteArray byteArray; - ShaderSerializer serializer(byteArray); - serializer.Serialize(shader); + UInt32 magicNumber; + UInt32 version; + m_stream >> magicNumber; + if (magicNumber != s_magicNumber) + throw std::runtime_error("invalid shader file"); - return byteArray; - } + m_stream >> version; + if (version > s_currentVersion) + throw std::runtime_error("unsupported version"); - StatementPtr Unserialize(const ByteArray& data) - { - ShaderUnserializer unserializer(data); - return unserializer.Unserialize(); - } + ShaderAst shader; - StatementPtr ShaderUnserializer::Unserialize() - { - NodePtr statement; - Node(statement); - if (!statement || statement->GetType() != NodeType::StatementBlock) - throw std::runtime_error("Invalid shader"); + UInt32 inputCount; + m_stream >> inputCount; + for (UInt32 i = 0; i < inputCount; ++i) + { + std::string inputName; + ShaderNodes::ExpressionType inputType; + std::optional location; - return std::static_pointer_cast(statement); + Value(inputName); + Enum(inputType); + OptVal(location); + + shader.AddInput(std::move(inputName), inputType, location); + } + + UInt32 outputCount; + m_stream >> outputCount; + for (UInt32 i = 0; i < outputCount; ++i) + { + std::string outputName; + ShaderNodes::ExpressionType outputType; + std::optional location; + + Value(outputName); + Enum(outputType); + OptVal(location); + + shader.AddOutput(std::move(outputName), outputType, location); + } + + UInt32 uniformCount; + m_stream >> uniformCount; + for (UInt32 i = 0; i < uniformCount; ++i) + { + std::string name; + ShaderNodes::ExpressionType type; + std::optional binding; + + Value(name); + Enum(type); + OptVal(binding); + + shader.AddUniform(std::move(name), type, binding); + } + + UInt32 funcCount; + m_stream >> funcCount; + for (UInt32 i = 0; i < funcCount; ++i) + { + std::string name; + ShaderNodes::ExpressionType retType; + std::vector parameters; + + Value(name); + Enum(retType); + Container(parameters); + for (auto& param : parameters) + { + Value(param.name); + Enum(param.type); + } + + ShaderNodes::NodePtr node; + Node(node); + if (!node || !node->IsStatement()) + throw std::runtime_error("functions can only have statements"); + + ShaderNodes::StatementPtr statement = std::static_pointer_cast(node); + + shader.AddFunction(std::move(name), std::move(statement), std::move(parameters), retType); + } + + return shader; } bool ShaderUnserializer::IsWriting() const @@ -347,17 +457,17 @@ namespace Nz::ShaderNodes return false; } - void ShaderUnserializer::Node(NodePtr& node) + void ShaderUnserializer::Node(ShaderNodes::NodePtr& node) { Int32 nodeTypeInt; m_stream >> nodeTypeInt; - NodeType nodeType = static_cast(nodeTypeInt); + ShaderNodes::NodeType nodeType = static_cast(nodeTypeInt); -#define HandleType(Type) case NodeType:: Type : node = std::make_shared(); break +#define HandleType(Type) case ShaderNodes::NodeType:: Type : node = std::make_shared(); break switch (nodeType) { - case NodeType::None: break; + case ShaderNodes::NodeType::None: break; HandleType(AssignOp); HandleType(BinaryOp); @@ -417,17 +527,17 @@ namespace Nz::ShaderNodes m_stream >> val; } - void ShaderUnserializer::Variable(VariablePtr& var) + void ShaderUnserializer::Variable(ShaderNodes::VariablePtr& var) { Int32 nodeTypeInt; m_stream >> nodeTypeInt; - VariableType nodeType = static_cast(nodeTypeInt); + ShaderNodes::VariableType nodeType = static_cast(nodeTypeInt); -#define HandleType(Type) case VariableType:: Type : var = std::make_shared(); break +#define HandleType(Type) case ShaderNodes::VariableType:: Type : var = std::make_shared(); break switch (nodeType) { - case VariableType::None: break; + case ShaderNodes::VariableType::None: break; HandleType(BuiltinVariable); HandleType(InputVariable); @@ -443,5 +553,21 @@ namespace Nz::ShaderNodes var->Visit(visitor); } } + + + ByteArray SerializeShader(const ShaderAst& shader) + { + ByteArray byteArray; + ShaderSerializer serializer(byteArray); + serializer.Serialize(shader); + + return byteArray; + } + + ShaderAst UnserializeShader(const ByteArray& data) + { + ShaderUnserializer unserializer(data); + return unserializer.Unserialize(); + } } diff --git a/src/ShaderNode/Widgets/MainWindow.cpp b/src/ShaderNode/Widgets/MainWindow.cpp index c59a59254..7f39eafc3 100644 --- a/src/ShaderNode/Widgets/MainWindow.cpp +++ b/src/ShaderNode/Widgets/MainWindow.cpp @@ -103,9 +103,6 @@ void MainWindow::OnCompileToGLSL() { Nz::ShaderNodes::StatementPtr shaderAst = m_shaderGraph.ToAst(); - Nz::File file("shader.shader", Nz::OpenMode_WriteOnly); - file.Write(Nz::ShaderNodes::Serialize(shaderAst)); - //TODO: Put in another function auto GetExpressionFromInOut = [&] (InOutType type) { @@ -145,6 +142,9 @@ void MainWindow::OnCompileToGLSL() shader.AddFunction("main", shaderAst); + Nz::File file("shader.shader", Nz::OpenMode_WriteOnly); + file.Write(Nz::SerializeShader(shader)); + Nz::GlslWriter writer; Nz::String glsl = writer.Generate(shader); From 66a98b234ff1cf2412730a5552bec90d15255d19 Mon Sep 17 00:00:00 2001 From: Lynix Date: Thu, 18 Jun 2020 20:03:22 +0200 Subject: [PATCH 042/105] Renderer/GlslWriter: Add environment --- include/Nazara/Renderer/GlslWriter.hpp | 15 +++++- src/Nazara/Renderer/GlslWriter.cpp | 73 +++++++++++++++++++++----- 2 files changed, 73 insertions(+), 15 deletions(-) diff --git a/include/Nazara/Renderer/GlslWriter.hpp b/include/Nazara/Renderer/GlslWriter.hpp index 22d6544f2..e0f9bf11e 100644 --- a/include/Nazara/Renderer/GlslWriter.hpp +++ b/include/Nazara/Renderer/GlslWriter.hpp @@ -23,6 +23,9 @@ namespace Nz class NAZARA_RENDERER_API GlslWriter : public ShaderWriter, public ShaderVarVisitor, public ShaderVisitor { public: + struct Environment; + using ExtSupportCallback = std::function; + GlslWriter(); GlslWriter(const GlslWriter&) = delete; GlslWriter(GlslWriter&&) = delete; @@ -30,7 +33,15 @@ namespace Nz std::string Generate(const ShaderAst& shader) override; - void SetGlslVersion(unsigned int version); + void SetEnv(Environment environment); + + struct Environment + { + ExtSupportCallback extCallback; + unsigned int glMajorVersion = 3; + unsigned int glMinorVersion = 0; + bool glES = false; + }; private: void Append(ShaderNodes::BuiltinEntry builtin); @@ -82,8 +93,8 @@ namespace Nz }; Context m_context; + Environment m_environment; State* m_currentState; - unsigned int m_glslVersion; }; } diff --git a/src/Nazara/Renderer/GlslWriter.cpp b/src/Nazara/Renderer/GlslWriter.cpp index 8617c522e..b60083f6f 100644 --- a/src/Nazara/Renderer/GlslWriter.cpp +++ b/src/Nazara/Renderer/GlslWriter.cpp @@ -11,8 +11,7 @@ namespace Nz { GlslWriter::GlslWriter() : - m_currentState(nullptr), - m_glslVersion(110) + m_currentState(nullptr) { } @@ -29,22 +28,67 @@ namespace Nz m_currentState = nullptr; }); + unsigned int glslVersion; + if (m_environment.glES) + { + if (m_environment.glMajorVersion >= 3 && m_environment.glMinorVersion >= 2) + glslVersion = 320; + else if (m_environment.glMajorVersion >= 3 && m_environment.glMinorVersion >= 1) + glslVersion = 310; + else if (m_environment.glMajorVersion >= 3 && m_environment.glMinorVersion >= 0) + glslVersion = 300; + else if (m_environment.glMajorVersion >= 2 && m_environment.glMinorVersion >= 0) + glslVersion = 100; + else + throw std::runtime_error("This version of OpenGL ES does not support shaders"); + } + else + { + if (m_environment.glMajorVersion >= 3 && m_environment.glMinorVersion >= 3) + glslVersion = m_environment.glMajorVersion * 100 + m_environment.glMinorVersion * 10; + else if (m_environment.glMajorVersion >= 3 && m_environment.glMinorVersion >= 2) + glslVersion = 150; + else if (m_environment.glMajorVersion >= 3 && m_environment.glMinorVersion >= 1) + glslVersion = 140; + else if (m_environment.glMajorVersion >= 3 && m_environment.glMinorVersion >= 0) + glslVersion = 130; + else if (m_environment.glMajorVersion >= 2 && m_environment.glMinorVersion >= 1) + glslVersion = 120; + else if (m_environment.glMajorVersion >= 2 && m_environment.glMinorVersion >= 0) + glslVersion = 110; + else + throw std::runtime_error("This version of OpenGL does not support shaders"); + } + // Header Append("#version "); - AppendLine(std::to_string(m_glslVersion)); + Append(glslVersion); + if (m_environment.glES) + Append(" es"); + + AppendLine(); AppendLine(); // Extensions std::vector requiredExtensions; - // GL_ARB_shading_language_420pack (required for layout(binding = X)) - if (m_glslVersion < 420 && HasExplicitBinding(shader)) - requiredExtensions.emplace_back("GL_ARB_shading_language_420pack"); + if (!m_environment.glES && m_environment.extCallback) + { + // GL_ARB_shading_language_420pack (required for layout(binding = X)) + if (glslVersion < 420 && HasExplicitBinding(shader)) + { + if (m_environment.extCallback("GL_ARB_shading_language_420pack")) + requiredExtensions.emplace_back("GL_ARB_shading_language_420pack"); + } - // GL_ARB_explicit_uniform_location (required for layout(location = X)) - if (m_glslVersion < 430 && HasExplicitLocation(shader)) - requiredExtensions.emplace_back("GL_ARB_explicit_uniform_location"); + // GL_ARB_separate_shader_objects (required for layout(location = X)) + if (glslVersion < 410 && HasExplicitLocation(shader)) + { + if (m_environment.extCallback("GL_ARB_separate_shader_objects")) + requiredExtensions.emplace_back("GL_ARB_separate_shader_objects"); + } + } if (!requiredExtensions.empty()) { @@ -55,9 +99,12 @@ namespace Nz } // Global variables (uniforms, input and outputs) + const char* inKeyword = (glslVersion >= 130) ? "in" : "varying"; + const char* outKeyword = (glslVersion >= 130) ? "out" : "varying"; + DeclareVariables(shader.GetUniforms(), "uniform", "Uniforms"); - DeclareVariables(shader.GetInputs(), "in", "Inputs"); - DeclareVariables(shader.GetOutputs(), "out", "Outputs"); + DeclareVariables(shader.GetInputs(), inKeyword, "Inputs"); + DeclareVariables(shader.GetOutputs(), outKeyword, "Outputs"); std::size_t functionCount = shader.GetFunctionCount(); if (functionCount > 1) @@ -79,9 +126,9 @@ namespace Nz return state.stream.str(); } - void GlslWriter::SetGlslVersion(unsigned int version) + void GlslWriter::SetEnv(Environment environment) { - m_glslVersion = version; + m_environment = std::move(environment); } void GlslWriter::Append(ShaderNodes::BuiltinEntry builtin) From bc490a2fe504f29a3dbcff04800f2d2e2682c513 Mon Sep 17 00:00:00 2001 From: Lynix Date: Thu, 18 Jun 2020 20:03:33 +0200 Subject: [PATCH 043/105] Renderer/GlslWriter: Fix double identifier bug --- src/Nazara/Renderer/GlslWriter.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Nazara/Renderer/GlslWriter.cpp b/src/Nazara/Renderer/GlslWriter.cpp index b60083f6f..9116aa3a3 100644 --- a/src/Nazara/Renderer/GlslWriter.cpp +++ b/src/Nazara/Renderer/GlslWriter.cpp @@ -420,8 +420,6 @@ namespace Nz Append(", "); Visit(node.parameters[i]); - Append(" "); - Visit(node.parameters[i]); } Append(")"); } From 691de5b5c421e8506d0fc6ced88df6d159fafd07 Mon Sep 17 00:00:00 2001 From: Lynix Date: Thu, 18 Jun 2020 20:03:56 +0200 Subject: [PATCH 044/105] Renderer/ShaderSerialize: Use ByteStream instead of ByteArray --- include/Nazara/Renderer/ShaderSerializer.hpp | 12 +++++------- include/Nazara/Renderer/ShaderSerializer.inl | 10 ++++------ src/Nazara/Renderer/ShaderSerializer.cpp | 11 +++++------ 3 files changed, 14 insertions(+), 19 deletions(-) diff --git a/include/Nazara/Renderer/ShaderSerializer.hpp b/include/Nazara/Renderer/ShaderSerializer.hpp index a5e012a9c..eac0c2bf8 100644 --- a/include/Nazara/Renderer/ShaderSerializer.hpp +++ b/include/Nazara/Renderer/ShaderSerializer.hpp @@ -67,7 +67,7 @@ namespace Nz class NAZARA_RENDERER_API ShaderSerializer final : public ShaderSerializerBase { public: - inline ShaderSerializer(ByteArray& byteArray); + inline ShaderSerializer(ByteStream& stream); ~ShaderSerializer() = default; void Serialize(const ShaderAst& shader); @@ -85,14 +85,13 @@ namespace Nz void Value(UInt32& val) override; void Variable(ShaderNodes::VariablePtr& var) override; - ByteArray& m_byteArray; - ByteStream m_stream; + ByteStream& m_stream; }; class NAZARA_RENDERER_API ShaderUnserializer final : public ShaderSerializerBase { public: - ShaderUnserializer(const ByteArray& byteArray); + ShaderUnserializer(ByteStream& stream); ~ShaderUnserializer() = default; ShaderAst Unserialize(); @@ -109,12 +108,11 @@ namespace Nz void Value(UInt32& val) override; void Variable(ShaderNodes::VariablePtr& var) override; - const ByteArray& m_byteArray; - ByteStream m_stream; + ByteStream& m_stream; }; NAZARA_RENDERER_API ByteArray SerializeShader(const ShaderAst& shader); - NAZARA_RENDERER_API ShaderAst UnserializeShader(const ByteArray& data); + NAZARA_RENDERER_API ShaderAst UnserializeShader(ByteStream& stream); } #include diff --git a/include/Nazara/Renderer/ShaderSerializer.inl b/include/Nazara/Renderer/ShaderSerializer.inl index a2b680b95..0daeb6653 100644 --- a/include/Nazara/Renderer/ShaderSerializer.inl +++ b/include/Nazara/Renderer/ShaderSerializer.inl @@ -95,15 +95,13 @@ namespace Nz val = static_cast(value); } - inline ShaderSerializer::ShaderSerializer(ByteArray& byteArray) : - m_byteArray(byteArray), - m_stream(&m_byteArray, OpenModeFlags(OpenMode_WriteOnly)) + inline ShaderSerializer::ShaderSerializer(ByteStream& stream) : + m_stream(stream) { } - inline ShaderUnserializer::ShaderUnserializer(const ByteArray& byteArray) : - m_byteArray(byteArray), - m_stream(const_cast(&m_byteArray), OpenModeFlags(OpenMode_ReadOnly)) + inline ShaderUnserializer::ShaderUnserializer(ByteStream& stream) : + m_stream(stream) { } } diff --git a/src/Nazara/Renderer/ShaderSerializer.cpp b/src/Nazara/Renderer/ShaderSerializer.cpp index 7d1b7ac2e..f97186acf 100644 --- a/src/Nazara/Renderer/ShaderSerializer.cpp +++ b/src/Nazara/Renderer/ShaderSerializer.cpp @@ -248,9 +248,6 @@ namespace Nz void ShaderSerializer::Serialize(const ShaderAst& shader) { - UInt32 magicNumber = s_magicNumber; - UInt32 version = s_currentVersion; - m_stream << s_magicNumber << s_currentVersion; auto SerializeInputOutput = [&](auto& inout) @@ -558,15 +555,17 @@ namespace Nz ByteArray SerializeShader(const ShaderAst& shader) { ByteArray byteArray; - ShaderSerializer serializer(byteArray); + ByteStream stream(&byteArray, OpenModeFlags(OpenMode_WriteOnly)); + + ShaderSerializer serializer(stream); serializer.Serialize(shader); return byteArray; } - ShaderAst UnserializeShader(const ByteArray& data) + ShaderAst UnserializeShader(ByteStream& stream) { - ShaderUnserializer unserializer(data); + ShaderUnserializer unserializer(stream); return unserializer.Unserialize(); } } From 74acf440fc76d744fb4fd9b3c4efb2576db45e19 Mon Sep 17 00:00:00 2001 From: Lynix Date: Thu, 18 Jun 2020 20:04:25 +0200 Subject: [PATCH 045/105] Minor fixes --- include/Nazara/OpenGLRenderer/Wrapper/Shader.inl | 4 ++-- src/Nazara/OpenGLRenderer/OpenGLRenderImage.cpp | 2 +- src/ShaderNode/Widgets/InputEditor.cpp | 1 + src/ShaderNode/Widgets/OutputEditor.cpp | 9 ++++----- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/include/Nazara/OpenGLRenderer/Wrapper/Shader.inl b/include/Nazara/OpenGLRenderer/Wrapper/Shader.inl index fe062149f..f73421706 100644 --- a/include/Nazara/OpenGLRenderer/Wrapper/Shader.inl +++ b/include/Nazara/OpenGLRenderer/Wrapper/Shader.inl @@ -68,12 +68,12 @@ namespace Nz::GL context.glSpecializeShaderARB(m_objectId, pEntryPoint, numSpecializationConstants, pConstantIndex, pConstantValue); } - inline GLuint Shader::CreateHelper(OpenGLDevice& device, const Context& context, GLenum shaderStage) + inline GLuint Shader::CreateHelper(OpenGLDevice& /*device*/, const Context& context, GLenum shaderStage) { return context.glCreateShader(shaderStage); } - inline void Shader::DestroyHelper(OpenGLDevice& device, const Context& context, GLuint objectId) + inline void Shader::DestroyHelper(OpenGLDevice& /*device*/, const Context& context, GLuint objectId) { context.glDeleteShader(objectId); } diff --git a/src/Nazara/OpenGLRenderer/OpenGLRenderImage.cpp b/src/Nazara/OpenGLRenderer/OpenGLRenderImage.cpp index 34946874b..39c2be6dd 100644 --- a/src/Nazara/OpenGLRenderer/OpenGLRenderImage.cpp +++ b/src/Nazara/OpenGLRenderer/OpenGLRenderImage.cpp @@ -17,7 +17,7 @@ namespace Nz { } - void OpenGLRenderImage::Execute(const std::function& callback, QueueTypeFlags queueTypeFlags) + void OpenGLRenderImage::Execute(const std::function& callback, QueueTypeFlags /*queueTypeFlags*/) { OpenGLCommandBuffer commandBuffer; OpenGLCommandBufferBuilder builder(commandBuffer); diff --git a/src/ShaderNode/Widgets/InputEditor.cpp b/src/ShaderNode/Widgets/InputEditor.cpp index f281c327a..7898c3c27 100644 --- a/src/ShaderNode/Widgets/InputEditor.cpp +++ b/src/ShaderNode/Widgets/InputEditor.cpp @@ -50,6 +50,7 @@ void InputEditor::OnEditInput(int inputIndex) const auto& input = m_shaderGraph.GetInput(inputIndex); InputInfo info; + info.locationIndex = input.locationIndex; info.name = input.name; info.type = input.type; info.role = input.role; diff --git a/src/ShaderNode/Widgets/OutputEditor.cpp b/src/ShaderNode/Widgets/OutputEditor.cpp index 868168c8a..40b8eea49 100644 --- a/src/ShaderNode/Widgets/OutputEditor.cpp +++ b/src/ShaderNode/Widgets/OutputEditor.cpp @@ -47,11 +47,12 @@ void OutputEditor::OnAddOutput() void OutputEditor::OnEditOutput(int inputIndex) { - const auto& input = m_shaderGraph.GetOutput(inputIndex); + const auto& output = m_shaderGraph.GetOutput(inputIndex); OutputInfo info; - info.name = input.name; - info.type = input.type; + info.locationIndex = output.locationIndex; + info.name = output.name; + info.type = output.type; OutputEditDialog* dialog = new OutputEditDialog(std::move(info), this); dialog->setAttribute(Qt::WA_DeleteOnClose, true); @@ -67,9 +68,7 @@ void OutputEditor::OnEditOutput(int inputIndex) void OutputEditor::OnOutputSelectionUpdate(int inputIndex) { if (inputIndex >= 0) - { m_currentOutputIndex = inputIndex; - } else m_currentOutputIndex.reset(); } From 58e59be267f706d6957e56f71175f770a972c551 Mon Sep 17 00:00:00 2001 From: Lynix Date: Thu, 18 Jun 2020 20:04:39 +0200 Subject: [PATCH 046/105] ShaderNode: Add compile to binary action --- src/ShaderNode/Widgets/MainWindow.cpp | 142 +++++++++++++++----------- src/ShaderNode/Widgets/MainWindow.hpp | 9 +- 2 files changed, 92 insertions(+), 59 deletions(-) diff --git a/src/ShaderNode/Widgets/MainWindow.cpp b/src/ShaderNode/Widgets/MainWindow.cpp index 7f39eafc3..e76946738 100644 --- a/src/ShaderNode/Widgets/MainWindow.cpp +++ b/src/ShaderNode/Widgets/MainWindow.cpp @@ -90,72 +90,30 @@ void MainWindow::BuildMenu() QObject::connect(loadShader, &QAction::triggered, this, &MainWindow::OnLoad); QAction* saveShader = shader->addAction(tr("Save...")); QObject::connect(saveShader, &QAction::triggered, this, &MainWindow::OnSave); + QAction* compileShader = shader->addAction(tr("Compile...")); + QObject::connect(compileShader, &QAction::triggered, this, &MainWindow::OnCompile); } - QMenu* compileMenu = menu->addMenu(tr("&Compilation")); - QAction* compileToGlsl = compileMenu->addAction(tr("GLSL")); - connect(compileToGlsl, &QAction::triggered, [&](bool) { OnCompileToGLSL(); }); + QMenu* generateMenu = menu->addMenu(tr("&Generate")); + QAction* generateGlsl = generateMenu->addAction(tr("GLSL")); + connect(generateGlsl, &QAction::triggered, [&](bool) { OnGenerateGLSL(); }); } -void MainWindow::OnCompileToGLSL() +void MainWindow::OnCompile() { try { - Nz::ShaderNodes::StatementPtr shaderAst = m_shaderGraph.ToAst(); + auto shader = ToShader(); - //TODO: Put in another function - auto GetExpressionFromInOut = [&] (InOutType type) - { - switch (type) - { - case InOutType::Bool: return Nz::ShaderNodes::ExpressionType::Boolean; - case InOutType::Float1: return Nz::ShaderNodes::ExpressionType::Float1; - case InOutType::Float2: return Nz::ShaderNodes::ExpressionType::Float2; - case InOutType::Float3: return Nz::ShaderNodes::ExpressionType::Float3; - case InOutType::Float4: return Nz::ShaderNodes::ExpressionType::Float4; - } + QString fileName = QFileDialog::getSaveFileName(nullptr, tr("Save shader"), QString(), tr("Shader Files (*.shader)")); + if (fileName.isEmpty()) + return; - assert(false); - throw std::runtime_error("Unhandled input type"); - }; + if (!fileName.endsWith("shader", Qt::CaseInsensitive)) + fileName += ".shader"; - auto GetExpressionFromTexture = [&](TextureType type) - { - switch (type) - { - case TextureType::Sampler2D: return Nz::ShaderNodes::ExpressionType::Sampler2D; - } - - assert(false); - throw std::runtime_error("Unhandled texture type"); - }; - - Nz::ShaderAst shader; - for (const auto& input : m_shaderGraph.GetInputs()) - shader.AddInput(input.name, GetExpressionFromInOut(input.type), input.locationIndex); - - for (const auto& output : m_shaderGraph.GetOutputs()) - shader.AddOutput(output.name, GetExpressionFromInOut(output.type), output.locationIndex); - - for (const auto& uniform : m_shaderGraph.GetTextures()) - shader.AddUniform(uniform.name, GetExpressionFromTexture(uniform.type), uniform.bindingIndex); - - shader.AddFunction("main", shaderAst); - - Nz::File file("shader.shader", Nz::OpenMode_WriteOnly); + Nz::File file(fileName.toStdString(), Nz::OpenMode_WriteOnly); file.Write(Nz::SerializeShader(shader)); - - Nz::GlslWriter writer; - Nz::String glsl = writer.Generate(shader); - - std::cout << glsl << std::endl; - - QTextEdit* output = new QTextEdit; - output->setReadOnly(true); - output->setText(QString::fromUtf8(glsl.GetConstBuffer(), int(glsl.GetSize()))); - output->setAttribute(Qt::WA_DeleteOnClose, true); - output->setWindowTitle("GLSL Output"); - output->show(); } catch (const std::exception& e) { @@ -163,9 +121,31 @@ void MainWindow::OnCompileToGLSL() } } +void MainWindow::OnGenerateGLSL() +{ + try + { + Nz::GlslWriter writer; + std::string glsl = writer.Generate(ToShader()); + + std::cout << glsl << std::endl; + + QTextEdit* output = new QTextEdit; + output->setReadOnly(true); + output->setText(QString::fromStdString(glsl)); + output->setAttribute(Qt::WA_DeleteOnClose, true); + output->setWindowTitle("GLSL Output"); + output->show(); + } + catch (const std::exception& e) + { + QMessageBox::critical(this, tr("Generation failed"), QString("Generation failed: ") + e.what()); + } +} + void MainWindow::OnLoad() { - QString fileName = QFileDialog::getOpenFileName(this, tr("Open shader flow"), QDir::homePath(), tr("Shader Flow Files (*.shaderflow)")); + QString fileName = QFileDialog::getOpenFileName(this, tr("Open shader flow"), QString(), tr("Shader Flow Files (*.shaderflow)")); if (fileName.isEmpty()) return; @@ -196,14 +176,60 @@ void MainWindow::OnLoad() void MainWindow::OnSave() { - QString fileName = QFileDialog::getSaveFileName(nullptr, tr("Open shader flow"), QDir::homePath(), tr("Shader Flow Files (*.shaderflow)")); + QString fileName = QFileDialog::getSaveFileName(nullptr, tr("Open shader flow"), QString(), tr("Shader Flow Files (*.shaderflow)")); if (fileName.isEmpty()) return; - if (!fileName.endsWith("flow", Qt::CaseInsensitive)) + if (!fileName.endsWith("shaderflow", Qt::CaseInsensitive)) fileName += ".shaderflow"; QFile file(fileName); if (file.open(QIODevice::WriteOnly)) file.write(QJsonDocument(m_shaderGraph.Save()).toJson()); } + +Nz::ShaderAst MainWindow::ToShader() +{ + Nz::ShaderNodes::StatementPtr shaderAst = m_shaderGraph.ToAst(); + + //TODO: Put in another function + auto GetExpressionFromInOut = [&](InOutType type) + { + switch (type) + { + case InOutType::Bool: return Nz::ShaderNodes::ExpressionType::Boolean; + case InOutType::Float1: return Nz::ShaderNodes::ExpressionType::Float1; + case InOutType::Float2: return Nz::ShaderNodes::ExpressionType::Float2; + case InOutType::Float3: return Nz::ShaderNodes::ExpressionType::Float3; + case InOutType::Float4: return Nz::ShaderNodes::ExpressionType::Float4; + } + + assert(false); + throw std::runtime_error("Unhandled input type"); + }; + + auto GetExpressionFromTexture = [&](TextureType type) + { + switch (type) + { + case TextureType::Sampler2D: return Nz::ShaderNodes::ExpressionType::Sampler2D; + } + + assert(false); + throw std::runtime_error("Unhandled texture type"); + }; + + Nz::ShaderAst shader; + for (const auto& input : m_shaderGraph.GetInputs()) + shader.AddInput(input.name, GetExpressionFromInOut(input.type), input.locationIndex); + + for (const auto& output : m_shaderGraph.GetOutputs()) + shader.AddOutput(output.name, GetExpressionFromInOut(output.type), output.locationIndex); + + for (const auto& uniform : m_shaderGraph.GetTextures()) + shader.AddUniform(uniform.name, GetExpressionFromTexture(uniform.type), uniform.bindingIndex); + + shader.AddFunction("main", shaderAst); + + return shader; +} diff --git a/src/ShaderNode/Widgets/MainWindow.hpp b/src/ShaderNode/Widgets/MainWindow.hpp index ff8b307c1..25c742625 100644 --- a/src/ShaderNode/Widgets/MainWindow.hpp +++ b/src/ShaderNode/Widgets/MainWindow.hpp @@ -9,6 +9,11 @@ class NodeEditor; +namespace Nz +{ + class ShaderAst; +} + class MainWindow : public QMainWindow { public: @@ -17,9 +22,11 @@ class MainWindow : public QMainWindow private: void BuildMenu(); - void OnCompileToGLSL(); + void OnCompile(); + void OnGenerateGLSL(); void OnLoad(); void OnSave(); + Nz::ShaderAst ToShader(); NazaraSlot(ShaderGraph, OnSelectedNodeUpdate, m_onSelectedNodeUpdate); From 4f671873c1019f137aeed6f7d41b2dd29f0ef6a4 Mon Sep 17 00:00:00 2001 From: Lynix Date: Thu, 18 Jun 2020 20:05:22 +0200 Subject: [PATCH 047/105] Renderer: Add NazaraBinary shader "language" and handle it in OpenGLRenderer --- examples/VulkanTest/main.cpp | 4 +-- examples/bin/shader.shader | Bin 0 -> 510 bytes include/Nazara/Renderer/Enums.hpp | 1 + .../OpenGLRenderer/OpenGLShaderStage.cpp | 32 ++++++++++++++++++ 4 files changed, 35 insertions(+), 2 deletions(-) create mode 100644 examples/bin/shader.shader diff --git a/examples/VulkanTest/main.cpp b/examples/VulkanTest/main.cpp index bfda1e2b2..e42aa41ac 100644 --- a/examples/VulkanTest/main.cpp +++ b/examples/VulkanTest/main.cpp @@ -3,7 +3,7 @@ #include #include -#define SPIRV 1 +#define SPIRV 0 int main() { @@ -44,7 +44,7 @@ int main() return __LINE__; } #else - auto fragmentShader = device->InstantiateShaderStage(Nz::ShaderStageType::Fragment, Nz::ShaderLanguage::GLSL, "resources/shaders/triangle.frag"); + auto fragmentShader = device->InstantiateShaderStage(Nz::ShaderStageType::Fragment, Nz::ShaderLanguage::NazaraBinary, "shader.shader"); if (!fragmentShader) { std::cout << "Failed to instantiate fragment shader" << std::endl; diff --git a/examples/bin/shader.shader b/examples/bin/shader.shader new file mode 100644 index 0000000000000000000000000000000000000000..7828e1b47f93c3a2edd5b8979ee976e5aac39742 GIT binary patch literal 510 zcmah_%L>9U5KJGo)%J6|_n;I{J@~o@ZEK)yptj)AKl7)&itdCgXcb%-Cd^J|lg&4) zwGhG~xP(Zxx$YWS)7gWF@>RRr6T1)?i5~i_lhs1kx`T<`;BZ@9`k^c681MzK-$>P> zPe3IEpAZnt_*zw`eyI@X*&bNj=8trp8P$ literal 0 HcmV?d00001 diff --git a/include/Nazara/Renderer/Enums.hpp b/include/Nazara/Renderer/Enums.hpp index a9b33ba5f..05daee7a5 100644 --- a/include/Nazara/Renderer/Enums.hpp +++ b/include/Nazara/Renderer/Enums.hpp @@ -49,6 +49,7 @@ namespace Nz GLSL, HLSL, MSL, + NazaraBinary, SpirV }; diff --git a/src/Nazara/OpenGLRenderer/OpenGLShaderStage.cpp b/src/Nazara/OpenGLRenderer/OpenGLShaderStage.cpp index 3364e4f11..561a1d196 100644 --- a/src/Nazara/OpenGLRenderer/OpenGLShaderStage.cpp +++ b/src/Nazara/OpenGLRenderer/OpenGLShaderStage.cpp @@ -4,7 +4,11 @@ #include #include +#include #include +#include +#include +#include #include #include @@ -22,6 +26,34 @@ namespace Nz m_shader.Compile(); break; + case ShaderLanguage::NazaraBinary: + { + ByteStream byteStream(source, sourceSize); + auto shader = Nz::UnserializeShader(byteStream); + + const auto& context = device.GetReferenceContext(); + const auto& contextParams = context.GetParams(); + + GlslWriter::Environment env; + env.glES = false; + //env.glES = (contextParams.type == GL::ContextType::OpenGL_ES); + env.glMajorVersion = contextParams.glMajorVersion; + env.glMinorVersion = contextParams.glMinorVersion; + env.extCallback = [&](const std::string_view& ext) + { + return context.IsExtensionSupported(std::string(ext)); + }; + + GlslWriter writer; + writer.SetEnv(env); + + std::string code = writer.Generate(shader); + + m_shader.SetSource(code.data(), code.size()); + m_shader.Compile(); + break; + } + case ShaderLanguage::SpirV: { if (!device.GetReferenceContext().IsExtensionSupported(GL::Extension::SpirV)) From 33d94c05f3db230e5b0766f8903ba03316c60600 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Fri, 3 Jul 2020 22:53:00 +0200 Subject: [PATCH 048/105] ShaderNodes: Use PreviewValues instead of QImage --- src/ShaderNode/DataModels/Cast.inl | 39 ++++----- src/ShaderNode/DataModels/FloatValue.cpp | 2 +- src/ShaderNode/DataModels/InputValue.cpp | 4 +- src/ShaderNode/DataModels/OutputValue.cpp | 2 +- src/ShaderNode/DataModels/SampleTexture.cpp | 52 ++++------- src/ShaderNode/DataModels/TextureValue.cpp | 13 ++- src/ShaderNode/DataModels/VecBinOp.cpp | 46 ++-------- src/ShaderNode/DataModels/VecBinOp.hpp | 10 +-- src/ShaderNode/DataModels/VecBinOp.inl | 32 +++---- src/ShaderNode/DataModels/VecDot.cpp | 48 +++++------ src/ShaderNode/DataModels/VecFloatMul.cpp | 45 +++++----- src/ShaderNode/DataModels/VecValue.inl | 10 ++- src/ShaderNode/DataTypes/FloatData.hpp | 4 +- src/ShaderNode/DataTypes/FloatData.inl | 4 +- src/ShaderNode/DataTypes/TextureData.hpp | 4 +- src/ShaderNode/DataTypes/TextureData.inl | 4 +- src/ShaderNode/DataTypes/VecData.hpp | 4 +- src/ShaderNode/DataTypes/VecData.inl | 4 +- src/ShaderNode/Previews/PreviewModel.hpp | 4 +- src/ShaderNode/Previews/PreviewValues.cpp | 95 +++++++++++++++++++++ src/ShaderNode/Previews/PreviewValues.hpp | 50 +++++++++++ src/ShaderNode/Previews/PreviewValues.inl | 21 +++++ src/ShaderNode/Previews/QuadPreview.cpp | 17 ++-- src/ShaderNode/Previews/QuadPreview.hpp | 4 +- 24 files changed, 314 insertions(+), 204 deletions(-) create mode 100644 src/ShaderNode/Previews/PreviewValues.cpp create mode 100644 src/ShaderNode/Previews/PreviewValues.hpp create mode 100644 src/ShaderNode/Previews/PreviewValues.inl diff --git a/src/ShaderNode/DataModels/Cast.inl b/src/ShaderNode/DataModels/Cast.inl index ccb15385c..fb088b3a0 100644 --- a/src/ShaderNode/DataModels/Cast.inl +++ b/src/ShaderNode/DataModels/Cast.inl @@ -176,7 +176,7 @@ bool CastVec::ComputePreview(QPixmap& pixmap) if (!m_input) return false; - pixmap = QPixmap::fromImage(m_output->preview); + pixmap = QPixmap::fromImage(m_output->preview.GenerateImage()); return true; } @@ -185,47 +185,38 @@ void CastVec::UpdateOutput() { if (!m_input) { - m_output->preview = QImage(1, 1, QImage::Format_RGBA8888); - m_output->preview.fill(QColor::fromRgb(0, 0, 0, 0)); + m_output->preview = PreviewValues(1, 1); + m_output->preview(0, 0) = Nz::Vector4f::Zero(); return; } - const QImage& input = m_input->preview; + const PreviewValues& input = m_input->preview; - int inputWidth = input.width(); - int inputHeight = input.height(); + std::size_t inputWidth = input.GetWidth(); + std::size_t inputHeight = input.GetHeight(); - QImage& output = m_output->preview; - output = QImage(inputWidth, inputHeight, QImage::Format_RGBA8888); + PreviewValues& output = m_output->preview; + output = PreviewValues(inputWidth, inputHeight); std::size_t fromComponentCount = m_input->componentCount; std::size_t commonComponents = std::min(fromComponentCount, ToComponentCount); std::size_t overflowComponentCount = (ToComponentCount > fromComponentCount) ? ToComponentCount - fromComponentCount : 0; std::size_t voidComponents = 4 - overflowComponentCount - commonComponents; - std::array constants; - if (ToComponentCount > fromComponentCount) + for (std::size_t y = 0; y < inputHeight; ++y) { - for (std::size_t i = 0; i < overflowComponentCount; ++i) - constants[i] = static_cast(std::clamp(int(m_overflowComponents[i] * 255), 0, 255)); - } - - std::uint8_t* outputPtr = output.bits(); - const std::uint8_t* inputPtr = input.constBits(); - for (int y = 0; y < inputHeight; ++y) - { - for (int x = 0; x < inputWidth; ++x) + for (std::size_t x = 0; x < inputWidth; ++x) { - for (std::size_t i = 0; i < commonComponents; ++i) - *outputPtr++ = inputPtr[i]; + Nz::Vector4f color = input(x, y); + float* colorPtr = &color.x; for (std::size_t i = 0; i < overflowComponentCount; ++i) - *outputPtr++ = constants[i]; + *colorPtr++ = m_overflowComponents[i]; for (std::size_t i = 0; i < voidComponents; ++i) - *outputPtr++ = (i == voidComponents - 1) ? 255 : 0; + *colorPtr++ = (i == voidComponents - 1) ? 1.f : 0.f; - inputPtr += 4; + output(x, y) = color; } } diff --git a/src/ShaderNode/DataModels/FloatValue.cpp b/src/ShaderNode/DataModels/FloatValue.cpp index f9c25074b..c30ea8874 100644 --- a/src/ShaderNode/DataModels/FloatValue.cpp +++ b/src/ShaderNode/DataModels/FloatValue.cpp @@ -46,7 +46,7 @@ std::shared_ptr FloatValue::outData(QtNodes::PortIndex port) assert(port == 0); auto out = std::make_shared(); - out->preview.fill(ToColor()); + out->preview(0, 0) = Nz::Vector4f(m_value, m_value, m_value, 1.f); return out; } diff --git a/src/ShaderNode/DataModels/InputValue.cpp b/src/ShaderNode/DataModels/InputValue.cpp index 5a2b088dd..e0b117e83 100644 --- a/src/ShaderNode/DataModels/InputValue.cpp +++ b/src/ShaderNode/DataModels/InputValue.cpp @@ -48,7 +48,7 @@ bool InputValue::ComputePreview(QPixmap& pixmap) const auto& inputEntry = graph.GetInput(*m_currentInputIndex); const auto& preview = graph.GetPreviewModel(); - pixmap = QPixmap::fromImage(preview.GetImage(inputEntry.role, inputEntry.roleIndex)); + pixmap = QPixmap::fromImage(preview.GetPreview(inputEntry.role, inputEntry.roleIndex).GenerateImage()); return true; } @@ -171,7 +171,7 @@ std::shared_ptr InputValue::outData(QtNodes::PortIndex port) const auto& preview = graph.GetPreviewModel(); auto vecData = std::make_shared(GetComponentCount(inputEntry.type)); - vecData->preview = preview.GetImage(inputEntry.role, inputEntry.roleIndex); + vecData->preview = preview.GetPreview(inputEntry.role, inputEntry.roleIndex); return vecData; } diff --git a/src/ShaderNode/DataModels/OutputValue.cpp b/src/ShaderNode/DataModels/OutputValue.cpp index 7cf6fedec..a6b644be3 100644 --- a/src/ShaderNode/DataModels/OutputValue.cpp +++ b/src/ShaderNode/DataModels/OutputValue.cpp @@ -170,7 +170,7 @@ bool OutputValue::ComputePreview(QPixmap& pixmap) if (!m_input) return false; - pixmap = QPixmap::fromImage(m_input->preview); + pixmap = QPixmap::fromImage(m_input->preview.GenerateImage()); return true; } diff --git a/src/ShaderNode/DataModels/SampleTexture.cpp b/src/ShaderNode/DataModels/SampleTexture.cpp index 2c9e2dcac..131a8b161 100644 --- a/src/ShaderNode/DataModels/SampleTexture.cpp +++ b/src/ShaderNode/DataModels/SampleTexture.cpp @@ -23,57 +23,37 @@ unsigned int SampleTexture::nPorts(QtNodes::PortType portType) const void SampleTexture::UpdateOutput() { - QImage& output = m_output->preview; + PreviewValues& output = m_output->preview; if (!m_texture || !m_uv) { - output = QImage(1, 1, QImage::Format_RGBA8888); - output.fill(QColor::fromRgb(0, 0, 0, 0)); + output = PreviewValues(1, 1); + output.Fill(Nz::Vector4f::Zero()); return; } - const QImage& texturePreview = m_texture->preview; + const PreviewValues& texturePreview = m_texture->preview; - int textureWidth = texturePreview.width(); - int textureHeight = texturePreview.height(); + std::size_t textureWidth = texturePreview.GetWidth(); + std::size_t textureHeight = texturePreview.GetHeight(); - const QImage& uv = m_uv->preview; + const PreviewValues& uv = m_uv->preview; - int uvWidth = uv.width(); - int uvHeight = uv.height(); + std::size_t uvWidth = uv.GetWidth(); + std::size_t uvHeight = uv.GetHeight(); - output = QImage(uvWidth, uvHeight, QImage::Format_RGBA8888); + output = PreviewValues(uvWidth, uvHeight); - std::uint8_t* outputPtr = output.bits(); - const std::uint8_t* uvPtr = uv.constBits(); - const std::uint8_t* texturePtr = texturePreview.constBits(); - for (int y = 0; y < uvHeight; ++y) + for (std::size_t y = 0; y < uvHeight; ++y) { - for (int x = 0; x < uvWidth; ++x) + for (std::size_t x = 0; x < uvWidth; ++x) { - float u = float(uvPtr[0]) / 255; - float v = float(uvPtr[1]) / 255; + Nz::Vector4f uvValue = uv(x, y); if (textureWidth > 0 && textureHeight > 0) - { - int texX = std::clamp(int(u * textureWidth), 0, textureWidth - 1); - int texY = std::clamp(int(v * textureHeight), 0, textureHeight - 1); - int texPixel = (texY * textureWidth + texX) * 4; - - *outputPtr++ = texturePtr[texPixel + 0]; - *outputPtr++ = texturePtr[texPixel + 1]; - *outputPtr++ = texturePtr[texPixel + 2]; - *outputPtr++ = texturePtr[texPixel + 3]; - } + output(x, y) = texturePreview.Sample(uvValue.x, uvValue.y); else - { - *outputPtr++ = 0; - *outputPtr++ = 0; - *outputPtr++ = 0; - *outputPtr++ = 0xFF; - } - - uvPtr += 4; + output(x, y) = Nz::Vector4f(0.f, 0.f, 0.f, 1.f); } } @@ -87,7 +67,7 @@ bool SampleTexture::ComputePreview(QPixmap& pixmap) if (!m_texture || !m_uv) return false; - pixmap = QPixmap::fromImage(m_output->preview); + pixmap = QPixmap::fromImage(m_output->preview.GenerateImage()); return true; } diff --git a/src/ShaderNode/DataModels/TextureValue.cpp b/src/ShaderNode/DataModels/TextureValue.cpp index 2e25eaa03..d0237e8bd 100644 --- a/src/ShaderNode/DataModels/TextureValue.cpp +++ b/src/ShaderNode/DataModels/TextureValue.cpp @@ -158,7 +158,18 @@ std::shared_ptr TextureValue::outData(QtNodes::PortIndex port assert(textureData); - textureData->preview = textureEntry.preview; + const QImage& previewImage = textureEntry.preview; + + textureData->preview = PreviewValues(previewImage.width(), previewImage.height()); + for (std::size_t y = 0; y < textureData->preview.GetHeight(); ++y) + { + for (std::size_t x = 0; x < textureData->preview.GetWidth(); ++x) + { + QColor pixelColor = previewImage.pixelColor(int(x), int(y)); + + textureData->preview(x, y) = Nz::Vector4f(pixelColor.redF(), pixelColor.greenF(), pixelColor.blueF(), pixelColor.alphaF()); + } + } return textureData; } diff --git a/src/ShaderNode/DataModels/VecBinOp.cpp b/src/ShaderNode/DataModels/VecBinOp.cpp index 3ea2838f3..f99591420 100644 --- a/src/ShaderNode/DataModels/VecBinOp.cpp +++ b/src/ShaderNode/DataModels/VecBinOp.cpp @@ -12,15 +12,10 @@ QString VecAdd::name() const return name; } -void VecAdd::ApplyOp(const std::uint8_t* left, const std::uint8_t* right, std::uint8_t* output, std::size_t pixelCount) +void VecAdd::ApplyOp(const Nz::Vector4f* left, const Nz::Vector4f* right, Nz::Vector4f* output, std::size_t pixelCount) { for (std::size_t i = 0; i < pixelCount; ++i) - { - unsigned int lValue = left[i]; - unsigned int rValue = right[i]; - - output[i] = static_cast(std::min(lValue + rValue, 255U)); - } + output[i] = left[i] + right[i]; } QString VecMul::caption() const @@ -35,15 +30,10 @@ QString VecMul::name() const return name; } -void VecMul::ApplyOp(const std::uint8_t* left, const std::uint8_t* right, std::uint8_t* output, std::size_t pixelCount) +void VecMul::ApplyOp(const Nz::Vector4f* left, const Nz::Vector4f* right, Nz::Vector4f* output, std::size_t pixelCount) { for (std::size_t i = 0; i < pixelCount; ++i) - { - unsigned int lValue = left[i]; - unsigned int rValue = right[i]; - - output[i] = static_cast(lValue * rValue / 255); - } + output[i] = left[i] * right[i]; } QString VecSub::caption() const @@ -59,17 +49,10 @@ QString VecSub::name() const return name; } -void VecSub::ApplyOp(const std::uint8_t* left, const std::uint8_t* right, std::uint8_t* output, std::size_t pixelCount) +void VecSub::ApplyOp(const Nz::Vector4f* left, const Nz::Vector4f* right, Nz::Vector4f* output, std::size_t pixelCount) { for (std::size_t i = 0; i < pixelCount; ++i) - { - unsigned int lValue = left[i]; - unsigned int rValue = right[i]; - - unsigned int sub = (lValue >= rValue) ? lValue - rValue : 0u; - - output[i] = static_cast(sub); - } + output[i] = left[i] - right[i]; } QString VecDiv::caption() const @@ -85,21 +68,8 @@ QString VecDiv::name() const return name; } -void VecDiv::ApplyOp(const std::uint8_t* left, const std::uint8_t* right, std::uint8_t* output, std::size_t pixelCount) +void VecDiv::ApplyOp(const Nz::Vector4f* left, const Nz::Vector4f* right, Nz::Vector4f* output, std::size_t pixelCount) { for (std::size_t i = 0; i < pixelCount; ++i) - { - unsigned int lValue = left[i]; - unsigned int rValue = right[i]; - - unsigned res; - if (rValue != 0) - res = lValue / rValue; - else if (lValue != 0) - res = 0xFF; //< positive / 0 = +inf, which we clamp to 0xFF - else - res = 0; //< 0 / 0 = NaN, which we set to zero - - output[i] = static_cast(res); - } + output[i] = left[i] / right[i]; } diff --git a/src/ShaderNode/DataModels/VecBinOp.hpp b/src/ShaderNode/DataModels/VecBinOp.hpp index d00049c04..3c0a5aebd 100644 --- a/src/ShaderNode/DataModels/VecBinOp.hpp +++ b/src/ShaderNode/DataModels/VecBinOp.hpp @@ -27,7 +27,7 @@ class VecBinOp : public ShaderNode QString validationMessage() const override; private: - virtual void ApplyOp(const std::uint8_t* left, const std::uint8_t* right, std::uint8_t* output, std::size_t pixelCount) = 0; + virtual void ApplyOp(const Nz::Vector4f* left, const Nz::Vector4f* right, Nz::Vector4f* output, std::size_t pixelCount) = 0; bool ComputePreview(QPixmap& pixmap) override; void UpdateOutput(); @@ -45,7 +45,7 @@ class VecAdd : public VecBinOp QString caption() const override; QString name() const override; - void ApplyOp(const std::uint8_t* left, const std::uint8_t* right, std::uint8_t* output, std::size_t pixelCount) override; + void ApplyOp(const Nz::Vector4f* left, const Nz::Vector4f* right, Nz::Vector4f* output, std::size_t pixelCount) override; }; class VecMul : public VecBinOp @@ -56,7 +56,7 @@ class VecMul : public VecBinOp QString caption() const override; QString name() const override; - void ApplyOp(const std::uint8_t* left, const std::uint8_t* right, std::uint8_t* output, std::size_t pixelCount) override; + void ApplyOp(const Nz::Vector4f* left, const Nz::Vector4f* right, Nz::Vector4f* output, std::size_t pixelCount) override; }; class VecSub : public VecBinOp @@ -67,7 +67,7 @@ class VecSub : public VecBinOp QString caption() const override; QString name() const override; - void ApplyOp(const std::uint8_t* left, const std::uint8_t* right, std::uint8_t* output, std::size_t pixelCount) override; + void ApplyOp(const Nz::Vector4f* left, const Nz::Vector4f* right, Nz::Vector4f* output, std::size_t pixelCount) override; }; class VecDiv : public VecBinOp @@ -78,7 +78,7 @@ class VecDiv : public VecBinOp QString caption() const override; QString name() const override; - void ApplyOp(const std::uint8_t* left, const std::uint8_t* right, std::uint8_t* output, std::size_t pixelCount) override; + void ApplyOp(const Nz::Vector4f* left, const Nz::Vector4f* right, Nz::Vector4f* output, std::size_t pixelCount) override; }; #include diff --git a/src/ShaderNode/DataModels/VecBinOp.inl b/src/ShaderNode/DataModels/VecBinOp.inl index 255946543..d159545be 100644 --- a/src/ShaderNode/DataModels/VecBinOp.inl +++ b/src/ShaderNode/DataModels/VecBinOp.inl @@ -95,7 +95,7 @@ bool VecBinOp::ComputePreview(QPixmap& pixmap) if (!m_lhs || !m_rhs) return false; - pixmap = QPixmap::fromImage(m_output->preview); + pixmap = QPixmap::fromImage(m_output->preview.GenerateImage()); return true; } @@ -105,29 +105,29 @@ void VecBinOp::UpdateOutput() if (validationState() != QtNodes::NodeValidationState::Valid) { m_output = std::make_shared(4); - m_output->preview = QImage(1, 1, QImage::Format_RGBA8888); - m_output->preview.fill(QColor::fromRgb(0, 0, 0, 0)); + m_output->preview = PreviewValues(1, 1); + m_output->preview.Fill(Nz::Vector4f::Zero()); return; } m_output = std::make_shared(m_lhs->componentCount); - const QImage& leftPreview = m_lhs->preview; - const QImage& rightPreview = m_rhs->preview; - int maxWidth = std::max(leftPreview.width(), rightPreview.width()); - int maxHeight = std::max(leftPreview.height(), rightPreview.height()); + const PreviewValues& leftPreview = m_lhs->preview; + const PreviewValues& rightPreview = m_rhs->preview; + std::size_t maxWidth = std::max(leftPreview.GetWidth(), rightPreview.GetWidth()); + std::size_t maxHeight = std::max(leftPreview.GetHeight(), rightPreview.GetHeight()); - // Exploit COW - QImage leftResized = leftPreview; - if (leftResized.width() != maxWidth || leftResized.height() != maxHeight) - leftResized = leftResized.scaled(maxWidth, maxHeight); + // FIXME: Prevent useless copy + PreviewValues leftResized = leftPreview; + if (leftResized.GetWidth() != maxWidth || leftResized.GetHeight() != maxHeight) + leftResized = leftResized.Resized(maxWidth, maxHeight); - QImage rightResized = rightPreview; - if (rightResized.width() != maxWidth || rightResized.height() != maxHeight) - rightResized = rightResized.scaled(maxWidth, maxHeight); + PreviewValues rightResized = rightPreview; + if (rightResized.GetWidth() != maxWidth || rightResized.GetHeight() != maxHeight) + rightResized = rightResized.Resized(maxWidth, maxHeight); - m_output->preview = QImage(maxWidth, maxHeight, QImage::Format_RGBA8888); - ApplyOp(leftResized.constBits(), rightResized.constBits(), m_output->preview.bits(), maxWidth * maxHeight * 4); + m_output->preview = PreviewValues(maxWidth, maxHeight); + ApplyOp(leftResized.GetData(), rightResized.GetData(), m_output->preview.GetData(), maxWidth * maxHeight); Q_EMIT dataUpdated(0); diff --git a/src/ShaderNode/DataModels/VecDot.cpp b/src/ShaderNode/DataModels/VecDot.cpp index 48aac108c..818a68a2a 100644 --- a/src/ShaderNode/DataModels/VecDot.cpp +++ b/src/ShaderNode/DataModels/VecDot.cpp @@ -112,7 +112,7 @@ bool VecDot::ComputePreview(QPixmap& pixmap) if (validationState() != QtNodes::NodeValidationState::Valid) return false; - pixmap = QPixmap::fromImage(m_output->preview); + pixmap = QPixmap::fromImage(m_output->preview.GenerateImage()); return true; } @@ -120,45 +120,41 @@ void VecDot::UpdateOutput() { if (validationState() != QtNodes::NodeValidationState::Valid) { - m_output->preview = QImage(1, 1, QImage::Format_RGBA8888); - m_output->preview.fill(QColor::fromRgb(0, 0, 0, 0)); + m_output->preview = PreviewValues(1, 1); + m_output->preview.Fill(Nz::Vector4f::Zero()); return; } - const QImage& leftPreview = m_lhs->preview; - const QImage& rightPreview = m_rhs->preview; - int maxWidth = std::max(leftPreview.width(), rightPreview.width()); - int maxHeight = std::max(leftPreview.height(), rightPreview.height()); + const PreviewValues& leftPreview = m_lhs->preview; + const PreviewValues& rightPreview = m_rhs->preview; + std::size_t maxWidth = std::max(leftPreview.GetWidth(), rightPreview.GetWidth()); + std::size_t maxHeight = std::max(leftPreview.GetHeight(), rightPreview.GetHeight()); - // Exploit COW - QImage leftResized = leftPreview; - if (leftResized.width() != maxWidth || leftResized.height() != maxHeight) - leftResized = leftResized.scaled(maxWidth, maxHeight); + // FIXME: Prevent useless copy + PreviewValues leftResized = leftPreview; + if (leftResized.GetWidth() != maxWidth || leftResized.GetHeight() != maxHeight) + leftResized = leftResized.Resized(maxWidth, maxHeight); - QImage rightResized = rightPreview; - if (rightResized.width() != maxWidth || rightResized.height() != maxHeight) - rightResized = rightResized.scaled(maxWidth, maxHeight); + PreviewValues rightResized = rightPreview; + if (rightResized.GetWidth() != maxWidth || rightResized.GetHeight() != maxHeight) + rightResized = rightResized.Resized(maxWidth, maxHeight); - m_output->preview = QImage(maxWidth, maxHeight, QImage::Format_RGBA8888); + m_output->preview = PreviewValues(maxWidth, maxHeight); - const uchar* left = leftResized.constBits(); - const uchar* right = rightPreview.constBits(); - uchar* output = m_output->preview.bits(); + const Nz::Vector4f* left = leftResized.GetData(); + const Nz::Vector4f* right = rightPreview.GetData(); + Nz::Vector4f* output = m_output->preview.GetData(); std::size_t pixelCount = maxWidth * maxHeight; for (std::size_t i = 0; i < pixelCount; ++i) { - unsigned int acc = 0; + float acc = 0.f; for (std::size_t j = 0; j < m_lhs->componentCount; ++j) - acc += left[j] * right[j] / 255; + acc += left[i][j] * right[i][j]; - unsigned int result = static_cast(std::min(acc, 255U)); for (std::size_t j = 0; j < 3; ++j) - *output++ = result; - *output++ = 255; //< leave alpha at maximum - - left += 4; - right += 4; + output[i][j] = acc; + output[i][3] = 1.f; //< leave alpha at maximum } Q_EMIT dataUpdated(0); diff --git a/src/ShaderNode/DataModels/VecFloatMul.cpp b/src/ShaderNode/DataModels/VecFloatMul.cpp index 3c10d08e2..c1ecf50d2 100644 --- a/src/ShaderNode/DataModels/VecFloatMul.cpp +++ b/src/ShaderNode/DataModels/VecFloatMul.cpp @@ -132,7 +132,7 @@ bool VecFloatMul::ComputePreview(QPixmap& pixmap) if (validationState() != QtNodes::NodeValidationState::Valid) return false; - pixmap = QPixmap::fromImage(m_output->preview); + pixmap = QPixmap::fromImage(m_output->preview.GenerateImage()); return true; } @@ -141,41 +141,36 @@ void VecFloatMul::UpdateOutput() if (validationState() != QtNodes::NodeValidationState::Valid) { m_output = std::make_shared(4); - m_output->preview = QImage(1, 1, QImage::Format_RGBA8888); - m_output->preview.fill(QColor::fromRgb(0, 0, 0, 0)); + m_output->preview = PreviewValues(1, 1); + m_output->preview.Fill(Nz::Vector4f::Zero()); return; } m_output = std::make_shared(m_rhs->componentCount); - const QImage& leftPreview = m_lhs->preview; - const QImage& rightPreview = m_rhs->preview; - int maxWidth = std::max(leftPreview.width(), rightPreview.width()); - int maxHeight = std::max(leftPreview.height(), rightPreview.height()); + const PreviewValues& leftPreview = m_lhs->preview; + const PreviewValues& rightPreview = m_rhs->preview; + std::size_t maxWidth = std::max(leftPreview.GetWidth(), rightPreview.GetWidth()); + std::size_t maxHeight = std::max(leftPreview.GetHeight(), rightPreview.GetHeight()); - // Exploit COW - QImage leftResized = leftPreview; - if (leftResized.width() != maxWidth || leftResized.height() != maxHeight) - leftResized = leftResized.scaled(maxWidth, maxHeight); + // FIXME: Prevent useless copy + PreviewValues leftResized = leftPreview; + if (leftResized.GetWidth() != maxWidth || leftResized.GetHeight() != maxHeight) + leftResized = leftResized.Resized(maxWidth, maxHeight); - QImage rightResized = rightPreview; - if (rightResized.width() != maxWidth || rightResized.height() != maxHeight) - rightResized = rightResized.scaled(maxWidth, maxHeight); + PreviewValues rightResized = rightPreview; + if (rightResized.GetWidth() != maxWidth || rightResized.GetHeight() != maxHeight) + rightResized = rightResized.Resized(maxWidth, maxHeight); - m_output->preview = QImage(maxWidth, maxHeight, QImage::Format_RGBA8888); + m_output->preview = PreviewValues(maxWidth, maxHeight); - const uchar* left = leftResized.constBits(); - const uchar* right = rightPreview.constBits(); - uchar* output = m_output->preview.bits(); + const Nz::Vector4f* left = leftResized.GetData(); + const Nz::Vector4f* right = rightPreview.GetData(); + Nz::Vector4f* output = m_output->preview.GetData(); - std::size_t pixelCount = maxWidth * maxHeight * 4; + std::size_t pixelCount = maxWidth * maxHeight; for (std::size_t i = 0; i < pixelCount; ++i) - { - unsigned int lValue = left[i]; - unsigned int rValue = right[i]; - - output[i] = static_cast(lValue * rValue / 255); - } + output[i] = left[i] * right[i]; Q_EMIT dataUpdated(0); diff --git a/src/ShaderNode/DataModels/VecValue.inl b/src/ShaderNode/DataModels/VecValue.inl index 8e158b94b..8b72d1186 100644 --- a/src/ShaderNode/DataModels/VecValue.inl +++ b/src/ShaderNode/DataModels/VecValue.inl @@ -63,8 +63,14 @@ std::shared_ptr VecValue::outData(QtNodes::Po assert(port == 0); auto out = std::make_shared(ComponentCount); - out->preview = QImage(1, 1, QImage::Format_RGBA8888); - out->preview.fill(ToColor()); + + std::array values = { 0.f, 0.f, 0.f, 1.f }; + + for (std::size_t i = 0; i < ComponentCount; ++i) + values[i] = m_value[i]; + + out->preview = PreviewValues(1, 1); + out->preview(0, 0) = Nz::Vector4f(values[0], values[1], values[2], values[3]); return out; } diff --git a/src/ShaderNode/DataTypes/FloatData.hpp b/src/ShaderNode/DataTypes/FloatData.hpp index e0f0451d2..d33d12b5d 100644 --- a/src/ShaderNode/DataTypes/FloatData.hpp +++ b/src/ShaderNode/DataTypes/FloatData.hpp @@ -3,8 +3,8 @@ #ifndef NAZARA_SHADERNODES_FLOATDATA_HPP #define NAZARA_SHADERNODES_FLOATDATA_HPP +#include #include -#include struct FloatData : public QtNodes::NodeData { @@ -20,7 +20,7 @@ struct FloatData : public QtNodes::NodeData return { "float", "Float" }; } - QImage preview; + PreviewValues preview; }; #include diff --git a/src/ShaderNode/DataTypes/FloatData.inl b/src/ShaderNode/DataTypes/FloatData.inl index 3960c5811..4f889aa90 100644 --- a/src/ShaderNode/DataTypes/FloatData.inl +++ b/src/ShaderNode/DataTypes/FloatData.inl @@ -1,7 +1,7 @@ #include inline FloatData::FloatData() : -preview(1, 1, QImage::Format_RGBA8888) +preview(1, 1) { - preview.fill(QColor::fromRgb(255, 255, 255, 0)); + preview(0, 0) = Nz::Vector4f(1.f, 1.f, 1.f, 0.f); } diff --git a/src/ShaderNode/DataTypes/TextureData.hpp b/src/ShaderNode/DataTypes/TextureData.hpp index 632fa5bde..b6f7b4433 100644 --- a/src/ShaderNode/DataTypes/TextureData.hpp +++ b/src/ShaderNode/DataTypes/TextureData.hpp @@ -3,15 +3,15 @@ #ifndef NAZARA_SHADERNODES_TEXTUREDATA_HPP #define NAZARA_SHADERNODES_TEXTUREDATA_HPP +#include #include #include -#include struct TextureData : public QtNodes::NodeData { inline TextureData(); - QImage preview; + PreviewValues preview; }; struct Texture2Data : public TextureData diff --git a/src/ShaderNode/DataTypes/TextureData.inl b/src/ShaderNode/DataTypes/TextureData.inl index e3ae7014f..b542dff60 100644 --- a/src/ShaderNode/DataTypes/TextureData.inl +++ b/src/ShaderNode/DataTypes/TextureData.inl @@ -1,7 +1,7 @@ #include inline TextureData::TextureData() : -preview(64, 64, QImage::Format_RGBA8888) +preview(64, 64) { - preview.fill(QColor::fromRgb(255, 255, 255, 0)); + preview.Fill(Nz::Vector4f(1.f, 1.f, 1.f, 0.f)); } diff --git a/src/ShaderNode/DataTypes/VecData.hpp b/src/ShaderNode/DataTypes/VecData.hpp index f333f9483..3c6a8f096 100644 --- a/src/ShaderNode/DataTypes/VecData.hpp +++ b/src/ShaderNode/DataTypes/VecData.hpp @@ -4,8 +4,8 @@ #define NAZARA_SHADERNODES_VECDATA_HPP #include +#include #include -#include struct VecData : public QtNodes::NodeData { @@ -18,7 +18,7 @@ struct VecData : public QtNodes::NodeData static inline QtNodes::NodeDataType Type(); std::size_t componentCount; - QImage preview; + PreviewValues preview; }; template diff --git a/src/ShaderNode/DataTypes/VecData.inl b/src/ShaderNode/DataTypes/VecData.inl index a84b5c344..7264ca7e9 100644 --- a/src/ShaderNode/DataTypes/VecData.inl +++ b/src/ShaderNode/DataTypes/VecData.inl @@ -2,9 +2,9 @@ inline VecData::VecData(std::size_t ComponentCount) : componentCount(ComponentCount), -preview(64, 64, QImage::Format_RGBA8888) +preview(64, 64) { - preview.fill(QColor::fromRgb(255, 255, 255, 0)); + preview.Fill(Nz::Vector4f(1.f, 1.f, 1.f, 0.f)); } inline QtNodes::NodeDataType VecData::type() const diff --git a/src/ShaderNode/Previews/PreviewModel.hpp b/src/ShaderNode/Previews/PreviewModel.hpp index 6ed8ec3ef..17b49fef2 100644 --- a/src/ShaderNode/Previews/PreviewModel.hpp +++ b/src/ShaderNode/Previews/PreviewModel.hpp @@ -5,7 +5,7 @@ #include -class QImage; +class PreviewValues; class PreviewModel { @@ -13,7 +13,7 @@ class PreviewModel PreviewModel() = default; virtual ~PreviewModel(); - virtual QImage GetImage(InputRole role, std::size_t roleIndex) const = 0; + virtual PreviewValues GetPreview(InputRole role, std::size_t roleIndex) const = 0; }; #include diff --git a/src/ShaderNode/Previews/PreviewValues.cpp b/src/ShaderNode/Previews/PreviewValues.cpp new file mode 100644 index 000000000..e44055333 --- /dev/null +++ b/src/ShaderNode/Previews/PreviewValues.cpp @@ -0,0 +1,95 @@ +#include +#include + +PreviewValues::PreviewValues() : +PreviewValues(0, 0) +{ +} + +PreviewValues::PreviewValues(std::size_t width, std::size_t height) : +m_height(height), +m_width(width) +{ + m_values.resize(m_width * m_height); //< RGBA +} + +void PreviewValues::Fill(const Nz::Vector4f& value) +{ + std::fill(m_values.begin(), m_values.end(), value); +} + +QImage PreviewValues::GenerateImage() const +{ + QImage preview(int(m_width), int(m_height), QImage::Format_RGBA8888); + + Nz::UInt8* ptr = preview.bits(); + + const Nz::Vector4f* src = m_values.data(); + for (std::size_t i = 0; i < m_values.size(); ++i) + { + for (std::size_t y = 0; y < 4; ++y) + *ptr++ = static_cast(std::clamp((*src)[y] * 0xFF, 0.f, 255.f)); + + *src++; + } + + return preview; +} + +PreviewValues PreviewValues::Resized(std::size_t newWidth, std::size_t newHeight) const +{ + PreviewValues resizedPreview(newWidth, newHeight); + + float xStep = 1.f / newWidth; + float yStep = 1.f / newHeight; + + for (std::size_t y = 0; y < newHeight; ++y) + { + for (std::size_t x = 0; x < newWidth; ++x) + resizedPreview(x, y) = Sample(x * xStep, y * yStep); + } + + return resizedPreview; +} + +Nz::Vector4f PreviewValues::Sample(float u, float v) const +{ + // Bilinear filtering + float x = std::clamp(u * m_width, 0.f, m_width - 1.f); + float y = std::clamp(v * m_height, 0.f, m_height - 1.f); + + std::size_t iX = static_cast(x); + std::size_t iY = static_cast(y); + + float dX = x - iX; + float dY = y - iY; + + auto ColorAt = [&](std::size_t x, std::size_t y) -> Nz::Vector4f + { + x = std::min(x, m_width - 1); + y = std::min(y, m_height - 1); + + return m_values[y * m_width + x]; + }; + + Nz::Vector4f d00 = ColorAt(iX, iY); + Nz::Vector4f d10 = ColorAt(iX + 1, iY); + Nz::Vector4f d01 = ColorAt(iX, iY + 1); + Nz::Vector4f d11 = ColorAt(iX + 1, iY + 1); + + return Nz::Lerp(Nz::Lerp(d00, d10, dX), Nz::Lerp(d01, d11, dX), dY); +} + +Nz::Vector4f& PreviewValues::operator()(std::size_t x, std::size_t y) +{ + assert(x < m_width); + assert(y < m_height); + return m_values[y * m_width + x]; +} + +Nz::Vector4f PreviewValues::operator()(std::size_t x, std::size_t y) const +{ + assert(x < m_width); + assert(y < m_height); + return m_values[y * m_width + x]; +} diff --git a/src/ShaderNode/Previews/PreviewValues.hpp b/src/ShaderNode/Previews/PreviewValues.hpp new file mode 100644 index 000000000..47ce14680 --- /dev/null +++ b/src/ShaderNode/Previews/PreviewValues.hpp @@ -0,0 +1,50 @@ +#pragma once + +#ifndef NAZARA_SHADERNODES_PREVIEWVALUES_HPP +#define NAZARA_SHADERNODES_PREVIEWVALUES_HPP + +#include +#include +#include +#include +#include + +class QImage; + +class PreviewValues +{ + public: + PreviewValues(); + PreviewValues(std::size_t width, std::size_t height); + PreviewValues(const PreviewValues&) = default; + PreviewValues(PreviewValues&&) = default; + ~PreviewValues() = default; + + void Fill(const Nz::Vector4f& value); + + QImage GenerateImage() const; + + inline Nz::Vector4f* GetData(); + inline const Nz::Vector4f* GetData() const; + inline std::size_t GetHeight() const; + inline std::size_t GetWidth() const; + + PreviewValues Resized(std::size_t newWidth, std::size_t newHeight) const; + + Nz::Vector4f Sample(float u, float v) const; + + Nz::Vector4f& operator()(std::size_t x, std::size_t y); + Nz::Vector4f operator()(std::size_t x, std::size_t y) const; + + PreviewValues& operator=(const PreviewValues&) = default; + PreviewValues& operator=(PreviewValues&&) = default; + + private: + std::size_t m_height; + std::size_t m_width; + std::vector m_values; +}; + +#include + +#endif diff --git a/src/ShaderNode/Previews/PreviewValues.inl b/src/ShaderNode/Previews/PreviewValues.inl new file mode 100644 index 000000000..06ca202ec --- /dev/null +++ b/src/ShaderNode/Previews/PreviewValues.inl @@ -0,0 +1,21 @@ +#include + +inline Nz::Vector4f* PreviewValues::GetData() +{ + return m_values.data(); +} + +inline const Nz::Vector4f* PreviewValues::GetData() const +{ + return m_values.data(); +} + +inline std::size_t PreviewValues::GetHeight() const +{ + return m_width; +} + +inline std::size_t PreviewValues::GetWidth() const +{ + return m_height; +} diff --git a/src/ShaderNode/Previews/QuadPreview.cpp b/src/ShaderNode/Previews/QuadPreview.cpp index ef064417d..a4edc9267 100644 --- a/src/ShaderNode/Previews/QuadPreview.cpp +++ b/src/ShaderNode/Previews/QuadPreview.cpp @@ -1,27 +1,22 @@ #include #include -QImage QuadPreview::GetImage(InputRole role, std::size_t roleIndex) const +PreviewValues QuadPreview::GetPreview(InputRole role, std::size_t roleIndex) const { if (role != InputRole::TexCoord) { - QImage dummy(1, 1, QImage::Format_RGBA8888); - dummy.fill(QColor::fromRgb(0, 0, 0, 0)); + PreviewValues dummy(1, 1); + dummy(0, 0) = Nz::Vector4f::Zero(); + return dummy; } - QImage uv(128, 128, QImage::Format_RGBA8888); + PreviewValues uv(128, 128); - std::uint8_t* content = uv.bits(); for (std::size_t y = 0; y < 128; ++y) { for (std::size_t x = 0; x < 128; ++x) - { - *content++ = (x * 255) / 128; - *content++ = (y * 255) / 128; - *content++ = 0; - *content++ = 255; - } + uv(x, y) = Nz::Vector4f(x / 128.f, y / 128.f, 0.f, 1.f); } return uv; diff --git a/src/ShaderNode/Previews/QuadPreview.hpp b/src/ShaderNode/Previews/QuadPreview.hpp index 6c980ae34..947b4d637 100644 --- a/src/ShaderNode/Previews/QuadPreview.hpp +++ b/src/ShaderNode/Previews/QuadPreview.hpp @@ -4,7 +4,7 @@ #define NAZARA_SHADERNODES_QUADPREVIEW_HPP #include -#include +#include class QuadPreview : public PreviewModel { @@ -12,7 +12,7 @@ class QuadPreview : public PreviewModel QuadPreview() = default; ~QuadPreview() = default; - QImage GetImage(InputRole role, std::size_t roleIndex) const override; + PreviewValues GetPreview(InputRole role, std::size_t roleIndex) const override; }; #include From 5164294bec74694c92b24a027e9633997d56f807 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Sat, 4 Jul 2020 22:52:17 +0200 Subject: [PATCH 049/105] ShaderNodes: Add TextureEdit dialog --- build/scripts/tools/shadernodes.lua | 14 ++-- src/ShaderNode/DataModels/TextureValue.cpp | 14 ++-- src/ShaderNode/DataModels/TextureValue.hpp | 3 +- src/ShaderNode/Previews/QuadPreview.cpp | 11 +-- src/ShaderNode/ShaderGraph.cpp | 11 +++ src/ShaderNode/ShaderGraph.hpp | 2 + src/ShaderNode/Widgets/TextureEditDialog.cpp | 73 ++++++++++++++++++++ src/ShaderNode/Widgets/TextureEditDialog.hpp | 39 +++++++++++ src/ShaderNode/Widgets/TextureEditDialog.inl | 1 + src/ShaderNode/Widgets/TextureEditor.cpp | 45 ++++++++++++ src/ShaderNode/Widgets/TextureEditor.hpp | 4 ++ 11 files changed, 200 insertions(+), 17 deletions(-) create mode 100644 src/ShaderNode/Widgets/TextureEditDialog.cpp create mode 100644 src/ShaderNode/Widgets/TextureEditDialog.hpp create mode 100644 src/ShaderNode/Widgets/TextureEditDialog.inl diff --git a/build/scripts/tools/shadernodes.lua b/build/scripts/tools/shadernodes.lua index 415b71c75..3abeaa658 100644 --- a/build/scripts/tools/shadernodes.lua +++ b/build/scripts/tools/shadernodes.lua @@ -13,11 +13,11 @@ TOOL.Includes = { "../include", "../extlibs/include", "../src", - [[E:\Qt\5.14.1\msvc2017_64\include]], - [[E:\Qt\5.14.1\msvc2017_64\include\QtCore]], - [[E:\Qt\5.14.1\msvc2017_64\include\QtGui]], - [[E:\Qt\5.14.1\msvc2017_64\include\QtWidgets]], - [[C:\Users\Lynix\Documents\GitHub\nodeeditor\include]], + [[C:\Projets\Libs\Qt\5.15.0\msvc2019_64\include]], + [[C:\Projets\Libs\Qt\5.15.0\msvc2019_64\include\QtCore]], + [[C:\Projets\Libs\Qt\5.15.0\msvc2019_64\include\QtGui]], + [[C:\Projets\Libs\Qt\5.15.0\msvc2019_64\include\QtWidgets]], + [[C:\Projets\Libs\nodeeditor\include]], } TOOL.Files = { @@ -37,6 +37,6 @@ TOOL.Libraries = { } TOOL.LibraryPaths.x64 = { - [[E:\Qt\5.14.1\msvc2017_64\lib]], - [[C:\Users\Lynix\Documents\GitHub\nodeeditor\build\lib\Debug]] + [[C:\Projets\Libs\Qt\5.15.0\msvc2019_64\lib]], + [[C:\Projets\Libs\nodeeditor\build\lib\Debug]] } diff --git a/src/ShaderNode/DataModels/TextureValue.cpp b/src/ShaderNode/DataModels/TextureValue.cpp index d0237e8bd..6a6402cf4 100644 --- a/src/ShaderNode/DataModels/TextureValue.cpp +++ b/src/ShaderNode/DataModels/TextureValue.cpp @@ -9,19 +9,23 @@ TextureValue::TextureValue(ShaderGraph& graph) : ShaderNode(graph) { m_onTextureListUpdateSlot.Connect(GetGraph().OnTextureListUpdate, [&](ShaderGraph*) { OnTextureListUpdate(); }); - m_onTexturePreviewUpdateSlot.Connect(GetGraph().OnTexturePreviewUpdate, [&](ShaderGraph*, std::size_t textureIndex) + + auto HandleTextureUpdate = [&](ShaderGraph*, std::size_t textureIndex) { if (m_currentTextureIndex == textureIndex) { UpdatePreview(); Q_EMIT dataUpdated(0); } - }); + }; + + m_onTexturePreviewUpdateSlot.Connect(GetGraph().OnTexturePreviewUpdate, HandleTextureUpdate); + m_onTextureUpdateSlot.Connect(GetGraph().OnTextureUpdate, HandleTextureUpdate); if (graph.GetTextureCount() > 0) { m_currentTextureIndex = 0; - UpdateOutputTexture(); + UpdateTexture(); } DisableCustomVariableName(); @@ -56,7 +60,7 @@ void TextureValue::OnTextureListUpdate() } } -void TextureValue::UpdateOutputTexture() +void TextureValue::UpdateTexture() { if (m_currentTextureIndex) { @@ -97,7 +101,7 @@ void TextureValue::BuildNodeEdition(QFormLayout* layout) else m_currentTextureIndex.reset(); - UpdateOutputTexture(); + UpdateTexture(); UpdatePreview(); Q_EMIT dataUpdated(0); diff --git a/src/ShaderNode/DataModels/TextureValue.hpp b/src/ShaderNode/DataModels/TextureValue.hpp index dfb7efaff..d328e2f05 100644 --- a/src/ShaderNode/DataModels/TextureValue.hpp +++ b/src/ShaderNode/DataModels/TextureValue.hpp @@ -35,13 +35,14 @@ class TextureValue : public ShaderNode protected: bool ComputePreview(QPixmap& pixmap) override; void OnTextureListUpdate(); - void UpdateOutputTexture(); + void UpdateTexture(); void restore(const QJsonObject& data) override; QJsonObject save() const override; NazaraSlot(ShaderGraph, OnTextureListUpdate, m_onTextureListUpdateSlot); NazaraSlot(ShaderGraph, OnTexturePreviewUpdate, m_onTexturePreviewUpdateSlot); + NazaraSlot(ShaderGraph, OnTextureUpdate, m_onTextureUpdateSlot); std::optional m_currentTextureIndex; std::string m_currentTextureText; diff --git a/src/ShaderNode/Previews/QuadPreview.cpp b/src/ShaderNode/Previews/QuadPreview.cpp index a4edc9267..ce6155903 100644 --- a/src/ShaderNode/Previews/QuadPreview.cpp +++ b/src/ShaderNode/Previews/QuadPreview.cpp @@ -11,12 +11,15 @@ PreviewValues QuadPreview::GetPreview(InputRole role, std::size_t roleIndex) con return dummy; } - PreviewValues uv(128, 128); + PreviewValues uv(128, 128); - for (std::size_t y = 0; y < 128; ++y) + float invWidth = 1.f / uv.GetWidth(); + float invHeight = 1.f / uv.GetHeight(); + + for (std::size_t y = 0; y < uv.GetHeight(); ++y) { - for (std::size_t x = 0; x < 128; ++x) - uv(x, y) = Nz::Vector4f(x / 128.f, y / 128.f, 0.f, 1.f); + for (std::size_t x = 0; x < uv.GetWidth(); ++x) + uv(x, y) = Nz::Vector4f(x * invWidth, y * invHeight, 0.f, 1.f); } return uv; diff --git a/src/ShaderNode/ShaderGraph.cpp b/src/ShaderNode/ShaderGraph.cpp index 880afb2a9..5788e1f8b 100644 --- a/src/ShaderNode/ShaderGraph.cpp +++ b/src/ShaderNode/ShaderGraph.cpp @@ -390,6 +390,17 @@ void ShaderGraph::UpdateOutput(std::size_t outputIndex, std::string name, InOutT OnOutputUpdate(this, outputIndex); } +void ShaderGraph::UpdateTexture(std::size_t textureIndex, std::string name, TextureType type, std::size_t bindingIndex) +{ + assert(textureIndex < m_textures.size()); + auto& textureEntry = m_textures[textureIndex]; + textureEntry.bindingIndex = bindingIndex; + textureEntry.name = std::move(name); + textureEntry.type = type; + + OnTextureUpdate(this, textureIndex); +} + void ShaderGraph::UpdateTexturePreview(std::size_t textureIndex, QImage preview) { assert(textureIndex < m_textures.size()); diff --git a/src/ShaderNode/ShaderGraph.hpp b/src/ShaderNode/ShaderGraph.hpp index add7e52ab..b65694f65 100644 --- a/src/ShaderNode/ShaderGraph.hpp +++ b/src/ShaderNode/ShaderGraph.hpp @@ -48,6 +48,7 @@ class ShaderGraph void UpdateInput(std::size_t inputIndex, std::string name, InOutType type, InputRole role, std::size_t roleIndex, std::size_t locationIndex); void UpdateOutput(std::size_t outputIndex, std::string name, InOutType type, std::size_t locationIndex); + void UpdateTexture(std::size_t textureIndex, std::string name, TextureType type, std::size_t bindingIndex); void UpdateTexturePreview(std::size_t texture, QImage preview); struct InputEntry @@ -81,6 +82,7 @@ class ShaderGraph NazaraSignal(OnSelectedNodeUpdate, ShaderGraph*, ShaderNode* /*node*/); NazaraSignal(OnTextureListUpdate, ShaderGraph*); NazaraSignal(OnTexturePreviewUpdate, ShaderGraph*, std::size_t /*textureIndex*/); + NazaraSignal(OnTextureUpdate, ShaderGraph*, std::size_t /*textureIndex*/); private: std::shared_ptr BuildRegistry(); diff --git a/src/ShaderNode/Widgets/TextureEditDialog.cpp b/src/ShaderNode/Widgets/TextureEditDialog.cpp new file mode 100644 index 000000000..f16530e1f --- /dev/null +++ b/src/ShaderNode/Widgets/TextureEditDialog.cpp @@ -0,0 +1,73 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +TextureEditDialog::TextureEditDialog(QWidget* parent) : +QDialog(parent) +{ + setWindowTitle(tr("Texture edit dialog")); + setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); + + m_textureName = new QLineEdit; + + m_typeList = new QComboBox; + for (std::size_t i = 0; i < TextureTypeCount; ++i) + m_typeList->addItem(EnumToString(static_cast(i))); + + m_bindingIndex = new QSpinBox; + + QFormLayout* formLayout = new QFormLayout; + formLayout->addRow(tr("Name"), m_textureName); + formLayout->addRow(tr("Type"), m_typeList); + formLayout->addRow(tr("Binding index"), m_bindingIndex); + + QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); + connect(buttonBox, &QDialogButtonBox::accepted, this, &TextureEditDialog::OnAccept); + connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); + + QVBoxLayout* verticalLayout = new QVBoxLayout; + verticalLayout->addLayout(formLayout); + verticalLayout->addWidget(buttonBox); + + setLayout(verticalLayout); +} + +TextureEditDialog::TextureEditDialog(const TextureInfo& texture, QWidget* parent) : +TextureEditDialog(parent) +{ + m_bindingIndex->setValue(int(texture.bindingIndex)); + m_textureName->setText(QString::fromStdString(texture.name)); + m_typeList->setCurrentText(EnumToString(texture.type)); +} + +TextureInfo TextureEditDialog::GetTextureInfo() const +{ + TextureInfo inputInfo; + inputInfo.bindingIndex = static_cast(m_bindingIndex->value()); + inputInfo.name = m_textureName->text().toStdString(); + inputInfo.type = static_cast(m_typeList->currentIndex()); + + return inputInfo; +} + +void TextureEditDialog::OnAccept() +{ + if (m_textureName->text().isEmpty()) + { + QMessageBox::critical(this, tr("Empty name"), tr("Texture name must be set"), QMessageBox::Ok); + return; + } + + if (m_typeList->currentIndex() < 0) + { + QMessageBox::critical(this, tr("Invalid type"), tr("You must select a type"), QMessageBox::Ok); + return; + } + + accept(); +} diff --git a/src/ShaderNode/Widgets/TextureEditDialog.hpp b/src/ShaderNode/Widgets/TextureEditDialog.hpp new file mode 100644 index 000000000..ea402f31d --- /dev/null +++ b/src/ShaderNode/Widgets/TextureEditDialog.hpp @@ -0,0 +1,39 @@ +#pragma once + +#ifndef NAZARA_SHADERNODES_TEXTUREEDITDIALOG_HPP +#define NAZARA_SHADERNODES_TEXTUREEDITDIALOG_HPP + +#include +#include + +class QComboBox; +class QLineEdit; +class QSpinBox; + +struct TextureInfo +{ + std::size_t bindingIndex; + std::string name; + TextureType type; +}; + +class TextureEditDialog : public QDialog +{ + public: + TextureEditDialog(QWidget* parent = nullptr); + TextureEditDialog(const TextureInfo& Texture, QWidget* parent = nullptr); + ~TextureEditDialog() = default; + + TextureInfo GetTextureInfo() const; + + private: + void OnAccept(); + + QComboBox* m_typeList; + QLineEdit* m_textureName; + QSpinBox* m_bindingIndex; +}; + +#include + +#endif diff --git a/src/ShaderNode/Widgets/TextureEditDialog.inl b/src/ShaderNode/Widgets/TextureEditDialog.inl new file mode 100644 index 000000000..c15d4e41c --- /dev/null +++ b/src/ShaderNode/Widgets/TextureEditDialog.inl @@ -0,0 +1 @@ +#include diff --git a/src/ShaderNode/Widgets/TextureEditor.cpp b/src/ShaderNode/Widgets/TextureEditor.cpp index 40cce4652..99b40316a 100644 --- a/src/ShaderNode/Widgets/TextureEditor.cpp +++ b/src/ShaderNode/Widgets/TextureEditor.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -11,6 +12,10 @@ m_shaderGraph(graph) { m_textureList = new QListWidget; connect(m_textureList, &QListWidget::currentRowChanged, this, &TextureEditor::OnTextureSelectionUpdate); + connect(m_textureList, &QListWidget::itemDoubleClicked, [this](QListWidgetItem* item) + { + OnEditTexture(m_textureList->row(item)); + }); m_pixmapLabel = new QLabel; @@ -26,10 +31,44 @@ m_shaderGraph(graph) m_onTextureListUpdateSlot.Connect(m_shaderGraph.OnTextureListUpdate, this, &TextureEditor::OnTextureListUpdate); m_onTexturePreviewUpdateSlot.Connect(m_shaderGraph.OnTexturePreviewUpdate, this, &TextureEditor::OnTexturePreviewUpdate); + m_onTextureUpdateSlot.Connect(m_shaderGraph.OnTextureUpdate, this, &TextureEditor::OnTextureUpdate); RefreshTextures(); } +void TextureEditor::OnAddTexture() +{ + TextureEditDialog* dialog = new TextureEditDialog(this); + dialog->setAttribute(Qt::WA_DeleteOnClose, true); + connect(dialog, &QDialog::accepted, [this, dialog] + { + TextureInfo outputInfo = dialog->GetTextureInfo(); + m_shaderGraph.AddTexture(std::move(outputInfo.name), outputInfo.type, outputInfo.bindingIndex); + }); + + dialog->open(); +} + +void TextureEditor::OnEditTexture(int inputIndex) +{ + const auto& output = m_shaderGraph.GetTexture(inputIndex); + + TextureInfo info; + info.bindingIndex = output.bindingIndex; + info.name = output.name; + info.type = output.type; + + TextureEditDialog* dialog = new TextureEditDialog(std::move(info), this); + dialog->setAttribute(Qt::WA_DeleteOnClose, true); + connect(dialog, &QDialog::accepted, [this, dialog, inputIndex] + { + TextureInfo textureInfo = dialog->GetTextureInfo(); + m_shaderGraph.UpdateTexture(inputIndex, std::move(textureInfo.name), textureInfo.type, textureInfo.bindingIndex); + }); + + dialog->open(); +} + void TextureEditor::OnLoadTexture() { if (!m_currentTextureIndex) @@ -64,6 +103,12 @@ void TextureEditor::OnTexturePreviewUpdate(ShaderGraph* /*graph*/, std::size_t t UpdateTexturePreview(); } +void TextureEditor::OnTextureUpdate(ShaderGraph* /*graph*/, std::size_t inputIndex) +{ + const auto& inputEntry = m_shaderGraph.GetTexture(inputIndex); + m_textureList->item(int(inputIndex))->setText(QString::fromStdString(inputEntry.name)); +} + void TextureEditor::RefreshTextures() { m_textureList->clear(); diff --git a/src/ShaderNode/Widgets/TextureEditor.hpp b/src/ShaderNode/Widgets/TextureEditor.hpp index a3497f288..1c006e0ab 100644 --- a/src/ShaderNode/Widgets/TextureEditor.hpp +++ b/src/ShaderNode/Widgets/TextureEditor.hpp @@ -18,15 +18,19 @@ class TextureEditor : public QWidget ~TextureEditor() = default; private: + void OnAddTexture(); + void OnEditTexture(int inputIndex); void OnLoadTexture(); void OnTextureSelectionUpdate(int textureIndex); void OnTextureListUpdate(ShaderGraph* graph); void OnTexturePreviewUpdate(ShaderGraph* graph, std::size_t textureIndex); + void OnTextureUpdate(ShaderGraph* graph, std::size_t textureIndex); void RefreshTextures(); void UpdateTexturePreview(); NazaraSlot(ShaderGraph, OnTextureListUpdate, m_onTextureListUpdateSlot); NazaraSlot(ShaderGraph, OnTexturePreviewUpdate, m_onTexturePreviewUpdateSlot); + NazaraSlot(ShaderGraph, OnTextureUpdate, m_onTextureUpdateSlot); std::optional m_currentTextureIndex; ShaderGraph& m_shaderGraph; From cd01facd01a311709876c75a1fd0b0c27385a7c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Wed, 8 Jul 2020 22:52:33 +0200 Subject: [PATCH 050/105] GlslWriter: Handle OpenGL ES precision qualifier --- src/Nazara/OpenGLRenderer/OpenGLShaderStage.cpp | 3 +-- src/Nazara/Renderer/GlslWriter.cpp | 10 ++++++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/Nazara/OpenGLRenderer/OpenGLShaderStage.cpp b/src/Nazara/OpenGLRenderer/OpenGLShaderStage.cpp index 561a1d196..b7cc63c9f 100644 --- a/src/Nazara/OpenGLRenderer/OpenGLShaderStage.cpp +++ b/src/Nazara/OpenGLRenderer/OpenGLShaderStage.cpp @@ -35,8 +35,7 @@ namespace Nz const auto& contextParams = context.GetParams(); GlslWriter::Environment env; - env.glES = false; - //env.glES = (contextParams.type == GL::ContextType::OpenGL_ES); + env.glES = (contextParams.type == GL::ContextType::OpenGL_ES); env.glMajorVersion = contextParams.glMajorVersion; env.glMinorVersion = contextParams.glMinorVersion; env.extCallback = [&](const std::string_view& ext) diff --git a/src/Nazara/Renderer/GlslWriter.cpp b/src/Nazara/Renderer/GlslWriter.cpp index 9116aa3a3..61dc030da 100644 --- a/src/Nazara/Renderer/GlslWriter.cpp +++ b/src/Nazara/Renderer/GlslWriter.cpp @@ -98,6 +98,16 @@ namespace Nz AppendLine(); } + if (m_environment.glES) + { + AppendLine("#if GL_FRAGMENT_PRECISION_HIGH"); + AppendLine("precision highp float;"); + AppendLine("#else"); + AppendLine("precision mediump float;"); + AppendLine("#endif"); + AppendLine(); + } + // Global variables (uniforms, input and outputs) const char* inKeyword = (glslVersion >= 130) ? "in" : "varying"; const char* outKeyword = (glslVersion >= 130) ? "out" : "varying"; From 4c0dc7813d9e0bf69846d6d243c5b834af8d68d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Tue, 14 Jul 2020 21:59:25 +0200 Subject: [PATCH 051/105] VulkanTest: Enable relative mouse mode --- examples/VulkanTest/main.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/examples/VulkanTest/main.cpp b/examples/VulkanTest/main.cpp index e42aa41ac..e0cb14437 100644 --- a/examples/VulkanTest/main.cpp +++ b/examples/VulkanTest/main.cpp @@ -229,6 +229,8 @@ int main() Nz::Clock secondClock; unsigned int fps = 0; + Nz::Mouse::SetRelativeMouseMode(true); + while (window.IsOpen()) { Nz::WindowEvent event; @@ -252,10 +254,6 @@ int main() camAngles.pitch = Nz::Clamp(camAngles.pitch + event.mouseMove.deltaY*sensitivity, -89.f, 89.f); camQuat = camAngles; - - // Pour éviter que le curseur ne sorte de l'écran, nous le renvoyons au centre de la fenêtre - // Cette fonction est codée de sorte à ne pas provoquer d'évènement MouseMoved - Nz::Mouse::SetPosition(windowSize.x / 2, windowSize.y / 2, window); break; } } From fbba281d14d6300290f7f4637e2277a47f2dfc5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Tue, 14 Jul 2020 21:59:49 +0200 Subject: [PATCH 052/105] Renderer: Add support for struct and UBO --- include/Nazara/Renderer/GlslWriter.hpp | 4 +- include/Nazara/Renderer/GlslWriter.inl | 95 +++++++++++-- include/Nazara/Renderer/ShaderAst.hpp | 34 ++++- include/Nazara/Renderer/ShaderAst.inl | 16 +++ include/Nazara/Renderer/ShaderEnums.hpp | 5 + include/Nazara/Renderer/ShaderSerializer.hpp | 11 +- include/Nazara/Renderer/ShaderSerializer.inl | 18 +++ include/Nazara/Renderer/ShaderValidator.hpp | 5 +- src/Nazara/Renderer/GlslWriter.cpp | 46 +++++- src/Nazara/Renderer/ShaderAst.cpp | 20 ++- src/Nazara/Renderer/ShaderSerializer.cpp | 139 +++++++++++++++++-- src/Nazara/Renderer/ShaderValidator.cpp | 2 +- 12 files changed, 346 insertions(+), 49 deletions(-) diff --git a/include/Nazara/Renderer/GlslWriter.hpp b/include/Nazara/Renderer/GlslWriter.hpp index e0f9bf11e..999a93c48 100644 --- a/include/Nazara/Renderer/GlslWriter.hpp +++ b/include/Nazara/Renderer/GlslWriter.hpp @@ -44,15 +44,17 @@ namespace Nz }; private: + void Append(ShaderAst::Type type); void Append(ShaderNodes::BuiltinEntry builtin); void Append(ShaderNodes::ExpressionType type); + void Append(ShaderNodes::MemoryLayout layout); template void Append(const T& param); void AppendCommentSection(const std::string& section); void AppendFunction(const ShaderAst::Function& func); void AppendFunctionPrototype(const ShaderAst::Function& func); void AppendLine(const std::string& txt = {}); - template void DeclareVariables(const std::vector& variables, const std::string& keyword = {}, const std::string& section = {}); + template void DeclareVariables(const ShaderAst& shader, const std::vector& variables, const std::string& keyword = {}, const std::string& section = {}); void EnterScope(); void LeaveScope(); diff --git a/include/Nazara/Renderer/GlslWriter.inl b/include/Nazara/Renderer/GlslWriter.inl index fcaca4b98..9b67eaa89 100644 --- a/include/Nazara/Renderer/GlslWriter.inl +++ b/include/Nazara/Renderer/GlslWriter.inl @@ -17,7 +17,7 @@ namespace Nz } template - void GlslWriter::DeclareVariables(const std::vector& variables, const std::string& keyword, const std::string& section) + void GlslWriter::DeclareVariables(const ShaderAst& shader, const std::vector& variables, const std::string& keyword, const std::string& section) { if (!variables.empty()) { @@ -34,27 +34,94 @@ namespace Nz Append(*var.locationIndex); Append(") "); } + + if (!keyword.empty()) + { + Append(keyword); + Append(" "); + } + + Append(var.type); + Append(" "); + Append(var.name); + AppendLine(";"); } else if constexpr (std::is_same_v) { - if (var.bindingIndex) + if (var.bindingIndex || var.memoryLayout) { - Append("layout(binding = "); - Append(*var.bindingIndex); + Append("layout("); + + bool first = true; + if (var.bindingIndex) + { + if (!first) + Append(", "); + + Append("binding = "); + Append(*var.bindingIndex); + + first = false; + } + + if (var.memoryLayout) + { + if (!first) + Append(", "); + + Append(*var.memoryLayout); + + first = false; + } + Append(") "); } - } - if (!keyword.empty()) - { - Append(keyword); - Append(" "); - } + if (!keyword.empty()) + { + Append(keyword); + Append(" "); + } - Append(var.type); - Append(" "); - Append(var.name); - AppendLine(";"); + std::visit([&](auto&& arg) + { + using T = std::decay_t; + if constexpr (std::is_same_v) + { + Append(arg); + Append(" "); + Append(var.name); + } + else if constexpr (std::is_same_v) + { + const auto& structs = shader.GetStructs(); + auto it = std::find_if(structs.begin(), structs.end(), [&](const auto& s) { return s.name == arg; }); + if (it == structs.end()) + throw std::runtime_error("struct " + arg + " has not been defined"); + + const auto& s = *it; + + AppendLine(var.name + "_interface"); + AppendLine("{"); + for (const auto& m : s.members) + { + Append("\t"); + Append(m.type); + Append(" "); + Append(m.name); + AppendLine(";"); + } + Append("} "); + Append(var.name); + } + else + static_assert(AlwaysFalse::value, "non-exhaustive visitor"); + + }, var.type); + + AppendLine(";"); + AppendLine(); + } } AppendLine(); diff --git a/include/Nazara/Renderer/ShaderAst.hpp b/include/Nazara/Renderer/ShaderAst.hpp index 0aa094a10..4b57bbced 100644 --- a/include/Nazara/Renderer/ShaderAst.hpp +++ b/include/Nazara/Renderer/ShaderAst.hpp @@ -11,6 +11,8 @@ #include #include #include +#include +#include #include namespace Nz @@ -21,16 +23,21 @@ namespace Nz struct Function; struct FunctionParameter; struct InputOutput; - struct VariableBase; + struct Struct; + struct StructMember; struct Uniform; + struct VariableBase; + + using Type = std::variant; ShaderAst() = default; ~ShaderAst() = default; void AddFunction(std::string name, ShaderNodes::StatementPtr statement, std::vector parameters = {}, ShaderNodes::ExpressionType returnType = ShaderNodes::ExpressionType::Void); - void AddInput(std::string name, ShaderNodes::ExpressionType type, std::optional locationIndex); - void AddOutput(std::string name, ShaderNodes::ExpressionType type, std::optional locationIndex); - void AddUniform(std::string name, ShaderNodes::ExpressionType type, std::optional bindingIndex); + void AddInput(std::string name, Type type, std::optional locationIndex); + void AddOutput(std::string name, Type type, std::optional locationIndex); + void AddStruct(std::string name, std::vector members); + void AddUniform(std::string name, Type type, std::optional bindingIndex, std::optional memoryLayout); inline const Function& GetFunction(std::size_t i) const; inline std::size_t GetFunctionCount() const; @@ -41,6 +48,9 @@ namespace Nz inline const InputOutput& GetOutput(std::size_t i) const; inline std::size_t GetOutputCount() const; inline const std::vector& GetOutputs() const; + inline const Struct& GetStruct(std::size_t i) const; + inline std::size_t GetStructCount() const; + inline const std::vector& GetStructs() const; inline const Uniform& GetUniform(std::size_t i) const; inline std::size_t GetUniformCount() const; inline const std::vector& GetUniforms() const; @@ -48,7 +58,7 @@ namespace Nz struct VariableBase { std::string name; - ShaderNodes::ExpressionType type; + Type type; }; struct FunctionParameter : VariableBase @@ -71,12 +81,26 @@ namespace Nz struct Uniform : VariableBase { std::optional bindingIndex; + std::optional memoryLayout; + }; + + struct Struct + { + std::string name; + std::vector members; + }; + + struct StructMember + { + std::string name; + Type type; }; private: std::vector m_functions; std::vector m_inputs; std::vector m_outputs; + std::vector m_structs; std::vector m_uniforms; }; } diff --git a/include/Nazara/Renderer/ShaderAst.inl b/include/Nazara/Renderer/ShaderAst.inl index d9f8f88aa..c42c1e9c1 100644 --- a/include/Nazara/Renderer/ShaderAst.inl +++ b/include/Nazara/Renderer/ShaderAst.inl @@ -55,6 +55,22 @@ namespace Nz return m_outputs; } + inline auto ShaderAst::GetStruct(std::size_t i) const -> const Struct& + { + assert(i < m_structs.size()); + return m_structs[i]; + } + + inline std::size_t ShaderAst::GetStructCount() const + { + return m_structs.size(); + } + + inline auto ShaderAst::GetStructs() const -> const std::vector& + { + return m_structs; + } + inline auto ShaderAst::GetUniform(std::size_t i) const -> const Uniform& { assert(i < m_uniforms.size()); diff --git a/include/Nazara/Renderer/ShaderEnums.hpp b/include/Nazara/Renderer/ShaderEnums.hpp index f400c7516..7a93cea7b 100644 --- a/include/Nazara/Renderer/ShaderEnums.hpp +++ b/include/Nazara/Renderer/ShaderEnums.hpp @@ -56,6 +56,11 @@ namespace Nz::ShaderNodes DotProduct }; + enum class MemoryLayout + { + Std140 + }; + enum class NodeType { None = -1, diff --git a/include/Nazara/Renderer/ShaderSerializer.hpp b/include/Nazara/Renderer/ShaderSerializer.hpp index eac0c2bf8..f79040b2c 100644 --- a/include/Nazara/Renderer/ShaderSerializer.hpp +++ b/include/Nazara/Renderer/ShaderSerializer.hpp @@ -11,13 +11,12 @@ #include #include #include +#include #include #include namespace Nz { - class ShaderAst; - class NAZARA_RENDERER_API ShaderSerializerBase { public: @@ -44,6 +43,7 @@ namespace Nz protected: template void Container(T& container); template void Enum(T& enumVal); + template void OptEnum(std::optional& optVal); template void OptVal(std::optional& optVal); virtual bool IsWriting() const = 0; @@ -57,6 +57,8 @@ namespace Nz virtual void Value(Vector2f& val) = 0; virtual void Value(Vector3f& val) = 0; virtual void Value(Vector4f& val) = 0; + virtual void Value(UInt8& val) = 0; + virtual void Value(UInt16& val) = 0; virtual void Value(UInt32& val) = 0; inline void Value(std::size_t& val); @@ -82,6 +84,8 @@ namespace Nz void Value(Vector2f& val) override; void Value(Vector3f& val) override; void Value(Vector4f& val) override; + void Value(UInt8& val) override; + void Value(UInt16& val) override; void Value(UInt32& val) override; void Variable(ShaderNodes::VariablePtr& var) override; @@ -99,12 +103,15 @@ namespace Nz private: bool IsWriting() const override; void Node(ShaderNodes::NodePtr& node) override; + void Type(ShaderAst::Type& type); void Value(bool& val) override; void Value(float& val) override; void Value(std::string& val) override; void Value(Vector2f& val) override; void Value(Vector3f& val) override; void Value(Vector4f& val) override; + void Value(UInt8& val) override; + void Value(UInt16& val) override; void Value(UInt32& val) override; void Variable(ShaderNodes::VariablePtr& var) override; diff --git a/include/Nazara/Renderer/ShaderSerializer.inl b/include/Nazara/Renderer/ShaderSerializer.inl index 0daeb6653..51187d520 100644 --- a/include/Nazara/Renderer/ShaderSerializer.inl +++ b/include/Nazara/Renderer/ShaderSerializer.inl @@ -36,6 +36,24 @@ namespace Nz enumVal = static_cast(value); } + template + void ShaderSerializerBase::OptEnum(std::optional& optVal) + { + bool isWriting = IsWriting(); + + bool hasValue; + if (isWriting) + hasValue = optVal.has_value(); + + Value(hasValue); + + if (!isWriting && hasValue) + optVal.emplace(); + + if (optVal.has_value()) + Enum(optVal.value()); + } + template void ShaderSerializerBase::OptVal(std::optional& optVal) { diff --git a/include/Nazara/Renderer/ShaderValidator.hpp b/include/Nazara/Renderer/ShaderValidator.hpp index bfdab9844..3df9f4ae5 100644 --- a/include/Nazara/Renderer/ShaderValidator.hpp +++ b/include/Nazara/Renderer/ShaderValidator.hpp @@ -11,12 +11,11 @@ #include #include #include +#include #include namespace Nz { - class ShaderAst; - class NAZARA_RENDERER_API ShaderValidator : public ShaderVisitor { public: @@ -31,7 +30,7 @@ namespace Nz const ShaderNodes::ExpressionPtr& MandatoryExpr(const ShaderNodes::ExpressionPtr& node); const ShaderNodes::NodePtr& MandatoryNode(const ShaderNodes::NodePtr& node); void TypeMustMatch(const ShaderNodes::ExpressionPtr& left, const ShaderNodes::ExpressionPtr& right); - void TypeMustMatch(ShaderNodes::ExpressionType left, ShaderNodes::ExpressionType right); + void TypeMustMatch(const ShaderAst::Type& left, const ShaderAst::Type& right); using ShaderVisitor::Visit; void Visit(const ShaderNodes::AssignOp& node) override; diff --git a/src/Nazara/Renderer/GlslWriter.cpp b/src/Nazara/Renderer/GlslWriter.cpp index 61dc030da..accb493b7 100644 --- a/src/Nazara/Renderer/GlslWriter.cpp +++ b/src/Nazara/Renderer/GlslWriter.cpp @@ -108,13 +108,35 @@ namespace Nz AppendLine(); } + // Structures + /*if (shader.GetStructCount() > 0) + { + AppendCommentSection("Structures"); + for (const auto& s : shader.GetStructs()) + { + Append("struct "); + AppendLine(s.name); + AppendLine("{"); + for (const auto& m : s.members) + { + Append("\t"); + Append(m.type); + Append(" "); + Append(m.name); + AppendLine(";"); + } + AppendLine("};"); + AppendLine(); + } + }*/ + // Global variables (uniforms, input and outputs) const char* inKeyword = (glslVersion >= 130) ? "in" : "varying"; const char* outKeyword = (glslVersion >= 130) ? "out" : "varying"; - DeclareVariables(shader.GetUniforms(), "uniform", "Uniforms"); - DeclareVariables(shader.GetInputs(), inKeyword, "Inputs"); - DeclareVariables(shader.GetOutputs(), outKeyword, "Outputs"); + DeclareVariables(shader, shader.GetUniforms(), "uniform", "Uniforms"); + DeclareVariables(shader, shader.GetInputs(), inKeyword, "Inputs"); + DeclareVariables(shader, shader.GetOutputs(), outKeyword, "Outputs"); std::size_t functionCount = shader.GetFunctionCount(); if (functionCount > 1) @@ -141,6 +163,14 @@ namespace Nz m_environment = std::move(environment); } + void GlslWriter::Append(ShaderAst::Type type) + { + std::visit([&](auto&& arg) + { + Append(arg); + }, type); + } + void GlslWriter::Append(ShaderNodes::BuiltinEntry builtin) { switch (builtin) @@ -182,6 +212,16 @@ namespace Nz } } + void GlslWriter::Append(ShaderNodes::MemoryLayout layout) + { + switch (layout) + { + case ShaderNodes::MemoryLayout::Std140: + Append("std140"); + break; + } + } + void GlslWriter::AppendCommentSection(const std::string& section) { NazaraAssert(m_currentState, "This function should only be called while processing an AST"); diff --git a/src/Nazara/Renderer/ShaderAst.cpp b/src/Nazara/Renderer/ShaderAst.cpp index a52cca657..05d3eb94d 100644 --- a/src/Nazara/Renderer/ShaderAst.cpp +++ b/src/Nazara/Renderer/ShaderAst.cpp @@ -16,27 +16,35 @@ namespace Nz functionEntry.statement = std::move(statement); } - void ShaderAst::AddInput(std::string name, ShaderNodes::ExpressionType type, std::optional locationIndex) + void ShaderAst::AddInput(std::string name, Type type, std::optional locationIndex) { auto& inputEntry = m_inputs.emplace_back(); inputEntry.name = std::move(name); inputEntry.locationIndex = std::move(locationIndex); - inputEntry.type = type; + inputEntry.type = std::move(type); } - void ShaderAst::AddOutput(std::string name, ShaderNodes::ExpressionType type, std::optional locationIndex) + void ShaderAst::AddOutput(std::string name, Type type, std::optional locationIndex) { auto& outputEntry = m_outputs.emplace_back(); outputEntry.name = std::move(name); outputEntry.locationIndex = std::move(locationIndex); - outputEntry.type = type; + outputEntry.type = std::move(type); } - void ShaderAst::AddUniform(std::string name, ShaderNodes::ExpressionType type, std::optional bindingIndex) + void ShaderAst::AddStruct(std::string name, std::vector members) + { + auto& structEntry = m_structs.emplace_back(); + structEntry.name = std::move(name); + structEntry.members = std::move(members); + } + + void ShaderAst::AddUniform(std::string name, Type type, std::optional bindingIndex, std::optional memoryLayout) { auto& uniformEntry = m_uniforms.emplace_back(); uniformEntry.bindingIndex = std::move(bindingIndex); + uniformEntry.memoryLayout = std::move(memoryLayout); uniformEntry.name = std::move(name); - uniformEntry.type = type; + uniformEntry.type = std::move(type); } } diff --git a/src/Nazara/Renderer/ShaderSerializer.cpp b/src/Nazara/Renderer/ShaderSerializer.cpp index f97186acf..9cf7c47ff 100644 --- a/src/Nazara/Renderer/ShaderSerializer.cpp +++ b/src/Nazara/Renderer/ShaderSerializer.cpp @@ -3,7 +3,6 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include -#include #include #include #include @@ -250,12 +249,33 @@ namespace Nz { m_stream << s_magicNumber << s_currentVersion; + auto SerializeType = [&](const ShaderAst::Type& type) + { + std::visit([&](auto&& arg) + { + using T = std::decay_t; + if constexpr (std::is_same_v) + { + m_stream << UInt8(0); + m_stream << UInt32(arg); + } + else if constexpr (std::is_same_v) + { + m_stream << UInt8(1); + m_stream << arg; + } + else + static_assert(AlwaysFalse::value, "non-exhaustive visitor"); + }, type); + }; + auto SerializeInputOutput = [&](auto& inout) { m_stream << UInt32(inout.size()); for (const auto& data : inout) { - m_stream << data.name << UInt32(data.type); + m_stream << data.name; + SerializeType(data.type); m_stream << data.locationIndex.has_value(); if (data.locationIndex) @@ -263,17 +283,34 @@ namespace Nz } }; + m_stream << UInt32(shader.GetStructCount()); + for (const auto& s : shader.GetStructs()) + { + m_stream << s.name; + m_stream << UInt32(s.members.size()); + for (const auto& member : s.members) + { + m_stream << member.name; + SerializeType(member.type); + } + } + SerializeInputOutput(shader.GetInputs()); SerializeInputOutput(shader.GetOutputs()); m_stream << UInt32(shader.GetUniformCount()); for (const auto& uniform : shader.GetUniforms()) { - m_stream << uniform.name << UInt32(uniform.type); + m_stream << uniform.name; + SerializeType(uniform.type); m_stream << uniform.bindingIndex.has_value(); if (uniform.bindingIndex) m_stream << UInt32(uniform.bindingIndex.value()); + + m_stream << uniform.memoryLayout.has_value(); + if (uniform.memoryLayout) + m_stream << UInt32(uniform.memoryLayout.value()); } m_stream << UInt32(shader.GetFunctionCount()); @@ -283,7 +320,10 @@ namespace Nz m_stream << UInt32(func.parameters.size()); for (const auto& param : func.parameters) - m_stream << param.name << UInt32(param.type); + { + m_stream << param.name; + SerializeType(param.type); + } Node(func.statement); } @@ -343,6 +383,16 @@ namespace Nz m_stream << val; } + void ShaderSerializer::Value(UInt8& val) + { + m_stream << val; + } + + void ShaderSerializer::Value(UInt16& val) + { + m_stream << val; + } + void ShaderSerializer::Value(UInt32& val) { m_stream << val; @@ -374,19 +424,38 @@ namespace Nz ShaderAst shader; + UInt32 structCount; + m_stream >> structCount; + for (UInt32 i = 0; i < structCount; ++i) + { + std::string structName; + std::vector members; + + Value(structName); + Container(members); + + for (auto& member : members) + { + Value(member.name); + Type(member.type); + } + + shader.AddStruct(std::move(structName), std::move(members)); + } + UInt32 inputCount; m_stream >> inputCount; for (UInt32 i = 0; i < inputCount; ++i) { std::string inputName; - ShaderNodes::ExpressionType inputType; + ShaderAst::Type inputType; std::optional location; Value(inputName); - Enum(inputType); + Type(inputType); OptVal(location); - shader.AddInput(std::move(inputName), inputType, location); + shader.AddInput(std::move(inputName), std::move(inputType), location); } UInt32 outputCount; @@ -394,14 +463,14 @@ namespace Nz for (UInt32 i = 0; i < outputCount; ++i) { std::string outputName; - ShaderNodes::ExpressionType outputType; + ShaderAst::Type outputType; std::optional location; Value(outputName); - Enum(outputType); + Type(outputType); OptVal(location); - shader.AddOutput(std::move(outputName), outputType, location); + shader.AddOutput(std::move(outputName), std::move(outputType), location); } UInt32 uniformCount; @@ -409,14 +478,16 @@ namespace Nz for (UInt32 i = 0; i < uniformCount; ++i) { std::string name; - ShaderNodes::ExpressionType type; + ShaderAst::Type type; std::optional binding; + std::optional memLayout; Value(name); - Enum(type); + Type(type); OptVal(binding); + OptEnum(memLayout); - shader.AddUniform(std::move(name), type, binding); + shader.AddUniform(std::move(name), std::move(type), std::move(binding), std::move(memLayout)); } UInt32 funcCount; @@ -433,7 +504,7 @@ namespace Nz for (auto& param : parameters) { Value(param.name); - Enum(param.type); + Type(param.type); } ShaderNodes::NodePtr node; @@ -489,6 +560,36 @@ namespace Nz } } + void ShaderUnserializer::Type(ShaderAst::Type& type) + { + UInt8 typeIndex; + Value(typeIndex); + + switch (typeIndex) + { + case 0: //< Primitive + { + ShaderNodes::ExpressionType exprType; + Enum(exprType); + + type = exprType; + break; + } + + case 1: //< Struct (name) + { + std::string structName; + Value(structName); + + type = std::move(structName); + break; + } + + default: + break; + } + } + void ShaderUnserializer::Value(bool& val) { m_stream >> val; @@ -519,6 +620,16 @@ namespace Nz m_stream >> val; } + void ShaderUnserializer::Value(UInt8& val) + { + m_stream >> val; + } + + void ShaderUnserializer::Value(UInt16& val) + { + m_stream >> val; + } + void ShaderUnserializer::Value(UInt32& val) { m_stream >> val; diff --git a/src/Nazara/Renderer/ShaderValidator.cpp b/src/Nazara/Renderer/ShaderValidator.cpp index aab559a61..37eecb767 100644 --- a/src/Nazara/Renderer/ShaderValidator.cpp +++ b/src/Nazara/Renderer/ShaderValidator.cpp @@ -77,7 +77,7 @@ namespace Nz return TypeMustMatch(left->GetExpressionType(), right->GetExpressionType()); } - void ShaderValidator::TypeMustMatch(ShaderNodes::ExpressionType left, ShaderNodes::ExpressionType right) + void ShaderValidator::TypeMustMatch(const ShaderAst::Type& left, const ShaderAst::Type& right) { if (left != right) throw AstError{ "Left expression type must match right expression type" }; From c7a8091e68d0f2225163e0ed333867a8439deee1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Tue, 14 Jul 2020 22:00:17 +0200 Subject: [PATCH 053/105] ShaderNode: Add buffers and structs --- src/ShaderNode/DataModels/InputValue.cpp | 18 +- src/ShaderNode/DataModels/OutputValue.cpp | 16 +- src/ShaderNode/Enums.cpp | 35 ++- src/ShaderNode/Enums.hpp | 18 +- src/ShaderNode/Previews/PreviewValues.inl | 4 +- src/ShaderNode/ShaderGraph.cpp | 170 ++++++++++++- src/ShaderNode/ShaderGraph.hpp | 53 ++++- src/ShaderNode/ShaderGraph.inl | 32 +++ src/ShaderNode/Widgets/BufferEditDialog.cpp | 88 +++++++ src/ShaderNode/Widgets/BufferEditDialog.hpp | 43 ++++ src/ShaderNode/Widgets/BufferEditDialog.inl | 1 + src/ShaderNode/Widgets/BufferEditor.cpp | 85 +++++++ src/ShaderNode/Widgets/BufferEditor.hpp | 36 +++ src/ShaderNode/Widgets/BufferEditor.inl | 1 + src/ShaderNode/Widgets/InputEditDialog.cpp | 6 +- src/ShaderNode/Widgets/InputEditDialog.hpp | 2 +- src/ShaderNode/Widgets/MainWindow.cpp | 63 ++++- src/ShaderNode/Widgets/OutputEditDialog.cpp | 6 +- src/ShaderNode/Widgets/OutputEditDialog.hpp | 2 +- src/ShaderNode/Widgets/StructEditDialog.cpp | 224 ++++++++++++++++++ src/ShaderNode/Widgets/StructEditDialog.hpp | 59 +++++ src/ShaderNode/Widgets/StructEditDialog.inl | 1 + src/ShaderNode/Widgets/StructEditor.cpp | 107 +++++++++ src/ShaderNode/Widgets/StructEditor.hpp | 37 +++ src/ShaderNode/Widgets/StructEditor.inl | 1 + .../Widgets/StructMemberEditDialog.cpp | 86 +++++++ .../Widgets/StructMemberEditDialog.hpp | 39 +++ .../Widgets/StructMemberEditDialog.inl | 1 + 28 files changed, 1169 insertions(+), 65 deletions(-) create mode 100644 src/ShaderNode/Widgets/BufferEditDialog.cpp create mode 100644 src/ShaderNode/Widgets/BufferEditDialog.hpp create mode 100644 src/ShaderNode/Widgets/BufferEditDialog.inl create mode 100644 src/ShaderNode/Widgets/BufferEditor.cpp create mode 100644 src/ShaderNode/Widgets/BufferEditor.hpp create mode 100644 src/ShaderNode/Widgets/BufferEditor.inl create mode 100644 src/ShaderNode/Widgets/StructEditDialog.cpp create mode 100644 src/ShaderNode/Widgets/StructEditDialog.hpp create mode 100644 src/ShaderNode/Widgets/StructEditDialog.inl create mode 100644 src/ShaderNode/Widgets/StructEditor.cpp create mode 100644 src/ShaderNode/Widgets/StructEditor.hpp create mode 100644 src/ShaderNode/Widgets/StructEditor.inl create mode 100644 src/ShaderNode/Widgets/StructMemberEditDialog.cpp create mode 100644 src/ShaderNode/Widgets/StructMemberEditDialog.hpp create mode 100644 src/ShaderNode/Widgets/StructMemberEditDialog.inl diff --git a/src/ShaderNode/DataModels/InputValue.cpp b/src/ShaderNode/DataModels/InputValue.cpp index e0b117e83..a5a3a269b 100644 --- a/src/ShaderNode/DataModels/InputValue.cpp +++ b/src/ShaderNode/DataModels/InputValue.cpp @@ -120,11 +120,11 @@ Nz::ShaderNodes::ExpressionPtr InputValue::GetExpression(Nz::ShaderNodes::Expres { switch (inputEntry.type) { - case InOutType::Bool: return Nz::ShaderNodes::ExpressionType::Boolean; - case InOutType::Float1: return Nz::ShaderNodes::ExpressionType::Float1; - case InOutType::Float2: return Nz::ShaderNodes::ExpressionType::Float2; - case InOutType::Float3: return Nz::ShaderNodes::ExpressionType::Float3; - case InOutType::Float4: return Nz::ShaderNodes::ExpressionType::Float4; + case PrimitiveType::Bool: return Nz::ShaderNodes::ExpressionType::Boolean; + case PrimitiveType::Float1: return Nz::ShaderNodes::ExpressionType::Float1; + case PrimitiveType::Float2: return Nz::ShaderNodes::ExpressionType::Float2; + case PrimitiveType::Float3: return Nz::ShaderNodes::ExpressionType::Float3; + case PrimitiveType::Float4: return Nz::ShaderNodes::ExpressionType::Float4; } assert(false); @@ -146,12 +146,12 @@ auto InputValue::dataType(QtNodes::PortType portType, QtNodes::PortIndex portInd switch (inputEntry.type) { //case InputType::Bool: return Nz::ShaderNodes::ExpressionType::Boolean; - case InOutType::Float1: + case PrimitiveType::Float1: return FloatData::Type(); - case InOutType::Float2: - case InOutType::Float3: - case InOutType::Float4: + case PrimitiveType::Float2: + case PrimitiveType::Float3: + case PrimitiveType::Float4: return VecData::Type(); } diff --git a/src/ShaderNode/DataModels/OutputValue.cpp b/src/ShaderNode/DataModels/OutputValue.cpp index a6b644be3..1f65c5953 100644 --- a/src/ShaderNode/DataModels/OutputValue.cpp +++ b/src/ShaderNode/DataModels/OutputValue.cpp @@ -67,11 +67,11 @@ Nz::ShaderNodes::ExpressionPtr OutputValue::GetExpression(Nz::ShaderNodes::Expre { switch (outputEntry.type) { - case InOutType::Bool: return Nz::ShaderNodes::ExpressionType::Boolean; - case InOutType::Float1: return Nz::ShaderNodes::ExpressionType::Float1; - case InOutType::Float2: return Nz::ShaderNodes::ExpressionType::Float2; - case InOutType::Float3: return Nz::ShaderNodes::ExpressionType::Float3; - case InOutType::Float4: return Nz::ShaderNodes::ExpressionType::Float4; + case PrimitiveType::Bool: return Nz::ShaderNodes::ExpressionType::Boolean; + case PrimitiveType::Float1: return Nz::ShaderNodes::ExpressionType::Float1; + case PrimitiveType::Float2: return Nz::ShaderNodes::ExpressionType::Float2; + case PrimitiveType::Float3: return Nz::ShaderNodes::ExpressionType::Float3; + case PrimitiveType::Float4: return Nz::ShaderNodes::ExpressionType::Float4; } assert(false); @@ -96,9 +96,9 @@ QtNodes::NodeDataType OutputValue::dataType(QtNodes::PortType portType, QtNodes: { //case InOutType::Bool: return Nz::ShaderNodes::ExpressionType::Boolean; //case InOutType::Float1: return Nz::ShaderNodes::ExpressionType::Float1; - case InOutType::Float2: - case InOutType::Float3: - case InOutType::Float4: + case PrimitiveType::Float2: + case PrimitiveType::Float3: + case PrimitiveType::Float4: return VecData::Type(); } diff --git a/src/ShaderNode/Enums.cpp b/src/ShaderNode/Enums.cpp index 1f756b8de..610078d65 100644 --- a/src/ShaderNode/Enums.cpp +++ b/src/ShaderNode/Enums.cpp @@ -1,21 +1,32 @@ #include #include -std::size_t GetComponentCount(InOutType type) +std::size_t GetComponentCount(PrimitiveType type) { switch (type) { - case InOutType::Bool: return 1; - case InOutType::Float1: return 1; - case InOutType::Float2: return 2; - case InOutType::Float3: return 3; - case InOutType::Float4: return 4; + case PrimitiveType::Bool: return 1; + case PrimitiveType::Float1: return 1; + case PrimitiveType::Float2: return 2; + case PrimitiveType::Float3: return 3; + case PrimitiveType::Float4: return 4; } assert(false); return 0; } +const char* EnumToString(BufferType bufferType) +{ + switch (bufferType) + { + case BufferType::UniformBufferObject: return "UniformBufferObject"; + } + + assert(false); + return ""; +} + const char* EnumToString(InputRole role) { switch (role) @@ -30,15 +41,15 @@ const char* EnumToString(InputRole role) return ""; } -const char* EnumToString(InOutType input) +const char* EnumToString(PrimitiveType input) { switch (input) { - case InOutType::Bool: return "Bool"; - case InOutType::Float1: return "Float"; - case InOutType::Float2: return "Float2"; - case InOutType::Float3: return "Float3"; - case InOutType::Float4: return "Float4"; + case PrimitiveType::Bool: return "Bool"; + case PrimitiveType::Float1: return "Float"; + case PrimitiveType::Float2: return "Float2"; + case PrimitiveType::Float3: return "Float3"; + case PrimitiveType::Float4: return "Float4"; } assert(false); diff --git a/src/ShaderNode/Enums.hpp b/src/ShaderNode/Enums.hpp index 72a5443f7..41e8f4360 100644 --- a/src/ShaderNode/Enums.hpp +++ b/src/ShaderNode/Enums.hpp @@ -7,6 +7,15 @@ #include #include +enum class BufferType +{ + UniformBufferObject, + + Max = UniformBufferObject +}; + +constexpr std::size_t BufferTypeCount = static_cast(BufferType::Max) + 1; + enum class InputRole { None, @@ -19,7 +28,7 @@ enum class InputRole constexpr std::size_t InputRoleCount = static_cast(InputRole::Max) + 1; -enum class InOutType +enum class PrimitiveType { Bool, Float1, @@ -30,7 +39,7 @@ enum class InOutType Max = Float4 }; -constexpr std::size_t InOutTypeCount = static_cast(InOutType::Max) + 1; +constexpr std::size_t PrimitiveTypeCount = static_cast(PrimitiveType::Max) + 1; enum class TextureType { @@ -43,10 +52,11 @@ constexpr std::size_t TextureTypeCount = static_cast(TextureType::M template std::optional DecodeEnum(const std::string_view& str); +const char* EnumToString(BufferType bufferType); const char* EnumToString(InputRole role); -const char* EnumToString(InOutType input); +const char* EnumToString(PrimitiveType input); const char* EnumToString(TextureType textureType); -std::size_t GetComponentCount(InOutType type); +std::size_t GetComponentCount(PrimitiveType type); #include diff --git a/src/ShaderNode/Previews/PreviewValues.inl b/src/ShaderNode/Previews/PreviewValues.inl index 06ca202ec..3efbebc39 100644 --- a/src/ShaderNode/Previews/PreviewValues.inl +++ b/src/ShaderNode/Previews/PreviewValues.inl @@ -12,10 +12,10 @@ inline const Nz::Vector4f* PreviewValues::GetData() const inline std::size_t PreviewValues::GetHeight() const { - return m_width; + return m_height; } inline std::size_t PreviewValues::GetWidth() const { - return m_height; + return m_width; } diff --git a/src/ShaderNode/ShaderGraph.cpp b/src/ShaderNode/ShaderGraph.cpp index 5788e1f8b..3648fed82 100644 --- a/src/ShaderNode/ShaderGraph.cpp +++ b/src/ShaderNode/ShaderGraph.cpp @@ -46,9 +46,23 @@ m_flowScene(BuildRegistry()) }); // Test - AddInput("UV", InOutType::Float2, InputRole::TexCoord, 0, 0); - AddOutput("RenderTarget0", InOutType::Float4, 0); + AddInput("UV", PrimitiveType::Float2, InputRole::TexCoord, 0, 0); + AddOutput("RenderTarget0", PrimitiveType::Float4, 0); AddTexture("Potato", TextureType::Sampler2D, 1); + AddStruct("TestStruct", { + { + { "position", PrimitiveType::Float3 }, + { "normal", PrimitiveType::Float3 }, + { "uv", PrimitiveType::Float2 }, + } + }); + AddStruct("TestStruct2", { + { + { "position", PrimitiveType::Float3 }, + { "normal", PrimitiveType::Float3 }, + { "uv", PrimitiveType::Float2 }, + } + }); UpdateTexturePreview(0, QImage(R"(C:\Users\Lynix\Pictures\potatavril.png)")); @@ -79,7 +93,21 @@ ShaderGraph::~ShaderGraph() m_flowScene.clearScene(); } -std::size_t ShaderGraph::AddInput(std::string name, InOutType type, InputRole role, std::size_t roleIndex, std::size_t locationIndex) +std::size_t ShaderGraph::AddBuffer(std::string name, BufferType bufferType, std::size_t structIndex, std::size_t bindingIndex) +{ + std::size_t index = m_buffers.size(); + auto& bufferEntry = m_buffers.emplace_back(); + bufferEntry.bindingIndex = bindingIndex; + bufferEntry.name = std::move(name); + bufferEntry.structIndex = structIndex; + bufferEntry.type = bufferType; + + OnBufferListUpdate(this); + + return index; +} + +std::size_t ShaderGraph::AddInput(std::string name, PrimitiveType type, InputRole role, std::size_t roleIndex, std::size_t locationIndex) { std::size_t index = m_inputs.size(); auto& inputEntry = m_inputs.emplace_back(); @@ -94,7 +122,7 @@ std::size_t ShaderGraph::AddInput(std::string name, InOutType type, InputRole ro return index; } -std::size_t ShaderGraph::AddOutput(std::string name, InOutType type, std::size_t locationIndex) +std::size_t ShaderGraph::AddOutput(std::string name, PrimitiveType type, std::size_t locationIndex) { std::size_t index = m_outputs.size(); auto& outputEntry = m_outputs.emplace_back(); @@ -107,6 +135,18 @@ std::size_t ShaderGraph::AddOutput(std::string name, InOutType type, std::size_t return index; } +std::size_t ShaderGraph::AddStruct(std::string name, std::vector members) +{ + std::size_t index = m_structs.size(); + auto& structEntry = m_structs.emplace_back(); + structEntry.name = std::move(name); + structEntry.members = std::move(members); + + OnStructListUpdate(this); + + return index; +} + std::size_t ShaderGraph::AddTexture(std::string name, TextureType type, std::size_t bindingIndex) { std::size_t index = m_textures.size(); @@ -125,11 +165,15 @@ void ShaderGraph::Clear() m_flowScene.clearScene(); m_flowScene.clear(); + m_buffers.clear(); m_inputs.clear(); + m_structs.clear(); m_outputs.clear(); m_textures.clear(); + OnBufferListUpdate(this); OnInputListUpdate(this); + OnStructListUpdate(this); OnOutputListUpdate(this); OnTextureListUpdate(this); } @@ -138,6 +182,20 @@ void ShaderGraph::Load(const QJsonObject& data) { Clear(); + QJsonArray bufferArray = data["buffers"].toArray(); + for (const auto& bufferDocRef : bufferArray) + { + QJsonObject bufferDoc = bufferDocRef.toObject(); + + BufferEntry& buffer = m_buffers.emplace_back(); + buffer.bindingIndex = static_cast(bufferDoc["bindingIndex"].toInt(0)); + buffer.name = bufferDoc["name"].toString().toStdString(); + buffer.structIndex = bufferDoc["structIndex"].toInt(); + buffer.type = DecodeEnum(bufferDoc["type"].toString().toStdString()).value(); + } + + OnBufferListUpdate(this); + QJsonArray inputArray = data["inputs"].toArray(); for (const auto& inputDocRef : inputArray) { @@ -148,7 +206,7 @@ void ShaderGraph::Load(const QJsonObject& data) input.name = inputDoc["name"].toString().toStdString(); input.role = DecodeEnum(inputDoc["role"].toString().toStdString()).value(); input.roleIndex = static_cast(inputDoc["roleIndex"].toInt(0)); - input.type = DecodeEnum(inputDoc["type"].toString().toStdString()).value(); + input.type = DecodeEnum(inputDoc["type"].toString().toStdString()).value(); } OnInputListUpdate(this); @@ -161,11 +219,37 @@ void ShaderGraph::Load(const QJsonObject& data) OutputEntry& output = m_outputs.emplace_back(); output.locationIndex = static_cast(outputDoc["locationIndex"].toInt(0)); output.name = outputDoc["name"].toString().toStdString(); - output.type = DecodeEnum(outputDoc["type"].toString().toStdString()).value(); + output.type = DecodeEnum(outputDoc["type"].toString().toStdString()).value(); } OnOutputListUpdate(this); + QJsonArray structArray = data["structs"].toArray(); + for (const auto& structDocRef : structArray) + { + QJsonObject structDoc = structDocRef.toObject(); + + StructEntry& structInfo = m_structs.emplace_back(); + structInfo.name = structDoc["name"].toString().toStdString(); + + QJsonArray memberArray = structDoc["members"].toArray(); + for (const auto& memberDocRef : memberArray) + { + QJsonObject memberDoc = memberDocRef.toObject(); + + auto& memberInfo = structInfo.members.emplace_back(); + memberInfo.name = memberDoc["name"].toString().toStdString(); + + const auto& typeDocRef = memberDoc["type"]; + if (typeDocRef.isString()) + memberInfo.type = DecodeEnum(typeDocRef.toString().toStdString()).value(); + else + memberInfo.type = typeDocRef.toInt(); + } + } + + OnStructListUpdate(this); + QJsonArray textureArray = data["textures"].toArray(); for (const auto& textureDocRef : textureArray) { @@ -190,6 +274,21 @@ QJsonObject ShaderGraph::Save() { QJsonObject sceneJson; + QJsonArray bufferArray; + { + for (const auto& buffer : m_buffers) + { + QJsonObject bufferDoc; + bufferDoc["bindingIndex"] = int(buffer.bindingIndex); + bufferDoc["name"] = QString::fromStdString(buffer.name); + bufferDoc["structIndex"] = int(buffer.structIndex); + bufferDoc["type"] = QString(EnumToString(buffer.type)); + + bufferArray.append(bufferDoc); + } + } + sceneJson["buffers"] = bufferArray; + QJsonArray inputArray; { for (const auto& input : m_inputs) @@ -220,6 +319,39 @@ QJsonObject ShaderGraph::Save() } sceneJson["outputs"] = outputArray; + QJsonArray structArray; + { + for (const auto& s : m_structs) + { + QJsonObject structDoc; + structDoc["name"] = QString::fromStdString(s.name); + + QJsonArray memberArray; + for (const auto& member : s.members) + { + QJsonObject memberDoc; + memberDoc["name"] = QString::fromStdString(member.name); + + std::visit([&](auto&& arg) + { + using T = std::decay_t; + if constexpr (std::is_same_v) + memberDoc["type"] = QString(EnumToString(arg)); + else if constexpr (std::is_same_v) + memberDoc["type"] = int(arg); + else + static_assert(AlwaysFalse::value, "non-exhaustive visitor"); + }, member.type); + + memberDoc["type"] = QString::fromStdString(member.name); + } + structDoc["members"] = memberArray; + + structArray.append(structDoc); + } + } + sceneJson["structs"] = structArray; + QJsonArray textureArray; { for (const auto& texture : m_textures) @@ -366,7 +498,19 @@ Nz::ShaderNodes::StatementPtr ShaderGraph::ToAst() return Nz::ShaderNodes::StatementBlock::Build(std::move(statements)); } -void ShaderGraph::UpdateInput(std::size_t inputIndex, std::string name, InOutType type, InputRole role, std::size_t roleIndex, std::size_t locationIndex) +void ShaderGraph::UpdateBuffer(std::size_t bufferIndex, std::string name, BufferType bufferType, std::size_t structIndex, std::size_t bindingIndex) +{ + assert(bufferIndex < m_buffers.size()); + auto& bufferEntry = m_buffers[bufferIndex]; + bufferEntry.bindingIndex = bindingIndex; + bufferEntry.name = std::move(name); + bufferEntry.structIndex = structIndex; + bufferEntry.type = bufferType; + + OnBufferUpdate(this, bufferIndex); +} + +void ShaderGraph::UpdateInput(std::size_t inputIndex, std::string name, PrimitiveType type, InputRole role, std::size_t roleIndex, std::size_t locationIndex) { assert(inputIndex < m_inputs.size()); auto& inputEntry = m_inputs[inputIndex]; @@ -379,7 +523,7 @@ void ShaderGraph::UpdateInput(std::size_t inputIndex, std::string name, InOutTyp OnInputUpdate(this, inputIndex); } -void ShaderGraph::UpdateOutput(std::size_t outputIndex, std::string name, InOutType type, std::size_t locationIndex) +void ShaderGraph::UpdateOutput(std::size_t outputIndex, std::string name, PrimitiveType type, std::size_t locationIndex) { assert(outputIndex < m_outputs.size()); auto& outputEntry = m_outputs[outputIndex]; @@ -390,6 +534,16 @@ void ShaderGraph::UpdateOutput(std::size_t outputIndex, std::string name, InOutT OnOutputUpdate(this, outputIndex); } +void ShaderGraph::UpdateStruct(std::size_t structIndex, std::string name, std::vector members) +{ + assert(structIndex < m_structs.size()); + auto& structEntry = m_structs[structIndex]; + structEntry.name = std::move(name); + structEntry.members = std::move(members); + + OnStructUpdate(this, structIndex); +} + void ShaderGraph::UpdateTexture(std::size_t textureIndex, std::string name, TextureType type, std::size_t bindingIndex) { assert(textureIndex < m_textures.size()); diff --git a/src/ShaderNode/ShaderGraph.hpp b/src/ShaderNode/ShaderGraph.hpp index b65694f65..d0ff63316 100644 --- a/src/ShaderNode/ShaderGraph.hpp +++ b/src/ShaderNode/ShaderGraph.hpp @@ -16,25 +16,36 @@ class ShaderNode; class ShaderGraph { public: + struct BufferEntry; struct InputEntry; struct OutputEntry; + struct StructEntry; + struct StructMemberEntry; struct TextureEntry; ShaderGraph(); ~ShaderGraph(); - std::size_t AddInput(std::string name, InOutType type, InputRole role, std::size_t roleIndex, std::size_t locationIndex); - std::size_t AddOutput(std::string name, InOutType type, std::size_t locationIndex); + std::size_t AddBuffer(std::string name, BufferType bufferType, std::size_t structIndex, std::size_t bindingIndex); + std::size_t AddInput(std::string name, PrimitiveType type, InputRole role, std::size_t roleIndex, std::size_t locationIndex); + std::size_t AddOutput(std::string name, PrimitiveType type, std::size_t locationIndex); + std::size_t AddStruct(std::string name, std::vector members); std::size_t AddTexture(std::string name, TextureType type, std::size_t bindingIndex); void Clear(); - inline const InputEntry& GetInput(std::size_t inputIndex) const; + inline const BufferEntry& GetBuffer(std::size_t bufferIndex) const; + inline std::size_t GetBufferCount() const; + inline const std::vector& GetBuffers() const; + inline const InputEntry& GetInput(std::size_t bufferIndex) const; inline std::size_t GetInputCount() const; inline const std::vector& GetInputs() const; inline const OutputEntry& GetOutput(std::size_t outputIndex) const; inline std::size_t GetOutputCount() const; inline const std::vector& GetOutputs() const; + inline const StructEntry& GetStruct(std::size_t structIndex) const; + inline std::size_t GetStructCount() const; + inline const std::vector& GetStructs() const; inline const PreviewModel& GetPreviewModel() const; inline QtNodes::FlowScene& GetScene(); inline const TextureEntry& GetTexture(std::size_t textureIndex) const; @@ -46,25 +57,47 @@ class ShaderGraph Nz::ShaderNodes::StatementPtr ToAst(); - void UpdateInput(std::size_t inputIndex, std::string name, InOutType type, InputRole role, std::size_t roleIndex, std::size_t locationIndex); - void UpdateOutput(std::size_t outputIndex, std::string name, InOutType type, std::size_t locationIndex); + void UpdateBuffer(std::size_t bufferIndex, std::string name, BufferType bufferType, std::size_t structIndex, std::size_t bindingIndex); + void UpdateInput(std::size_t inputIndex, std::string name, PrimitiveType type, InputRole role, std::size_t roleIndex, std::size_t locationIndex); + void UpdateOutput(std::size_t outputIndex, std::string name, PrimitiveType type, std::size_t locationIndex); + void UpdateStruct(std::size_t structIndex, std::string name, std::vector members); void UpdateTexture(std::size_t textureIndex, std::string name, TextureType type, std::size_t bindingIndex); void UpdateTexturePreview(std::size_t texture, QImage preview); + struct BufferEntry + { + std::size_t bindingIndex; + std::size_t structIndex; + std::string name; + BufferType type; + }; + struct InputEntry { std::size_t locationIndex; std::size_t roleIndex; std::string name; InputRole role; - InOutType type; + PrimitiveType type; }; struct OutputEntry { std::size_t locationIndex; std::string name; - InOutType type; + PrimitiveType type; + }; + + struct StructEntry + { + std::string name; + std::vector members; + }; + + struct StructMemberEntry + { + std::string name; + std::variant type; }; struct TextureEntry @@ -75,11 +108,15 @@ class ShaderGraph QImage preview; }; + NazaraSignal(OnBufferListUpdate, ShaderGraph*); + NazaraSignal(OnBufferUpdate, ShaderGraph*, std::size_t /*outputIndex*/); NazaraSignal(OnInputListUpdate, ShaderGraph*); NazaraSignal(OnInputUpdate, ShaderGraph*, std::size_t /*inputIndex*/); NazaraSignal(OnOutputListUpdate, ShaderGraph*); NazaraSignal(OnOutputUpdate, ShaderGraph*, std::size_t /*outputIndex*/); NazaraSignal(OnSelectedNodeUpdate, ShaderGraph*, ShaderNode* /*node*/); + NazaraSignal(OnStructListUpdate, ShaderGraph*); + NazaraSignal(OnStructUpdate, ShaderGraph*, std::size_t /*structIndex*/); NazaraSignal(OnTextureListUpdate, ShaderGraph*); NazaraSignal(OnTexturePreviewUpdate, ShaderGraph*, std::size_t /*textureIndex*/); NazaraSignal(OnTextureUpdate, ShaderGraph*, std::size_t /*textureIndex*/); @@ -88,8 +125,10 @@ class ShaderGraph std::shared_ptr BuildRegistry(); QtNodes::FlowScene m_flowScene; + std::vector m_buffers; std::vector m_inputs; std::vector m_outputs; + std::vector m_structs; std::vector m_textures; std::unique_ptr m_previewModel; }; diff --git a/src/ShaderNode/ShaderGraph.inl b/src/ShaderNode/ShaderGraph.inl index 3f839534c..04f86834c 100644 --- a/src/ShaderNode/ShaderGraph.inl +++ b/src/ShaderNode/ShaderGraph.inl @@ -1,5 +1,21 @@ #include +inline auto ShaderGraph::GetBuffer(std::size_t bufferIndex) const -> const BufferEntry& +{ + assert(bufferIndex < m_buffers.size()); + return m_buffers[bufferIndex]; +} + +inline std::size_t ShaderGraph::GetBufferCount() const +{ + return m_buffers.size(); +} + +inline auto ShaderGraph::GetBuffers() const -> const std::vector& +{ + return m_buffers; +} + inline auto ShaderGraph::GetInput(std::size_t inputIndex) const -> const InputEntry& { assert(inputIndex < m_inputs.size()); @@ -32,6 +48,22 @@ inline auto ShaderGraph::GetOutputs() const -> const std::vector& return m_outputs; } +inline auto ShaderGraph::GetStruct(std::size_t structIndex) const -> const StructEntry& +{ + assert(structIndex < m_structs.size()); + return m_structs[structIndex]; +} + +inline std::size_t ShaderGraph::GetStructCount() const +{ + return m_structs.size(); +} + +inline auto ShaderGraph::GetStructs() const -> const std::vector& +{ + return m_structs; +} + inline const PreviewModel& ShaderGraph::GetPreviewModel() const { return *m_previewModel; diff --git a/src/ShaderNode/Widgets/BufferEditDialog.cpp b/src/ShaderNode/Widgets/BufferEditDialog.cpp new file mode 100644 index 000000000..3f08ca2fa --- /dev/null +++ b/src/ShaderNode/Widgets/BufferEditDialog.cpp @@ -0,0 +1,88 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +BufferEditDialog::BufferEditDialog(const ShaderGraph& shaderGraph, QWidget* parent) : +QDialog(parent), +m_shaderGraph(shaderGraph) +{ + setWindowTitle(tr("Buffer edit dialog")); + setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); + + m_outputName = new QLineEdit; + + m_typeList = new QComboBox; + for (std::size_t i = 0; i < BufferTypeCount; ++i) + m_typeList->addItem(EnumToString(static_cast(i))); + + m_structList = new QComboBox; + for (const auto& structEntry : m_shaderGraph.GetStructs()) + m_structList->addItem(QString::fromStdString(structEntry.name)); + + m_bindingIndex = new QSpinBox; + + QFormLayout* formLayout = new QFormLayout; + formLayout->addRow(tr("Name"), m_outputName); + formLayout->addRow(tr("Type"), m_typeList); + formLayout->addRow(tr("Struct"), m_structList); + formLayout->addRow(tr("Binding index"), m_bindingIndex); + + QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); + connect(buttonBox, &QDialogButtonBox::accepted, this, &BufferEditDialog::OnAccept); + connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); + + QVBoxLayout* verticalLayout = new QVBoxLayout; + verticalLayout->addLayout(formLayout); + verticalLayout->addWidget(buttonBox); + + setLayout(verticalLayout); +} + +BufferEditDialog::BufferEditDialog(const ShaderGraph& shaderGraph, const BufferInfo& buffer, QWidget* parent) : +BufferEditDialog(shaderGraph, parent) +{ + m_bindingIndex->setValue(int(buffer.bindingIndex)); + m_outputName->setText(QString::fromStdString(buffer.name)); + m_structList->setCurrentIndex(buffer.structIndex); + m_typeList->setCurrentIndex(int(buffer.type)); +} + +BufferInfo BufferEditDialog::GetBufferInfo() const +{ + BufferInfo bufferInfo; + bufferInfo.bindingIndex = static_cast(m_bindingIndex->value()); + bufferInfo.name = m_outputName->text().toStdString(); + bufferInfo.structIndex = m_structList->currentIndex(); + bufferInfo.type = static_cast(m_typeList->currentIndex()); + + return bufferInfo; +} + +void BufferEditDialog::OnAccept() +{ + if (m_outputName->text().isEmpty()) + { + QMessageBox::critical(this, tr("Empty name"), tr("Buffer name must be set"), QMessageBox::Ok); + return; + } + + if (m_structList->currentIndex() < 0) + { + QMessageBox::critical(this, tr("Invalid struct"), tr("You must select a struct"), QMessageBox::Ok); + return; + } + + if (m_typeList->currentIndex() < 0) + { + QMessageBox::critical(this, tr("Invalid type"), tr("You must select a type"), QMessageBox::Ok); + return; + } + + accept(); +} diff --git a/src/ShaderNode/Widgets/BufferEditDialog.hpp b/src/ShaderNode/Widgets/BufferEditDialog.hpp new file mode 100644 index 000000000..3e5c12e51 --- /dev/null +++ b/src/ShaderNode/Widgets/BufferEditDialog.hpp @@ -0,0 +1,43 @@ +#pragma once + +#ifndef NAZARA_SHADERNODES_BUFFEREDITDIALOG_HPP +#define NAZARA_SHADERNODES_BUFFEREDITDIALOG_HPP + +#include +#include + +class QComboBox; +class QLineEdit; +class QSpinBox; +class ShaderGraph; + +struct BufferInfo +{ + std::size_t bindingIndex; + std::size_t structIndex; + std::string name; + BufferType type; +}; + +class BufferEditDialog : public QDialog +{ + public: + BufferEditDialog(const ShaderGraph& shaderGraph, QWidget* parent = nullptr); + BufferEditDialog(const ShaderGraph& shaderGraph, const BufferInfo& output, QWidget* parent = nullptr); + ~BufferEditDialog() = default; + + BufferInfo GetBufferInfo() const; + + private: + void OnAccept(); + + const ShaderGraph& m_shaderGraph; + QComboBox* m_typeList; + QComboBox* m_structList; + QLineEdit* m_outputName; + QSpinBox* m_bindingIndex; +}; + +#include + +#endif diff --git a/src/ShaderNode/Widgets/BufferEditDialog.inl b/src/ShaderNode/Widgets/BufferEditDialog.inl new file mode 100644 index 000000000..a0add384b --- /dev/null +++ b/src/ShaderNode/Widgets/BufferEditDialog.inl @@ -0,0 +1 @@ +#include diff --git a/src/ShaderNode/Widgets/BufferEditor.cpp b/src/ShaderNode/Widgets/BufferEditor.cpp new file mode 100644 index 000000000..cd795ee09 --- /dev/null +++ b/src/ShaderNode/Widgets/BufferEditor.cpp @@ -0,0 +1,85 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +BufferEditor::BufferEditor(ShaderGraph& graph) : +m_shaderGraph(graph) +{ + m_bufferList = new QListWidget(this); + connect(m_bufferList, &QListWidget::itemDoubleClicked, [this](QListWidgetItem* item) + { + OnEditBuffer(m_bufferList->row(item)); + }); + + QPushButton* addBufferButton = new QPushButton(tr("Add buffer...")); + connect(addBufferButton, &QPushButton::released, this, &BufferEditor::OnAddBuffer); + + m_layout = new QVBoxLayout; + m_layout->addWidget(m_bufferList); + m_layout->addWidget(addBufferButton); + + setLayout(m_layout); + + m_onBufferListUpdateSlot.Connect(m_shaderGraph.OnBufferListUpdate, this, &BufferEditor::OnBufferListUpdate); + m_onBufferUpdateSlot.Connect(m_shaderGraph.OnBufferUpdate, this, &BufferEditor::OnBufferUpdate); + + RefreshBuffers(); +} + +void BufferEditor::OnAddBuffer() +{ + BufferEditDialog* dialog = new BufferEditDialog(m_shaderGraph, this); + dialog->setAttribute(Qt::WA_DeleteOnClose, true); + connect(dialog, &QDialog::accepted, [this, dialog] + { + BufferInfo bufferInfo = dialog->GetBufferInfo(); + m_shaderGraph.AddBuffer(std::move(bufferInfo.name), bufferInfo.type, bufferInfo.structIndex, bufferInfo.bindingIndex); + }); + + dialog->open(); +} + +void BufferEditor::OnEditBuffer(int inputIndex) +{ + const auto& buffer = m_shaderGraph.GetBuffer(inputIndex); + + BufferInfo info; + info.name = buffer.name; + info.structIndex = buffer.structIndex; + info.type = buffer.type; + + BufferEditDialog* dialog = new BufferEditDialog(m_shaderGraph, std::move(info), this); + dialog->setAttribute(Qt::WA_DeleteOnClose, true); + connect(dialog, &QDialog::accepted, [this, dialog, inputIndex] + { + BufferInfo bufferInfo = dialog->GetBufferInfo(); + m_shaderGraph.UpdateBuffer(inputIndex, std::move(bufferInfo.name), bufferInfo.type, bufferInfo.structIndex, bufferInfo.bindingIndex); + }); + + dialog->open(); +} + +void BufferEditor::OnBufferListUpdate(ShaderGraph* /*graph*/) +{ + RefreshBuffers(); +} + +void BufferEditor::OnBufferUpdate(ShaderGraph* /*graph*/, std::size_t bufferIndex) +{ + const auto& bufferEntry = m_shaderGraph.GetBuffer(bufferIndex); + m_bufferList->item(int(bufferIndex))->setText(QString::fromStdString(bufferEntry.name)); +} + +void BufferEditor::RefreshBuffers() +{ + m_bufferList->clear(); + m_bufferList->setCurrentRow(-1); + + for (const auto& bufferEntry : m_shaderGraph.GetBuffers()) + m_bufferList->addItem(QString::fromStdString(bufferEntry.name)); +} diff --git a/src/ShaderNode/Widgets/BufferEditor.hpp b/src/ShaderNode/Widgets/BufferEditor.hpp new file mode 100644 index 000000000..4d97d161b --- /dev/null +++ b/src/ShaderNode/Widgets/BufferEditor.hpp @@ -0,0 +1,36 @@ +#pragma once + +#ifndef NAZARA_SHADERNODES_BUFFEREDITOR_HPP +#define NAZARA_SHADERNODES_BUFFEREDITOR_HPP + +#include +#include + +class QLabel; +class QListWidget; +class QVBoxLayout; + +class BufferEditor : public QWidget +{ + public: + BufferEditor(ShaderGraph& graph); + ~BufferEditor() = default; + + private: + void OnAddBuffer(); + void OnEditBuffer(int inputIndex); + void OnBufferListUpdate(ShaderGraph* graph); + void OnBufferUpdate(ShaderGraph* graph, std::size_t inputIndex); + void RefreshBuffers(); + + NazaraSlot(ShaderGraph, OnBufferListUpdate, m_onBufferListUpdateSlot); + NazaraSlot(ShaderGraph, OnBufferUpdate, m_onBufferUpdateSlot); + + ShaderGraph& m_shaderGraph; + QListWidget* m_bufferList; + QVBoxLayout* m_layout; +}; + +#include + +#endif diff --git a/src/ShaderNode/Widgets/BufferEditor.inl b/src/ShaderNode/Widgets/BufferEditor.inl new file mode 100644 index 000000000..ef7b911cd --- /dev/null +++ b/src/ShaderNode/Widgets/BufferEditor.inl @@ -0,0 +1 @@ +#include diff --git a/src/ShaderNode/Widgets/InputEditDialog.cpp b/src/ShaderNode/Widgets/InputEditDialog.cpp index bd56fd598..45ceed2c6 100644 --- a/src/ShaderNode/Widgets/InputEditDialog.cpp +++ b/src/ShaderNode/Widgets/InputEditDialog.cpp @@ -16,8 +16,8 @@ QDialog(parent) m_inputName = new QLineEdit; m_typeList = new QComboBox; - for (std::size_t i = 0; i < InOutTypeCount; ++i) - m_typeList->addItem(EnumToString(static_cast(i))); + for (std::size_t i = 0; i < PrimitiveTypeCount; ++i) + m_typeList->addItem(EnumToString(static_cast(i))); m_roleList = new QComboBox; for (std::size_t i = 0; i < InputRoleCount; ++i) @@ -62,7 +62,7 @@ InputInfo InputEditDialog::GetInputInfo() const inputInfo.name = m_inputName->text().toStdString(); inputInfo.role = static_cast(m_roleList->currentIndex()); inputInfo.roleIndex = static_cast(m_roleIndex->value()); - inputInfo.type = static_cast(m_typeList->currentIndex()); + inputInfo.type = static_cast(m_typeList->currentIndex()); return inputInfo; } diff --git a/src/ShaderNode/Widgets/InputEditDialog.hpp b/src/ShaderNode/Widgets/InputEditDialog.hpp index 0f6655088..edd7577bf 100644 --- a/src/ShaderNode/Widgets/InputEditDialog.hpp +++ b/src/ShaderNode/Widgets/InputEditDialog.hpp @@ -16,7 +16,7 @@ struct InputInfo std::size_t roleIndex; std::string name; InputRole role; - InOutType type; + PrimitiveType type; }; class InputEditDialog : public QDialog diff --git a/src/ShaderNode/Widgets/MainWindow.cpp b/src/ShaderNode/Widgets/MainWindow.cpp index e76946738..213d190cb 100644 --- a/src/ShaderNode/Widgets/MainWindow.cpp +++ b/src/ShaderNode/Widgets/MainWindow.cpp @@ -3,9 +3,11 @@ #include #include #include +#include #include #include #include +#include #include #include #include @@ -63,6 +65,24 @@ m_shaderGraph(graph) addDockWidget(Qt::RightDockWidgetArea, nodeEditorDock); + // Buffer editor + BufferEditor* bufferEditor = new BufferEditor(m_shaderGraph); + + QDockWidget* bufferDock = new QDockWidget(tr("Buffers")); + bufferDock->setFeatures(QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetMovable); + bufferDock->setWidget(bufferEditor); + + addDockWidget(Qt::RightDockWidgetArea, bufferDock); + + // Struct editor + StructEditor* structEditor = new StructEditor(m_shaderGraph); + + QDockWidget* structDock = new QDockWidget(tr("Structs")); + structDock->setFeatures(QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetMovable); + structDock->setWidget(structEditor); + + addDockWidget(Qt::RightDockWidgetArea, structDock); + m_onSelectedNodeUpdate.Connect(m_shaderGraph.OnSelectedNodeUpdate, [&](ShaderGraph*, ShaderNode* node) { if (node) @@ -193,15 +213,15 @@ Nz::ShaderAst MainWindow::ToShader() Nz::ShaderNodes::StatementPtr shaderAst = m_shaderGraph.ToAst(); //TODO: Put in another function - auto GetExpressionFromInOut = [&](InOutType type) + auto GetExpressionFromInOut = [&](PrimitiveType type) { switch (type) { - case InOutType::Bool: return Nz::ShaderNodes::ExpressionType::Boolean; - case InOutType::Float1: return Nz::ShaderNodes::ExpressionType::Float1; - case InOutType::Float2: return Nz::ShaderNodes::ExpressionType::Float2; - case InOutType::Float3: return Nz::ShaderNodes::ExpressionType::Float3; - case InOutType::Float4: return Nz::ShaderNodes::ExpressionType::Float4; + case PrimitiveType::Bool: return Nz::ShaderNodes::ExpressionType::Boolean; + case PrimitiveType::Float1: return Nz::ShaderNodes::ExpressionType::Float1; + case PrimitiveType::Float2: return Nz::ShaderNodes::ExpressionType::Float2; + case PrimitiveType::Float3: return Nz::ShaderNodes::ExpressionType::Float3; + case PrimitiveType::Float4: return Nz::ShaderNodes::ExpressionType::Float4; } assert(false); @@ -226,8 +246,37 @@ Nz::ShaderAst MainWindow::ToShader() for (const auto& output : m_shaderGraph.GetOutputs()) shader.AddOutput(output.name, GetExpressionFromInOut(output.type), output.locationIndex); + for (const auto& buffer : m_shaderGraph.GetBuffers()) + { + const auto& structInfo = m_shaderGraph.GetStruct(buffer.structIndex); + shader.AddUniform(buffer.name, structInfo.name, buffer.bindingIndex, Nz::ShaderNodes::MemoryLayout::Std140); + } + for (const auto& uniform : m_shaderGraph.GetTextures()) - shader.AddUniform(uniform.name, GetExpressionFromTexture(uniform.type), uniform.bindingIndex); + shader.AddUniform(uniform.name, GetExpressionFromTexture(uniform.type), uniform.bindingIndex, {}); + + for (const auto& s : m_shaderGraph.GetStructs()) + { + std::vector members; + for (const auto& sMember : s.members) + { + auto& member = members.emplace_back(); + member.name = sMember.name; + + std::visit([&](auto&& arg) + { + using T = std::decay_t; + if constexpr (std::is_same_v) + member.type = GetExpressionFromInOut(arg); + else if constexpr (std::is_same_v) + member.type = m_shaderGraph.GetStruct(arg).name; + else + static_assert(AlwaysFalse::value, "non-exhaustive visitor"); + }, sMember.type); + } + + shader.AddStruct(s.name, std::move(members)); + } shader.AddFunction("main", shaderAst); diff --git a/src/ShaderNode/Widgets/OutputEditDialog.cpp b/src/ShaderNode/Widgets/OutputEditDialog.cpp index d2c83e58e..c6233e64c 100644 --- a/src/ShaderNode/Widgets/OutputEditDialog.cpp +++ b/src/ShaderNode/Widgets/OutputEditDialog.cpp @@ -16,8 +16,8 @@ QDialog(parent) m_outputName = new QLineEdit; m_typeList = new QComboBox; - for (std::size_t i = 0; i < InOutTypeCount; ++i) - m_typeList->addItem(EnumToString(static_cast(i))); + for (std::size_t i = 0; i < PrimitiveTypeCount; ++i) + m_typeList->addItem(EnumToString(static_cast(i))); m_locationIndex = new QSpinBox; @@ -50,7 +50,7 @@ OutputInfo OutputEditDialog::GetOutputInfo() const OutputInfo inputInfo; inputInfo.locationIndex = static_cast(m_locationIndex->value()); inputInfo.name = m_outputName->text().toStdString(); - inputInfo.type = static_cast(m_typeList->currentIndex()); + inputInfo.type = static_cast(m_typeList->currentIndex()); return inputInfo; } diff --git a/src/ShaderNode/Widgets/OutputEditDialog.hpp b/src/ShaderNode/Widgets/OutputEditDialog.hpp index 6a8cc68fb..5b045faff 100644 --- a/src/ShaderNode/Widgets/OutputEditDialog.hpp +++ b/src/ShaderNode/Widgets/OutputEditDialog.hpp @@ -14,7 +14,7 @@ struct OutputInfo { std::size_t locationIndex; std::string name; - InOutType type; + PrimitiveType type; }; class OutputEditDialog : public QDialog diff --git a/src/ShaderNode/Widgets/StructEditDialog.cpp b/src/ShaderNode/Widgets/StructEditDialog.cpp new file mode 100644 index 000000000..320ad586a --- /dev/null +++ b/src/ShaderNode/Widgets/StructEditDialog.cpp @@ -0,0 +1,224 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +StructEditDialog::StructEditDialog(ShaderGraph& graph, QWidget* parent) : +QDialog(parent), +m_shaderGraph(graph) +{ + setWindowTitle(tr("Struct edit dialog")); + setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); + + m_structName = new QLineEdit; + connect(m_structName, &QLineEdit::textEdited, [this](QString newText) + { + m_info.name = newText.toStdString(); + }); + + m_memberList = new QListWidget; + connect(m_memberList, &QListWidget::currentRowChanged, this, &StructEditDialog::OnMemberSelected); + connect(m_memberList, &QListWidget::itemDoubleClicked, [this](QListWidgetItem* item) + { + OnEditMember(m_memberList->row(item)); + }); + + m_memberMoveUpButton = new QPushButton(tr("Move up")); + m_memberMoveUpButton->setEnabled(false); + connect(m_memberMoveUpButton, &QPushButton::released, this, &StructEditDialog::OnMemberMoveUp); + + m_memberMoveDownButton = new QPushButton(tr("Move down")); + m_memberMoveDownButton->setEnabled(false); + connect(m_memberMoveDownButton, &QPushButton::released, this, &StructEditDialog::OnMemberMoveDown); + + m_deleteMemberButton = new QPushButton(tr("Delete member")); + m_deleteMemberButton->setEnabled(false); + connect(m_deleteMemberButton, &QPushButton::released, this, &StructEditDialog::OnDeleteMember); + + QPushButton* addMemberButton = new QPushButton(tr("Add member...")); + connect(addMemberButton, &QPushButton::released, this, &StructEditDialog::OnAddMember); + + QVBoxLayout* arrowLayout = new QVBoxLayout; + arrowLayout->addWidget(m_memberMoveUpButton); + arrowLayout->addWidget(m_memberMoveDownButton); + arrowLayout->addWidget(m_deleteMemberButton); + arrowLayout->addWidget(addMemberButton); + + QHBoxLayout* entityListLayout = new QHBoxLayout; + entityListLayout->addWidget(m_memberList); + entityListLayout->addLayout(arrowLayout); + + QFormLayout* formLayout = new QFormLayout; + formLayout->addRow(tr("Name"), m_structName); + formLayout->addRow(tr("Members"), entityListLayout); + + QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); + connect(buttonBox, &QDialogButtonBox::accepted, this, &StructEditDialog::OnAccept); + connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); + + QVBoxLayout* verticalLayout = new QVBoxLayout; + verticalLayout->addLayout(formLayout); + verticalLayout->addWidget(buttonBox); + + setLayout(verticalLayout); +} + +StructEditDialog::StructEditDialog(ShaderGraph& graph, const StructInfo& structInfo, QWidget* parent) : +StructEditDialog(graph, parent) +{ + m_info = structInfo; + + m_structName->setText(QString::fromStdString(m_info.name)); + UpdateMemberList(); +} + +const StructInfo& StructEditDialog::GetStructInfo() const +{ + return m_info; +} + +QString StructEditDialog::GetMemberName(const StructInfo::Member& member) +{ + QString name = QString::fromStdString(member.name) + " ("; + + std::visit([&](auto&& arg) + { + using T = std::decay_t; + if constexpr (std::is_same_v) + name += QString(EnumToString(arg)); + else if constexpr (std::is_same_v) + name += QString::fromStdString(m_shaderGraph.GetStruct(arg).name); + else + static_assert(AlwaysFalse::value, "non-exhaustive visitor"); + }, + member.type); + + name += ")"; + + return name; +} + +void StructEditDialog::OnAccept() +{ + if (m_info.name.empty()) + { + QMessageBox::critical(this, tr("Empty name"), tr("Struct name must be set"), QMessageBox::Ok); + return; + } + + accept(); +} + +void StructEditDialog::OnAddMember() +{ + StructMemberEditDialog* dialog = new StructMemberEditDialog(m_shaderGraph, this); + dialog->setAttribute(Qt::WA_DeleteOnClose, true); + connect(dialog, &QDialog::accepted, [this, dialog] + { + const StructMemberInfo& structInfo = dialog->GetMemberInfo(); + + auto& memberInfo = m_info.members.emplace_back(); + memberInfo.name = structInfo.name; + memberInfo.type = structInfo.type; + + UpdateMemberList(true); + }); + + dialog->open(); +} + +void StructEditDialog::OnDeleteMember() +{ + int memberIndex = m_memberList->currentRow(); + if (memberIndex < 0) + return; + + m_info.members.erase(m_info.members.begin() + memberIndex); + UpdateMemberList(); +} + +void StructEditDialog::OnEditMember(int memberIndex) +{ + assert(memberIndex >= 0); + + auto& memberInfo = m_info.members[memberIndex]; + + StructMemberInfo info; + info.name = memberInfo.name; + info.type = memberInfo.type; + + StructMemberEditDialog* dialog = new StructMemberEditDialog(m_shaderGraph, std::move(info), this); + dialog->setAttribute(Qt::WA_DeleteOnClose, true); + connect(dialog, &QDialog::accepted, [this, dialog, &memberInfo] + { + const StructMemberInfo& structInfo = dialog->GetMemberInfo(); + memberInfo.name = structInfo.name; + memberInfo.type = structInfo.type; + + UpdateMemberList(true); + }); + + dialog->open(); +} + +void StructEditDialog::OnMemberMoveUp() +{ + int memberIndex = m_memberList->currentRow(); + if (memberIndex <= 0) + return; + + std::size_t newMemberIndex = static_cast(memberIndex - 1); + std::swap(m_info.members[memberIndex], m_info.members[newMemberIndex]); + UpdateMemberList(); + + m_memberList->setCurrentRow(int(newMemberIndex)); +} + +void StructEditDialog::OnMemberMoveDown() +{ + int memberIndex = m_memberList->currentRow(); + if (memberIndex < 0 || memberIndex + 1 >= m_memberList->count()) + return; + + std::size_t newMemberIndex = static_cast(memberIndex + 1); + std::swap(m_info.members[memberIndex], m_info.members[newMemberIndex]); + UpdateMemberList(); + + m_memberList->setCurrentRow(int(newMemberIndex)); +} + +void StructEditDialog::OnMemberSelected(int memberIndex) +{ + if (memberIndex >= 0) + { + m_deleteMemberButton->setEnabled(true); + m_memberMoveDownButton->setEnabled(memberIndex + 1 < m_memberList->count()); + m_memberMoveUpButton->setEnabled(memberIndex != 0); + } + else + { + m_deleteMemberButton->setEnabled(false); + m_memberMoveDownButton->setEnabled(false); + m_memberMoveUpButton->setEnabled(false); + } +} + +void StructEditDialog::UpdateMemberList(bool keepSelection) +{ + int selectionIndex = m_memberList->currentRow(); + + m_memberList->clear(); + for (const auto& memberInfo : m_info.members) + m_memberList->addItem(GetMemberName(memberInfo)); + + if (keepSelection && selectionIndex >= 0 && selectionIndex < m_memberList->count()) + m_memberList->setCurrentRow(selectionIndex); +} diff --git a/src/ShaderNode/Widgets/StructEditDialog.hpp b/src/ShaderNode/Widgets/StructEditDialog.hpp new file mode 100644 index 000000000..992aacddb --- /dev/null +++ b/src/ShaderNode/Widgets/StructEditDialog.hpp @@ -0,0 +1,59 @@ +#pragma once + +#ifndef NAZARA_SHADERNODES_STRUCTEDITDIALOG_HPP +#define NAZARA_SHADERNODES_STRUCTEDITDIALOG_HPP + +#include +#include +#include +#include + +class QLineEdit; +class QListWidget; +class QPushButton; +class ShaderGraph; + +struct StructInfo +{ + struct Member + { + std::string name; + std::variant type; + }; + + std::string name; + std::vector members; +}; + +class StructEditDialog : public QDialog +{ + public: + StructEditDialog(ShaderGraph& graph, QWidget* parent = nullptr); + StructEditDialog(ShaderGraph& graph, const StructInfo& output, QWidget* parent = nullptr); + ~StructEditDialog() = default; + + const StructInfo& GetStructInfo() const; + + private: + QString GetMemberName(const StructInfo::Member& member); + void OnAccept(); + void OnAddMember(); + void OnDeleteMember(); + void OnEditMember(int memberIndex); + void OnMemberMoveUp(); + void OnMemberMoveDown(); + void OnMemberSelected(int memberIndex); + void UpdateMemberList(bool keepSelection = false); + + QLineEdit* m_structName; + QListWidget* m_memberList; + QPushButton* m_deleteMemberButton; + QPushButton* m_memberMoveUpButton; + QPushButton* m_memberMoveDownButton; + ShaderGraph& m_shaderGraph; + StructInfo m_info; +}; + +#include + +#endif diff --git a/src/ShaderNode/Widgets/StructEditDialog.inl b/src/ShaderNode/Widgets/StructEditDialog.inl new file mode 100644 index 000000000..474a6f20e --- /dev/null +++ b/src/ShaderNode/Widgets/StructEditDialog.inl @@ -0,0 +1 @@ +#include diff --git a/src/ShaderNode/Widgets/StructEditor.cpp b/src/ShaderNode/Widgets/StructEditor.cpp new file mode 100644 index 000000000..a68e6106d --- /dev/null +++ b/src/ShaderNode/Widgets/StructEditor.cpp @@ -0,0 +1,107 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +StructEditor::StructEditor(ShaderGraph& graph) : +m_shaderGraph(graph) +{ + m_structList = new QListWidget(this); + connect(m_structList, &QListWidget::itemDoubleClicked, [this](QListWidgetItem* item) + { + OnEditStruct(m_structList->row(item)); + }); + + QPushButton* addStructButton = new QPushButton(tr("Add struct...")); + connect(addStructButton, &QPushButton::released, this, &StructEditor::OnAddStruct); + + m_layout = new QVBoxLayout; + m_layout->addWidget(m_structList); + m_layout->addWidget(addStructButton); + + setLayout(m_layout); + + m_onStructListUpdateSlot.Connect(m_shaderGraph.OnStructListUpdate, this, &StructEditor::OnStructListUpdate); + m_onStructUpdateSlot.Connect(m_shaderGraph.OnStructUpdate, this, &StructEditor::OnStructUpdate); + + RefreshStructs(); +} + +void StructEditor::OnAddStruct() +{ + StructEditDialog* dialog = new StructEditDialog(m_shaderGraph, this); + dialog->setAttribute(Qt::WA_DeleteOnClose, true); + connect(dialog, &QDialog::accepted, [this, dialog] + { + const StructInfo& structInfo = dialog->GetStructInfo(); + + std::vector members; + for (const auto& memberInfo : structInfo.members) + { + auto& member = members.emplace_back(); + member.name = memberInfo.name; + member.type = memberInfo.type; + } + + m_shaderGraph.AddStruct(std::move(structInfo.name), std::move(members)); + }); + + dialog->open(); +} + +void StructEditor::OnEditStruct(int inputIndex) +{ + const auto& structInfo = m_shaderGraph.GetStruct(inputIndex); + + StructInfo info; + info.name = structInfo.name; + for (const auto& memberInfo : structInfo.members) + { + auto& member = info.members.emplace_back(); + member.name = memberInfo.name; + member.type = memberInfo.type; + } + + StructEditDialog* dialog = new StructEditDialog(m_shaderGraph, std::move(info), this); + dialog->setAttribute(Qt::WA_DeleteOnClose, true); + connect(dialog, &QDialog::accepted, [this, dialog, inputIndex] + { + const StructInfo& structInfo = dialog->GetStructInfo(); + + std::vector members; + for (const auto& memberInfo : structInfo.members) + { + auto& member = members.emplace_back(); + member.name = memberInfo.name; + member.type = memberInfo.type; + } + + m_shaderGraph.UpdateStruct(inputIndex, std::move(structInfo.name), std::move(members)); + }); + + dialog->open(); +} + +void StructEditor::OnStructListUpdate(ShaderGraph* /*graph*/) +{ + RefreshStructs(); +} + +void StructEditor::OnStructUpdate(ShaderGraph* /*graph*/, std::size_t structIndex) +{ + const auto& structEntry = m_shaderGraph.GetStruct(structIndex); + m_structList->item(int(structIndex))->setText(QString::fromStdString(structEntry.name)); +} + +void StructEditor::RefreshStructs() +{ + m_structList->clear(); + m_structList->setCurrentRow(-1); + + for (const auto& structEntry : m_shaderGraph.GetStructs()) + m_structList->addItem(QString::fromStdString(structEntry.name)); +} diff --git a/src/ShaderNode/Widgets/StructEditor.hpp b/src/ShaderNode/Widgets/StructEditor.hpp new file mode 100644 index 000000000..3e00fc5bb --- /dev/null +++ b/src/ShaderNode/Widgets/StructEditor.hpp @@ -0,0 +1,37 @@ +#pragma once + +#ifndef NAZARA_SHADERNODES_STRUCTEDITOR_HPP +#define NAZARA_SHADERNODES_STRUCTEDITOR_HPP + +#include +#include +#include + +class QLabel; +class QListWidget; +class QVBoxLayout; + +class StructEditor : public QWidget +{ + public: + StructEditor(ShaderGraph& graph); + ~StructEditor() = default; + + private: + void OnAddStruct(); + void OnEditStruct(int inputIndex); + void OnStructListUpdate(ShaderGraph* graph); + void OnStructUpdate(ShaderGraph* graph, std::size_t inputIndex); + void RefreshStructs(); + + NazaraSlot(ShaderGraph, OnStructListUpdate, m_onStructListUpdateSlot); + NazaraSlot(ShaderGraph, OnStructUpdate, m_onStructUpdateSlot); + + ShaderGraph& m_shaderGraph; + QListWidget* m_structList; + QVBoxLayout* m_layout; +}; + +#include + +#endif diff --git a/src/ShaderNode/Widgets/StructEditor.inl b/src/ShaderNode/Widgets/StructEditor.inl new file mode 100644 index 000000000..95ebbea7e --- /dev/null +++ b/src/ShaderNode/Widgets/StructEditor.inl @@ -0,0 +1 @@ +#include diff --git a/src/ShaderNode/Widgets/StructMemberEditDialog.cpp b/src/ShaderNode/Widgets/StructMemberEditDialog.cpp new file mode 100644 index 000000000..82bc4e1a2 --- /dev/null +++ b/src/ShaderNode/Widgets/StructMemberEditDialog.cpp @@ -0,0 +1,86 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +StructMemberEditDialog::StructMemberEditDialog(const ShaderGraph& shaderGraph, QWidget* parent) : +QDialog(parent), +m_shaderGraph(shaderGraph) +{ + setWindowTitle(tr("Struct member edit dialog")); + setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); + + m_memberName = new QLineEdit; + + m_typeList = new QComboBox; + for (std::size_t i = 0; i < PrimitiveTypeCount; ++i) + m_typeList->addItem(EnumToString(static_cast(i))); + + for (const auto& structInfo : m_shaderGraph.GetStructs()) + m_typeList->addItem(QString::fromStdString(structInfo.name)); + + QFormLayout* formLayout = new QFormLayout; + formLayout->addRow(tr("Name"), m_memberName); + formLayout->addRow(tr("Type"), m_typeList); + + QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); + connect(buttonBox, &QDialogButtonBox::accepted, this, &StructMemberEditDialog::OnAccept); + connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); + + QVBoxLayout* verticalLayout = new QVBoxLayout; + verticalLayout->addLayout(formLayout); + verticalLayout->addWidget(buttonBox); + + setLayout(verticalLayout); +} + +StructMemberEditDialog::StructMemberEditDialog(const ShaderGraph& shaderGraph, const StructMemberInfo& member, QWidget* parent) : +StructMemberEditDialog(shaderGraph, parent) +{ + m_memberName->setText(QString::fromStdString(member.name)); + std::visit([&](auto&& arg) + { + using T = std::decay_t; + if constexpr (std::is_same_v) + m_typeList->setCurrentIndex(static_cast(arg)); + else if constexpr (std::is_same_v) + m_typeList->setCurrentIndex(static_cast(PrimitiveTypeCount + arg)); + else + static_assert(AlwaysFalse::value, "non-exhaustive visitor"); + }, + member.type); +} + +StructMemberInfo StructMemberEditDialog::GetMemberInfo() const +{ + StructMemberInfo inputInfo; + inputInfo.name = m_memberName->text().toStdString(); + + if (m_typeList->currentIndex() < PrimitiveTypeCount) + inputInfo.type = static_cast(m_typeList->currentIndex()); + else + inputInfo.type = static_cast(m_typeList->currentIndex() - PrimitiveTypeCount); + + return inputInfo; +} + +void StructMemberEditDialog::OnAccept() +{ + if (m_memberName->text().isEmpty()) + { + QMessageBox::critical(this, tr("Empty name"), tr("Struct member name must be set"), QMessageBox::Ok); + return; + } + + if (m_typeList->currentIndex() < 0) + { + QMessageBox::critical(this, tr("Invalid type"), tr("You must select a type"), QMessageBox::Ok); + return; + } + + accept(); +} diff --git a/src/ShaderNode/Widgets/StructMemberEditDialog.hpp b/src/ShaderNode/Widgets/StructMemberEditDialog.hpp new file mode 100644 index 000000000..e482766dc --- /dev/null +++ b/src/ShaderNode/Widgets/StructMemberEditDialog.hpp @@ -0,0 +1,39 @@ +#pragma once + +#ifndef NAZARA_SHADERNODES_OUTPUTEDITDIALOG_HPP +#define NAZARA_SHADERNODES_OUTPUTEDITDIALOG_HPP + +#include +#include +#include + +class QComboBox; +class QLineEdit; +class ShaderGraph; + +struct StructMemberInfo +{ + std::string name; + std::variant type; +}; + +class StructMemberEditDialog : public QDialog +{ + public: + StructMemberEditDialog(const ShaderGraph& shaderGraph, QWidget* parent = nullptr); + StructMemberEditDialog(const ShaderGraph& shaderGraph, const StructMemberInfo& output, QWidget* parent = nullptr); + ~StructMemberEditDialog() = default; + + StructMemberInfo GetMemberInfo() const; + + private: + void OnAccept(); + + const ShaderGraph& m_shaderGraph; + QComboBox* m_typeList; + QLineEdit* m_memberName; +}; + +#include + +#endif diff --git a/src/ShaderNode/Widgets/StructMemberEditDialog.inl b/src/ShaderNode/Widgets/StructMemberEditDialog.inl new file mode 100644 index 000000000..e663ea05a --- /dev/null +++ b/src/ShaderNode/Widgets/StructMemberEditDialog.inl @@ -0,0 +1 @@ +#include From 1d2fb88198a19dc4a6da03fee05c4332d11a9f07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Thu, 16 Jul 2020 18:34:58 +0200 Subject: [PATCH 054/105] Renderer: Rename enums ExpressionType => BasicType ShaderAst::Type => ShaderExpressionType --- include/Nazara/Renderer/GlslWriter.hpp | 4 +- include/Nazara/Renderer/GlslWriter.inl | 2 +- include/Nazara/Renderer/ShaderAst.hpp | 19 ++++---- include/Nazara/Renderer/ShaderBuilder.hpp | 2 +- include/Nazara/Renderer/ShaderBuilder.inl | 8 ++-- include/Nazara/Renderer/ShaderEnums.hpp | 26 +++++------ .../Nazara/Renderer/ShaderExpressionType.hpp | 20 +++++++++ include/Nazara/Renderer/ShaderNodes.hpp | 30 ++++++------- include/Nazara/Renderer/ShaderNodes.inl | 38 ++++++++-------- include/Nazara/Renderer/ShaderSerializer.hpp | 2 +- include/Nazara/Renderer/ShaderValidator.hpp | 2 +- include/Nazara/Renderer/ShaderVariables.hpp | 14 +++--- include/Nazara/Renderer/ShaderVariables.inl | 12 ++--- src/Nazara/OpenGLRenderer/Wrapper/Context.cpp | 2 + .../Wrapper/Win32/WGLContext.cpp | 7 +++ src/Nazara/Renderer/GlslWriter.cpp | 30 ++++++------- src/Nazara/Renderer/ShaderAst.cpp | 8 ++-- src/Nazara/Renderer/ShaderNodes.cpp | 32 +++++++------- src/Nazara/Renderer/ShaderSerializer.cpp | 26 +++++------ src/Nazara/Renderer/ShaderValidator.cpp | 44 +++++++++---------- src/ShaderNode/DataModels/InputValue.cpp | 14 +++--- src/ShaderNode/DataModels/OutputValue.cpp | 16 +++---- src/ShaderNode/DataModels/TextureValue.cpp | 4 +- src/ShaderNode/DataTypes/VecData.cpp | 8 ++-- src/ShaderNode/DataTypes/VecData.hpp | 12 ++--- src/ShaderNode/Widgets/MainWindow.cpp | 12 ++--- 26 files changed, 210 insertions(+), 184 deletions(-) create mode 100644 include/Nazara/Renderer/ShaderExpressionType.hpp diff --git a/include/Nazara/Renderer/GlslWriter.hpp b/include/Nazara/Renderer/GlslWriter.hpp index 999a93c48..94ca21676 100644 --- a/include/Nazara/Renderer/GlslWriter.hpp +++ b/include/Nazara/Renderer/GlslWriter.hpp @@ -44,9 +44,9 @@ namespace Nz }; private: - void Append(ShaderAst::Type type); + void Append(ShaderExpressionType type); void Append(ShaderNodes::BuiltinEntry builtin); - void Append(ShaderNodes::ExpressionType type); + void Append(ShaderNodes::BasicType type); void Append(ShaderNodes::MemoryLayout layout); template void Append(const T& param); void AppendCommentSection(const std::string& section); diff --git a/include/Nazara/Renderer/GlslWriter.inl b/include/Nazara/Renderer/GlslWriter.inl index 9b67eaa89..e543f870f 100644 --- a/include/Nazara/Renderer/GlslWriter.inl +++ b/include/Nazara/Renderer/GlslWriter.inl @@ -86,7 +86,7 @@ namespace Nz std::visit([&](auto&& arg) { using T = std::decay_t; - if constexpr (std::is_same_v) + if constexpr (std::is_same_v) { Append(arg); Append(" "); diff --git a/include/Nazara/Renderer/ShaderAst.hpp b/include/Nazara/Renderer/ShaderAst.hpp index 4b57bbced..035aa5cce 100644 --- a/include/Nazara/Renderer/ShaderAst.hpp +++ b/include/Nazara/Renderer/ShaderAst.hpp @@ -8,11 +8,10 @@ #define NAZARA_SHADER_AST_HPP #include +#include #include #include -#include #include -#include #include namespace Nz @@ -28,16 +27,14 @@ namespace Nz struct Uniform; struct VariableBase; - using Type = std::variant; - ShaderAst() = default; ~ShaderAst() = default; - void AddFunction(std::string name, ShaderNodes::StatementPtr statement, std::vector parameters = {}, ShaderNodes::ExpressionType returnType = ShaderNodes::ExpressionType::Void); - void AddInput(std::string name, Type type, std::optional locationIndex); - void AddOutput(std::string name, Type type, std::optional locationIndex); + void AddFunction(std::string name, ShaderNodes::StatementPtr statement, std::vector parameters = {}, ShaderNodes::BasicType returnType = ShaderNodes::BasicType::Void); + void AddInput(std::string name, ShaderExpressionType type, std::optional locationIndex); + void AddOutput(std::string name, ShaderExpressionType type, std::optional locationIndex); void AddStruct(std::string name, std::vector members); - void AddUniform(std::string name, Type type, std::optional bindingIndex, std::optional memoryLayout); + void AddUniform(std::string name, ShaderExpressionType type, std::optional bindingIndex, std::optional memoryLayout); inline const Function& GetFunction(std::size_t i) const; inline std::size_t GetFunctionCount() const; @@ -58,7 +55,7 @@ namespace Nz struct VariableBase { std::string name; - Type type; + ShaderExpressionType type; }; struct FunctionParameter : VariableBase @@ -69,7 +66,7 @@ namespace Nz { std::string name; std::vector parameters; - ShaderNodes::ExpressionType returnType; + ShaderNodes::BasicType returnType; ShaderNodes::StatementPtr statement; }; @@ -93,7 +90,7 @@ namespace Nz struct StructMember { std::string name; - Type type; + ShaderExpressionType type; }; private: diff --git a/include/Nazara/Renderer/ShaderBuilder.hpp b/include/Nazara/Renderer/ShaderBuilder.hpp index cc437f45f..7d8502151 100644 --- a/include/Nazara/Renderer/ShaderBuilder.hpp +++ b/include/Nazara/Renderer/ShaderBuilder.hpp @@ -67,7 +67,7 @@ namespace Nz::ShaderBuilder constexpr BinOpBuilder Substract; constexpr GenBuilder Uniform; - template std::shared_ptr Cast(Args&&... args); + template std::shared_ptr Cast(Args&&... args); } #include diff --git a/include/Nazara/Renderer/ShaderBuilder.inl b/include/Nazara/Renderer/ShaderBuilder.inl index dda1d730b..8ef833536 100644 --- a/include/Nazara/Renderer/ShaderBuilder.inl +++ b/include/Nazara/Renderer/ShaderBuilder.inl @@ -28,21 +28,21 @@ namespace Nz::ShaderBuilder inline std::shared_ptr BuiltinBuilder::operator()(ShaderNodes::BuiltinEntry builtin) const { - ShaderNodes::ExpressionType exprType = ShaderNodes::ExpressionType::Void; + ShaderNodes::BasicType exprType = ShaderNodes::BasicType::Void; switch (builtin) { case ShaderNodes::BuiltinEntry::VertexPosition: - exprType = ShaderNodes::ExpressionType::Float4; + exprType = ShaderNodes::BasicType::Float4; break; } - NazaraAssert(exprType != ShaderNodes::ExpressionType::Void, "Unhandled builtin"); + NazaraAssert(exprType != ShaderNodes::BasicType::Void, "Unhandled builtin"); return ShaderNodes::BuiltinVariable::Build(builtin, exprType); } - template + template std::shared_ptr Cast(Args&&... args) { return ShaderNodes::Cast::Build(Type, std::forward(args)...); diff --git a/include/Nazara/Renderer/ShaderEnums.hpp b/include/Nazara/Renderer/ShaderEnums.hpp index 7a93cea7b..a9db1abe8 100644 --- a/include/Nazara/Renderer/ShaderEnums.hpp +++ b/include/Nazara/Renderer/ShaderEnums.hpp @@ -16,6 +16,19 @@ namespace Nz::ShaderNodes Simple //< = }; + enum class BasicType + { + Boolean, // bool + Float1, // float + Float2, // vec2 + Float3, // vec3 + Float4, // vec4 + Mat4x4, // mat4 + Sampler2D, // sampler2D + + Void // void + }; + enum class BinaryType { Add, //< + @@ -37,19 +50,6 @@ namespace Nz::ShaderNodes RValue }; - enum class ExpressionType - { - Boolean, // bool - Float1, // float - Float2, // vec2 - Float3, // vec3 - Float4, // vec4 - Mat4x4, // mat4 - Sampler2D, // sampler2D - - Void // void - }; - enum class IntrinsicType { CrossProduct, diff --git a/include/Nazara/Renderer/ShaderExpressionType.hpp b/include/Nazara/Renderer/ShaderExpressionType.hpp new file mode 100644 index 000000000..c937d6a10 --- /dev/null +++ b/include/Nazara/Renderer/ShaderExpressionType.hpp @@ -0,0 +1,20 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Renderer module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_SHADER_EXPRESSIONTYPE_HPP +#define NAZARA_SHADER_EXPRESSIONTYPE_HPP + +#include +#include +#include +#include + +namespace Nz +{ + using ShaderExpressionType = std::variant; +} + +#endif // NAZARA_SHADER_EXPRESSIONTYPE_HPP diff --git a/include/Nazara/Renderer/ShaderNodes.hpp b/include/Nazara/Renderer/ShaderNodes.hpp index 659e643a3..57ff5ab60 100644 --- a/include/Nazara/Renderer/ShaderNodes.hpp +++ b/include/Nazara/Renderer/ShaderNodes.hpp @@ -38,8 +38,8 @@ namespace Nz virtual void Visit(ShaderVisitor& visitor) = 0; - static inline unsigned int GetComponentCount(ExpressionType type); - static inline ExpressionType GetComponentType(ExpressionType type); + static inline unsigned int GetComponentCount(BasicType type); + static inline BasicType GetComponentType(BasicType type); protected: inline Node(NodeType type, bool isStatement); @@ -59,7 +59,7 @@ namespace Nz inline Expression(NodeType type); virtual ExpressionCategory GetExpressionCategory() const; - virtual ExpressionType GetExpressionType() const = 0; + virtual BasicType GetExpressionType() const = 0; }; class Statement; @@ -125,7 +125,7 @@ namespace Nz inline Identifier(); ExpressionCategory GetExpressionCategory() const override; - ExpressionType GetExpressionType() const override; + BasicType GetExpressionType() const override; void Visit(ShaderVisitor& visitor) override; VariablePtr var; @@ -139,7 +139,7 @@ namespace Nz { inline AssignOp(); - ExpressionType GetExpressionType() const override; + BasicType GetExpressionType() const override; void Visit(ShaderVisitor& visitor) override; AssignType op; @@ -153,7 +153,7 @@ namespace Nz { inline BinaryOp(); - ExpressionType GetExpressionType() const override; + BasicType GetExpressionType() const override; void Visit(ShaderVisitor& visitor) override; BinaryType op; @@ -187,24 +187,24 @@ namespace Nz { inline Cast(); - ExpressionType GetExpressionType() const override; + BasicType GetExpressionType() const override; void Visit(ShaderVisitor& visitor) override; - ExpressionType exprType; + BasicType exprType; std::array expressions; - static inline std::shared_ptr Build(ExpressionType castTo, ExpressionPtr first, ExpressionPtr second = nullptr, ExpressionPtr third = nullptr, ExpressionPtr fourth = nullptr); - static inline std::shared_ptr Build(ExpressionType castTo, ExpressionPtr* expressions, std::size_t expressionCount); + static inline std::shared_ptr Build(BasicType castTo, ExpressionPtr first, ExpressionPtr second = nullptr, ExpressionPtr third = nullptr, ExpressionPtr fourth = nullptr); + static inline std::shared_ptr Build(BasicType castTo, ExpressionPtr* expressions, std::size_t expressionCount); }; struct NAZARA_RENDERER_API Constant : public Expression { inline Constant(); - ExpressionType GetExpressionType() const override; + BasicType GetExpressionType() const override; void Visit(ShaderVisitor& visitor) override; - ExpressionType exprType; + BasicType exprType; union { @@ -227,7 +227,7 @@ namespace Nz inline SwizzleOp(); ExpressionCategory GetExpressionCategory() const override; - ExpressionType GetExpressionType() const override; + BasicType GetExpressionType() const override; void Visit(ShaderVisitor& visitor) override; std::array components; @@ -243,7 +243,7 @@ namespace Nz { inline Sample2D(); - ExpressionType GetExpressionType() const override; + BasicType GetExpressionType() const override; void Visit(ShaderVisitor& visitor) override; ExpressionPtr sampler; @@ -258,7 +258,7 @@ namespace Nz { inline IntrinsicCall(); - ExpressionType GetExpressionType() const override; + BasicType GetExpressionType() const override; void Visit(ShaderVisitor& visitor) override; IntrinsicType intrinsic; diff --git a/include/Nazara/Renderer/ShaderNodes.inl b/include/Nazara/Renderer/ShaderNodes.inl index bafad38f5..31d3028ed 100644 --- a/include/Nazara/Renderer/ShaderNodes.inl +++ b/include/Nazara/Renderer/ShaderNodes.inl @@ -23,20 +23,20 @@ namespace Nz::ShaderNodes return m_isStatement; } - inline unsigned int Node::GetComponentCount(ExpressionType type) + inline unsigned int Node::GetComponentCount(BasicType type) { switch (type) { - case ExpressionType::Float2: + case BasicType::Float2: return 2; - case ExpressionType::Float3: + case BasicType::Float3: return 3; - case ExpressionType::Float4: + case BasicType::Float4: return 4; - case ExpressionType::Mat4x4: + case BasicType::Mat4x4: return 4; default: @@ -44,17 +44,17 @@ namespace Nz::ShaderNodes } } - inline ExpressionType Node::GetComponentType(ExpressionType type) + inline BasicType Node::GetComponentType(BasicType type) { switch (type) { - case ExpressionType::Float2: - case ExpressionType::Float3: - case ExpressionType::Float4: - return ExpressionType::Float1; + case BasicType::Float2: + case BasicType::Float3: + case BasicType::Float4: + return BasicType::Float1; - case ExpressionType::Mat4x4: - return ExpressionType::Float4; + case BasicType::Mat4x4: + return BasicType::Float4; default: return type; @@ -198,7 +198,7 @@ namespace Nz::ShaderNodes { } - inline std::shared_ptr Cast::Build(ExpressionType castTo, ExpressionPtr first, ExpressionPtr second, ExpressionPtr third, ExpressionPtr fourth) + inline std::shared_ptr Cast::Build(BasicType castTo, ExpressionPtr first, ExpressionPtr second, ExpressionPtr third, ExpressionPtr fourth) { auto node = std::make_shared(); node->exprType = castTo; @@ -207,7 +207,7 @@ namespace Nz::ShaderNodes return node; } - inline std::shared_ptr Cast::Build(ExpressionType castTo, ExpressionPtr* Expressions, std::size_t expressionCount) + inline std::shared_ptr Cast::Build(BasicType castTo, ExpressionPtr* Expressions, std::size_t expressionCount) { auto node = std::make_shared(); node->exprType = castTo; @@ -226,7 +226,7 @@ namespace Nz::ShaderNodes inline std::shared_ptr Constant::Build(bool value) { auto node = std::make_shared(); - node->exprType = ExpressionType::Boolean; + node->exprType = BasicType::Boolean; node->values.bool1 = value; return node; @@ -235,7 +235,7 @@ namespace Nz::ShaderNodes inline std::shared_ptr Constant::Build(float value) { auto node = std::make_shared(); - node->exprType = ExpressionType::Float1; + node->exprType = BasicType::Float1; node->values.vec1 = value; return node; @@ -244,7 +244,7 @@ namespace Nz::ShaderNodes inline std::shared_ptr Constant::Build(const Vector2f& value) { auto node = std::make_shared(); - node->exprType = ExpressionType::Float2; + node->exprType = BasicType::Float2; node->values.vec2 = value; return node; @@ -253,7 +253,7 @@ namespace Nz::ShaderNodes inline std::shared_ptr Constant::Build(const Vector3f& value) { auto node = std::make_shared(); - node->exprType = ExpressionType::Float3; + node->exprType = BasicType::Float3; node->values.vec3 = value; return node; @@ -262,7 +262,7 @@ namespace Nz::ShaderNodes inline std::shared_ptr Constant::Build(const Vector4f& value) { auto node = std::make_shared(); - node->exprType = ExpressionType::Float4; + node->exprType = BasicType::Float4; node->values.vec4 = value; return node; diff --git a/include/Nazara/Renderer/ShaderSerializer.hpp b/include/Nazara/Renderer/ShaderSerializer.hpp index f79040b2c..e4e6be7b3 100644 --- a/include/Nazara/Renderer/ShaderSerializer.hpp +++ b/include/Nazara/Renderer/ShaderSerializer.hpp @@ -103,7 +103,7 @@ namespace Nz private: bool IsWriting() const override; void Node(ShaderNodes::NodePtr& node) override; - void Type(ShaderAst::Type& type); + void Type(ShaderExpressionType& type); void Value(bool& val) override; void Value(float& val) override; void Value(std::string& val) override; diff --git a/include/Nazara/Renderer/ShaderValidator.hpp b/include/Nazara/Renderer/ShaderValidator.hpp index 3df9f4ae5..ecfea1290 100644 --- a/include/Nazara/Renderer/ShaderValidator.hpp +++ b/include/Nazara/Renderer/ShaderValidator.hpp @@ -30,7 +30,7 @@ namespace Nz const ShaderNodes::ExpressionPtr& MandatoryExpr(const ShaderNodes::ExpressionPtr& node); const ShaderNodes::NodePtr& MandatoryNode(const ShaderNodes::NodePtr& node); void TypeMustMatch(const ShaderNodes::ExpressionPtr& left, const ShaderNodes::ExpressionPtr& right); - void TypeMustMatch(const ShaderAst::Type& left, const ShaderAst::Type& right); + void TypeMustMatch(const ShaderExpressionType& left, const ShaderExpressionType& right); using ShaderVisitor::Visit; void Visit(const ShaderNodes::AssignOp& node) override; diff --git a/include/Nazara/Renderer/ShaderVariables.hpp b/include/Nazara/Renderer/ShaderVariables.hpp index 242f129db..f80386d0c 100644 --- a/include/Nazara/Renderer/ShaderVariables.hpp +++ b/include/Nazara/Renderer/ShaderVariables.hpp @@ -34,7 +34,7 @@ namespace Nz virtual VariableType GetType() const = 0; virtual void Visit(ShaderVarVisitor& visitor) = 0; - ExpressionType type; + BasicType type; }; struct BuiltinVariable; @@ -48,7 +48,7 @@ namespace Nz VariableType GetType() const override; void Visit(ShaderVarVisitor& visitor) override; - static inline std::shared_ptr Build(BuiltinEntry entry, ExpressionType varType); + static inline std::shared_ptr Build(BuiltinEntry entry, BasicType varType); }; struct NamedVariable; @@ -69,7 +69,7 @@ namespace Nz VariableType GetType() const override; void Visit(ShaderVarVisitor& visitor) override; - static inline std::shared_ptr Build(std::string varName, ExpressionType varType); + static inline std::shared_ptr Build(std::string varName, BasicType varType); }; struct LocalVariable; @@ -81,7 +81,7 @@ namespace Nz VariableType GetType() const override; void Visit(ShaderVarVisitor& visitor) override; - static inline std::shared_ptr Build(std::string varName, ExpressionType varType); + static inline std::shared_ptr Build(std::string varName, BasicType varType); }; struct OutputVariable; @@ -93,7 +93,7 @@ namespace Nz VariableType GetType() const override; void Visit(ShaderVarVisitor& visitor) override; - static inline std::shared_ptr Build(std::string varName, ExpressionType varType); + static inline std::shared_ptr Build(std::string varName, BasicType varType); }; struct ParameterVariable; @@ -105,7 +105,7 @@ namespace Nz VariableType GetType() const override; void Visit(ShaderVarVisitor& visitor) override; - static inline std::shared_ptr Build(std::string varName, ExpressionType varType); + static inline std::shared_ptr Build(std::string varName, BasicType varType); }; struct UniformVariable; @@ -117,7 +117,7 @@ namespace Nz VariableType GetType() const override; void Visit(ShaderVarVisitor& visitor) override; - static inline std::shared_ptr Build(std::string varName, ExpressionType varType); + static inline std::shared_ptr Build(std::string varName, BasicType varType); }; } } diff --git a/include/Nazara/Renderer/ShaderVariables.inl b/include/Nazara/Renderer/ShaderVariables.inl index d20c9d6ea..e01ecb33e 100644 --- a/include/Nazara/Renderer/ShaderVariables.inl +++ b/include/Nazara/Renderer/ShaderVariables.inl @@ -7,7 +7,7 @@ namespace Nz::ShaderNodes { - inline std::shared_ptr BuiltinVariable::Build(BuiltinEntry variable, ExpressionType varType) + inline std::shared_ptr BuiltinVariable::Build(BuiltinEntry variable, BasicType varType) { auto node = std::make_shared(); node->entry = variable; @@ -16,7 +16,7 @@ namespace Nz::ShaderNodes return node; } - inline std::shared_ptr InputVariable::Build(std::string varName, ExpressionType varType) + inline std::shared_ptr InputVariable::Build(std::string varName, BasicType varType) { auto node = std::make_shared(); node->name = std::move(varName); @@ -25,7 +25,7 @@ namespace Nz::ShaderNodes return node; } - inline std::shared_ptr LocalVariable::Build(std::string varName, ExpressionType varType) + inline std::shared_ptr LocalVariable::Build(std::string varName, BasicType varType) { auto node = std::make_shared(); node->name = std::move(varName); @@ -34,7 +34,7 @@ namespace Nz::ShaderNodes return node; } - inline std::shared_ptr OutputVariable::Build(std::string varName, ExpressionType varType) + inline std::shared_ptr OutputVariable::Build(std::string varName, BasicType varType) { auto node = std::make_shared(); node->name = std::move(varName); @@ -43,7 +43,7 @@ namespace Nz::ShaderNodes return node; } - inline std::shared_ptr ParameterVariable::Build(std::string varName, ExpressionType varType) + inline std::shared_ptr ParameterVariable::Build(std::string varName, BasicType varType) { auto node = std::make_shared(); node->name = std::move(varName); @@ -52,7 +52,7 @@ namespace Nz::ShaderNodes return node; } - inline std::shared_ptr UniformVariable::Build(std::string varName, ExpressionType varType) + inline std::shared_ptr UniformVariable::Build(std::string varName, BasicType varType) { auto node = std::make_shared(); node->name = std::move(varName); diff --git a/src/Nazara/OpenGLRenderer/Wrapper/Context.cpp b/src/Nazara/OpenGLRenderer/Wrapper/Context.cpp index 902f22813..2cd045504 100644 --- a/src/Nazara/OpenGLRenderer/Wrapper/Context.cpp +++ b/src/Nazara/OpenGLRenderer/Wrapper/Context.cpp @@ -278,6 +278,8 @@ namespace Nz::GL glGetIntegerv(GL_VIEWPORT, res.data()); m_state.viewport = { res[0], res[1], res[2], res[3] }; + EnableVerticalSync(false); + return true; } diff --git a/src/Nazara/OpenGLRenderer/Wrapper/Win32/WGLContext.cpp b/src/Nazara/OpenGLRenderer/Wrapper/Win32/WGLContext.cpp index e07a21294..c904a42d4 100644 --- a/src/Nazara/OpenGLRenderer/Wrapper/Win32/WGLContext.cpp +++ b/src/Nazara/OpenGLRenderer/Wrapper/Win32/WGLContext.cpp @@ -67,6 +67,13 @@ namespace Nz::GL void WGLContext::EnableVerticalSync(bool enabled) { + if (wglSwapIntervalEXT) + { + if (!SetCurrentContext(this)) + return; + + wglSwapIntervalEXT(enabled); + } } void WGLContext::SwapBuffers() diff --git a/src/Nazara/Renderer/GlslWriter.cpp b/src/Nazara/Renderer/GlslWriter.cpp index accb493b7..4dcbcd4cc 100644 --- a/src/Nazara/Renderer/GlslWriter.cpp +++ b/src/Nazara/Renderer/GlslWriter.cpp @@ -163,7 +163,7 @@ namespace Nz m_environment = std::move(environment); } - void GlslWriter::Append(ShaderAst::Type type) + void GlslWriter::Append(ShaderExpressionType type) { std::visit([&](auto&& arg) { @@ -181,32 +181,32 @@ namespace Nz } } - void GlslWriter::Append(ShaderNodes::ExpressionType type) + void GlslWriter::Append(ShaderNodes::BasicType type) { switch (type) { - case ShaderNodes::ExpressionType::Boolean: + case ShaderNodes::BasicType::Boolean: Append("bool"); break; - case ShaderNodes::ExpressionType::Float1: + case ShaderNodes::BasicType::Float1: Append("float"); break; - case ShaderNodes::ExpressionType::Float2: + case ShaderNodes::BasicType::Float2: Append("vec2"); break; - case ShaderNodes::ExpressionType::Float3: + case ShaderNodes::BasicType::Float3: Append("vec3"); break; - case ShaderNodes::ExpressionType::Float4: + case ShaderNodes::BasicType::Float4: Append("vec4"); break; - case ShaderNodes::ExpressionType::Mat4x4: + case ShaderNodes::BasicType::Mat4x4: Append("mat4"); break; - case ShaderNodes::ExpressionType::Sampler2D: + case ShaderNodes::BasicType::Sampler2D: Append("sampler2D"); break; - case ShaderNodes::ExpressionType::Void: + case ShaderNodes::BasicType::Void: Append("void"); break; } @@ -395,23 +395,23 @@ namespace Nz { switch (node.exprType) { - case ShaderNodes::ExpressionType::Boolean: + case ShaderNodes::BasicType::Boolean: Append((node.values.bool1) ? "true" : "false"); break; - case ShaderNodes::ExpressionType::Float1: + case ShaderNodes::BasicType::Float1: Append(std::to_string(node.values.vec1)); break; - case ShaderNodes::ExpressionType::Float2: + case ShaderNodes::BasicType::Float2: Append("vec2(" + std::to_string(node.values.vec2.x) + ", " + std::to_string(node.values.vec2.y) + ")"); break; - case ShaderNodes::ExpressionType::Float3: + case ShaderNodes::BasicType::Float3: Append("vec3(" + std::to_string(node.values.vec3.x) + ", " + std::to_string(node.values.vec3.y) + ", " + std::to_string(node.values.vec3.z) + ")"); break; - case ShaderNodes::ExpressionType::Float4: + case ShaderNodes::BasicType::Float4: Append("vec4(" + std::to_string(node.values.vec4.x) + ", " + std::to_string(node.values.vec4.y) + ", " + std::to_string(node.values.vec4.z) + ", " + std::to_string(node.values.vec4.w) + ")"); break; diff --git a/src/Nazara/Renderer/ShaderAst.cpp b/src/Nazara/Renderer/ShaderAst.cpp index 05d3eb94d..da009248b 100644 --- a/src/Nazara/Renderer/ShaderAst.cpp +++ b/src/Nazara/Renderer/ShaderAst.cpp @@ -7,7 +7,7 @@ namespace Nz { - void ShaderAst::AddFunction(std::string name, ShaderNodes::StatementPtr statement, std::vector parameters, ShaderNodes::ExpressionType returnType) + void ShaderAst::AddFunction(std::string name, ShaderNodes::StatementPtr statement, std::vector parameters, ShaderNodes::BasicType returnType) { auto& functionEntry = m_functions.emplace_back(); functionEntry.name = std::move(name); @@ -16,7 +16,7 @@ namespace Nz functionEntry.statement = std::move(statement); } - void ShaderAst::AddInput(std::string name, Type type, std::optional locationIndex) + void ShaderAst::AddInput(std::string name, ShaderExpressionType type, std::optional locationIndex) { auto& inputEntry = m_inputs.emplace_back(); inputEntry.name = std::move(name); @@ -24,7 +24,7 @@ namespace Nz inputEntry.type = std::move(type); } - void ShaderAst::AddOutput(std::string name, Type type, std::optional locationIndex) + void ShaderAst::AddOutput(std::string name, ShaderExpressionType type, std::optional locationIndex) { auto& outputEntry = m_outputs.emplace_back(); outputEntry.name = std::move(name); @@ -39,7 +39,7 @@ namespace Nz structEntry.members = std::move(members); } - void ShaderAst::AddUniform(std::string name, Type type, std::optional bindingIndex, std::optional memoryLayout) + void ShaderAst::AddUniform(std::string name, ShaderExpressionType type, std::optional bindingIndex, std::optional memoryLayout) { auto& uniformEntry = m_uniforms.emplace_back(); uniformEntry.bindingIndex = std::move(bindingIndex); diff --git a/src/Nazara/Renderer/ShaderNodes.cpp b/src/Nazara/Renderer/ShaderNodes.cpp index eb4f59160..57ac58ee8 100644 --- a/src/Nazara/Renderer/ShaderNodes.cpp +++ b/src/Nazara/Renderer/ShaderNodes.cpp @@ -47,7 +47,7 @@ namespace Nz::ShaderNodes return ExpressionCategory::LValue; } - ExpressionType Identifier::GetExpressionType() const + BasicType Identifier::GetExpressionType() const { assert(var); return var->type; @@ -59,7 +59,7 @@ namespace Nz::ShaderNodes } - ExpressionType AssignOp::GetExpressionType() const + BasicType AssignOp::GetExpressionType() const { return left->GetExpressionType(); } @@ -70,9 +70,9 @@ namespace Nz::ShaderNodes } - ExpressionType BinaryOp::GetExpressionType() const + BasicType BinaryOp::GetExpressionType() const { - ShaderNodes::ExpressionType exprType = ShaderNodes::ExpressionType::Void; + ShaderNodes::BasicType exprType = ShaderNodes::BasicType::Void; switch (op) { @@ -84,15 +84,15 @@ namespace Nz::ShaderNodes case ShaderNodes::BinaryType::Divide: case ShaderNodes::BinaryType::Multiply: //FIXME - exprType = static_cast(std::max(UnderlyingCast(left->GetExpressionType()), UnderlyingCast(right->GetExpressionType()))); + exprType = static_cast(std::max(UnderlyingCast(left->GetExpressionType()), UnderlyingCast(right->GetExpressionType()))); break; case ShaderNodes::BinaryType::Equality: - exprType = ExpressionType::Boolean; + exprType = BasicType::Boolean; break; } - NazaraAssert(exprType != ShaderNodes::ExpressionType::Void, "Unhandled builtin"); + NazaraAssert(exprType != ShaderNodes::BasicType::Void, "Unhandled builtin"); return exprType; } @@ -109,7 +109,7 @@ namespace Nz::ShaderNodes } - ExpressionType Constant::GetExpressionType() const + BasicType Constant::GetExpressionType() const { return exprType; } @@ -119,7 +119,7 @@ namespace Nz::ShaderNodes visitor.Visit(*this); } - ExpressionType Cast::GetExpressionType() const + BasicType Cast::GetExpressionType() const { return exprType; } @@ -135,9 +135,9 @@ namespace Nz::ShaderNodes return ExpressionCategory::LValue; } - ExpressionType SwizzleOp::GetExpressionType() const + BasicType SwizzleOp::GetExpressionType() const { - return static_cast(UnderlyingCast(GetComponentType(expression->GetExpressionType())) + componentCount - 1); + return static_cast(UnderlyingCast(GetComponentType(expression->GetExpressionType())) + componentCount - 1); } void SwizzleOp::Visit(ShaderVisitor& visitor) @@ -146,9 +146,9 @@ namespace Nz::ShaderNodes } - ExpressionType Sample2D::GetExpressionType() const + BasicType Sample2D::GetExpressionType() const { - return ExpressionType::Float4; + return BasicType::Float4; } void Sample2D::Visit(ShaderVisitor& visitor) @@ -157,7 +157,7 @@ namespace Nz::ShaderNodes } - ExpressionType IntrinsicCall::GetExpressionType() const + BasicType IntrinsicCall::GetExpressionType() const { switch (intrinsic) { @@ -165,11 +165,11 @@ namespace Nz::ShaderNodes return parameters.front()->GetExpressionType(); case IntrinsicType::DotProduct: - return ExpressionType::Float1; + return BasicType::Float1; } NazaraAssert(false, "Unhandled builtin"); - return ExpressionType::Void; + return BasicType::Void; } void IntrinsicCall::Visit(ShaderVisitor& visitor) diff --git a/src/Nazara/Renderer/ShaderSerializer.cpp b/src/Nazara/Renderer/ShaderSerializer.cpp index 9cf7c47ff..17f369037 100644 --- a/src/Nazara/Renderer/ShaderSerializer.cpp +++ b/src/Nazara/Renderer/ShaderSerializer.cpp @@ -170,23 +170,23 @@ namespace Nz switch (node.exprType) { - case ShaderNodes::ExpressionType::Boolean: + case ShaderNodes::BasicType::Boolean: Value(node.values.bool1); break; - case ShaderNodes::ExpressionType::Float1: + case ShaderNodes::BasicType::Float1: Value(node.values.vec1); break; - case ShaderNodes::ExpressionType::Float2: + case ShaderNodes::BasicType::Float2: Value(node.values.vec2); break; - case ShaderNodes::ExpressionType::Float3: + case ShaderNodes::BasicType::Float3: Value(node.values.vec3); break; - case ShaderNodes::ExpressionType::Float4: + case ShaderNodes::BasicType::Float4: Value(node.values.vec4); break; } @@ -249,12 +249,12 @@ namespace Nz { m_stream << s_magicNumber << s_currentVersion; - auto SerializeType = [&](const ShaderAst::Type& type) + auto SerializeType = [&](const ShaderExpressionType& type) { std::visit([&](auto&& arg) { using T = std::decay_t; - if constexpr (std::is_same_v) + if constexpr (std::is_same_v) { m_stream << UInt8(0); m_stream << UInt32(arg); @@ -448,7 +448,7 @@ namespace Nz for (UInt32 i = 0; i < inputCount; ++i) { std::string inputName; - ShaderAst::Type inputType; + ShaderExpressionType inputType; std::optional location; Value(inputName); @@ -463,7 +463,7 @@ namespace Nz for (UInt32 i = 0; i < outputCount; ++i) { std::string outputName; - ShaderAst::Type outputType; + ShaderExpressionType outputType; std::optional location; Value(outputName); @@ -478,7 +478,7 @@ namespace Nz for (UInt32 i = 0; i < uniformCount; ++i) { std::string name; - ShaderAst::Type type; + ShaderExpressionType type; std::optional binding; std::optional memLayout; @@ -495,7 +495,7 @@ namespace Nz for (UInt32 i = 0; i < funcCount; ++i) { std::string name; - ShaderNodes::ExpressionType retType; + ShaderNodes::BasicType retType; std::vector parameters; Value(name); @@ -560,7 +560,7 @@ namespace Nz } } - void ShaderUnserializer::Type(ShaderAst::Type& type) + void ShaderUnserializer::Type(ShaderExpressionType& type) { UInt8 typeIndex; Value(typeIndex); @@ -569,7 +569,7 @@ namespace Nz { case 0: //< Primitive { - ShaderNodes::ExpressionType exprType; + ShaderNodes::BasicType exprType; Enum(exprType); type = exprType; diff --git a/src/Nazara/Renderer/ShaderValidator.cpp b/src/Nazara/Renderer/ShaderValidator.cpp index 37eecb767..1445d4cf1 100644 --- a/src/Nazara/Renderer/ShaderValidator.cpp +++ b/src/Nazara/Renderer/ShaderValidator.cpp @@ -21,7 +21,7 @@ namespace Nz struct Local { std::string name; - ShaderNodes::ExpressionType type; + ShaderNodes::BasicType type; }; const ShaderAst::Function* currentFunction; @@ -77,7 +77,7 @@ namespace Nz return TypeMustMatch(left->GetExpressionType(), right->GetExpressionType()); } - void ShaderValidator::TypeMustMatch(const ShaderAst::Type& left, const ShaderAst::Type& right) + void ShaderValidator::TypeMustMatch(const ShaderExpressionType& left, const ShaderExpressionType& right) { if (left != right) throw AstError{ "Left expression type must match right expression type" }; @@ -101,8 +101,8 @@ namespace Nz MandatoryNode(node.left); MandatoryNode(node.right); - ShaderNodes::ExpressionType leftType = node.left->GetExpressionType(); - ShaderNodes::ExpressionType rightType = node.right->GetExpressionType(); + ShaderNodes::BasicType leftType = node.left->GetExpressionType(); + ShaderNodes::BasicType rightType = node.right->GetExpressionType(); switch (node.op) { @@ -117,31 +117,31 @@ namespace Nz { switch (leftType) { - case ShaderNodes::ExpressionType::Float1: + case ShaderNodes::BasicType::Float1: { - if (ShaderNodes::Node::GetComponentType(rightType) != ShaderNodes::ExpressionType::Float1) + if (ShaderNodes::Node::GetComponentType(rightType) != ShaderNodes::BasicType::Float1) throw AstError{ "Left expression type is not compatible with right expression type" }; break; } - case ShaderNodes::ExpressionType::Float2: - case ShaderNodes::ExpressionType::Float3: - case ShaderNodes::ExpressionType::Float4: + case ShaderNodes::BasicType::Float2: + case ShaderNodes::BasicType::Float3: + case ShaderNodes::BasicType::Float4: { - if (leftType != rightType && rightType != ShaderNodes::ExpressionType::Float1) + if (leftType != rightType && rightType != ShaderNodes::BasicType::Float1) throw AstError{ "Left expression type is not compatible with right expression type" }; break; } - case ShaderNodes::ExpressionType::Mat4x4: + case ShaderNodes::BasicType::Mat4x4: { switch (rightType) { - case ShaderNodes::ExpressionType::Float1: - case ShaderNodes::ExpressionType::Float4: - case ShaderNodes::ExpressionType::Mat4x4: + case ShaderNodes::BasicType::Float1: + case ShaderNodes::BasicType::Float4: + case ShaderNodes::BasicType::Mat4x4: break; default: @@ -318,7 +318,7 @@ namespace Nz for (auto& param : node.parameters) MandatoryNode(param); - ShaderNodes::ExpressionType type = node.parameters.front()->GetExpressionType(); + ShaderNodes::BasicType type = node.parameters.front()->GetExpressionType(); for (std::size_t i = 1; i < node.parameters.size(); ++i) { if (type != node.parameters[i]->GetExpressionType()) @@ -333,7 +333,7 @@ namespace Nz { case ShaderNodes::IntrinsicType::CrossProduct: { - if (node.parameters[0]->GetExpressionType() != ShaderNodes::ExpressionType::Float3) + if (node.parameters[0]->GetExpressionType() != ShaderNodes::BasicType::Float3) throw AstError{ "CrossProduct only works with Float3 expressions" }; break; @@ -349,10 +349,10 @@ namespace Nz void ShaderValidator::Visit(const ShaderNodes::Sample2D& node) { - if (MandatoryExpr(node.sampler)->GetExpressionType() != ShaderNodes::ExpressionType::Sampler2D) + if (MandatoryExpr(node.sampler)->GetExpressionType() != ShaderNodes::BasicType::Sampler2D) throw AstError{ "Sampler must be a Sampler2D" }; - if (MandatoryExpr(node.coordinates)->GetExpressionType() != ShaderNodes::ExpressionType::Float2) + if (MandatoryExpr(node.coordinates)->GetExpressionType() != ShaderNodes::BasicType::Float2) throw AstError{ "Coordinates must be a Float2" }; Visit(node.sampler); @@ -380,10 +380,10 @@ namespace Nz switch (MandatoryExpr(node.expression)->GetExpressionType()) { - case ShaderNodes::ExpressionType::Float1: - case ShaderNodes::ExpressionType::Float2: - case ShaderNodes::ExpressionType::Float3: - case ShaderNodes::ExpressionType::Float4: + case ShaderNodes::BasicType::Float1: + case ShaderNodes::BasicType::Float2: + case ShaderNodes::BasicType::Float3: + case ShaderNodes::BasicType::Float4: break; default: diff --git a/src/ShaderNode/DataModels/InputValue.cpp b/src/ShaderNode/DataModels/InputValue.cpp index a5a3a269b..f9337f262 100644 --- a/src/ShaderNode/DataModels/InputValue.cpp +++ b/src/ShaderNode/DataModels/InputValue.cpp @@ -116,15 +116,15 @@ Nz::ShaderNodes::ExpressionPtr InputValue::GetExpression(Nz::ShaderNodes::Expres const auto& inputEntry = GetGraph().GetInput(*m_currentInputIndex); - Nz::ShaderNodes::ExpressionType expression = [&] + Nz::ShaderNodes::BasicType expression = [&] { switch (inputEntry.type) { - case PrimitiveType::Bool: return Nz::ShaderNodes::ExpressionType::Boolean; - case PrimitiveType::Float1: return Nz::ShaderNodes::ExpressionType::Float1; - case PrimitiveType::Float2: return Nz::ShaderNodes::ExpressionType::Float2; - case PrimitiveType::Float3: return Nz::ShaderNodes::ExpressionType::Float3; - case PrimitiveType::Float4: return Nz::ShaderNodes::ExpressionType::Float4; + case PrimitiveType::Bool: return Nz::ShaderNodes::BasicType::Boolean; + case PrimitiveType::Float1: return Nz::ShaderNodes::BasicType::Float1; + case PrimitiveType::Float2: return Nz::ShaderNodes::BasicType::Float2; + case PrimitiveType::Float3: return Nz::ShaderNodes::BasicType::Float3; + case PrimitiveType::Float4: return Nz::ShaderNodes::BasicType::Float4; } assert(false); @@ -145,7 +145,7 @@ auto InputValue::dataType(QtNodes::PortType portType, QtNodes::PortIndex portInd const auto& inputEntry = GetGraph().GetInput(*m_currentInputIndex); switch (inputEntry.type) { - //case InputType::Bool: return Nz::ShaderNodes::ExpressionType::Boolean; + //case InputType::Bool: return Nz::ShaderNodes::BasicType::Boolean; case PrimitiveType::Float1: return FloatData::Type(); diff --git a/src/ShaderNode/DataModels/OutputValue.cpp b/src/ShaderNode/DataModels/OutputValue.cpp index 1f65c5953..b86c46879 100644 --- a/src/ShaderNode/DataModels/OutputValue.cpp +++ b/src/ShaderNode/DataModels/OutputValue.cpp @@ -63,15 +63,15 @@ Nz::ShaderNodes::ExpressionPtr OutputValue::GetExpression(Nz::ShaderNodes::Expre const auto& outputEntry = GetGraph().GetOutput(*m_currentOutputIndex); - Nz::ShaderNodes::ExpressionType expression = [&] + Nz::ShaderNodes::BasicType expression = [&] { switch (outputEntry.type) { - case PrimitiveType::Bool: return Nz::ShaderNodes::ExpressionType::Boolean; - case PrimitiveType::Float1: return Nz::ShaderNodes::ExpressionType::Float1; - case PrimitiveType::Float2: return Nz::ShaderNodes::ExpressionType::Float2; - case PrimitiveType::Float3: return Nz::ShaderNodes::ExpressionType::Float3; - case PrimitiveType::Float4: return Nz::ShaderNodes::ExpressionType::Float4; + case PrimitiveType::Bool: return Nz::ShaderNodes::BasicType::Boolean; + case PrimitiveType::Float1: return Nz::ShaderNodes::BasicType::Float1; + case PrimitiveType::Float2: return Nz::ShaderNodes::BasicType::Float2; + case PrimitiveType::Float3: return Nz::ShaderNodes::BasicType::Float3; + case PrimitiveType::Float4: return Nz::ShaderNodes::BasicType::Float4; } assert(false); @@ -94,8 +94,8 @@ QtNodes::NodeDataType OutputValue::dataType(QtNodes::PortType portType, QtNodes: const auto& outputEntry = GetGraph().GetOutput(*m_currentOutputIndex); switch (outputEntry.type) { - //case InOutType::Bool: return Nz::ShaderNodes::ExpressionType::Boolean; - //case InOutType::Float1: return Nz::ShaderNodes::ExpressionType::Float1; + //case InOutType::Bool: return Nz::ShaderNodes::BasicType::Boolean; + //case InOutType::Float1: return Nz::ShaderNodes::BasicType::Float1; case PrimitiveType::Float2: case PrimitiveType::Float3: case PrimitiveType::Float4: diff --git a/src/ShaderNode/DataModels/TextureValue.cpp b/src/ShaderNode/DataModels/TextureValue.cpp index 6a6402cf4..79df6de5c 100644 --- a/src/ShaderNode/DataModels/TextureValue.cpp +++ b/src/ShaderNode/DataModels/TextureValue.cpp @@ -119,11 +119,11 @@ Nz::ShaderNodes::ExpressionPtr TextureValue::GetExpression(Nz::ShaderNodes::Expr const auto& textureEntry = GetGraph().GetTexture(*m_currentTextureIndex); - Nz::ShaderNodes::ExpressionType expression = [&] + Nz::ShaderNodes::BasicType expression = [&] { switch (textureEntry.type) { - case TextureType::Sampler2D: return Nz::ShaderNodes::ExpressionType::Sampler2D; + case TextureType::Sampler2D: return Nz::ShaderNodes::BasicType::Sampler2D; } assert(false); diff --git a/src/ShaderNode/DataTypes/VecData.cpp b/src/ShaderNode/DataTypes/VecData.cpp index 2d4a38001..0402864e0 100644 --- a/src/ShaderNode/DataTypes/VecData.cpp +++ b/src/ShaderNode/DataTypes/VecData.cpp @@ -2,13 +2,13 @@ #include #include -Nz::ShaderNodes::ExpressionType VecData::GetExpressionType() const +Nz::ShaderNodes::BasicType VecData::GetExpressionType() const { switch (componentCount) { - case 2: return Nz::ShaderNodes::ExpressionType::Float2; - case 3: return Nz::ShaderNodes::ExpressionType::Float3; - case 4: return Nz::ShaderNodes::ExpressionType::Float4; + case 2: return Nz::ShaderNodes::BasicType::Float2; + case 3: return Nz::ShaderNodes::BasicType::Float3; + case 4: return Nz::ShaderNodes::BasicType::Float4; default: break; } diff --git a/src/ShaderNode/DataTypes/VecData.hpp b/src/ShaderNode/DataTypes/VecData.hpp index 3c6a8f096..7c515a12a 100644 --- a/src/ShaderNode/DataTypes/VecData.hpp +++ b/src/ShaderNode/DataTypes/VecData.hpp @@ -13,7 +13,7 @@ struct VecData : public QtNodes::NodeData inline QtNodes::NodeDataType type() const override; - Nz::ShaderNodes::ExpressionType GetExpressionType() const; + Nz::ShaderNodes::BasicType GetExpressionType() const; static inline QtNodes::NodeDataType Type(); @@ -27,28 +27,28 @@ struct VecExpressionTypeHelper; template<> struct VecExpressionTypeHelper<1> { - static constexpr Nz::ShaderNodes::ExpressionType ExpressionType = Nz::ShaderNodes::ExpressionType::Float1; + static constexpr Nz::ShaderNodes::BasicType ExpressionType = Nz::ShaderNodes::BasicType::Float1; }; template<> struct VecExpressionTypeHelper<2> { - static constexpr Nz::ShaderNodes::ExpressionType ExpressionType = Nz::ShaderNodes::ExpressionType::Float2; + static constexpr Nz::ShaderNodes::BasicType ExpressionType = Nz::ShaderNodes::BasicType::Float2; }; template<> struct VecExpressionTypeHelper<3> { - static constexpr Nz::ShaderNodes::ExpressionType ExpressionType = Nz::ShaderNodes::ExpressionType::Float3; + static constexpr Nz::ShaderNodes::BasicType ExpressionType = Nz::ShaderNodes::BasicType::Float3; }; template<> struct VecExpressionTypeHelper<4> { - static constexpr Nz::ShaderNodes::ExpressionType ExpressionType = Nz::ShaderNodes::ExpressionType::Float4; + static constexpr Nz::ShaderNodes::BasicType ExpressionType = Nz::ShaderNodes::BasicType::Float4; }; -template constexpr Nz::ShaderNodes::ExpressionType VecExpressionType = VecExpressionTypeHelper::template ExpressionType; +template constexpr Nz::ShaderNodes::BasicType VecExpressionType = VecExpressionTypeHelper::template ExpressionType; struct VecTypeDummy {}; diff --git a/src/ShaderNode/Widgets/MainWindow.cpp b/src/ShaderNode/Widgets/MainWindow.cpp index 213d190cb..813d1b5ab 100644 --- a/src/ShaderNode/Widgets/MainWindow.cpp +++ b/src/ShaderNode/Widgets/MainWindow.cpp @@ -217,11 +217,11 @@ Nz::ShaderAst MainWindow::ToShader() { switch (type) { - case PrimitiveType::Bool: return Nz::ShaderNodes::ExpressionType::Boolean; - case PrimitiveType::Float1: return Nz::ShaderNodes::ExpressionType::Float1; - case PrimitiveType::Float2: return Nz::ShaderNodes::ExpressionType::Float2; - case PrimitiveType::Float3: return Nz::ShaderNodes::ExpressionType::Float3; - case PrimitiveType::Float4: return Nz::ShaderNodes::ExpressionType::Float4; + case PrimitiveType::Bool: return Nz::ShaderNodes::BasicType::Boolean; + case PrimitiveType::Float1: return Nz::ShaderNodes::BasicType::Float1; + case PrimitiveType::Float2: return Nz::ShaderNodes::BasicType::Float2; + case PrimitiveType::Float3: return Nz::ShaderNodes::BasicType::Float3; + case PrimitiveType::Float4: return Nz::ShaderNodes::BasicType::Float4; } assert(false); @@ -232,7 +232,7 @@ Nz::ShaderAst MainWindow::ToShader() { switch (type) { - case TextureType::Sampler2D: return Nz::ShaderNodes::ExpressionType::Sampler2D; + case TextureType::Sampler2D: return Nz::ShaderNodes::BasicType::Sampler2D; } assert(false); From 086f76fb97458fe417f95347582a3a9059b743a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Sun, 19 Jul 2020 21:05:46 +0200 Subject: [PATCH 055/105] Renderer/ShaderNodes: Add support for accessing struct fields --- include/Nazara/Renderer/GlslWriter.hpp | 2 + include/Nazara/Renderer/ShaderBuilder.hpp | 1 + include/Nazara/Renderer/ShaderEnums.hpp | 1 + .../Nazara/Renderer/ShaderExpressionType.hpp | 2 +- include/Nazara/Renderer/ShaderNodes.hpp | 34 +++++++--- include/Nazara/Renderer/ShaderNodes.inl | 16 +++++ include/Nazara/Renderer/ShaderSerializer.hpp | 6 +- include/Nazara/Renderer/ShaderValidator.hpp | 1 + include/Nazara/Renderer/ShaderVariables.hpp | 16 ++--- include/Nazara/Renderer/ShaderVariables.inl | 12 ++-- include/Nazara/Renderer/ShaderVisitor.hpp | 1 + src/Nazara/Renderer/GlslWriter.cpp | 32 +++++++-- src/Nazara/Renderer/ShaderNodes.cpp | 65 +++++++++++++------ src/Nazara/Renderer/ShaderSerializer.cpp | 38 ++++++++++- src/Nazara/Renderer/ShaderValidator.cpp | 56 +++++++++++++--- 15 files changed, 221 insertions(+), 62 deletions(-) diff --git a/include/Nazara/Renderer/GlslWriter.hpp b/include/Nazara/Renderer/GlslWriter.hpp index 94ca21676..ba2444aec 100644 --- a/include/Nazara/Renderer/GlslWriter.hpp +++ b/include/Nazara/Renderer/GlslWriter.hpp @@ -61,6 +61,7 @@ namespace Nz using ShaderVarVisitor::Visit; using ShaderVisitor::Visit; + void Visit(const ShaderNodes::AccessMember& node) override; void Visit(const ShaderNodes::AssignOp& node) override; void Visit(const ShaderNodes::Branch& node) override; void Visit(const ShaderNodes::BinaryOp& node) override; @@ -85,6 +86,7 @@ namespace Nz struct Context { + const ShaderAst* shader = nullptr; const ShaderAst::Function* currentFunction = nullptr; }; diff --git a/include/Nazara/Renderer/ShaderBuilder.hpp b/include/Nazara/Renderer/ShaderBuilder.hpp index 7d8502151..8f544e018 100644 --- a/include/Nazara/Renderer/ShaderBuilder.hpp +++ b/include/Nazara/Renderer/ShaderBuilder.hpp @@ -44,6 +44,7 @@ namespace Nz::ShaderBuilder template std::shared_ptr operator()(Args&&... args) const; }; + constexpr GenBuilder AccessMember; constexpr BinOpBuilder Add; constexpr AssignOpBuilder Assign; constexpr BuiltinBuilder Builtin; diff --git a/include/Nazara/Renderer/ShaderEnums.hpp b/include/Nazara/Renderer/ShaderEnums.hpp index a9db1abe8..6edaad1de 100644 --- a/include/Nazara/Renderer/ShaderEnums.hpp +++ b/include/Nazara/Renderer/ShaderEnums.hpp @@ -65,6 +65,7 @@ namespace Nz::ShaderNodes { None = -1, + AccessMember, AssignOp, BinaryOp, Branch, diff --git a/include/Nazara/Renderer/ShaderExpressionType.hpp b/include/Nazara/Renderer/ShaderExpressionType.hpp index c937d6a10..68671b07c 100644 --- a/include/Nazara/Renderer/ShaderExpressionType.hpp +++ b/include/Nazara/Renderer/ShaderExpressionType.hpp @@ -8,7 +8,7 @@ #define NAZARA_SHADER_EXPRESSIONTYPE_HPP #include -#include +#include #include #include diff --git a/include/Nazara/Renderer/ShaderNodes.hpp b/include/Nazara/Renderer/ShaderNodes.hpp index 57ff5ab60..0c5049df9 100644 --- a/include/Nazara/Renderer/ShaderNodes.hpp +++ b/include/Nazara/Renderer/ShaderNodes.hpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -59,7 +60,7 @@ namespace Nz inline Expression(NodeType type); virtual ExpressionCategory GetExpressionCategory() const; - virtual BasicType GetExpressionType() const = 0; + virtual ShaderExpressionType GetExpressionType() const = 0; }; class Statement; @@ -125,7 +126,7 @@ namespace Nz inline Identifier(); ExpressionCategory GetExpressionCategory() const override; - BasicType GetExpressionType() const override; + ShaderExpressionType GetExpressionType() const override; void Visit(ShaderVisitor& visitor) override; VariablePtr var; @@ -133,13 +134,28 @@ namespace Nz static inline std::shared_ptr Build(VariablePtr variable); }; + struct NAZARA_RENDERER_API AccessMember : public Expression + { + inline AccessMember(); + + ExpressionCategory GetExpressionCategory() const override; + ShaderExpressionType GetExpressionType() const override; + void Visit(ShaderVisitor& visitor) override; + + std::size_t memberIndex; + ExpressionPtr structExpr; + ShaderExpressionType exprType; //< FIXME: Use ShaderAst to automate + + static inline std::shared_ptr Build(ExpressionPtr structExpr, std::size_t memberIndex, ShaderExpressionType exprType); + }; + ////////////////////////////////////////////////////////////////////////// struct NAZARA_RENDERER_API AssignOp : public Expression { inline AssignOp(); - BasicType GetExpressionType() const override; + ShaderExpressionType GetExpressionType() const override; void Visit(ShaderVisitor& visitor) override; AssignType op; @@ -153,7 +169,7 @@ namespace Nz { inline BinaryOp(); - BasicType GetExpressionType() const override; + ShaderExpressionType GetExpressionType() const override; void Visit(ShaderVisitor& visitor) override; BinaryType op; @@ -187,7 +203,7 @@ namespace Nz { inline Cast(); - BasicType GetExpressionType() const override; + ShaderExpressionType GetExpressionType() const override; void Visit(ShaderVisitor& visitor) override; BasicType exprType; @@ -201,7 +217,7 @@ namespace Nz { inline Constant(); - BasicType GetExpressionType() const override; + ShaderExpressionType GetExpressionType() const override; void Visit(ShaderVisitor& visitor) override; BasicType exprType; @@ -227,7 +243,7 @@ namespace Nz inline SwizzleOp(); ExpressionCategory GetExpressionCategory() const override; - BasicType GetExpressionType() const override; + ShaderExpressionType GetExpressionType() const override; void Visit(ShaderVisitor& visitor) override; std::array components; @@ -243,7 +259,7 @@ namespace Nz { inline Sample2D(); - BasicType GetExpressionType() const override; + ShaderExpressionType GetExpressionType() const override; void Visit(ShaderVisitor& visitor) override; ExpressionPtr sampler; @@ -258,7 +274,7 @@ namespace Nz { inline IntrinsicCall(); - BasicType GetExpressionType() const override; + ShaderExpressionType GetExpressionType() const override; void Visit(ShaderVisitor& visitor) override; IntrinsicType intrinsic; diff --git a/include/Nazara/Renderer/ShaderNodes.inl b/include/Nazara/Renderer/ShaderNodes.inl index 31d3028ed..606487e0c 100644 --- a/include/Nazara/Renderer/ShaderNodes.inl +++ b/include/Nazara/Renderer/ShaderNodes.inl @@ -146,6 +146,22 @@ namespace Nz::ShaderNodes } + inline AccessMember::AccessMember() : + Expression(NodeType::AccessMember) + { + } + + inline std::shared_ptr AccessMember::Build(ExpressionPtr structExpr, std::size_t memberIndex, ShaderExpressionType exprType) + { + auto node = std::make_shared(); + node->exprType = std::move(exprType); + node->memberIndex = memberIndex; + node->structExpr = std::move(structExpr); + + return node; + } + + inline AssignOp::AssignOp() : Expression(NodeType::AssignOp) { diff --git a/include/Nazara/Renderer/ShaderSerializer.hpp b/include/Nazara/Renderer/ShaderSerializer.hpp index e4e6be7b3..c6596b58d 100644 --- a/include/Nazara/Renderer/ShaderSerializer.hpp +++ b/include/Nazara/Renderer/ShaderSerializer.hpp @@ -25,6 +25,7 @@ namespace Nz ShaderSerializerBase(ShaderSerializerBase&&) = delete; ~ShaderSerializerBase() = default; + void Serialize(ShaderNodes::AccessMember& node); void Serialize(ShaderNodes::AssignOp& node); void Serialize(ShaderNodes::BinaryOp& node); void Serialize(ShaderNodes::BuiltinVariable& var); @@ -51,6 +52,8 @@ namespace Nz virtual void Node(ShaderNodes::NodePtr& node) = 0; template void Node(std::shared_ptr& node); + virtual void Type(ShaderExpressionType& type) = 0; + virtual void Value(bool& val) = 0; virtual void Value(float& val) = 0; virtual void Value(std::string& val) = 0; @@ -78,6 +81,7 @@ namespace Nz bool IsWriting() const override; void Node(const ShaderNodes::NodePtr& node); void Node(ShaderNodes::NodePtr& node) override; + void Type(ShaderExpressionType& type) override; void Value(bool& val) override; void Value(float& val) override; void Value(std::string& val) override; @@ -103,7 +107,7 @@ namespace Nz private: bool IsWriting() const override; void Node(ShaderNodes::NodePtr& node) override; - void Type(ShaderExpressionType& type); + void Type(ShaderExpressionType& type) override; void Value(bool& val) override; void Value(float& val) override; void Value(std::string& val) override; diff --git a/include/Nazara/Renderer/ShaderValidator.hpp b/include/Nazara/Renderer/ShaderValidator.hpp index ecfea1290..09015b073 100644 --- a/include/Nazara/Renderer/ShaderValidator.hpp +++ b/include/Nazara/Renderer/ShaderValidator.hpp @@ -33,6 +33,7 @@ namespace Nz void TypeMustMatch(const ShaderExpressionType& left, const ShaderExpressionType& right); using ShaderVisitor::Visit; + void Visit(const ShaderNodes::AccessMember& node) override; void Visit(const ShaderNodes::AssignOp& node) override; void Visit(const ShaderNodes::BinaryOp& node) override; void Visit(const ShaderNodes::Branch& node) override; diff --git a/include/Nazara/Renderer/ShaderVariables.hpp b/include/Nazara/Renderer/ShaderVariables.hpp index f80386d0c..9b52d3913 100644 --- a/include/Nazara/Renderer/ShaderVariables.hpp +++ b/include/Nazara/Renderer/ShaderVariables.hpp @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include #include @@ -34,7 +34,7 @@ namespace Nz virtual VariableType GetType() const = 0; virtual void Visit(ShaderVarVisitor& visitor) = 0; - BasicType type; + ShaderExpressionType type; }; struct BuiltinVariable; @@ -48,7 +48,7 @@ namespace Nz VariableType GetType() const override; void Visit(ShaderVarVisitor& visitor) override; - static inline std::shared_ptr Build(BuiltinEntry entry, BasicType varType); + static inline std::shared_ptr Build(BuiltinEntry entry, ShaderExpressionType varType); }; struct NamedVariable; @@ -69,7 +69,7 @@ namespace Nz VariableType GetType() const override; void Visit(ShaderVarVisitor& visitor) override; - static inline std::shared_ptr Build(std::string varName, BasicType varType); + static inline std::shared_ptr Build(std::string varName, ShaderExpressionType varType); }; struct LocalVariable; @@ -81,7 +81,7 @@ namespace Nz VariableType GetType() const override; void Visit(ShaderVarVisitor& visitor) override; - static inline std::shared_ptr Build(std::string varName, BasicType varType); + static inline std::shared_ptr Build(std::string varName, ShaderExpressionType varType); }; struct OutputVariable; @@ -93,7 +93,7 @@ namespace Nz VariableType GetType() const override; void Visit(ShaderVarVisitor& visitor) override; - static inline std::shared_ptr Build(std::string varName, BasicType varType); + static inline std::shared_ptr Build(std::string varName, ShaderExpressionType varType); }; struct ParameterVariable; @@ -105,7 +105,7 @@ namespace Nz VariableType GetType() const override; void Visit(ShaderVarVisitor& visitor) override; - static inline std::shared_ptr Build(std::string varName, BasicType varType); + static inline std::shared_ptr Build(std::string varName, ShaderExpressionType varType); }; struct UniformVariable; @@ -117,7 +117,7 @@ namespace Nz VariableType GetType() const override; void Visit(ShaderVarVisitor& visitor) override; - static inline std::shared_ptr Build(std::string varName, BasicType varType); + static inline std::shared_ptr Build(std::string varName, ShaderExpressionType varType); }; } } diff --git a/include/Nazara/Renderer/ShaderVariables.inl b/include/Nazara/Renderer/ShaderVariables.inl index e01ecb33e..917459c67 100644 --- a/include/Nazara/Renderer/ShaderVariables.inl +++ b/include/Nazara/Renderer/ShaderVariables.inl @@ -7,7 +7,7 @@ namespace Nz::ShaderNodes { - inline std::shared_ptr BuiltinVariable::Build(BuiltinEntry variable, BasicType varType) + inline std::shared_ptr BuiltinVariable::Build(BuiltinEntry variable, ShaderExpressionType varType) { auto node = std::make_shared(); node->entry = variable; @@ -16,7 +16,7 @@ namespace Nz::ShaderNodes return node; } - inline std::shared_ptr InputVariable::Build(std::string varName, BasicType varType) + inline std::shared_ptr InputVariable::Build(std::string varName, ShaderExpressionType varType) { auto node = std::make_shared(); node->name = std::move(varName); @@ -25,7 +25,7 @@ namespace Nz::ShaderNodes return node; } - inline std::shared_ptr LocalVariable::Build(std::string varName, BasicType varType) + inline std::shared_ptr LocalVariable::Build(std::string varName, ShaderExpressionType varType) { auto node = std::make_shared(); node->name = std::move(varName); @@ -34,7 +34,7 @@ namespace Nz::ShaderNodes return node; } - inline std::shared_ptr OutputVariable::Build(std::string varName, BasicType varType) + inline std::shared_ptr OutputVariable::Build(std::string varName, ShaderExpressionType varType) { auto node = std::make_shared(); node->name = std::move(varName); @@ -43,7 +43,7 @@ namespace Nz::ShaderNodes return node; } - inline std::shared_ptr ParameterVariable::Build(std::string varName, BasicType varType) + inline std::shared_ptr ParameterVariable::Build(std::string varName, ShaderExpressionType varType) { auto node = std::make_shared(); node->name = std::move(varName); @@ -52,7 +52,7 @@ namespace Nz::ShaderNodes return node; } - inline std::shared_ptr UniformVariable::Build(std::string varName, BasicType varType) + inline std::shared_ptr UniformVariable::Build(std::string varName, ShaderExpressionType varType) { auto node = std::make_shared(); node->name = std::move(varName); diff --git a/include/Nazara/Renderer/ShaderVisitor.hpp b/include/Nazara/Renderer/ShaderVisitor.hpp index 9db22882c..1cd98fac3 100644 --- a/include/Nazara/Renderer/ShaderVisitor.hpp +++ b/include/Nazara/Renderer/ShaderVisitor.hpp @@ -27,6 +27,7 @@ namespace Nz bool IsConditionEnabled(const std::string& name) const; + virtual void Visit(const ShaderNodes::AccessMember& node) = 0; virtual void Visit(const ShaderNodes::AssignOp& node) = 0; virtual void Visit(const ShaderNodes::BinaryOp& node) = 0; virtual void Visit(const ShaderNodes::Branch& node) = 0; diff --git a/src/Nazara/Renderer/GlslWriter.cpp b/src/Nazara/Renderer/GlslWriter.cpp index 4dcbcd4cc..33ae8c0db 100644 --- a/src/Nazara/Renderer/GlslWriter.cpp +++ b/src/Nazara/Renderer/GlslWriter.cpp @@ -21,6 +21,8 @@ namespace Nz if (!ValidateShader(shader, &error)) throw std::runtime_error("Invalid shader AST: " + error); + m_context.shader = &shader; + State state; m_currentState = &state; CallOnExit onExit([this]() @@ -294,7 +296,30 @@ namespace Nz AppendLine(); AppendLine("}"); } - + + void GlslWriter::Visit(const ShaderNodes::AccessMember& node) + { + Append("("); + Visit(node.structExpr); + Append(")"); + + const ShaderExpressionType& exprType = node.structExpr->GetExpressionType(); + assert(std::holds_alternative(exprType)); + + const std::string& structName = std::get(exprType); + + const auto& structs = m_context.shader->GetStructs(); + auto it = std::find_if(structs.begin(), structs.end(), [&](const auto& s) { return s.name == structName; }); + assert(it != structs.end()); + + const ShaderAst::Struct& s = *it; + assert(node.memberIndex < s.members.size()); + + const auto& member = s.members[node.memberIndex]; + Append("."); + Append(member.name); + } + void GlslWriter::Visit(const ShaderNodes::AssignOp& node) { Visit(node.left); @@ -374,9 +399,7 @@ namespace Nz Append(node.exprType); Append("("); - unsigned int i = 0; - unsigned int requiredComponents = ShaderNodes::Node::GetComponentCount(node.exprType); - while (requiredComponents > 0) + for (std::size_t i = 0; node.expressions[i]; ++i) { if (i != 0) m_currentState->stream << ", "; @@ -385,7 +408,6 @@ namespace Nz NazaraAssert(exprPtr, "Invalid expression"); Visit(exprPtr); - requiredComponents -= ShaderNodes::Node::GetComponentCount(exprPtr->GetExpressionType()); } Append(")"); diff --git a/src/Nazara/Renderer/ShaderNodes.cpp b/src/Nazara/Renderer/ShaderNodes.cpp index 57ac58ee8..794e1217a 100644 --- a/src/Nazara/Renderer/ShaderNodes.cpp +++ b/src/Nazara/Renderer/ShaderNodes.cpp @@ -47,7 +47,7 @@ namespace Nz::ShaderNodes return ExpressionCategory::LValue; } - BasicType Identifier::GetExpressionType() const + ShaderExpressionType Identifier::GetExpressionType() const { assert(var); return var->type; @@ -58,8 +58,22 @@ namespace Nz::ShaderNodes visitor.Visit(*this); } + ExpressionCategory ShaderNodes::AccessMember::GetExpressionCategory() const + { + return ExpressionCategory::LValue; + } - BasicType AssignOp::GetExpressionType() const + ShaderExpressionType AccessMember::GetExpressionType() const + { + return exprType; + } + + void AccessMember::Visit(ShaderVisitor& visitor) + { + visitor.Visit(*this); + } + + ShaderExpressionType AssignOp::GetExpressionType() const { return left->GetExpressionType(); } @@ -70,31 +84,39 @@ namespace Nz::ShaderNodes } - BasicType BinaryOp::GetExpressionType() const + ShaderExpressionType BinaryOp::GetExpressionType() const { - ShaderNodes::BasicType exprType = ShaderNodes::BasicType::Void; + std::optional exprType; switch (op) { - case ShaderNodes::BinaryType::Add: - case ShaderNodes::BinaryType::Substract: + case BinaryType::Add: + case BinaryType::Substract: exprType = left->GetExpressionType(); break; - case ShaderNodes::BinaryType::Divide: - case ShaderNodes::BinaryType::Multiply: - //FIXME - exprType = static_cast(std::max(UnderlyingCast(left->GetExpressionType()), UnderlyingCast(right->GetExpressionType()))); - break; + case BinaryType::Divide: + case BinaryType::Multiply: + { + const ShaderExpressionType& leftExprType = left->GetExpressionType(); + assert(std::holds_alternative(leftExprType)); - case ShaderNodes::BinaryType::Equality: + const ShaderExpressionType& rightExprType = right->GetExpressionType(); + assert(std::holds_alternative(rightExprType)); + + //FIXME + exprType = static_cast(std::max(UnderlyingCast(std::get(leftExprType)), UnderlyingCast(std::get(rightExprType)))); + break; + } + + case BinaryType::Equality: exprType = BasicType::Boolean; break; } - NazaraAssert(exprType != ShaderNodes::BasicType::Void, "Unhandled builtin"); + NazaraAssert(exprType.has_value(), "Unhandled builtin"); - return exprType; + return *exprType; } void BinaryOp::Visit(ShaderVisitor& visitor) @@ -109,7 +131,7 @@ namespace Nz::ShaderNodes } - BasicType Constant::GetExpressionType() const + ShaderExpressionType Constant::GetExpressionType() const { return exprType; } @@ -119,7 +141,7 @@ namespace Nz::ShaderNodes visitor.Visit(*this); } - BasicType Cast::GetExpressionType() const + ShaderExpressionType Cast::GetExpressionType() const { return exprType; } @@ -135,9 +157,12 @@ namespace Nz::ShaderNodes return ExpressionCategory::LValue; } - BasicType SwizzleOp::GetExpressionType() const + ShaderExpressionType SwizzleOp::GetExpressionType() const { - return static_cast(UnderlyingCast(GetComponentType(expression->GetExpressionType())) + componentCount - 1); + const ShaderExpressionType& exprType = expression->GetExpressionType(); + assert(std::holds_alternative(exprType)); + + return static_cast(UnderlyingCast(GetComponentType(std::get(exprType))) + componentCount - 1); } void SwizzleOp::Visit(ShaderVisitor& visitor) @@ -146,7 +171,7 @@ namespace Nz::ShaderNodes } - BasicType Sample2D::GetExpressionType() const + ShaderExpressionType Sample2D::GetExpressionType() const { return BasicType::Float4; } @@ -157,7 +182,7 @@ namespace Nz::ShaderNodes } - BasicType IntrinsicCall::GetExpressionType() const + ShaderExpressionType IntrinsicCall::GetExpressionType() const { switch (intrinsic) { diff --git a/src/Nazara/Renderer/ShaderSerializer.cpp b/src/Nazara/Renderer/ShaderSerializer.cpp index 17f369037..71beead60 100644 --- a/src/Nazara/Renderer/ShaderSerializer.cpp +++ b/src/Nazara/Renderer/ShaderSerializer.cpp @@ -22,6 +22,11 @@ namespace Nz { } + void Visit(const ShaderNodes::AccessMember& node) override + { + Serialize(node); + } + void Visit(const ShaderNodes::AssignOp& node) override { Serialize(node); @@ -125,6 +130,13 @@ namespace Nz }; } + void ShaderSerializerBase::Serialize(ShaderNodes::AccessMember& node) + { + Value(node.memberIndex); + Node(node.structExpr); + Type(node.exprType); + } + void ShaderSerializerBase::Serialize(ShaderNodes::AssignOp& node) { Enum(node.op); @@ -153,8 +165,8 @@ namespace Nz void ShaderSerializerBase::Serialize(ShaderNodes::BuiltinVariable& node) { - Enum(node.type); - Enum(node.type); + Enum(node.entry); + Type(node.type); } void ShaderSerializerBase::Serialize(ShaderNodes::Cast& node) @@ -219,7 +231,7 @@ namespace Nz void ShaderSerializerBase::Serialize(ShaderNodes::NamedVariable& node) { Value(node.name); - Enum(node.type); + Type(node.type); } void ShaderSerializerBase::Serialize(ShaderNodes::Sample2D& node) @@ -348,6 +360,26 @@ namespace Nz } } + void ShaderSerializer::Type(ShaderExpressionType& type) + { + std::visit([&](auto&& arg) + { + using T = std::decay_t; + if constexpr (std::is_same_v) + { + m_stream << UInt8(0); + m_stream << UInt32(arg); + } + else if constexpr (std::is_same_v) + { + m_stream << UInt8(1); + m_stream << arg; + } + else + static_assert(AlwaysFalse::value, "non-exhaustive visitor"); + }, type); + } + void ShaderSerializer::Node(const ShaderNodes::NodePtr& node) { Node(const_cast(node)); //< Yes const_cast is ugly but it won't be used for writing diff --git a/src/Nazara/Renderer/ShaderValidator.cpp b/src/Nazara/Renderer/ShaderValidator.cpp index 1445d4cf1..c181ecd62 100644 --- a/src/Nazara/Renderer/ShaderValidator.cpp +++ b/src/Nazara/Renderer/ShaderValidator.cpp @@ -21,7 +21,7 @@ namespace Nz struct Local { std::string name; - ShaderNodes::BasicType type; + ShaderExpressionType type; }; const ShaderAst::Function* currentFunction; @@ -83,6 +83,28 @@ namespace Nz throw AstError{ "Left expression type must match right expression type" }; } + void ShaderValidator::Visit(const ShaderNodes::AccessMember& node) + { + const ShaderExpressionType& exprType = MandatoryExpr(node.structExpr)->GetExpressionType(); + if (!std::holds_alternative(exprType)) + throw AstError{ "expression is not a structure" }; + + const std::string& structName = std::get(exprType); + + const auto& structs = m_shader.GetStructs(); + auto it = std::find_if(structs.begin(), structs.end(), [&](const auto& s) { return s.name == structName; }); + if (it == structs.end()) + throw AstError{ "invalid structure" }; + + const ShaderAst::Struct& s = *it; + if (node.memberIndex >= s.members.size()) + throw AstError{ "member index out of bounds" }; + + const auto& member = s.members[node.memberIndex]; + if (member.type != node.exprType) + throw AstError{ "member type does not match node type" }; + } + void ShaderValidator::Visit(const ShaderNodes::AssignOp& node) { MandatoryNode(node.left); @@ -101,8 +123,16 @@ namespace Nz MandatoryNode(node.left); MandatoryNode(node.right); - ShaderNodes::BasicType leftType = node.left->GetExpressionType(); - ShaderNodes::BasicType rightType = node.right->GetExpressionType(); + const ShaderExpressionType& leftExprType = MandatoryExpr(node.left)->GetExpressionType(); + if (!std::holds_alternative(leftExprType)) + throw AstError{ "left expression type does not support binary operation" }; + + const ShaderExpressionType& rightExprType = MandatoryExpr(node.right)->GetExpressionType(); + if (!std::holds_alternative(rightExprType)) + throw AstError{ "right expression type does not support binary operation" }; + + ShaderNodes::BasicType leftType = std::get(leftExprType); + ShaderNodes::BasicType rightType = std::get(rightExprType); switch (node.op) { @@ -179,7 +209,11 @@ namespace Nz if (!exprPtr) break; - componentCount += node.GetComponentCount(exprPtr->GetExpressionType()); + const ShaderExpressionType& exprType = exprPtr->GetExpressionType(); + if (!std::holds_alternative(exprType)) + throw AstError{ "incompatible type" }; + + componentCount += node.GetComponentCount(std::get(exprType)); Visit(exprPtr); } @@ -318,7 +352,7 @@ namespace Nz for (auto& param : node.parameters) MandatoryNode(param); - ShaderNodes::BasicType type = node.parameters.front()->GetExpressionType(); + ShaderExpressionType type = node.parameters.front()->GetExpressionType(); for (std::size_t i = 1; i < node.parameters.size(); ++i) { if (type != node.parameters[i]->GetExpressionType()) @@ -333,7 +367,7 @@ namespace Nz { case ShaderNodes::IntrinsicType::CrossProduct: { - if (node.parameters[0]->GetExpressionType() != ShaderNodes::BasicType::Float3) + if (node.parameters[0]->GetExpressionType() != ShaderExpressionType{ ShaderNodes::BasicType::Float3 }) throw AstError{ "CrossProduct only works with Float3 expressions" }; break; @@ -349,10 +383,10 @@ namespace Nz void ShaderValidator::Visit(const ShaderNodes::Sample2D& node) { - if (MandatoryExpr(node.sampler)->GetExpressionType() != ShaderNodes::BasicType::Sampler2D) + if (MandatoryExpr(node.sampler)->GetExpressionType() != ShaderExpressionType{ ShaderNodes::BasicType::Sampler2D }) throw AstError{ "Sampler must be a Sampler2D" }; - if (MandatoryExpr(node.coordinates)->GetExpressionType() != ShaderNodes::BasicType::Float2) + if (MandatoryExpr(node.coordinates)->GetExpressionType() != ShaderExpressionType{ ShaderNodes::BasicType::Float2 }) throw AstError{ "Coordinates must be a Float2" }; Visit(node.sampler); @@ -378,7 +412,11 @@ namespace Nz if (node.componentCount > 4) throw AstError{ "Cannot swizzle more than four elements" }; - switch (MandatoryExpr(node.expression)->GetExpressionType()) + const ShaderExpressionType& exprType = MandatoryExpr(node.expression)->GetExpressionType(); + if (!std::holds_alternative(exprType)) + throw AstError{ "Cannot swizzle this type" }; + + switch (std::get(exprType)) { case ShaderNodes::BasicType::Float1: case ShaderNodes::BasicType::Float2: From 5258f0b61a6e596d76e0884c38a1af35d56b7377 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Sun, 19 Jul 2020 21:08:21 +0200 Subject: [PATCH 056/105] ShaderNodes: Add BufferField node --- src/ShaderNode/DataModels/BufferField.cpp | 409 ++++++++++++++++++++++ src/ShaderNode/DataModels/BufferField.hpp | 67 ++++ src/ShaderNode/DataModels/BufferField.inl | 2 + src/ShaderNode/DataTypes/BoolData.cpp | 1 + src/ShaderNode/DataTypes/BoolData.hpp | 28 ++ src/ShaderNode/DataTypes/BoolData.inl | 7 + 6 files changed, 514 insertions(+) create mode 100644 src/ShaderNode/DataModels/BufferField.cpp create mode 100644 src/ShaderNode/DataModels/BufferField.hpp create mode 100644 src/ShaderNode/DataModels/BufferField.inl create mode 100644 src/ShaderNode/DataTypes/BoolData.cpp create mode 100644 src/ShaderNode/DataTypes/BoolData.hpp create mode 100644 src/ShaderNode/DataTypes/BoolData.inl diff --git a/src/ShaderNode/DataModels/BufferField.cpp b/src/ShaderNode/DataModels/BufferField.cpp new file mode 100644 index 000000000..c9d81bdcd --- /dev/null +++ b/src/ShaderNode/DataModels/BufferField.cpp @@ -0,0 +1,409 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +BufferField::BufferField(ShaderGraph& graph) : +ShaderNode(graph) +{ + m_onBufferListUpdateSlot.Connect(GetGraph().OnBufferListUpdate, [&](ShaderGraph*) { UpdateCurrentBufferIndex(); }); + m_onBufferUpdateSlot.Connect(GetGraph().OnBufferUpdate, [&](ShaderGraph*, std::size_t bufferIndex) + { + if (m_currentBufferIndex == bufferIndex) + { + UpdatePreview(); + Q_EMIT dataUpdated(0); + } + }); + + if (graph.GetBufferCount() > 0) + { + m_currentBufferIndex = 0; + UpdateBufferText(); + } + + DisableCustomVariableName(); + UpdatePreview(); +} + +unsigned int BufferField::nPorts(QtNodes::PortType portType) const +{ + switch (portType) + { + case QtNodes::PortType::In: return 0; + case QtNodes::PortType::Out: return 1; + } + + return 0; +} + +bool BufferField::ComputePreview(QPixmap& pixmap) +{ + return false; + + /*if (!m_currentBufferIndex) + return false; + + const ShaderGraph& graph = GetGraph(); + const auto& inputEntry = graph.GetBuffer(*m_currentBufferIndex); + const auto& preview = graph.GetPreviewModel(); + + pixmap = QPixmap::fromImage(preview.GetPreview(inputEntry.role, inputEntry.roleIndex).GenerateImage()); + return true;*/ +} + +void BufferField::UpdateCurrentBufferIndex() +{ + Nz::CallOnExit resetIfNotFound([&] + { + m_currentBufferIndex.reset(); + m_currentBufferText.clear(); + m_currentFieldIndex.reset(); + m_currentFieldText.clear(); + }); + + if (m_currentBufferText.empty()) + return; + + std::size_t bufferIndex = 0; + for (const auto& bufferEntry : GetGraph().GetBuffers()) + { + if (bufferEntry.name == m_currentBufferText) + { + m_currentBufferIndex = bufferIndex; + resetIfNotFound.Reset(); + break; + } + + bufferIndex++; + } +} + +void BufferField::UpdateCurrentFieldIndex() +{ + Nz::CallOnExit resetIfNotFound([&] + { + m_currentFieldIndex.reset(); + m_currentFieldText.clear(); + }); + + if (m_currentFieldText.empty()) + return; + + if (!m_currentFieldIndex) + m_currentFieldIndex.emplace(); + + CurrentField& currentField = *m_currentFieldIndex; + currentField.nestedFields.clear(); + + const ShaderGraph& graph = GetGraph(); + auto& buffer = graph.GetBuffer(*m_currentBufferIndex); + + std::function FetchField; + FetchField = [&](std::size_t structIndex, const std::string& prefix) -> bool + { + const auto& s = graph.GetStruct(structIndex); + for (auto it = s.members.begin(); it != s.members.end(); ++it) + { + const auto& member = *it; + + bool found = std::visit([&](auto&& arg) -> bool + { + using T = std::decay_t; + if constexpr (std::is_same_v) + { + if (prefix + member.name == m_currentFieldText) + { + currentField.finalFieldIndex = std::distance(s.members.begin(), it); + return true; + } + else + return false; + } + else if constexpr (std::is_same_v) + { + currentField.nestedFields.push_back(std::distance(s.members.begin(), it)); + bool found = FetchField(arg, prefix + member.name + "."); + if (!found) + { + currentField.nestedFields.pop_back(); + return false; + } + + return true; + } + else + static_assert(Nz::AlwaysFalse::value, "non-exhaustive visitor"); + }, + member.type); + + if (found) + return true; + } + + return false; + }; + + if (FetchField(buffer.structIndex, "")) + resetIfNotFound.Reset(); +} + +void BufferField::PopulateField(QComboBox* fieldList, std::size_t structIndex, const std::string& prefix) +{ + const auto& s = GetGraph().GetStruct(structIndex); + for (const auto& member : s.members) + { + std::visit([&](auto&& arg) + { + using T = std::decay_t; + if constexpr (std::is_same_v) + fieldList->addItem(QString::fromStdString(prefix + member.name)); + else if constexpr (std::is_same_v) + PopulateField(fieldList, arg, prefix + member.name + "."); + else + static_assert(AlwaysFalse::value, "non-exhaustive visitor"); + }, + member.type); + } +} + +const ShaderGraph::StructMemberEntry& BufferField::RetrieveNestedMember() const +{ + const ShaderGraph& graph = GetGraph(); + auto& buffer = graph.GetBuffer(*m_currentBufferIndex); + + assert(m_currentFieldIndex); + const CurrentField& currentField = *m_currentFieldIndex; + + const ShaderGraph::StructEntry* structEntry = &graph.GetStruct(buffer.structIndex); + for (std::size_t nestedIndex : currentField.nestedFields) + { + assert(nestedIndex < structEntry->members.size()); + const auto& memberEntry = structEntry->members[nestedIndex]; + assert(std::holds_alternative(memberEntry.type)); + + std::size_t nestedStructIndex = std::get(memberEntry.type); + structEntry = &graph.GetStruct(nestedStructIndex); + } + + return structEntry->members[currentField.finalFieldIndex]; +} + +void BufferField::UpdateBufferText() +{ + if (m_currentBufferIndex) + { + auto& buffer = GetGraph().GetBuffer(*m_currentBufferIndex); + m_currentBufferText = buffer.name; + } + else + m_currentBufferText.clear(); +} + +void BufferField::BuildNodeEdition(QFormLayout* layout) +{ + ShaderNode::BuildNodeEdition(layout); + + QComboBox* fieldSelection = new QComboBox; + connect(fieldSelection, qOverload(&QComboBox::currentIndexChanged), [=](int index) + { + if (index >= 0) + m_currentFieldText = fieldSelection->itemText(index).toStdString(); + else + m_currentFieldText.clear(); + + UpdateCurrentFieldIndex(); + UpdatePreview(); + + Q_EMIT dataUpdated(0); + }); + + QComboBox* bufferSelection = new QComboBox; + for (const auto& inputEntry : GetGraph().GetBuffers()) + bufferSelection->addItem(QString::fromStdString(inputEntry.name)); + + connect(bufferSelection, qOverload(&QComboBox::currentIndexChanged), [=](int index) + { + fieldSelection->clear(); + fieldSelection->setCurrentIndex(-1); + + if (index >= 0) + { + m_currentBufferIndex = static_cast(index); + + const ShaderGraph& graph = GetGraph(); + const auto& buffer = graph.GetBuffer(*m_currentBufferIndex); + PopulateField(fieldSelection, buffer.structIndex); + } + else + m_currentBufferIndex.reset(); + + UpdateBufferText(); + }); + + if (m_currentBufferIndex) + { + int index = int(*m_currentBufferIndex); + QString currentFieldText = QString::fromStdString(m_currentFieldText); + + bufferSelection->setCurrentIndex(-1); + bufferSelection->setCurrentIndex(index); + + fieldSelection->setCurrentText(currentFieldText); + } + else + { + bufferSelection->setCurrentIndex(-1); + fieldSelection->setCurrentIndex(-1); + } + + layout->addRow(tr("Buffer"), bufferSelection); + layout->addRow(tr("Field"), fieldSelection); +} + +Nz::ShaderNodes::ExpressionPtr BufferField::GetExpression(Nz::ShaderNodes::ExpressionPtr* /*expressions*/, std::size_t count) const +{ + assert(count == 0); + + if (!m_currentBufferIndex) + throw std::runtime_error("no buffer"); + + const ShaderGraph& graph = GetGraph(); + + const auto& bufferEntry = graph.GetBuffer(*m_currentBufferIndex); + const auto& structEntry = graph.GetStruct(bufferEntry.structIndex); + + Nz::ShaderNodes::VariablePtr varPtr; + switch (bufferEntry.type) + { + case BufferType::UniformBufferObject: + varPtr = Nz::ShaderBuilder::Uniform(bufferEntry.name, structEntry.name); + break; + } + + assert(varPtr); + + assert(m_currentFieldIndex); + const CurrentField& currentField = *m_currentFieldIndex; + + Nz::ShaderNodes::ExpressionPtr sourceExpr = Nz::ShaderBuilder::Identifier(varPtr); + + const ShaderGraph::StructEntry* sourceStruct = &structEntry; + for (std::size_t nestedIndex : currentField.nestedFields) + { + assert(nestedIndex < sourceStruct->members.size()); + const auto& memberEntry = sourceStruct->members[nestedIndex]; + assert(std::holds_alternative(memberEntry.type)); + + std::size_t nestedStructIndex = std::get(memberEntry.type); + sourceStruct = &graph.GetStruct(nestedStructIndex); + + sourceExpr = Nz::ShaderBuilder::AccessMember(std::move(sourceExpr), 0, graph.ToShaderExpressionType(memberEntry.type)); + } + + assert(currentField.finalFieldIndex < sourceStruct->members.size()); + const auto& memberEntry = sourceStruct->members[currentField.finalFieldIndex]; + assert(std::holds_alternative(memberEntry.type)); + + return Nz::ShaderBuilder::AccessMember(std::move(sourceExpr), 0, graph.ToShaderExpressionType(std::get(memberEntry.type))); +} + +auto BufferField::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const -> QtNodes::NodeDataType +{ + assert(portType == QtNodes::PortType::Out); + assert(portIndex == 0); + + if (!m_currentBufferIndex || !m_currentFieldIndex) + return VecData::Type(); + + const auto& member = RetrieveNestedMember(); + assert(std::holds_alternative(member.type)); + + switch (std::get(member.type)) + { + case PrimitiveType::Bool: + return BoolData::Type(); + + case PrimitiveType::Float1: + return FloatData::Type(); + + case PrimitiveType::Float2: + case PrimitiveType::Float3: + case PrimitiveType::Float4: + return VecData::Type(); + } + + assert(false); + throw std::runtime_error("Unhandled primitive type"); +} + +std::shared_ptr BufferField::outData(QtNodes::PortIndex port) +{ + if (!m_currentBufferIndex) + return nullptr; + + assert(port == 0); + + if (!m_currentBufferIndex || !m_currentFieldIndex) + return {}; + + const auto& member = RetrieveNestedMember(); + assert(std::holds_alternative(member.type)); + + switch (std::get(member.type)) + { + case PrimitiveType::Bool: return std::make_shared(); + case PrimitiveType::Float1: return std::make_shared(); + case PrimitiveType::Float2: return std::make_shared(2); + case PrimitiveType::Float3: return std::make_shared(3); + case PrimitiveType::Float4: return std::make_shared(4); + } + + assert(false); + throw std::runtime_error("Unhandled primitive type"); +} + +QtNodes::NodeValidationState BufferField::validationState() const +{ + if (!m_currentBufferIndex) + return QtNodes::NodeValidationState::Error; + + if (!m_currentFieldIndex) + return QtNodes::NodeValidationState::Error; + + return QtNodes::NodeValidationState::Valid; +} + +QString BufferField::validationMessage() const +{ + if (!m_currentBufferIndex) + return "No input selected"; + + if (!m_currentFieldIndex) + return "No field selected"; + + return QString(); +} + +void BufferField::restore(const QJsonObject& data) +{ + m_currentBufferText = data["buffer"].toString().toStdString(); + m_currentFieldText = data["field"].toString().toStdString(); + UpdateCurrentBufferIndex(); + + ShaderNode::restore(data); +} + +QJsonObject BufferField::save() const +{ + QJsonObject data = ShaderNode::save(); + data["buffer"] = QString::fromStdString(m_currentBufferText); + data["field"] = QString::fromStdString(m_currentFieldText); + + return data; +} diff --git a/src/ShaderNode/DataModels/BufferField.hpp b/src/ShaderNode/DataModels/BufferField.hpp new file mode 100644 index 000000000..304165386 --- /dev/null +++ b/src/ShaderNode/DataModels/BufferField.hpp @@ -0,0 +1,67 @@ +#pragma once + +#ifndef NAZARA_SHADERNODES_BUFFERFIELD_HPP +#define NAZARA_SHADERNODES_BUFFERFIELD_HPP + +#include +#include +#include +#include +#include +#include +#include + +class BufferField : public ShaderNode +{ + public: + BufferField(ShaderGraph& graph); + ~BufferField() = default; + + void BuildNodeEdition(QFormLayout* layout) override; + + Nz::ShaderNodes::ExpressionPtr GetExpression(Nz::ShaderNodes::ExpressionPtr* /*expressions*/, std::size_t count) const override; + + QString caption() const override { return "BufferField"; } + QString name() const override { return "BufferField"; } + + unsigned int nPorts(QtNodes::PortType portType) const override; + + QtNodes::NodeDataType dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; + + std::shared_ptr outData(QtNodes::PortIndex port) override; + + QtNodes::NodeValidationState validationState() const override; + QString validationMessage() const override; + + private: + bool ComputePreview(QPixmap& pixmap) override; + void UpdateCurrentBufferIndex(); + void UpdateCurrentFieldIndex(); + void PopulateField(QComboBox* fieldList, std::size_t structIndex, const std::string& prefix = ""); + const ShaderGraph::StructMemberEntry& RetrieveNestedMember() const; + void UpdateBufferText(); + + void restore(const QJsonObject& data) override; + QJsonObject save() const override; + + NazaraSlot(ShaderGraph, OnBufferListUpdate, m_onBufferListUpdateSlot); + NazaraSlot(ShaderGraph, OnBufferUpdate, m_onBufferUpdateSlot); + + NazaraSlot(ShaderGraph, OnStructListUpdate, m_onStructListUpdateSlot); + NazaraSlot(ShaderGraph, OnStructUpdate, m_onStructUpdateSlot); + + struct CurrentField + { + std::vector nestedFields; + std::size_t finalFieldIndex; + }; + + std::optional m_currentBufferIndex; + std::optional m_currentFieldIndex; + std::string m_currentBufferText; + std::string m_currentFieldText; +}; + +#include + +#endif diff --git a/src/ShaderNode/DataModels/BufferField.inl b/src/ShaderNode/DataModels/BufferField.inl new file mode 100644 index 000000000..67cd1a5e7 --- /dev/null +++ b/src/ShaderNode/DataModels/BufferField.inl @@ -0,0 +1,2 @@ +#include +#include diff --git a/src/ShaderNode/DataTypes/BoolData.cpp b/src/ShaderNode/DataTypes/BoolData.cpp new file mode 100644 index 000000000..7c3123701 --- /dev/null +++ b/src/ShaderNode/DataTypes/BoolData.cpp @@ -0,0 +1 @@ +#include diff --git a/src/ShaderNode/DataTypes/BoolData.hpp b/src/ShaderNode/DataTypes/BoolData.hpp new file mode 100644 index 000000000..adb410888 --- /dev/null +++ b/src/ShaderNode/DataTypes/BoolData.hpp @@ -0,0 +1,28 @@ +#pragma once + +#ifndef NAZARA_SHADERNODES_BOOLDATA_HPP +#define NAZARA_SHADERNODES_BOOLDATA_HPP + +#include +#include + +struct BoolData : public QtNodes::NodeData +{ + inline BoolData(); + + QtNodes::NodeDataType type() const override + { + return Type(); + } + + static QtNodes::NodeDataType Type() + { + return { "bool", "Bool" }; + } + + PreviewValues preview; +}; + +#include + +#endif diff --git a/src/ShaderNode/DataTypes/BoolData.inl b/src/ShaderNode/DataTypes/BoolData.inl new file mode 100644 index 000000000..c12b8f72c --- /dev/null +++ b/src/ShaderNode/DataTypes/BoolData.inl @@ -0,0 +1,7 @@ +#include + +inline BoolData::BoolData() : +preview(1, 1) +{ + preview(0, 0) = Nz::Vector4f(1.f, 1.f, 1.f, 0.f); +} From e342c88e64b47f3f8b65fd01e55e477896f2fcf9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Sun, 19 Jul 2020 21:08:25 +0200 Subject: [PATCH 057/105] ShaderNodes/InputValue: Fix output type when using Float1 --- src/ShaderNode/DataModels/InputValue.cpp | 18 ++++++++++++++---- src/ShaderNode/DataModels/InputValue.inl | 1 - 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/ShaderNode/DataModels/InputValue.cpp b/src/ShaderNode/DataModels/InputValue.cpp index f9337f262..1b33a8c9b 100644 --- a/src/ShaderNode/DataModels/InputValue.cpp +++ b/src/ShaderNode/DataModels/InputValue.cpp @@ -1,5 +1,5 @@ -#include #include +#include #include #include #include @@ -170,10 +170,20 @@ std::shared_ptr InputValue::outData(QtNodes::PortIndex port) const auto& inputEntry = graph.GetInput(*m_currentInputIndex); const auto& preview = graph.GetPreviewModel(); - auto vecData = std::make_shared(GetComponentCount(inputEntry.type)); - vecData->preview = preview.GetPreview(inputEntry.role, inputEntry.roleIndex); + if (inputEntry.type == PrimitiveType::Float1) + { + auto fData = std::make_shared(); + fData->preview = preview.GetPreview(inputEntry.role, inputEntry.roleIndex); - return vecData; + return fData; + } + else + { + auto vecData = std::make_shared(GetComponentCount(inputEntry.type)); + vecData->preview = preview.GetPreview(inputEntry.role, inputEntry.roleIndex); + + return vecData; + } } QtNodes::NodeValidationState InputValue::validationState() const diff --git a/src/ShaderNode/DataModels/InputValue.inl b/src/ShaderNode/DataModels/InputValue.inl index 344e3db41..ec5e2f581 100644 --- a/src/ShaderNode/DataModels/InputValue.inl +++ b/src/ShaderNode/DataModels/InputValue.inl @@ -1,2 +1 @@ #include -#include From 3c1c61fb5ef0b7d7150820f1d73858b45d47fd44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Sun, 19 Jul 2020 21:08:43 +0200 Subject: [PATCH 058/105] Improve code --- src/ShaderNode/ShaderGraph.cpp | 45 +++++++++++++++++++++++++++ src/ShaderNode/ShaderGraph.hpp | 4 +++ src/ShaderNode/Widgets/MainWindow.cpp | 35 +++------------------ 3 files changed, 53 insertions(+), 31 deletions(-) diff --git a/src/ShaderNode/ShaderGraph.cpp b/src/ShaderNode/ShaderGraph.cpp index 3648fed82..2d5ba933d 100644 --- a/src/ShaderNode/ShaderGraph.cpp +++ b/src/ShaderNode/ShaderGraph.cpp @@ -498,6 +498,24 @@ Nz::ShaderNodes::StatementPtr ShaderGraph::ToAst() return Nz::ShaderNodes::StatementBlock::Build(std::move(statements)); } +Nz::ShaderExpressionType ShaderGraph::ToShaderExpressionType(const std::variant& type) const +{ + return std::visit([&](auto&& arg) -> Nz::ShaderExpressionType + { + using T = std::decay_t; + if constexpr (std::is_same_v) + return ToShaderExpressionType(arg); + else if constexpr (std::is_same_v) + { + assert(arg < m_structs.size()); + const auto& s = m_structs[arg]; + return s.name; + } + else + static_assert(AlwaysFalse::value, "non-exhaustive visitor"); + }, type); +}; + void ShaderGraph::UpdateBuffer(std::size_t bufferIndex, std::string name, BufferType bufferType, std::size_t structIndex, std::size_t bindingIndex) { assert(bufferIndex < m_buffers.size()); @@ -565,9 +583,36 @@ void ShaderGraph::UpdateTexturePreview(std::size_t textureIndex, QImage preview) OnTexturePreviewUpdate(this, textureIndex); } +Nz::ShaderExpressionType ShaderGraph::ToShaderExpressionType(PrimitiveType type) +{ + switch (type) + { + case PrimitiveType::Bool: return Nz::ShaderNodes::BasicType::Boolean; + case PrimitiveType::Float1: return Nz::ShaderNodes::BasicType::Float1; + case PrimitiveType::Float2: return Nz::ShaderNodes::BasicType::Float2; + case PrimitiveType::Float3: return Nz::ShaderNodes::BasicType::Float3; + case PrimitiveType::Float4: return Nz::ShaderNodes::BasicType::Float4; + } + + assert(false); + throw std::runtime_error("Unhandled primitive type"); +} + +Nz::ShaderExpressionType ShaderGraph::ToShaderExpressionType(TextureType type) +{ + switch (type) + { + case TextureType::Sampler2D: return Nz::ShaderNodes::BasicType::Sampler2D; + } + + assert(false); + throw std::runtime_error("Unhandled texture type"); +} + std::shared_ptr ShaderGraph::BuildRegistry() { auto registry = std::make_shared(); + RegisterShaderNode(*this, registry, "Inputs"); RegisterShaderNode(*this, registry, "Casts"); RegisterShaderNode(*this, registry, "Casts"); RegisterShaderNode(*this, registry, "Casts"); diff --git a/src/ShaderNode/ShaderGraph.hpp b/src/ShaderNode/ShaderGraph.hpp index d0ff63316..0cab330d0 100644 --- a/src/ShaderNode/ShaderGraph.hpp +++ b/src/ShaderNode/ShaderGraph.hpp @@ -56,6 +56,7 @@ class ShaderGraph QJsonObject Save(); Nz::ShaderNodes::StatementPtr ToAst(); + Nz::ShaderExpressionType ToShaderExpressionType(const std::variant& type) const; void UpdateBuffer(std::size_t bufferIndex, std::string name, BufferType bufferType, std::size_t structIndex, std::size_t bindingIndex); void UpdateInput(std::size_t inputIndex, std::string name, PrimitiveType type, InputRole role, std::size_t roleIndex, std::size_t locationIndex); @@ -121,6 +122,9 @@ class ShaderGraph NazaraSignal(OnTexturePreviewUpdate, ShaderGraph*, std::size_t /*textureIndex*/); NazaraSignal(OnTextureUpdate, ShaderGraph*, std::size_t /*textureIndex*/); + static Nz::ShaderExpressionType ToShaderExpressionType(PrimitiveType type); + static Nz::ShaderExpressionType ToShaderExpressionType(TextureType type); + private: std::shared_ptr BuildRegistry(); diff --git a/src/ShaderNode/Widgets/MainWindow.cpp b/src/ShaderNode/Widgets/MainWindow.cpp index 813d1b5ab..7c7101047 100644 --- a/src/ShaderNode/Widgets/MainWindow.cpp +++ b/src/ShaderNode/Widgets/MainWindow.cpp @@ -212,39 +212,12 @@ Nz::ShaderAst MainWindow::ToShader() { Nz::ShaderNodes::StatementPtr shaderAst = m_shaderGraph.ToAst(); - //TODO: Put in another function - auto GetExpressionFromInOut = [&](PrimitiveType type) - { - switch (type) - { - case PrimitiveType::Bool: return Nz::ShaderNodes::BasicType::Boolean; - case PrimitiveType::Float1: return Nz::ShaderNodes::BasicType::Float1; - case PrimitiveType::Float2: return Nz::ShaderNodes::BasicType::Float2; - case PrimitiveType::Float3: return Nz::ShaderNodes::BasicType::Float3; - case PrimitiveType::Float4: return Nz::ShaderNodes::BasicType::Float4; - } - - assert(false); - throw std::runtime_error("Unhandled input type"); - }; - - auto GetExpressionFromTexture = [&](TextureType type) - { - switch (type) - { - case TextureType::Sampler2D: return Nz::ShaderNodes::BasicType::Sampler2D; - } - - assert(false); - throw std::runtime_error("Unhandled texture type"); - }; - Nz::ShaderAst shader; for (const auto& input : m_shaderGraph.GetInputs()) - shader.AddInput(input.name, GetExpressionFromInOut(input.type), input.locationIndex); + shader.AddInput(input.name, m_shaderGraph.ToShaderExpressionType(input.type), input.locationIndex); for (const auto& output : m_shaderGraph.GetOutputs()) - shader.AddOutput(output.name, GetExpressionFromInOut(output.type), output.locationIndex); + shader.AddOutput(output.name, m_shaderGraph.ToShaderExpressionType(output.type), output.locationIndex); for (const auto& buffer : m_shaderGraph.GetBuffers()) { @@ -253,7 +226,7 @@ Nz::ShaderAst MainWindow::ToShader() } for (const auto& uniform : m_shaderGraph.GetTextures()) - shader.AddUniform(uniform.name, GetExpressionFromTexture(uniform.type), uniform.bindingIndex, {}); + shader.AddUniform(uniform.name, m_shaderGraph.ToShaderExpressionType(uniform.type), uniform.bindingIndex, {}); for (const auto& s : m_shaderGraph.GetStructs()) { @@ -267,7 +240,7 @@ Nz::ShaderAst MainWindow::ToShader() { using T = std::decay_t; if constexpr (std::is_same_v) - member.type = GetExpressionFromInOut(arg); + member.type = m_shaderGraph.ToShaderExpressionType(arg); else if constexpr (std::is_same_v) member.type = m_shaderGraph.GetStruct(arg).name; else From 405c020125c2a49e266717b0afd8635e4fd3d55d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Sun, 19 Jul 2020 21:08:53 +0200 Subject: [PATCH 059/105] Set some struct in default scene for testing --- src/ShaderNode/ShaderGraph.cpp | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/ShaderNode/ShaderGraph.cpp b/src/ShaderNode/ShaderGraph.cpp index 2d5ba933d..22d74dca2 100644 --- a/src/ShaderNode/ShaderGraph.cpp +++ b/src/ShaderNode/ShaderGraph.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -54,15 +55,22 @@ m_flowScene(BuildRegistry()) { "position", PrimitiveType::Float3 }, { "normal", PrimitiveType::Float3 }, { "uv", PrimitiveType::Float2 }, + { "inner", 2 } } }); - AddStruct("TestStruct2", { - { - { "position", PrimitiveType::Float3 }, - { "normal", PrimitiveType::Float3 }, - { "uv", PrimitiveType::Float2 }, - } + AddStruct("InnerStruct", { + { + { "a", PrimitiveType::Float3 }, + } }); + AddStruct("OuterStruct", { + { + { "a", 1 }, + { "b", PrimitiveType::Float1 } + } + }); + + AddBuffer("testUBO", BufferType::UniformBufferObject, 0, 0); UpdateTexturePreview(0, QImage(R"(C:\Users\Lynix\Pictures\potatavril.png)")); From 042eb067a05115bef05382e1b2bec1a8eba1e8c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Mon, 20 Jul 2020 11:21:31 +0200 Subject: [PATCH 060/105] Move and rename functions --- src/ShaderNode/DataModels/BufferField.cpp | 198 +++++++++++----------- src/ShaderNode/DataModels/BufferField.hpp | 4 +- 2 files changed, 101 insertions(+), 101 deletions(-) diff --git a/src/ShaderNode/DataModels/BufferField.cpp b/src/ShaderNode/DataModels/BufferField.cpp index c9d81bdcd..25b626f48 100644 --- a/src/ShaderNode/DataModels/BufferField.cpp +++ b/src/ShaderNode/DataModels/BufferField.cpp @@ -11,7 +11,7 @@ BufferField::BufferField(ShaderGraph& graph) : ShaderNode(graph) { - m_onBufferListUpdateSlot.Connect(GetGraph().OnBufferListUpdate, [&](ShaderGraph*) { UpdateCurrentBufferIndex(); }); + m_onBufferListUpdateSlot.Connect(GetGraph().OnBufferListUpdate, [&](ShaderGraph*) { UpdateBufferIndex(); }); m_onBufferUpdateSlot.Connect(GetGraph().OnBufferUpdate, [&](ShaderGraph*, std::size_t bufferIndex) { if (m_currentBufferIndex == bufferIndex) @@ -57,102 +57,6 @@ bool BufferField::ComputePreview(QPixmap& pixmap) return true;*/ } -void BufferField::UpdateCurrentBufferIndex() -{ - Nz::CallOnExit resetIfNotFound([&] - { - m_currentBufferIndex.reset(); - m_currentBufferText.clear(); - m_currentFieldIndex.reset(); - m_currentFieldText.clear(); - }); - - if (m_currentBufferText.empty()) - return; - - std::size_t bufferIndex = 0; - for (const auto& bufferEntry : GetGraph().GetBuffers()) - { - if (bufferEntry.name == m_currentBufferText) - { - m_currentBufferIndex = bufferIndex; - resetIfNotFound.Reset(); - break; - } - - bufferIndex++; - } -} - -void BufferField::UpdateCurrentFieldIndex() -{ - Nz::CallOnExit resetIfNotFound([&] - { - m_currentFieldIndex.reset(); - m_currentFieldText.clear(); - }); - - if (m_currentFieldText.empty()) - return; - - if (!m_currentFieldIndex) - m_currentFieldIndex.emplace(); - - CurrentField& currentField = *m_currentFieldIndex; - currentField.nestedFields.clear(); - - const ShaderGraph& graph = GetGraph(); - auto& buffer = graph.GetBuffer(*m_currentBufferIndex); - - std::function FetchField; - FetchField = [&](std::size_t structIndex, const std::string& prefix) -> bool - { - const auto& s = graph.GetStruct(structIndex); - for (auto it = s.members.begin(); it != s.members.end(); ++it) - { - const auto& member = *it; - - bool found = std::visit([&](auto&& arg) -> bool - { - using T = std::decay_t; - if constexpr (std::is_same_v) - { - if (prefix + member.name == m_currentFieldText) - { - currentField.finalFieldIndex = std::distance(s.members.begin(), it); - return true; - } - else - return false; - } - else if constexpr (std::is_same_v) - { - currentField.nestedFields.push_back(std::distance(s.members.begin(), it)); - bool found = FetchField(arg, prefix + member.name + "."); - if (!found) - { - currentField.nestedFields.pop_back(); - return false; - } - - return true; - } - else - static_assert(Nz::AlwaysFalse::value, "non-exhaustive visitor"); - }, - member.type); - - if (found) - return true; - } - - return false; - }; - - if (FetchField(buffer.structIndex, "")) - resetIfNotFound.Reset(); -} - void BufferField::PopulateField(QComboBox* fieldList, std::size_t structIndex, const std::string& prefix) { const auto& s = GetGraph().GetStruct(structIndex); @@ -194,6 +98,33 @@ const ShaderGraph::StructMemberEntry& BufferField::RetrieveNestedMember() const return structEntry->members[currentField.finalFieldIndex]; } +void BufferField::UpdateBufferIndex() +{ + Nz::CallOnExit resetIfNotFound([&] + { + m_currentBufferIndex.reset(); + m_currentBufferText.clear(); + m_currentFieldIndex.reset(); + m_currentFieldText.clear(); + }); + + if (m_currentBufferText.empty()) + return; + + std::size_t bufferIndex = 0; + for (const auto& bufferEntry : GetGraph().GetBuffers()) + { + if (bufferEntry.name == m_currentBufferText) + { + m_currentBufferIndex = bufferIndex; + resetIfNotFound.Reset(); + break; + } + + bufferIndex++; + } +} + void BufferField::UpdateBufferText() { if (m_currentBufferIndex) @@ -217,7 +148,7 @@ void BufferField::BuildNodeEdition(QFormLayout* layout) else m_currentFieldText.clear(); - UpdateCurrentFieldIndex(); + UpdateFieldIndex(); UpdatePreview(); Q_EMIT dataUpdated(0); @@ -266,6 +197,75 @@ void BufferField::BuildNodeEdition(QFormLayout* layout) layout->addRow(tr("Field"), fieldSelection); } +void BufferField::UpdateFieldIndex() +{ + Nz::CallOnExit resetIfNotFound([&] + { + m_currentFieldIndex.reset(); + m_currentFieldText.clear(); + }); + + if (m_currentFieldText.empty()) + return; + + if (!m_currentFieldIndex) + m_currentFieldIndex.emplace(); + + CurrentField& currentField = *m_currentFieldIndex; + currentField.nestedFields.clear(); + + const ShaderGraph& graph = GetGraph(); + auto& buffer = graph.GetBuffer(*m_currentBufferIndex); + + std::function FetchField; + FetchField = [&](std::size_t structIndex, const std::string& prefix) -> bool + { + const auto& s = graph.GetStruct(structIndex); + for (auto it = s.members.begin(); it != s.members.end(); ++it) + { + const auto& member = *it; + + bool found = std::visit([&](auto&& arg) -> bool + { + using T = std::decay_t; + if constexpr (std::is_same_v) + { + if (prefix + member.name == m_currentFieldText) + { + currentField.finalFieldIndex = std::distance(s.members.begin(), it); + return true; + } + else + return false; + } + else if constexpr (std::is_same_v) + { + currentField.nestedFields.push_back(std::distance(s.members.begin(), it)); + bool found = FetchField(arg, prefix + member.name + "."); + if (!found) + { + currentField.nestedFields.pop_back(); + return false; + } + + return true; + } + else + static_assert(Nz::AlwaysFalse::value, "non-exhaustive visitor"); + }, + member.type); + + if (found) + return true; + } + + return false; + }; + + if (FetchField(buffer.structIndex, "")) + resetIfNotFound.Reset(); +} + Nz::ShaderNodes::ExpressionPtr BufferField::GetExpression(Nz::ShaderNodes::ExpressionPtr* /*expressions*/, std::size_t count) const { assert(count == 0); @@ -394,7 +394,7 @@ void BufferField::restore(const QJsonObject& data) { m_currentBufferText = data["buffer"].toString().toStdString(); m_currentFieldText = data["field"].toString().toStdString(); - UpdateCurrentBufferIndex(); + UpdateBufferIndex(); ShaderNode::restore(data); } diff --git a/src/ShaderNode/DataModels/BufferField.hpp b/src/ShaderNode/DataModels/BufferField.hpp index 304165386..d4d77bb1d 100644 --- a/src/ShaderNode/DataModels/BufferField.hpp +++ b/src/ShaderNode/DataModels/BufferField.hpp @@ -35,11 +35,11 @@ class BufferField : public ShaderNode private: bool ComputePreview(QPixmap& pixmap) override; - void UpdateCurrentBufferIndex(); - void UpdateCurrentFieldIndex(); void PopulateField(QComboBox* fieldList, std::size_t structIndex, const std::string& prefix = ""); const ShaderGraph::StructMemberEntry& RetrieveNestedMember() const; + void UpdateBufferIndex(); void UpdateBufferText(); + void UpdateFieldIndex(); void restore(const QJsonObject& data) override; QJsonObject save() const override; From 5ce67f434b7f74eaf47f9953e3e1178f91014337 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Mon, 20 Jul 2020 20:41:22 +0200 Subject: [PATCH 061/105] Finish BufferField --- src/ShaderNode/DataModels/BufferField.cpp | 511 ++++++++++++---------- src/ShaderNode/DataModels/BufferField.hpp | 9 +- src/ShaderNode/DataModels/ShaderNode.cpp | 8 +- src/ShaderNode/DataModels/ShaderNode.hpp | 6 +- 4 files changed, 299 insertions(+), 235 deletions(-) diff --git a/src/ShaderNode/DataModels/BufferField.cpp b/src/ShaderNode/DataModels/BufferField.cpp index 25b626f48..a8399509c 100644 --- a/src/ShaderNode/DataModels/BufferField.cpp +++ b/src/ShaderNode/DataModels/BufferField.cpp @@ -7,6 +7,7 @@ #include #include #include +#include BufferField::BufferField(ShaderGraph& graph) : ShaderNode(graph) @@ -17,20 +18,78 @@ ShaderNode(graph) if (m_currentBufferIndex == bufferIndex) { UpdatePreview(); + Q_EMIT dataUpdated(0); } }); - if (graph.GetBufferCount() > 0) + m_onStructListUpdateSlot.Connect(GetGraph().OnStructListUpdate, [&](ShaderGraph*) { - m_currentBufferIndex = 0; - UpdateBufferText(); - } + UpdateFieldIndex(); + UpdatePreview(); + + Q_EMIT dataUpdated(0); + }); + + m_onStructUpdateSlot.Connect(GetGraph().OnStructUpdate, [&](ShaderGraph*, std::size_t) + { + UpdateFieldIndex(); + UpdatePreview(); + + Q_EMIT dataUpdated(0); + }); DisableCustomVariableName(); UpdatePreview(); } +Nz::ShaderNodes::ExpressionPtr BufferField::GetExpression(Nz::ShaderNodes::ExpressionPtr* /*expressions*/, std::size_t count) const +{ + assert(count == 0); + + if (!m_currentBufferIndex) + throw std::runtime_error("no buffer"); + + const ShaderGraph& graph = GetGraph(); + + const auto& bufferEntry = graph.GetBuffer(*m_currentBufferIndex); + const auto& structEntry = graph.GetStruct(bufferEntry.structIndex); + + Nz::ShaderNodes::VariablePtr varPtr; + switch (bufferEntry.type) + { + case BufferType::UniformBufferObject: + varPtr = Nz::ShaderBuilder::Uniform(bufferEntry.name, structEntry.name); + break; + } + + assert(varPtr); + + assert(m_currentFieldIndex); + const CurrentField& currentField = *m_currentFieldIndex; + + Nz::ShaderNodes::ExpressionPtr sourceExpr = Nz::ShaderBuilder::Identifier(varPtr); + + const ShaderGraph::StructEntry* sourceStruct = &structEntry; + for (std::size_t nestedIndex : currentField.nestedFields) + { + assert(nestedIndex < sourceStruct->members.size()); + const auto& memberEntry = sourceStruct->members[nestedIndex]; + assert(std::holds_alternative(memberEntry.type)); + + std::size_t nestedStructIndex = std::get(memberEntry.type); + sourceStruct = &graph.GetStruct(nestedStructIndex); + + sourceExpr = Nz::ShaderBuilder::AccessMember(std::move(sourceExpr), 0, graph.ToShaderExpressionType(memberEntry.type)); + } + + assert(currentField.finalFieldIndex < sourceStruct->members.size()); + const auto& memberEntry = sourceStruct->members[currentField.finalFieldIndex]; + assert(std::holds_alternative(memberEntry.type)); + + return Nz::ShaderBuilder::AccessMember(std::move(sourceExpr), 0, graph.ToShaderExpressionType(std::get(memberEntry.type))); +} + unsigned int BufferField::nPorts(QtNodes::PortType portType) const { switch (portType) @@ -42,100 +101,6 @@ unsigned int BufferField::nPorts(QtNodes::PortType portType) const return 0; } -bool BufferField::ComputePreview(QPixmap& pixmap) -{ - return false; - - /*if (!m_currentBufferIndex) - return false; - - const ShaderGraph& graph = GetGraph(); - const auto& inputEntry = graph.GetBuffer(*m_currentBufferIndex); - const auto& preview = graph.GetPreviewModel(); - - pixmap = QPixmap::fromImage(preview.GetPreview(inputEntry.role, inputEntry.roleIndex).GenerateImage()); - return true;*/ -} - -void BufferField::PopulateField(QComboBox* fieldList, std::size_t structIndex, const std::string& prefix) -{ - const auto& s = GetGraph().GetStruct(structIndex); - for (const auto& member : s.members) - { - std::visit([&](auto&& arg) - { - using T = std::decay_t; - if constexpr (std::is_same_v) - fieldList->addItem(QString::fromStdString(prefix + member.name)); - else if constexpr (std::is_same_v) - PopulateField(fieldList, arg, prefix + member.name + "."); - else - static_assert(AlwaysFalse::value, "non-exhaustive visitor"); - }, - member.type); - } -} - -const ShaderGraph::StructMemberEntry& BufferField::RetrieveNestedMember() const -{ - const ShaderGraph& graph = GetGraph(); - auto& buffer = graph.GetBuffer(*m_currentBufferIndex); - - assert(m_currentFieldIndex); - const CurrentField& currentField = *m_currentFieldIndex; - - const ShaderGraph::StructEntry* structEntry = &graph.GetStruct(buffer.structIndex); - for (std::size_t nestedIndex : currentField.nestedFields) - { - assert(nestedIndex < structEntry->members.size()); - const auto& memberEntry = structEntry->members[nestedIndex]; - assert(std::holds_alternative(memberEntry.type)); - - std::size_t nestedStructIndex = std::get(memberEntry.type); - structEntry = &graph.GetStruct(nestedStructIndex); - } - - return structEntry->members[currentField.finalFieldIndex]; -} - -void BufferField::UpdateBufferIndex() -{ - Nz::CallOnExit resetIfNotFound([&] - { - m_currentBufferIndex.reset(); - m_currentBufferText.clear(); - m_currentFieldIndex.reset(); - m_currentFieldText.clear(); - }); - - if (m_currentBufferText.empty()) - return; - - std::size_t bufferIndex = 0; - for (const auto& bufferEntry : GetGraph().GetBuffers()) - { - if (bufferEntry.name == m_currentBufferText) - { - m_currentBufferIndex = bufferIndex; - resetIfNotFound.Reset(); - break; - } - - bufferIndex++; - } -} - -void BufferField::UpdateBufferText() -{ - if (m_currentBufferIndex) - { - auto& buffer = GetGraph().GetBuffer(*m_currentBufferIndex); - m_currentBufferText = buffer.name; - } - else - m_currentBufferText.clear(); -} - void BufferField::BuildNodeEdition(QFormLayout* layout) { ShaderNode::BuildNodeEdition(layout); @@ -197,122 +162,6 @@ void BufferField::BuildNodeEdition(QFormLayout* layout) layout->addRow(tr("Field"), fieldSelection); } -void BufferField::UpdateFieldIndex() -{ - Nz::CallOnExit resetIfNotFound([&] - { - m_currentFieldIndex.reset(); - m_currentFieldText.clear(); - }); - - if (m_currentFieldText.empty()) - return; - - if (!m_currentFieldIndex) - m_currentFieldIndex.emplace(); - - CurrentField& currentField = *m_currentFieldIndex; - currentField.nestedFields.clear(); - - const ShaderGraph& graph = GetGraph(); - auto& buffer = graph.GetBuffer(*m_currentBufferIndex); - - std::function FetchField; - FetchField = [&](std::size_t structIndex, const std::string& prefix) -> bool - { - const auto& s = graph.GetStruct(structIndex); - for (auto it = s.members.begin(); it != s.members.end(); ++it) - { - const auto& member = *it; - - bool found = std::visit([&](auto&& arg) -> bool - { - using T = std::decay_t; - if constexpr (std::is_same_v) - { - if (prefix + member.name == m_currentFieldText) - { - currentField.finalFieldIndex = std::distance(s.members.begin(), it); - return true; - } - else - return false; - } - else if constexpr (std::is_same_v) - { - currentField.nestedFields.push_back(std::distance(s.members.begin(), it)); - bool found = FetchField(arg, prefix + member.name + "."); - if (!found) - { - currentField.nestedFields.pop_back(); - return false; - } - - return true; - } - else - static_assert(Nz::AlwaysFalse::value, "non-exhaustive visitor"); - }, - member.type); - - if (found) - return true; - } - - return false; - }; - - if (FetchField(buffer.structIndex, "")) - resetIfNotFound.Reset(); -} - -Nz::ShaderNodes::ExpressionPtr BufferField::GetExpression(Nz::ShaderNodes::ExpressionPtr* /*expressions*/, std::size_t count) const -{ - assert(count == 0); - - if (!m_currentBufferIndex) - throw std::runtime_error("no buffer"); - - const ShaderGraph& graph = GetGraph(); - - const auto& bufferEntry = graph.GetBuffer(*m_currentBufferIndex); - const auto& structEntry = graph.GetStruct(bufferEntry.structIndex); - - Nz::ShaderNodes::VariablePtr varPtr; - switch (bufferEntry.type) - { - case BufferType::UniformBufferObject: - varPtr = Nz::ShaderBuilder::Uniform(bufferEntry.name, structEntry.name); - break; - } - - assert(varPtr); - - assert(m_currentFieldIndex); - const CurrentField& currentField = *m_currentFieldIndex; - - Nz::ShaderNodes::ExpressionPtr sourceExpr = Nz::ShaderBuilder::Identifier(varPtr); - - const ShaderGraph::StructEntry* sourceStruct = &structEntry; - for (std::size_t nestedIndex : currentField.nestedFields) - { - assert(nestedIndex < sourceStruct->members.size()); - const auto& memberEntry = sourceStruct->members[nestedIndex]; - assert(std::holds_alternative(memberEntry.type)); - - std::size_t nestedStructIndex = std::get(memberEntry.type); - sourceStruct = &graph.GetStruct(nestedStructIndex); - - sourceExpr = Nz::ShaderBuilder::AccessMember(std::move(sourceExpr), 0, graph.ToShaderExpressionType(memberEntry.type)); - } - - assert(currentField.finalFieldIndex < sourceStruct->members.size()); - const auto& memberEntry = sourceStruct->members[currentField.finalFieldIndex]; - assert(std::holds_alternative(memberEntry.type)); - - return Nz::ShaderBuilder::AccessMember(std::move(sourceExpr), 0, graph.ToShaderExpressionType(std::get(memberEntry.type))); -} - auto BufferField::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const -> QtNodes::NodeDataType { assert(portType == QtNodes::PortType::Out); @@ -342,6 +191,55 @@ auto BufferField::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIn throw std::runtime_error("Unhandled primitive type"); } +QString BufferField::portCaption(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const +{ + assert(portType == QtNodes::PortType::Out); + assert(portIndex == 0); + + if (!m_currentBufferIndex || !m_currentFieldIndex) + return ""; + + std::stringstream ss; + + const ShaderGraph& graph = GetGraph(); + + const auto& bufferEntry = graph.GetBuffer(*m_currentBufferIndex); + const auto& structEntry = graph.GetStruct(bufferEntry.structIndex); + + ss << bufferEntry.name << "."; + + const CurrentField& currentField = *m_currentFieldIndex; + + const ShaderGraph::StructEntry* sourceStruct = &structEntry; + for (std::size_t nestedIndex : currentField.nestedFields) + { + assert(nestedIndex < sourceStruct->members.size()); + const auto& memberEntry = sourceStruct->members[nestedIndex]; + assert(std::holds_alternative(memberEntry.type)); + + std::size_t nestedStructIndex = std::get(memberEntry.type); + sourceStruct = &graph.GetStruct(nestedStructIndex); + + ss << memberEntry.name << "."; + } + + assert(currentField.finalFieldIndex < sourceStruct->members.size()); + const auto& memberEntry = sourceStruct->members[currentField.finalFieldIndex]; + assert(std::holds_alternative(memberEntry.type)); + + ss << memberEntry.name; + + return QString::fromStdString(ss.str()); +} + +bool BufferField::portCaptionVisible(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const +{ + assert(portType == QtNodes::PortType::Out); + assert(portIndex == 0); + + return true; +} + std::shared_ptr BufferField::outData(QtNodes::PortIndex port) { if (!m_currentBufferIndex) @@ -368,6 +266,24 @@ std::shared_ptr BufferField::outData(QtNodes::PortIndex port) throw std::runtime_error("Unhandled primitive type"); } +void BufferField::restore(const QJsonObject& data) +{ + m_currentBufferText = data["buffer"].toString().toStdString(); + m_currentFieldText = data["field"].toString().toStdString(); + UpdateBufferIndex(); + + ShaderNode::restore(data); +} + +QJsonObject BufferField::save() const +{ + QJsonObject data = ShaderNode::save(); + data["buffer"] = QString::fromStdString(m_currentBufferText); + data["field"] = QString::fromStdString(m_currentFieldText); + + return data; +} + QtNodes::NodeValidationState BufferField::validationState() const { if (!m_currentBufferIndex) @@ -390,20 +306,165 @@ QString BufferField::validationMessage() const return QString(); } -void BufferField::restore(const QJsonObject& data) +bool BufferField::ComputePreview(QPixmap& pixmap) { - m_currentBufferText = data["buffer"].toString().toStdString(); - m_currentFieldText = data["field"].toString().toStdString(); - UpdateBufferIndex(); + return false; - ShaderNode::restore(data); + /*if (!m_currentBufferIndex) + return false; + + const ShaderGraph& graph = GetGraph(); + const auto& inputEntry = graph.GetBuffer(*m_currentBufferIndex); + const auto& preview = graph.GetPreviewModel(); + + pixmap = QPixmap::fromImage(preview.GetPreview(inputEntry.role, inputEntry.roleIndex).GenerateImage()); + return true;*/ } -QJsonObject BufferField::save() const +void BufferField::PopulateField(QComboBox* fieldList, std::size_t structIndex, const std::string& prefix) { - QJsonObject data = ShaderNode::save(); - data["buffer"] = QString::fromStdString(m_currentBufferText); - data["field"] = QString::fromStdString(m_currentFieldText); - - return data; + const auto& s = GetGraph().GetStruct(structIndex); + for (const auto& member : s.members) + { + std::visit([&](auto&& arg) + { + using T = std::decay_t; + if constexpr (std::is_same_v) + fieldList->addItem(QString::fromStdString(prefix + member.name)); + else if constexpr (std::is_same_v) + PopulateField(fieldList, arg, prefix + member.name + "."); + else + static_assert(AlwaysFalse::value, "non-exhaustive visitor"); + }, + member.type); + } +} + +const ShaderGraph::StructMemberEntry& BufferField::RetrieveNestedMember() const +{ + const ShaderGraph& graph = GetGraph(); + auto& buffer = graph.GetBuffer(*m_currentBufferIndex); + + assert(m_currentFieldIndex); + const CurrentField& currentField = *m_currentFieldIndex; + + const ShaderGraph::StructEntry* structEntry = &graph.GetStruct(buffer.structIndex); + for (std::size_t nestedIndex : currentField.nestedFields) + { + assert(nestedIndex < structEntry->members.size()); + const auto& memberEntry = structEntry->members[nestedIndex]; + assert(std::holds_alternative(memberEntry.type)); + + std::size_t nestedStructIndex = std::get(memberEntry.type); + structEntry = &graph.GetStruct(nestedStructIndex); + } + + return structEntry->members[currentField.finalFieldIndex]; +} + +void BufferField::UpdateBufferIndex() +{ + Nz::CallOnExit resetIfNotFound([&] + { + m_currentBufferIndex.reset(); + m_currentBufferText.clear(); + m_currentFieldIndex.reset(); + m_currentFieldText.clear(); + }); + + if (m_currentBufferText.empty()) + return; + + std::size_t bufferIndex = 0; + for (const auto& bufferEntry : GetGraph().GetBuffers()) + { + if (bufferEntry.name == m_currentBufferText) + { + m_currentBufferIndex = bufferIndex; + resetIfNotFound.Reset(); + break; + } + + bufferIndex++; + } +} + +void BufferField::UpdateBufferText() +{ + if (m_currentBufferIndex) + { + auto& buffer = GetGraph().GetBuffer(*m_currentBufferIndex); + m_currentBufferText = buffer.name; + } + else + m_currentBufferText.clear(); +} + +void BufferField::UpdateFieldIndex() +{ + Nz::CallOnExit resetIfNotFound([&] + { + m_currentFieldIndex.reset(); + m_currentFieldText.clear(); + }); + + if (m_currentFieldText.empty()) + return; + + if (!m_currentFieldIndex) + m_currentFieldIndex.emplace(); + + CurrentField& currentField = *m_currentFieldIndex; + currentField.nestedFields.clear(); + + const ShaderGraph& graph = GetGraph(); + auto& buffer = graph.GetBuffer(*m_currentBufferIndex); + + std::function FetchField; + FetchField = [&](std::size_t structIndex, const std::string& prefix) -> bool + { + const auto& s = graph.GetStruct(structIndex); + for (auto it = s.members.begin(); it != s.members.end(); ++it) + { + const auto& member = *it; + + bool found = std::visit([&](auto&& arg) -> bool + { + using T = std::decay_t; + if constexpr (std::is_same_v) + { + if (prefix + member.name == m_currentFieldText) + { + currentField.finalFieldIndex = std::distance(s.members.begin(), it); + return true; + } + else + return false; + } + else if constexpr (std::is_same_v) + { + currentField.nestedFields.push_back(std::distance(s.members.begin(), it)); + bool found = FetchField(arg, prefix + member.name + "."); + if (!found) + { + currentField.nestedFields.pop_back(); + return false; + } + + return true; + } + else + static_assert(Nz::AlwaysFalse::value, "non-exhaustive visitor"); + }, + member.type); + + if (found) + return true; + } + + return false; + }; + + if (FetchField(buffer.structIndex, "")) + resetIfNotFound.Reset(); } diff --git a/src/ShaderNode/DataModels/BufferField.hpp b/src/ShaderNode/DataModels/BufferField.hpp index d4d77bb1d..7d1295e99 100644 --- a/src/ShaderNode/DataModels/BufferField.hpp +++ b/src/ShaderNode/DataModels/BufferField.hpp @@ -28,8 +28,14 @@ class BufferField : public ShaderNode QtNodes::NodeDataType dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; + QString portCaption(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; + bool portCaptionVisible(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; + std::shared_ptr outData(QtNodes::PortIndex port) override; + void restore(const QJsonObject& data) override; + QJsonObject save() const override; + QtNodes::NodeValidationState validationState() const override; QString validationMessage() const override; @@ -41,9 +47,6 @@ class BufferField : public ShaderNode void UpdateBufferText(); void UpdateFieldIndex(); - void restore(const QJsonObject& data) override; - QJsonObject save() const override; - NazaraSlot(ShaderGraph, OnBufferListUpdate, m_onBufferListUpdateSlot); NazaraSlot(ShaderGraph, OnBufferUpdate, m_onBufferUpdateSlot); diff --git a/src/ShaderNode/DataModels/ShaderNode.cpp b/src/ShaderNode/DataModels/ShaderNode.cpp index a9b06adf8..7ed3bc84c 100644 --- a/src/ShaderNode/DataModels/ShaderNode.cpp +++ b/src/ShaderNode/DataModels/ShaderNode.cpp @@ -89,10 +89,6 @@ QWidget* ShaderNode::embeddedWidget() return m_pixmapLabel; } -void ShaderNode::setInData(std::shared_ptr, int) -{ -} - void ShaderNode::restore(const QJsonObject& data) { NodeDataModel::restore(data); @@ -116,6 +112,10 @@ QJsonObject ShaderNode::save() const return data; } +void ShaderNode::setInData(std::shared_ptr, int) +{ +} + bool ShaderNode::ComputePreview(QPixmap& /*pixmap*/) { return false; diff --git a/src/ShaderNode/DataModels/ShaderNode.hpp b/src/ShaderNode/DataModels/ShaderNode.hpp index 30e2504ca..1becb5a3d 100644 --- a/src/ShaderNode/DataModels/ShaderNode.hpp +++ b/src/ShaderNode/DataModels/ShaderNode.hpp @@ -33,6 +33,9 @@ class ShaderNode : public QtNodes::NodeDataModel QWidget* embeddedWidget() final; + void restore(const QJsonObject& data) override; + QJsonObject save() const override; + void setInData(std::shared_ptr, int) override; protected: @@ -40,9 +43,6 @@ class ShaderNode : public QtNodes::NodeDataModel inline void EnableCustomVariableName(bool enable = true); void UpdatePreview(); - void restore(const QJsonObject& data) override; - QJsonObject save() const override; - private: virtual bool ComputePreview(QPixmap& pixmap); From f66758f99bbfa3dae7d44b9710ec827294fc8bbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Wed, 22 Jul 2020 14:44:49 +0200 Subject: [PATCH 062/105] Renderer/ShaderSerializer: Fix AccessMember --- src/Nazara/Renderer/ShaderSerializer.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Nazara/Renderer/ShaderSerializer.cpp b/src/Nazara/Renderer/ShaderSerializer.cpp index 71beead60..350ec2096 100644 --- a/src/Nazara/Renderer/ShaderSerializer.cpp +++ b/src/Nazara/Renderer/ShaderSerializer.cpp @@ -569,6 +569,7 @@ namespace Nz { case ShaderNodes::NodeType::None: break; + HandleType(AccessMember); HandleType(AssignOp); HandleType(BinaryOp); HandleType(Branch); From db945d11fb31f3d3e2264c871bdd839cba7d9264 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Wed, 22 Jul 2020 14:45:19 +0200 Subject: [PATCH 063/105] Renderer/GlslWriter: Fix generation bugs --- src/Nazara/Renderer/GlslWriter.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Nazara/Renderer/GlslWriter.cpp b/src/Nazara/Renderer/GlslWriter.cpp index 33ae8c0db..972cdb4d2 100644 --- a/src/Nazara/Renderer/GlslWriter.cpp +++ b/src/Nazara/Renderer/GlslWriter.cpp @@ -391,7 +391,7 @@ namespace Nz void GlslWriter::Visit(const ShaderNodes::BuiltinVariable& var) { - Append(var.type); + Append(var.entry); } void GlslWriter::Visit(const ShaderNodes::Cast& node) @@ -404,7 +404,7 @@ namespace Nz if (i != 0) m_currentState->stream << ", "; - const auto& exprPtr = node.expressions[i++]; + const auto& exprPtr = node.expressions[i]; NazaraAssert(exprPtr, "Invalid expression"); Visit(exprPtr); From b441bab218402c23b3b867f6693af6b19d21e917 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Wed, 22 Jul 2020 14:45:40 +0200 Subject: [PATCH 064/105] Renderer/ShaderNodes: Fix BinOp expression type --- src/Nazara/Renderer/ShaderNodes.cpp | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/Nazara/Renderer/ShaderNodes.cpp b/src/Nazara/Renderer/ShaderNodes.cpp index 794e1217a..ddf5e09c7 100644 --- a/src/Nazara/Renderer/ShaderNodes.cpp +++ b/src/Nazara/Renderer/ShaderNodes.cpp @@ -104,8 +104,25 @@ namespace Nz::ShaderNodes const ShaderExpressionType& rightExprType = right->GetExpressionType(); assert(std::holds_alternative(rightExprType)); - //FIXME - exprType = static_cast(std::max(UnderlyingCast(std::get(leftExprType)), UnderlyingCast(std::get(rightExprType)))); + switch (std::get(leftExprType)) + { + case BasicType::Boolean: + case BasicType::Float2: + case BasicType::Float3: + case BasicType::Float4: + exprType = leftExprType; + break; + + case BasicType::Float1: + case BasicType::Mat4x4: + exprType = rightExprType; + break; + + case BasicType::Sampler2D: + case BasicType::Void: + break; + } + break; } From 5a350ee76b69e1c6f88b2028ead32f4ea2d4d55a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Wed, 22 Jul 2020 14:46:44 +0200 Subject: [PATCH 065/105] ShaderNode: Add Mat4x4 type and nodes --- src/ShaderNode/DataModels/BufferField.cpp | 18 +-- src/ShaderNode/DataModels/InputValue.cpp | 80 +++++----- src/ShaderNode/DataModels/Mat4BinOp.cpp | 37 +++++ src/ShaderNode/DataModels/Mat4BinOp.hpp | 67 ++++++++ src/ShaderNode/DataModels/Mat4BinOp.inl | 131 +++++++++++++++ src/ShaderNode/DataModels/Mat4VecMul.cpp | 186 ++++++++++++++++++++++ src/ShaderNode/DataModels/Mat4VecMul.hpp | 43 +++++ src/ShaderNode/DataModels/Mat4VecMul.inl | 1 + src/ShaderNode/DataModels/OutputValue.cpp | 131 ++++++++++----- src/ShaderNode/DataModels/OutputValue.hpp | 6 +- src/ShaderNode/DataTypes/Matrix4Data.cpp | 1 + src/ShaderNode/DataTypes/Matrix4Data.hpp | 19 +++ src/ShaderNode/DataTypes/Matrix4Data.inl | 11 ++ src/ShaderNode/Enums.cpp | 2 + src/ShaderNode/Enums.hpp | 3 +- src/ShaderNode/ShaderGraph.cpp | 35 ++++ src/ShaderNode/ShaderGraph.hpp | 1 + 17 files changed, 668 insertions(+), 104 deletions(-) create mode 100644 src/ShaderNode/DataModels/Mat4BinOp.cpp create mode 100644 src/ShaderNode/DataModels/Mat4BinOp.hpp create mode 100644 src/ShaderNode/DataModels/Mat4BinOp.inl create mode 100644 src/ShaderNode/DataModels/Mat4VecMul.cpp create mode 100644 src/ShaderNode/DataModels/Mat4VecMul.hpp create mode 100644 src/ShaderNode/DataModels/Mat4VecMul.inl create mode 100644 src/ShaderNode/DataTypes/Matrix4Data.cpp create mode 100644 src/ShaderNode/DataTypes/Matrix4Data.hpp create mode 100644 src/ShaderNode/DataTypes/Matrix4Data.inl diff --git a/src/ShaderNode/DataModels/BufferField.cpp b/src/ShaderNode/DataModels/BufferField.cpp index a8399509c..480d53c2c 100644 --- a/src/ShaderNode/DataModels/BufferField.cpp +++ b/src/ShaderNode/DataModels/BufferField.cpp @@ -173,22 +173,7 @@ auto BufferField::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIn const auto& member = RetrieveNestedMember(); assert(std::holds_alternative(member.type)); - switch (std::get(member.type)) - { - case PrimitiveType::Bool: - return BoolData::Type(); - - case PrimitiveType::Float1: - return FloatData::Type(); - - case PrimitiveType::Float2: - case PrimitiveType::Float3: - case PrimitiveType::Float4: - return VecData::Type(); - } - - assert(false); - throw std::runtime_error("Unhandled primitive type"); + return ShaderGraph::ToNodeDataType(std::get(member.type)); } QString BufferField::portCaption(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const @@ -260,6 +245,7 @@ std::shared_ptr BufferField::outData(QtNodes::PortIndex port) case PrimitiveType::Float2: return std::make_shared(2); case PrimitiveType::Float3: return std::make_shared(3); case PrimitiveType::Float4: return std::make_shared(4); + case PrimitiveType::Mat4x4: return std::make_shared(); } assert(false); diff --git a/src/ShaderNode/DataModels/InputValue.cpp b/src/ShaderNode/DataModels/InputValue.cpp index 1b33a8c9b..c2c6f6b01 100644 --- a/src/ShaderNode/DataModels/InputValue.cpp +++ b/src/ShaderNode/DataModels/InputValue.cpp @@ -1,6 +1,8 @@ #include #include +#include #include +#include #include #include #include @@ -115,23 +117,7 @@ Nz::ShaderNodes::ExpressionPtr InputValue::GetExpression(Nz::ShaderNodes::Expres throw std::runtime_error("no input"); const auto& inputEntry = GetGraph().GetInput(*m_currentInputIndex); - - Nz::ShaderNodes::BasicType expression = [&] - { - switch (inputEntry.type) - { - case PrimitiveType::Bool: return Nz::ShaderNodes::BasicType::Boolean; - case PrimitiveType::Float1: return Nz::ShaderNodes::BasicType::Float1; - case PrimitiveType::Float2: return Nz::ShaderNodes::BasicType::Float2; - case PrimitiveType::Float3: return Nz::ShaderNodes::BasicType::Float3; - case PrimitiveType::Float4: return Nz::ShaderNodes::BasicType::Float4; - } - - assert(false); - throw std::runtime_error("Unhandled input type"); - }(); - - return Nz::ShaderBuilder::Identifier(Nz::ShaderBuilder::Input(inputEntry.name, expression)); + return Nz::ShaderBuilder::Identifier(Nz::ShaderBuilder::Input(inputEntry.name, ShaderGraph::ToShaderExpressionType(inputEntry.type))); } auto InputValue::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const -> QtNodes::NodeDataType @@ -143,20 +129,7 @@ auto InputValue::dataType(QtNodes::PortType portType, QtNodes::PortIndex portInd return VecData::Type(); const auto& inputEntry = GetGraph().GetInput(*m_currentInputIndex); - switch (inputEntry.type) - { - //case InputType::Bool: return Nz::ShaderNodes::BasicType::Boolean; - case PrimitiveType::Float1: - return FloatData::Type(); - - case PrimitiveType::Float2: - case PrimitiveType::Float3: - case PrimitiveType::Float4: - return VecData::Type(); - } - - assert(false); - throw std::runtime_error("Unhandled input type"); + return ShaderGraph::ToNodeDataType(inputEntry.type); } std::shared_ptr InputValue::outData(QtNodes::PortIndex port) @@ -170,20 +143,45 @@ std::shared_ptr InputValue::outData(QtNodes::PortIndex port) const auto& inputEntry = graph.GetInput(*m_currentInputIndex); const auto& preview = graph.GetPreviewModel(); - if (inputEntry.type == PrimitiveType::Float1) + switch (inputEntry.type) { - auto fData = std::make_shared(); - fData->preview = preview.GetPreview(inputEntry.role, inputEntry.roleIndex); + case PrimitiveType::Bool: + { + auto bData = std::make_shared(); + bData->preview = preview.GetPreview(inputEntry.role, inputEntry.roleIndex); - return fData; - } - else - { - auto vecData = std::make_shared(GetComponentCount(inputEntry.type)); - vecData->preview = preview.GetPreview(inputEntry.role, inputEntry.roleIndex); + return bData; + } - return vecData; + case PrimitiveType::Float1: + { + auto fData = std::make_shared(); + fData->preview = preview.GetPreview(inputEntry.role, inputEntry.roleIndex); + + return fData; + } + + case PrimitiveType::Float2: + case PrimitiveType::Float3: + case PrimitiveType::Float4: + { + auto vecData = std::make_shared(GetComponentCount(inputEntry.type)); + vecData->preview = preview.GetPreview(inputEntry.role, inputEntry.roleIndex); + + return vecData; + } + + case PrimitiveType::Mat4x4: + { + auto matData = std::make_shared(); + //TODO: Handle preview + + return matData; + } } + + assert(false); + throw std::runtime_error("Unhandled input type"); } QtNodes::NodeValidationState InputValue::validationState() const diff --git a/src/ShaderNode/DataModels/Mat4BinOp.cpp b/src/ShaderNode/DataModels/Mat4BinOp.cpp new file mode 100644 index 000000000..4376b2995 --- /dev/null +++ b/src/ShaderNode/DataModels/Mat4BinOp.cpp @@ -0,0 +1,37 @@ +#include + +QString Mat4Add::caption() const +{ + static QString caption = "Matrix4 addition"; + return caption; +} + +QString Mat4Add::name() const +{ + static QString name = "mat4_add"; + return name; +} + +QString Mat4Mul::caption() const +{ + static QString caption = "Matrix4 multiplication"; + return caption; +} + +QString Mat4Mul::name() const +{ + static QString name = "mat4_mul"; + return name; +} + +QString Mat4Sub::caption() const +{ + static QString caption = "Matrix4 subtraction"; + return caption; +} + +QString Mat4Sub::name() const +{ + static QString name = "mat4_sub"; + return name; +} diff --git a/src/ShaderNode/DataModels/Mat4BinOp.hpp b/src/ShaderNode/DataModels/Mat4BinOp.hpp new file mode 100644 index 000000000..c90549bdd --- /dev/null +++ b/src/ShaderNode/DataModels/Mat4BinOp.hpp @@ -0,0 +1,67 @@ +#pragma once + +#ifndef NAZARA_SHADERNODES_MAT4BINOP_HPP +#define NAZARA_SHADERNODES_MAT4BINOP_HPP + +#include +#include + +template +class Mat4BinOp : public ShaderNode +{ + public: + Mat4BinOp(ShaderGraph& graph); + ~Mat4BinOp() = default; + + Nz::ShaderNodes::ExpressionPtr GetExpression(Nz::ShaderNodes::ExpressionPtr* expressions, std::size_t count) const override; + + unsigned int nPorts(QtNodes::PortType portType) const override; + + QtNodes::NodeDataType dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; + + std::shared_ptr outData(QtNodes::PortIndex port) override; + + void setInData(std::shared_ptr value, int index) override; + + QtNodes::NodeValidationState validationState() const override; + QString validationMessage() const override; + + private: + bool ComputePreview(QPixmap& pixmap) override; + void UpdateOutput(); + + std::shared_ptr m_lhs; + std::shared_ptr m_rhs; + std::shared_ptr m_output; +}; + +class Mat4Add : public Mat4BinOp +{ + public: + using Mat4BinOp::Mat4BinOp; + + QString caption() const override; + QString name() const override; +}; + +class Mat4Mul : public Mat4BinOp +{ + public: + using Mat4BinOp::Mat4BinOp; + + QString caption() const override; + QString name() const override; +}; + +class Mat4Sub : public Mat4BinOp +{ + public: + using Mat4BinOp::Mat4BinOp; + + QString caption() const override; + QString name() const override; +}; + +#include + +#endif diff --git a/src/ShaderNode/DataModels/Mat4BinOp.inl b/src/ShaderNode/DataModels/Mat4BinOp.inl new file mode 100644 index 000000000..684a6ec79 --- /dev/null +++ b/src/ShaderNode/DataModels/Mat4BinOp.inl @@ -0,0 +1,131 @@ +#include +#include + +template +Mat4BinOp::Mat4BinOp(ShaderGraph& graph) : +ShaderNode(graph) +{ + UpdateOutput(); +} + +template +Nz::ShaderNodes::ExpressionPtr Mat4BinOp::GetExpression(Nz::ShaderNodes::ExpressionPtr* expressions, std::size_t count) const +{ + assert(count == 2); + using BuilderType = typename Nz::ShaderBuilder::template BinOpBuilder; + constexpr BuilderType builder; + return builder(expressions[0], expressions[1]); +} + +template +QtNodes::NodeDataType Mat4BinOp::dataType(QtNodes::PortType /*portType*/, QtNodes::PortIndex portIndex) const +{ + assert(portIndex == 0 || portIndex == 1); + + return Matrix4Data::Type(); +} + +template +unsigned int Mat4BinOp::nPorts(QtNodes::PortType portType) const +{ + switch (portType) + { + case QtNodes::PortType::In: return 2; + case QtNodes::PortType::Out: return 1; + } + + return 0; +} + +template +std::shared_ptr Mat4BinOp::outData(QtNodes::PortIndex port) +{ + assert(port == 0); + return m_output; +} + +template +void Mat4BinOp::setInData(std::shared_ptr value, int index) +{ + assert(index == 0 || index == 1); + + std::shared_ptr castedValue; + if (value) + { + assert(dynamic_cast(value.get()) != nullptr); + + castedValue = std::static_pointer_cast(value); + } + + if (index == 0) + m_lhs = std::move(castedValue); + else + m_rhs = std::move(castedValue); + + UpdateOutput(); +} + +template +QtNodes::NodeValidationState Mat4BinOp::validationState() const +{ + if (!m_lhs || !m_rhs) + return QtNodes::NodeValidationState::Error; + + return QtNodes::NodeValidationState::Valid; +} + +template +QString Mat4BinOp::validationMessage() const +{ + if (!m_lhs || !m_rhs) + return "Missing operands"; + + return QString(); +} + +template +bool Mat4BinOp::ComputePreview(QPixmap& pixmap) +{ + if (!m_lhs || !m_rhs) + return false; + + return false; + + //pixmap = QPixmap::fromImage(m_output->preview.GenerateImage()); + //return true; +} + +template +void Mat4BinOp::UpdateOutput() +{ + if (validationState() != QtNodes::NodeValidationState::Valid) + { + m_output = std::make_shared(); + return; + } + + m_output = std::make_shared(); + + /*m_output = std::make_shared(m_lhs->componentCount); + + const PreviewValues& leftPreview = m_lhs->preview; + const PreviewValues& rightPreview = m_rhs->preview; + std::size_t maxWidth = std::max(leftPreview.GetWidth(), rightPreview.GetWidth()); + std::size_t maxHeight = std::max(leftPreview.GetHeight(), rightPreview.GetHeight()); + + // FIXME: Prevent useless copy + PreviewValues leftResized = leftPreview; + if (leftResized.GetWidth() != maxWidth || leftResized.GetHeight() != maxHeight) + leftResized = leftResized.Resized(maxWidth, maxHeight); + + PreviewValues rightResized = rightPreview; + if (rightResized.GetWidth() != maxWidth || rightResized.GetHeight() != maxHeight) + rightResized = rightResized.Resized(maxWidth, maxHeight); + + m_output->preview = PreviewValues(maxWidth, maxHeight); + ApplyOp(leftResized.GetData(), rightResized.GetData(), m_output->preview.GetData(), maxWidth * maxHeight);*/ + + Q_EMIT dataUpdated(0); + + UpdatePreview(); +} diff --git a/src/ShaderNode/DataModels/Mat4VecMul.cpp b/src/ShaderNode/DataModels/Mat4VecMul.cpp new file mode 100644 index 000000000..2e530e496 --- /dev/null +++ b/src/ShaderNode/DataModels/Mat4VecMul.cpp @@ -0,0 +1,186 @@ +#include +#include + +Mat4VecMul::Mat4VecMul(ShaderGraph& graph) : +ShaderNode(graph) +{ + UpdateOutput(); +} + +Nz::ShaderNodes::ExpressionPtr Mat4VecMul::GetExpression(Nz::ShaderNodes::ExpressionPtr* expressions, std::size_t count) const +{ + assert(count == 2); + using namespace Nz::ShaderNodes; + return BinaryOp::Build(BinaryType::Multiply, expressions[0], expressions[1]); +} + +QString Mat4VecMul::caption() const +{ + static QString caption = "Mat4/Vec multiplication"; + return caption; +} + +QString Mat4VecMul::name() const +{ + static QString name = "mat4vec_mul"; + return name; +} + +QtNodes::NodeDataType Mat4VecMul::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const +{ + switch (portType) + { + case QtNodes::PortType::In: + { + assert(portIndex == 0 || portIndex == 1); + switch (portIndex) + { + case 0: return Matrix4Data::Type(); + case 1: return VecData::Type(); + } + } + + case QtNodes::PortType::Out: + { + assert(portIndex == 0); + return VecData::Type(); + } + } + + assert(false); + throw std::runtime_error("Invalid port type"); +} + +unsigned int Mat4VecMul::nPorts(QtNodes::PortType portType) const +{ + switch (portType) + { + case QtNodes::PortType::In: return 2; + case QtNodes::PortType::Out: return 1; + } + + assert(false); + throw std::runtime_error("Invalid port type"); +} + +std::shared_ptr Mat4VecMul::outData(QtNodes::PortIndex port) +{ + assert(port == 0); + return m_output; +} + +void Mat4VecMul::setInData(std::shared_ptr value, int index) +{ + assert(index == 0 || index == 1); + + switch (index) + { + case 0: + { + if (value) + { + assert(dynamic_cast(value.get()) != nullptr); + m_lhs = std::static_pointer_cast(value); + } + else + m_lhs.reset(); + + break; + } + + case 1: + { + if (value) + { + assert(dynamic_cast(value.get()) != nullptr); + m_rhs = std::static_pointer_cast(value); + } + else + m_rhs.reset(); + + break; + } + + default: + assert(false); + throw std::runtime_error("Invalid PortType"); + } + + UpdateOutput(); +} + +QtNodes::NodeValidationState Mat4VecMul::validationState() const +{ + if (!m_lhs || !m_rhs) + return QtNodes::NodeValidationState::Error; + + if (m_rhs->componentCount != 4) + return QtNodes::NodeValidationState::Error; + + return QtNodes::NodeValidationState::Valid; +} + +QString Mat4VecMul::validationMessage() const +{ + if (!m_lhs || !m_rhs) + return "Missing operands"; + + if (m_rhs->componentCount != 4) + return QString("Expected vector with 4 components, got ") + QString::number(m_rhs->componentCount); + + return QString(); +} + +bool Mat4VecMul::ComputePreview(QPixmap& pixmap) +{ + if (validationState() != QtNodes::NodeValidationState::Valid) + return false; + + pixmap = QPixmap::fromImage(m_output->preview.GenerateImage()); + return true; +} + +void Mat4VecMul::UpdateOutput() +{ + if (validationState() != QtNodes::NodeValidationState::Valid) + { + m_output = std::make_shared(4); + m_output->preview = PreviewValues(1, 1); + m_output->preview.Fill(Nz::Vector4f::Zero()); + return; + } + + m_output = std::make_shared(4); + m_output->preview = PreviewValues(1, 1); + m_output->preview.Fill(Nz::Vector4f::Zero()); + + /*m_output = std::make_shared(m_rhs->componentCount); + + const PreviewValues& leftPreview = m_lhs->preview; + const PreviewValues& rightPreview = m_rhs->preview; + std::size_t maxWidth = std::max(leftPreview.GetWidth(), rightPreview.GetWidth()); + std::size_t maxHeight = std::max(leftPreview.GetHeight(), rightPreview.GetHeight()); + + // FIXME: Prevent useless copy + PreviewValues leftResized = leftPreview; + if (leftResized.GetWidth() != maxWidth || leftResized.GetHeight() != maxHeight) + leftResized = leftResized.Resized(maxWidth, maxHeight); + + PreviewValues rightResized = rightPreview; + if (rightResized.GetWidth() != maxWidth || rightResized.GetHeight() != maxHeight) + rightResized = rightResized.Resized(maxWidth, maxHeight); + + m_output->preview = PreviewValues(maxWidth, maxHeight); + + const Nz::Vector4f* left = leftResized.GetData(); + const Nz::Vector4f* right = rightPreview.GetData(); + Nz::Vector4f* output = m_output->preview.GetData(); + + std::size_t pixelCount = maxWidth * maxHeight; + for (std::size_t i = 0; i < pixelCount; ++i) + output[i] = left[i] * right[i]; + + Q_EMIT dataUpdated(0); + + UpdatePreview();*/ +} diff --git a/src/ShaderNode/DataModels/Mat4VecMul.hpp b/src/ShaderNode/DataModels/Mat4VecMul.hpp new file mode 100644 index 000000000..608439fcb --- /dev/null +++ b/src/ShaderNode/DataModels/Mat4VecMul.hpp @@ -0,0 +1,43 @@ +#pragma once + +#ifndef NAZARA_SHADERNODES_MAT4VECMUL_HPP +#define NAZARA_SHADERNODES_MAT4VECMUL_HPP + +#include +#include +#include + +class Mat4VecMul : public ShaderNode +{ + public: + Mat4VecMul(ShaderGraph& graph); + ~Mat4VecMul() = default; + + Nz::ShaderNodes::ExpressionPtr GetExpression(Nz::ShaderNodes::ExpressionPtr* expressions, std::size_t count) const override; + + QString caption() const override; + QString name() const override; + + unsigned int nPorts(QtNodes::PortType portType) const override; + + QtNodes::NodeDataType dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; + + std::shared_ptr outData(QtNodes::PortIndex port) override; + + void setInData(std::shared_ptr value, int index) override; + + QtNodes::NodeValidationState validationState() const override; + QString validationMessage() const override; + + private: + bool ComputePreview(QPixmap& pixmap) override; + void UpdateOutput(); + + std::shared_ptr m_lhs; + std::shared_ptr m_rhs; + std::shared_ptr m_output; +}; + +#include + +#endif diff --git a/src/ShaderNode/DataModels/Mat4VecMul.inl b/src/ShaderNode/DataModels/Mat4VecMul.inl new file mode 100644 index 000000000..a798943a8 --- /dev/null +++ b/src/ShaderNode/DataModels/Mat4VecMul.inl @@ -0,0 +1 @@ +#include diff --git a/src/ShaderNode/DataModels/OutputValue.cpp b/src/ShaderNode/DataModels/OutputValue.cpp index b86c46879..6f30a9b66 100644 --- a/src/ShaderNode/DataModels/OutputValue.cpp +++ b/src/ShaderNode/DataModels/OutputValue.cpp @@ -1,6 +1,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -62,23 +65,7 @@ Nz::ShaderNodes::ExpressionPtr OutputValue::GetExpression(Nz::ShaderNodes::Expre throw std::runtime_error("no output"); const auto& outputEntry = GetGraph().GetOutput(*m_currentOutputIndex); - - Nz::ShaderNodes::BasicType expression = [&] - { - switch (outputEntry.type) - { - case PrimitiveType::Bool: return Nz::ShaderNodes::BasicType::Boolean; - case PrimitiveType::Float1: return Nz::ShaderNodes::BasicType::Float1; - case PrimitiveType::Float2: return Nz::ShaderNodes::BasicType::Float2; - case PrimitiveType::Float3: return Nz::ShaderNodes::BasicType::Float3; - case PrimitiveType::Float4: return Nz::ShaderNodes::BasicType::Float4; - } - - assert(false); - throw std::runtime_error("Unhandled output type"); - }(); - - auto output = Nz::ShaderBuilder::Identifier(Nz::ShaderBuilder::Output(outputEntry.name, expression)); + auto output = Nz::ShaderBuilder::Identifier(Nz::ShaderBuilder::Output(outputEntry.name, ShaderGraph::ToShaderExpressionType(outputEntry.type))); return Nz::ShaderBuilder::Assign(std::move(output), *expressions); } @@ -92,18 +79,7 @@ QtNodes::NodeDataType OutputValue::dataType(QtNodes::PortType portType, QtNodes: return VecData::Type(); const auto& outputEntry = GetGraph().GetOutput(*m_currentOutputIndex); - switch (outputEntry.type) - { - //case InOutType::Bool: return Nz::ShaderNodes::BasicType::Boolean; - //case InOutType::Float1: return Nz::ShaderNodes::BasicType::Float1; - case PrimitiveType::Float2: - case PrimitiveType::Float3: - case PrimitiveType::Float4: - return VecData::Type(); - } - - assert(false); - throw std::runtime_error("Unhandled output type"); + return ShaderGraph::ToNodeDataType(outputEntry.type); } unsigned int OutputValue::nPorts(QtNodes::PortType portType) const @@ -124,14 +100,11 @@ std::shared_ptr OutputValue::outData(QtNodes::PortIndex /*por void OutputValue::setInData(std::shared_ptr value, int index) { + if (!m_currentOutputIndex) + return; + assert(index == 0); - if (value) - { - assert(dynamic_cast(value.get()) != nullptr); - m_input = std::static_pointer_cast(value); - } - else - m_input.reset(); + m_input = std::move(value); UpdatePreview(); } @@ -142,8 +115,23 @@ QtNodes::NodeValidationState OutputValue::validationState() const return QtNodes::NodeValidationState::Error; const auto& outputEntry = GetGraph().GetOutput(*m_currentOutputIndex); - if (GetComponentCount(outputEntry.type) != m_input->componentCount) - return QtNodes::NodeValidationState::Error; + switch (outputEntry.type) + { + case PrimitiveType::Bool: + case PrimitiveType::Float1: + case PrimitiveType::Mat4x4: + break; + + case PrimitiveType::Float2: + case PrimitiveType::Float3: + case PrimitiveType::Float4: + { + assert(dynamic_cast(m_input.get()) != nullptr); + const VecData& vec = static_cast(*m_input); + if (GetComponentCount(outputEntry.type) != vec.componentCount) + return QtNodes::NodeValidationState::Error; + } + } return QtNodes::NodeValidationState::Valid; } @@ -157,10 +145,26 @@ QString OutputValue::validationMessage() const return "Missing input"; const auto& outputEntry = GetGraph().GetOutput(*m_currentOutputIndex); - std::size_t outputComponentCount = GetComponentCount(outputEntry.type); + switch (outputEntry.type) + { + case PrimitiveType::Bool: + case PrimitiveType::Float1: + case PrimitiveType::Mat4x4: + break; - if (m_input->componentCount != outputComponentCount) - return "Incompatible component count (expected " + QString::number(outputComponentCount) + ", got " + QString::number(m_input->componentCount) + ")"; + case PrimitiveType::Float2: + case PrimitiveType::Float3: + case PrimitiveType::Float4: + { + assert(dynamic_cast(m_input.get()) != nullptr); + const VecData& vec = static_cast(*m_input); + + std::size_t outputComponentCount = GetComponentCount(outputEntry.type); + + if (outputComponentCount != vec.componentCount) + return "Incompatible component count (expected " + QString::number(outputComponentCount) + ", got " + QString::number(vec.componentCount) + ")"; + } + } return QString(); } @@ -170,8 +174,49 @@ bool OutputValue::ComputePreview(QPixmap& pixmap) if (!m_input) return false; - pixmap = QPixmap::fromImage(m_input->preview.GenerateImage()); - return true; + const auto& outputEntry = GetGraph().GetOutput(*m_currentOutputIndex); + switch (outputEntry.type) + { + case PrimitiveType::Bool: + { + assert(dynamic_cast(m_input.get()) != nullptr); + const BoolData& data = static_cast(*m_input); + + pixmap = QPixmap::fromImage(data.preview.GenerateImage()); + return true; + } + + case PrimitiveType::Float1: + { + assert(dynamic_cast(m_input.get()) != nullptr); + const FloatData& data = static_cast(*m_input); + + pixmap = QPixmap::fromImage(data.preview.GenerateImage()); + return true; + } + + case PrimitiveType::Mat4x4: + { + //TODO + /*assert(dynamic_cast(m_input.get()) != nullptr); + const Matrix4Data& data = static_cast(*m_input);*/ + + return false; + } + + case PrimitiveType::Float2: + case PrimitiveType::Float3: + case PrimitiveType::Float4: + { + assert(dynamic_cast(m_input.get()) != nullptr); + const VecData& data = static_cast(*m_input); + + pixmap = QPixmap::fromImage(data.preview.GenerateImage()); + return true; + } + } + + return false; } void OutputValue::OnOutputListUpdate() diff --git a/src/ShaderNode/DataModels/OutputValue.hpp b/src/ShaderNode/DataModels/OutputValue.hpp index 284e302ea..12c812c5c 100644 --- a/src/ShaderNode/DataModels/OutputValue.hpp +++ b/src/ShaderNode/DataModels/OutputValue.hpp @@ -1,7 +1,7 @@ #pragma once -#ifndef NAZARA_SHADERNODES_FRAGMENTOUTPUT_HPP -#define NAZARA_SHADERNODES_FRAGMENTOUTPUT_HPP +#ifndef NAZARA_SHADERNODES_OUTPUTVALUE_HPP +#define NAZARA_SHADERNODES_OUTPUTVALUE_HPP #include #include @@ -44,7 +44,7 @@ class OutputValue : public ShaderNode NazaraSlot(ShaderGraph, OnOutputUpdate, m_onOutputUpdateSlot); std::optional m_currentOutputIndex; - std::shared_ptr m_input; + std::shared_ptr m_input; std::string m_currentOutputText; }; diff --git a/src/ShaderNode/DataTypes/Matrix4Data.cpp b/src/ShaderNode/DataTypes/Matrix4Data.cpp new file mode 100644 index 000000000..24dfe95a2 --- /dev/null +++ b/src/ShaderNode/DataTypes/Matrix4Data.cpp @@ -0,0 +1 @@ +#include diff --git a/src/ShaderNode/DataTypes/Matrix4Data.hpp b/src/ShaderNode/DataTypes/Matrix4Data.hpp new file mode 100644 index 000000000..fdfbf1897 --- /dev/null +++ b/src/ShaderNode/DataTypes/Matrix4Data.hpp @@ -0,0 +1,19 @@ +#pragma once + +#ifndef NAZARA_SHADERNODES_MATRIXDATA_HPP +#define NAZARA_SHADERNODES_MATRIXDATA_HPP + +#include +#include +#include + +struct Matrix4Data : public QtNodes::NodeData +{ + inline QtNodes::NodeDataType type() const override; + + static inline QtNodes::NodeDataType Type(); +}; + +#include + +#endif diff --git a/src/ShaderNode/DataTypes/Matrix4Data.inl b/src/ShaderNode/DataTypes/Matrix4Data.inl new file mode 100644 index 000000000..157e35810 --- /dev/null +++ b/src/ShaderNode/DataTypes/Matrix4Data.inl @@ -0,0 +1,11 @@ +#include + +inline QtNodes::NodeDataType Matrix4Data::type() const +{ + return Type(); +} + +inline QtNodes::NodeDataType Matrix4Data::Type() +{ + return { "mat4", "Matrix4x4" }; +} diff --git a/src/ShaderNode/Enums.cpp b/src/ShaderNode/Enums.cpp index 610078d65..2c924c3ed 100644 --- a/src/ShaderNode/Enums.cpp +++ b/src/ShaderNode/Enums.cpp @@ -10,6 +10,7 @@ std::size_t GetComponentCount(PrimitiveType type) case PrimitiveType::Float2: return 2; case PrimitiveType::Float3: return 3; case PrimitiveType::Float4: return 4; + case PrimitiveType::Mat4x4: return 16; } assert(false); @@ -50,6 +51,7 @@ const char* EnumToString(PrimitiveType input) case PrimitiveType::Float2: return "Float2"; case PrimitiveType::Float3: return "Float3"; case PrimitiveType::Float4: return "Float4"; + case PrimitiveType::Mat4x4: return "Mat4x4"; } assert(false); diff --git a/src/ShaderNode/Enums.hpp b/src/ShaderNode/Enums.hpp index 41e8f4360..e59d66424 100644 --- a/src/ShaderNode/Enums.hpp +++ b/src/ShaderNode/Enums.hpp @@ -35,8 +35,9 @@ enum class PrimitiveType Float2, Float3, Float4, + Mat4x4, - Max = Float4 + Max = Mat4x4 }; constexpr std::size_t PrimitiveTypeCount = static_cast(PrimitiveType::Max) + 1; diff --git a/src/ShaderNode/ShaderGraph.cpp b/src/ShaderNode/ShaderGraph.cpp index 22d74dca2..5b248bfc3 100644 --- a/src/ShaderNode/ShaderGraph.cpp +++ b/src/ShaderNode/ShaderGraph.cpp @@ -8,11 +8,18 @@ #include #include #include +#include +#include #include #include #include #include #include +#include +#include +#include +#include +#include #include #include #include @@ -591,6 +598,29 @@ void ShaderGraph::UpdateTexturePreview(std::size_t textureIndex, QImage preview) OnTexturePreviewUpdate(this, textureIndex); } +QtNodes::NodeDataType ShaderGraph::ToNodeDataType(PrimitiveType type) +{ + switch (type) + { + case PrimitiveType::Bool: + return BoolData::Type(); + + case PrimitiveType::Float1: + return FloatData::Type(); + + case PrimitiveType::Float2: + case PrimitiveType::Float3: + case PrimitiveType::Float4: + return VecData::Type(); + + case PrimitiveType::Mat4x4: + return Matrix4Data::Type(); + } + + assert(false); + throw std::runtime_error("Unhandled input type"); +} + Nz::ShaderExpressionType ShaderGraph::ToShaderExpressionType(PrimitiveType type) { switch (type) @@ -600,6 +630,7 @@ Nz::ShaderExpressionType ShaderGraph::ToShaderExpressionType(PrimitiveType type) case PrimitiveType::Float2: return Nz::ShaderNodes::BasicType::Float2; case PrimitiveType::Float3: return Nz::ShaderNodes::BasicType::Float3; case PrimitiveType::Float4: return Nz::ShaderNodes::BasicType::Float4; + case PrimitiveType::Mat4x4: return Nz::ShaderNodes::BasicType::Mat4x4; } assert(false); @@ -629,6 +660,10 @@ std::shared_ptr ShaderGraph::BuildRegistry() RegisterShaderNode(*this, registry, "Outputs"); RegisterShaderNode(*this, registry, "Texture"); RegisterShaderNode(*this, registry, "Texture"); + RegisterShaderNode(*this, registry, "Matrix operations"); + RegisterShaderNode(*this, registry, "Matrix operations"); + RegisterShaderNode(*this, registry, "Matrix operations"); + RegisterShaderNode(*this, registry, "Matrix operations"); RegisterShaderNode(*this, registry, "Vector operations"); RegisterShaderNode(*this, registry, "Vector operations"); RegisterShaderNode(*this, registry, "Vector operations"); diff --git a/src/ShaderNode/ShaderGraph.hpp b/src/ShaderNode/ShaderGraph.hpp index 0cab330d0..e91127cb5 100644 --- a/src/ShaderNode/ShaderGraph.hpp +++ b/src/ShaderNode/ShaderGraph.hpp @@ -122,6 +122,7 @@ class ShaderGraph NazaraSignal(OnTexturePreviewUpdate, ShaderGraph*, std::size_t /*textureIndex*/); NazaraSignal(OnTextureUpdate, ShaderGraph*, std::size_t /*textureIndex*/); + static QtNodes::NodeDataType ToNodeDataType(PrimitiveType type); static Nz::ShaderExpressionType ToShaderExpressionType(PrimitiveType type); static Nz::ShaderExpressionType ToShaderExpressionType(TextureType type); From 471194ec16e205467702768d2d8f950f9ff7e264 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Wed, 22 Jul 2020 14:47:00 +0200 Subject: [PATCH 066/105] ShaderNode: Add PositionOutputValue --- .../DataModels/PositionOutputValue.cpp | 84 +++++++++++++++++++ .../DataModels/PositionOutputValue.hpp | 39 +++++++++ .../DataModels/PositionOutputValue.inl | 1 + src/ShaderNode/ShaderGraph.cpp | 2 + 4 files changed, 126 insertions(+) create mode 100644 src/ShaderNode/DataModels/PositionOutputValue.cpp create mode 100644 src/ShaderNode/DataModels/PositionOutputValue.hpp create mode 100644 src/ShaderNode/DataModels/PositionOutputValue.inl diff --git a/src/ShaderNode/DataModels/PositionOutputValue.cpp b/src/ShaderNode/DataModels/PositionOutputValue.cpp new file mode 100644 index 000000000..ee1be66a2 --- /dev/null +++ b/src/ShaderNode/DataModels/PositionOutputValue.cpp @@ -0,0 +1,84 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +PositionOutputValue::PositionOutputValue(ShaderGraph& graph) : +ShaderNode(graph) +{ + DisableCustomVariableName(); +} + +Nz::ShaderNodes::ExpressionPtr PositionOutputValue::GetExpression(Nz::ShaderNodes::ExpressionPtr* expressions, std::size_t count) const +{ + using namespace Nz::ShaderBuilder; + using namespace Nz::ShaderNodes; + + assert(count == 1); + + auto output = Nz::ShaderBuilder::Identifier(Nz::ShaderBuilder::Builtin(BuiltinEntry::VertexPosition)); + return Nz::ShaderBuilder::Assign(std::move(output), *expressions); +} + +QtNodes::NodeDataType PositionOutputValue::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const +{ + assert(portType == QtNodes::PortType::In); + assert(portIndex == 0); + + return VecData::Type(); +} + +unsigned int PositionOutputValue::nPorts(QtNodes::PortType portType) const +{ + switch (portType) + { + case QtNodes::PortType::In: return 1; + case QtNodes::PortType::Out: return 0; + } + + return 0; +} + +std::shared_ptr PositionOutputValue::outData(QtNodes::PortIndex /*port*/) +{ + return {}; +} + +void PositionOutputValue::setInData(std::shared_ptr value, int index) +{ + assert(index == 0); + if (value) + { + assert(dynamic_cast(value.get()) != nullptr); + m_input = std::static_pointer_cast(value); + } + else + m_input.reset(); +} + +QtNodes::NodeValidationState PositionOutputValue::validationState() const +{ + if (!m_input) + return QtNodes::NodeValidationState::Error; + + if (m_input->componentCount != 4) + return QtNodes::NodeValidationState::Error; + + return QtNodes::NodeValidationState::Valid; +} + +QString PositionOutputValue::validationMessage() const +{ + if (!m_input) + return "Missing input"; + + if (m_input->componentCount != 4) + return QString("Expected vector with 4 components, got ") + QString::number(m_input->componentCount); + + return QString(); +} diff --git a/src/ShaderNode/DataModels/PositionOutputValue.hpp b/src/ShaderNode/DataModels/PositionOutputValue.hpp new file mode 100644 index 000000000..2c2b6eb54 --- /dev/null +++ b/src/ShaderNode/DataModels/PositionOutputValue.hpp @@ -0,0 +1,39 @@ +#pragma once + +#ifndef NAZARA_SHADERNODES_POSITIONOUTPUTVALUE_HPP +#define NAZARA_SHADERNODES_POSITIONOUTPUTVALUE_HPP + +#include +#include +#include + +class QFormLayout; + +class PositionOutputValue : public ShaderNode +{ + public: + PositionOutputValue(ShaderGraph& graph); + + Nz::ShaderNodes::ExpressionPtr GetExpression(Nz::ShaderNodes::ExpressionPtr* expressions, std::size_t count) const override; + + QString caption() const override { return "PositionOutputValue"; } + QString name() const override { return "PositionOutputValue"; } + + QtNodes::NodeDataType dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const override; + + unsigned int nPorts(QtNodes::PortType portType) const override; + + std::shared_ptr outData(QtNodes::PortIndex port) override; + + void setInData(std::shared_ptr value, int index) override; + + QtNodes::NodeValidationState validationState() const override; + QString validationMessage() const override; + + private: + std::shared_ptr m_input; +}; + +#include + +#endif diff --git a/src/ShaderNode/DataModels/PositionOutputValue.inl b/src/ShaderNode/DataModels/PositionOutputValue.inl new file mode 100644 index 000000000..585e40a7f --- /dev/null +++ b/src/ShaderNode/DataModels/PositionOutputValue.inl @@ -0,0 +1 @@ +#include diff --git a/src/ShaderNode/ShaderGraph.cpp b/src/ShaderNode/ShaderGraph.cpp index 5b248bfc3..afa53d2f3 100644 --- a/src/ShaderNode/ShaderGraph.cpp +++ b/src/ShaderNode/ShaderGraph.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -657,6 +658,7 @@ std::shared_ptr ShaderGraph::BuildRegistry() RegisterShaderNode(*this, registry, "Casts"); RegisterShaderNode(*this, registry, "Constants"); RegisterShaderNode(*this, registry, "Inputs"); + RegisterShaderNode(*this, registry, "Outputs"); RegisterShaderNode(*this, registry, "Outputs"); RegisterShaderNode(*this, registry, "Texture"); RegisterShaderNode(*this, registry, "Texture"); From 7b1d712560dc02b1d03d5038203357b49d9c823e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Wed, 22 Jul 2020 14:47:13 +0200 Subject: [PATCH 067/105] ShaderNode: Fix struct members serialization --- src/ShaderNode/ShaderGraph.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ShaderNode/ShaderGraph.cpp b/src/ShaderNode/ShaderGraph.cpp index afa53d2f3..b7f9b99a6 100644 --- a/src/ShaderNode/ShaderGraph.cpp +++ b/src/ShaderNode/ShaderGraph.cpp @@ -359,7 +359,7 @@ QJsonObject ShaderGraph::Save() static_assert(AlwaysFalse::value, "non-exhaustive visitor"); }, member.type); - memberDoc["type"] = QString::fromStdString(member.name); + memberArray.append(std::move(memberDoc)); } structDoc["members"] = memberArray; From c6c301c9f58698e7070b2e063123d9325d8d97b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Wed, 22 Jul 2020 14:47:57 +0200 Subject: [PATCH 068/105] ShaderNode: Fix BufferField remaining bugs --- src/ShaderNode/DataModels/BufferField.cpp | 35 +++++++++++++++++------ src/ShaderNode/DataModels/BufferField.hpp | 10 +++---- 2 files changed, 32 insertions(+), 13 deletions(-) diff --git a/src/ShaderNode/DataModels/BufferField.cpp b/src/ShaderNode/DataModels/BufferField.cpp index 480d53c2c..844f56bd8 100644 --- a/src/ShaderNode/DataModels/BufferField.cpp +++ b/src/ShaderNode/DataModels/BufferField.cpp @@ -3,8 +3,10 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -12,6 +14,8 @@ BufferField::BufferField(ShaderGraph& graph) : ShaderNode(graph) { + UpdateFieldList(); + m_onBufferListUpdateSlot.Connect(GetGraph().OnBufferListUpdate, [&](ShaderGraph*) { UpdateBufferIndex(); }); m_onBufferUpdateSlot.Connect(GetGraph().OnBufferUpdate, [&](ShaderGraph*, std::size_t bufferIndex) { @@ -25,6 +29,7 @@ ShaderNode(graph) m_onStructListUpdateSlot.Connect(GetGraph().OnStructListUpdate, [&](ShaderGraph*) { + UpdateFieldList(); UpdateFieldIndex(); UpdatePreview(); @@ -33,6 +38,7 @@ ShaderNode(graph) m_onStructUpdateSlot.Connect(GetGraph().OnStructUpdate, [&](ShaderGraph*, std::size_t) { + UpdateFieldList(); UpdateFieldIndex(); UpdatePreview(); @@ -87,7 +93,7 @@ Nz::ShaderNodes::ExpressionPtr BufferField::GetExpression(Nz::ShaderNodes::Expre const auto& memberEntry = sourceStruct->members[currentField.finalFieldIndex]; assert(std::holds_alternative(memberEntry.type)); - return Nz::ShaderBuilder::AccessMember(std::move(sourceExpr), 0, graph.ToShaderExpressionType(std::get(memberEntry.type))); + return Nz::ShaderBuilder::AccessMember(std::move(sourceExpr), currentField.finalFieldIndex, graph.ToShaderExpressionType(std::get(memberEntry.type))); } unsigned int BufferField::nPorts(QtNodes::PortType portType) const @@ -109,7 +115,7 @@ void BufferField::BuildNodeEdition(QFormLayout* layout) connect(fieldSelection, qOverload(&QComboBox::currentIndexChanged), [=](int index) { if (index >= 0) - m_currentFieldText = fieldSelection->itemText(index).toStdString(); + m_currentFieldText = m_fieldList[index]; else m_currentFieldText.clear(); @@ -132,9 +138,9 @@ void BufferField::BuildNodeEdition(QFormLayout* layout) { m_currentBufferIndex = static_cast(index); - const ShaderGraph& graph = GetGraph(); - const auto& buffer = graph.GetBuffer(*m_currentBufferIndex); - PopulateField(fieldSelection, buffer.structIndex); + UpdateFieldList(); + for (const std::string& field : m_fieldList) + fieldSelection->addItem(QString::fromStdString(field)); } else m_currentBufferIndex.reset(); @@ -257,6 +263,7 @@ void BufferField::restore(const QJsonObject& data) m_currentBufferText = data["buffer"].toString().toStdString(); m_currentFieldText = data["field"].toString().toStdString(); UpdateBufferIndex(); + UpdateFieldIndex(); ShaderNode::restore(data); } @@ -307,7 +314,7 @@ bool BufferField::ComputePreview(QPixmap& pixmap) return true;*/ } -void BufferField::PopulateField(QComboBox* fieldList, std::size_t structIndex, const std::string& prefix) +void BufferField::PopulateFieldList(std::size_t structIndex, const std::string& prefix) { const auto& s = GetGraph().GetStruct(structIndex); for (const auto& member : s.members) @@ -316,9 +323,9 @@ void BufferField::PopulateField(QComboBox* fieldList, std::size_t structIndex, c { using T = std::decay_t; if constexpr (std::is_same_v) - fieldList->addItem(QString::fromStdString(prefix + member.name)); + m_fieldList.push_back(prefix + member.name); else if constexpr (std::is_same_v) - PopulateField(fieldList, arg, prefix + member.name + "."); + PopulateFieldList(arg, prefix + member.name + "."); else static_assert(AlwaysFalse::value, "non-exhaustive visitor"); }, @@ -454,3 +461,15 @@ void BufferField::UpdateFieldIndex() if (FetchField(buffer.structIndex, "")) resetIfNotFound.Reset(); } + +void BufferField::UpdateFieldList() +{ + m_fieldList.clear(); + if (!m_currentBufferIndex) + return; + + const ShaderGraph& graph = GetGraph(); + const auto& buffer = graph.GetBuffer(*m_currentBufferIndex); + + PopulateFieldList(buffer.structIndex); +} diff --git a/src/ShaderNode/DataModels/BufferField.hpp b/src/ShaderNode/DataModels/BufferField.hpp index 7d1295e99..8bd232a7a 100644 --- a/src/ShaderNode/DataModels/BufferField.hpp +++ b/src/ShaderNode/DataModels/BufferField.hpp @@ -3,13 +3,11 @@ #ifndef NAZARA_SHADERNODES_BUFFERFIELD_HPP #define NAZARA_SHADERNODES_BUFFERFIELD_HPP -#include -#include -#include #include #include -#include #include +#include +#include class BufferField : public ShaderNode { @@ -41,11 +39,12 @@ class BufferField : public ShaderNode private: bool ComputePreview(QPixmap& pixmap) override; - void PopulateField(QComboBox* fieldList, std::size_t structIndex, const std::string& prefix = ""); + void PopulateFieldList(std::size_t structIndex, const std::string& prefix = ""); const ShaderGraph::StructMemberEntry& RetrieveNestedMember() const; void UpdateBufferIndex(); void UpdateBufferText(); void UpdateFieldIndex(); + void UpdateFieldList(); NazaraSlot(ShaderGraph, OnBufferListUpdate, m_onBufferListUpdateSlot); NazaraSlot(ShaderGraph, OnBufferUpdate, m_onBufferUpdateSlot); @@ -63,6 +62,7 @@ class BufferField : public ShaderNode std::optional m_currentFieldIndex; std::string m_currentBufferText; std::string m_currentFieldText; + std::vector m_fieldList; }; #include From 063b7dd6020e10813ff2505e699c5020ca38acaa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Wed, 22 Jul 2020 14:48:15 +0200 Subject: [PATCH 069/105] Renderer/GlslWriter: Add parenthesis where required (wip) --- include/Nazara/Renderer/GlslWriter.hpp | 1 + src/Nazara/Renderer/GlslWriter.cpp | 21 ++++++++++++++++----- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/include/Nazara/Renderer/GlslWriter.hpp b/include/Nazara/Renderer/GlslWriter.hpp index ba2444aec..f9694a8f1 100644 --- a/include/Nazara/Renderer/GlslWriter.hpp +++ b/include/Nazara/Renderer/GlslWriter.hpp @@ -61,6 +61,7 @@ namespace Nz using ShaderVarVisitor::Visit; using ShaderVisitor::Visit; + void Visit(const ShaderNodes::ExpressionPtr& expr, bool encloseIfRequired = false); void Visit(const ShaderNodes::AccessMember& node) override; void Visit(const ShaderNodes::AssignOp& node) override; void Visit(const ShaderNodes::Branch& node) override; diff --git a/src/Nazara/Renderer/GlslWriter.cpp b/src/Nazara/Renderer/GlslWriter.cpp index 972cdb4d2..3f2a4a4a3 100644 --- a/src/Nazara/Renderer/GlslWriter.cpp +++ b/src/Nazara/Renderer/GlslWriter.cpp @@ -297,11 +297,22 @@ namespace Nz AppendLine("}"); } + void GlslWriter::Visit(const ShaderNodes::ExpressionPtr& expr, bool encloseIfRequired) + { + bool enclose = encloseIfRequired && (expr->GetExpressionCategory() != ShaderNodes::ExpressionCategory::LValue); + + if (enclose) + Append("("); + + ShaderVisitor::Visit(expr); + + if (enclose) + Append(")"); + } + void GlslWriter::Visit(const ShaderNodes::AccessMember& node) { - Append("("); - Visit(node.structExpr); - Append(")"); + Visit(node.structExpr, true); const ShaderExpressionType& exprType = node.structExpr->GetExpressionType(); assert(std::holds_alternative(exprType)); @@ -365,7 +376,7 @@ namespace Nz void GlslWriter::Visit(const ShaderNodes::BinaryOp& node) { - Visit(node.left); + Visit(node.left, true); switch (node.op) { @@ -386,7 +397,7 @@ namespace Nz break; } - Visit(node.right); + Visit(node.right, true); } void GlslWriter::Visit(const ShaderNodes::BuiltinVariable& var) From 6d0a59caab1650c25b25cf5bbc9ae35eb878c5bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Wed, 22 Jul 2020 14:48:35 +0200 Subject: [PATCH 070/105] VulkanTest: Use generated shader nodes --- examples/VulkanTest/main.cpp | 4 ++-- examples/bin/frag.shader | Bin 0 -> 610 bytes examples/bin/shader.shader | Bin 510 -> 0 bytes examples/bin/vert.shader | Bin 0 -> 695 bytes 4 files changed, 2 insertions(+), 2 deletions(-) create mode 100644 examples/bin/frag.shader delete mode 100644 examples/bin/shader.shader create mode 100644 examples/bin/vert.shader diff --git a/examples/VulkanTest/main.cpp b/examples/VulkanTest/main.cpp index e0cb14437..f52e14561 100644 --- a/examples/VulkanTest/main.cpp +++ b/examples/VulkanTest/main.cpp @@ -44,14 +44,14 @@ int main() return __LINE__; } #else - auto fragmentShader = device->InstantiateShaderStage(Nz::ShaderStageType::Fragment, Nz::ShaderLanguage::NazaraBinary, "shader.shader"); + auto fragmentShader = device->InstantiateShaderStage(Nz::ShaderStageType::Fragment, Nz::ShaderLanguage::NazaraBinary, "frag.shader"); if (!fragmentShader) { std::cout << "Failed to instantiate fragment shader" << std::endl; return __LINE__; } - auto vertexShader = device->InstantiateShaderStage(Nz::ShaderStageType::Vertex, Nz::ShaderLanguage::GLSL, "resources/shaders/triangle.vert"); + auto vertexShader = device->InstantiateShaderStage(Nz::ShaderStageType::Vertex, Nz::ShaderLanguage::NazaraBinary, "vert.shader"); if (!vertexShader) { std::cout << "Failed to instantiate fragment shader" << std::endl; diff --git a/examples/bin/frag.shader b/examples/bin/frag.shader new file mode 100644 index 0000000000000000000000000000000000000000..bf92becd151cdb94d0caf6505eee679eb663e25e GIT binary patch literal 610 zcmdr|%L>9U5R7frYU#gt@ZO7vryg4M9yHWIno7vQzw@WO3hpckKIj)17&e{R>CUEZ zca0EYLcmD~xwiG-dTBtUQOUGD9Kj@DBFaYDvvPasI^|c8vuHqFdUb1Me>KWMn?)P@ zvtDXT>>LuEl8_Sc%{h$jE`Fog3Sk-=#C`pIRD_S_f}6MU7=9LXNz$EUM>iu l)AHb;!fqrOS(jMY;|$cXECun%fE|8cB}j<+e&xSe9U5KJGo)%J6|_n;I{J@~o@ZEK)yptj)AKl7)&itdCgXcb%-Cd^J|lg&4) zwGhG~xP(Zxx$YWS)7gWF@>RRr6T1)?i5~i_lhs1kx`T<`;BZ@9`k^c681MzK-$>P> zPe3IEpAZnt_*zw`eyI@X*&bNj=8trp8P$ diff --git a/examples/bin/vert.shader b/examples/bin/vert.shader new file mode 100644 index 0000000000000000000000000000000000000000..63df1bfb3e72b125fb3222535f8a1ace0f827aa8 GIT binary patch literal 695 zcmah`K@Ng25Uf(77=4omFP@B1KY-Xn4Ny}>Jo+=ArZa^qsU&PNS$1}Jy1Q)l>zxo{ z)M8qsH>)#sMH~V0V$B&|#6)due)5sLYgPMzwXrU@hK(Yk94*o1#@Hgwe>77wT^`h9 zWsG%dV{+pbiK%W)4~U=A9JKFoVy?-L9aTre@9+2w+*01lBGn~=2?^K&kiZmh#qbHh zMgHGvlPnBp2i2z$tkDq&Zh{PF;`+%ovr73RayoyM&?DuH6Z6mf?awR|G$#!|SjhDT o6*(5cLN;{%IwP{nrx5Sf5Qpah)mV2!HcB?W0D1z(XL@e)0UA Date: Mon, 27 Jul 2020 18:52:58 +0200 Subject: [PATCH 071/105] Add shader type --- include/Nazara/Renderer/ShaderAst.hpp | 10 +++- include/Nazara/Renderer/ShaderAst.inl | 10 ++++ include/Nazara/Renderer/ShaderWriter.hpp | 4 +- .../OpenGLRenderer/OpenGLShaderStage.cpp | 3 + src/Nazara/Renderer/ShaderSerializer.cpp | 7 ++- src/ShaderNode/Enums.cpp | 13 +++++ src/ShaderNode/Enums.hpp | 13 +++++ src/ShaderNode/ShaderGraph.cpp | 33 ++++++++++- src/ShaderNode/ShaderGraph.hpp | 6 ++ src/ShaderNode/ShaderGraph.inl | 5 ++ src/ShaderNode/Widgets/MainWindow.cpp | 39 ++++++++++--- src/ShaderNode/Widgets/MainWindow.hpp | 1 + src/ShaderNode/Widgets/ShaderInfoDialog.cpp | 58 +++++++++++++++++++ src/ShaderNode/Widgets/ShaderInfoDialog.hpp | 33 +++++++++++ src/ShaderNode/Widgets/ShaderInfoDialog.inl | 1 + 15 files changed, 224 insertions(+), 12 deletions(-) create mode 100644 src/ShaderNode/Widgets/ShaderInfoDialog.cpp create mode 100644 src/ShaderNode/Widgets/ShaderInfoDialog.hpp create mode 100644 src/ShaderNode/Widgets/ShaderInfoDialog.inl diff --git a/include/Nazara/Renderer/ShaderAst.hpp b/include/Nazara/Renderer/ShaderAst.hpp index 035aa5cce..51117c1d7 100644 --- a/include/Nazara/Renderer/ShaderAst.hpp +++ b/include/Nazara/Renderer/ShaderAst.hpp @@ -8,6 +8,7 @@ #define NAZARA_SHADER_AST_HPP #include +#include #include #include #include @@ -27,7 +28,9 @@ namespace Nz struct Uniform; struct VariableBase; - ShaderAst() = default; + inline ShaderAst(ShaderStageType shaderStage); + ShaderAst(const ShaderAst&) = default; + ShaderAst(ShaderAst&&) = default; ~ShaderAst() = default; void AddFunction(std::string name, ShaderNodes::StatementPtr statement, std::vector parameters = {}, ShaderNodes::BasicType returnType = ShaderNodes::BasicType::Void); @@ -45,6 +48,7 @@ namespace Nz inline const InputOutput& GetOutput(std::size_t i) const; inline std::size_t GetOutputCount() const; inline const std::vector& GetOutputs() const; + inline ShaderStageType GetStage() const; inline const Struct& GetStruct(std::size_t i) const; inline std::size_t GetStructCount() const; inline const std::vector& GetStructs() const; @@ -52,6 +56,9 @@ namespace Nz inline std::size_t GetUniformCount() const; inline const std::vector& GetUniforms() const; + ShaderAst& operator=(const ShaderAst&) = default; + ShaderAst& operator=(ShaderAst&&) = default; + struct VariableBase { std::string name; @@ -99,6 +106,7 @@ namespace Nz std::vector m_outputs; std::vector m_structs; std::vector m_uniforms; + ShaderStageType m_stage; }; } diff --git a/include/Nazara/Renderer/ShaderAst.inl b/include/Nazara/Renderer/ShaderAst.inl index c42c1e9c1..f0bc1aebb 100644 --- a/include/Nazara/Renderer/ShaderAst.inl +++ b/include/Nazara/Renderer/ShaderAst.inl @@ -7,6 +7,11 @@ namespace Nz { + inline ShaderAst::ShaderAst(ShaderStageType shaderStage) : + m_stage(shaderStage) + { + } + inline auto ShaderAst::GetFunction(std::size_t i) const -> const Function& { assert(i < m_functions.size()); @@ -55,6 +60,11 @@ namespace Nz return m_outputs; } + inline ShaderStageType ShaderAst::GetStage() const + { + return m_stage; + } + inline auto ShaderAst::GetStruct(std::size_t i) const -> const Struct& { assert(i < m_structs.size()); diff --git a/include/Nazara/Renderer/ShaderWriter.hpp b/include/Nazara/Renderer/ShaderWriter.hpp index 6c2655226..e4fe2d835 100644 --- a/include/Nazara/Renderer/ShaderWriter.hpp +++ b/include/Nazara/Renderer/ShaderWriter.hpp @@ -19,8 +19,8 @@ namespace Nz { public: ShaderWriter() = default; - ShaderWriter(const ShaderWriter&) = delete; - ShaderWriter(ShaderWriter&&) = delete; + ShaderWriter(const ShaderWriter&) = default; + ShaderWriter(ShaderWriter&&) = default; virtual ~ShaderWriter(); virtual std::string Generate(const ShaderAst& shader) = 0; diff --git a/src/Nazara/OpenGLRenderer/OpenGLShaderStage.cpp b/src/Nazara/OpenGLRenderer/OpenGLShaderStage.cpp index b7cc63c9f..a2a3fbf7a 100644 --- a/src/Nazara/OpenGLRenderer/OpenGLShaderStage.cpp +++ b/src/Nazara/OpenGLRenderer/OpenGLShaderStage.cpp @@ -31,6 +31,9 @@ namespace Nz ByteStream byteStream(source, sourceSize); auto shader = Nz::UnserializeShader(byteStream); + if (shader.GetStage() != type) + throw std::runtime_error("incompatible shader stage"); + const auto& context = device.GetReferenceContext(); const auto& contextParams = context.GetParams(); diff --git a/src/Nazara/Renderer/ShaderSerializer.cpp b/src/Nazara/Renderer/ShaderSerializer.cpp index 350ec2096..7441162a0 100644 --- a/src/Nazara/Renderer/ShaderSerializer.cpp +++ b/src/Nazara/Renderer/ShaderSerializer.cpp @@ -261,6 +261,8 @@ namespace Nz { m_stream << s_magicNumber << s_currentVersion; + m_stream << UInt32(shader.GetStage()); + auto SerializeType = [&](const ShaderExpressionType& type) { std::visit([&](auto&& arg) @@ -454,7 +456,10 @@ namespace Nz if (version > s_currentVersion) throw std::runtime_error("unsupported version"); - ShaderAst shader; + UInt32 shaderStage; + m_stream >> shaderStage; + + ShaderAst shader(static_cast(shaderStage)); UInt32 structCount; m_stream >> structCount; diff --git a/src/ShaderNode/Enums.cpp b/src/ShaderNode/Enums.cpp index 2c924c3ed..73af36b06 100644 --- a/src/ShaderNode/Enums.cpp +++ b/src/ShaderNode/Enums.cpp @@ -58,6 +58,19 @@ const char* EnumToString(PrimitiveType input) return ""; } +const char* EnumToString(ShaderType type) +{ + switch (type) + { + case ShaderType::NotSet: return "NotSet"; + case ShaderType::Fragment: return "Fragment"; + case ShaderType::Vertex: return "Vertex"; + } + + assert(false); + return ""; +} + const char* EnumToString(TextureType textureType) { switch (textureType) diff --git a/src/ShaderNode/Enums.hpp b/src/ShaderNode/Enums.hpp index e59d66424..c57969fb2 100644 --- a/src/ShaderNode/Enums.hpp +++ b/src/ShaderNode/Enums.hpp @@ -42,6 +42,18 @@ enum class PrimitiveType constexpr std::size_t PrimitiveTypeCount = static_cast(PrimitiveType::Max) + 1; +enum class ShaderType +{ + NotSet = -1, + + Fragment, + Vertex, + + Max = Vertex +}; + +constexpr std::size_t ShaderTypeCount = static_cast(ShaderType::Max) + 1; + enum class TextureType { Sampler2D, @@ -56,6 +68,7 @@ template std::optional DecodeEnum(const std::string_view& str); const char* EnumToString(BufferType bufferType); const char* EnumToString(InputRole role); const char* EnumToString(PrimitiveType input); +const char* EnumToString(ShaderType type); const char* EnumToString(TextureType textureType); std::size_t GetComponentCount(PrimitiveType type); diff --git a/src/ShaderNode/ShaderGraph.cpp b/src/ShaderNode/ShaderGraph.cpp index b7f9b99a6..a1799df3b 100644 --- a/src/ShaderNode/ShaderGraph.cpp +++ b/src/ShaderNode/ShaderGraph.cpp @@ -41,7 +41,8 @@ namespace } ShaderGraph::ShaderGraph() : -m_flowScene(BuildRegistry()) +m_flowScene(BuildRegistry()), +m_type(ShaderType::NotSet) { m_previewModel = std::make_unique(); @@ -178,6 +179,8 @@ std::size_t ShaderGraph::AddTexture(std::string name, TextureType type, std::siz void ShaderGraph::Clear() { + m_type = ShaderType::NotSet; + m_flowScene.clearScene(); m_flowScene.clear(); @@ -198,6 +201,9 @@ void ShaderGraph::Load(const QJsonObject& data) { Clear(); + if (auto typeOpt = DecodeEnum(data["type"].toString().toStdString())) + m_type = typeOpt.value(); + QJsonArray bufferArray = data["buffers"].toArray(); for (const auto& bufferDocRef : bufferArray) { @@ -289,6 +295,7 @@ void ShaderGraph::Load(const QJsonObject& data) QJsonObject ShaderGraph::Save() { QJsonObject sceneJson; + sceneJson["type"] = QString(EnumToString(m_type)); QJsonArray bufferArray; { @@ -599,6 +606,15 @@ void ShaderGraph::UpdateTexturePreview(std::size_t textureIndex, QImage preview) OnTexturePreviewUpdate(this, textureIndex); } +void ShaderGraph::UpdateType(ShaderType type) +{ + if (m_type != type) + { + m_type = type; + OnTypeUpdated(this); + } +} + QtNodes::NodeDataType ShaderGraph::ToNodeDataType(PrimitiveType type) { switch (type) @@ -649,6 +665,21 @@ Nz::ShaderExpressionType ShaderGraph::ToShaderExpressionType(TextureType type) throw std::runtime_error("Unhandled texture type"); } +Nz::ShaderStageType ShaderGraph::ToShaderStageType(ShaderType type) +{ + switch (type) + { + case ShaderType::NotSet: + throw std::runtime_error("Invalid shader type"); + + case ShaderType::Fragment: return Nz::ShaderStageType::Fragment; + case ShaderType::Vertex: return Nz::ShaderStageType::Vertex; + } + + assert(false); + throw std::runtime_error("Unhandled shader type"); +} + std::shared_ptr ShaderGraph::BuildRegistry() { auto registry = std::make_shared(); diff --git a/src/ShaderNode/ShaderGraph.hpp b/src/ShaderNode/ShaderGraph.hpp index e91127cb5..be7aeba4c 100644 --- a/src/ShaderNode/ShaderGraph.hpp +++ b/src/ShaderNode/ShaderGraph.hpp @@ -4,6 +4,7 @@ #define NAZARA_SHADERNODES_SHADERGRAPH_HPP #include +#include #include #include #include @@ -51,6 +52,7 @@ class ShaderGraph inline const TextureEntry& GetTexture(std::size_t textureIndex) const; inline std::size_t GetTextureCount() const; inline const std::vector& GetTextures() const; + inline ShaderType GetType() const; void Load(const QJsonObject& data); QJsonObject Save(); @@ -64,6 +66,7 @@ class ShaderGraph void UpdateStruct(std::size_t structIndex, std::string name, std::vector members); void UpdateTexture(std::size_t textureIndex, std::string name, TextureType type, std::size_t bindingIndex); void UpdateTexturePreview(std::size_t texture, QImage preview); + void UpdateType(ShaderType type); struct BufferEntry { @@ -121,10 +124,12 @@ class ShaderGraph NazaraSignal(OnTextureListUpdate, ShaderGraph*); NazaraSignal(OnTexturePreviewUpdate, ShaderGraph*, std::size_t /*textureIndex*/); NazaraSignal(OnTextureUpdate, ShaderGraph*, std::size_t /*textureIndex*/); + NazaraSignal(OnTypeUpdated, ShaderGraph*); static QtNodes::NodeDataType ToNodeDataType(PrimitiveType type); static Nz::ShaderExpressionType ToShaderExpressionType(PrimitiveType type); static Nz::ShaderExpressionType ToShaderExpressionType(TextureType type); + static Nz::ShaderStageType ToShaderStageType(ShaderType type); private: std::shared_ptr BuildRegistry(); @@ -136,6 +141,7 @@ class ShaderGraph std::vector m_structs; std::vector m_textures; std::unique_ptr m_previewModel; + ShaderType m_type; }; #include diff --git a/src/ShaderNode/ShaderGraph.inl b/src/ShaderNode/ShaderGraph.inl index 04f86834c..afa867dcd 100644 --- a/src/ShaderNode/ShaderGraph.inl +++ b/src/ShaderNode/ShaderGraph.inl @@ -90,3 +90,8 @@ inline auto ShaderGraph::GetTextures() const -> const std::vector& return m_textures; } +inline ShaderType ShaderGraph::GetType() const +{ + return m_type; +} + diff --git a/src/ShaderNode/Widgets/MainWindow.cpp b/src/ShaderNode/Widgets/MainWindow.cpp index 7c7101047..f25f95a18 100644 --- a/src/ShaderNode/Widgets/MainWindow.cpp +++ b/src/ShaderNode/Widgets/MainWindow.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -104,19 +105,27 @@ void MainWindow::BuildMenu() { QMenuBar* menu = menuBar(); + QMenu* file = menu->addMenu(tr("&File")); + { + QAction* loadShader = file->addAction(tr("Load...")); + QObject::connect(loadShader, &QAction::triggered, this, &MainWindow::OnLoad); + QAction* saveShader = file->addAction(tr("Save...")); + QObject::connect(saveShader, &QAction::triggered, this, &MainWindow::OnSave); + } + QMenu* shader = menu->addMenu(tr("&Shader")); { - QAction* loadShader = shader->addAction(tr("Load...")); - QObject::connect(loadShader, &QAction::triggered, this, &MainWindow::OnLoad); - QAction* saveShader = shader->addAction(tr("Save...")); - QObject::connect(saveShader, &QAction::triggered, this, &MainWindow::OnSave); + QAction* settings = shader->addAction(tr("Settings...")); + QObject::connect(settings, &QAction::triggered, this, &MainWindow::OnUpdateInfo); QAction* compileShader = shader->addAction(tr("Compile...")); QObject::connect(compileShader, &QAction::triggered, this, &MainWindow::OnCompile); } QMenu* generateMenu = menu->addMenu(tr("&Generate")); - QAction* generateGlsl = generateMenu->addAction(tr("GLSL")); - connect(generateGlsl, &QAction::triggered, [&](bool) { OnGenerateGLSL(); }); + { + QAction* generateGlsl = generateMenu->addAction(tr("GLSL")); + connect(generateGlsl, &QAction::triggered, [&](bool) { OnGenerateGLSL(); }); + } } void MainWindow::OnCompile() @@ -208,11 +217,27 @@ void MainWindow::OnSave() file.write(QJsonDocument(m_shaderGraph.Save()).toJson()); } +void MainWindow::OnUpdateInfo() +{ + ShaderInfo info; + info.type = m_shaderGraph.GetType(); + + ShaderInfoDialog* dialog = new ShaderInfoDialog(std::move(info), this); + dialog->setAttribute(Qt::WA_DeleteOnClose, true); + connect(dialog, &QDialog::accepted, [this, dialog] + { + ShaderInfo shaderInfo = dialog->GetShaderInfo(); + m_shaderGraph.UpdateType(shaderInfo.type); + }); + + dialog->open(); +} + Nz::ShaderAst MainWindow::ToShader() { Nz::ShaderNodes::StatementPtr shaderAst = m_shaderGraph.ToAst(); - Nz::ShaderAst shader; + Nz::ShaderAst shader(ShaderGraph::ToShaderStageType(m_shaderGraph.GetType())); //< FIXME for (const auto& input : m_shaderGraph.GetInputs()) shader.AddInput(input.name, m_shaderGraph.ToShaderExpressionType(input.type), input.locationIndex); diff --git a/src/ShaderNode/Widgets/MainWindow.hpp b/src/ShaderNode/Widgets/MainWindow.hpp index 25c742625..76615bb98 100644 --- a/src/ShaderNode/Widgets/MainWindow.hpp +++ b/src/ShaderNode/Widgets/MainWindow.hpp @@ -26,6 +26,7 @@ class MainWindow : public QMainWindow void OnGenerateGLSL(); void OnLoad(); void OnSave(); + void OnUpdateInfo(); Nz::ShaderAst ToShader(); NazaraSlot(ShaderGraph, OnSelectedNodeUpdate, m_onSelectedNodeUpdate); diff --git a/src/ShaderNode/Widgets/ShaderInfoDialog.cpp b/src/ShaderNode/Widgets/ShaderInfoDialog.cpp new file mode 100644 index 000000000..54687a99e --- /dev/null +++ b/src/ShaderNode/Widgets/ShaderInfoDialog.cpp @@ -0,0 +1,58 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +ShaderInfoDialog::ShaderInfoDialog(QWidget* parent) : +QDialog(parent) +{ + setWindowTitle(tr("Shader edit dialog")); + setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); + + m_typeList = new QComboBox; + for (std::size_t i = 0; i < ShaderTypeCount; ++i) + m_typeList->addItem(EnumToString(static_cast(i))); + + QFormLayout* formLayout = new QFormLayout; + formLayout->addRow(tr("Type"), m_typeList); + + QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); + connect(buttonBox, &QDialogButtonBox::accepted, this, &ShaderInfoDialog::OnAccept); + connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); + + QVBoxLayout* verticalLayout = new QVBoxLayout; + verticalLayout->addLayout(formLayout); + verticalLayout->addWidget(buttonBox); + + setLayout(verticalLayout); +} + +ShaderInfoDialog::ShaderInfoDialog(const ShaderInfo& shader, QWidget* parent) : +ShaderInfoDialog(parent) +{ + m_typeList->setCurrentText(QString(EnumToString(shader.type))); +} + +ShaderInfo ShaderInfoDialog::GetShaderInfo() const +{ + ShaderInfo bufferInfo; + bufferInfo.type = static_cast(m_typeList->currentIndex()); + + return bufferInfo; +} + +void ShaderInfoDialog::OnAccept() +{ + if (m_typeList->currentIndex() < 0) + { + QMessageBox::critical(this, tr("Invalid shader type"), tr("You must select a shader type"), QMessageBox::Ok); + return; + } + + accept(); +} diff --git a/src/ShaderNode/Widgets/ShaderInfoDialog.hpp b/src/ShaderNode/Widgets/ShaderInfoDialog.hpp new file mode 100644 index 000000000..210323a8e --- /dev/null +++ b/src/ShaderNode/Widgets/ShaderInfoDialog.hpp @@ -0,0 +1,33 @@ +#pragma once + +#ifndef NAZARA_SHADERNODES_BUFFEREDITDIALOG_HPP +#define NAZARA_SHADERNODES_BUFFEREDITDIALOG_HPP + +#include +#include + +class QComboBox; + +struct ShaderInfo +{ + ShaderType type; +}; + +class ShaderInfoDialog : public QDialog +{ + public: + ShaderInfoDialog(QWidget* parent = nullptr); + ShaderInfoDialog(const ShaderInfo& shader, QWidget* parent = nullptr); + ~ShaderInfoDialog() = default; + + ShaderInfo GetShaderInfo() const; + + private: + void OnAccept(); + + QComboBox* m_typeList; +}; + +#include + +#endif diff --git a/src/ShaderNode/Widgets/ShaderInfoDialog.inl b/src/ShaderNode/Widgets/ShaderInfoDialog.inl new file mode 100644 index 000000000..e81e9cd71 --- /dev/null +++ b/src/ShaderNode/Widgets/ShaderInfoDialog.inl @@ -0,0 +1 @@ +#include From 251810ca9929baa72b965e0eea46cd0f974fbc97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Wed, 29 Jul 2020 11:22:52 +0200 Subject: [PATCH 072/105] WIP SpirvWriter --- examples/VulkanTest/main.cpp | 33 + examples/bin/frag.shader | Bin 610 -> 610 bytes examples/bin/vert.shader | Bin 695 -> 695 bytes include/Nazara/Renderer/ShaderEnums.hpp | 9 + include/Nazara/Renderer/SpirvWriter.hpp | 100 ++ include/Nazara/Renderer/SpirvWriter.inl | 56 + src/Nazara/Renderer/SpirvWriter.cpp | 178 ++ thirdparty/include/SpirV/GLSL.std.450.h | 131 ++ thirdparty/include/SpirV/spirv.h | 2163 +++++++++++++++++++++++ 9 files changed, 2670 insertions(+) create mode 100644 include/Nazara/Renderer/SpirvWriter.hpp create mode 100644 include/Nazara/Renderer/SpirvWriter.inl create mode 100644 src/Nazara/Renderer/SpirvWriter.cpp create mode 100644 thirdparty/include/SpirV/GLSL.std.450.h create mode 100644 thirdparty/include/SpirV/spirv.h diff --git a/examples/VulkanTest/main.cpp b/examples/VulkanTest/main.cpp index f52e14561..9a5313f9a 100644 --- a/examples/VulkanTest/main.cpp +++ b/examples/VulkanTest/main.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include @@ -7,6 +8,38 @@ int main() { + { + Nz::File file("frag.shader"); + if (!file.Open(Nz::OpenMode_ReadOnly)) + return __LINE__; + + std::size_t length = static_cast(file.GetSize()); + + std::vector source(length); + if (file.Read(&source[0], length) != length) + { + NazaraError("Failed to read program file"); + return {}; + } + + + + Nz::SpirvWriter writer; + + Nz::ByteStream byteStream(source.data(), source.size()); + auto shader = Nz::UnserializeShader(byteStream); + + std::vector result = writer.Generate(shader); + + Nz::File target("test.spirv"); + if (!target.Open(Nz::OpenMode_WriteOnly | Nz::OpenMode_Truncate)) + return __LINE__; + + target.Write(result.data(), result.size() * sizeof(Nz::UInt32)); + + return 0; + } + Nz::Initializer loader; if (!loader) { diff --git a/examples/bin/frag.shader b/examples/bin/frag.shader index bf92becd151cdb94d0caf6505eee679eb663e25e..1fbcce530ddddc3a7d749a622786ce22b08df3f9 100644 GIT binary patch delta 51 ycmaFF@`#1UFW4i9fq{V$h#59=xG;*c0vRm!4GawXffz)C@MK5Eh{<~ymjVC+!3xj- delta 28 hcmaFF@`#1QFW4i9fq{W>BaaK?WKkyHiC1bs6aaEJ2jTz# diff --git a/examples/bin/vert.shader b/examples/bin/vert.shader index 63df1bfb3e72b125fb3222535f8a1ace0f827aa8..b1fa132bbaea340fd46bf5c9b7f93ea34411ff74 100644 GIT binary patch delta 46 zcmdnax}BB7FW4i9fq{W>BFhg(=E;tX;*&)f3nsfT3QR6$5}mw?k!SKI#&wg^nF0VB CN(|uu delta 40 vcmdnax}BB9FW4h!BF7I#mdT8a?TqY`7cz-WUc`75$P=DCgHd#H2a`Sk_~r}l diff --git a/include/Nazara/Renderer/ShaderEnums.hpp b/include/Nazara/Renderer/ShaderEnums.hpp index 6edaad1de..ab9ed4953 100644 --- a/include/Nazara/Renderer/ShaderEnums.hpp +++ b/include/Nazara/Renderer/ShaderEnums.hpp @@ -81,6 +81,15 @@ namespace Nz::ShaderNodes StatementBlock }; + enum class SsaInstruction + { + OpAdd, + OpDiv, + OpMul, + OpSub, + OpSample + }; + enum class SwizzleComponent { First, diff --git a/include/Nazara/Renderer/SpirvWriter.hpp b/include/Nazara/Renderer/SpirvWriter.hpp new file mode 100644 index 000000000..6cc4bb780 --- /dev/null +++ b/include/Nazara/Renderer/SpirvWriter.hpp @@ -0,0 +1,100 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Renderer module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_SPIRVWRITER_HPP +#define NAZARA_SPIRVWRITER_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + class NAZARA_RENDERER_API SpirvWriter : public ShaderVarVisitor, public ShaderVisitor + { + public: + struct Environment; + + SpirvWriter(); + SpirvWriter(const SpirvWriter&) = delete; + SpirvWriter(SpirvWriter&&) = delete; + ~SpirvWriter() = default; + + std::vector Generate(const ShaderAst& shader); + + void SetEnv(Environment environment); + + struct Environment + { + }; + + private: + struct Opcode; + + inline void Append(const char* str); + void Append(const std::string_view& str); + void Append(const Opcode& opcode, unsigned int wordCount); + void Append(UInt32 codepoint); + void Append(std::initializer_list codepoints); + template void Append(Opcode opcode, const Args&... args); + template void Append(T value); + + void AppendHeader(); + + inline unsigned int CountWord(const char* str); + unsigned int CountWord(const std::string_view& str); + template unsigned int CountWord(const T& value); + template unsigned int CountWord(const T1& value, const T2& value2, const Args&... rest); + + using ShaderVarVisitor::Visit; + using ShaderVisitor::Visit; + void Visit(const ShaderNodes::ExpressionPtr& expr, bool encloseIfRequired = false); + void Visit(const ShaderNodes::AccessMember& node) override; + void Visit(const ShaderNodes::AssignOp& node) override; + void Visit(const ShaderNodes::Branch& node) override; + void Visit(const ShaderNodes::BinaryOp& node) override; + void Visit(const ShaderNodes::BuiltinVariable& var) override; + void Visit(const ShaderNodes::Cast& node) override; + void Visit(const ShaderNodes::Constant& node) override; + void Visit(const ShaderNodes::DeclareVariable& node) override; + void Visit(const ShaderNodes::ExpressionStatement& node) override; + void Visit(const ShaderNodes::Identifier& node) override; + void Visit(const ShaderNodes::InputVariable& var) override; + void Visit(const ShaderNodes::IntrinsicCall& node) override; + void Visit(const ShaderNodes::LocalVariable& var) override; + void Visit(const ShaderNodes::ParameterVariable& var) override; + void Visit(const ShaderNodes::OutputVariable& var) override; + void Visit(const ShaderNodes::Sample2D& node) override; + void Visit(const ShaderNodes::StatementBlock& node) override; + void Visit(const ShaderNodes::SwizzleOp& node) override; + void Visit(const ShaderNodes::UniformVariable& var) override; + + struct Context + { + const ShaderAst* shader = nullptr; + const ShaderAst::Function* currentFunction = nullptr; + }; + + struct State + { + std::vector output; + }; + + Context m_context; + Environment m_environment; + State* m_currentState; + }; +} + +#include + +#endif diff --git a/include/Nazara/Renderer/SpirvWriter.inl b/include/Nazara/Renderer/SpirvWriter.inl new file mode 100644 index 000000000..86f578d3d --- /dev/null +++ b/include/Nazara/Renderer/SpirvWriter.inl @@ -0,0 +1,56 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Renderer module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include + +namespace Nz +{ + inline void SpirvWriter::Append(const char* str) + { + return Append(std::string_view(str)); + } + + template + void SpirvWriter::Append(T value) + { + assert(m_currentState); + m_currentState->output.push_back(static_cast(value)); + } + + template + inline void SpirvWriter::Append(Opcode opcode, const Args&... args) + { + unsigned int wordCount = 1 + (CountWord(args) + ... + 0); + Append(opcode, wordCount); + if constexpr (sizeof...(args) > 0) + (Append(args), ...); + } + + template + inline unsigned int SpirvWriter::CountWord(const T& value) + { + return 1; + } + + template + unsigned int SpirvWriter::CountWord(const T1& value, const T2& value2, const Args&... rest) + { + return CountWord(value) + CountWord(value2) + (CountWord(rest) + ...); + } + + inline unsigned int SpirvWriter::CountWord(const char* str) + { + return CountWord(std::string_view(str)); + } + + inline unsigned int SpirvWriter::CountWord(const std::string_view& str) + { + return (str.size() + 1 + 4 - 1) / 4; //< + 1 for null character + } +} + +#include diff --git a/src/Nazara/Renderer/SpirvWriter.cpp b/src/Nazara/Renderer/SpirvWriter.cpp new file mode 100644 index 000000000..863666588 --- /dev/null +++ b/src/Nazara/Renderer/SpirvWriter.cpp @@ -0,0 +1,178 @@ +// Copyright (C) 2015 Jérôme Leclercq +// This file is part of the "Nazara Engine - Renderer module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + struct SpirvWriter::Opcode + { + SpvOp op; + }; + + SpirvWriter::SpirvWriter() : + m_currentState(nullptr) + { + } + + std::vector SpirvWriter::Generate(const ShaderAst& shader) + { + std::string error; + if (!ValidateShader(shader, &error)) + throw std::runtime_error("Invalid shader AST: " + error); + + m_context.shader = &shader; + + State state; + m_currentState = &state; + CallOnExit onExit([this]() + { + m_currentState = nullptr; + }); + + AppendHeader(); + + // OpImageSampleImplicitLod %23 %31 %35 + + //Append("BONJOUR PRAETONUS"); + + std::vector ret = std::move(state.output); + return ret; + } + + void SpirvWriter::SetEnv(Environment environment) + { + m_environment = std::move(environment); + } + + void SpirvWriter::Append(const std::string_view& str) + { + std::size_t size4 = CountWord(str); + for (std::size_t i = 0; i < size4; ++i) + { + auto GetChar = [&](std::size_t pos) -> UInt32 + { + if (pos < str.size()) + return static_cast(str[pos]); + else + return 0; + }; + + UInt32 codepoint = 0; + for (std::size_t j = 0; j < 4; ++j) + codepoint |= GetChar(i * 4 + j) << (j * 8); + + Append(codepoint); + } + } + + void SpirvWriter::Append(const Opcode& opcode, unsigned int wordCount) + { + Append(UInt32(opcode.op) | UInt32(wordCount) << 16); + } + + void SpirvWriter::Append(UInt32 codepoint) + { + assert(m_currentState); + m_currentState->output.push_back(codepoint); + } + + void SpirvWriter::Append(std::initializer_list codepoints) + { + for (UInt32 cp : codepoints) + Append(cp); + } + + void SpirvWriter::AppendHeader() + { + Append(SpvMagicNumber); //< Spir-V magic number + Append(0x00010000); //< Spir-V version number (1.0 for compatibility) + Append(0); //< Generator magic number (TODO: Register generator to Khronos) + Append(1); //< Bound (ID count) + Append(0); //< Instruction schema (required to be 0 for now) + Append(Opcode{ SpvOpCapability }, SpvCapabilityShader); + Append(Opcode{ SpvOpExtInstImport }, 1, "GLSL.std.450"); + Append(Opcode{ SpvOpMemoryModel }, SpvAddressingModelLogical, SpvMemoryModelGLSL450); + + assert(m_context.shader); + switch (m_context.shader->GetStage()) + { + case ShaderStageType::Fragment: + break; + case ShaderStageType::Vertex: + break; + + default: + break; + } + } + + void SpirvWriter::Visit(const ShaderNodes::ExpressionPtr& expr, bool encloseIfRequired) + { + } + void SpirvWriter::Visit(const ShaderNodes::AccessMember& node) + { + } + void SpirvWriter::Visit(const ShaderNodes::AssignOp& node) + { + } + void SpirvWriter::Visit(const ShaderNodes::Branch& node) + { + } + void SpirvWriter::Visit(const ShaderNodes::BinaryOp& node) + { + } + void SpirvWriter::Visit(const ShaderNodes::BuiltinVariable& var) + { + } + void SpirvWriter::Visit(const ShaderNodes::Cast& node) + { + } + void SpirvWriter::Visit(const ShaderNodes::Constant& node) + { + } + void SpirvWriter::Visit(const ShaderNodes::DeclareVariable& node) + { + } + void SpirvWriter::Visit(const ShaderNodes::ExpressionStatement& node) + { + } + void SpirvWriter::Visit(const ShaderNodes::Identifier& node) + { + } + void SpirvWriter::Visit(const ShaderNodes::InputVariable& var) + { + } + void SpirvWriter::Visit(const ShaderNodes::IntrinsicCall& node) + { + } + void SpirvWriter::Visit(const ShaderNodes::LocalVariable& var) + { + } + void SpirvWriter::Visit(const ShaderNodes::ParameterVariable& var) + { + } + void SpirvWriter::Visit(const ShaderNodes::OutputVariable& var) + { + } + void SpirvWriter::Visit(const ShaderNodes::Sample2D& node) + { + } + void SpirvWriter::Visit(const ShaderNodes::StatementBlock& node) + { + } + void SpirvWriter::Visit(const ShaderNodes::SwizzleOp& node) + { + } + void SpirvWriter::Visit(const ShaderNodes::UniformVariable& var) + { + } +} diff --git a/thirdparty/include/SpirV/GLSL.std.450.h b/thirdparty/include/SpirV/GLSL.std.450.h new file mode 100644 index 000000000..54cc00e9a --- /dev/null +++ b/thirdparty/include/SpirV/GLSL.std.450.h @@ -0,0 +1,131 @@ +/* +** Copyright (c) 2014-2016 The Khronos Group Inc. +** +** Permission is hereby granted, free of charge, to any person obtaining a copy +** of this software and/or associated documentation files (the "Materials"), +** to deal in the Materials without restriction, including without limitation +** the rights to use, copy, modify, merge, publish, distribute, sublicense, +** and/or sell copies of the Materials, and to permit persons to whom the +** Materials are furnished to do so, subject to the following conditions: +** +** The above copyright notice and this permission notice shall be included in +** all copies or substantial portions of the Materials. +** +** MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS KHRONOS +** STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS SPECIFICATIONS AND +** HEADER INFORMATION ARE LOCATED AT https://www.khronos.org/registry/ +** +** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +** THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +** FROM,OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE USE OR OTHER DEALINGS +** IN THE MATERIALS. +*/ + +#ifndef GLSLstd450_H +#define GLSLstd450_H + +static const int GLSLstd450Version = 100; +static const int GLSLstd450Revision = 3; + +enum GLSLstd450 { + GLSLstd450Bad = 0, // Don't use + + GLSLstd450Round = 1, + GLSLstd450RoundEven = 2, + GLSLstd450Trunc = 3, + GLSLstd450FAbs = 4, + GLSLstd450SAbs = 5, + GLSLstd450FSign = 6, + GLSLstd450SSign = 7, + GLSLstd450Floor = 8, + GLSLstd450Ceil = 9, + GLSLstd450Fract = 10, + + GLSLstd450Radians = 11, + GLSLstd450Degrees = 12, + GLSLstd450Sin = 13, + GLSLstd450Cos = 14, + GLSLstd450Tan = 15, + GLSLstd450Asin = 16, + GLSLstd450Acos = 17, + GLSLstd450Atan = 18, + GLSLstd450Sinh = 19, + GLSLstd450Cosh = 20, + GLSLstd450Tanh = 21, + GLSLstd450Asinh = 22, + GLSLstd450Acosh = 23, + GLSLstd450Atanh = 24, + GLSLstd450Atan2 = 25, + + GLSLstd450Pow = 26, + GLSLstd450Exp = 27, + GLSLstd450Log = 28, + GLSLstd450Exp2 = 29, + GLSLstd450Log2 = 30, + GLSLstd450Sqrt = 31, + GLSLstd450InverseSqrt = 32, + + GLSLstd450Determinant = 33, + GLSLstd450MatrixInverse = 34, + + GLSLstd450Modf = 35, // second operand needs an OpVariable to write to + GLSLstd450ModfStruct = 36, // no OpVariable operand + GLSLstd450FMin = 37, + GLSLstd450UMin = 38, + GLSLstd450SMin = 39, + GLSLstd450FMax = 40, + GLSLstd450UMax = 41, + GLSLstd450SMax = 42, + GLSLstd450FClamp = 43, + GLSLstd450UClamp = 44, + GLSLstd450SClamp = 45, + GLSLstd450FMix = 46, + GLSLstd450IMix = 47, // Reserved + GLSLstd450Step = 48, + GLSLstd450SmoothStep = 49, + + GLSLstd450Fma = 50, + GLSLstd450Frexp = 51, // second operand needs an OpVariable to write to + GLSLstd450FrexpStruct = 52, // no OpVariable operand + GLSLstd450Ldexp = 53, + + GLSLstd450PackSnorm4x8 = 54, + GLSLstd450PackUnorm4x8 = 55, + GLSLstd450PackSnorm2x16 = 56, + GLSLstd450PackUnorm2x16 = 57, + GLSLstd450PackHalf2x16 = 58, + GLSLstd450PackDouble2x32 = 59, + GLSLstd450UnpackSnorm2x16 = 60, + GLSLstd450UnpackUnorm2x16 = 61, + GLSLstd450UnpackHalf2x16 = 62, + GLSLstd450UnpackSnorm4x8 = 63, + GLSLstd450UnpackUnorm4x8 = 64, + GLSLstd450UnpackDouble2x32 = 65, + + GLSLstd450Length = 66, + GLSLstd450Distance = 67, + GLSLstd450Cross = 68, + GLSLstd450Normalize = 69, + GLSLstd450FaceForward = 70, + GLSLstd450Reflect = 71, + GLSLstd450Refract = 72, + + GLSLstd450FindILsb = 73, + GLSLstd450FindSMsb = 74, + GLSLstd450FindUMsb = 75, + + GLSLstd450InterpolateAtCentroid = 76, + GLSLstd450InterpolateAtSample = 77, + GLSLstd450InterpolateAtOffset = 78, + + GLSLstd450NMin = 79, + GLSLstd450NMax = 80, + GLSLstd450NClamp = 81, + + GLSLstd450Count +}; + +#endif // #ifndef GLSLstd450_H diff --git a/thirdparty/include/SpirV/spirv.h b/thirdparty/include/SpirV/spirv.h new file mode 100644 index 000000000..1e999f27b --- /dev/null +++ b/thirdparty/include/SpirV/spirv.h @@ -0,0 +1,2163 @@ +/* +** Copyright (c) 2014-2020 The Khronos Group Inc. +** +** Permission is hereby granted, free of charge, to any person obtaining a copy +** of this software and/or associated documentation files (the "Materials"), +** to deal in the Materials without restriction, including without limitation +** the rights to use, copy, modify, merge, publish, distribute, sublicense, +** and/or sell copies of the Materials, and to permit persons to whom the +** Materials are furnished to do so, subject to the following conditions: +** +** The above copyright notice and this permission notice shall be included in +** all copies or substantial portions of the Materials. +** +** MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS KHRONOS +** STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS SPECIFICATIONS AND +** HEADER INFORMATION ARE LOCATED AT https://www.khronos.org/registry/ +** +** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +** THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +** FROM,OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE USE OR OTHER DEALINGS +** IN THE MATERIALS. +*/ + +/* +** This header is automatically generated by the same tool that creates +** the Binary Section of the SPIR-V specification. +*/ + +/* +** Enumeration tokens for SPIR-V, in various styles: +** C, C++, C++11, JSON, Lua, Python, C#, D +** +** - C will have tokens with a "Spv" prefix, e.g.: SpvSourceLanguageGLSL +** - C++ will have tokens in the "spv" name space, e.g.: spv::SourceLanguageGLSL +** - C++11 will use enum classes in the spv namespace, e.g.: spv::SourceLanguage::GLSL +** - Lua will use tables, e.g.: spv.SourceLanguage.GLSL +** - Python will use dictionaries, e.g.: spv['SourceLanguage']['GLSL'] +** - C# will use enum classes in the Specification class located in the "Spv" namespace, +** e.g.: Spv.Specification.SourceLanguage.GLSL +** - D will have tokens under the "spv" module, e.g: spv.SourceLanguage.GLSL +** +** Some tokens act like mask values, which can be OR'd together, +** while others are mutually exclusive. The mask-like ones have +** "Mask" in their name, and a parallel enum that has the shift +** amount (1 << x) for each corresponding enumerant. +*/ + +#ifndef spirv_H +#define spirv_H + +typedef unsigned int SpvId; + +#define SPV_VERSION 0x10500 +#define SPV_REVISION 3 + +static const unsigned int SpvMagicNumber = 0x07230203; +static const unsigned int SpvVersion = 0x00010500; +static const unsigned int SpvRevision = 3; +static const unsigned int SpvOpCodeMask = 0xffff; +static const unsigned int SpvWordCountShift = 16; + +typedef enum SpvSourceLanguage_ { + SpvSourceLanguageUnknown = 0, + SpvSourceLanguageESSL = 1, + SpvSourceLanguageGLSL = 2, + SpvSourceLanguageOpenCL_C = 3, + SpvSourceLanguageOpenCL_CPP = 4, + SpvSourceLanguageHLSL = 5, + SpvSourceLanguageMax = 0x7fffffff, +} SpvSourceLanguage; + +typedef enum SpvExecutionModel_ { + SpvExecutionModelVertex = 0, + SpvExecutionModelTessellationControl = 1, + SpvExecutionModelTessellationEvaluation = 2, + SpvExecutionModelGeometry = 3, + SpvExecutionModelFragment = 4, + SpvExecutionModelGLCompute = 5, + SpvExecutionModelKernel = 6, + SpvExecutionModelTaskNV = 5267, + SpvExecutionModelMeshNV = 5268, + SpvExecutionModelRayGenerationKHR = 5313, + SpvExecutionModelRayGenerationNV = 5313, + SpvExecutionModelIntersectionKHR = 5314, + SpvExecutionModelIntersectionNV = 5314, + SpvExecutionModelAnyHitKHR = 5315, + SpvExecutionModelAnyHitNV = 5315, + SpvExecutionModelClosestHitKHR = 5316, + SpvExecutionModelClosestHitNV = 5316, + SpvExecutionModelMissKHR = 5317, + SpvExecutionModelMissNV = 5317, + SpvExecutionModelCallableKHR = 5318, + SpvExecutionModelCallableNV = 5318, + SpvExecutionModelMax = 0x7fffffff, +} SpvExecutionModel; + +typedef enum SpvAddressingModel_ { + SpvAddressingModelLogical = 0, + SpvAddressingModelPhysical32 = 1, + SpvAddressingModelPhysical64 = 2, + SpvAddressingModelPhysicalStorageBuffer64 = 5348, + SpvAddressingModelPhysicalStorageBuffer64EXT = 5348, + SpvAddressingModelMax = 0x7fffffff, +} SpvAddressingModel; + +typedef enum SpvMemoryModel_ { + SpvMemoryModelSimple = 0, + SpvMemoryModelGLSL450 = 1, + SpvMemoryModelOpenCL = 2, + SpvMemoryModelVulkan = 3, + SpvMemoryModelVulkanKHR = 3, + SpvMemoryModelMax = 0x7fffffff, +} SpvMemoryModel; + +typedef enum SpvExecutionMode_ { + SpvExecutionModeInvocations = 0, + SpvExecutionModeSpacingEqual = 1, + SpvExecutionModeSpacingFractionalEven = 2, + SpvExecutionModeSpacingFractionalOdd = 3, + SpvExecutionModeVertexOrderCw = 4, + SpvExecutionModeVertexOrderCcw = 5, + SpvExecutionModePixelCenterInteger = 6, + SpvExecutionModeOriginUpperLeft = 7, + SpvExecutionModeOriginLowerLeft = 8, + SpvExecutionModeEarlyFragmentTests = 9, + SpvExecutionModePointMode = 10, + SpvExecutionModeXfb = 11, + SpvExecutionModeDepthReplacing = 12, + SpvExecutionModeDepthGreater = 14, + SpvExecutionModeDepthLess = 15, + SpvExecutionModeDepthUnchanged = 16, + SpvExecutionModeLocalSize = 17, + SpvExecutionModeLocalSizeHint = 18, + SpvExecutionModeInputPoints = 19, + SpvExecutionModeInputLines = 20, + SpvExecutionModeInputLinesAdjacency = 21, + SpvExecutionModeTriangles = 22, + SpvExecutionModeInputTrianglesAdjacency = 23, + SpvExecutionModeQuads = 24, + SpvExecutionModeIsolines = 25, + SpvExecutionModeOutputVertices = 26, + SpvExecutionModeOutputPoints = 27, + SpvExecutionModeOutputLineStrip = 28, + SpvExecutionModeOutputTriangleStrip = 29, + SpvExecutionModeVecTypeHint = 30, + SpvExecutionModeContractionOff = 31, + SpvExecutionModeInitializer = 33, + SpvExecutionModeFinalizer = 34, + SpvExecutionModeSubgroupSize = 35, + SpvExecutionModeSubgroupsPerWorkgroup = 36, + SpvExecutionModeSubgroupsPerWorkgroupId = 37, + SpvExecutionModeLocalSizeId = 38, + SpvExecutionModeLocalSizeHintId = 39, + SpvExecutionModePostDepthCoverage = 4446, + SpvExecutionModeDenormPreserve = 4459, + SpvExecutionModeDenormFlushToZero = 4460, + SpvExecutionModeSignedZeroInfNanPreserve = 4461, + SpvExecutionModeRoundingModeRTE = 4462, + SpvExecutionModeRoundingModeRTZ = 4463, + SpvExecutionModeStencilRefReplacingEXT = 5027, + SpvExecutionModeOutputLinesNV = 5269, + SpvExecutionModeOutputPrimitivesNV = 5270, + SpvExecutionModeDerivativeGroupQuadsNV = 5289, + SpvExecutionModeDerivativeGroupLinearNV = 5290, + SpvExecutionModeOutputTrianglesNV = 5298, + SpvExecutionModePixelInterlockOrderedEXT = 5366, + SpvExecutionModePixelInterlockUnorderedEXT = 5367, + SpvExecutionModeSampleInterlockOrderedEXT = 5368, + SpvExecutionModeSampleInterlockUnorderedEXT = 5369, + SpvExecutionModeShadingRateInterlockOrderedEXT = 5370, + SpvExecutionModeShadingRateInterlockUnorderedEXT = 5371, + SpvExecutionModeMaxWorkgroupSizeINTEL = 5893, + SpvExecutionModeMaxWorkDimINTEL = 5894, + SpvExecutionModeNoGlobalOffsetINTEL = 5895, + SpvExecutionModeNumSIMDWorkitemsINTEL = 5896, + SpvExecutionModeMax = 0x7fffffff, +} SpvExecutionMode; + +typedef enum SpvStorageClass_ { + SpvStorageClassUniformConstant = 0, + SpvStorageClassInput = 1, + SpvStorageClassUniform = 2, + SpvStorageClassOutput = 3, + SpvStorageClassWorkgroup = 4, + SpvStorageClassCrossWorkgroup = 5, + SpvStorageClassPrivate = 6, + SpvStorageClassFunction = 7, + SpvStorageClassGeneric = 8, + SpvStorageClassPushConstant = 9, + SpvStorageClassAtomicCounter = 10, + SpvStorageClassImage = 11, + SpvStorageClassStorageBuffer = 12, + SpvStorageClassCallableDataKHR = 5328, + SpvStorageClassCallableDataNV = 5328, + SpvStorageClassIncomingCallableDataKHR = 5329, + SpvStorageClassIncomingCallableDataNV = 5329, + SpvStorageClassRayPayloadKHR = 5338, + SpvStorageClassRayPayloadNV = 5338, + SpvStorageClassHitAttributeKHR = 5339, + SpvStorageClassHitAttributeNV = 5339, + SpvStorageClassIncomingRayPayloadKHR = 5342, + SpvStorageClassIncomingRayPayloadNV = 5342, + SpvStorageClassShaderRecordBufferKHR = 5343, + SpvStorageClassShaderRecordBufferNV = 5343, + SpvStorageClassPhysicalStorageBuffer = 5349, + SpvStorageClassPhysicalStorageBufferEXT = 5349, + SpvStorageClassCodeSectionINTEL = 5605, + SpvStorageClassMax = 0x7fffffff, +} SpvStorageClass; + +typedef enum SpvDim_ { + SpvDim1D = 0, + SpvDim2D = 1, + SpvDim3D = 2, + SpvDimCube = 3, + SpvDimRect = 4, + SpvDimBuffer = 5, + SpvDimSubpassData = 6, + SpvDimMax = 0x7fffffff, +} SpvDim; + +typedef enum SpvSamplerAddressingMode_ { + SpvSamplerAddressingModeNone = 0, + SpvSamplerAddressingModeClampToEdge = 1, + SpvSamplerAddressingModeClamp = 2, + SpvSamplerAddressingModeRepeat = 3, + SpvSamplerAddressingModeRepeatMirrored = 4, + SpvSamplerAddressingModeMax = 0x7fffffff, +} SpvSamplerAddressingMode; + +typedef enum SpvSamplerFilterMode_ { + SpvSamplerFilterModeNearest = 0, + SpvSamplerFilterModeLinear = 1, + SpvSamplerFilterModeMax = 0x7fffffff, +} SpvSamplerFilterMode; + +typedef enum SpvImageFormat_ { + SpvImageFormatUnknown = 0, + SpvImageFormatRgba32f = 1, + SpvImageFormatRgba16f = 2, + SpvImageFormatR32f = 3, + SpvImageFormatRgba8 = 4, + SpvImageFormatRgba8Snorm = 5, + SpvImageFormatRg32f = 6, + SpvImageFormatRg16f = 7, + SpvImageFormatR11fG11fB10f = 8, + SpvImageFormatR16f = 9, + SpvImageFormatRgba16 = 10, + SpvImageFormatRgb10A2 = 11, + SpvImageFormatRg16 = 12, + SpvImageFormatRg8 = 13, + SpvImageFormatR16 = 14, + SpvImageFormatR8 = 15, + SpvImageFormatRgba16Snorm = 16, + SpvImageFormatRg16Snorm = 17, + SpvImageFormatRg8Snorm = 18, + SpvImageFormatR16Snorm = 19, + SpvImageFormatR8Snorm = 20, + SpvImageFormatRgba32i = 21, + SpvImageFormatRgba16i = 22, + SpvImageFormatRgba8i = 23, + SpvImageFormatR32i = 24, + SpvImageFormatRg32i = 25, + SpvImageFormatRg16i = 26, + SpvImageFormatRg8i = 27, + SpvImageFormatR16i = 28, + SpvImageFormatR8i = 29, + SpvImageFormatRgba32ui = 30, + SpvImageFormatRgba16ui = 31, + SpvImageFormatRgba8ui = 32, + SpvImageFormatR32ui = 33, + SpvImageFormatRgb10a2ui = 34, + SpvImageFormatRg32ui = 35, + SpvImageFormatRg16ui = 36, + SpvImageFormatRg8ui = 37, + SpvImageFormatR16ui = 38, + SpvImageFormatR8ui = 39, + SpvImageFormatMax = 0x7fffffff, +} SpvImageFormat; + +typedef enum SpvImageChannelOrder_ { + SpvImageChannelOrderR = 0, + SpvImageChannelOrderA = 1, + SpvImageChannelOrderRG = 2, + SpvImageChannelOrderRA = 3, + SpvImageChannelOrderRGB = 4, + SpvImageChannelOrderRGBA = 5, + SpvImageChannelOrderBGRA = 6, + SpvImageChannelOrderARGB = 7, + SpvImageChannelOrderIntensity = 8, + SpvImageChannelOrderLuminance = 9, + SpvImageChannelOrderRx = 10, + SpvImageChannelOrderRGx = 11, + SpvImageChannelOrderRGBx = 12, + SpvImageChannelOrderDepth = 13, + SpvImageChannelOrderDepthStencil = 14, + SpvImageChannelOrdersRGB = 15, + SpvImageChannelOrdersRGBx = 16, + SpvImageChannelOrdersRGBA = 17, + SpvImageChannelOrdersBGRA = 18, + SpvImageChannelOrderABGR = 19, + SpvImageChannelOrderMax = 0x7fffffff, +} SpvImageChannelOrder; + +typedef enum SpvImageChannelDataType_ { + SpvImageChannelDataTypeSnormInt8 = 0, + SpvImageChannelDataTypeSnormInt16 = 1, + SpvImageChannelDataTypeUnormInt8 = 2, + SpvImageChannelDataTypeUnormInt16 = 3, + SpvImageChannelDataTypeUnormShort565 = 4, + SpvImageChannelDataTypeUnormShort555 = 5, + SpvImageChannelDataTypeUnormInt101010 = 6, + SpvImageChannelDataTypeSignedInt8 = 7, + SpvImageChannelDataTypeSignedInt16 = 8, + SpvImageChannelDataTypeSignedInt32 = 9, + SpvImageChannelDataTypeUnsignedInt8 = 10, + SpvImageChannelDataTypeUnsignedInt16 = 11, + SpvImageChannelDataTypeUnsignedInt32 = 12, + SpvImageChannelDataTypeHalfFloat = 13, + SpvImageChannelDataTypeFloat = 14, + SpvImageChannelDataTypeUnormInt24 = 15, + SpvImageChannelDataTypeUnormInt101010_2 = 16, + SpvImageChannelDataTypeMax = 0x7fffffff, +} SpvImageChannelDataType; + +typedef enum SpvImageOperandsShift_ { + SpvImageOperandsBiasShift = 0, + SpvImageOperandsLodShift = 1, + SpvImageOperandsGradShift = 2, + SpvImageOperandsConstOffsetShift = 3, + SpvImageOperandsOffsetShift = 4, + SpvImageOperandsConstOffsetsShift = 5, + SpvImageOperandsSampleShift = 6, + SpvImageOperandsMinLodShift = 7, + SpvImageOperandsMakeTexelAvailableShift = 8, + SpvImageOperandsMakeTexelAvailableKHRShift = 8, + SpvImageOperandsMakeTexelVisibleShift = 9, + SpvImageOperandsMakeTexelVisibleKHRShift = 9, + SpvImageOperandsNonPrivateTexelShift = 10, + SpvImageOperandsNonPrivateTexelKHRShift = 10, + SpvImageOperandsVolatileTexelShift = 11, + SpvImageOperandsVolatileTexelKHRShift = 11, + SpvImageOperandsSignExtendShift = 12, + SpvImageOperandsZeroExtendShift = 13, + SpvImageOperandsMax = 0x7fffffff, +} SpvImageOperandsShift; + +typedef enum SpvImageOperandsMask_ { + SpvImageOperandsMaskNone = 0, + SpvImageOperandsBiasMask = 0x00000001, + SpvImageOperandsLodMask = 0x00000002, + SpvImageOperandsGradMask = 0x00000004, + SpvImageOperandsConstOffsetMask = 0x00000008, + SpvImageOperandsOffsetMask = 0x00000010, + SpvImageOperandsConstOffsetsMask = 0x00000020, + SpvImageOperandsSampleMask = 0x00000040, + SpvImageOperandsMinLodMask = 0x00000080, + SpvImageOperandsMakeTexelAvailableMask = 0x00000100, + SpvImageOperandsMakeTexelAvailableKHRMask = 0x00000100, + SpvImageOperandsMakeTexelVisibleMask = 0x00000200, + SpvImageOperandsMakeTexelVisibleKHRMask = 0x00000200, + SpvImageOperandsNonPrivateTexelMask = 0x00000400, + SpvImageOperandsNonPrivateTexelKHRMask = 0x00000400, + SpvImageOperandsVolatileTexelMask = 0x00000800, + SpvImageOperandsVolatileTexelKHRMask = 0x00000800, + SpvImageOperandsSignExtendMask = 0x00001000, + SpvImageOperandsZeroExtendMask = 0x00002000, +} SpvImageOperandsMask; + +typedef enum SpvFPFastMathModeShift_ { + SpvFPFastMathModeNotNaNShift = 0, + SpvFPFastMathModeNotInfShift = 1, + SpvFPFastMathModeNSZShift = 2, + SpvFPFastMathModeAllowRecipShift = 3, + SpvFPFastMathModeFastShift = 4, + SpvFPFastMathModeMax = 0x7fffffff, +} SpvFPFastMathModeShift; + +typedef enum SpvFPFastMathModeMask_ { + SpvFPFastMathModeMaskNone = 0, + SpvFPFastMathModeNotNaNMask = 0x00000001, + SpvFPFastMathModeNotInfMask = 0x00000002, + SpvFPFastMathModeNSZMask = 0x00000004, + SpvFPFastMathModeAllowRecipMask = 0x00000008, + SpvFPFastMathModeFastMask = 0x00000010, +} SpvFPFastMathModeMask; + +typedef enum SpvFPRoundingMode_ { + SpvFPRoundingModeRTE = 0, + SpvFPRoundingModeRTZ = 1, + SpvFPRoundingModeRTP = 2, + SpvFPRoundingModeRTN = 3, + SpvFPRoundingModeMax = 0x7fffffff, +} SpvFPRoundingMode; + +typedef enum SpvLinkageType_ { + SpvLinkageTypeExport = 0, + SpvLinkageTypeImport = 1, + SpvLinkageTypeMax = 0x7fffffff, +} SpvLinkageType; + +typedef enum SpvAccessQualifier_ { + SpvAccessQualifierReadOnly = 0, + SpvAccessQualifierWriteOnly = 1, + SpvAccessQualifierReadWrite = 2, + SpvAccessQualifierMax = 0x7fffffff, +} SpvAccessQualifier; + +typedef enum SpvFunctionParameterAttribute_ { + SpvFunctionParameterAttributeZext = 0, + SpvFunctionParameterAttributeSext = 1, + SpvFunctionParameterAttributeByVal = 2, + SpvFunctionParameterAttributeSret = 3, + SpvFunctionParameterAttributeNoAlias = 4, + SpvFunctionParameterAttributeNoCapture = 5, + SpvFunctionParameterAttributeNoWrite = 6, + SpvFunctionParameterAttributeNoReadWrite = 7, + SpvFunctionParameterAttributeMax = 0x7fffffff, +} SpvFunctionParameterAttribute; + +typedef enum SpvDecoration_ { + SpvDecorationRelaxedPrecision = 0, + SpvDecorationSpecId = 1, + SpvDecorationBlock = 2, + SpvDecorationBufferBlock = 3, + SpvDecorationRowMajor = 4, + SpvDecorationColMajor = 5, + SpvDecorationArrayStride = 6, + SpvDecorationMatrixStride = 7, + SpvDecorationGLSLShared = 8, + SpvDecorationGLSLPacked = 9, + SpvDecorationCPacked = 10, + SpvDecorationBuiltIn = 11, + SpvDecorationNoPerspective = 13, + SpvDecorationFlat = 14, + SpvDecorationPatch = 15, + SpvDecorationCentroid = 16, + SpvDecorationSample = 17, + SpvDecorationInvariant = 18, + SpvDecorationRestrict = 19, + SpvDecorationAliased = 20, + SpvDecorationVolatile = 21, + SpvDecorationConstant = 22, + SpvDecorationCoherent = 23, + SpvDecorationNonWritable = 24, + SpvDecorationNonReadable = 25, + SpvDecorationUniform = 26, + SpvDecorationUniformId = 27, + SpvDecorationSaturatedConversion = 28, + SpvDecorationStream = 29, + SpvDecorationLocation = 30, + SpvDecorationComponent = 31, + SpvDecorationIndex = 32, + SpvDecorationBinding = 33, + SpvDecorationDescriptorSet = 34, + SpvDecorationOffset = 35, + SpvDecorationXfbBuffer = 36, + SpvDecorationXfbStride = 37, + SpvDecorationFuncParamAttr = 38, + SpvDecorationFPRoundingMode = 39, + SpvDecorationFPFastMathMode = 40, + SpvDecorationLinkageAttributes = 41, + SpvDecorationNoContraction = 42, + SpvDecorationInputAttachmentIndex = 43, + SpvDecorationAlignment = 44, + SpvDecorationMaxByteOffset = 45, + SpvDecorationAlignmentId = 46, + SpvDecorationMaxByteOffsetId = 47, + SpvDecorationNoSignedWrap = 4469, + SpvDecorationNoUnsignedWrap = 4470, + SpvDecorationExplicitInterpAMD = 4999, + SpvDecorationOverrideCoverageNV = 5248, + SpvDecorationPassthroughNV = 5250, + SpvDecorationViewportRelativeNV = 5252, + SpvDecorationSecondaryViewportRelativeNV = 5256, + SpvDecorationPerPrimitiveNV = 5271, + SpvDecorationPerViewNV = 5272, + SpvDecorationPerTaskNV = 5273, + SpvDecorationPerVertexNV = 5285, + SpvDecorationNonUniform = 5300, + SpvDecorationNonUniformEXT = 5300, + SpvDecorationRestrictPointer = 5355, + SpvDecorationRestrictPointerEXT = 5355, + SpvDecorationAliasedPointer = 5356, + SpvDecorationAliasedPointerEXT = 5356, + SpvDecorationReferencedIndirectlyINTEL = 5602, + SpvDecorationCounterBuffer = 5634, + SpvDecorationHlslCounterBufferGOOGLE = 5634, + SpvDecorationHlslSemanticGOOGLE = 5635, + SpvDecorationUserSemantic = 5635, + SpvDecorationUserTypeGOOGLE = 5636, + SpvDecorationRegisterINTEL = 5825, + SpvDecorationMemoryINTEL = 5826, + SpvDecorationNumbanksINTEL = 5827, + SpvDecorationBankwidthINTEL = 5828, + SpvDecorationMaxPrivateCopiesINTEL = 5829, + SpvDecorationSinglepumpINTEL = 5830, + SpvDecorationDoublepumpINTEL = 5831, + SpvDecorationMaxReplicatesINTEL = 5832, + SpvDecorationSimpleDualPortINTEL = 5833, + SpvDecorationMergeINTEL = 5834, + SpvDecorationBankBitsINTEL = 5835, + SpvDecorationForcePow2DepthINTEL = 5836, + SpvDecorationMax = 0x7fffffff, +} SpvDecoration; + +typedef enum SpvBuiltIn_ { + SpvBuiltInPosition = 0, + SpvBuiltInPointSize = 1, + SpvBuiltInClipDistance = 3, + SpvBuiltInCullDistance = 4, + SpvBuiltInVertexId = 5, + SpvBuiltInInstanceId = 6, + SpvBuiltInPrimitiveId = 7, + SpvBuiltInInvocationId = 8, + SpvBuiltInLayer = 9, + SpvBuiltInViewportIndex = 10, + SpvBuiltInTessLevelOuter = 11, + SpvBuiltInTessLevelInner = 12, + SpvBuiltInTessCoord = 13, + SpvBuiltInPatchVertices = 14, + SpvBuiltInFragCoord = 15, + SpvBuiltInPointCoord = 16, + SpvBuiltInFrontFacing = 17, + SpvBuiltInSampleId = 18, + SpvBuiltInSamplePosition = 19, + SpvBuiltInSampleMask = 20, + SpvBuiltInFragDepth = 22, + SpvBuiltInHelperInvocation = 23, + SpvBuiltInNumWorkgroups = 24, + SpvBuiltInWorkgroupSize = 25, + SpvBuiltInWorkgroupId = 26, + SpvBuiltInLocalInvocationId = 27, + SpvBuiltInGlobalInvocationId = 28, + SpvBuiltInLocalInvocationIndex = 29, + SpvBuiltInWorkDim = 30, + SpvBuiltInGlobalSize = 31, + SpvBuiltInEnqueuedWorkgroupSize = 32, + SpvBuiltInGlobalOffset = 33, + SpvBuiltInGlobalLinearId = 34, + SpvBuiltInSubgroupSize = 36, + SpvBuiltInSubgroupMaxSize = 37, + SpvBuiltInNumSubgroups = 38, + SpvBuiltInNumEnqueuedSubgroups = 39, + SpvBuiltInSubgroupId = 40, + SpvBuiltInSubgroupLocalInvocationId = 41, + SpvBuiltInVertexIndex = 42, + SpvBuiltInInstanceIndex = 43, + SpvBuiltInSubgroupEqMask = 4416, + SpvBuiltInSubgroupEqMaskKHR = 4416, + SpvBuiltInSubgroupGeMask = 4417, + SpvBuiltInSubgroupGeMaskKHR = 4417, + SpvBuiltInSubgroupGtMask = 4418, + SpvBuiltInSubgroupGtMaskKHR = 4418, + SpvBuiltInSubgroupLeMask = 4419, + SpvBuiltInSubgroupLeMaskKHR = 4419, + SpvBuiltInSubgroupLtMask = 4420, + SpvBuiltInSubgroupLtMaskKHR = 4420, + SpvBuiltInBaseVertex = 4424, + SpvBuiltInBaseInstance = 4425, + SpvBuiltInDrawIndex = 4426, + SpvBuiltInDeviceIndex = 4438, + SpvBuiltInViewIndex = 4440, + SpvBuiltInBaryCoordNoPerspAMD = 4992, + SpvBuiltInBaryCoordNoPerspCentroidAMD = 4993, + SpvBuiltInBaryCoordNoPerspSampleAMD = 4994, + SpvBuiltInBaryCoordSmoothAMD = 4995, + SpvBuiltInBaryCoordSmoothCentroidAMD = 4996, + SpvBuiltInBaryCoordSmoothSampleAMD = 4997, + SpvBuiltInBaryCoordPullModelAMD = 4998, + SpvBuiltInFragStencilRefEXT = 5014, + SpvBuiltInViewportMaskNV = 5253, + SpvBuiltInSecondaryPositionNV = 5257, + SpvBuiltInSecondaryViewportMaskNV = 5258, + SpvBuiltInPositionPerViewNV = 5261, + SpvBuiltInViewportMaskPerViewNV = 5262, + SpvBuiltInFullyCoveredEXT = 5264, + SpvBuiltInTaskCountNV = 5274, + SpvBuiltInPrimitiveCountNV = 5275, + SpvBuiltInPrimitiveIndicesNV = 5276, + SpvBuiltInClipDistancePerViewNV = 5277, + SpvBuiltInCullDistancePerViewNV = 5278, + SpvBuiltInLayerPerViewNV = 5279, + SpvBuiltInMeshViewCountNV = 5280, + SpvBuiltInMeshViewIndicesNV = 5281, + SpvBuiltInBaryCoordNV = 5286, + SpvBuiltInBaryCoordNoPerspNV = 5287, + SpvBuiltInFragSizeEXT = 5292, + SpvBuiltInFragmentSizeNV = 5292, + SpvBuiltInFragInvocationCountEXT = 5293, + SpvBuiltInInvocationsPerPixelNV = 5293, + SpvBuiltInLaunchIdKHR = 5319, + SpvBuiltInLaunchIdNV = 5319, + SpvBuiltInLaunchSizeKHR = 5320, + SpvBuiltInLaunchSizeNV = 5320, + SpvBuiltInWorldRayOriginKHR = 5321, + SpvBuiltInWorldRayOriginNV = 5321, + SpvBuiltInWorldRayDirectionKHR = 5322, + SpvBuiltInWorldRayDirectionNV = 5322, + SpvBuiltInObjectRayOriginKHR = 5323, + SpvBuiltInObjectRayOriginNV = 5323, + SpvBuiltInObjectRayDirectionKHR = 5324, + SpvBuiltInObjectRayDirectionNV = 5324, + SpvBuiltInRayTminKHR = 5325, + SpvBuiltInRayTminNV = 5325, + SpvBuiltInRayTmaxKHR = 5326, + SpvBuiltInRayTmaxNV = 5326, + SpvBuiltInInstanceCustomIndexKHR = 5327, + SpvBuiltInInstanceCustomIndexNV = 5327, + SpvBuiltInObjectToWorldKHR = 5330, + SpvBuiltInObjectToWorldNV = 5330, + SpvBuiltInWorldToObjectKHR = 5331, + SpvBuiltInWorldToObjectNV = 5331, + SpvBuiltInHitTKHR = 5332, + SpvBuiltInHitTNV = 5332, + SpvBuiltInHitKindKHR = 5333, + SpvBuiltInHitKindNV = 5333, + SpvBuiltInIncomingRayFlagsKHR = 5351, + SpvBuiltInIncomingRayFlagsNV = 5351, + SpvBuiltInRayGeometryIndexKHR = 5352, + SpvBuiltInWarpsPerSMNV = 5374, + SpvBuiltInSMCountNV = 5375, + SpvBuiltInWarpIDNV = 5376, + SpvBuiltInSMIDNV = 5377, + SpvBuiltInMax = 0x7fffffff, +} SpvBuiltIn; + +typedef enum SpvSelectionControlShift_ { + SpvSelectionControlFlattenShift = 0, + SpvSelectionControlDontFlattenShift = 1, + SpvSelectionControlMax = 0x7fffffff, +} SpvSelectionControlShift; + +typedef enum SpvSelectionControlMask_ { + SpvSelectionControlMaskNone = 0, + SpvSelectionControlFlattenMask = 0x00000001, + SpvSelectionControlDontFlattenMask = 0x00000002, +} SpvSelectionControlMask; + +typedef enum SpvLoopControlShift_ { + SpvLoopControlUnrollShift = 0, + SpvLoopControlDontUnrollShift = 1, + SpvLoopControlDependencyInfiniteShift = 2, + SpvLoopControlDependencyLengthShift = 3, + SpvLoopControlMinIterationsShift = 4, + SpvLoopControlMaxIterationsShift = 5, + SpvLoopControlIterationMultipleShift = 6, + SpvLoopControlPeelCountShift = 7, + SpvLoopControlPartialCountShift = 8, + SpvLoopControlInitiationIntervalINTELShift = 16, + SpvLoopControlMaxConcurrencyINTELShift = 17, + SpvLoopControlDependencyArrayINTELShift = 18, + SpvLoopControlPipelineEnableINTELShift = 19, + SpvLoopControlLoopCoalesceINTELShift = 20, + SpvLoopControlMaxInterleavingINTELShift = 21, + SpvLoopControlSpeculatedIterationsINTELShift = 22, + SpvLoopControlMax = 0x7fffffff, +} SpvLoopControlShift; + +typedef enum SpvLoopControlMask_ { + SpvLoopControlMaskNone = 0, + SpvLoopControlUnrollMask = 0x00000001, + SpvLoopControlDontUnrollMask = 0x00000002, + SpvLoopControlDependencyInfiniteMask = 0x00000004, + SpvLoopControlDependencyLengthMask = 0x00000008, + SpvLoopControlMinIterationsMask = 0x00000010, + SpvLoopControlMaxIterationsMask = 0x00000020, + SpvLoopControlIterationMultipleMask = 0x00000040, + SpvLoopControlPeelCountMask = 0x00000080, + SpvLoopControlPartialCountMask = 0x00000100, + SpvLoopControlInitiationIntervalINTELMask = 0x00010000, + SpvLoopControlMaxConcurrencyINTELMask = 0x00020000, + SpvLoopControlDependencyArrayINTELMask = 0x00040000, + SpvLoopControlPipelineEnableINTELMask = 0x00080000, + SpvLoopControlLoopCoalesceINTELMask = 0x00100000, + SpvLoopControlMaxInterleavingINTELMask = 0x00200000, + SpvLoopControlSpeculatedIterationsINTELMask = 0x00400000, +} SpvLoopControlMask; + +typedef enum SpvFunctionControlShift_ { + SpvFunctionControlInlineShift = 0, + SpvFunctionControlDontInlineShift = 1, + SpvFunctionControlPureShift = 2, + SpvFunctionControlConstShift = 3, + SpvFunctionControlMax = 0x7fffffff, +} SpvFunctionControlShift; + +typedef enum SpvFunctionControlMask_ { + SpvFunctionControlMaskNone = 0, + SpvFunctionControlInlineMask = 0x00000001, + SpvFunctionControlDontInlineMask = 0x00000002, + SpvFunctionControlPureMask = 0x00000004, + SpvFunctionControlConstMask = 0x00000008, +} SpvFunctionControlMask; + +typedef enum SpvMemorySemanticsShift_ { + SpvMemorySemanticsAcquireShift = 1, + SpvMemorySemanticsReleaseShift = 2, + SpvMemorySemanticsAcquireReleaseShift = 3, + SpvMemorySemanticsSequentiallyConsistentShift = 4, + SpvMemorySemanticsUniformMemoryShift = 6, + SpvMemorySemanticsSubgroupMemoryShift = 7, + SpvMemorySemanticsWorkgroupMemoryShift = 8, + SpvMemorySemanticsCrossWorkgroupMemoryShift = 9, + SpvMemorySemanticsAtomicCounterMemoryShift = 10, + SpvMemorySemanticsImageMemoryShift = 11, + SpvMemorySemanticsOutputMemoryShift = 12, + SpvMemorySemanticsOutputMemoryKHRShift = 12, + SpvMemorySemanticsMakeAvailableShift = 13, + SpvMemorySemanticsMakeAvailableKHRShift = 13, + SpvMemorySemanticsMakeVisibleShift = 14, + SpvMemorySemanticsMakeVisibleKHRShift = 14, + SpvMemorySemanticsVolatileShift = 15, + SpvMemorySemanticsMax = 0x7fffffff, +} SpvMemorySemanticsShift; + +typedef enum SpvMemorySemanticsMask_ { + SpvMemorySemanticsMaskNone = 0, + SpvMemorySemanticsAcquireMask = 0x00000002, + SpvMemorySemanticsReleaseMask = 0x00000004, + SpvMemorySemanticsAcquireReleaseMask = 0x00000008, + SpvMemorySemanticsSequentiallyConsistentMask = 0x00000010, + SpvMemorySemanticsUniformMemoryMask = 0x00000040, + SpvMemorySemanticsSubgroupMemoryMask = 0x00000080, + SpvMemorySemanticsWorkgroupMemoryMask = 0x00000100, + SpvMemorySemanticsCrossWorkgroupMemoryMask = 0x00000200, + SpvMemorySemanticsAtomicCounterMemoryMask = 0x00000400, + SpvMemorySemanticsImageMemoryMask = 0x00000800, + SpvMemorySemanticsOutputMemoryMask = 0x00001000, + SpvMemorySemanticsOutputMemoryKHRMask = 0x00001000, + SpvMemorySemanticsMakeAvailableMask = 0x00002000, + SpvMemorySemanticsMakeAvailableKHRMask = 0x00002000, + SpvMemorySemanticsMakeVisibleMask = 0x00004000, + SpvMemorySemanticsMakeVisibleKHRMask = 0x00004000, + SpvMemorySemanticsVolatileMask = 0x00008000, +} SpvMemorySemanticsMask; + +typedef enum SpvMemoryAccessShift_ { + SpvMemoryAccessVolatileShift = 0, + SpvMemoryAccessAlignedShift = 1, + SpvMemoryAccessNontemporalShift = 2, + SpvMemoryAccessMakePointerAvailableShift = 3, + SpvMemoryAccessMakePointerAvailableKHRShift = 3, + SpvMemoryAccessMakePointerVisibleShift = 4, + SpvMemoryAccessMakePointerVisibleKHRShift = 4, + SpvMemoryAccessNonPrivatePointerShift = 5, + SpvMemoryAccessNonPrivatePointerKHRShift = 5, + SpvMemoryAccessMax = 0x7fffffff, +} SpvMemoryAccessShift; + +typedef enum SpvMemoryAccessMask_ { + SpvMemoryAccessMaskNone = 0, + SpvMemoryAccessVolatileMask = 0x00000001, + SpvMemoryAccessAlignedMask = 0x00000002, + SpvMemoryAccessNontemporalMask = 0x00000004, + SpvMemoryAccessMakePointerAvailableMask = 0x00000008, + SpvMemoryAccessMakePointerAvailableKHRMask = 0x00000008, + SpvMemoryAccessMakePointerVisibleMask = 0x00000010, + SpvMemoryAccessMakePointerVisibleKHRMask = 0x00000010, + SpvMemoryAccessNonPrivatePointerMask = 0x00000020, + SpvMemoryAccessNonPrivatePointerKHRMask = 0x00000020, +} SpvMemoryAccessMask; + +typedef enum SpvScope_ { + SpvScopeCrossDevice = 0, + SpvScopeDevice = 1, + SpvScopeWorkgroup = 2, + SpvScopeSubgroup = 3, + SpvScopeInvocation = 4, + SpvScopeQueueFamily = 5, + SpvScopeQueueFamilyKHR = 5, + SpvScopeShaderCallKHR = 6, + SpvScopeMax = 0x7fffffff, +} SpvScope; + +typedef enum SpvGroupOperation_ { + SpvGroupOperationReduce = 0, + SpvGroupOperationInclusiveScan = 1, + SpvGroupOperationExclusiveScan = 2, + SpvGroupOperationClusteredReduce = 3, + SpvGroupOperationPartitionedReduceNV = 6, + SpvGroupOperationPartitionedInclusiveScanNV = 7, + SpvGroupOperationPartitionedExclusiveScanNV = 8, + SpvGroupOperationMax = 0x7fffffff, +} SpvGroupOperation; + +typedef enum SpvKernelEnqueueFlags_ { + SpvKernelEnqueueFlagsNoWait = 0, + SpvKernelEnqueueFlagsWaitKernel = 1, + SpvKernelEnqueueFlagsWaitWorkGroup = 2, + SpvKernelEnqueueFlagsMax = 0x7fffffff, +} SpvKernelEnqueueFlags; + +typedef enum SpvKernelProfilingInfoShift_ { + SpvKernelProfilingInfoCmdExecTimeShift = 0, + SpvKernelProfilingInfoMax = 0x7fffffff, +} SpvKernelProfilingInfoShift; + +typedef enum SpvKernelProfilingInfoMask_ { + SpvKernelProfilingInfoMaskNone = 0, + SpvKernelProfilingInfoCmdExecTimeMask = 0x00000001, +} SpvKernelProfilingInfoMask; + +typedef enum SpvCapability_ { + SpvCapabilityMatrix = 0, + SpvCapabilityShader = 1, + SpvCapabilityGeometry = 2, + SpvCapabilityTessellation = 3, + SpvCapabilityAddresses = 4, + SpvCapabilityLinkage = 5, + SpvCapabilityKernel = 6, + SpvCapabilityVector16 = 7, + SpvCapabilityFloat16Buffer = 8, + SpvCapabilityFloat16 = 9, + SpvCapabilityFloat64 = 10, + SpvCapabilityInt64 = 11, + SpvCapabilityInt64Atomics = 12, + SpvCapabilityImageBasic = 13, + SpvCapabilityImageReadWrite = 14, + SpvCapabilityImageMipmap = 15, + SpvCapabilityPipes = 17, + SpvCapabilityGroups = 18, + SpvCapabilityDeviceEnqueue = 19, + SpvCapabilityLiteralSampler = 20, + SpvCapabilityAtomicStorage = 21, + SpvCapabilityInt16 = 22, + SpvCapabilityTessellationPointSize = 23, + SpvCapabilityGeometryPointSize = 24, + SpvCapabilityImageGatherExtended = 25, + SpvCapabilityStorageImageMultisample = 27, + SpvCapabilityUniformBufferArrayDynamicIndexing = 28, + SpvCapabilitySampledImageArrayDynamicIndexing = 29, + SpvCapabilityStorageBufferArrayDynamicIndexing = 30, + SpvCapabilityStorageImageArrayDynamicIndexing = 31, + SpvCapabilityClipDistance = 32, + SpvCapabilityCullDistance = 33, + SpvCapabilityImageCubeArray = 34, + SpvCapabilitySampleRateShading = 35, + SpvCapabilityImageRect = 36, + SpvCapabilitySampledRect = 37, + SpvCapabilityGenericPointer = 38, + SpvCapabilityInt8 = 39, + SpvCapabilityInputAttachment = 40, + SpvCapabilitySparseResidency = 41, + SpvCapabilityMinLod = 42, + SpvCapabilitySampled1D = 43, + SpvCapabilityImage1D = 44, + SpvCapabilitySampledCubeArray = 45, + SpvCapabilitySampledBuffer = 46, + SpvCapabilityImageBuffer = 47, + SpvCapabilityImageMSArray = 48, + SpvCapabilityStorageImageExtendedFormats = 49, + SpvCapabilityImageQuery = 50, + SpvCapabilityDerivativeControl = 51, + SpvCapabilityInterpolationFunction = 52, + SpvCapabilityTransformFeedback = 53, + SpvCapabilityGeometryStreams = 54, + SpvCapabilityStorageImageReadWithoutFormat = 55, + SpvCapabilityStorageImageWriteWithoutFormat = 56, + SpvCapabilityMultiViewport = 57, + SpvCapabilitySubgroupDispatch = 58, + SpvCapabilityNamedBarrier = 59, + SpvCapabilityPipeStorage = 60, + SpvCapabilityGroupNonUniform = 61, + SpvCapabilityGroupNonUniformVote = 62, + SpvCapabilityGroupNonUniformArithmetic = 63, + SpvCapabilityGroupNonUniformBallot = 64, + SpvCapabilityGroupNonUniformShuffle = 65, + SpvCapabilityGroupNonUniformShuffleRelative = 66, + SpvCapabilityGroupNonUniformClustered = 67, + SpvCapabilityGroupNonUniformQuad = 68, + SpvCapabilityShaderLayer = 69, + SpvCapabilityShaderViewportIndex = 70, + SpvCapabilitySubgroupBallotKHR = 4423, + SpvCapabilityDrawParameters = 4427, + SpvCapabilitySubgroupVoteKHR = 4431, + SpvCapabilityStorageBuffer16BitAccess = 4433, + SpvCapabilityStorageUniformBufferBlock16 = 4433, + SpvCapabilityStorageUniform16 = 4434, + SpvCapabilityUniformAndStorageBuffer16BitAccess = 4434, + SpvCapabilityStoragePushConstant16 = 4435, + SpvCapabilityStorageInputOutput16 = 4436, + SpvCapabilityDeviceGroup = 4437, + SpvCapabilityMultiView = 4439, + SpvCapabilityVariablePointersStorageBuffer = 4441, + SpvCapabilityVariablePointers = 4442, + SpvCapabilityAtomicStorageOps = 4445, + SpvCapabilitySampleMaskPostDepthCoverage = 4447, + SpvCapabilityStorageBuffer8BitAccess = 4448, + SpvCapabilityUniformAndStorageBuffer8BitAccess = 4449, + SpvCapabilityStoragePushConstant8 = 4450, + SpvCapabilityDenormPreserve = 4464, + SpvCapabilityDenormFlushToZero = 4465, + SpvCapabilitySignedZeroInfNanPreserve = 4466, + SpvCapabilityRoundingModeRTE = 4467, + SpvCapabilityRoundingModeRTZ = 4468, + SpvCapabilityRayQueryProvisionalKHR = 4471, + SpvCapabilityRayTraversalPrimitiveCullingProvisionalKHR = 4478, + SpvCapabilityFloat16ImageAMD = 5008, + SpvCapabilityImageGatherBiasLodAMD = 5009, + SpvCapabilityFragmentMaskAMD = 5010, + SpvCapabilityStencilExportEXT = 5013, + SpvCapabilityImageReadWriteLodAMD = 5015, + SpvCapabilityShaderClockKHR = 5055, + SpvCapabilitySampleMaskOverrideCoverageNV = 5249, + SpvCapabilityGeometryShaderPassthroughNV = 5251, + SpvCapabilityShaderViewportIndexLayerEXT = 5254, + SpvCapabilityShaderViewportIndexLayerNV = 5254, + SpvCapabilityShaderViewportMaskNV = 5255, + SpvCapabilityShaderStereoViewNV = 5259, + SpvCapabilityPerViewAttributesNV = 5260, + SpvCapabilityFragmentFullyCoveredEXT = 5265, + SpvCapabilityMeshShadingNV = 5266, + SpvCapabilityImageFootprintNV = 5282, + SpvCapabilityFragmentBarycentricNV = 5284, + SpvCapabilityComputeDerivativeGroupQuadsNV = 5288, + SpvCapabilityFragmentDensityEXT = 5291, + SpvCapabilityShadingRateNV = 5291, + SpvCapabilityGroupNonUniformPartitionedNV = 5297, + SpvCapabilityShaderNonUniform = 5301, + SpvCapabilityShaderNonUniformEXT = 5301, + SpvCapabilityRuntimeDescriptorArray = 5302, + SpvCapabilityRuntimeDescriptorArrayEXT = 5302, + SpvCapabilityInputAttachmentArrayDynamicIndexing = 5303, + SpvCapabilityInputAttachmentArrayDynamicIndexingEXT = 5303, + SpvCapabilityUniformTexelBufferArrayDynamicIndexing = 5304, + SpvCapabilityUniformTexelBufferArrayDynamicIndexingEXT = 5304, + SpvCapabilityStorageTexelBufferArrayDynamicIndexing = 5305, + SpvCapabilityStorageTexelBufferArrayDynamicIndexingEXT = 5305, + SpvCapabilityUniformBufferArrayNonUniformIndexing = 5306, + SpvCapabilityUniformBufferArrayNonUniformIndexingEXT = 5306, + SpvCapabilitySampledImageArrayNonUniformIndexing = 5307, + SpvCapabilitySampledImageArrayNonUniformIndexingEXT = 5307, + SpvCapabilityStorageBufferArrayNonUniformIndexing = 5308, + SpvCapabilityStorageBufferArrayNonUniformIndexingEXT = 5308, + SpvCapabilityStorageImageArrayNonUniformIndexing = 5309, + SpvCapabilityStorageImageArrayNonUniformIndexingEXT = 5309, + SpvCapabilityInputAttachmentArrayNonUniformIndexing = 5310, + SpvCapabilityInputAttachmentArrayNonUniformIndexingEXT = 5310, + SpvCapabilityUniformTexelBufferArrayNonUniformIndexing = 5311, + SpvCapabilityUniformTexelBufferArrayNonUniformIndexingEXT = 5311, + SpvCapabilityStorageTexelBufferArrayNonUniformIndexing = 5312, + SpvCapabilityStorageTexelBufferArrayNonUniformIndexingEXT = 5312, + SpvCapabilityRayTracingNV = 5340, + SpvCapabilityVulkanMemoryModel = 5345, + SpvCapabilityVulkanMemoryModelKHR = 5345, + SpvCapabilityVulkanMemoryModelDeviceScope = 5346, + SpvCapabilityVulkanMemoryModelDeviceScopeKHR = 5346, + SpvCapabilityPhysicalStorageBufferAddresses = 5347, + SpvCapabilityPhysicalStorageBufferAddressesEXT = 5347, + SpvCapabilityComputeDerivativeGroupLinearNV = 5350, + SpvCapabilityRayTracingProvisionalKHR = 5353, + SpvCapabilityCooperativeMatrixNV = 5357, + SpvCapabilityFragmentShaderSampleInterlockEXT = 5363, + SpvCapabilityFragmentShaderShadingRateInterlockEXT = 5372, + SpvCapabilityShaderSMBuiltinsNV = 5373, + SpvCapabilityFragmentShaderPixelInterlockEXT = 5378, + SpvCapabilityDemoteToHelperInvocationEXT = 5379, + SpvCapabilitySubgroupShuffleINTEL = 5568, + SpvCapabilitySubgroupBufferBlockIOINTEL = 5569, + SpvCapabilitySubgroupImageBlockIOINTEL = 5570, + SpvCapabilitySubgroupImageMediaBlockIOINTEL = 5579, + SpvCapabilityIntegerFunctions2INTEL = 5584, + SpvCapabilityFunctionPointersINTEL = 5603, + SpvCapabilityIndirectReferencesINTEL = 5604, + SpvCapabilitySubgroupAvcMotionEstimationINTEL = 5696, + SpvCapabilitySubgroupAvcMotionEstimationIntraINTEL = 5697, + SpvCapabilitySubgroupAvcMotionEstimationChromaINTEL = 5698, + SpvCapabilityFPGAMemoryAttributesINTEL = 5824, + SpvCapabilityUnstructuredLoopControlsINTEL = 5886, + SpvCapabilityFPGALoopControlsINTEL = 5888, + SpvCapabilityKernelAttributesINTEL = 5892, + SpvCapabilityFPGAKernelAttributesINTEL = 5897, + SpvCapabilityBlockingPipesINTEL = 5945, + SpvCapabilityFPGARegINTEL = 5948, + SpvCapabilityAtomicFloat32AddEXT = 6033, + SpvCapabilityAtomicFloat64AddEXT = 6034, + SpvCapabilityMax = 0x7fffffff, +} SpvCapability; + +typedef enum SpvRayFlagsShift_ { + SpvRayFlagsOpaqueKHRShift = 0, + SpvRayFlagsNoOpaqueKHRShift = 1, + SpvRayFlagsTerminateOnFirstHitKHRShift = 2, + SpvRayFlagsSkipClosestHitShaderKHRShift = 3, + SpvRayFlagsCullBackFacingTrianglesKHRShift = 4, + SpvRayFlagsCullFrontFacingTrianglesKHRShift = 5, + SpvRayFlagsCullOpaqueKHRShift = 6, + SpvRayFlagsCullNoOpaqueKHRShift = 7, + SpvRayFlagsSkipTrianglesKHRShift = 8, + SpvRayFlagsSkipAABBsKHRShift = 9, + SpvRayFlagsMax = 0x7fffffff, +} SpvRayFlagsShift; + +typedef enum SpvRayFlagsMask_ { + SpvRayFlagsMaskNone = 0, + SpvRayFlagsOpaqueKHRMask = 0x00000001, + SpvRayFlagsNoOpaqueKHRMask = 0x00000002, + SpvRayFlagsTerminateOnFirstHitKHRMask = 0x00000004, + SpvRayFlagsSkipClosestHitShaderKHRMask = 0x00000008, + SpvRayFlagsCullBackFacingTrianglesKHRMask = 0x00000010, + SpvRayFlagsCullFrontFacingTrianglesKHRMask = 0x00000020, + SpvRayFlagsCullOpaqueKHRMask = 0x00000040, + SpvRayFlagsCullNoOpaqueKHRMask = 0x00000080, + SpvRayFlagsSkipTrianglesKHRMask = 0x00000100, + SpvRayFlagsSkipAABBsKHRMask = 0x00000200, +} SpvRayFlagsMask; + +typedef enum SpvRayQueryIntersection_ { + SpvRayQueryIntersectionRayQueryCandidateIntersectionKHR = 0, + SpvRayQueryIntersectionRayQueryCommittedIntersectionKHR = 1, + SpvRayQueryIntersectionMax = 0x7fffffff, +} SpvRayQueryIntersection; + +typedef enum SpvRayQueryCommittedIntersectionType_ { + SpvRayQueryCommittedIntersectionTypeRayQueryCommittedIntersectionNoneKHR = 0, + SpvRayQueryCommittedIntersectionTypeRayQueryCommittedIntersectionTriangleKHR = 1, + SpvRayQueryCommittedIntersectionTypeRayQueryCommittedIntersectionGeneratedKHR = 2, + SpvRayQueryCommittedIntersectionTypeMax = 0x7fffffff, +} SpvRayQueryCommittedIntersectionType; + +typedef enum SpvRayQueryCandidateIntersectionType_ { + SpvRayQueryCandidateIntersectionTypeRayQueryCandidateIntersectionTriangleKHR = 0, + SpvRayQueryCandidateIntersectionTypeRayQueryCandidateIntersectionAABBKHR = 1, + SpvRayQueryCandidateIntersectionTypeMax = 0x7fffffff, +} SpvRayQueryCandidateIntersectionType; + +typedef enum SpvOp_ { + SpvOpNop = 0, + SpvOpUndef = 1, + SpvOpSourceContinued = 2, + SpvOpSource = 3, + SpvOpSourceExtension = 4, + SpvOpName = 5, + SpvOpMemberName = 6, + SpvOpString = 7, + SpvOpLine = 8, + SpvOpExtension = 10, + SpvOpExtInstImport = 11, + SpvOpExtInst = 12, + SpvOpMemoryModel = 14, + SpvOpEntryPoint = 15, + SpvOpExecutionMode = 16, + SpvOpCapability = 17, + SpvOpTypeVoid = 19, + SpvOpTypeBool = 20, + SpvOpTypeInt = 21, + SpvOpTypeFloat = 22, + SpvOpTypeVector = 23, + SpvOpTypeMatrix = 24, + SpvOpTypeImage = 25, + SpvOpTypeSampler = 26, + SpvOpTypeSampledImage = 27, + SpvOpTypeArray = 28, + SpvOpTypeRuntimeArray = 29, + SpvOpTypeStruct = 30, + SpvOpTypeOpaque = 31, + SpvOpTypePointer = 32, + SpvOpTypeFunction = 33, + SpvOpTypeEvent = 34, + SpvOpTypeDeviceEvent = 35, + SpvOpTypeReserveId = 36, + SpvOpTypeQueue = 37, + SpvOpTypePipe = 38, + SpvOpTypeForwardPointer = 39, + SpvOpConstantTrue = 41, + SpvOpConstantFalse = 42, + SpvOpConstant = 43, + SpvOpConstantComposite = 44, + SpvOpConstantSampler = 45, + SpvOpConstantNull = 46, + SpvOpSpecConstantTrue = 48, + SpvOpSpecConstantFalse = 49, + SpvOpSpecConstant = 50, + SpvOpSpecConstantComposite = 51, + SpvOpSpecConstantOp = 52, + SpvOpFunction = 54, + SpvOpFunctionParameter = 55, + SpvOpFunctionEnd = 56, + SpvOpFunctionCall = 57, + SpvOpVariable = 59, + SpvOpImageTexelPointer = 60, + SpvOpLoad = 61, + SpvOpStore = 62, + SpvOpCopyMemory = 63, + SpvOpCopyMemorySized = 64, + SpvOpAccessChain = 65, + SpvOpInBoundsAccessChain = 66, + SpvOpPtrAccessChain = 67, + SpvOpArrayLength = 68, + SpvOpGenericPtrMemSemantics = 69, + SpvOpInBoundsPtrAccessChain = 70, + SpvOpDecorate = 71, + SpvOpMemberDecorate = 72, + SpvOpDecorationGroup = 73, + SpvOpGroupDecorate = 74, + SpvOpGroupMemberDecorate = 75, + SpvOpVectorExtractDynamic = 77, + SpvOpVectorInsertDynamic = 78, + SpvOpVectorShuffle = 79, + SpvOpCompositeConstruct = 80, + SpvOpCompositeExtract = 81, + SpvOpCompositeInsert = 82, + SpvOpCopyObject = 83, + SpvOpTranspose = 84, + SpvOpSampledImage = 86, + SpvOpImageSampleImplicitLod = 87, + SpvOpImageSampleExplicitLod = 88, + SpvOpImageSampleDrefImplicitLod = 89, + SpvOpImageSampleDrefExplicitLod = 90, + SpvOpImageSampleProjImplicitLod = 91, + SpvOpImageSampleProjExplicitLod = 92, + SpvOpImageSampleProjDrefImplicitLod = 93, + SpvOpImageSampleProjDrefExplicitLod = 94, + SpvOpImageFetch = 95, + SpvOpImageGather = 96, + SpvOpImageDrefGather = 97, + SpvOpImageRead = 98, + SpvOpImageWrite = 99, + SpvOpImage = 100, + SpvOpImageQueryFormat = 101, + SpvOpImageQueryOrder = 102, + SpvOpImageQuerySizeLod = 103, + SpvOpImageQuerySize = 104, + SpvOpImageQueryLod = 105, + SpvOpImageQueryLevels = 106, + SpvOpImageQuerySamples = 107, + SpvOpConvertFToU = 109, + SpvOpConvertFToS = 110, + SpvOpConvertSToF = 111, + SpvOpConvertUToF = 112, + SpvOpUConvert = 113, + SpvOpSConvert = 114, + SpvOpFConvert = 115, + SpvOpQuantizeToF16 = 116, + SpvOpConvertPtrToU = 117, + SpvOpSatConvertSToU = 118, + SpvOpSatConvertUToS = 119, + SpvOpConvertUToPtr = 120, + SpvOpPtrCastToGeneric = 121, + SpvOpGenericCastToPtr = 122, + SpvOpGenericCastToPtrExplicit = 123, + SpvOpBitcast = 124, + SpvOpSNegate = 126, + SpvOpFNegate = 127, + SpvOpIAdd = 128, + SpvOpFAdd = 129, + SpvOpISub = 130, + SpvOpFSub = 131, + SpvOpIMul = 132, + SpvOpFMul = 133, + SpvOpUDiv = 134, + SpvOpSDiv = 135, + SpvOpFDiv = 136, + SpvOpUMod = 137, + SpvOpSRem = 138, + SpvOpSMod = 139, + SpvOpFRem = 140, + SpvOpFMod = 141, + SpvOpVectorTimesScalar = 142, + SpvOpMatrixTimesScalar = 143, + SpvOpVectorTimesMatrix = 144, + SpvOpMatrixTimesVector = 145, + SpvOpMatrixTimesMatrix = 146, + SpvOpOuterProduct = 147, + SpvOpDot = 148, + SpvOpIAddCarry = 149, + SpvOpISubBorrow = 150, + SpvOpUMulExtended = 151, + SpvOpSMulExtended = 152, + SpvOpAny = 154, + SpvOpAll = 155, + SpvOpIsNan = 156, + SpvOpIsInf = 157, + SpvOpIsFinite = 158, + SpvOpIsNormal = 159, + SpvOpSignBitSet = 160, + SpvOpLessOrGreater = 161, + SpvOpOrdered = 162, + SpvOpUnordered = 163, + SpvOpLogicalEqual = 164, + SpvOpLogicalNotEqual = 165, + SpvOpLogicalOr = 166, + SpvOpLogicalAnd = 167, + SpvOpLogicalNot = 168, + SpvOpSelect = 169, + SpvOpIEqual = 170, + SpvOpINotEqual = 171, + SpvOpUGreaterThan = 172, + SpvOpSGreaterThan = 173, + SpvOpUGreaterThanEqual = 174, + SpvOpSGreaterThanEqual = 175, + SpvOpULessThan = 176, + SpvOpSLessThan = 177, + SpvOpULessThanEqual = 178, + SpvOpSLessThanEqual = 179, + SpvOpFOrdEqual = 180, + SpvOpFUnordEqual = 181, + SpvOpFOrdNotEqual = 182, + SpvOpFUnordNotEqual = 183, + SpvOpFOrdLessThan = 184, + SpvOpFUnordLessThan = 185, + SpvOpFOrdGreaterThan = 186, + SpvOpFUnordGreaterThan = 187, + SpvOpFOrdLessThanEqual = 188, + SpvOpFUnordLessThanEqual = 189, + SpvOpFOrdGreaterThanEqual = 190, + SpvOpFUnordGreaterThanEqual = 191, + SpvOpShiftRightLogical = 194, + SpvOpShiftRightArithmetic = 195, + SpvOpShiftLeftLogical = 196, + SpvOpBitwiseOr = 197, + SpvOpBitwiseXor = 198, + SpvOpBitwiseAnd = 199, + SpvOpNot = 200, + SpvOpBitFieldInsert = 201, + SpvOpBitFieldSExtract = 202, + SpvOpBitFieldUExtract = 203, + SpvOpBitReverse = 204, + SpvOpBitCount = 205, + SpvOpDPdx = 207, + SpvOpDPdy = 208, + SpvOpFwidth = 209, + SpvOpDPdxFine = 210, + SpvOpDPdyFine = 211, + SpvOpFwidthFine = 212, + SpvOpDPdxCoarse = 213, + SpvOpDPdyCoarse = 214, + SpvOpFwidthCoarse = 215, + SpvOpEmitVertex = 218, + SpvOpEndPrimitive = 219, + SpvOpEmitStreamVertex = 220, + SpvOpEndStreamPrimitive = 221, + SpvOpControlBarrier = 224, + SpvOpMemoryBarrier = 225, + SpvOpAtomicLoad = 227, + SpvOpAtomicStore = 228, + SpvOpAtomicExchange = 229, + SpvOpAtomicCompareExchange = 230, + SpvOpAtomicCompareExchangeWeak = 231, + SpvOpAtomicIIncrement = 232, + SpvOpAtomicIDecrement = 233, + SpvOpAtomicIAdd = 234, + SpvOpAtomicISub = 235, + SpvOpAtomicSMin = 236, + SpvOpAtomicUMin = 237, + SpvOpAtomicSMax = 238, + SpvOpAtomicUMax = 239, + SpvOpAtomicAnd = 240, + SpvOpAtomicOr = 241, + SpvOpAtomicXor = 242, + SpvOpPhi = 245, + SpvOpLoopMerge = 246, + SpvOpSelectionMerge = 247, + SpvOpLabel = 248, + SpvOpBranch = 249, + SpvOpBranchConditional = 250, + SpvOpSwitch = 251, + SpvOpKill = 252, + SpvOpReturn = 253, + SpvOpReturnValue = 254, + SpvOpUnreachable = 255, + SpvOpLifetimeStart = 256, + SpvOpLifetimeStop = 257, + SpvOpGroupAsyncCopy = 259, + SpvOpGroupWaitEvents = 260, + SpvOpGroupAll = 261, + SpvOpGroupAny = 262, + SpvOpGroupBroadcast = 263, + SpvOpGroupIAdd = 264, + SpvOpGroupFAdd = 265, + SpvOpGroupFMin = 266, + SpvOpGroupUMin = 267, + SpvOpGroupSMin = 268, + SpvOpGroupFMax = 269, + SpvOpGroupUMax = 270, + SpvOpGroupSMax = 271, + SpvOpReadPipe = 274, + SpvOpWritePipe = 275, + SpvOpReservedReadPipe = 276, + SpvOpReservedWritePipe = 277, + SpvOpReserveReadPipePackets = 278, + SpvOpReserveWritePipePackets = 279, + SpvOpCommitReadPipe = 280, + SpvOpCommitWritePipe = 281, + SpvOpIsValidReserveId = 282, + SpvOpGetNumPipePackets = 283, + SpvOpGetMaxPipePackets = 284, + SpvOpGroupReserveReadPipePackets = 285, + SpvOpGroupReserveWritePipePackets = 286, + SpvOpGroupCommitReadPipe = 287, + SpvOpGroupCommitWritePipe = 288, + SpvOpEnqueueMarker = 291, + SpvOpEnqueueKernel = 292, + SpvOpGetKernelNDrangeSubGroupCount = 293, + SpvOpGetKernelNDrangeMaxSubGroupSize = 294, + SpvOpGetKernelWorkGroupSize = 295, + SpvOpGetKernelPreferredWorkGroupSizeMultiple = 296, + SpvOpRetainEvent = 297, + SpvOpReleaseEvent = 298, + SpvOpCreateUserEvent = 299, + SpvOpIsValidEvent = 300, + SpvOpSetUserEventStatus = 301, + SpvOpCaptureEventProfilingInfo = 302, + SpvOpGetDefaultQueue = 303, + SpvOpBuildNDRange = 304, + SpvOpImageSparseSampleImplicitLod = 305, + SpvOpImageSparseSampleExplicitLod = 306, + SpvOpImageSparseSampleDrefImplicitLod = 307, + SpvOpImageSparseSampleDrefExplicitLod = 308, + SpvOpImageSparseSampleProjImplicitLod = 309, + SpvOpImageSparseSampleProjExplicitLod = 310, + SpvOpImageSparseSampleProjDrefImplicitLod = 311, + SpvOpImageSparseSampleProjDrefExplicitLod = 312, + SpvOpImageSparseFetch = 313, + SpvOpImageSparseGather = 314, + SpvOpImageSparseDrefGather = 315, + SpvOpImageSparseTexelsResident = 316, + SpvOpNoLine = 317, + SpvOpAtomicFlagTestAndSet = 318, + SpvOpAtomicFlagClear = 319, + SpvOpImageSparseRead = 320, + SpvOpSizeOf = 321, + SpvOpTypePipeStorage = 322, + SpvOpConstantPipeStorage = 323, + SpvOpCreatePipeFromPipeStorage = 324, + SpvOpGetKernelLocalSizeForSubgroupCount = 325, + SpvOpGetKernelMaxNumSubgroups = 326, + SpvOpTypeNamedBarrier = 327, + SpvOpNamedBarrierInitialize = 328, + SpvOpMemoryNamedBarrier = 329, + SpvOpModuleProcessed = 330, + SpvOpExecutionModeId = 331, + SpvOpDecorateId = 332, + SpvOpGroupNonUniformElect = 333, + SpvOpGroupNonUniformAll = 334, + SpvOpGroupNonUniformAny = 335, + SpvOpGroupNonUniformAllEqual = 336, + SpvOpGroupNonUniformBroadcast = 337, + SpvOpGroupNonUniformBroadcastFirst = 338, + SpvOpGroupNonUniformBallot = 339, + SpvOpGroupNonUniformInverseBallot = 340, + SpvOpGroupNonUniformBallotBitExtract = 341, + SpvOpGroupNonUniformBallotBitCount = 342, + SpvOpGroupNonUniformBallotFindLSB = 343, + SpvOpGroupNonUniformBallotFindMSB = 344, + SpvOpGroupNonUniformShuffle = 345, + SpvOpGroupNonUniformShuffleXor = 346, + SpvOpGroupNonUniformShuffleUp = 347, + SpvOpGroupNonUniformShuffleDown = 348, + SpvOpGroupNonUniformIAdd = 349, + SpvOpGroupNonUniformFAdd = 350, + SpvOpGroupNonUniformIMul = 351, + SpvOpGroupNonUniformFMul = 352, + SpvOpGroupNonUniformSMin = 353, + SpvOpGroupNonUniformUMin = 354, + SpvOpGroupNonUniformFMin = 355, + SpvOpGroupNonUniformSMax = 356, + SpvOpGroupNonUniformUMax = 357, + SpvOpGroupNonUniformFMax = 358, + SpvOpGroupNonUniformBitwiseAnd = 359, + SpvOpGroupNonUniformBitwiseOr = 360, + SpvOpGroupNonUniformBitwiseXor = 361, + SpvOpGroupNonUniformLogicalAnd = 362, + SpvOpGroupNonUniformLogicalOr = 363, + SpvOpGroupNonUniformLogicalXor = 364, + SpvOpGroupNonUniformQuadBroadcast = 365, + SpvOpGroupNonUniformQuadSwap = 366, + SpvOpCopyLogical = 400, + SpvOpPtrEqual = 401, + SpvOpPtrNotEqual = 402, + SpvOpPtrDiff = 403, + SpvOpTerminateInvocation = 4416, + SpvOpSubgroupBallotKHR = 4421, + SpvOpSubgroupFirstInvocationKHR = 4422, + SpvOpSubgroupAllKHR = 4428, + SpvOpSubgroupAnyKHR = 4429, + SpvOpSubgroupAllEqualKHR = 4430, + SpvOpSubgroupReadInvocationKHR = 4432, + SpvOpTypeRayQueryProvisionalKHR = 4472, + SpvOpRayQueryInitializeKHR = 4473, + SpvOpRayQueryTerminateKHR = 4474, + SpvOpRayQueryGenerateIntersectionKHR = 4475, + SpvOpRayQueryConfirmIntersectionKHR = 4476, + SpvOpRayQueryProceedKHR = 4477, + SpvOpRayQueryGetIntersectionTypeKHR = 4479, + SpvOpGroupIAddNonUniformAMD = 5000, + SpvOpGroupFAddNonUniformAMD = 5001, + SpvOpGroupFMinNonUniformAMD = 5002, + SpvOpGroupUMinNonUniformAMD = 5003, + SpvOpGroupSMinNonUniformAMD = 5004, + SpvOpGroupFMaxNonUniformAMD = 5005, + SpvOpGroupUMaxNonUniformAMD = 5006, + SpvOpGroupSMaxNonUniformAMD = 5007, + SpvOpFragmentMaskFetchAMD = 5011, + SpvOpFragmentFetchAMD = 5012, + SpvOpReadClockKHR = 5056, + SpvOpImageSampleFootprintNV = 5283, + SpvOpGroupNonUniformPartitionNV = 5296, + SpvOpWritePackedPrimitiveIndices4x8NV = 5299, + SpvOpReportIntersectionKHR = 5334, + SpvOpReportIntersectionNV = 5334, + SpvOpIgnoreIntersectionKHR = 5335, + SpvOpIgnoreIntersectionNV = 5335, + SpvOpTerminateRayKHR = 5336, + SpvOpTerminateRayNV = 5336, + SpvOpTraceNV = 5337, + SpvOpTraceRayKHR = 5337, + SpvOpTypeAccelerationStructureKHR = 5341, + SpvOpTypeAccelerationStructureNV = 5341, + SpvOpExecuteCallableKHR = 5344, + SpvOpExecuteCallableNV = 5344, + SpvOpTypeCooperativeMatrixNV = 5358, + SpvOpCooperativeMatrixLoadNV = 5359, + SpvOpCooperativeMatrixStoreNV = 5360, + SpvOpCooperativeMatrixMulAddNV = 5361, + SpvOpCooperativeMatrixLengthNV = 5362, + SpvOpBeginInvocationInterlockEXT = 5364, + SpvOpEndInvocationInterlockEXT = 5365, + SpvOpDemoteToHelperInvocationEXT = 5380, + SpvOpIsHelperInvocationEXT = 5381, + SpvOpSubgroupShuffleINTEL = 5571, + SpvOpSubgroupShuffleDownINTEL = 5572, + SpvOpSubgroupShuffleUpINTEL = 5573, + SpvOpSubgroupShuffleXorINTEL = 5574, + SpvOpSubgroupBlockReadINTEL = 5575, + SpvOpSubgroupBlockWriteINTEL = 5576, + SpvOpSubgroupImageBlockReadINTEL = 5577, + SpvOpSubgroupImageBlockWriteINTEL = 5578, + SpvOpSubgroupImageMediaBlockReadINTEL = 5580, + SpvOpSubgroupImageMediaBlockWriteINTEL = 5581, + SpvOpUCountLeadingZerosINTEL = 5585, + SpvOpUCountTrailingZerosINTEL = 5586, + SpvOpAbsISubINTEL = 5587, + SpvOpAbsUSubINTEL = 5588, + SpvOpIAddSatINTEL = 5589, + SpvOpUAddSatINTEL = 5590, + SpvOpIAverageINTEL = 5591, + SpvOpUAverageINTEL = 5592, + SpvOpIAverageRoundedINTEL = 5593, + SpvOpUAverageRoundedINTEL = 5594, + SpvOpISubSatINTEL = 5595, + SpvOpUSubSatINTEL = 5596, + SpvOpIMul32x16INTEL = 5597, + SpvOpUMul32x16INTEL = 5598, + SpvOpFunctionPointerINTEL = 5600, + SpvOpFunctionPointerCallINTEL = 5601, + SpvOpDecorateString = 5632, + SpvOpDecorateStringGOOGLE = 5632, + SpvOpMemberDecorateString = 5633, + SpvOpMemberDecorateStringGOOGLE = 5633, + SpvOpVmeImageINTEL = 5699, + SpvOpTypeVmeImageINTEL = 5700, + SpvOpTypeAvcImePayloadINTEL = 5701, + SpvOpTypeAvcRefPayloadINTEL = 5702, + SpvOpTypeAvcSicPayloadINTEL = 5703, + SpvOpTypeAvcMcePayloadINTEL = 5704, + SpvOpTypeAvcMceResultINTEL = 5705, + SpvOpTypeAvcImeResultINTEL = 5706, + SpvOpTypeAvcImeResultSingleReferenceStreamoutINTEL = 5707, + SpvOpTypeAvcImeResultDualReferenceStreamoutINTEL = 5708, + SpvOpTypeAvcImeSingleReferenceStreaminINTEL = 5709, + SpvOpTypeAvcImeDualReferenceStreaminINTEL = 5710, + SpvOpTypeAvcRefResultINTEL = 5711, + SpvOpTypeAvcSicResultINTEL = 5712, + SpvOpSubgroupAvcMceGetDefaultInterBaseMultiReferencePenaltyINTEL = 5713, + SpvOpSubgroupAvcMceSetInterBaseMultiReferencePenaltyINTEL = 5714, + SpvOpSubgroupAvcMceGetDefaultInterShapePenaltyINTEL = 5715, + SpvOpSubgroupAvcMceSetInterShapePenaltyINTEL = 5716, + SpvOpSubgroupAvcMceGetDefaultInterDirectionPenaltyINTEL = 5717, + SpvOpSubgroupAvcMceSetInterDirectionPenaltyINTEL = 5718, + SpvOpSubgroupAvcMceGetDefaultIntraLumaShapePenaltyINTEL = 5719, + SpvOpSubgroupAvcMceGetDefaultInterMotionVectorCostTableINTEL = 5720, + SpvOpSubgroupAvcMceGetDefaultHighPenaltyCostTableINTEL = 5721, + SpvOpSubgroupAvcMceGetDefaultMediumPenaltyCostTableINTEL = 5722, + SpvOpSubgroupAvcMceGetDefaultLowPenaltyCostTableINTEL = 5723, + SpvOpSubgroupAvcMceSetMotionVectorCostFunctionINTEL = 5724, + SpvOpSubgroupAvcMceGetDefaultIntraLumaModePenaltyINTEL = 5725, + SpvOpSubgroupAvcMceGetDefaultNonDcLumaIntraPenaltyINTEL = 5726, + SpvOpSubgroupAvcMceGetDefaultIntraChromaModeBasePenaltyINTEL = 5727, + SpvOpSubgroupAvcMceSetAcOnlyHaarINTEL = 5728, + SpvOpSubgroupAvcMceSetSourceInterlacedFieldPolarityINTEL = 5729, + SpvOpSubgroupAvcMceSetSingleReferenceInterlacedFieldPolarityINTEL = 5730, + SpvOpSubgroupAvcMceSetDualReferenceInterlacedFieldPolaritiesINTEL = 5731, + SpvOpSubgroupAvcMceConvertToImePayloadINTEL = 5732, + SpvOpSubgroupAvcMceConvertToImeResultINTEL = 5733, + SpvOpSubgroupAvcMceConvertToRefPayloadINTEL = 5734, + SpvOpSubgroupAvcMceConvertToRefResultINTEL = 5735, + SpvOpSubgroupAvcMceConvertToSicPayloadINTEL = 5736, + SpvOpSubgroupAvcMceConvertToSicResultINTEL = 5737, + SpvOpSubgroupAvcMceGetMotionVectorsINTEL = 5738, + SpvOpSubgroupAvcMceGetInterDistortionsINTEL = 5739, + SpvOpSubgroupAvcMceGetBestInterDistortionsINTEL = 5740, + SpvOpSubgroupAvcMceGetInterMajorShapeINTEL = 5741, + SpvOpSubgroupAvcMceGetInterMinorShapeINTEL = 5742, + SpvOpSubgroupAvcMceGetInterDirectionsINTEL = 5743, + SpvOpSubgroupAvcMceGetInterMotionVectorCountINTEL = 5744, + SpvOpSubgroupAvcMceGetInterReferenceIdsINTEL = 5745, + SpvOpSubgroupAvcMceGetInterReferenceInterlacedFieldPolaritiesINTEL = 5746, + SpvOpSubgroupAvcImeInitializeINTEL = 5747, + SpvOpSubgroupAvcImeSetSingleReferenceINTEL = 5748, + SpvOpSubgroupAvcImeSetDualReferenceINTEL = 5749, + SpvOpSubgroupAvcImeRefWindowSizeINTEL = 5750, + SpvOpSubgroupAvcImeAdjustRefOffsetINTEL = 5751, + SpvOpSubgroupAvcImeConvertToMcePayloadINTEL = 5752, + SpvOpSubgroupAvcImeSetMaxMotionVectorCountINTEL = 5753, + SpvOpSubgroupAvcImeSetUnidirectionalMixDisableINTEL = 5754, + SpvOpSubgroupAvcImeSetEarlySearchTerminationThresholdINTEL = 5755, + SpvOpSubgroupAvcImeSetWeightedSadINTEL = 5756, + SpvOpSubgroupAvcImeEvaluateWithSingleReferenceINTEL = 5757, + SpvOpSubgroupAvcImeEvaluateWithDualReferenceINTEL = 5758, + SpvOpSubgroupAvcImeEvaluateWithSingleReferenceStreaminINTEL = 5759, + SpvOpSubgroupAvcImeEvaluateWithDualReferenceStreaminINTEL = 5760, + SpvOpSubgroupAvcImeEvaluateWithSingleReferenceStreamoutINTEL = 5761, + SpvOpSubgroupAvcImeEvaluateWithDualReferenceStreamoutINTEL = 5762, + SpvOpSubgroupAvcImeEvaluateWithSingleReferenceStreaminoutINTEL = 5763, + SpvOpSubgroupAvcImeEvaluateWithDualReferenceStreaminoutINTEL = 5764, + SpvOpSubgroupAvcImeConvertToMceResultINTEL = 5765, + SpvOpSubgroupAvcImeGetSingleReferenceStreaminINTEL = 5766, + SpvOpSubgroupAvcImeGetDualReferenceStreaminINTEL = 5767, + SpvOpSubgroupAvcImeStripSingleReferenceStreamoutINTEL = 5768, + SpvOpSubgroupAvcImeStripDualReferenceStreamoutINTEL = 5769, + SpvOpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeMotionVectorsINTEL = 5770, + SpvOpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeDistortionsINTEL = 5771, + SpvOpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeReferenceIdsINTEL = 5772, + SpvOpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeMotionVectorsINTEL = 5773, + SpvOpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeDistortionsINTEL = 5774, + SpvOpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeReferenceIdsINTEL = 5775, + SpvOpSubgroupAvcImeGetBorderReachedINTEL = 5776, + SpvOpSubgroupAvcImeGetTruncatedSearchIndicationINTEL = 5777, + SpvOpSubgroupAvcImeGetUnidirectionalEarlySearchTerminationINTEL = 5778, + SpvOpSubgroupAvcImeGetWeightingPatternMinimumMotionVectorINTEL = 5779, + SpvOpSubgroupAvcImeGetWeightingPatternMinimumDistortionINTEL = 5780, + SpvOpSubgroupAvcFmeInitializeINTEL = 5781, + SpvOpSubgroupAvcBmeInitializeINTEL = 5782, + SpvOpSubgroupAvcRefConvertToMcePayloadINTEL = 5783, + SpvOpSubgroupAvcRefSetBidirectionalMixDisableINTEL = 5784, + SpvOpSubgroupAvcRefSetBilinearFilterEnableINTEL = 5785, + SpvOpSubgroupAvcRefEvaluateWithSingleReferenceINTEL = 5786, + SpvOpSubgroupAvcRefEvaluateWithDualReferenceINTEL = 5787, + SpvOpSubgroupAvcRefEvaluateWithMultiReferenceINTEL = 5788, + SpvOpSubgroupAvcRefEvaluateWithMultiReferenceInterlacedINTEL = 5789, + SpvOpSubgroupAvcRefConvertToMceResultINTEL = 5790, + SpvOpSubgroupAvcSicInitializeINTEL = 5791, + SpvOpSubgroupAvcSicConfigureSkcINTEL = 5792, + SpvOpSubgroupAvcSicConfigureIpeLumaINTEL = 5793, + SpvOpSubgroupAvcSicConfigureIpeLumaChromaINTEL = 5794, + SpvOpSubgroupAvcSicGetMotionVectorMaskINTEL = 5795, + SpvOpSubgroupAvcSicConvertToMcePayloadINTEL = 5796, + SpvOpSubgroupAvcSicSetIntraLumaShapePenaltyINTEL = 5797, + SpvOpSubgroupAvcSicSetIntraLumaModeCostFunctionINTEL = 5798, + SpvOpSubgroupAvcSicSetIntraChromaModeCostFunctionINTEL = 5799, + SpvOpSubgroupAvcSicSetBilinearFilterEnableINTEL = 5800, + SpvOpSubgroupAvcSicSetSkcForwardTransformEnableINTEL = 5801, + SpvOpSubgroupAvcSicSetBlockBasedRawSkipSadINTEL = 5802, + SpvOpSubgroupAvcSicEvaluateIpeINTEL = 5803, + SpvOpSubgroupAvcSicEvaluateWithSingleReferenceINTEL = 5804, + SpvOpSubgroupAvcSicEvaluateWithDualReferenceINTEL = 5805, + SpvOpSubgroupAvcSicEvaluateWithMultiReferenceINTEL = 5806, + SpvOpSubgroupAvcSicEvaluateWithMultiReferenceInterlacedINTEL = 5807, + SpvOpSubgroupAvcSicConvertToMceResultINTEL = 5808, + SpvOpSubgroupAvcSicGetIpeLumaShapeINTEL = 5809, + SpvOpSubgroupAvcSicGetBestIpeLumaDistortionINTEL = 5810, + SpvOpSubgroupAvcSicGetBestIpeChromaDistortionINTEL = 5811, + SpvOpSubgroupAvcSicGetPackedIpeLumaModesINTEL = 5812, + SpvOpSubgroupAvcSicGetIpeChromaModeINTEL = 5813, + SpvOpSubgroupAvcSicGetPackedSkcLumaCountThresholdINTEL = 5814, + SpvOpSubgroupAvcSicGetPackedSkcLumaSumThresholdINTEL = 5815, + SpvOpSubgroupAvcSicGetInterRawSadsINTEL = 5816, + SpvOpLoopControlINTEL = 5887, + SpvOpReadPipeBlockingINTEL = 5946, + SpvOpWritePipeBlockingINTEL = 5947, + SpvOpFPGARegINTEL = 5949, + SpvOpRayQueryGetRayTMinKHR = 6016, + SpvOpRayQueryGetRayFlagsKHR = 6017, + SpvOpRayQueryGetIntersectionTKHR = 6018, + SpvOpRayQueryGetIntersectionInstanceCustomIndexKHR = 6019, + SpvOpRayQueryGetIntersectionInstanceIdKHR = 6020, + SpvOpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffsetKHR = 6021, + SpvOpRayQueryGetIntersectionGeometryIndexKHR = 6022, + SpvOpRayQueryGetIntersectionPrimitiveIndexKHR = 6023, + SpvOpRayQueryGetIntersectionBarycentricsKHR = 6024, + SpvOpRayQueryGetIntersectionFrontFaceKHR = 6025, + SpvOpRayQueryGetIntersectionCandidateAABBOpaqueKHR = 6026, + SpvOpRayQueryGetIntersectionObjectRayDirectionKHR = 6027, + SpvOpRayQueryGetIntersectionObjectRayOriginKHR = 6028, + SpvOpRayQueryGetWorldRayDirectionKHR = 6029, + SpvOpRayQueryGetWorldRayOriginKHR = 6030, + SpvOpRayQueryGetIntersectionObjectToWorldKHR = 6031, + SpvOpRayQueryGetIntersectionWorldToObjectKHR = 6032, + SpvOpAtomicFAddEXT = 6035, + SpvOpMax = 0x7fffffff, +} SpvOp; + +#ifdef SPV_ENABLE_UTILITY_CODE +inline void SpvHasResultAndType(SpvOp opcode, bool *hasResult, bool *hasResultType) { + *hasResult = *hasResultType = false; + switch (opcode) { + default: /* unknown opcode */ break; + case SpvOpNop: *hasResult = false; *hasResultType = false; break; + case SpvOpUndef: *hasResult = true; *hasResultType = true; break; + case SpvOpSourceContinued: *hasResult = false; *hasResultType = false; break; + case SpvOpSource: *hasResult = false; *hasResultType = false; break; + case SpvOpSourceExtension: *hasResult = false; *hasResultType = false; break; + case SpvOpName: *hasResult = false; *hasResultType = false; break; + case SpvOpMemberName: *hasResult = false; *hasResultType = false; break; + case SpvOpString: *hasResult = true; *hasResultType = false; break; + case SpvOpLine: *hasResult = false; *hasResultType = false; break; + case SpvOpExtension: *hasResult = false; *hasResultType = false; break; + case SpvOpExtInstImport: *hasResult = true; *hasResultType = false; break; + case SpvOpExtInst: *hasResult = true; *hasResultType = true; break; + case SpvOpMemoryModel: *hasResult = false; *hasResultType = false; break; + case SpvOpEntryPoint: *hasResult = false; *hasResultType = false; break; + case SpvOpExecutionMode: *hasResult = false; *hasResultType = false; break; + case SpvOpCapability: *hasResult = false; *hasResultType = false; break; + case SpvOpTypeVoid: *hasResult = true; *hasResultType = false; break; + case SpvOpTypeBool: *hasResult = true; *hasResultType = false; break; + case SpvOpTypeInt: *hasResult = true; *hasResultType = false; break; + case SpvOpTypeFloat: *hasResult = true; *hasResultType = false; break; + case SpvOpTypeVector: *hasResult = true; *hasResultType = false; break; + case SpvOpTypeMatrix: *hasResult = true; *hasResultType = false; break; + case SpvOpTypeImage: *hasResult = true; *hasResultType = false; break; + case SpvOpTypeSampler: *hasResult = true; *hasResultType = false; break; + case SpvOpTypeSampledImage: *hasResult = true; *hasResultType = false; break; + case SpvOpTypeArray: *hasResult = true; *hasResultType = false; break; + case SpvOpTypeRuntimeArray: *hasResult = true; *hasResultType = false; break; + case SpvOpTypeStruct: *hasResult = true; *hasResultType = false; break; + case SpvOpTypeOpaque: *hasResult = true; *hasResultType = false; break; + case SpvOpTypePointer: *hasResult = true; *hasResultType = false; break; + case SpvOpTypeFunction: *hasResult = true; *hasResultType = false; break; + case SpvOpTypeEvent: *hasResult = true; *hasResultType = false; break; + case SpvOpTypeDeviceEvent: *hasResult = true; *hasResultType = false; break; + case SpvOpTypeReserveId: *hasResult = true; *hasResultType = false; break; + case SpvOpTypeQueue: *hasResult = true; *hasResultType = false; break; + case SpvOpTypePipe: *hasResult = true; *hasResultType = false; break; + case SpvOpTypeForwardPointer: *hasResult = false; *hasResultType = false; break; + case SpvOpConstantTrue: *hasResult = true; *hasResultType = true; break; + case SpvOpConstantFalse: *hasResult = true; *hasResultType = true; break; + case SpvOpConstant: *hasResult = true; *hasResultType = true; break; + case SpvOpConstantComposite: *hasResult = true; *hasResultType = true; break; + case SpvOpConstantSampler: *hasResult = true; *hasResultType = true; break; + case SpvOpConstantNull: *hasResult = true; *hasResultType = true; break; + case SpvOpSpecConstantTrue: *hasResult = true; *hasResultType = true; break; + case SpvOpSpecConstantFalse: *hasResult = true; *hasResultType = true; break; + case SpvOpSpecConstant: *hasResult = true; *hasResultType = true; break; + case SpvOpSpecConstantComposite: *hasResult = true; *hasResultType = true; break; + case SpvOpSpecConstantOp: *hasResult = true; *hasResultType = true; break; + case SpvOpFunction: *hasResult = true; *hasResultType = true; break; + case SpvOpFunctionParameter: *hasResult = true; *hasResultType = true; break; + case SpvOpFunctionEnd: *hasResult = false; *hasResultType = false; break; + case SpvOpFunctionCall: *hasResult = true; *hasResultType = true; break; + case SpvOpVariable: *hasResult = true; *hasResultType = true; break; + case SpvOpImageTexelPointer: *hasResult = true; *hasResultType = true; break; + case SpvOpLoad: *hasResult = true; *hasResultType = true; break; + case SpvOpStore: *hasResult = false; *hasResultType = false; break; + case SpvOpCopyMemory: *hasResult = false; *hasResultType = false; break; + case SpvOpCopyMemorySized: *hasResult = false; *hasResultType = false; break; + case SpvOpAccessChain: *hasResult = true; *hasResultType = true; break; + case SpvOpInBoundsAccessChain: *hasResult = true; *hasResultType = true; break; + case SpvOpPtrAccessChain: *hasResult = true; *hasResultType = true; break; + case SpvOpArrayLength: *hasResult = true; *hasResultType = true; break; + case SpvOpGenericPtrMemSemantics: *hasResult = true; *hasResultType = true; break; + case SpvOpInBoundsPtrAccessChain: *hasResult = true; *hasResultType = true; break; + case SpvOpDecorate: *hasResult = false; *hasResultType = false; break; + case SpvOpMemberDecorate: *hasResult = false; *hasResultType = false; break; + case SpvOpDecorationGroup: *hasResult = true; *hasResultType = false; break; + case SpvOpGroupDecorate: *hasResult = false; *hasResultType = false; break; + case SpvOpGroupMemberDecorate: *hasResult = false; *hasResultType = false; break; + case SpvOpVectorExtractDynamic: *hasResult = true; *hasResultType = true; break; + case SpvOpVectorInsertDynamic: *hasResult = true; *hasResultType = true; break; + case SpvOpVectorShuffle: *hasResult = true; *hasResultType = true; break; + case SpvOpCompositeConstruct: *hasResult = true; *hasResultType = true; break; + case SpvOpCompositeExtract: *hasResult = true; *hasResultType = true; break; + case SpvOpCompositeInsert: *hasResult = true; *hasResultType = true; break; + case SpvOpCopyObject: *hasResult = true; *hasResultType = true; break; + case SpvOpTranspose: *hasResult = true; *hasResultType = true; break; + case SpvOpSampledImage: *hasResult = true; *hasResultType = true; break; + case SpvOpImageSampleImplicitLod: *hasResult = true; *hasResultType = true; break; + case SpvOpImageSampleExplicitLod: *hasResult = true; *hasResultType = true; break; + case SpvOpImageSampleDrefImplicitLod: *hasResult = true; *hasResultType = true; break; + case SpvOpImageSampleDrefExplicitLod: *hasResult = true; *hasResultType = true; break; + case SpvOpImageSampleProjImplicitLod: *hasResult = true; *hasResultType = true; break; + case SpvOpImageSampleProjExplicitLod: *hasResult = true; *hasResultType = true; break; + case SpvOpImageSampleProjDrefImplicitLod: *hasResult = true; *hasResultType = true; break; + case SpvOpImageSampleProjDrefExplicitLod: *hasResult = true; *hasResultType = true; break; + case SpvOpImageFetch: *hasResult = true; *hasResultType = true; break; + case SpvOpImageGather: *hasResult = true; *hasResultType = true; break; + case SpvOpImageDrefGather: *hasResult = true; *hasResultType = true; break; + case SpvOpImageRead: *hasResult = true; *hasResultType = true; break; + case SpvOpImageWrite: *hasResult = false; *hasResultType = false; break; + case SpvOpImage: *hasResult = true; *hasResultType = true; break; + case SpvOpImageQueryFormat: *hasResult = true; *hasResultType = true; break; + case SpvOpImageQueryOrder: *hasResult = true; *hasResultType = true; break; + case SpvOpImageQuerySizeLod: *hasResult = true; *hasResultType = true; break; + case SpvOpImageQuerySize: *hasResult = true; *hasResultType = true; break; + case SpvOpImageQueryLod: *hasResult = true; *hasResultType = true; break; + case SpvOpImageQueryLevels: *hasResult = true; *hasResultType = true; break; + case SpvOpImageQuerySamples: *hasResult = true; *hasResultType = true; break; + case SpvOpConvertFToU: *hasResult = true; *hasResultType = true; break; + case SpvOpConvertFToS: *hasResult = true; *hasResultType = true; break; + case SpvOpConvertSToF: *hasResult = true; *hasResultType = true; break; + case SpvOpConvertUToF: *hasResult = true; *hasResultType = true; break; + case SpvOpUConvert: *hasResult = true; *hasResultType = true; break; + case SpvOpSConvert: *hasResult = true; *hasResultType = true; break; + case SpvOpFConvert: *hasResult = true; *hasResultType = true; break; + case SpvOpQuantizeToF16: *hasResult = true; *hasResultType = true; break; + case SpvOpConvertPtrToU: *hasResult = true; *hasResultType = true; break; + case SpvOpSatConvertSToU: *hasResult = true; *hasResultType = true; break; + case SpvOpSatConvertUToS: *hasResult = true; *hasResultType = true; break; + case SpvOpConvertUToPtr: *hasResult = true; *hasResultType = true; break; + case SpvOpPtrCastToGeneric: *hasResult = true; *hasResultType = true; break; + case SpvOpGenericCastToPtr: *hasResult = true; *hasResultType = true; break; + case SpvOpGenericCastToPtrExplicit: *hasResult = true; *hasResultType = true; break; + case SpvOpBitcast: *hasResult = true; *hasResultType = true; break; + case SpvOpSNegate: *hasResult = true; *hasResultType = true; break; + case SpvOpFNegate: *hasResult = true; *hasResultType = true; break; + case SpvOpIAdd: *hasResult = true; *hasResultType = true; break; + case SpvOpFAdd: *hasResult = true; *hasResultType = true; break; + case SpvOpISub: *hasResult = true; *hasResultType = true; break; + case SpvOpFSub: *hasResult = true; *hasResultType = true; break; + case SpvOpIMul: *hasResult = true; *hasResultType = true; break; + case SpvOpFMul: *hasResult = true; *hasResultType = true; break; + case SpvOpUDiv: *hasResult = true; *hasResultType = true; break; + case SpvOpSDiv: *hasResult = true; *hasResultType = true; break; + case SpvOpFDiv: *hasResult = true; *hasResultType = true; break; + case SpvOpUMod: *hasResult = true; *hasResultType = true; break; + case SpvOpSRem: *hasResult = true; *hasResultType = true; break; + case SpvOpSMod: *hasResult = true; *hasResultType = true; break; + case SpvOpFRem: *hasResult = true; *hasResultType = true; break; + case SpvOpFMod: *hasResult = true; *hasResultType = true; break; + case SpvOpVectorTimesScalar: *hasResult = true; *hasResultType = true; break; + case SpvOpMatrixTimesScalar: *hasResult = true; *hasResultType = true; break; + case SpvOpVectorTimesMatrix: *hasResult = true; *hasResultType = true; break; + case SpvOpMatrixTimesVector: *hasResult = true; *hasResultType = true; break; + case SpvOpMatrixTimesMatrix: *hasResult = true; *hasResultType = true; break; + case SpvOpOuterProduct: *hasResult = true; *hasResultType = true; break; + case SpvOpDot: *hasResult = true; *hasResultType = true; break; + case SpvOpIAddCarry: *hasResult = true; *hasResultType = true; break; + case SpvOpISubBorrow: *hasResult = true; *hasResultType = true; break; + case SpvOpUMulExtended: *hasResult = true; *hasResultType = true; break; + case SpvOpSMulExtended: *hasResult = true; *hasResultType = true; break; + case SpvOpAny: *hasResult = true; *hasResultType = true; break; + case SpvOpAll: *hasResult = true; *hasResultType = true; break; + case SpvOpIsNan: *hasResult = true; *hasResultType = true; break; + case SpvOpIsInf: *hasResult = true; *hasResultType = true; break; + case SpvOpIsFinite: *hasResult = true; *hasResultType = true; break; + case SpvOpIsNormal: *hasResult = true; *hasResultType = true; break; + case SpvOpSignBitSet: *hasResult = true; *hasResultType = true; break; + case SpvOpLessOrGreater: *hasResult = true; *hasResultType = true; break; + case SpvOpOrdered: *hasResult = true; *hasResultType = true; break; + case SpvOpUnordered: *hasResult = true; *hasResultType = true; break; + case SpvOpLogicalEqual: *hasResult = true; *hasResultType = true; break; + case SpvOpLogicalNotEqual: *hasResult = true; *hasResultType = true; break; + case SpvOpLogicalOr: *hasResult = true; *hasResultType = true; break; + case SpvOpLogicalAnd: *hasResult = true; *hasResultType = true; break; + case SpvOpLogicalNot: *hasResult = true; *hasResultType = true; break; + case SpvOpSelect: *hasResult = true; *hasResultType = true; break; + case SpvOpIEqual: *hasResult = true; *hasResultType = true; break; + case SpvOpINotEqual: *hasResult = true; *hasResultType = true; break; + case SpvOpUGreaterThan: *hasResult = true; *hasResultType = true; break; + case SpvOpSGreaterThan: *hasResult = true; *hasResultType = true; break; + case SpvOpUGreaterThanEqual: *hasResult = true; *hasResultType = true; break; + case SpvOpSGreaterThanEqual: *hasResult = true; *hasResultType = true; break; + case SpvOpULessThan: *hasResult = true; *hasResultType = true; break; + case SpvOpSLessThan: *hasResult = true; *hasResultType = true; break; + case SpvOpULessThanEqual: *hasResult = true; *hasResultType = true; break; + case SpvOpSLessThanEqual: *hasResult = true; *hasResultType = true; break; + case SpvOpFOrdEqual: *hasResult = true; *hasResultType = true; break; + case SpvOpFUnordEqual: *hasResult = true; *hasResultType = true; break; + case SpvOpFOrdNotEqual: *hasResult = true; *hasResultType = true; break; + case SpvOpFUnordNotEqual: *hasResult = true; *hasResultType = true; break; + case SpvOpFOrdLessThan: *hasResult = true; *hasResultType = true; break; + case SpvOpFUnordLessThan: *hasResult = true; *hasResultType = true; break; + case SpvOpFOrdGreaterThan: *hasResult = true; *hasResultType = true; break; + case SpvOpFUnordGreaterThan: *hasResult = true; *hasResultType = true; break; + case SpvOpFOrdLessThanEqual: *hasResult = true; *hasResultType = true; break; + case SpvOpFUnordLessThanEqual: *hasResult = true; *hasResultType = true; break; + case SpvOpFOrdGreaterThanEqual: *hasResult = true; *hasResultType = true; break; + case SpvOpFUnordGreaterThanEqual: *hasResult = true; *hasResultType = true; break; + case SpvOpShiftRightLogical: *hasResult = true; *hasResultType = true; break; + case SpvOpShiftRightArithmetic: *hasResult = true; *hasResultType = true; break; + case SpvOpShiftLeftLogical: *hasResult = true; *hasResultType = true; break; + case SpvOpBitwiseOr: *hasResult = true; *hasResultType = true; break; + case SpvOpBitwiseXor: *hasResult = true; *hasResultType = true; break; + case SpvOpBitwiseAnd: *hasResult = true; *hasResultType = true; break; + case SpvOpNot: *hasResult = true; *hasResultType = true; break; + case SpvOpBitFieldInsert: *hasResult = true; *hasResultType = true; break; + case SpvOpBitFieldSExtract: *hasResult = true; *hasResultType = true; break; + case SpvOpBitFieldUExtract: *hasResult = true; *hasResultType = true; break; + case SpvOpBitReverse: *hasResult = true; *hasResultType = true; break; + case SpvOpBitCount: *hasResult = true; *hasResultType = true; break; + case SpvOpDPdx: *hasResult = true; *hasResultType = true; break; + case SpvOpDPdy: *hasResult = true; *hasResultType = true; break; + case SpvOpFwidth: *hasResult = true; *hasResultType = true; break; + case SpvOpDPdxFine: *hasResult = true; *hasResultType = true; break; + case SpvOpDPdyFine: *hasResult = true; *hasResultType = true; break; + case SpvOpFwidthFine: *hasResult = true; *hasResultType = true; break; + case SpvOpDPdxCoarse: *hasResult = true; *hasResultType = true; break; + case SpvOpDPdyCoarse: *hasResult = true; *hasResultType = true; break; + case SpvOpFwidthCoarse: *hasResult = true; *hasResultType = true; break; + case SpvOpEmitVertex: *hasResult = false; *hasResultType = false; break; + case SpvOpEndPrimitive: *hasResult = false; *hasResultType = false; break; + case SpvOpEmitStreamVertex: *hasResult = false; *hasResultType = false; break; + case SpvOpEndStreamPrimitive: *hasResult = false; *hasResultType = false; break; + case SpvOpControlBarrier: *hasResult = false; *hasResultType = false; break; + case SpvOpMemoryBarrier: *hasResult = false; *hasResultType = false; break; + case SpvOpAtomicLoad: *hasResult = true; *hasResultType = true; break; + case SpvOpAtomicStore: *hasResult = false; *hasResultType = false; break; + case SpvOpAtomicExchange: *hasResult = true; *hasResultType = true; break; + case SpvOpAtomicCompareExchange: *hasResult = true; *hasResultType = true; break; + case SpvOpAtomicCompareExchangeWeak: *hasResult = true; *hasResultType = true; break; + case SpvOpAtomicIIncrement: *hasResult = true; *hasResultType = true; break; + case SpvOpAtomicIDecrement: *hasResult = true; *hasResultType = true; break; + case SpvOpAtomicIAdd: *hasResult = true; *hasResultType = true; break; + case SpvOpAtomicISub: *hasResult = true; *hasResultType = true; break; + case SpvOpAtomicSMin: *hasResult = true; *hasResultType = true; break; + case SpvOpAtomicUMin: *hasResult = true; *hasResultType = true; break; + case SpvOpAtomicSMax: *hasResult = true; *hasResultType = true; break; + case SpvOpAtomicUMax: *hasResult = true; *hasResultType = true; break; + case SpvOpAtomicAnd: *hasResult = true; *hasResultType = true; break; + case SpvOpAtomicOr: *hasResult = true; *hasResultType = true; break; + case SpvOpAtomicXor: *hasResult = true; *hasResultType = true; break; + case SpvOpPhi: *hasResult = true; *hasResultType = true; break; + case SpvOpLoopMerge: *hasResult = false; *hasResultType = false; break; + case SpvOpSelectionMerge: *hasResult = false; *hasResultType = false; break; + case SpvOpLabel: *hasResult = true; *hasResultType = false; break; + case SpvOpBranch: *hasResult = false; *hasResultType = false; break; + case SpvOpBranchConditional: *hasResult = false; *hasResultType = false; break; + case SpvOpSwitch: *hasResult = false; *hasResultType = false; break; + case SpvOpKill: *hasResult = false; *hasResultType = false; break; + case SpvOpReturn: *hasResult = false; *hasResultType = false; break; + case SpvOpReturnValue: *hasResult = false; *hasResultType = false; break; + case SpvOpUnreachable: *hasResult = false; *hasResultType = false; break; + case SpvOpLifetimeStart: *hasResult = false; *hasResultType = false; break; + case SpvOpLifetimeStop: *hasResult = false; *hasResultType = false; break; + case SpvOpGroupAsyncCopy: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupWaitEvents: *hasResult = false; *hasResultType = false; break; + case SpvOpGroupAll: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupAny: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupBroadcast: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupIAdd: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupFAdd: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupFMin: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupUMin: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupSMin: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupFMax: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupUMax: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupSMax: *hasResult = true; *hasResultType = true; break; + case SpvOpReadPipe: *hasResult = true; *hasResultType = true; break; + case SpvOpWritePipe: *hasResult = true; *hasResultType = true; break; + case SpvOpReservedReadPipe: *hasResult = true; *hasResultType = true; break; + case SpvOpReservedWritePipe: *hasResult = true; *hasResultType = true; break; + case SpvOpReserveReadPipePackets: *hasResult = true; *hasResultType = true; break; + case SpvOpReserveWritePipePackets: *hasResult = true; *hasResultType = true; break; + case SpvOpCommitReadPipe: *hasResult = false; *hasResultType = false; break; + case SpvOpCommitWritePipe: *hasResult = false; *hasResultType = false; break; + case SpvOpIsValidReserveId: *hasResult = true; *hasResultType = true; break; + case SpvOpGetNumPipePackets: *hasResult = true; *hasResultType = true; break; + case SpvOpGetMaxPipePackets: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupReserveReadPipePackets: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupReserveWritePipePackets: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupCommitReadPipe: *hasResult = false; *hasResultType = false; break; + case SpvOpGroupCommitWritePipe: *hasResult = false; *hasResultType = false; break; + case SpvOpEnqueueMarker: *hasResult = true; *hasResultType = true; break; + case SpvOpEnqueueKernel: *hasResult = true; *hasResultType = true; break; + case SpvOpGetKernelNDrangeSubGroupCount: *hasResult = true; *hasResultType = true; break; + case SpvOpGetKernelNDrangeMaxSubGroupSize: *hasResult = true; *hasResultType = true; break; + case SpvOpGetKernelWorkGroupSize: *hasResult = true; *hasResultType = true; break; + case SpvOpGetKernelPreferredWorkGroupSizeMultiple: *hasResult = true; *hasResultType = true; break; + case SpvOpRetainEvent: *hasResult = false; *hasResultType = false; break; + case SpvOpReleaseEvent: *hasResult = false; *hasResultType = false; break; + case SpvOpCreateUserEvent: *hasResult = true; *hasResultType = true; break; + case SpvOpIsValidEvent: *hasResult = true; *hasResultType = true; break; + case SpvOpSetUserEventStatus: *hasResult = false; *hasResultType = false; break; + case SpvOpCaptureEventProfilingInfo: *hasResult = false; *hasResultType = false; break; + case SpvOpGetDefaultQueue: *hasResult = true; *hasResultType = true; break; + case SpvOpBuildNDRange: *hasResult = true; *hasResultType = true; break; + case SpvOpImageSparseSampleImplicitLod: *hasResult = true; *hasResultType = true; break; + case SpvOpImageSparseSampleExplicitLod: *hasResult = true; *hasResultType = true; break; + case SpvOpImageSparseSampleDrefImplicitLod: *hasResult = true; *hasResultType = true; break; + case SpvOpImageSparseSampleDrefExplicitLod: *hasResult = true; *hasResultType = true; break; + case SpvOpImageSparseSampleProjImplicitLod: *hasResult = true; *hasResultType = true; break; + case SpvOpImageSparseSampleProjExplicitLod: *hasResult = true; *hasResultType = true; break; + case SpvOpImageSparseSampleProjDrefImplicitLod: *hasResult = true; *hasResultType = true; break; + case SpvOpImageSparseSampleProjDrefExplicitLod: *hasResult = true; *hasResultType = true; break; + case SpvOpImageSparseFetch: *hasResult = true; *hasResultType = true; break; + case SpvOpImageSparseGather: *hasResult = true; *hasResultType = true; break; + case SpvOpImageSparseDrefGather: *hasResult = true; *hasResultType = true; break; + case SpvOpImageSparseTexelsResident: *hasResult = true; *hasResultType = true; break; + case SpvOpNoLine: *hasResult = false; *hasResultType = false; break; + case SpvOpAtomicFlagTestAndSet: *hasResult = true; *hasResultType = true; break; + case SpvOpAtomicFlagClear: *hasResult = false; *hasResultType = false; break; + case SpvOpImageSparseRead: *hasResult = true; *hasResultType = true; break; + case SpvOpSizeOf: *hasResult = true; *hasResultType = true; break; + case SpvOpTypePipeStorage: *hasResult = true; *hasResultType = false; break; + case SpvOpConstantPipeStorage: *hasResult = true; *hasResultType = true; break; + case SpvOpCreatePipeFromPipeStorage: *hasResult = true; *hasResultType = true; break; + case SpvOpGetKernelLocalSizeForSubgroupCount: *hasResult = true; *hasResultType = true; break; + case SpvOpGetKernelMaxNumSubgroups: *hasResult = true; *hasResultType = true; break; + case SpvOpTypeNamedBarrier: *hasResult = true; *hasResultType = false; break; + case SpvOpNamedBarrierInitialize: *hasResult = true; *hasResultType = true; break; + case SpvOpMemoryNamedBarrier: *hasResult = false; *hasResultType = false; break; + case SpvOpModuleProcessed: *hasResult = false; *hasResultType = false; break; + case SpvOpExecutionModeId: *hasResult = false; *hasResultType = false; break; + case SpvOpDecorateId: *hasResult = false; *hasResultType = false; break; + case SpvOpGroupNonUniformElect: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupNonUniformAll: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupNonUniformAny: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupNonUniformAllEqual: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupNonUniformBroadcast: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupNonUniformBroadcastFirst: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupNonUniformBallot: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupNonUniformInverseBallot: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupNonUniformBallotBitExtract: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupNonUniformBallotBitCount: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupNonUniformBallotFindLSB: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupNonUniformBallotFindMSB: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupNonUniformShuffle: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupNonUniformShuffleXor: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupNonUniformShuffleUp: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupNonUniformShuffleDown: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupNonUniformIAdd: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupNonUniformFAdd: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupNonUniformIMul: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupNonUniformFMul: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupNonUniformSMin: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupNonUniformUMin: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupNonUniformFMin: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupNonUniformSMax: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupNonUniformUMax: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupNonUniformFMax: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupNonUniformBitwiseAnd: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupNonUniformBitwiseOr: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupNonUniformBitwiseXor: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupNonUniformLogicalAnd: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupNonUniformLogicalOr: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupNonUniformLogicalXor: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupNonUniformQuadBroadcast: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupNonUniformQuadSwap: *hasResult = true; *hasResultType = true; break; + case SpvOpCopyLogical: *hasResult = true; *hasResultType = true; break; + case SpvOpPtrEqual: *hasResult = true; *hasResultType = true; break; + case SpvOpPtrNotEqual: *hasResult = true; *hasResultType = true; break; + case SpvOpPtrDiff: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupBallotKHR: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupFirstInvocationKHR: *hasResult = true; *hasResultType = true; break; + case SpvOpTerminateInvocation: *hasResult = false; *hasResultType = false; break; + case SpvOpSubgroupAllKHR: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAnyKHR: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAllEqualKHR: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupReadInvocationKHR: *hasResult = true; *hasResultType = true; break; + case SpvOpTypeRayQueryProvisionalKHR: *hasResult = true; *hasResultType = false; break; + case SpvOpRayQueryInitializeKHR: *hasResult = false; *hasResultType = false; break; + case SpvOpRayQueryTerminateKHR: *hasResult = false; *hasResultType = false; break; + case SpvOpRayQueryGenerateIntersectionKHR: *hasResult = false; *hasResultType = false; break; + case SpvOpRayQueryConfirmIntersectionKHR: *hasResult = false; *hasResultType = false; break; + case SpvOpRayQueryProceedKHR: *hasResult = true; *hasResultType = true; break; + case SpvOpRayQueryGetIntersectionTypeKHR: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupIAddNonUniformAMD: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupFAddNonUniformAMD: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupFMinNonUniformAMD: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupUMinNonUniformAMD: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupSMinNonUniformAMD: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupFMaxNonUniformAMD: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupUMaxNonUniformAMD: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupSMaxNonUniformAMD: *hasResult = true; *hasResultType = true; break; + case SpvOpFragmentMaskFetchAMD: *hasResult = true; *hasResultType = true; break; + case SpvOpFragmentFetchAMD: *hasResult = true; *hasResultType = true; break; + case SpvOpReadClockKHR: *hasResult = true; *hasResultType = true; break; + case SpvOpImageSampleFootprintNV: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupNonUniformPartitionNV: *hasResult = true; *hasResultType = true; break; + case SpvOpWritePackedPrimitiveIndices4x8NV: *hasResult = false; *hasResultType = false; break; + case SpvOpReportIntersectionNV: *hasResult = true; *hasResultType = true; break; + case SpvOpIgnoreIntersectionNV: *hasResult = false; *hasResultType = false; break; + case SpvOpTerminateRayNV: *hasResult = false; *hasResultType = false; break; + case SpvOpTraceNV: *hasResult = false; *hasResultType = false; break; + case SpvOpTypeAccelerationStructureNV: *hasResult = true; *hasResultType = false; break; + case SpvOpExecuteCallableNV: *hasResult = false; *hasResultType = false; break; + case SpvOpTypeCooperativeMatrixNV: *hasResult = true; *hasResultType = false; break; + case SpvOpCooperativeMatrixLoadNV: *hasResult = true; *hasResultType = true; break; + case SpvOpCooperativeMatrixStoreNV: *hasResult = false; *hasResultType = false; break; + case SpvOpCooperativeMatrixMulAddNV: *hasResult = true; *hasResultType = true; break; + case SpvOpCooperativeMatrixLengthNV: *hasResult = true; *hasResultType = true; break; + case SpvOpBeginInvocationInterlockEXT: *hasResult = false; *hasResultType = false; break; + case SpvOpEndInvocationInterlockEXT: *hasResult = false; *hasResultType = false; break; + case SpvOpDemoteToHelperInvocationEXT: *hasResult = false; *hasResultType = false; break; + case SpvOpIsHelperInvocationEXT: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupShuffleINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupShuffleDownINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupShuffleUpINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupShuffleXorINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupBlockReadINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupBlockWriteINTEL: *hasResult = false; *hasResultType = false; break; + case SpvOpSubgroupImageBlockReadINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupImageBlockWriteINTEL: *hasResult = false; *hasResultType = false; break; + case SpvOpSubgroupImageMediaBlockReadINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupImageMediaBlockWriteINTEL: *hasResult = false; *hasResultType = false; break; + case SpvOpUCountLeadingZerosINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpUCountTrailingZerosINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpAbsISubINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpAbsUSubINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpIAddSatINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpUAddSatINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpIAverageINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpUAverageINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpIAverageRoundedINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpUAverageRoundedINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpISubSatINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpUSubSatINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpIMul32x16INTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpUMul32x16INTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpFunctionPointerINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpFunctionPointerCallINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpDecorateString: *hasResult = false; *hasResultType = false; break; + case SpvOpMemberDecorateString: *hasResult = false; *hasResultType = false; break; + case SpvOpVmeImageINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpTypeVmeImageINTEL: *hasResult = true; *hasResultType = false; break; + case SpvOpTypeAvcImePayloadINTEL: *hasResult = true; *hasResultType = false; break; + case SpvOpTypeAvcRefPayloadINTEL: *hasResult = true; *hasResultType = false; break; + case SpvOpTypeAvcSicPayloadINTEL: *hasResult = true; *hasResultType = false; break; + case SpvOpTypeAvcMcePayloadINTEL: *hasResult = true; *hasResultType = false; break; + case SpvOpTypeAvcMceResultINTEL: *hasResult = true; *hasResultType = false; break; + case SpvOpTypeAvcImeResultINTEL: *hasResult = true; *hasResultType = false; break; + case SpvOpTypeAvcImeResultSingleReferenceStreamoutINTEL: *hasResult = true; *hasResultType = false; break; + case SpvOpTypeAvcImeResultDualReferenceStreamoutINTEL: *hasResult = true; *hasResultType = false; break; + case SpvOpTypeAvcImeSingleReferenceStreaminINTEL: *hasResult = true; *hasResultType = false; break; + case SpvOpTypeAvcImeDualReferenceStreaminINTEL: *hasResult = true; *hasResultType = false; break; + case SpvOpTypeAvcRefResultINTEL: *hasResult = true; *hasResultType = false; break; + case SpvOpTypeAvcSicResultINTEL: *hasResult = true; *hasResultType = false; break; + case SpvOpSubgroupAvcMceGetDefaultInterBaseMultiReferencePenaltyINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcMceSetInterBaseMultiReferencePenaltyINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcMceGetDefaultInterShapePenaltyINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcMceSetInterShapePenaltyINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcMceGetDefaultInterDirectionPenaltyINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcMceSetInterDirectionPenaltyINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcMceGetDefaultIntraLumaShapePenaltyINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcMceGetDefaultInterMotionVectorCostTableINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcMceGetDefaultHighPenaltyCostTableINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcMceGetDefaultMediumPenaltyCostTableINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcMceGetDefaultLowPenaltyCostTableINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcMceSetMotionVectorCostFunctionINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcMceGetDefaultIntraLumaModePenaltyINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcMceGetDefaultNonDcLumaIntraPenaltyINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcMceGetDefaultIntraChromaModeBasePenaltyINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcMceSetAcOnlyHaarINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcMceSetSourceInterlacedFieldPolarityINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcMceSetSingleReferenceInterlacedFieldPolarityINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcMceSetDualReferenceInterlacedFieldPolaritiesINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcMceConvertToImePayloadINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcMceConvertToImeResultINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcMceConvertToRefPayloadINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcMceConvertToRefResultINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcMceConvertToSicPayloadINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcMceConvertToSicResultINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcMceGetMotionVectorsINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcMceGetInterDistortionsINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcMceGetBestInterDistortionsINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcMceGetInterMajorShapeINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcMceGetInterMinorShapeINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcMceGetInterDirectionsINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcMceGetInterMotionVectorCountINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcMceGetInterReferenceIdsINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcMceGetInterReferenceInterlacedFieldPolaritiesINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcImeInitializeINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcImeSetSingleReferenceINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcImeSetDualReferenceINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcImeRefWindowSizeINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcImeAdjustRefOffsetINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcImeConvertToMcePayloadINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcImeSetMaxMotionVectorCountINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcImeSetUnidirectionalMixDisableINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcImeSetEarlySearchTerminationThresholdINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcImeSetWeightedSadINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcImeEvaluateWithSingleReferenceINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcImeEvaluateWithDualReferenceINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcImeEvaluateWithSingleReferenceStreaminINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcImeEvaluateWithDualReferenceStreaminINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcImeEvaluateWithSingleReferenceStreamoutINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcImeEvaluateWithDualReferenceStreamoutINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcImeEvaluateWithSingleReferenceStreaminoutINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcImeEvaluateWithDualReferenceStreaminoutINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcImeConvertToMceResultINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcImeGetSingleReferenceStreaminINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcImeGetDualReferenceStreaminINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcImeStripSingleReferenceStreamoutINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcImeStripDualReferenceStreamoutINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeMotionVectorsINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeDistortionsINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeReferenceIdsINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeMotionVectorsINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeDistortionsINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeReferenceIdsINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcImeGetBorderReachedINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcImeGetTruncatedSearchIndicationINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcImeGetUnidirectionalEarlySearchTerminationINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcImeGetWeightingPatternMinimumMotionVectorINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcImeGetWeightingPatternMinimumDistortionINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcFmeInitializeINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcBmeInitializeINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcRefConvertToMcePayloadINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcRefSetBidirectionalMixDisableINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcRefSetBilinearFilterEnableINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcRefEvaluateWithSingleReferenceINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcRefEvaluateWithDualReferenceINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcRefEvaluateWithMultiReferenceINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcRefEvaluateWithMultiReferenceInterlacedINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcRefConvertToMceResultINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcSicInitializeINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcSicConfigureSkcINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcSicConfigureIpeLumaINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcSicConfigureIpeLumaChromaINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcSicGetMotionVectorMaskINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcSicConvertToMcePayloadINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcSicSetIntraLumaShapePenaltyINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcSicSetIntraLumaModeCostFunctionINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcSicSetIntraChromaModeCostFunctionINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcSicSetBilinearFilterEnableINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcSicSetSkcForwardTransformEnableINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcSicSetBlockBasedRawSkipSadINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcSicEvaluateIpeINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcSicEvaluateWithSingleReferenceINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcSicEvaluateWithDualReferenceINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcSicEvaluateWithMultiReferenceINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcSicEvaluateWithMultiReferenceInterlacedINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcSicConvertToMceResultINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcSicGetIpeLumaShapeINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcSicGetBestIpeLumaDistortionINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcSicGetBestIpeChromaDistortionINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcSicGetPackedIpeLumaModesINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcSicGetIpeChromaModeINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcSicGetPackedSkcLumaCountThresholdINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcSicGetPackedSkcLumaSumThresholdINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcSicGetInterRawSadsINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpLoopControlINTEL: *hasResult = false; *hasResultType = false; break; + case SpvOpReadPipeBlockingINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpWritePipeBlockingINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpFPGARegINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpRayQueryGetRayTMinKHR: *hasResult = true; *hasResultType = true; break; + case SpvOpRayQueryGetRayFlagsKHR: *hasResult = true; *hasResultType = true; break; + case SpvOpRayQueryGetIntersectionTKHR: *hasResult = true; *hasResultType = true; break; + case SpvOpRayQueryGetIntersectionInstanceCustomIndexKHR: *hasResult = true; *hasResultType = true; break; + case SpvOpRayQueryGetIntersectionInstanceIdKHR: *hasResult = true; *hasResultType = true; break; + case SpvOpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffsetKHR: *hasResult = true; *hasResultType = true; break; + case SpvOpRayQueryGetIntersectionGeometryIndexKHR: *hasResult = true; *hasResultType = true; break; + case SpvOpRayQueryGetIntersectionPrimitiveIndexKHR: *hasResult = true; *hasResultType = true; break; + case SpvOpRayQueryGetIntersectionBarycentricsKHR: *hasResult = true; *hasResultType = true; break; + case SpvOpRayQueryGetIntersectionFrontFaceKHR: *hasResult = true; *hasResultType = true; break; + case SpvOpRayQueryGetIntersectionCandidateAABBOpaqueKHR: *hasResult = true; *hasResultType = true; break; + case SpvOpRayQueryGetIntersectionObjectRayDirectionKHR: *hasResult = true; *hasResultType = true; break; + case SpvOpRayQueryGetIntersectionObjectRayOriginKHR: *hasResult = true; *hasResultType = true; break; + case SpvOpRayQueryGetWorldRayDirectionKHR: *hasResult = true; *hasResultType = true; break; + case SpvOpRayQueryGetWorldRayOriginKHR: *hasResult = true; *hasResultType = true; break; + case SpvOpRayQueryGetIntersectionObjectToWorldKHR: *hasResult = true; *hasResultType = true; break; + case SpvOpRayQueryGetIntersectionWorldToObjectKHR: *hasResult = true; *hasResultType = true; break; + case SpvOpAtomicFAddEXT: *hasResult = true; *hasResultType = true; break; + } +} +#endif /* SPV_ENABLE_UTILITY_CODE */ + +#endif + From a02dd3bf052af7effa4a83423c64b6a90deaf7a9 Mon Sep 17 00:00:00 2001 From: Lynix Date: Wed, 29 Jul 2020 14:31:54 +0200 Subject: [PATCH 073/105] Renderer: Add ShaderRecursiveVisitor --- .../Renderer/ShaderRecursiveVisitor.hpp | 42 +++++++++ .../Renderer/ShaderRecursiveVisitor.inl | 12 +++ include/Nazara/Renderer/ShaderValidator.hpp | 6 +- .../Renderer/ShaderRecursiveVisitor.cpp | 93 +++++++++++++++++++ src/Nazara/Renderer/ShaderValidator.cpp | 36 +++---- 5 files changed, 169 insertions(+), 20 deletions(-) create mode 100644 include/Nazara/Renderer/ShaderRecursiveVisitor.hpp create mode 100644 include/Nazara/Renderer/ShaderRecursiveVisitor.inl create mode 100644 src/Nazara/Renderer/ShaderRecursiveVisitor.cpp diff --git a/include/Nazara/Renderer/ShaderRecursiveVisitor.hpp b/include/Nazara/Renderer/ShaderRecursiveVisitor.hpp new file mode 100644 index 000000000..0e1087a58 --- /dev/null +++ b/include/Nazara/Renderer/ShaderRecursiveVisitor.hpp @@ -0,0 +1,42 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Renderer module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_SHADER_RECURSIVE_VISITOR_HPP +#define NAZARA_SHADER_RECURSIVE_VISITOR_HPP + +#include +#include +#include + +namespace Nz +{ + class NAZARA_RENDERER_API ShaderRecursiveVisitor : public ShaderVisitor + { + public: + ShaderRecursiveVisitor() = default; + ~ShaderRecursiveVisitor() = default; + + using ShaderVisitor::Visit; + + void Visit(const ShaderNodes::AccessMember& node) override; + void Visit(const ShaderNodes::AssignOp& node) override; + void Visit(const ShaderNodes::BinaryOp& node) override; + void Visit(const ShaderNodes::Branch& node) override; + void Visit(const ShaderNodes::Cast& node) override; + void Visit(const ShaderNodes::Constant& node) override; + void Visit(const ShaderNodes::DeclareVariable& node) override; + void Visit(const ShaderNodes::ExpressionStatement& node) override; + void Visit(const ShaderNodes::Identifier& node) override; + void Visit(const ShaderNodes::IntrinsicCall& node) override; + void Visit(const ShaderNodes::Sample2D& node) override; + void Visit(const ShaderNodes::StatementBlock& node) override; + void Visit(const ShaderNodes::SwizzleOp& node) override; + }; +} + +#include + +#endif diff --git a/include/Nazara/Renderer/ShaderRecursiveVisitor.inl b/include/Nazara/Renderer/ShaderRecursiveVisitor.inl new file mode 100644 index 000000000..b107f06e7 --- /dev/null +++ b/include/Nazara/Renderer/ShaderRecursiveVisitor.inl @@ -0,0 +1,12 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Renderer module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include + +namespace Nz +{ +} + +#include diff --git a/include/Nazara/Renderer/ShaderValidator.hpp b/include/Nazara/Renderer/ShaderValidator.hpp index 09015b073..237ecaa73 100644 --- a/include/Nazara/Renderer/ShaderValidator.hpp +++ b/include/Nazara/Renderer/ShaderValidator.hpp @@ -12,11 +12,11 @@ #include #include #include -#include +#include namespace Nz { - class NAZARA_RENDERER_API ShaderValidator : public ShaderVisitor + class NAZARA_RENDERER_API ShaderValidator : public ShaderRecursiveVisitor { public: inline ShaderValidator(const ShaderAst& shader); @@ -32,7 +32,7 @@ namespace Nz void TypeMustMatch(const ShaderNodes::ExpressionPtr& left, const ShaderNodes::ExpressionPtr& right); void TypeMustMatch(const ShaderExpressionType& left, const ShaderExpressionType& right); - using ShaderVisitor::Visit; + using ShaderRecursiveVisitor::Visit; void Visit(const ShaderNodes::AccessMember& node) override; void Visit(const ShaderNodes::AssignOp& node) override; void Visit(const ShaderNodes::BinaryOp& node) override; diff --git a/src/Nazara/Renderer/ShaderRecursiveVisitor.cpp b/src/Nazara/Renderer/ShaderRecursiveVisitor.cpp new file mode 100644 index 000000000..2116da21c --- /dev/null +++ b/src/Nazara/Renderer/ShaderRecursiveVisitor.cpp @@ -0,0 +1,93 @@ +// Copyright (C) 2015 Jérôme Leclercq +// This file is part of the "Nazara Engine - Renderer module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include + +namespace Nz +{ + void ShaderRecursiveVisitor::Visit(const ShaderNodes::AccessMember& node) + { + Visit(node.structExpr); + } + + void ShaderRecursiveVisitor::Visit(const ShaderNodes::AssignOp& node) + { + Visit(node.left); + Visit(node.right); + } + + void ShaderRecursiveVisitor::Visit(const ShaderNodes::BinaryOp& node) + { + Visit(node.left); + Visit(node.right); + } + + void ShaderRecursiveVisitor::Visit(const ShaderNodes::Branch& node) + { + for (auto& cond : node.condStatements) + { + Visit(cond.condition); + Visit(cond.statement); + } + + if (node.elseStatement) + Visit(node.elseStatement); + } + + void ShaderRecursiveVisitor::Visit(const ShaderNodes::Cast& node) + { + for (auto& expr : node.expressions) + { + if (!expr) + break; + + Visit(expr); + } + } + + void ShaderRecursiveVisitor::Visit(const ShaderNodes::Constant& /*node*/) + { + /* Nothing to do */ + } + + void ShaderRecursiveVisitor::Visit(const ShaderNodes::DeclareVariable& node) + { + if (node.expression) + Visit(node.expression); + } + + void ShaderRecursiveVisitor::Visit(const ShaderNodes::ExpressionStatement& node) + { + Visit(node.expression); + } + + void ShaderRecursiveVisitor::Visit(const ShaderNodes::Identifier& /*node*/) + { + /* Nothing to do */ + } + + void ShaderRecursiveVisitor::Visit(const ShaderNodes::IntrinsicCall& node) + { + for (auto& param : node.parameters) + Visit(param); + } + + void ShaderRecursiveVisitor::Visit(const ShaderNodes::Sample2D& node) + { + Visit(node.sampler); + Visit(node.coordinates); + } + + void ShaderRecursiveVisitor::Visit(const ShaderNodes::StatementBlock& node) + { + for (auto& statement : node.statements) + Visit(statement); + } + + void ShaderRecursiveVisitor::Visit(const ShaderNodes::SwizzleOp& node) + { + Visit(node.expression); + } +} diff --git a/src/Nazara/Renderer/ShaderValidator.cpp b/src/Nazara/Renderer/ShaderValidator.cpp index c181ecd62..01f038217 100644 --- a/src/Nazara/Renderer/ShaderValidator.cpp +++ b/src/Nazara/Renderer/ShaderValidator.cpp @@ -114,8 +114,7 @@ namespace Nz if (node.left->GetExpressionCategory() != ShaderNodes::ExpressionCategory::LValue) throw AstError { "Assignation is only possible with a l-value" }; - Visit(node.left); - Visit(node.right); + ShaderRecursiveVisitor::Visit(node); } void ShaderValidator::Visit(const ShaderNodes::BinaryOp& node) @@ -187,17 +186,18 @@ namespace Nz } } - Visit(node.left); - Visit(node.right); + ShaderRecursiveVisitor::Visit(node); } void ShaderValidator::Visit(const ShaderNodes::Branch& node) { for (const auto& condStatement : node.condStatements) { - Visit(MandatoryNode(condStatement.condition)); - Visit(MandatoryNode(condStatement.statement)); + MandatoryNode(condStatement.condition); + MandatoryNode(condStatement.statement); } + + ShaderRecursiveVisitor::Visit(node); } void ShaderValidator::Visit(const ShaderNodes::Cast& node) @@ -214,11 +214,12 @@ namespace Nz throw AstError{ "incompatible type" }; componentCount += node.GetComponentCount(std::get(exprType)); - Visit(exprPtr); } if (componentCount != requiredComponents) throw AstError{ "Component count doesn't match required component count" }; + + ShaderRecursiveVisitor::Visit(node); } void ShaderValidator::Visit(const ShaderNodes::Constant& /*node*/) @@ -229,17 +230,18 @@ namespace Nz { assert(m_context); - if (node.expression) - Visit(node.expression); - auto& local = m_context->declaredLocals.emplace_back(); local.name = node.variable->name; local.type = node.variable->type; + + ShaderRecursiveVisitor::Visit(node); } void ShaderValidator::Visit(const ShaderNodes::ExpressionStatement& node) { - Visit(MandatoryNode(node.expression)); + MandatoryNode(node.expression); + + ShaderRecursiveVisitor::Visit(node); } void ShaderValidator::Visit(const ShaderNodes::Identifier& node) @@ -377,8 +379,7 @@ namespace Nz break; } - for (auto& param : node.parameters) - Visit(param); + ShaderRecursiveVisitor::Visit(node); } void ShaderValidator::Visit(const ShaderNodes::Sample2D& node) @@ -389,8 +390,7 @@ namespace Nz if (MandatoryExpr(node.coordinates)->GetExpressionType() != ShaderExpressionType{ ShaderNodes::BasicType::Float2 }) throw AstError{ "Coordinates must be a Float2" }; - Visit(node.sampler); - Visit(node.coordinates); + ShaderRecursiveVisitor::Visit(node); } void ShaderValidator::Visit(const ShaderNodes::StatementBlock& node) @@ -400,11 +400,13 @@ namespace Nz m_context->blockLocalIndex.push_back(m_context->declaredLocals.size()); for (const auto& statement : node.statements) - Visit(MandatoryNode(statement)); + MandatoryNode(statement); assert(m_context->declaredLocals.size() >= m_context->blockLocalIndex.back()); m_context->declaredLocals.resize(m_context->blockLocalIndex.back()); m_context->blockLocalIndex.pop_back(); + + ShaderRecursiveVisitor::Visit(node); } void ShaderValidator::Visit(const ShaderNodes::SwizzleOp& node) @@ -428,7 +430,7 @@ namespace Nz throw AstError{ "Cannot swizzle this type" }; } - Visit(node.expression); + ShaderRecursiveVisitor::Visit(node); } bool ValidateShader(const ShaderAst& shader, std::string* error) From 22714327485f83d3042fc1434bf658f3a7f56c47 Mon Sep 17 00:00:00 2001 From: Lynix Date: Wed, 29 Jul 2020 14:39:34 +0200 Subject: [PATCH 074/105] Renderer/ShaderValidator: Use ShaderVarVisitor instead of switch --- include/Nazara/Renderer/ShaderValidator.hpp | 11 +- src/Nazara/Renderer/ShaderValidator.cpp | 163 +++++++++----------- 2 files changed, 85 insertions(+), 89 deletions(-) diff --git a/include/Nazara/Renderer/ShaderValidator.hpp b/include/Nazara/Renderer/ShaderValidator.hpp index 237ecaa73..edf54370f 100644 --- a/include/Nazara/Renderer/ShaderValidator.hpp +++ b/include/Nazara/Renderer/ShaderValidator.hpp @@ -13,10 +13,11 @@ #include #include #include +#include namespace Nz { - class NAZARA_RENDERER_API ShaderValidator : public ShaderRecursiveVisitor + class NAZARA_RENDERER_API ShaderValidator : public ShaderRecursiveVisitor, public ShaderVarVisitor { public: inline ShaderValidator(const ShaderAst& shader); @@ -47,6 +48,14 @@ namespace Nz void Visit(const ShaderNodes::StatementBlock& node) override; void Visit(const ShaderNodes::SwizzleOp& node) override; + using ShaderVarVisitor::Visit; + void Visit(const ShaderNodes::BuiltinVariable& var) override; + void Visit(const ShaderNodes::InputVariable& var) override; + void Visit(const ShaderNodes::LocalVariable& var) override; + void Visit(const ShaderNodes::OutputVariable& var) override; + void Visit(const ShaderNodes::ParameterVariable& var) override; + void Visit(const ShaderNodes::UniformVariable& var) override; + struct Context; const ShaderAst& m_shader; diff --git a/src/Nazara/Renderer/ShaderValidator.cpp b/src/Nazara/Renderer/ShaderValidator.cpp index 01f038217..351a46839 100644 --- a/src/Nazara/Renderer/ShaderValidator.cpp +++ b/src/Nazara/Renderer/ShaderValidator.cpp @@ -251,94 +251,7 @@ namespace Nz if (!node.var) throw AstError{ "Invalid variable" }; - //< FIXME: Use variable visitor - switch (node.var->GetType()) - { - case ShaderNodes::VariableType::BuiltinVariable: - break; - - case ShaderNodes::VariableType::InputVariable: - { - auto& namedVar = static_cast(*node.var); - - for (std::size_t i = 0; i < m_shader.GetInputCount(); ++i) - { - const auto& input = m_shader.GetInput(i); - if (input.name == namedVar.name) - { - TypeMustMatch(input.type, namedVar.type); - return; - } - } - - throw AstError{ "Input not found" }; - } - - case ShaderNodes::VariableType::LocalVariable: - { - auto& localVar = static_cast(*node.var); - const auto& vars = m_context->declaredLocals; - - auto it = std::find_if(vars.begin(), vars.end(), [&](const auto& var) { return var.name == localVar.name; }); - if (it == vars.end()) - throw AstError{ "Local variable not found in this block" }; - - TypeMustMatch(it->type, localVar.type); - break; - } - - case ShaderNodes::VariableType::OutputVariable: - { - auto& outputVar = static_cast(*node.var); - - for (std::size_t i = 0; i < m_shader.GetOutputCount(); ++i) - { - const auto& input = m_shader.GetOutput(i); - if (input.name == outputVar.name) - { - TypeMustMatch(input.type, outputVar.type); - return; - } - } - - throw AstError{ "Output not found" }; - } - - case ShaderNodes::VariableType::ParameterVariable: - { - assert(m_context->currentFunction); - - auto& parameter = static_cast(*node.var); - const auto& parameters = m_context->currentFunction->parameters; - - auto it = std::find_if(parameters.begin(), parameters.end(), [&](const auto& parameter) { return parameter.name == parameter.name; }); - if (it == parameters.end()) - throw AstError{ "Parameter not found in function" }; - - TypeMustMatch(it->type, parameter.type); - break; - } - - case ShaderNodes::VariableType::UniformVariable: - { - auto& uniformVar = static_cast(*node.var); - - for (std::size_t i = 0; i < m_shader.GetUniformCount(); ++i) - { - const auto& uniform = m_shader.GetUniform(i); - if (uniform.name == uniformVar.name) - { - TypeMustMatch(uniform.type, uniformVar.type); - return; - } - } - - throw AstError{ "Uniform not found" }; - } - - default: - break; - } + Visit(node.var); } void ShaderValidator::Visit(const ShaderNodes::IntrinsicCall& node) @@ -433,6 +346,80 @@ namespace Nz ShaderRecursiveVisitor::Visit(node); } + void ShaderValidator::Visit(const ShaderNodes::BuiltinVariable& /*var*/) + { + /* Nothing to do */ + } + + void ShaderValidator::Visit(const ShaderNodes::InputVariable& var) + { + for (std::size_t i = 0; i < m_shader.GetInputCount(); ++i) + { + const auto& input = m_shader.GetInput(i); + if (input.name == var.name) + { + TypeMustMatch(input.type, var.type); + return; + } + } + + throw AstError{ "Input not found" }; + } + + void ShaderValidator::Visit(const ShaderNodes::LocalVariable& var) + { + const auto& vars = m_context->declaredLocals; + + auto it = std::find_if(vars.begin(), vars.end(), [&](const auto& v) { return v.name == var.name; }); + if (it == vars.end()) + throw AstError{ "Local variable not found in this block" }; + + TypeMustMatch(it->type, var.type); + } + + void ShaderValidator::Visit(const ShaderNodes::OutputVariable& var) + { + for (std::size_t i = 0; i < m_shader.GetOutputCount(); ++i) + { + const auto& input = m_shader.GetOutput(i); + if (input.name == var.name) + { + TypeMustMatch(input.type, var.type); + return; + } + } + + throw AstError{ "Output not found" }; + } + + void ShaderValidator::Visit(const ShaderNodes::ParameterVariable& var) + { + assert(m_context->currentFunction); + + const auto& parameters = m_context->currentFunction->parameters; + + auto it = std::find_if(parameters.begin(), parameters.end(), [&](const auto& parameter) { return parameter.name == var.name; }); + if (it == parameters.end()) + throw AstError{ "Parameter not found in function" }; + + TypeMustMatch(it->type, var.type); + } + + void ShaderValidator::Visit(const ShaderNodes::UniformVariable& var) + { + for (std::size_t i = 0; i < m_shader.GetUniformCount(); ++i) + { + const auto& uniform = m_shader.GetUniform(i); + if (uniform.name == var.name) + { + TypeMustMatch(uniform.type, var.type); + return; + } + } + + throw AstError{ "Uniform not found" }; + } + bool ValidateShader(const ShaderAst& shader, std::string* error) { ShaderValidator validator(shader); From 10860ed5621151b96f710367ef4de852c4ec2fe0 Mon Sep 17 00:00:00 2001 From: Lynix Date: Fri, 31 Jul 2020 12:36:37 +0200 Subject: [PATCH 075/105] Improve code --- include/Nazara/Renderer/SpirvWriter.inl | 2 +- src/Nazara/Renderer/SpirvWriter.cpp | 18 +++++------------- 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/include/Nazara/Renderer/SpirvWriter.inl b/include/Nazara/Renderer/SpirvWriter.inl index 86f578d3d..366e8ac46 100644 --- a/include/Nazara/Renderer/SpirvWriter.inl +++ b/include/Nazara/Renderer/SpirvWriter.inl @@ -49,7 +49,7 @@ namespace Nz inline unsigned int SpirvWriter::CountWord(const std::string_view& str) { - return (str.size() + 1 + 4 - 1) / 4; //< + 1 for null character + return (static_cast(str.size() + 1) + sizeof(UInt32) - 1) / sizeof(UInt32); //< + 1 for null character } } diff --git a/src/Nazara/Renderer/SpirvWriter.cpp b/src/Nazara/Renderer/SpirvWriter.cpp index 863666588..ea74e5066 100644 --- a/src/Nazara/Renderer/SpirvWriter.cpp +++ b/src/Nazara/Renderer/SpirvWriter.cpp @@ -40,10 +40,6 @@ namespace Nz AppendHeader(); - // OpImageSampleImplicitLod %23 %31 %35 - - //Append("BONJOUR PRAETONUS"); - std::vector ret = std::move(state.output); return ret; } @@ -58,17 +54,13 @@ namespace Nz std::size_t size4 = CountWord(str); for (std::size_t i = 0; i < size4; ++i) { - auto GetChar = [&](std::size_t pos) -> UInt32 - { - if (pos < str.size()) - return static_cast(str[pos]); - else - return 0; - }; - UInt32 codepoint = 0; for (std::size_t j = 0; j < 4; ++j) - codepoint |= GetChar(i * 4 + j) << (j * 8); + { + std::size_t pos = i * 4 + j; + if (pos < str.size()) + codepoint |= UInt32(str[pos]) << (j * 8); + } Append(codepoint); } From 50bd150345ddb1692acd063dae1de3f129d849be Mon Sep 17 00:00:00 2001 From: Lynix Date: Sun, 2 Aug 2020 20:42:51 +0200 Subject: [PATCH 076/105] WIP --- include/Nazara/Renderer/ShaderVariables.hpp | 3 +- include/Nazara/Renderer/SpirvWriter.hpp | 43 +- include/Nazara/Renderer/SpirvWriter.inl | 56 +- src/Nazara/Renderer/SpirvWriter.cpp | 426 ++++- src/Nazara/VulkanRenderer/Vulkan.cpp | 2 +- thirdparty/include/tsl/ordered_hash.h | 1628 +++++++++++++++++++ thirdparty/include/tsl/ordered_map.h | 863 ++++++++++ thirdparty/include/tsl/ordered_set.h | 718 ++++++++ 8 files changed, 3626 insertions(+), 113 deletions(-) create mode 100644 thirdparty/include/tsl/ordered_hash.h create mode 100644 thirdparty/include/tsl/ordered_map.h create mode 100644 thirdparty/include/tsl/ordered_set.h diff --git a/include/Nazara/Renderer/ShaderVariables.hpp b/include/Nazara/Renderer/ShaderVariables.hpp index 9b52d3913..4fac1681f 100644 --- a/include/Nazara/Renderer/ShaderVariables.hpp +++ b/include/Nazara/Renderer/ShaderVariables.hpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -27,7 +28,7 @@ namespace Nz using VariablePtr = std::shared_ptr; - struct NAZARA_RENDERER_API Variable + struct NAZARA_RENDERER_API Variable : std::enable_shared_from_this { virtual ~Variable(); diff --git a/include/Nazara/Renderer/SpirvWriter.hpp b/include/Nazara/Renderer/SpirvWriter.hpp index 6cc4bb780..e95bc5a4e 100644 --- a/include/Nazara/Renderer/SpirvWriter.hpp +++ b/include/Nazara/Renderer/SpirvWriter.hpp @@ -13,13 +13,13 @@ #include #include #include -#include +#include #include #include namespace Nz { - class NAZARA_RENDERER_API SpirvWriter : public ShaderVarVisitor, public ShaderVisitor + class NAZARA_RENDERER_API SpirvWriter : public ShaderVisitor { public: struct Environment; @@ -35,48 +35,54 @@ namespace Nz struct Environment { + UInt32 spvMajorVersion = 1; + UInt32 spvMinorVersion = 0; }; private: struct Opcode; - inline void Append(const char* str); - void Append(const std::string_view& str); - void Append(const Opcode& opcode, unsigned int wordCount); - void Append(UInt32 codepoint); - void Append(std::initializer_list codepoints); - template void Append(Opcode opcode, const Args&... args); - template void Append(T value); + inline std::size_t Append(const char* str); + inline std::size_t Append(const std::string_view& str); + inline std::size_t Append(const std::string& str); + std::size_t Append(UInt32 value); + std::size_t Append(const Opcode& opcode, unsigned int wordCount); + inline std::size_t Append(std::initializer_list codepoints); + template std::size_t Append(Opcode opcode, const Args&... args); + template std::size_t Append(T value); + + UInt32 AllocateResultId(); void AppendHeader(); + void AppendTypes(); inline unsigned int CountWord(const char* str); unsigned int CountWord(const std::string_view& str); + inline unsigned int CountWord(const std::string& str); template unsigned int CountWord(const T& value); template unsigned int CountWord(const T1& value, const T2& value2, const Args&... rest); - using ShaderVarVisitor::Visit; + std::size_t GetOutputOffset() const; + + UInt32 ProcessType(ShaderExpressionType type); + using ShaderVisitor::Visit; void Visit(const ShaderNodes::ExpressionPtr& expr, bool encloseIfRequired = false); void Visit(const ShaderNodes::AccessMember& node) override; void Visit(const ShaderNodes::AssignOp& node) override; void Visit(const ShaderNodes::Branch& node) override; void Visit(const ShaderNodes::BinaryOp& node) override; - void Visit(const ShaderNodes::BuiltinVariable& var) override; void Visit(const ShaderNodes::Cast& node) override; void Visit(const ShaderNodes::Constant& node) override; void Visit(const ShaderNodes::DeclareVariable& node) override; void Visit(const ShaderNodes::ExpressionStatement& node) override; void Visit(const ShaderNodes::Identifier& node) override; - void Visit(const ShaderNodes::InputVariable& var) override; void Visit(const ShaderNodes::IntrinsicCall& node) override; - void Visit(const ShaderNodes::LocalVariable& var) override; - void Visit(const ShaderNodes::ParameterVariable& var) override; - void Visit(const ShaderNodes::OutputVariable& var) override; void Visit(const ShaderNodes::Sample2D& node) override; void Visit(const ShaderNodes::StatementBlock& node) override; void Visit(const ShaderNodes::SwizzleOp& node) override; - void Visit(const ShaderNodes::UniformVariable& var) override; + + static void MergeBlocks(std::vector& output, const std::vector& from); struct Context { @@ -84,10 +90,7 @@ namespace Nz const ShaderAst::Function* currentFunction = nullptr; }; - struct State - { - std::vector output; - }; + struct State; Context m_context; Environment m_environment; diff --git a/include/Nazara/Renderer/SpirvWriter.inl b/include/Nazara/Renderer/SpirvWriter.inl index 366e8ac46..5d0bbd328 100644 --- a/include/Nazara/Renderer/SpirvWriter.inl +++ b/include/Nazara/Renderer/SpirvWriter.inl @@ -9,25 +9,62 @@ namespace Nz { - inline void SpirvWriter::Append(const char* str) + inline std::size_t SpirvWriter::Append(const char* str) { return Append(std::string_view(str)); } - template - void SpirvWriter::Append(T value) + inline std::size_t SpirvWriter::Append(const std::string_view& str) { - assert(m_currentState); - m_currentState->output.push_back(static_cast(value)); + 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); + } + + return offset; + } + + inline std::size_t SpirvWriter::Append(const std::string& str) + { + return Append(std::string_view(str)); + } + + inline std::size_t SpirvWriter::Append(std::initializer_list codepoints) + { + std::size_t offset = GetOutputOffset(); + + for (UInt32 cp : codepoints) + Append(cp); + + return offset; } template - inline void SpirvWriter::Append(Opcode opcode, const Args&... args) + inline std::size_t SpirvWriter::Append(Opcode opcode, const Args&... args) { unsigned int wordCount = 1 + (CountWord(args) + ... + 0); - Append(opcode, wordCount); + std::size_t offset = Append(opcode, wordCount); if constexpr (sizeof...(args) > 0) (Append(args), ...); + + return offset; + } + + template + inline std::size_t SpirvWriter::Append(T value) + { + return Append(static_cast(value)); } template @@ -47,6 +84,11 @@ namespace Nz return CountWord(std::string_view(str)); } + inline unsigned int Nz::SpirvWriter::CountWord(const std::string& str) + { + return CountWord(std::string_view(str)); + } + inline unsigned int SpirvWriter::CountWord(const std::string_view& str) { return (static_cast(str.size() + 1) + sizeof(UInt32) - 1) / sizeof(UInt32); //< + 1 for null character diff --git a/src/Nazara/Renderer/SpirvWriter.cpp b/src/Nazara/Renderer/SpirvWriter.cpp index ea74e5066..24d9fcd84 100644 --- a/src/Nazara/Renderer/SpirvWriter.cpp +++ b/src/Nazara/Renderer/SpirvWriter.cpp @@ -5,19 +5,119 @@ #include #include #include +#include #include #include #include #include +#include +#include #include namespace Nz { + namespace + { + class PreVisitor : public ShaderRecursiveVisitor, public ShaderVarVisitor + { + public: + using BuiltinContainer = std::unordered_set>; + using ExtInstList = std::unordered_set; + using LocalContainer = std::unordered_set>; + using ParameterContainer = std::unordered_set< std::shared_ptr>; + + using ShaderRecursiveVisitor::Visit; + using ShaderVarVisitor::Visit; + + void Visit(const ShaderNodes::DeclareVariable& node) override + { + Visit(node.variable); + } + + void Visit(const ShaderNodes::Identifier& node) override + { + Visit(node.var); + } + + void Visit(const ShaderNodes::IntrinsicCall& node) override + { + ShaderRecursiveVisitor::Visit(node); + + switch (node.intrinsic) + { + // Require GLSL.std.450 + case ShaderNodes::IntrinsicType::CrossProduct: + extInsts.emplace("GLSL.std.450"); + break; + + // Part of SPIR-V core + case ShaderNodes::IntrinsicType::DotProduct: + break; + } + } + + void Visit(const ShaderNodes::BuiltinVariable& var) override + { + builtinVars.insert(std::static_pointer_cast(var.shared_from_this())); + } + + void Visit(const ShaderNodes::InputVariable& var) override + { + /* Handled by ShaderAst */ + } + + void Visit(const ShaderNodes::LocalVariable& var) override + { + localVars.insert(std::static_pointer_cast(var.shared_from_this())); + } + + void Visit(const ShaderNodes::OutputVariable& var) override + { + /* Handled by ShaderAst */ + } + + void Visit(const ShaderNodes::ParameterVariable& var) override + { + paramVars.insert(std::static_pointer_cast(var.shared_from_this())); + } + + void Visit(const ShaderNodes::UniformVariable& var) override + { + /* Handled by ShaderAst */ + } + + BuiltinContainer builtinVars; + ExtInstList extInsts; + LocalContainer localVars; + ParameterContainer paramVars; + }; + } + struct SpirvWriter::Opcode { SpvOp op; }; + struct SpirvWriter::State + { + std::size_t boundIndex; + std::unordered_map extensionInstructions; + std::unordered_map builtinIds; + tsl::ordered_map typeIds; + std::vector funcIds; + std::vector funcTypeIds; + std::vector inputIds; + std::vector outputIds; + std::vector uniformIds; + UInt32 nextVarIndex = 1; + + // Output + std::vector* output; + std::vector header; + std::vector info; + std::vector instructions; + }; + SpirvWriter::SpirvWriter() : m_currentState(nullptr) { @@ -38,63 +138,78 @@ namespace Nz m_currentState = nullptr; }); + PreVisitor preVisitor; + for (const auto& func : shader.GetFunctions()) + preVisitor.Visit(func.statement); + + // Register all extended instruction sets + for (const std::string& extInst : preVisitor.extInsts) + m_currentState->extensionInstructions[extInst] = AllocateResultId(); + + // Register all types + state.output = &state.instructions; + + for (const auto& func : shader.GetFunctions()) + { + ProcessType(func.returnType); + for (const auto& param : func.parameters) + ProcessType(param.type); + + m_currentState->funcTypeIds.push_back(AllocateResultId()); + } + + for (const auto& input : shader.GetInputs()) + ProcessType(input.type); + + for (const auto& output : shader.GetOutputs()) + ProcessType(output.type); + + for (const auto& uniform : shader.GetUniforms()) + ProcessType(uniform.type); + + for (const auto& local : preVisitor.localVars) + ProcessType(local->type); + + // Register result id and debug infos for global variables/functions + state.output = &state.info; + + for (const auto& input : shader.GetInputs()) + { + UInt32 resultId = AllocateResultId(); + Append(Opcode{ SpvOpName }, resultId, input.name); + + m_currentState->inputIds.push_back(resultId); + } + + for (const auto& output : shader.GetOutputs()) + { + UInt32 resultId = AllocateResultId(); + Append(Opcode{ SpvOpName }, resultId, output.name); + + m_currentState->outputIds.push_back(resultId); + } + + for (const auto& uniform : shader.GetUniforms()) + { + UInt32 resultId = AllocateResultId(); + Append(Opcode{ SpvOpName }, resultId, uniform.name); + + m_currentState->uniformIds.push_back(resultId); + } + + for (const auto& func : shader.GetFunctions()) + { + UInt32 resultId = AllocateResultId(); + Append(Opcode{ SpvOpName }, resultId, func.name); + + m_currentState->funcIds.push_back(resultId); + } + + state.output = &state.header; + AppendHeader(); - std::vector ret = std::move(state.output); - return ret; - } - - void SpirvWriter::SetEnv(Environment environment) - { - m_environment = std::move(environment); - } - - void SpirvWriter::Append(const std::string_view& str) - { - 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); - } - } - - void SpirvWriter::Append(const Opcode& opcode, unsigned int wordCount) - { - Append(UInt32(opcode.op) | UInt32(wordCount) << 16); - } - - void SpirvWriter::Append(UInt32 codepoint) - { - assert(m_currentState); - m_currentState->output.push_back(codepoint); - } - - void SpirvWriter::Append(std::initializer_list codepoints) - { - for (UInt32 cp : codepoints) - Append(cp); - } - - void SpirvWriter::AppendHeader() - { - Append(SpvMagicNumber); //< Spir-V magic number - Append(0x00010000); //< Spir-V version number (1.0 for compatibility) - Append(0); //< Generator magic number (TODO: Register generator to Khronos) - Append(1); //< Bound (ID count) - Append(0); //< Instruction schema (required to be 0 for now) - Append(Opcode{ SpvOpCapability }, SpvCapabilityShader); - Append(Opcode{ SpvOpExtInstImport }, 1, "GLSL.std.450"); - Append(Opcode{ SpvOpMemoryModel }, SpvAddressingModelLogical, SpvMemoryModelGLSL450); - - assert(m_context.shader); + /*assert(m_context.shader); switch (m_context.shader->GetStage()) { case ShaderStageType::Fragment: @@ -104,67 +219,210 @@ namespace Nz default: break; + }*/ + + state.header[state.boundIndex] = state.nextVarIndex; + + std::vector ret; + ret.reserve(state.header.size() + state.info.size() + state.instructions.size()); + + MergeBlocks(ret, state.header); + MergeBlocks(ret, state.info); + MergeBlocks(ret, state.instructions); + + return ret; + } + + void SpirvWriter::SetEnv(Environment environment) + { + m_environment = std::move(environment); + } + + std::size_t Nz::SpirvWriter::Append(UInt32 value) + { + std::size_t offset = GetOutputOffset(); + m_currentState->output->push_back(value); + + return offset; + } + + std::size_t SpirvWriter::Append(const Opcode& opcode, unsigned int wordCount) + { + return Append(UInt32(opcode.op) | UInt32(wordCount) << 16); + } + + UInt32 Nz::SpirvWriter::AllocateResultId() + { + return m_currentState->nextVarIndex++; + } + + void SpirvWriter::AppendHeader() + { + Append(SpvMagicNumber); //< Spir-V magic number + + UInt32 version = (m_environment.spvMajorVersion << 16) | m_environment.spvMinorVersion << 8; + Append(version); //< Spir-V version number (1.0 for compatibility) + Append(0); //< Generator identifier (TODO: Register generator to Khronos) + + m_currentState->boundIndex = Append(0); //< Bound (ID count), will be filled later + Append(0); //< Instruction schema (required to be 0 for now) + + Append(Opcode{ SpvOpCapability }, SpvCapabilityShader); + + for (const auto& [extInst, resultId] : m_currentState->extensionInstructions) + Append(Opcode{ SpvOpExtInstImport }, resultId, extInst); + + Append(Opcode{ SpvOpMemoryModel }, SpvAddressingModelLogical, SpvMemoryModelGLSL450); + } + + void SpirvWriter::AppendTypes() + { + for (const auto& [type, typeId] : m_currentState->typeIds.values_container()) + { + UInt32 resultId = typeId; + + // Register sub-types, if any + std::visit([&](auto&& arg) + { + using T = std::decay_t; + if constexpr (std::is_same_v) + { + // In SPIR-V, vec3 (for example) depends on float + UInt32 depResultId; + if (ShaderNodes::Node::GetComponentCount(arg) != 1) + depResultId = ProcessType(ShaderNodes::Node::GetComponentType(arg)); + + switch (arg) + { + case ShaderNodes::BasicType::Boolean: + Append(Opcode{ SpvOpTypeBool }, resultId); + break; + + case ShaderNodes::BasicType::Float1: + Append(Opcode{ SpvOpTypeFloat }, resultId); + break; + + case ShaderNodes::BasicType::Float2: + case ShaderNodes::BasicType::Float3: + case ShaderNodes::BasicType::Float4: + case ShaderNodes::BasicType::Mat4x4: + case ShaderNodes::BasicType::Sampler2D: + case ShaderNodes::BasicType::Void: + Append(Opcode{ SpvOpTypeVoid }, resultId); + break; + } + } + else if constexpr (std::is_same_v) + { + // Register struct members type + const auto& structs = m_context.shader->GetStructs(); + auto it = std::find_if(structs.begin(), structs.end(), [&](const auto& s) { return s.name == arg; }); + if (it == structs.end()) + throw std::runtime_error("struct " + arg + " has not been defined"); + + const ShaderAst::Struct& s = *it; + for (const auto& member : s.members) + ProcessType(member.type); + } + else + static_assert(AlwaysFalse::value, "non-exhaustive visitor"); + }, type); } } + std::size_t SpirvWriter::GetOutputOffset() const + { + assert(m_currentState); + return m_currentState->output->size(); + } + + UInt32 SpirvWriter::ProcessType(ShaderExpressionType type) + { + auto it = m_currentState->typeIds.find(type); + if (it == m_currentState->typeIds.end()) + { + // Register sub-types, if any + std::visit([&](auto&& arg) + { + using T = std::decay_t; + if constexpr (std::is_same_v) + { + // In SPIR-V, vec3 (for example) depends on float + if (ShaderNodes::Node::GetComponentCount(arg) != 1) + ProcessType(ShaderNodes::Node::GetComponentType(arg)); + } + else if constexpr (std::is_same_v) + { + // Register struct members type + const auto& structs = m_context.shader->GetStructs(); + auto it = std::find_if(structs.begin(), structs.end(), [&](const auto& s) { return s.name == arg; }); + if (it == structs.end()) + throw std::runtime_error("struct " + arg + " has not been defined"); + + const ShaderAst::Struct& s = *it; + for (const auto& member : s.members) + ProcessType(member.type); + } + else + static_assert(AlwaysFalse::value, "non-exhaustive visitor"); + }, type); + + it = m_currentState->typeIds.emplace(std::move(type), AllocateResultId()).first; + } + + return it->second; + } + void SpirvWriter::Visit(const ShaderNodes::ExpressionPtr& expr, bool encloseIfRequired) { } - void SpirvWriter::Visit(const ShaderNodes::AccessMember& node) + void SpirvWriter::Visit(const ShaderNodes::AccessMember& /*node*/) { } - void SpirvWriter::Visit(const ShaderNodes::AssignOp& node) + void SpirvWriter::Visit(const ShaderNodes::AssignOp& /*node*/) { } - void SpirvWriter::Visit(const ShaderNodes::Branch& node) + void SpirvWriter::Visit(const ShaderNodes::Branch& /*node*/) { } - void SpirvWriter::Visit(const ShaderNodes::BinaryOp& node) + void SpirvWriter::Visit(const ShaderNodes::BinaryOp& /*node*/) { } - void SpirvWriter::Visit(const ShaderNodes::BuiltinVariable& var) + + void SpirvWriter::Visit(const ShaderNodes::Cast& /*node*/) { } - void SpirvWriter::Visit(const ShaderNodes::Cast& node) + void SpirvWriter::Visit(const ShaderNodes::Constant& /*node*/) { } - void SpirvWriter::Visit(const ShaderNodes::Constant& node) + void SpirvWriter::Visit(const ShaderNodes::DeclareVariable& /*node*/) { } - void SpirvWriter::Visit(const ShaderNodes::DeclareVariable& node) + void SpirvWriter::Visit(const ShaderNodes::ExpressionStatement& /*node*/) { } - void SpirvWriter::Visit(const ShaderNodes::ExpressionStatement& node) + void SpirvWriter::Visit(const ShaderNodes::Identifier& /*node*/) { } - void SpirvWriter::Visit(const ShaderNodes::Identifier& node) + + void SpirvWriter::Visit(const ShaderNodes::IntrinsicCall& /*node*/) { } - void SpirvWriter::Visit(const ShaderNodes::InputVariable& var) + + void SpirvWriter::Visit(const ShaderNodes::Sample2D& /*node*/) { } - void SpirvWriter::Visit(const ShaderNodes::IntrinsicCall& node) + void SpirvWriter::Visit(const ShaderNodes::StatementBlock& /*node*/) { } - void SpirvWriter::Visit(const ShaderNodes::LocalVariable& var) + void SpirvWriter::Visit(const ShaderNodes::SwizzleOp& /*node*/) { } - void SpirvWriter::Visit(const ShaderNodes::ParameterVariable& var) - { - } - void SpirvWriter::Visit(const ShaderNodes::OutputVariable& var) - { - } - void SpirvWriter::Visit(const ShaderNodes::Sample2D& node) - { - } - void SpirvWriter::Visit(const ShaderNodes::StatementBlock& node) - { - } - void SpirvWriter::Visit(const ShaderNodes::SwizzleOp& node) - { - } - void SpirvWriter::Visit(const ShaderNodes::UniformVariable& var) + + void SpirvWriter::MergeBlocks(std::vector& output, const std::vector& from) { + std::size_t prevSize = output.size(); + output.resize(prevSize + from.size()); + std::copy(from.begin(), from.end(), output.begin() + prevSize); } } diff --git a/src/Nazara/VulkanRenderer/Vulkan.cpp b/src/Nazara/VulkanRenderer/Vulkan.cpp index 4f55223e1..e6e2d4cfd 100644 --- a/src/Nazara/VulkanRenderer/Vulkan.cpp +++ b/src/Nazara/VulkanRenderer/Vulkan.cpp @@ -57,7 +57,7 @@ namespace Nz String appName = "Another application made with Nazara Engine"; String engineName = "Nazara Engine - Vulkan Renderer"; - UInt32 appVersion = VK_MAKE_VERSION(1, 0, 0); + constexpr UInt32 appVersion = VK_MAKE_VERSION(1, 0, 0); UInt32 engineVersion = VK_MAKE_VERSION(1, 0, 0); parameters.GetStringParameter("VkAppInfo_OverrideApplicationName", &appName); diff --git a/thirdparty/include/tsl/ordered_hash.h b/thirdparty/include/tsl/ordered_hash.h new file mode 100644 index 000000000..5fbbfcb01 --- /dev/null +++ b/thirdparty/include/tsl/ordered_hash.h @@ -0,0 +1,1628 @@ +/** + * MIT License + * + * Copyright (c) 2017 Thibaut Goetghebuer-Planchon + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef TSL_ORDERED_HASH_H +#define TSL_ORDERED_HASH_H + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/** + * Macros for compatibility with GCC 4.8 + */ +#if (defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ < 9)) +# define TSL_OH_NO_CONTAINER_ERASE_CONST_ITERATOR +# define TSL_OH_NO_CONTAINER_EMPLACE_CONST_ITERATOR +#endif + +/** + * Only activate tsl_oh_assert if TSL_DEBUG is defined. + * This way we avoid the performance hit when NDEBUG is not defined with assert as tsl_oh_assert is used a lot + * (people usually compile with "-O3" and not "-O3 -DNDEBUG"). + */ +#ifdef TSL_DEBUG +# define tsl_oh_assert(expr) assert(expr) +#else +# define tsl_oh_assert(expr) (static_cast(0)) +#endif + +/** + * If exceptions are enabled, throw the exception passed in parameter, otherwise call std::terminate. + */ +#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || (defined (_MSC_VER) && defined (_CPPUNWIND))) && !defined(TSL_NO_EXCEPTIONS) +# define TSL_OH_THROW_OR_TERMINATE(ex, msg) throw ex(msg) +#else +# define TSL_OH_NO_EXCEPTIONS +# ifdef NDEBUG +# define TSL_OH_THROW_OR_TERMINATE(ex, msg) std::terminate() +# else +# include +# define TSL_OH_THROW_OR_TERMINATE(ex, msg) do { std::cerr << msg << std::endl; std::terminate(); } while(0) +# endif +#endif + + +namespace tsl { + +namespace detail_ordered_hash { + +template +struct make_void { + using type = void; +}; + +template +struct has_is_transparent: std::false_type { +}; + +template +struct has_is_transparent::type>: std::true_type { +}; + + +template +struct is_vector: std::false_type { +}; + +template +struct is_vector>::value + >::type>: std::true_type { +}; + +// Only available in C++17, we need to be compatible with C++11 +template +const T& clamp( const T& v, const T& lo, const T& hi) { + return std::min(hi, std::max(lo, v)); +} + +template +static T numeric_cast(U value, const char* error_message = "numeric_cast() failed.") { + T ret = static_cast(value); + if(static_cast(ret) != value) { + TSL_OH_THROW_OR_TERMINATE(std::runtime_error, error_message); + } + + const bool is_same_signedness = (std::is_unsigned::value && std::is_unsigned::value) || + (std::is_signed::value && std::is_signed::value); + if(!is_same_signedness && (ret < T{}) != (value < U{})) { + TSL_OH_THROW_OR_TERMINATE(std::runtime_error, error_message); + } + + return ret; +} + + +/** + * Fixed size type used to represent size_type values on serialization. Need to be big enough + * to represent a std::size_t on 32 and 64 bits platforms, and must be the same size on both platforms. + */ +using slz_size_type = std::uint64_t; +static_assert(std::numeric_limits::max() >= std::numeric_limits::max(), + "slz_size_type must be >= std::size_t"); + +template +static T deserialize_value(Deserializer& deserializer) { + // MSVC < 2017 is not conformant, circumvent the problem by removing the template keyword +#if defined (_MSC_VER) && _MSC_VER < 1910 + return deserializer.Deserializer::operator()(); +#else + return deserializer.Deserializer::template operator()(); +#endif +} + + +/** + * Each bucket entry stores an index which is the index in m_values corresponding to the bucket's value + * and a hash (which may be truncated to 32 bits depending on IndexType) corresponding to the hash of the value. + * + * The size of IndexType limits the size of the hash table to std::numeric_limits::max() - 1 elements (-1 due to + * a reserved value used to mark a bucket as empty). + */ +template +class bucket_entry { + static_assert(std::is_unsigned::value, "IndexType must be an unsigned value."); + static_assert(std::numeric_limits::max() <= std::numeric_limits::max(), + "std::numeric_limits::max() must be <= std::numeric_limits::max()."); + +public: + using index_type = IndexType; + using truncated_hash_type = typename std::conditional::max() <= + std::numeric_limits::max(), + std::uint_least32_t, + std::size_t>::type; + + bucket_entry() noexcept: m_index(EMPTY_MARKER_INDEX), m_hash(0) { + } + + bool empty() const noexcept { + return m_index == EMPTY_MARKER_INDEX; + } + + void clear() noexcept { + m_index = EMPTY_MARKER_INDEX; + } + + index_type index() const noexcept { + tsl_oh_assert(!empty()); + return m_index; + } + + index_type& index_ref() noexcept { + tsl_oh_assert(!empty()); + return m_index; + } + + void set_index(index_type index) noexcept { + tsl_oh_assert(index <= max_size()); + + m_index = index; + } + + truncated_hash_type truncated_hash() const noexcept { + tsl_oh_assert(!empty()); + return m_hash; + } + + truncated_hash_type& truncated_hash_ref() noexcept { + tsl_oh_assert(!empty()); + return m_hash; + } + + void set_hash(std::size_t hash) noexcept { + m_hash = truncate_hash(hash); + } + + template + void serialize(Serializer& serializer) const { + const slz_size_type index = m_index; + serializer(index); + + const slz_size_type hash = m_hash; + serializer(hash); + } + + template + static bucket_entry deserialize(Deserializer& deserializer) { + const slz_size_type index = deserialize_value(deserializer); + const slz_size_type hash = deserialize_value(deserializer); + + bucket_entry bentry; + bentry.m_index = numeric_cast(index, "Deserialized index is too big."); + bentry.m_hash = numeric_cast(hash, "Deserialized hash is too big."); + + return bentry; + } + + + + static truncated_hash_type truncate_hash(std::size_t hash) noexcept { + return truncated_hash_type(hash); + } + + static std::size_t max_size() noexcept { + return static_cast(std::numeric_limits::max()) - NB_RESERVED_INDEXES; + } + +private: + static const index_type EMPTY_MARKER_INDEX = std::numeric_limits::max(); + static const std::size_t NB_RESERVED_INDEXES = 1; + + index_type m_index; + truncated_hash_type m_hash; +}; + + + +/** + * Internal common class used by ordered_map and ordered_set. + * + * ValueType is what will be stored by ordered_hash (usually std::pair for map and Key for set). + * + * KeySelect should be a FunctionObject which takes a ValueType in parameter and return a reference to the key. + * + * ValueSelect should be a FunctionObject which takes a ValueType in parameter and return a reference to the value. + * ValueSelect should be void if there is no value (in set for example). + * + * ValueTypeContainer is the container which will be used to store ValueType values. + * Usually a std::deque or std::vector. + * + * + * + * The ordered_hash structure is a hash table which preserves the order of insertion of the elements. + * To do so, it stores the values in the ValueTypeContainer (m_values) using emplace_back at each + * insertion of a new element. Another structure (m_buckets of type std::vector) will + * serve as buckets array for the hash table part. Each bucket stores an index which corresponds to + * the index in m_values where the bucket's value is and the (truncated) hash of this value. An index + * is used instead of a pointer to the value to reduce the size of each bucket entry. + * + * To resolve collisions in the buckets array, the structures use robin hood linear probing with + * backward shift deletion. + */ +template +class ordered_hash: private Hash, private KeyEqual { +private: + template + using has_mapped_type = typename std::integral_constant::value>; + + static_assert(std::is_same::value, + "ValueTypeContainer::value_type != ValueType. " + "Check that the ValueTypeContainer has 'Key' as type for a set or 'std::pair' as type for a map."); + + static_assert(std::is_same::value, + "ValueTypeContainer::allocator_type != Allocator. " + "Check that the allocator for ValueTypeContainer is the same as Allocator."); + + static_assert(std::is_same::value, + "Allocator::value_type != ValueType. " + "Check that the allocator has 'Key' as type for a set or 'std::pair' as type for a map."); + + +public: + template + class ordered_iterator; + + using key_type = typename KeySelect::key_type; + using value_type = ValueType; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + using hasher = Hash; + using key_equal = KeyEqual; + using allocator_type = Allocator; + using reference = value_type&; + using const_reference = const value_type&; + using pointer = value_type*; + using const_pointer = const value_type*; + using iterator = ordered_iterator; + using const_iterator = ordered_iterator; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + + using values_container_type = ValueTypeContainer; + +public: + template + class ordered_iterator { + friend class ordered_hash; + + private: + using iterator = typename std::conditional::type; + + + ordered_iterator(iterator it) noexcept: m_iterator(it) { + } + + public: + using iterator_category = std::random_access_iterator_tag; + using value_type = const typename ordered_hash::value_type; + using difference_type = typename iterator::difference_type; + using reference = value_type&; + using pointer = value_type*; + + + ordered_iterator() noexcept { + } + + // Copy constructor from iterator to const_iterator. + template::type* = nullptr> + ordered_iterator(const ordered_iterator& other) noexcept: m_iterator(other.m_iterator) { + } + + ordered_iterator(const ordered_iterator& other) = default; + ordered_iterator(ordered_iterator&& other) = default; + ordered_iterator& operator=(const ordered_iterator& other) = default; + ordered_iterator& operator=(ordered_iterator&& other) = default; + + const typename ordered_hash::key_type& key() const { + return KeySelect()(*m_iterator); + } + + template::value && IsConst>::type* = nullptr> + const typename U::value_type& value() const { + return U()(*m_iterator); + } + + template::value && !IsConst>::type* = nullptr> + typename U::value_type& value() { + return U()(*m_iterator); + } + + reference operator*() const { return *m_iterator; } + pointer operator->() const { return m_iterator.operator->(); } + + ordered_iterator& operator++() { ++m_iterator; return *this; } + ordered_iterator& operator--() { --m_iterator; return *this; } + + ordered_iterator operator++(int) { ordered_iterator tmp(*this); ++(*this); return tmp; } + ordered_iterator operator--(int) { ordered_iterator tmp(*this); --(*this); return tmp; } + + reference operator[](difference_type n) const { return m_iterator[n]; } + + ordered_iterator& operator+=(difference_type n) { m_iterator += n; return *this; } + ordered_iterator& operator-=(difference_type n) { m_iterator -= n; return *this; } + + ordered_iterator operator+(difference_type n) { ordered_iterator tmp(*this); tmp += n; return tmp; } + ordered_iterator operator-(difference_type n) { ordered_iterator tmp(*this); tmp -= n; return tmp; } + + friend bool operator==(const ordered_iterator& lhs, const ordered_iterator& rhs) { + return lhs.m_iterator == rhs.m_iterator; + } + + friend bool operator!=(const ordered_iterator& lhs, const ordered_iterator& rhs) { + return lhs.m_iterator != rhs.m_iterator; + } + + friend bool operator<(const ordered_iterator& lhs, const ordered_iterator& rhs) { + return lhs.m_iterator < rhs.m_iterator; + } + + friend bool operator>(const ordered_iterator& lhs, const ordered_iterator& rhs) { + return lhs.m_iterator > rhs.m_iterator; + } + + friend bool operator<=(const ordered_iterator& lhs, const ordered_iterator& rhs) { + return lhs.m_iterator <= rhs.m_iterator; + } + + friend bool operator>=(const ordered_iterator& lhs, const ordered_iterator& rhs) { + return lhs.m_iterator >= rhs.m_iterator; + } + + friend ordered_iterator operator+(difference_type n, const ordered_iterator& it) { + return n + it.m_iterator; + } + + friend difference_type operator-(const ordered_iterator& lhs, const ordered_iterator& rhs) { + return lhs.m_iterator - rhs.m_iterator; + } + + private: + iterator m_iterator; + }; + + +private: + using bucket_entry = tsl::detail_ordered_hash::bucket_entry; + + using buckets_container_allocator = typename + std::allocator_traits::template rebind_alloc; + + using buckets_container_type = std::vector; + + + using truncated_hash_type = typename bucket_entry::truncated_hash_type; + using index_type = typename bucket_entry::index_type; + +public: + ordered_hash(size_type bucket_count, + const Hash& hash, + const KeyEqual& equal, + const Allocator& alloc, + float max_load_factor): Hash(hash), + KeyEqual(equal), + m_buckets_data(alloc), + m_buckets(static_empty_bucket_ptr()), + m_hash_mask(0), + m_values(alloc), + m_grow_on_next_insert(false) + { + if(bucket_count > max_bucket_count()) { + TSL_OH_THROW_OR_TERMINATE(std::length_error, "The map exceeds its maximum size."); + } + + if(bucket_count > 0) { + bucket_count = round_up_to_power_of_two(bucket_count); + + m_buckets_data.resize(bucket_count); + m_buckets = m_buckets_data.data(), + m_hash_mask = bucket_count - 1; + } + + this->max_load_factor(max_load_factor); + } + + ordered_hash(const ordered_hash& other): Hash(other), + KeyEqual(other), + m_buckets_data(other.m_buckets_data), + m_buckets(m_buckets_data.empty()?static_empty_bucket_ptr(): + m_buckets_data.data()), + m_hash_mask(other.m_hash_mask), + m_values(other.m_values), + m_load_threshold(other.m_load_threshold), + m_max_load_factor(other.m_max_load_factor), + m_grow_on_next_insert(other.m_grow_on_next_insert) + { + } + + ordered_hash(ordered_hash&& other) noexcept(std::is_nothrow_move_constructible::value && + std::is_nothrow_move_constructible::value && + std::is_nothrow_move_constructible::value && + std::is_nothrow_move_constructible::value) + : Hash(std::move(static_cast(other))), + KeyEqual(std::move(static_cast(other))), + m_buckets_data(std::move(other.m_buckets_data)), + m_buckets(m_buckets_data.empty()?static_empty_bucket_ptr(): + m_buckets_data.data()), + m_hash_mask(other.m_hash_mask), + m_values(std::move(other.m_values)), + m_load_threshold(other.m_load_threshold), + m_max_load_factor(other.m_max_load_factor), + m_grow_on_next_insert(other.m_grow_on_next_insert) + { + other.m_buckets_data.clear(); + other.m_buckets = static_empty_bucket_ptr(); + other.m_hash_mask = 0; + other.m_values.clear(); + other.m_load_threshold = 0; + other.m_grow_on_next_insert = false; + } + + ordered_hash& operator=(const ordered_hash& other) { + if(&other != this) { + Hash::operator=(other); + KeyEqual::operator=(other); + + m_buckets_data = other.m_buckets_data; + m_buckets = m_buckets_data.empty()?static_empty_bucket_ptr(): + m_buckets_data.data(); + + m_hash_mask = other.m_hash_mask; + m_values = other.m_values; + m_load_threshold = other.m_load_threshold; + m_max_load_factor = other.m_max_load_factor; + m_grow_on_next_insert = other.m_grow_on_next_insert; + } + + return *this; + } + + ordered_hash& operator=(ordered_hash&& other) { + other.swap(*this); + other.clear(); + + return *this; + } + + allocator_type get_allocator() const { + return m_values.get_allocator(); + } + + + /* + * Iterators + */ + iterator begin() noexcept { + return iterator(m_values.begin()); + } + + const_iterator begin() const noexcept { + return cbegin(); + } + + const_iterator cbegin() const noexcept { + return const_iterator(m_values.cbegin()); + } + + iterator end() noexcept { + return iterator(m_values.end()); + } + + const_iterator end() const noexcept { + return cend(); + } + + const_iterator cend() const noexcept { + return const_iterator(m_values.cend()); + } + + + reverse_iterator rbegin() noexcept { + return reverse_iterator(m_values.end()); + } + + const_reverse_iterator rbegin() const noexcept { + return rcbegin(); + } + + const_reverse_iterator rcbegin() const noexcept { + return const_reverse_iterator(m_values.cend()); + } + + reverse_iterator rend() noexcept { + return reverse_iterator(m_values.begin()); + } + + const_reverse_iterator rend() const noexcept { + return rcend(); + } + + const_reverse_iterator rcend() const noexcept { + return const_reverse_iterator(m_values.cbegin()); + } + + + /* + * Capacity + */ + bool empty() const noexcept { + return m_values.empty(); + } + + size_type size() const noexcept { + return m_values.size(); + } + + size_type max_size() const noexcept { + return std::min(bucket_entry::max_size(), m_values.max_size()); + } + + + /* + * Modifiers + */ + void clear() noexcept { + for(auto& bucket: m_buckets_data) { + bucket.clear(); + } + + m_values.clear(); + m_grow_on_next_insert = false; + } + + template + std::pair insert(P&& value) { + return insert_impl(KeySelect()(value), std::forward

(value)); + } + + template + iterator insert_hint(const_iterator hint, P&& value) { + if(hint != cend() && compare_keys(KeySelect()(*hint), KeySelect()(value))) { + return mutable_iterator(hint); + } + + return insert(std::forward

(value)).first; + } + + template + void insert(InputIt first, InputIt last) { + if(std::is_base_of::iterator_category>::value) + { + const auto nb_elements_insert = std::distance(first, last); + const size_type nb_free_buckets = m_load_threshold - size(); + tsl_oh_assert(m_load_threshold >= size()); + + if(nb_elements_insert > 0 && nb_free_buckets < size_type(nb_elements_insert)) { + reserve(size() + size_type(nb_elements_insert)); + } + } + + for(; first != last; ++first) { + insert(*first); + } + } + + + + template + std::pair insert_or_assign(K&& key, M&& value) { + auto it = try_emplace(std::forward(key), std::forward(value)); + if(!it.second) { + it.first.value() = std::forward(value); + } + + return it; + } + + template + iterator insert_or_assign(const_iterator hint, K&& key, M&& obj) { + if(hint != cend() && compare_keys(KeySelect()(*hint), key)) { + auto it = mutable_iterator(hint); + it.value() = std::forward(obj); + + return it; + } + + return insert_or_assign(std::forward(key), std::forward(obj)).first; + } + + + + template + std::pair emplace(Args&&... args) { + return insert(value_type(std::forward(args)...)); + } + + template + iterator emplace_hint(const_iterator hint, Args&&... args) { + return insert_hint(hint, value_type(std::forward(args)...)); + } + + + + template + std::pair try_emplace(K&& key, Args&&... value_args) { + return insert_impl(key, std::piecewise_construct, + std::forward_as_tuple(std::forward(key)), + std::forward_as_tuple(std::forward(value_args)...)); + } + + template + iterator try_emplace_hint(const_iterator hint, K&& key, Args&&... args) { + if(hint != cend() && compare_keys(KeySelect()(*hint), key)) { + return mutable_iterator(hint); + } + + return try_emplace(std::forward(key), std::forward(args)...).first; + } + + + + /** + * Here to avoid `template size_type erase(const K& key)` being used when + * we use an `iterator` instead of a `const_iterator`. + */ + iterator erase(iterator pos) { + return erase(const_iterator(pos)); + } + + iterator erase(const_iterator pos) { + tsl_oh_assert(pos != cend()); + + const std::size_t index_erase = iterator_to_index(pos); + + auto it_bucket = find_key(pos.key(), hash_key(pos.key())); + tsl_oh_assert(it_bucket != m_buckets_data.end()); + + erase_value_from_bucket(it_bucket); + + /* + * One element was removed from m_values, due to the left shift the next element + * is now at the position of the previous element (or end if none). + */ + return begin() + index_erase; + } + + iterator erase(const_iterator first, const_iterator last) { + if(first == last) { + return mutable_iterator(first); + } + + tsl_oh_assert(std::distance(first, last) > 0); + const std::size_t start_index = iterator_to_index(first); + const std::size_t nb_values = std::size_t(std::distance(first, last)); + const std::size_t end_index = start_index + nb_values; + + // Delete all values +#ifdef TSL_OH_NO_CONTAINER_ERASE_CONST_ITERATOR + auto next_it = m_values.erase(mutable_iterator(first).m_iterator, mutable_iterator(last).m_iterator); +#else + auto next_it = m_values.erase(first.m_iterator, last.m_iterator); +#endif + + /* + * Mark the buckets corresponding to the values as empty and do a backward shift. + * + * Also, the erase operation on m_values has shifted all the values on the right of last.m_iterator. + * Adapt the indexes for these values. + */ + std::size_t ibucket = 0; + while(ibucket < m_buckets_data.size()) { + if(m_buckets[ibucket].empty()) { + ibucket++; + } + else if(m_buckets[ibucket].index() >= start_index && m_buckets[ibucket].index() < end_index) { + m_buckets[ibucket].clear(); + backward_shift(ibucket); + // Don't increment ibucket, backward_shift may have replaced current bucket. + } + else if(m_buckets[ibucket].index() >= end_index) { + m_buckets[ibucket].set_index(index_type(m_buckets[ibucket].index() - nb_values)); + ibucket++; + } + else { + ibucket++; + } + } + + return iterator(next_it); + } + + + template + size_type erase(const K& key) { + return erase(key, hash_key(key)); + } + + template + size_type erase(const K& key, std::size_t hash) { + return erase_impl(key, hash); + } + + void swap(ordered_hash& other) { + using std::swap; + + swap(static_cast(*this), static_cast(other)); + swap(static_cast(*this), static_cast(other)); + swap(m_buckets_data, other.m_buckets_data); + swap(m_buckets, other.m_buckets); + swap(m_hash_mask, other.m_hash_mask); + swap(m_values, other.m_values); + swap(m_load_threshold, other.m_load_threshold); + swap(m_max_load_factor, other.m_max_load_factor); + swap(m_grow_on_next_insert, other.m_grow_on_next_insert); + } + + + + + /* + * Lookup + */ + template::value>::type* = nullptr> + typename U::value_type& at(const K& key) { + return at(key, hash_key(key)); + } + + template::value>::type* = nullptr> + typename U::value_type& at(const K& key, std::size_t hash) { + return const_cast(static_cast(this)->at(key, hash)); + } + + template::value>::type* = nullptr> + const typename U::value_type& at(const K& key) const { + return at(key, hash_key(key)); + } + + template::value>::type* = nullptr> + const typename U::value_type& at(const K& key, std::size_t hash) const { + auto it = find(key, hash); + if(it != end()) { + return it.value(); + } + else { + TSL_OH_THROW_OR_TERMINATE(std::out_of_range, "Couldn't find the key."); + } + } + + + template::value>::type* = nullptr> + typename U::value_type& operator[](K&& key) { + return try_emplace(std::forward(key)).first.value(); + } + + + template + size_type count(const K& key) const { + return count(key, hash_key(key)); + } + + template + size_type count(const K& key, std::size_t hash) const { + if(find(key, hash) == cend()) { + return 0; + } + else { + return 1; + } + } + + template + iterator find(const K& key) { + return find(key, hash_key(key)); + } + + template + iterator find(const K& key, std::size_t hash) { + auto it_bucket = find_key(key, hash); + return (it_bucket != m_buckets_data.end())?iterator(m_values.begin() + it_bucket->index()):end(); + } + + template + const_iterator find(const K& key) const { + return find(key, hash_key(key)); + } + + template + const_iterator find(const K& key, std::size_t hash) const { + auto it_bucket = find_key(key, hash); + return (it_bucket != m_buckets_data.cend())?const_iterator(m_values.begin() + it_bucket->index()):end(); + } + + + template + bool contains(const K& key) const { + return contains(key, hash_key(key)); + } + + template + bool contains(const K& key, std::size_t hash) const { + return find(key, hash) != cend(); + } + + + template + std::pair equal_range(const K& key) { + return equal_range(key, hash_key(key)); + } + + template + std::pair equal_range(const K& key, std::size_t hash) { + iterator it = find(key, hash); + return std::make_pair(it, (it == end())?it:std::next(it)); + } + + template + std::pair equal_range(const K& key) const { + return equal_range(key, hash_key(key)); + } + + template + std::pair equal_range(const K& key, std::size_t hash) const { + const_iterator it = find(key, hash); + return std::make_pair(it, (it == cend())?it:std::next(it)); + } + + + /* + * Bucket interface + */ + size_type bucket_count() const { + return m_buckets_data.size(); + } + + size_type max_bucket_count() const { + return m_buckets_data.max_size(); + } + + /* + * Hash policy + */ + float load_factor() const { + if(bucket_count() == 0) { + return 0; + } + + return float(size())/float(bucket_count()); + } + + float max_load_factor() const { + return m_max_load_factor; + } + + void max_load_factor(float ml) { + m_max_load_factor = clamp(ml, float(MAX_LOAD_FACTOR__MINIMUM), + float(MAX_LOAD_FACTOR__MAXIMUM)); + + m_max_load_factor = ml; + m_load_threshold = size_type(float(bucket_count())*m_max_load_factor); + } + + void rehash(size_type count) { + count = std::max(count, size_type(std::ceil(float(size())/max_load_factor()))); + rehash_impl(count); + } + + void reserve(size_type count) { + reserve_space_for_values(count); + + count = size_type(std::ceil(float(count)/max_load_factor())); + rehash(count); + } + + + /* + * Observers + */ + hasher hash_function() const { + return static_cast(*this); + } + + key_equal key_eq() const { + return static_cast(*this); + } + + + /* + * Other + */ + iterator mutable_iterator(const_iterator pos) { + return iterator(m_values.begin() + iterator_to_index(pos)); + } + + iterator nth(size_type index) { + tsl_oh_assert(index <= size()); + return iterator(m_values.begin() + index); + } + + const_iterator nth(size_type index) const { + tsl_oh_assert(index <= size()); + return const_iterator(m_values.cbegin() + index); + } + + const_reference front() const { + tsl_oh_assert(!empty()); + return m_values.front(); + } + + const_reference back() const { + tsl_oh_assert(!empty()); + return m_values.back(); + } + + const values_container_type& values_container() const noexcept { + return m_values; + } + + template::value>::type* = nullptr> + const typename values_container_type::value_type* data() const noexcept { + return m_values.data(); + } + + template::value>::type* = nullptr> + size_type capacity() const noexcept { + return m_values.capacity(); + } + + void shrink_to_fit() { + m_values.shrink_to_fit(); + } + + + template + std::pair insert_at_position(const_iterator pos, P&& value) { + return insert_at_position_impl(pos.m_iterator, KeySelect()(value), std::forward

(value)); + } + + template + std::pair emplace_at_position(const_iterator pos, Args&&... args) { + return insert_at_position(pos, value_type(std::forward(args)...)); + } + + template + std::pair try_emplace_at_position(const_iterator pos, K&& key, Args&&... value_args) { + return insert_at_position_impl(pos.m_iterator, key, + std::piecewise_construct, + std::forward_as_tuple(std::forward(key)), + std::forward_as_tuple(std::forward(value_args)...)); + } + + + void pop_back() { + tsl_oh_assert(!empty()); + erase(std::prev(end())); + } + + + /** + * Here to avoid `template size_type unordered_erase(const K& key)` being used when + * we use a iterator instead of a const_iterator. + */ + iterator unordered_erase(iterator pos) { + return unordered_erase(const_iterator(pos)); + } + + iterator unordered_erase(const_iterator pos) { + const std::size_t index_erase = iterator_to_index(pos); + unordered_erase(pos.key()); + + /* + * One element was deleted, index_erase now points to the next element as the elements after + * the deleted value were shifted to the left in m_values (will be end() if we deleted the last element). + */ + return begin() + index_erase; + } + + template + size_type unordered_erase(const K& key) { + return unordered_erase(key, hash_key(key)); + } + + template + size_type unordered_erase(const K& key, std::size_t hash) { + auto it_bucket_key = find_key(key, hash); + if(it_bucket_key == m_buckets_data.end()) { + return 0; + } + + /** + * If we are not erasing the last element in m_values, we swap + * the element we are erasing with the last element. We then would + * just have to do a pop_back() in m_values. + */ + if(!compare_keys(key, KeySelect()(back()))) { + auto it_bucket_last_elem = find_key(KeySelect()(back()), hash_key(KeySelect()(back()))); + tsl_oh_assert(it_bucket_last_elem != m_buckets_data.end()); + tsl_oh_assert(it_bucket_last_elem->index() == m_values.size() - 1); + + using std::swap; + swap(m_values[it_bucket_key->index()], m_values[it_bucket_last_elem->index()]); + swap(it_bucket_key->index_ref(), it_bucket_last_elem->index_ref()); + } + + erase_value_from_bucket(it_bucket_key); + + return 1; + } + + template + void serialize(Serializer& serializer) const { + serialize_impl(serializer); + } + + template + void deserialize(Deserializer& deserializer, bool hash_compatible) { + deserialize_impl(deserializer, hash_compatible); + } + + friend bool operator==(const ordered_hash& lhs, const ordered_hash& rhs) { + return lhs.m_values == rhs.m_values; + } + + friend bool operator!=(const ordered_hash& lhs, const ordered_hash& rhs) { + return lhs.m_values != rhs.m_values; + } + + friend bool operator<(const ordered_hash& lhs, const ordered_hash& rhs) { + return lhs.m_values < rhs.m_values; + } + + friend bool operator<=(const ordered_hash& lhs, const ordered_hash& rhs) { + return lhs.m_values <= rhs.m_values; + } + + friend bool operator>(const ordered_hash& lhs, const ordered_hash& rhs) { + return lhs.m_values > rhs.m_values; + } + + friend bool operator>=(const ordered_hash& lhs, const ordered_hash& rhs) { + return lhs.m_values >= rhs.m_values; + } + + +private: + template + std::size_t hash_key(const K& key) const { + return Hash::operator()(key); + } + + template + bool compare_keys(const K1& key1, const K2& key2) const { + return KeyEqual::operator()(key1, key2); + } + + template + typename buckets_container_type::iterator find_key(const K& key, std::size_t hash) { + auto it = static_cast(this)->find_key(key, hash); + return m_buckets_data.begin() + std::distance(m_buckets_data.cbegin(), it); + } + + /** + * Return bucket which has the key 'key' or m_buckets_data.end() if none. + * + * From the bucket_for_hash, search for the value until we either find an empty bucket + * or a bucket which has a value with a distance from its ideal bucket longer + * than the probe length for the value we are looking for. + */ + template + typename buckets_container_type::const_iterator find_key(const K& key, std::size_t hash) const { + for(std::size_t ibucket = bucket_for_hash(hash), dist_from_ideal_bucket = 0; ; + ibucket = next_bucket(ibucket), dist_from_ideal_bucket++) + { + if(m_buckets[ibucket].empty()) { + return m_buckets_data.end(); + } + else if(m_buckets[ibucket].truncated_hash() == bucket_entry::truncate_hash(hash) && + compare_keys(key, KeySelect()(m_values[m_buckets[ibucket].index()]))) + { + return m_buckets_data.begin() + ibucket; + } + else if(dist_from_ideal_bucket > distance_from_ideal_bucket(ibucket)) { + return m_buckets_data.end(); + } + } + } + + void rehash_impl(size_type bucket_count) { + tsl_oh_assert(bucket_count >= size_type(std::ceil(float(size())/max_load_factor()))); + + if(bucket_count > max_bucket_count()) { + TSL_OH_THROW_OR_TERMINATE(std::length_error, "The map exceeds its maximum size."); + } + + if(bucket_count > 0) { + bucket_count = round_up_to_power_of_two(bucket_count); + } + + if(bucket_count == this->bucket_count()) { + return; + } + + + buckets_container_type old_buckets(bucket_count); + m_buckets_data.swap(old_buckets); + m_buckets = m_buckets_data.empty()?static_empty_bucket_ptr(): + m_buckets_data.data(); + // Everything should be noexcept from here. + + m_hash_mask = (bucket_count > 0)?(bucket_count - 1):0; + this->max_load_factor(m_max_load_factor); + m_grow_on_next_insert = false; + + + + for(const bucket_entry& old_bucket: old_buckets) { + if(old_bucket.empty()) { + continue; + } + + truncated_hash_type insert_hash = old_bucket.truncated_hash(); + index_type insert_index = old_bucket.index(); + + for(std::size_t ibucket = bucket_for_hash(insert_hash), dist_from_ideal_bucket = 0; ; + ibucket = next_bucket(ibucket), dist_from_ideal_bucket++) + { + if(m_buckets[ibucket].empty()) { + m_buckets[ibucket].set_index(insert_index); + m_buckets[ibucket].set_hash(insert_hash); + break; + } + + const std::size_t distance = distance_from_ideal_bucket(ibucket); + if(dist_from_ideal_bucket > distance) { + std::swap(insert_index, m_buckets[ibucket].index_ref()); + std::swap(insert_hash, m_buckets[ibucket].truncated_hash_ref()); + dist_from_ideal_bucket = distance; + } + } + } + } + + template::value>::type* = nullptr> + void reserve_space_for_values(size_type count) { + m_values.reserve(count); + } + + template::value>::type* = nullptr> + void reserve_space_for_values(size_type /*count*/) { + } + + /** + * Swap the empty bucket with the values on its right until we cross another empty bucket + * or if the other bucket has a distance_from_ideal_bucket == 0. + */ + void backward_shift(std::size_t empty_ibucket) noexcept { + tsl_oh_assert(m_buckets[empty_ibucket].empty()); + + std::size_t previous_ibucket = empty_ibucket; + for(std::size_t current_ibucket = next_bucket(previous_ibucket); + !m_buckets[current_ibucket].empty() && distance_from_ideal_bucket(current_ibucket) > 0; + previous_ibucket = current_ibucket, current_ibucket = next_bucket(current_ibucket)) + { + std::swap(m_buckets[current_ibucket], m_buckets[previous_ibucket]); + } + } + + void erase_value_from_bucket(typename buckets_container_type::iterator it_bucket) { + tsl_oh_assert(it_bucket != m_buckets_data.end() && !it_bucket->empty()); + + m_values.erase(m_values.begin() + it_bucket->index()); + + /* + * m_values.erase shifted all the values on the right of the erased value, + * shift the indexes by -1 in the buckets array for these values. + */ + if(it_bucket->index() != m_values.size()) { + shift_indexes_in_buckets(it_bucket->index(), -1); + } + + // Mark the bucket as empty and do a backward shift of the values on the right + it_bucket->clear(); + backward_shift(std::size_t(std::distance(m_buckets_data.begin(), it_bucket))); + } + + /** + * Go through each value from [from_ivalue, m_values.size()) in m_values and for each + * bucket corresponding to the value, shift the index by delta. + * + * delta must be equal to 1 or -1. + */ + void shift_indexes_in_buckets(index_type from_ivalue, int delta) noexcept { + tsl_oh_assert(delta == 1 || delta == -1); + + for(std::size_t ivalue = from_ivalue; ivalue < m_values.size(); ivalue++) { + // All the values in m_values have been shifted by delta. Find the bucket corresponding + // to the value m_values[ivalue] + const index_type old_index = static_cast(ivalue - delta); + + std::size_t ibucket = bucket_for_hash(hash_key(KeySelect()(m_values[ivalue]))); + while(m_buckets[ibucket].index() != old_index) { + ibucket = next_bucket(ibucket); + } + + m_buckets[ibucket].set_index(index_type(ivalue)); + } + } + + template + size_type erase_impl(const K& key, std::size_t hash) { + auto it_bucket = find_key(key, hash); + if(it_bucket != m_buckets_data.end()) { + erase_value_from_bucket(it_bucket); + + return 1; + } + else { + return 0; + } + } + + /** + * Insert the element at the end. + */ + template + std::pair insert_impl(const K& key, Args&&... value_type_args) { + const std::size_t hash = hash_key(key); + + std::size_t ibucket = bucket_for_hash(hash); + std::size_t dist_from_ideal_bucket = 0; + + while(!m_buckets[ibucket].empty() && dist_from_ideal_bucket <= distance_from_ideal_bucket(ibucket)) { + if(m_buckets[ibucket].truncated_hash() == bucket_entry::truncate_hash(hash) && + compare_keys(key, KeySelect()(m_values[m_buckets[ibucket].index()]))) + { + return std::make_pair(begin() + m_buckets[ibucket].index(), false); + } + + ibucket = next_bucket(ibucket); + dist_from_ideal_bucket++; + } + + if(size() >= max_size()) { + TSL_OH_THROW_OR_TERMINATE(std::length_error, "We reached the maximum size for the hash table."); + } + + + if(grow_on_high_load()) { + ibucket = bucket_for_hash(hash); + dist_from_ideal_bucket = 0; + } + + + m_values.emplace_back(std::forward(value_type_args)...); + insert_index(ibucket, dist_from_ideal_bucket, + index_type(m_values.size() - 1), bucket_entry::truncate_hash(hash)); + + + return std::make_pair(std::prev(end()), true); + } + + /** + * Insert the element before insert_position. + */ + template + std::pair insert_at_position_impl(typename values_container_type::const_iterator insert_position, + const K& key, Args&&... value_type_args) + { + const std::size_t hash = hash_key(key); + + std::size_t ibucket = bucket_for_hash(hash); + std::size_t dist_from_ideal_bucket = 0; + + while(!m_buckets[ibucket].empty() && dist_from_ideal_bucket <= distance_from_ideal_bucket(ibucket)) { + if(m_buckets[ibucket].truncated_hash() == bucket_entry::truncate_hash(hash) && + compare_keys(key, KeySelect()(m_values[m_buckets[ibucket].index()]))) + { + return std::make_pair(begin() + m_buckets[ibucket].index(), false); + } + + ibucket = next_bucket(ibucket); + dist_from_ideal_bucket++; + } + + if(size() >= max_size()) { + TSL_OH_THROW_OR_TERMINATE(std::length_error, "We reached the maximum size for the hash table."); + } + + + if(grow_on_high_load()) { + ibucket = bucket_for_hash(hash); + dist_from_ideal_bucket = 0; + } + + + const index_type index_insert_position = index_type(std::distance(m_values.cbegin(), insert_position)); + +#ifdef TSL_OH_NO_CONTAINER_EMPLACE_CONST_ITERATOR + m_values.emplace(m_values.begin() + std::distance(m_values.cbegin(), insert_position), std::forward(value_type_args)...); +#else + m_values.emplace(insert_position, std::forward(value_type_args)...); +#endif + + insert_index(ibucket, dist_from_ideal_bucket, + index_insert_position, bucket_entry::truncate_hash(hash)); + + /* + * The insertion didn't happend at the end of the m_values container, + * we need to shift the indexes in m_buckets_data. + */ + if(index_insert_position != m_values.size() - 1) { + shift_indexes_in_buckets(index_insert_position + 1, 1); + } + + return std::make_pair(iterator(m_values.begin() + index_insert_position), true); + } + + void insert_index(std::size_t ibucket, std::size_t dist_from_ideal_bucket, + index_type index_insert, truncated_hash_type hash_insert) noexcept + { + while(!m_buckets[ibucket].empty()) { + const std::size_t distance = distance_from_ideal_bucket(ibucket); + if(dist_from_ideal_bucket > distance) { + std::swap(index_insert, m_buckets[ibucket].index_ref()); + std::swap(hash_insert, m_buckets[ibucket].truncated_hash_ref()); + + dist_from_ideal_bucket = distance; + } + + + ibucket = next_bucket(ibucket); + dist_from_ideal_bucket++; + + + if(dist_from_ideal_bucket > REHASH_ON_HIGH_NB_PROBES__NPROBES && !m_grow_on_next_insert && + load_factor() >= REHASH_ON_HIGH_NB_PROBES__MIN_LOAD_FACTOR) + { + // We don't want to grow the map now as we need this method to be noexcept. + // Do it on next insert. + m_grow_on_next_insert = true; + } + } + + + m_buckets[ibucket].set_index(index_insert); + m_buckets[ibucket].set_hash(hash_insert); + } + + std::size_t distance_from_ideal_bucket(std::size_t ibucket) const noexcept { + const std::size_t ideal_bucket = bucket_for_hash(m_buckets[ibucket].truncated_hash()); + + if(ibucket >= ideal_bucket) { + return ibucket - ideal_bucket; + } + // If the bucket is smaller than the ideal bucket for the value, there was a wrapping at the end of the + // bucket array due to the modulo. + else { + return (bucket_count() + ibucket) - ideal_bucket; + } + } + + std::size_t next_bucket(std::size_t index) const noexcept { + tsl_oh_assert(index < m_buckets_data.size()); + + index++; + return (index < m_buckets_data.size())?index:0; + } + + std::size_t bucket_for_hash(std::size_t hash) const noexcept { + return hash & m_hash_mask; + } + + std::size_t iterator_to_index(const_iterator it) const noexcept { + const auto dist = std::distance(cbegin(), it); + tsl_oh_assert(dist >= 0); + + return std::size_t(dist); + } + + /** + * Return true if the map has been rehashed. + */ + bool grow_on_high_load() { + if(m_grow_on_next_insert || size() >= m_load_threshold) { + rehash_impl(std::max(size_type(1), bucket_count() * 2)); + m_grow_on_next_insert = false; + + return true; + } + else { + return false; + } + } + + template + void serialize_impl(Serializer& serializer) const { + const slz_size_type version = SERIALIZATION_PROTOCOL_VERSION; + serializer(version); + + const slz_size_type nb_elements = m_values.size(); + serializer(nb_elements); + + const slz_size_type bucket_count = m_buckets_data.size(); + serializer(bucket_count); + + const float max_load_factor = m_max_load_factor; + serializer(max_load_factor); + + + for(const value_type& value: m_values) { + serializer(value); + } + + for(const bucket_entry& bucket: m_buckets_data) { + bucket.serialize(serializer); + } + } + + template + void deserialize_impl(Deserializer& deserializer, bool hash_compatible) { + tsl_oh_assert(m_buckets_data.empty()); // Current hash table must be empty + + const slz_size_type version = deserialize_value(deserializer); + // For now we only have one version of the serialization protocol. + // If it doesn't match there is a problem with the file. + if(version != SERIALIZATION_PROTOCOL_VERSION) { + TSL_OH_THROW_OR_TERMINATE(std::runtime_error, "Can't deserialize the ordered_map/set. " + "The protocol version header is invalid."); + } + + const slz_size_type nb_elements = deserialize_value(deserializer); + const slz_size_type bucket_count_ds = deserialize_value(deserializer); + const float max_load_factor = deserialize_value(deserializer); + + if(max_load_factor < MAX_LOAD_FACTOR__MINIMUM || max_load_factor > MAX_LOAD_FACTOR__MAXIMUM) { + TSL_OH_THROW_OR_TERMINATE(std::runtime_error, "Invalid max_load_factor. Check that the serializer " + "and deserializer support floats correctly as they " + "can be converted implicitly to ints."); + } + + + this->max_load_factor(max_load_factor); + + if(bucket_count_ds == 0) { + tsl_oh_assert(nb_elements == 0); + return; + } + + + if(!hash_compatible) { + reserve(numeric_cast(nb_elements, "Deserialized nb_elements is too big.")); + for(slz_size_type el = 0; el < nb_elements; el++) { + insert(deserialize_value(deserializer)); + } + } + else { + m_buckets_data.reserve(numeric_cast(bucket_count_ds, "Deserialized bucket_count is too big.")); + m_buckets = m_buckets_data.data(), + m_hash_mask = m_buckets_data.capacity() - 1; + + reserve_space_for_values(numeric_cast(nb_elements, "Deserialized nb_elements is too big.")); + for(slz_size_type el = 0; el < nb_elements; el++) { + m_values.push_back(deserialize_value(deserializer)); + } + + for(slz_size_type b = 0; b < bucket_count_ds; b++) { + m_buckets_data.push_back(bucket_entry::deserialize(deserializer)); + } + } + } + + static std::size_t round_up_to_power_of_two(std::size_t value) { + if(is_power_of_two(value)) { + return value; + } + + if(value == 0) { + return 1; + } + + --value; + for(std::size_t i = 1; i < sizeof(std::size_t) * CHAR_BIT; i *= 2) { + value |= value >> i; + } + + return value + 1; + } + + static constexpr bool is_power_of_two(std::size_t value) { + return value != 0 && (value & (value - 1)) == 0; + } + + +public: + static const size_type DEFAULT_INIT_BUCKETS_SIZE = 0; + static constexpr float DEFAULT_MAX_LOAD_FACTOR = 0.75f; + +private: + static constexpr float MAX_LOAD_FACTOR__MINIMUM = 0.1f; + static constexpr float MAX_LOAD_FACTOR__MAXIMUM = 0.95f; + + static const size_type REHASH_ON_HIGH_NB_PROBES__NPROBES = 128; + static constexpr float REHASH_ON_HIGH_NB_PROBES__MIN_LOAD_FACTOR = 0.15f; + + /** + * Protocol version currenlty used for serialization. + */ + static const slz_size_type SERIALIZATION_PROTOCOL_VERSION = 1; + + /** + * Return an always valid pointer to an static empty bucket_entry with last_bucket() == true. + */ + bucket_entry* static_empty_bucket_ptr() { + static bucket_entry empty_bucket; + return &empty_bucket; + } + +private: + buckets_container_type m_buckets_data; + + /** + * Points to m_buckets_data.data() if !m_buckets_data.empty() otherwise points to static_empty_bucket_ptr. + * This variable is useful to avoid the cost of checking if m_buckets_data is empty when trying + * to find an element. + * + * TODO Remove m_buckets_data and only use a pointer+size instead of a pointer+vector to save some space in the ordered_hash object. + */ + bucket_entry* m_buckets; + + size_type m_hash_mask; + + values_container_type m_values; + + size_type m_load_threshold; + float m_max_load_factor; + + bool m_grow_on_next_insert; +}; + + +} // end namespace detail_ordered_hash + +} // end namespace tsl + +#endif diff --git a/thirdparty/include/tsl/ordered_map.h b/thirdparty/include/tsl/ordered_map.h new file mode 100644 index 000000000..1a20ccae0 --- /dev/null +++ b/thirdparty/include/tsl/ordered_map.h @@ -0,0 +1,863 @@ +/** + * MIT License + * + * Copyright (c) 2017 Thibaut Goetghebuer-Planchon + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef TSL_ORDERED_MAP_H +#define TSL_ORDERED_MAP_H + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ordered_hash.h" + + +namespace tsl { + + +/** + * Implementation of an hash map using open addressing with robin hood with backshift delete to resolve collisions. + * + * The particularity of this hash map is that it remembers the order in which the elements were added and + * provide a way to access the structure which stores these values through the 'values_container()' method. + * The used container is defined by ValueTypeContainer, by default a std::deque is used (grows faster) but + * a std::vector may be used. In this case the map provides a 'data()' method which give a direct access + * to the memory used to store the values (which can be useful to communicate with C API's). + * + * The Key and T must be copy constructible and/or move constructible. To use `unordered_erase` they both + * must be swappable. + * + * The behaviour of the hash map is undefined if the destructor of Key or T throws an exception. + * + * By default the maximum size of a map is limited to 2^32 - 1 values, if needed this can be changed through + * the IndexType template parameter. Using an `uint64_t` will raise this limit to 2^64 - 1 values but each + * bucket will use 16 bytes instead of 8 bytes in addition to the space needed to store the values. + * + * Iterators invalidation: + * - clear, operator=, reserve, rehash: always invalidate the iterators (also invalidate end()). + * - insert, emplace, emplace_hint, operator[]: when a std::vector is used as ValueTypeContainer + * and if size() < capacity(), only end(). + * Otherwise all the iterators are invalidated if an insert occurs. + * - erase, unordered_erase: when a std::vector is used as ValueTypeContainer invalidate the iterator of + * the erased element and all the ones after the erased element (including end()). + * Otherwise all the iterators are invalidated if an erase occurs. + */ +template, + class KeyEqual = std::equal_to, + class Allocator = std::allocator>, + class ValueTypeContainer = std::deque, Allocator>, + class IndexType = std::uint_least32_t> +class ordered_map { +private: + template + using has_is_transparent = tsl::detail_ordered_hash::has_is_transparent; + + class KeySelect { + public: + using key_type = Key; + + const key_type& operator()(const std::pair& key_value) const noexcept { + return key_value.first; + } + + key_type& operator()(std::pair& key_value) noexcept { + return key_value.first; + } + }; + + class ValueSelect { + public: + using value_type = T; + + const value_type& operator()(const std::pair& key_value) const noexcept { + return key_value.second; + } + + value_type& operator()(std::pair& key_value) noexcept { + return key_value.second; + } + }; + + using ht = detail_ordered_hash::ordered_hash, KeySelect, ValueSelect, + Hash, KeyEqual, Allocator, ValueTypeContainer, IndexType>; + +public: + using key_type = typename ht::key_type; + using mapped_type = T; + using value_type = typename ht::value_type; + using size_type = typename ht::size_type; + using difference_type = typename ht::difference_type; + using hasher = typename ht::hasher; + using key_equal = typename ht::key_equal; + using allocator_type = typename ht::allocator_type; + using reference = typename ht::reference; + using const_reference = typename ht::const_reference; + using pointer = typename ht::pointer; + using const_pointer = typename ht::const_pointer; + using iterator = typename ht::iterator; + using const_iterator = typename ht::const_iterator; + using reverse_iterator = typename ht::reverse_iterator; + using const_reverse_iterator = typename ht::const_reverse_iterator; + + using values_container_type = typename ht::values_container_type; + + + /* + * Constructors + */ + ordered_map(): ordered_map(ht::DEFAULT_INIT_BUCKETS_SIZE) { + } + + explicit ordered_map(size_type bucket_count, + const Hash& hash = Hash(), + const KeyEqual& equal = KeyEqual(), + const Allocator& alloc = Allocator()): + m_ht(bucket_count, hash, equal, alloc, ht::DEFAULT_MAX_LOAD_FACTOR) + { + } + + ordered_map(size_type bucket_count, + const Allocator& alloc): ordered_map(bucket_count, Hash(), KeyEqual(), alloc) + { + } + + ordered_map(size_type bucket_count, + const Hash& hash, + const Allocator& alloc): ordered_map(bucket_count, hash, KeyEqual(), alloc) + { + } + + explicit ordered_map(const Allocator& alloc): ordered_map(ht::DEFAULT_INIT_BUCKETS_SIZE, alloc) { + } + + template + ordered_map(InputIt first, InputIt last, + size_type bucket_count = ht::DEFAULT_INIT_BUCKETS_SIZE, + const Hash& hash = Hash(), + const KeyEqual& equal = KeyEqual(), + const Allocator& alloc = Allocator()): ordered_map(bucket_count, hash, equal, alloc) + { + insert(first, last); + } + + template + ordered_map(InputIt first, InputIt last, + size_type bucket_count, + const Allocator& alloc): ordered_map(first, last, bucket_count, Hash(), KeyEqual(), alloc) + { + } + + template + ordered_map(InputIt first, InputIt last, + size_type bucket_count, + const Hash& hash, + const Allocator& alloc): ordered_map(first, last, bucket_count, hash, KeyEqual(), alloc) + { + } + + ordered_map(std::initializer_list init, + size_type bucket_count = ht::DEFAULT_INIT_BUCKETS_SIZE, + const Hash& hash = Hash(), + const KeyEqual& equal = KeyEqual(), + const Allocator& alloc = Allocator()): + ordered_map(init.begin(), init.end(), bucket_count, hash, equal, alloc) + { + } + + ordered_map(std::initializer_list init, + size_type bucket_count, + const Allocator& alloc): + ordered_map(init.begin(), init.end(), bucket_count, Hash(), KeyEqual(), alloc) + { + } + + ordered_map(std::initializer_list init, + size_type bucket_count, + const Hash& hash, + const Allocator& alloc): + ordered_map(init.begin(), init.end(), bucket_count, hash, KeyEqual(), alloc) + { + } + + + ordered_map& operator=(std::initializer_list ilist) { + m_ht.clear(); + + m_ht.reserve(ilist.size()); + m_ht.insert(ilist.begin(), ilist.end()); + + return *this; + } + + allocator_type get_allocator() const { return m_ht.get_allocator(); } + + + + /* + * Iterators + */ + iterator begin() noexcept { return m_ht.begin(); } + const_iterator begin() const noexcept { return m_ht.begin(); } + const_iterator cbegin() const noexcept { return m_ht.cbegin(); } + + iterator end() noexcept { return m_ht.end(); } + const_iterator end() const noexcept { return m_ht.end(); } + const_iterator cend() const noexcept { return m_ht.cend(); } + + reverse_iterator rbegin() noexcept { return m_ht.rbegin(); } + const_reverse_iterator rbegin() const noexcept { return m_ht.rbegin(); } + const_reverse_iterator rcbegin() const noexcept { return m_ht.rcbegin(); } + + reverse_iterator rend() noexcept { return m_ht.rend(); } + const_reverse_iterator rend() const noexcept { return m_ht.rend(); } + const_reverse_iterator rcend() const noexcept { return m_ht.rcend(); } + + + /* + * Capacity + */ + bool empty() const noexcept { return m_ht.empty(); } + size_type size() const noexcept { return m_ht.size(); } + size_type max_size() const noexcept { return m_ht.max_size(); } + + /* + * Modifiers + */ + void clear() noexcept { m_ht.clear(); } + + + + std::pair insert(const value_type& value) { return m_ht.insert(value); } + + template::value>::type* = nullptr> + std::pair insert(P&& value) { return m_ht.emplace(std::forward

(value)); } + + std::pair insert(value_type&& value) { return m_ht.insert(std::move(value)); } + + + iterator insert(const_iterator hint, const value_type& value) { + return m_ht.insert_hint(hint, value); + } + + template::value>::type* = nullptr> + iterator insert(const_iterator hint, P&& value) { + return m_ht.emplace_hint(hint, std::forward

(value)); + } + + iterator insert(const_iterator hint, value_type&& value) { + return m_ht.insert_hint(hint, std::move(value)); + } + + + template + void insert(InputIt first, InputIt last) { m_ht.insert(first, last); } + void insert(std::initializer_list ilist) { m_ht.insert(ilist.begin(), ilist.end()); } + + + + + template + std::pair insert_or_assign(const key_type& k, M&& obj) { + return m_ht.insert_or_assign(k, std::forward(obj)); + } + + template + std::pair insert_or_assign(key_type&& k, M&& obj) { + return m_ht.insert_or_assign(std::move(k), std::forward(obj)); + } + + + template + iterator insert_or_assign(const_iterator hint, const key_type& k, M&& obj) { + return m_ht.insert_or_assign(hint, k, std::forward(obj)); + } + + template + iterator insert_or_assign(const_iterator hint, key_type&& k, M&& obj) { + return m_ht.insert_or_assign(hint, std::move(k), std::forward(obj)); + } + + /** + * Due to the way elements are stored, emplace will need to move or copy the key-value once. + * The method is equivalent to insert(value_type(std::forward(args)...)); + * + * Mainly here for compatibility with the std::unordered_map interface. + */ + template + std::pair emplace(Args&&... args) { return m_ht.emplace(std::forward(args)...); } + + /** + * Due to the way elements are stored, emplace_hint will need to move or copy the key-value once. + * The method is equivalent to insert(hint, value_type(std::forward(args)...)); + * + * Mainly here for compatibility with the std::unordered_map interface. + */ + template + iterator emplace_hint(const_iterator hint, Args&&... args) { + return m_ht.emplace_hint(hint, std::forward(args)...); + } + + + + + template + std::pair try_emplace(const key_type& k, Args&&... args) { + return m_ht.try_emplace(k, std::forward(args)...); + } + + template + std::pair try_emplace(key_type&& k, Args&&... args) { + return m_ht.try_emplace(std::move(k), std::forward(args)...); + } + + template + iterator try_emplace(const_iterator hint, const key_type& k, Args&&... args) { + return m_ht.try_emplace_hint(hint, k, std::forward(args)...); + } + + template + iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args) { + return m_ht.try_emplace_hint(hint, std::move(k), std::forward(args)...); + } + + + + + /** + * When erasing an element, the insert order will be preserved and no holes will be present in the container + * returned by 'values_container()'. + * + * The method is in O(n), if the order is not important 'unordered_erase(...)' method is faster with an O(1) + * average complexity. + */ + iterator erase(iterator pos) { return m_ht.erase(pos); } + + /** + * @copydoc erase(iterator pos) + */ + iterator erase(const_iterator pos) { return m_ht.erase(pos); } + + /** + * @copydoc erase(iterator pos) + */ + iterator erase(const_iterator first, const_iterator last) { return m_ht.erase(first, last); } + + /** + * @copydoc erase(iterator pos) + */ + size_type erase(const key_type& key) { return m_ht.erase(key); } + + /** + * @copydoc erase(iterator pos) + * + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Useful to speed-up the lookup to the value if you already have the hash. + */ + size_type erase(const key_type& key, std::size_t precalculated_hash) { + return m_ht.erase(key, precalculated_hash); + } + + /** + * @copydoc erase(iterator pos) + * + * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. + * If so, K must be hashable and comparable to Key. + */ + template::value>::type* = nullptr> + size_type erase(const K& key) { return m_ht.erase(key); } + + /** + * @copydoc erase(const key_type& key, std::size_t precalculated_hash) + * + * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. + * If so, K must be hashable and comparable to Key. + */ + template::value>::type* = nullptr> + size_type erase(const K& key, std::size_t precalculated_hash) { + return m_ht.erase(key, precalculated_hash); + } + + + + void swap(ordered_map& other) { other.m_ht.swap(m_ht); } + + /* + * Lookup + */ + T& at(const Key& key) { return m_ht.at(key); } + + /** + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Useful to speed-up the lookup if you already have the hash. + */ + T& at(const Key& key, std::size_t precalculated_hash) { return m_ht.at(key, precalculated_hash); } + + + const T& at(const Key& key) const { return m_ht.at(key); } + + /** + * @copydoc at(const Key& key, std::size_t precalculated_hash) + */ + const T& at(const Key& key, std::size_t precalculated_hash) const { return m_ht.at(key, precalculated_hash); } + + + /** + * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. + * If so, K must be hashable and comparable to Key. + */ + template::value>::type* = nullptr> + T& at(const K& key) { return m_ht.at(key); } + + /** + * @copydoc at(const K& key) + * + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Useful to speed-up the lookup if you already have the hash. + */ + template::value>::type* = nullptr> + T& at(const K& key, std::size_t precalculated_hash) { return m_ht.at(key, precalculated_hash); } + + /** + * @copydoc at(const K& key) + */ + template::value>::type* = nullptr> + const T& at(const K& key) const { return m_ht.at(key); } + + /** + * @copydoc at(const K& key, std::size_t precalculated_hash) + */ + template::value>::type* = nullptr> + const T& at(const K& key, std::size_t precalculated_hash) const { return m_ht.at(key, precalculated_hash); } + + + + T& operator[](const Key& key) { return m_ht[key]; } + T& operator[](Key&& key) { return m_ht[std::move(key)]; } + + + + size_type count(const Key& key) const { return m_ht.count(key); } + + /** + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Useful to speed-up the lookup if you already have the hash. + */ + size_type count(const Key& key, std::size_t precalculated_hash) const { + return m_ht.count(key, precalculated_hash); + } + + /** + * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. + * If so, K must be hashable and comparable to Key. + */ + template::value>::type* = nullptr> + size_type count(const K& key) const { return m_ht.count(key); } + + /** + * @copydoc count(const K& key) const + * + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Useful to speed-up the lookup if you already have the hash. + */ + template::value>::type* = nullptr> + size_type count(const K& key, std::size_t precalculated_hash) const { + return m_ht.count(key, precalculated_hash); + } + + + + iterator find(const Key& key) { return m_ht.find(key); } + + /** + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Useful to speed-up the lookup if you already have the hash. + */ + iterator find(const Key& key, std::size_t precalculated_hash) { return m_ht.find(key, precalculated_hash); } + + const_iterator find(const Key& key) const { return m_ht.find(key); } + + /** + * @copydoc find(const Key& key, std::size_t precalculated_hash) + */ + const_iterator find(const Key& key, std::size_t precalculated_hash) const { + return m_ht.find(key, precalculated_hash); + } + + /** + * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. + * If so, K must be hashable and comparable to Key. + */ + template::value>::type* = nullptr> + iterator find(const K& key) { return m_ht.find(key); } + + /** + * @copydoc find(const K& key) + * + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Useful to speed-up the lookup if you already have the hash. + */ + template::value>::type* = nullptr> + iterator find(const K& key, std::size_t precalculated_hash) { return m_ht.find(key, precalculated_hash); } + + /** + * @copydoc find(const K& key) + */ + template::value>::type* = nullptr> + const_iterator find(const K& key) const { return m_ht.find(key); } + + /** + * @copydoc find(const K& key) + * + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Useful to speed-up the lookup if you already have the hash. + */ + template::value>::type* = nullptr> + const_iterator find(const K& key, std::size_t precalculated_hash) const { + return m_ht.find(key, precalculated_hash); + } + + + + bool contains(const Key& key) const { return m_ht.contains(key); } + + /** + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Useful to speed-up the lookup if you already have the hash. + */ + bool contains(const Key& key, std::size_t precalculated_hash) const { + return m_ht.contains(key, precalculated_hash); + } + + /** + * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. + * If so, K must be hashable and comparable to Key. + */ + template::value>::type* = nullptr> + bool contains(const K& key) const { return m_ht.contains(key); } + + /** + * @copydoc contains(const K& key) const + * + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Useful to speed-up the lookup if you already have the hash. + */ + template::value>::type* = nullptr> + bool contains(const K& key, std::size_t precalculated_hash) const { + return m_ht.contains(key, precalculated_hash); + } + + + + std::pair equal_range(const Key& key) { return m_ht.equal_range(key); } + + /** + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Useful to speed-up the lookup if you already have the hash. + */ + std::pair equal_range(const Key& key, std::size_t precalculated_hash) { + return m_ht.equal_range(key, precalculated_hash); + } + + std::pair equal_range(const Key& key) const { return m_ht.equal_range(key); } + + /** + * @copydoc equal_range(const Key& key, std::size_t precalculated_hash) + */ + std::pair equal_range(const Key& key, std::size_t precalculated_hash) const { + return m_ht.equal_range(key, precalculated_hash); + } + + /** + * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. + * If so, K must be hashable and comparable to Key. + */ + template::value>::type* = nullptr> + std::pair equal_range(const K& key) { return m_ht.equal_range(key); } + + /** + * @copydoc equal_range(const K& key) + * + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Useful to speed-up the lookup if you already have the hash. + */ + template::value>::type* = nullptr> + std::pair equal_range(const K& key, std::size_t precalculated_hash) { + return m_ht.equal_range(key, precalculated_hash); + } + + /** + * @copydoc equal_range(const K& key) + */ + template::value>::type* = nullptr> + std::pair equal_range(const K& key) const { return m_ht.equal_range(key); } + + /** + * @copydoc equal_range(const K& key, std::size_t precalculated_hash) + */ + template::value>::type* = nullptr> + std::pair equal_range(const K& key, std::size_t precalculated_hash) const { + return m_ht.equal_range(key, precalculated_hash); + } + + + + /* + * Bucket interface + */ + size_type bucket_count() const { return m_ht.bucket_count(); } + size_type max_bucket_count() const { return m_ht.max_bucket_count(); } + + + /* + * Hash policy + */ + float load_factor() const { return m_ht.load_factor(); } + float max_load_factor() const { return m_ht.max_load_factor(); } + void max_load_factor(float ml) { m_ht.max_load_factor(ml); } + + void rehash(size_type count) { m_ht.rehash(count); } + void reserve(size_type count) { m_ht.reserve(count); } + + + /* + * Observers + */ + hasher hash_function() const { return m_ht.hash_function(); } + key_equal key_eq() const { return m_ht.key_eq(); } + + + + /* + * Other + */ + + /** + * Convert a const_iterator to an iterator. + */ + iterator mutable_iterator(const_iterator pos) { + return m_ht.mutable_iterator(pos); + } + + /** + * Requires index <= size(). + * + * Return an iterator to the element at index. Return end() if index == size(). + */ + iterator nth(size_type index) { return m_ht.nth(index); } + + /** + * @copydoc nth(size_type index) + */ + const_iterator nth(size_type index) const { return m_ht.nth(index); } + + + /** + * Return const_reference to the first element. Requires the container to not be empty. + */ + const_reference front() const { return m_ht.front(); } + + /** + * Return const_reference to the last element. Requires the container to not be empty. + */ + const_reference back() const { return m_ht.back(); } + + + /** + * Only available if ValueTypeContainer is a std::vector. Same as calling 'values_container().data()'. + */ + template::value>::type* = nullptr> + const typename values_container_type::value_type* data() const noexcept { return m_ht.data(); } + + /** + * Return the container in which the values are stored. The values are in the same order as the insertion order + * and are contiguous in the structure, no holes (size() == values_container().size()). + */ + const values_container_type& values_container() const noexcept { return m_ht.values_container(); } + + template::value>::type* = nullptr> + size_type capacity() const noexcept { return m_ht.capacity(); } + + void shrink_to_fit() { m_ht.shrink_to_fit(); } + + + + /** + * Insert the value before pos shifting all the elements on the right of pos (including pos) one position + * to the right. + * + * Amortized linear time-complexity in the distance between pos and end(). + */ + std::pair insert_at_position(const_iterator pos, const value_type& value) { + return m_ht.insert_at_position(pos, value); + } + + /** + * @copydoc insert_at_position(const_iterator pos, const value_type& value) + */ + std::pair insert_at_position(const_iterator pos, value_type&& value) { + return m_ht.insert_at_position(pos, std::move(value)); + } + + /** + * @copydoc insert_at_position(const_iterator pos, const value_type& value) + * + * Same as insert_at_position(pos, value_type(std::forward(args)...), mainly + * here for coherence. + */ + template + std::pair emplace_at_position(const_iterator pos, Args&&... args) { + return m_ht.emplace_at_position(pos, std::forward(args)...); + } + + /** + * @copydoc insert_at_position(const_iterator pos, const value_type& value) + */ + template + std::pair try_emplace_at_position(const_iterator pos, const key_type& k, Args&&... args) { + return m_ht.try_emplace_at_position(pos, k, std::forward(args)...); + } + + /** + * @copydoc insert_at_position(const_iterator pos, const value_type& value) + */ + template + std::pair try_emplace_at_position(const_iterator pos, key_type&& k, Args&&... args) { + return m_ht.try_emplace_at_position(pos, std::move(k), std::forward(args)...); + } + + + + void pop_back() { m_ht.pop_back(); } + + /** + * Faster erase operation with an O(1) average complexity but it doesn't preserve the insertion order. + * + * If an erasure occurs, the last element of the map will take the place of the erased element. + */ + iterator unordered_erase(iterator pos) { return m_ht.unordered_erase(pos); } + + /** + * @copydoc unordered_erase(iterator pos) + */ + iterator unordered_erase(const_iterator pos) { return m_ht.unordered_erase(pos); } + + /** + * @copydoc unordered_erase(iterator pos) + */ + size_type unordered_erase(const key_type& key) { return m_ht.unordered_erase(key); } + + /** + * @copydoc unordered_erase(iterator pos) + * + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Useful to speed-up the lookup if you already have the hash. + */ + size_type unordered_erase(const key_type& key, std::size_t precalculated_hash) { + return m_ht.unordered_erase(key, precalculated_hash); + } + + /** + * @copydoc unordered_erase(iterator pos) + * + * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. + * If so, K must be hashable and comparable to Key. + */ + template::value>::type* = nullptr> + size_type unordered_erase(const K& key) { return m_ht.unordered_erase(key); } + + /** + * @copydoc unordered_erase(const K& key) + * + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Useful to speed-up the lookup if you already have the hash. + */ + template::value>::type* = nullptr> + size_type unordered_erase(const K& key, std::size_t precalculated_hash) { + return m_ht.unordered_erase(key, precalculated_hash); + } + + /** + * Serialize the map through the `serializer` parameter. + * + * The `serializer` parameter must be a function object that supports the following call: + * - `template void operator()(const U& value);` where the types `std::uint64_t`, `float` and `std::pair` must be supported for U. + * + * The implementation leaves binary compatibility (endianness, IEEE 754 for floats, ...) of the types it serializes + * in the hands of the `Serializer` function object if compatibility is required. + */ + template + void serialize(Serializer& serializer) const { + m_ht.serialize(serializer); + } + + /** + * Deserialize a previously serialized map through the `deserializer` parameter. + * + * The `deserializer` parameter must be a function object that supports the following calls: + * - `template U operator()();` where the types `std::uint64_t`, `float` and `std::pair` must be supported for U. + * + * If the deserialized hash map type is hash compatible with the serialized map, the deserialization process can be + * sped up by setting `hash_compatible` to true. To be hash compatible, the Hash and KeyEqual must behave the same way + * than the ones used on the serialized map. The `std::size_t` must also be of the same size as the one on the platform used + * to serialize the map, the same apply for `IndexType`. If these criteria are not met, the behaviour is undefined with + * `hash_compatible` sets to true. + * + * The behaviour is undefined if the type `Key` and `T` of the `ordered_map` are not the same as the + * types used during serialization. + * + * The implementation leaves binary compatibility (endianness, IEEE 754 for floats, size of int, ...) of the types it + * deserializes in the hands of the `Deserializer` function object if compatibility is required. + */ + template + static ordered_map deserialize(Deserializer& deserializer, bool hash_compatible = false) { + ordered_map map(0); + map.m_ht.deserialize(deserializer, hash_compatible); + + return map; + } + + + + friend bool operator==(const ordered_map& lhs, const ordered_map& rhs) { return lhs.m_ht == rhs.m_ht; } + friend bool operator!=(const ordered_map& lhs, const ordered_map& rhs) { return lhs.m_ht != rhs.m_ht; } + friend bool operator<(const ordered_map& lhs, const ordered_map& rhs) { return lhs.m_ht < rhs.m_ht; } + friend bool operator<=(const ordered_map& lhs, const ordered_map& rhs) { return lhs.m_ht <= rhs.m_ht; } + friend bool operator>(const ordered_map& lhs, const ordered_map& rhs) { return lhs.m_ht > rhs.m_ht; } + friend bool operator>=(const ordered_map& lhs, const ordered_map& rhs) { return lhs.m_ht >= rhs.m_ht; } + + friend void swap(ordered_map& lhs, ordered_map& rhs) { lhs.swap(rhs); } + +private: + ht m_ht; +}; + +} // end namespace tsl + +#endif diff --git a/thirdparty/include/tsl/ordered_set.h b/thirdparty/include/tsl/ordered_set.h new file mode 100644 index 000000000..90a99eee3 --- /dev/null +++ b/thirdparty/include/tsl/ordered_set.h @@ -0,0 +1,718 @@ +/** + * MIT License + * + * Copyright (c) 2017 Thibaut Goetghebuer-Planchon + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef TSL_ORDERED_SET_H +#define TSL_ORDERED_SET_H + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ordered_hash.h" + + +namespace tsl { + + +/** + * Implementation of an hash set using open addressing with robin hood with backshift delete to resolve collisions. + * + * The particularity of this hash set is that it remembers the order in which the elements were added and + * provide a way to access the structure which stores these values through the 'values_container()' method. + * The used container is defined by ValueTypeContainer, by default a std::deque is used (grows faster) but + * a std::vector may be used. In this case the set provides a 'data()' method which give a direct access + * to the memory used to store the values (which can be useful to communicate with C API's). + * + * The Key must be copy constructible and/or move constructible. To use `unordered_erase` it also must be swappable. + * + * The behaviour of the hash set is undefined if the destructor of Key throws an exception. + * + * By default the maximum size of a set is limited to 2^32 - 1 values, if needed this can be changed through + * the IndexType template parameter. Using an `uint64_t` will raise this limit to 2^64 - 1 values but each + * bucket will use 16 bytes instead of 8 bytes in addition to the space needed to store the values. + * + * Iterators invalidation: + * - clear, operator=, reserve, rehash: always invalidate the iterators (also invalidate end()). + * - insert, emplace, emplace_hint, operator[]: when a std::vector is used as ValueTypeContainer + * and if size() < capacity(), only end(). + * Otherwise all the iterators are invalidated if an insert occurs. + * - erase, unordered_erase: when a std::vector is used as ValueTypeContainer invalidate the iterator of + * the erased element and all the ones after the erased element (including end()). + * Otherwise all the iterators are invalidated if an erase occurs. + */ +template, + class KeyEqual = std::equal_to, + class Allocator = std::allocator, + class ValueTypeContainer = std::deque, + class IndexType = std::uint_least32_t> +class ordered_set { +private: + template + using has_is_transparent = tsl::detail_ordered_hash::has_is_transparent; + + class KeySelect { + public: + using key_type = Key; + + const key_type& operator()(const Key& key) const noexcept { + return key; + } + + key_type& operator()(Key& key) noexcept { + return key; + } + }; + + using ht = detail_ordered_hash::ordered_hash; + +public: + using key_type = typename ht::key_type; + using value_type = typename ht::value_type; + using size_type = typename ht::size_type; + using difference_type = typename ht::difference_type; + using hasher = typename ht::hasher; + using key_equal = typename ht::key_equal; + using allocator_type = typename ht::allocator_type; + using reference = typename ht::reference; + using const_reference = typename ht::const_reference; + using pointer = typename ht::pointer; + using const_pointer = typename ht::const_pointer; + using iterator = typename ht::iterator; + using const_iterator = typename ht::const_iterator; + using reverse_iterator = typename ht::reverse_iterator; + using const_reverse_iterator = typename ht::const_reverse_iterator; + + using values_container_type = typename ht::values_container_type; + + + /* + * Constructors + */ + ordered_set(): ordered_set(ht::DEFAULT_INIT_BUCKETS_SIZE) { + } + + explicit ordered_set(size_type bucket_count, + const Hash& hash = Hash(), + const KeyEqual& equal = KeyEqual(), + const Allocator& alloc = Allocator()): + m_ht(bucket_count, hash, equal, alloc, ht::DEFAULT_MAX_LOAD_FACTOR) + { + } + + ordered_set(size_type bucket_count, + const Allocator& alloc): ordered_set(bucket_count, Hash(), KeyEqual(), alloc) + { + } + + ordered_set(size_type bucket_count, + const Hash& hash, + const Allocator& alloc): ordered_set(bucket_count, hash, KeyEqual(), alloc) + { + } + + explicit ordered_set(const Allocator& alloc): ordered_set(ht::DEFAULT_INIT_BUCKETS_SIZE, alloc) { + } + + template + ordered_set(InputIt first, InputIt last, + size_type bucket_count = ht::DEFAULT_INIT_BUCKETS_SIZE, + const Hash& hash = Hash(), + const KeyEqual& equal = KeyEqual(), + const Allocator& alloc = Allocator()): ordered_set(bucket_count, hash, equal, alloc) + { + insert(first, last); + } + + template + ordered_set(InputIt first, InputIt last, + size_type bucket_count, + const Allocator& alloc): ordered_set(first, last, bucket_count, Hash(), KeyEqual(), alloc) + { + } + + template + ordered_set(InputIt first, InputIt last, + size_type bucket_count, + const Hash& hash, + const Allocator& alloc): ordered_set(first, last, bucket_count, hash, KeyEqual(), alloc) + { + } + + ordered_set(std::initializer_list init, + size_type bucket_count = ht::DEFAULT_INIT_BUCKETS_SIZE, + const Hash& hash = Hash(), + const KeyEqual& equal = KeyEqual(), + const Allocator& alloc = Allocator()): + ordered_set(init.begin(), init.end(), bucket_count, hash, equal, alloc) + { + } + + ordered_set(std::initializer_list init, + size_type bucket_count, + const Allocator& alloc): + ordered_set(init.begin(), init.end(), bucket_count, Hash(), KeyEqual(), alloc) + { + } + + ordered_set(std::initializer_list init, + size_type bucket_count, + const Hash& hash, + const Allocator& alloc): + ordered_set(init.begin(), init.end(), bucket_count, hash, KeyEqual(), alloc) + { + } + + + ordered_set& operator=(std::initializer_list ilist) { + m_ht.clear(); + + m_ht.reserve(ilist.size()); + m_ht.insert(ilist.begin(), ilist.end()); + + return *this; + } + + allocator_type get_allocator() const { return m_ht.get_allocator(); } + + + /* + * Iterators + */ + iterator begin() noexcept { return m_ht.begin(); } + const_iterator begin() const noexcept { return m_ht.begin(); } + const_iterator cbegin() const noexcept { return m_ht.cbegin(); } + + iterator end() noexcept { return m_ht.end(); } + const_iterator end() const noexcept { return m_ht.end(); } + const_iterator cend() const noexcept { return m_ht.cend(); } + + reverse_iterator rbegin() noexcept { return m_ht.rbegin(); } + const_reverse_iterator rbegin() const noexcept { return m_ht.rbegin(); } + const_reverse_iterator rcbegin() const noexcept { return m_ht.rcbegin(); } + + reverse_iterator rend() noexcept { return m_ht.rend(); } + const_reverse_iterator rend() const noexcept { return m_ht.rend(); } + const_reverse_iterator rcend() const noexcept { return m_ht.rcend(); } + + + /* + * Capacity + */ + bool empty() const noexcept { return m_ht.empty(); } + size_type size() const noexcept { return m_ht.size(); } + size_type max_size() const noexcept { return m_ht.max_size(); } + + /* + * Modifiers + */ + void clear() noexcept { m_ht.clear(); } + + + + std::pair insert(const value_type& value) { return m_ht.insert(value); } + std::pair insert(value_type&& value) { return m_ht.insert(std::move(value)); } + + iterator insert(const_iterator hint, const value_type& value) { + return m_ht.insert_hint(hint, value); + } + + iterator insert(const_iterator hint, value_type&& value) { + return m_ht.insert_hint(hint, std::move(value)); + } + + template + void insert(InputIt first, InputIt last) { m_ht.insert(first, last); } + void insert(std::initializer_list ilist) { m_ht.insert(ilist.begin(), ilist.end()); } + + + + /** + * Due to the way elements are stored, emplace will need to move or copy the key-value once. + * The method is equivalent to insert(value_type(std::forward(args)...)); + * + * Mainly here for compatibility with the std::unordered_map interface. + */ + template + std::pair emplace(Args&&... args) { return m_ht.emplace(std::forward(args)...); } + + /** + * Due to the way elements are stored, emplace_hint will need to move or copy the key-value once. + * The method is equivalent to insert(hint, value_type(std::forward(args)...)); + * + * Mainly here for compatibility with the std::unordered_map interface. + */ + template + iterator emplace_hint(const_iterator hint, Args&&... args) { + return m_ht.emplace_hint(hint, std::forward(args)...); + } + + /** + * When erasing an element, the insert order will be preserved and no holes will be present in the container + * returned by 'values_container()'. + * + * The method is in O(n), if the order is not important 'unordered_erase(...)' method is faster with an O(1) + * average complexity. + */ + iterator erase(iterator pos) { return m_ht.erase(pos); } + + /** + * @copydoc erase(iterator pos) + */ + iterator erase(const_iterator pos) { return m_ht.erase(pos); } + + /** + * @copydoc erase(iterator pos) + */ + iterator erase(const_iterator first, const_iterator last) { return m_ht.erase(first, last); } + + /** + * @copydoc erase(iterator pos) + */ + size_type erase(const key_type& key) { return m_ht.erase(key); } + + /** + * @copydoc erase(iterator pos) + * + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Useful to speed-up the lookup to the value if you already have the hash. + */ + size_type erase(const key_type& key, std::size_t precalculated_hash) { + return m_ht.erase(key, precalculated_hash); + } + + /** + * @copydoc erase(iterator pos) + * + * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. + * If so, K must be hashable and comparable to Key. + */ + template::value>::type* = nullptr> + size_type erase(const K& key) { return m_ht.erase(key); } + + /** + * @copydoc erase(const key_type& key, std::size_t precalculated_hash) + * + * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. + * If so, K must be hashable and comparable to Key. + */ + template::value>::type* = nullptr> + size_type erase(const K& key, std::size_t precalculated_hash) { + return m_ht.erase(key, precalculated_hash); + } + + + + void swap(ordered_set& other) { other.m_ht.swap(m_ht); } + + /* + * Lookup + */ + size_type count(const Key& key) const { return m_ht.count(key); } + + /** + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Useful to speed-up the lookup if you already have the hash. + */ + size_type count(const Key& key, std::size_t precalculated_hash) const { + return m_ht.count(key, precalculated_hash); + } + + /** + * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. + * If so, K must be hashable and comparable to Key. + */ + template::value>::type* = nullptr> + size_type count(const K& key) const { return m_ht.count(key); } + + /** + * @copydoc count(const K& key) const + * + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Useful to speed-up the lookup if you already have the hash. + */ + template::value>::type* = nullptr> + size_type count(const K& key, std::size_t precalculated_hash) const { + return m_ht.count(key, precalculated_hash); + } + + + + + iterator find(const Key& key) { return m_ht.find(key); } + + /** + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Useful to speed-up the lookup if you already have the hash. + */ + iterator find(const Key& key, std::size_t precalculated_hash) { return m_ht.find(key, precalculated_hash); } + + const_iterator find(const Key& key) const { return m_ht.find(key); } + + /** + * @copydoc find(const Key& key, std::size_t precalculated_hash) + */ + const_iterator find(const Key& key, std::size_t precalculated_hash) const { + return m_ht.find(key, precalculated_hash); + } + + /** + * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. + * If so, K must be hashable and comparable to Key. + */ + template::value>::type* = nullptr> + iterator find(const K& key) { return m_ht.find(key); } + + /** + * @copydoc find(const K& key) + * + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Useful to speed-up the lookup if you already have the hash. + */ + template::value>::type* = nullptr> + iterator find(const K& key, std::size_t precalculated_hash) { return m_ht.find(key, precalculated_hash); } + + /** + * @copydoc find(const K& key) + */ + template::value>::type* = nullptr> + const_iterator find(const K& key) const { return m_ht.find(key); } + + /** + * @copydoc find(const K& key) + * + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Useful to speed-up the lookup if you already have the hash. + */ + template::value>::type* = nullptr> + const_iterator find(const K& key, std::size_t precalculated_hash) const { + return m_ht.find(key, precalculated_hash); + } + + + + bool contains(const Key& key) const { return m_ht.contains(key); } + + /** + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Useful to speed-up the lookup if you already have the hash. + */ + bool contains(const Key& key, std::size_t precalculated_hash) const { + return m_ht.contains(key, precalculated_hash); + } + + /** + * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. + * If so, K must be hashable and comparable to Key. + */ + template::value>::type* = nullptr> + bool contains(const K& key) const { return m_ht.contains(key); } + + /** + * @copydoc contains(const K& key) const + * + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Useful to speed-up the lookup if you already have the hash. + */ + template::value>::type* = nullptr> + bool contains(const K& key, std::size_t precalculated_hash) const { + return m_ht.contains(key, precalculated_hash); + } + + + + std::pair equal_range(const Key& key) { return m_ht.equal_range(key); } + + /** + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Useful to speed-up the lookup if you already have the hash. + */ + std::pair equal_range(const Key& key, std::size_t precalculated_hash) { + return m_ht.equal_range(key, precalculated_hash); + } + + std::pair equal_range(const Key& key) const { return m_ht.equal_range(key); } + + /** + * @copydoc equal_range(const Key& key, std::size_t precalculated_hash) + */ + std::pair equal_range(const Key& key, std::size_t precalculated_hash) const { + return m_ht.equal_range(key, precalculated_hash); + } + + /** + * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. + * If so, K must be hashable and comparable to Key. + */ + template::value>::type* = nullptr> + std::pair equal_range(const K& key) { return m_ht.equal_range(key); } + + /** + * @copydoc equal_range(const K& key) + * + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Useful to speed-up the lookup if you already have the hash. + */ + template::value>::type* = nullptr> + std::pair equal_range(const K& key, std::size_t precalculated_hash) { + return m_ht.equal_range(key, precalculated_hash); + } + + /** + * @copydoc equal_range(const K& key) + */ + template::value>::type* = nullptr> + std::pair equal_range(const K& key) const { return m_ht.equal_range(key); } + + /** + * @copydoc equal_range(const K& key, std::size_t precalculated_hash) + */ + template::value>::type* = nullptr> + std::pair equal_range(const K& key, std::size_t precalculated_hash) const { + return m_ht.equal_range(key, precalculated_hash); + } + + + /* + * Bucket interface + */ + size_type bucket_count() const { return m_ht.bucket_count(); } + size_type max_bucket_count() const { return m_ht.max_bucket_count(); } + + + /* + * Hash policy + */ + float load_factor() const { return m_ht.load_factor(); } + float max_load_factor() const { return m_ht.max_load_factor(); } + void max_load_factor(float ml) { m_ht.max_load_factor(ml); } + + void rehash(size_type count) { m_ht.rehash(count); } + void reserve(size_type count) { m_ht.reserve(count); } + + + /* + * Observers + */ + hasher hash_function() const { return m_ht.hash_function(); } + key_equal key_eq() const { return m_ht.key_eq(); } + + + /* + * Other + */ + + /** + * Convert a const_iterator to an iterator. + */ + iterator mutable_iterator(const_iterator pos) { + return m_ht.mutable_iterator(pos); + } + + /** + * Requires index <= size(). + * + * Return an iterator to the element at index. Return end() if index == size(). + */ + iterator nth(size_type index) { return m_ht.nth(index); } + + /** + * @copydoc nth(size_type index) + */ + const_iterator nth(size_type index) const { return m_ht.nth(index); } + + + /** + * Return const_reference to the first element. Requires the container to not be empty. + */ + const_reference front() const { return m_ht.front(); } + + /** + * Return const_reference to the last element. Requires the container to not be empty. + */ + const_reference back() const { return m_ht.back(); } + + + /** + * Only available if ValueTypeContainer is a std::vector. Same as calling 'values_container().data()'. + */ + template::value>::type* = nullptr> + const typename values_container_type::value_type* data() const noexcept { return m_ht.data(); } + + /** + * Return the container in which the values are stored. The values are in the same order as the insertion order + * and are contiguous in the structure, no holes (size() == values_container().size()). + */ + const values_container_type& values_container() const noexcept { return m_ht.values_container(); } + + template::value>::type* = nullptr> + size_type capacity() const noexcept { return m_ht.capacity(); } + + void shrink_to_fit() { m_ht.shrink_to_fit(); } + + + + /** + * Insert the value before pos shifting all the elements on the right of pos (including pos) one position + * to the right. + * + * Amortized linear time-complexity in the distance between pos and end(). + */ + std::pair insert_at_position(const_iterator pos, const value_type& value) { + return m_ht.insert_at_position(pos, value); + } + + /** + * @copydoc insert_at_position(const_iterator pos, const value_type& value) + */ + std::pair insert_at_position(const_iterator pos, value_type&& value) { + return m_ht.insert_at_position(pos, std::move(value)); + } + + /** + * @copydoc insert_at_position(const_iterator pos, const value_type& value) + * + * Same as insert_at_position(pos, value_type(std::forward(args)...), mainly + * here for coherence. + */ + template + std::pair emplace_at_position(const_iterator pos, Args&&... args) { + return m_ht.emplace_at_position(pos, std::forward(args)...); + } + + + + void pop_back() { m_ht.pop_back(); } + + /** + * Faster erase operation with an O(1) average complexity but it doesn't preserve the insertion order. + * + * If an erasure occurs, the last element of the map will take the place of the erased element. + */ + iterator unordered_erase(iterator pos) { return m_ht.unordered_erase(pos); } + + /** + * @copydoc unordered_erase(iterator pos) + */ + iterator unordered_erase(const_iterator pos) { return m_ht.unordered_erase(pos); } + + /** + * @copydoc unordered_erase(iterator pos) + */ + size_type unordered_erase(const key_type& key) { return m_ht.unordered_erase(key); } + + /** + * @copydoc unordered_erase(iterator pos) + * + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Useful to speed-up the lookup if you already have the hash. + */ + size_type unordered_erase(const key_type& key, std::size_t precalculated_hash) { + return m_ht.unordered_erase(key, precalculated_hash); + } + + /** + * @copydoc unordered_erase(iterator pos) + * + * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. + * If so, K must be hashable and comparable to Key. + */ + template::value>::type* = nullptr> + size_type unordered_erase(const K& key) { return m_ht.unordered_erase(key); } + + /** + * @copydoc unordered_erase(const K& key) + * + * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same + * as hash_function()(key). Useful to speed-up the lookup if you already have the hash. + */ + template::value>::type* = nullptr> + size_type unordered_erase(const K& key, std::size_t precalculated_hash) { + return m_ht.unordered_erase(key, precalculated_hash); + } + + /** + * Serialize the set through the `serializer` parameter. + * + * The `serializer` parameter must be a function object that supports the following call: + * - `void operator()(const U& value);` where the types `std::uint64_t`, `float` and `Key` must be supported for U. + * + * The implementation leaves binary compatibility (endianness, IEEE 754 for floats, ...) of the types it serializes + * in the hands of the `Serializer` function object if compatibility is required. + */ + template + void serialize(Serializer& serializer) const { + m_ht.serialize(serializer); + } + + /** + * Deserialize a previously serialized set through the `deserializer` parameter. + * + * The `deserializer` parameter must be a function object that supports the following calls: + * - `template U operator()();` where the types `std::uint64_t`, `float` and `Key` must be supported for U. + * + * If the deserialized hash set type is hash compatible with the serialized set, the deserialization process can be + * sped up by setting `hash_compatible` to true. To be hash compatible, the Hash and KeyEqual must behave the same way + * than the ones used on the serialized map. The `std::size_t` must also be of the same size as the one on the platform used + * to serialize the map, the same apply for `IndexType`. If these criteria are not met, the behaviour is undefined with + * `hash_compatible` sets to true. + * + * The behaviour is undefined if the type `Key` of the `ordered_set` is not the same as the + * type used during serialization. + * + * The implementation leaves binary compatibility (endianness, IEEE 754 for floats, size of int, ...) of the types it + * deserializes in the hands of the `Deserializer` function object if compatibility is required. + */ + template + static ordered_set deserialize(Deserializer& deserializer, bool hash_compatible = false) { + ordered_set set(0); + set.m_ht.deserialize(deserializer, hash_compatible); + + return set; + } + + + + friend bool operator==(const ordered_set& lhs, const ordered_set& rhs) { return lhs.m_ht == rhs.m_ht; } + friend bool operator!=(const ordered_set& lhs, const ordered_set& rhs) { return lhs.m_ht != rhs.m_ht; } + friend bool operator<(const ordered_set& lhs, const ordered_set& rhs) { return lhs.m_ht < rhs.m_ht; } + friend bool operator<=(const ordered_set& lhs, const ordered_set& rhs) { return lhs.m_ht <= rhs.m_ht; } + friend bool operator>(const ordered_set& lhs, const ordered_set& rhs) { return lhs.m_ht > rhs.m_ht; } + friend bool operator>=(const ordered_set& lhs, const ordered_set& rhs) { return lhs.m_ht >= rhs.m_ht; } + + friend void swap(ordered_set& lhs, ordered_set& rhs) { lhs.swap(rhs); } + +private: + ht m_ht; +}; + +} // end namespace tsl + +#endif From 7736312c2f361512ab841f852c1b18349abd6d3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Tue, 4 Aug 2020 01:33:31 +0200 Subject: [PATCH 077/105] ShaderNodes: Replace union by std::variant --- include/Nazara/Renderer/ShaderNodes.hpp | 23 +++++-------- include/Nazara/Renderer/ShaderNodes.inl | 42 ++---------------------- src/Nazara/Renderer/GlslWriter.cpp | 39 +++++++++------------- src/Nazara/Renderer/ShaderNodes.cpp | 19 ++++++++++- src/Nazara/Renderer/ShaderSerializer.cpp | 39 +++++++++++----------- 5 files changed, 66 insertions(+), 96 deletions(-) diff --git a/include/Nazara/Renderer/ShaderNodes.hpp b/include/Nazara/Renderer/ShaderNodes.hpp index 0c5049df9..0b6daec79 100644 --- a/include/Nazara/Renderer/ShaderNodes.hpp +++ b/include/Nazara/Renderer/ShaderNodes.hpp @@ -220,22 +220,17 @@ namespace Nz ShaderExpressionType GetExpressionType() const override; void Visit(ShaderVisitor& visitor) override; - BasicType exprType; + using Variant = std::variant< + bool, + float, + Vector2f, + Vector3f, + Vector4f + >; - union - { - bool bool1; - float vec1; - Vector2f vec2; - Vector3f vec3; - Vector4f vec4; - } values; + Variant value; - static inline std::shared_ptr Build(bool value); - static inline std::shared_ptr Build(float value); - static inline std::shared_ptr Build(const Vector2f& value); - static inline std::shared_ptr Build(const Vector3f& value); - static inline std::shared_ptr Build(const Vector4f& value); + template static std::shared_ptr Build(const T& value); }; struct NAZARA_RENDERER_API SwizzleOp : public Expression diff --git a/include/Nazara/Renderer/ShaderNodes.inl b/include/Nazara/Renderer/ShaderNodes.inl index 606487e0c..27d387bcd 100644 --- a/include/Nazara/Renderer/ShaderNodes.inl +++ b/include/Nazara/Renderer/ShaderNodes.inl @@ -239,47 +239,11 @@ namespace Nz::ShaderNodes { } - inline std::shared_ptr Constant::Build(bool value) + template + std::shared_ptr Nz::ShaderNodes::Constant::Build(const T& value) { auto node = std::make_shared(); - node->exprType = BasicType::Boolean; - node->values.bool1 = value; - - return node; - } - - inline std::shared_ptr Constant::Build(float value) - { - auto node = std::make_shared(); - node->exprType = BasicType::Float1; - node->values.vec1 = value; - - return node; - } - - inline std::shared_ptr Constant::Build(const Vector2f& value) - { - auto node = std::make_shared(); - node->exprType = BasicType::Float2; - node->values.vec2 = value; - - return node; - } - - inline std::shared_ptr Constant::Build(const Vector3f& value) - { - auto node = std::make_shared(); - node->exprType = BasicType::Float3; - node->values.vec3 = value; - - return node; - } - - inline std::shared_ptr Constant::Build(const Vector4f& value) - { - auto node = std::make_shared(); - node->exprType = BasicType::Float4; - node->values.vec4 = value; + node->value = value; return node; } diff --git a/src/Nazara/Renderer/GlslWriter.cpp b/src/Nazara/Renderer/GlslWriter.cpp index 3f2a4a4a3..fcb1847a7 100644 --- a/src/Nazara/Renderer/GlslWriter.cpp +++ b/src/Nazara/Renderer/GlslWriter.cpp @@ -3,6 +3,7 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include +#include #include #include #include @@ -426,31 +427,23 @@ namespace Nz void GlslWriter::Visit(const ShaderNodes::Constant& node) { - switch (node.exprType) + std::visit([&](auto&& arg) { - case ShaderNodes::BasicType::Boolean: - Append((node.values.bool1) ? "true" : "false"); - break; + using T = std::decay_t; - case ShaderNodes::BasicType::Float1: - Append(std::to_string(node.values.vec1)); - break; - - case ShaderNodes::BasicType::Float2: - Append("vec2(" + std::to_string(node.values.vec2.x) + ", " + std::to_string(node.values.vec2.y) + ")"); - break; - - case ShaderNodes::BasicType::Float3: - Append("vec3(" + std::to_string(node.values.vec3.x) + ", " + std::to_string(node.values.vec3.y) + ", " + std::to_string(node.values.vec3.z) + ")"); - break; - - case ShaderNodes::BasicType::Float4: - Append("vec4(" + std::to_string(node.values.vec4.x) + ", " + std::to_string(node.values.vec4.y) + ", " + std::to_string(node.values.vec4.z) + ", " + std::to_string(node.values.vec4.w) + ")"); - break; - - default: - throw std::runtime_error("Unhandled expression type"); - } + if constexpr (std::is_same_v) + Append((arg) ? "true" : "false"); + else if constexpr (std::is_same_v) + Append(std::to_string(arg)); + else if constexpr (std::is_same_v) + Append("vec2(" + std::to_string(arg.x) + ", " + std::to_string(arg.y) + ")"); + else if constexpr (std::is_same_v) + Append("vec3(" + std::to_string(arg.x) + ", " + std::to_string(arg.y) + ", " + std::to_string(arg.z) + ")"); + else if constexpr (std::is_same_v) + Append("vec4(" + std::to_string(arg.x) + ", " + std::to_string(arg.y) + ", " + std::to_string(arg.z) + ", " + std::to_string(arg.w) + ")"); + else + static_assert(AlwaysFalse::value, "non-exhaustive visitor"); + }, node.value); } void GlslWriter::Visit(const ShaderNodes::DeclareVariable& node) diff --git a/src/Nazara/Renderer/ShaderNodes.cpp b/src/Nazara/Renderer/ShaderNodes.cpp index ddf5e09c7..da2157826 100644 --- a/src/Nazara/Renderer/ShaderNodes.cpp +++ b/src/Nazara/Renderer/ShaderNodes.cpp @@ -3,6 +3,7 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include +#include #include #include #include @@ -150,7 +151,23 @@ namespace Nz::ShaderNodes ShaderExpressionType Constant::GetExpressionType() const { - return exprType; + return std::visit([&](auto&& arg) + { + using T = std::decay_t; + + if constexpr (std::is_same_v) + return ShaderNodes::BasicType::Boolean; + else if constexpr (std::is_same_v) + return ShaderNodes::BasicType::Float1; + else if constexpr (std::is_same_v) + return ShaderNodes::BasicType::Float2; + else if constexpr (std::is_same_v) + return ShaderNodes::BasicType::Float3; + else if constexpr (std::is_same_v) + return ShaderNodes::BasicType::Float4; + else + static_assert(AlwaysFalse::value, "non-exhaustive visitor"); + }, value); } void Constant::Visit(ShaderVisitor& visitor) diff --git a/src/Nazara/Renderer/ShaderSerializer.cpp b/src/Nazara/Renderer/ShaderSerializer.cpp index 7441162a0..2433bf070 100644 --- a/src/Nazara/Renderer/ShaderSerializer.cpp +++ b/src/Nazara/Renderer/ShaderSerializer.cpp @@ -178,29 +178,30 @@ namespace Nz void ShaderSerializerBase::Serialize(ShaderNodes::Constant& node) { - Enum(node.exprType); + UInt32 typeIndex; + if (IsWriting()) + typeIndex = UInt32(node.value.index()); - switch (node.exprType) + Value(typeIndex); + + // Waiting for template lambda in C++20 + auto SerializeValue = [&](auto dummyType) { - case ShaderNodes::BasicType::Boolean: - Value(node.values.bool1); - break; + using T = std::decay_t; - case ShaderNodes::BasicType::Float1: - Value(node.values.vec1); - break; + auto& value = (IsWriting()) ? std::get(node.value) : node.value.emplace(); + Value(value); + }; - case ShaderNodes::BasicType::Float2: - Value(node.values.vec2); - break; - - case ShaderNodes::BasicType::Float3: - Value(node.values.vec3); - break; - - case ShaderNodes::BasicType::Float4: - Value(node.values.vec4); - break; + static_assert(std::variant_size_v == 5); + switch (typeIndex) + { + case 0: SerializeValue(bool()); break; + case 1: SerializeValue(float()); break; + case 2: SerializeValue(Vector2f()); break; + case 3: SerializeValue(Vector3f()); break; + case 4: SerializeValue(Vector4f()); break; + default: throw std::runtime_error("unexpected data type"); } } From 7fd3264d0823be72f25b03abcb634c9a323fb393 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Tue, 4 Aug 2020 01:33:52 +0200 Subject: [PATCH 078/105] Add FieldOffsets class --- include/Nazara/Utility/Enums.hpp | 34 +++++ include/Nazara/Utility/FieldOffsets.hpp | 52 ++++++++ include/Nazara/Utility/FieldOffsets.inl | 169 ++++++++++++++++++++++++ src/Nazara/Utility/FieldOffsets.cpp | 101 ++++++++++++++ 4 files changed, 356 insertions(+) create mode 100644 include/Nazara/Utility/FieldOffsets.hpp create mode 100644 include/Nazara/Utility/FieldOffsets.inl create mode 100644 src/Nazara/Utility/FieldOffsets.cpp diff --git a/include/Nazara/Utility/Enums.hpp b/include/Nazara/Utility/Enums.hpp index 7ac18a697..0e652448e 100644 --- a/include/Nazara/Utility/Enums.hpp +++ b/include/Nazara/Utility/Enums.hpp @@ -309,6 +309,40 @@ namespace Nz SamplerWrap_Max = SamplerWrap_Repeat }; + enum StructFieldType + { + StructFieldType_Bool1, + StructFieldType_Bool2, + StructFieldType_Bool3, + StructFieldType_Bool4, + StructFieldType_Float1, + StructFieldType_Float2, + StructFieldType_Float3, + StructFieldType_Float4, + StructFieldType_Double1, + StructFieldType_Double2, + StructFieldType_Double3, + StructFieldType_Double4, + StructFieldType_Int1, + StructFieldType_Int2, + StructFieldType_Int3, + StructFieldType_Int4, + StructFieldType_UInt1, + StructFieldType_UInt2, + StructFieldType_UInt3, + StructFieldType_UInt4, + + StructFieldType_Max = StructFieldType_UInt4 + }; + + enum StructLayout + { + StructLayout_Packed, + StructLayout_Std140, + + StructLayout_Max = StructLayout_Std140 + }; + enum StencilOperation { StencilOperation_Decrement, diff --git a/include/Nazara/Utility/FieldOffsets.hpp b/include/Nazara/Utility/FieldOffsets.hpp new file mode 100644 index 000000000..7cdeb83a9 --- /dev/null +++ b/include/Nazara/Utility/FieldOffsets.hpp @@ -0,0 +1,52 @@ +// Copyright (C) 2019 Jérôme Leclercq +// This file is part of the "Nazara Engine - Utility module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_FIELDOFFSETS_HPP +#define NAZARA_FIELDOFFSETS_HPP + +#include +#include + +namespace Nz +{ + class NAZARA_UTILITY_API FieldOffsets + { + public: + inline FieldOffsets(StructLayout layout); + FieldOffsets(const FieldOffsets&) = default; + FieldOffsets(FieldOffsets&&) = default; + ~FieldOffsets() = default; + + std::size_t AddField(StructFieldType type); + std::size_t AddFieldArray(StructFieldType type, std::size_t arraySize); + std::size_t AddMatrix(StructFieldType cellType, unsigned int columns, unsigned int rows, bool columnMajor); + std::size_t AddMatrixArray(StructFieldType cellType, unsigned int columns, unsigned int rows, bool columnMajor, std::size_t arraySize); + std::size_t AddStruct(const FieldOffsets& fieldStruct); + std::size_t AddStructArray(const FieldOffsets& fieldStruct, std::size_t arraySize); + + inline std::size_t GetLargestFieldAlignement() const; + inline std::size_t GetSize() const; + + FieldOffsets& operator=(const FieldOffsets&) = default; + FieldOffsets& operator=(FieldOffsets&&) = default; + + static std::size_t GetAlignement(StructLayout layout, StructFieldType fieldType); + static std::size_t GetCount(StructFieldType fieldType); + static std::size_t GetSize(StructFieldType fieldType); + + private: + static inline std::size_t Align(std::size_t source, std::size_t alignment); + + std::size_t m_largestFieldAlignment; + std::size_t m_offsetRounding; + std::size_t m_size; + StructLayout m_layout; + }; +} + +#include + +#endif // NAZARA_FIELDOFFSETS_HPP diff --git a/include/Nazara/Utility/FieldOffsets.inl b/include/Nazara/Utility/FieldOffsets.inl new file mode 100644 index 000000000..899e6a241 --- /dev/null +++ b/include/Nazara/Utility/FieldOffsets.inl @@ -0,0 +1,169 @@ +// Copyright (C) 2019 Jérôme Leclercq +// This file is part of the "Nazara Engine - Utility module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include + +namespace Nz +{ + inline FieldOffsets::FieldOffsets(StructLayout layout) : + m_largestFieldAlignment(1), + m_offsetRounding(1), + m_size(0), + m_layout(layout) + { + } + + inline std::size_t FieldOffsets::GetLargestFieldAlignement() const + { + return m_largestFieldAlignment; + } + + inline std::size_t FieldOffsets::GetSize() const + { + return m_size; + } + + inline std::size_t FieldOffsets::GetAlignement(StructLayout layout, StructFieldType fieldType) + { + switch (layout) + { + case StructLayout_Packed: + return 1; + + case StructLayout_Std140: + { + switch (fieldType) + { + case StructFieldType_Bool1: + case StructFieldType_Float1: + case StructFieldType_Int1: + case StructFieldType_UInt1: + return 4; + + case StructFieldType_Bool2: + case StructFieldType_Float2: + case StructFieldType_Int2: + case StructFieldType_UInt2: + return 2 * 4; + + case StructFieldType_Bool3: + case StructFieldType_Float3: + case StructFieldType_Int3: + case StructFieldType_UInt3: + case StructFieldType_Bool4: + case StructFieldType_Float4: + case StructFieldType_Int4: + case StructFieldType_UInt4: + return 4 * 4; + + case StructFieldType_Double1: + return 8; + + case StructFieldType_Double2: + return 2 * 8; + + case StructFieldType_Double3: + case StructFieldType_Double4: + return 4 * 8; + } + } + } + + return 0; + } + + inline std::size_t FieldOffsets::GetCount(StructFieldType fieldType) + { + switch (fieldType) + { + case StructFieldType_Bool1: + case StructFieldType_Double1: + case StructFieldType_Float1: + case StructFieldType_Int1: + case StructFieldType_UInt1: + return 1; + + case StructFieldType_Bool2: + case StructFieldType_Double2: + case StructFieldType_Float2: + case StructFieldType_Int2: + case StructFieldType_UInt2: + return 2; + + case StructFieldType_Bool3: + case StructFieldType_Double3: + case StructFieldType_Float3: + case StructFieldType_Int3: + case StructFieldType_UInt3: + return 3; + + case StructFieldType_Bool4: + case StructFieldType_Double4: + case StructFieldType_Float4: + case StructFieldType_Int4: + case StructFieldType_UInt4: + return 4; + } + + return 0; + } + + inline std::size_t FieldOffsets::GetSize(StructFieldType fieldType) + { + switch (fieldType) + { + case StructFieldType_Bool1: + case StructFieldType_Float1: + case StructFieldType_Int1: + case StructFieldType_UInt1: + return 4; + + case StructFieldType_Bool2: + case StructFieldType_Float2: + case StructFieldType_Int2: + case StructFieldType_UInt2: + return 2 * 4; + + case StructFieldType_Bool3: + case StructFieldType_Float3: + case StructFieldType_Int3: + case StructFieldType_UInt3: + return 3 * 4; + + case StructFieldType_Bool4: + case StructFieldType_Float4: + case StructFieldType_Int4: + case StructFieldType_UInt4: + return 4 * 4; + + case StructFieldType_Double1: + return 8; + + case StructFieldType_Double2: + return 2 * 8; + + case StructFieldType_Double3: + return 3 * 8; + + case StructFieldType_Double4: + return 4 * 8; + } + + return 0; + } + + inline std::size_t FieldOffsets::Align(std::size_t source, std::size_t alignment) + { + if (source == 0) + return source; + + assert(alignment > 0); + return ((source + alignment - 1) / alignment) * alignment; + } +} + +#include diff --git a/src/Nazara/Utility/FieldOffsets.cpp b/src/Nazara/Utility/FieldOffsets.cpp new file mode 100644 index 000000000..76cb50e71 --- /dev/null +++ b/src/Nazara/Utility/FieldOffsets.cpp @@ -0,0 +1,101 @@ +// Copyright (C) 2019 Jérôme Leclercq +// This file is part of the "Nazara Engine - Utility module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include + +namespace Nz +{ + std::size_t FieldOffsets::AddField(StructFieldType type) + { + std::size_t fieldAlignement = GetAlignement(m_layout, type); + + m_largestFieldAlignment = std::max(m_largestFieldAlignment, fieldAlignement); + + std::size_t offset = Align(m_size, Align(fieldAlignement, m_offsetRounding)); + m_size = offset + GetSize(type); + + m_offsetRounding = 1; + + return offset; + } + + std::size_t FieldOffsets::AddFieldArray(StructFieldType type, std::size_t arraySize) + { + std::size_t fieldAlignement = GetAlignement(m_layout, type); + if (m_layout == StructLayout_Std140) + fieldAlignement = Align(fieldAlignement, GetAlignement(StructLayout_Std140, StructFieldType_Float4)); + + m_largestFieldAlignment = std::max(fieldAlignement, m_largestFieldAlignment); + + std::size_t offset = Align(m_size, Align(fieldAlignement, m_offsetRounding)); + m_size = offset + GetSize(type) * arraySize; + + m_offsetRounding = 1; + + return offset; + } + + std::size_t FieldOffsets::AddMatrix(StructFieldType cellType, unsigned int columns, unsigned int rows, bool columnMajor) + { + assert(GetCount(cellType) == 1); + assert(columns >= 2 && columns <= 4); + assert(rows >= 2 && rows <= 4); + + if (columnMajor) + return AddFieldArray(static_cast(cellType + rows - 1), columns); + else + return AddFieldArray(static_cast(cellType + columns - 1), rows); + } + + std::size_t FieldOffsets::AddMatrixArray(StructFieldType cellType, unsigned int columns, unsigned int rows, bool columnMajor, std::size_t arraySize) + { + assert(GetCount(cellType) == 1); + assert(columns >= 2 && columns <= 4); + assert(rows >= 2 && rows <= 4); + + if (columnMajor) + return AddFieldArray(static_cast(cellType + rows - 1), columns * arraySize); + else + return AddFieldArray(static_cast(cellType + columns - 1), rows * arraySize); + } + + std::size_t FieldOffsets::AddStruct(const FieldOffsets& fieldStruct) + { + std::size_t fieldAlignement = fieldStruct.GetLargestFieldAlignement(); + if (m_layout == StructLayout_Std140) + fieldAlignement = Align(fieldAlignement, GetAlignement(StructLayout_Std140, StructFieldType_Float4)); + + m_largestFieldAlignment = std::max(m_largestFieldAlignment, fieldAlignement); + + std::size_t offset = Align(m_size, Align(fieldAlignement, m_offsetRounding)); + m_size = offset + fieldStruct.GetSize(); + + m_offsetRounding = std::max(Align(fieldStruct.GetSize(), fieldAlignement) - fieldStruct.GetSize(), 1); + + return offset; + } + + std::size_t FieldOffsets::AddStructArray(const FieldOffsets& fieldStruct, std::size_t arraySize) + { + assert(arraySize > 0); + + std::size_t fieldAlignement = fieldStruct.GetLargestFieldAlignement(); + if (m_layout == StructLayout_Std140) + fieldAlignement = Align(fieldAlignement, GetAlignement(StructLayout_Std140, StructFieldType_Float4)); + + m_largestFieldAlignment = std::max(m_largestFieldAlignment, fieldAlignement); + + std::size_t offset = Align(m_size, Align(fieldAlignement, m_offsetRounding)); + m_size = offset + + fieldStruct.GetSize() * arraySize + + (Align(fieldStruct.GetSize(), fieldAlignement) - fieldStruct.GetSize()) * (arraySize - 1); + + m_offsetRounding = fieldAlignement; + + return offset; + } +} From 7a5f91f74089c39f0ebeacfc607374b542eeefc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Tue, 4 Aug 2020 01:35:30 +0200 Subject: [PATCH 079/105] SpivWriter WIP We have debug label, annotations, types and constants. The big part missing is instructions --- include/Nazara/Renderer/SpirvWriter.hpp | 51 +- include/Nazara/Renderer/SpirvWriter.inl | 37 +- src/Nazara/Renderer/SpirvWriter.cpp | 682 +++++++++++++++++++----- 3 files changed, 594 insertions(+), 176 deletions(-) diff --git a/include/Nazara/Renderer/SpirvWriter.hpp b/include/Nazara/Renderer/SpirvWriter.hpp index e95bc5a4e..5786ea55b 100644 --- a/include/Nazara/Renderer/SpirvWriter.hpp +++ b/include/Nazara/Renderer/SpirvWriter.hpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -41,33 +42,49 @@ namespace Nz private: struct Opcode; + struct Raw; + struct WordCount; - inline std::size_t Append(const char* str); - inline std::size_t Append(const std::string_view& str); - inline std::size_t Append(const std::string& str); - std::size_t Append(UInt32 value); - std::size_t Append(const Opcode& opcode, unsigned int wordCount); - inline std::size_t Append(std::initializer_list codepoints); - template std::size_t Append(Opcode opcode, const Args&... args); - template std::size_t Append(T value); + struct Section + { + inline std::size_t Append(const char* str); + inline std::size_t Append(const std::string_view& str); + inline std::size_t Append(const std::string& str); + inline std::size_t Append(UInt32 value); + std::size_t Append(const Opcode& opcode, const WordCount& wordCount); + std::size_t Append(const Raw& raw); + inline std::size_t Append(std::initializer_list codepoints); + template std::size_t Append(Opcode opcode, const Args&... args); + template std::size_t Append(T value); + + inline unsigned int CountWord(const char* str); + inline unsigned int CountWord(const std::string_view& str); + inline unsigned int CountWord(const std::string& str); + unsigned int CountWord(const Raw& raw); + template unsigned int CountWord(const T& value); + template unsigned int CountWord(const T1& value, const T2& value2, const Args&... rest); + + inline std::size_t GetOutputOffset() const; + + std::vector data; + }; UInt32 AllocateResultId(); + void AppendConstants(); void AppendHeader(); + void AppendStructType(std::size_t structIndex, UInt32 resultId); void AppendTypes(); - inline unsigned int CountWord(const char* str); - unsigned int CountWord(const std::string_view& str); - inline unsigned int CountWord(const std::string& str); - template unsigned int CountWord(const T& value); - template unsigned int CountWord(const T1& value, const T2& value2, const Args&... rest); + UInt32 GetConstantId(const ShaderNodes::Constant::Variant& value) const; + UInt32 GetTypeId(const ShaderExpressionType& type) const; - std::size_t GetOutputOffset() const; + void PushResultId(UInt32 value); + UInt32 PopResultId(); - UInt32 ProcessType(ShaderExpressionType type); + UInt32 RegisterType(ShaderExpressionType type); using ShaderVisitor::Visit; - void Visit(const ShaderNodes::ExpressionPtr& expr, bool encloseIfRequired = false); void Visit(const ShaderNodes::AccessMember& node) override; void Visit(const ShaderNodes::AssignOp& node) override; void Visit(const ShaderNodes::Branch& node) override; @@ -82,7 +99,7 @@ namespace Nz void Visit(const ShaderNodes::StatementBlock& node) override; void Visit(const ShaderNodes::SwizzleOp& node) override; - static void MergeBlocks(std::vector& output, const std::vector& from); + static void MergeBlocks(std::vector& output, const Section& from); struct Context { diff --git a/include/Nazara/Renderer/SpirvWriter.inl b/include/Nazara/Renderer/SpirvWriter.inl index 5d0bbd328..2e75f1271 100644 --- a/include/Nazara/Renderer/SpirvWriter.inl +++ b/include/Nazara/Renderer/SpirvWriter.inl @@ -9,12 +9,12 @@ namespace Nz { - inline std::size_t SpirvWriter::Append(const char* str) + inline std::size_t SpirvWriter::Section::Append(const char* str) { return Append(std::string_view(str)); } - inline std::size_t SpirvWriter::Append(const std::string_view& str) + inline std::size_t SpirvWriter::Section::Append(const std::string_view& str) { std::size_t offset = GetOutputOffset(); @@ -35,12 +35,20 @@ namespace Nz return offset; } - inline std::size_t SpirvWriter::Append(const std::string& str) + inline std::size_t SpirvWriter::Section::Append(const std::string& str) { return Append(std::string_view(str)); } - inline std::size_t SpirvWriter::Append(std::initializer_list codepoints) + inline std::size_t SpirvWriter::Section::Append(UInt32 value) + { + std::size_t offset = GetOutputOffset(); + data.push_back(value); + + return offset; + } + + inline std::size_t SpirvWriter::Section::Append(std::initializer_list codepoints) { std::size_t offset = GetOutputOffset(); @@ -51,10 +59,10 @@ namespace Nz } template - inline std::size_t SpirvWriter::Append(Opcode opcode, const Args&... args) + std::size_t SpirvWriter::Section::Append(Opcode opcode, const Args&... args) { unsigned int wordCount = 1 + (CountWord(args) + ... + 0); - std::size_t offset = Append(opcode, wordCount); + std::size_t offset = Append(opcode, WordCount{ wordCount }); if constexpr (sizeof...(args) > 0) (Append(args), ...); @@ -62,37 +70,42 @@ namespace Nz } template - inline std::size_t SpirvWriter::Append(T value) + std::size_t SpirvWriter::Section::Append(T value) { return Append(static_cast(value)); } template - inline unsigned int SpirvWriter::CountWord(const T& value) + unsigned int SpirvWriter::Section::CountWord(const T& value) { return 1; } template - unsigned int SpirvWriter::CountWord(const T1& value, const T2& value2, const Args&... rest) + unsigned int SpirvWriter::Section::CountWord(const T1& value, const T2& value2, const Args&... rest) { return CountWord(value) + CountWord(value2) + (CountWord(rest) + ...); } - inline unsigned int SpirvWriter::CountWord(const char* str) + inline unsigned int SpirvWriter::Section::CountWord(const char* str) { return CountWord(std::string_view(str)); } - inline unsigned int Nz::SpirvWriter::CountWord(const std::string& str) + inline unsigned int Nz::SpirvWriter::Section::CountWord(const std::string& str) { return CountWord(std::string_view(str)); } - inline unsigned int SpirvWriter::CountWord(const std::string_view& str) + inline unsigned int SpirvWriter::Section::CountWord(const std::string_view& str) { return (static_cast(str.size() + 1) + sizeof(UInt32) - 1) / sizeof(UInt32); //< + 1 for null character } + + std::size_t SpirvWriter::Section::GetOutputOffset() const + { + return data.size(); + } } #include diff --git a/src/Nazara/Renderer/SpirvWriter.cpp b/src/Nazara/Renderer/SpirvWriter.cpp index 24d9fcd84..1ccf23f97 100644 --- a/src/Nazara/Renderer/SpirvWriter.cpp +++ b/src/Nazara/Renderer/SpirvWriter.cpp @@ -4,8 +4,10 @@ #include #include +#include #include #include +#include #include #include #include @@ -18,10 +20,13 @@ namespace Nz { namespace { + using ConstantVariant = ShaderNodes::Constant::Variant; + class PreVisitor : public ShaderRecursiveVisitor, public ShaderVarVisitor { public: using BuiltinContainer = std::unordered_set>; + using ConstantContainer = tsl::ordered_set; using ExtInstList = std::unordered_set; using LocalContainer = std::unordered_set>; using ParameterContainer = std::unordered_set< std::shared_ptr>; @@ -29,14 +34,55 @@ namespace Nz using ShaderRecursiveVisitor::Visit; using ShaderVarVisitor::Visit; + void Visit(const ShaderNodes::Constant& node) override + { + std::visit([&](auto&& arg) + { + using T = std::decay_t; + + if constexpr (std::is_same_v || std::is_same_v) + constants.emplace(arg); + else if constexpr (std::is_same_v) + { + constants.emplace(arg.x); + constants.emplace(arg.y); + constants.emplace(arg); + } + else if constexpr (std::is_same_v) + { + constants.emplace(arg.x); + constants.emplace(arg.y); + constants.emplace(arg.z); + constants.emplace(arg); + } + else if constexpr (std::is_same_v) + { + constants.emplace(arg.x); + constants.emplace(arg.y); + constants.emplace(arg.z); + constants.emplace(arg.w); + constants.emplace(arg); + } + else + static_assert(AlwaysFalse::value, "non-exhaustive visitor"); + }, + node.value); + + ShaderRecursiveVisitor::Visit(node); + } + void Visit(const ShaderNodes::DeclareVariable& node) override { Visit(node.variable); + + ShaderRecursiveVisitor::Visit(node); } void Visit(const ShaderNodes::Identifier& node) override { Visit(node.var); + + ShaderRecursiveVisitor::Visit(node); } void Visit(const ShaderNodes::IntrinsicCall& node) override @@ -87,6 +133,7 @@ namespace Nz } BuiltinContainer builtinVars; + ConstantContainer constants; ExtInstList extInsts; LocalContainer localVars; ParameterContainer paramVars; @@ -98,24 +145,51 @@ namespace Nz SpvOp op; }; + struct SpirvWriter::Raw + { + const void* ptr; + std::size_t size; + }; + + struct SpirvWriter::WordCount + { + unsigned int wc; + }; + struct SpirvWriter::State { - std::size_t boundIndex; + struct Func + { + UInt32 typeId; + UInt32 id; + std::vector paramsId; + }; + + struct ExtVar + { + UInt32 pointerTypeId; + UInt32 varId; + }; + std::unordered_map extensionInstructions; std::unordered_map builtinIds; + tsl::ordered_map constantIds; tsl::ordered_map typeIds; - std::vector funcIds; - std::vector funcTypeIds; - std::vector inputIds; - std::vector outputIds; - std::vector uniformIds; + std::vector funcs; + std::vector inputIds; + std::vector outputIds; + std::vector uniformIds; + std::vector> structFields; + std::vector resultIds; UInt32 nextVarIndex = 1; // Output - std::vector* output; - std::vector header; - std::vector info; - std::vector instructions; + Section header; + Section constants; + Section debugInfo; + Section annotations; + Section types; + Section instructions; }; SpirvWriter::SpirvWriter() : @@ -138,74 +212,154 @@ namespace Nz m_currentState = nullptr; }); + state.structFields.resize(shader.GetStructCount()); + state.annotations.Append(Opcode{ SpvOpNop }); + state.constants.Append(Opcode{ SpvOpNop }); + state.debugInfo.Append(Opcode{ SpvOpNop }); + state.types.Append(Opcode{ SpvOpNop }); + PreVisitor preVisitor; for (const auto& func : shader.GetFunctions()) preVisitor.Visit(func.statement); // Register all extended instruction sets for (const std::string& extInst : preVisitor.extInsts) - m_currentState->extensionInstructions[extInst] = AllocateResultId(); + state.extensionInstructions[extInst] = AllocateResultId(); // Register all types - state.output = &state.instructions; - for (const auto& func : shader.GetFunctions()) { - ProcessType(func.returnType); + RegisterType(func.returnType); for (const auto& param : func.parameters) - ProcessType(param.type); - - m_currentState->funcTypeIds.push_back(AllocateResultId()); + RegisterType(param.type); } for (const auto& input : shader.GetInputs()) - ProcessType(input.type); + RegisterType(input.type); for (const auto& output : shader.GetOutputs()) - ProcessType(output.type); + RegisterType(output.type); for (const auto& uniform : shader.GetUniforms()) - ProcessType(uniform.type); + RegisterType(uniform.type); for (const auto& local : preVisitor.localVars) - ProcessType(local->type); + RegisterType(local->type); + + // Register constant types + for (const auto& constant : preVisitor.constants) + { + std::visit([&](auto&& arg) + { + using T = std::decay_t; + + if constexpr (std::is_same_v) + RegisterType(ShaderNodes::BasicType::Boolean); + else if constexpr (std::is_same_v) + RegisterType(ShaderNodes::BasicType::Float1); + else if constexpr (std::is_same_v) + RegisterType(ShaderNodes::BasicType::Float2); + else if constexpr (std::is_same_v) + RegisterType(ShaderNodes::BasicType::Float3); + else if constexpr (std::is_same_v) + RegisterType(ShaderNodes::BasicType::Float4); + else + static_assert(AlwaysFalse::value, "non-exhaustive visitor"); + }, constant); + } + + AppendTypes(); // Register result id and debug infos for global variables/functions - state.output = &state.info; - for (const auto& input : shader.GetInputs()) { - UInt32 resultId = AllocateResultId(); - Append(Opcode{ SpvOpName }, resultId, input.name); + auto& inputData = state.inputIds.emplace_back(); + inputData.pointerTypeId = AllocateResultId(); + inputData.varId = AllocateResultId(); - m_currentState->inputIds.push_back(resultId); + state.debugInfo.Append(Opcode{ SpvOpName }, inputData.varId, input.name); + state.types.Append(Opcode{ SpvOpTypePointer }, inputData.pointerTypeId, SpvStorageClassInput, GetTypeId(input.type)); + state.types.Append(Opcode{ SpvOpVariable }, inputData.pointerTypeId, inputData.varId, SpvStorageClassInput); + + if (input.locationIndex) + state.annotations.Append(Opcode{ SpvOpDecorate }, inputData.varId, SpvDecorationLocation, *input.locationIndex); } for (const auto& output : shader.GetOutputs()) { - UInt32 resultId = AllocateResultId(); - Append(Opcode{ SpvOpName }, resultId, output.name); + auto& outputData = state.outputIds.emplace_back(); + outputData.pointerTypeId = AllocateResultId(); + outputData.varId = AllocateResultId(); - m_currentState->outputIds.push_back(resultId); + state.debugInfo.Append(Opcode{ SpvOpName }, outputData.varId, output.name); + state.types.Append(Opcode{ SpvOpTypePointer }, outputData.pointerTypeId, SpvStorageClassOutput, GetTypeId(output.type)); + state.types.Append(Opcode{ SpvOpVariable }, outputData.pointerTypeId, outputData.varId, SpvStorageClassOutput); + + if (output.locationIndex) + state.annotations.Append(Opcode{ SpvOpDecorate }, outputData.varId, SpvDecorationLocation, *output.locationIndex); } for (const auto& uniform : shader.GetUniforms()) { - UInt32 resultId = AllocateResultId(); - Append(Opcode{ SpvOpName }, resultId, uniform.name); + auto& uniformData = state.uniformIds.emplace_back(); + uniformData.pointerTypeId = AllocateResultId(); + uniformData.varId = AllocateResultId(); - m_currentState->uniformIds.push_back(resultId); + state.debugInfo.Append(Opcode{ SpvOpName }, uniformData.varId, uniform.name); + state.types.Append(Opcode{ SpvOpTypePointer }, uniformData.pointerTypeId, SpvStorageClassUniform, GetTypeId(uniform.type)); + state.types.Append(Opcode{ SpvOpVariable }, uniformData.pointerTypeId, uniformData.varId, SpvStorageClassUniform); + + if (uniform.bindingIndex) + { + state.annotations.Append(Opcode{ SpvOpDecorate }, uniformData.varId, SpvDecorationBinding, *uniform.bindingIndex); + state.annotations.Append(Opcode{ SpvOpDecorate }, uniformData.varId, SpvDecorationDescriptorSet, 0); + } } for (const auto& func : shader.GetFunctions()) { - UInt32 resultId = AllocateResultId(); - Append(Opcode{ SpvOpName }, resultId, func.name); + auto& funcData = state.funcs.emplace_back(); + funcData.id = AllocateResultId(); + funcData.typeId = AllocateResultId(); - m_currentState->funcIds.push_back(resultId); + state.debugInfo.Append(Opcode{ SpvOpName }, funcData.id, func.name); + + state.types.Append(Opcode{ SpvOpTypeFunction }, WordCount{ 3 + static_cast(func.parameters.size()) }); + state.types.Append(funcData.typeId); + state.types.Append(GetTypeId(func.returnType)); + + for (const auto& param : func.parameters) + state.types.Append(GetTypeId(param.type)); } - state.output = &state.header; + // Register constants + for (const auto& constant : preVisitor.constants) + state.constantIds[constant] = AllocateResultId(); + + AppendConstants(); + + for (std::size_t funcIndex = 0; funcIndex < shader.GetFunctionCount(); ++funcIndex) + { + const auto& func = shader.GetFunction(funcIndex); + + auto& funcData = state.funcs[funcIndex]; + + state.instructions.Append(Opcode{ SpvOpNop }); + + state.instructions.Append(Opcode{ SpvOpFunction }, GetTypeId(func.returnType), funcData.id, 0, funcData.typeId); + + for (const auto& param : func.parameters) + { + UInt32 paramResultId = AllocateResultId(); + funcData.paramsId.push_back(paramResultId); + + state.instructions.Append(Opcode{ SpvOpFunctionParameter }, GetTypeId(param.type), paramResultId); + } + + Visit(func.statement); + + state.instructions.Append(Opcode{ SpvOpFunctionEnd }); + } AppendHeader(); @@ -221,13 +375,12 @@ namespace Nz break; }*/ - state.header[state.boundIndex] = state.nextVarIndex; - std::vector ret; - ret.reserve(state.header.size() + state.info.size() + state.instructions.size()); - MergeBlocks(ret, state.header); - MergeBlocks(ret, state.info); + MergeBlocks(ret, state.debugInfo); + MergeBlocks(ret, state.annotations); + MergeBlocks(ret, state.types); + MergeBlocks(ret, state.constants); MergeBlocks(ret, state.instructions); return ret; @@ -238,41 +391,125 @@ namespace Nz m_environment = std::move(environment); } - std::size_t Nz::SpirvWriter::Append(UInt32 value) - { - std::size_t offset = GetOutputOffset(); - m_currentState->output->push_back(value); - - return offset; - } - - std::size_t SpirvWriter::Append(const Opcode& opcode, unsigned int wordCount) - { - return Append(UInt32(opcode.op) | UInt32(wordCount) << 16); - } - UInt32 Nz::SpirvWriter::AllocateResultId() { return m_currentState->nextVarIndex++; } + void SpirvWriter::AppendConstants() + { + for (const auto& [value, resultId] : m_currentState->constantIds) + { + UInt32 constantId = resultId; + std::visit([&](auto&& arg) + { + using T = std::decay_t; + + if constexpr (std::is_same_v) + m_currentState->constants.Append(Opcode{ (arg) ? SpvOpConstantTrue : SpvOpConstantFalse }, constantId); + else if constexpr (std::is_same_v) + m_currentState->constants.Append(Opcode{ SpvOpConstant }, GetTypeId(ShaderNodes::BasicType::Float1), constantId, Raw{ &arg, sizeof(arg) }); + else if constexpr (std::is_same_v) + m_currentState->constants.Append(Opcode{ SpvOpConstantComposite }, GetTypeId(ShaderNodes::BasicType::Float2), constantId, GetConstantId(arg.x), GetConstantId(arg.y)); + else if constexpr (std::is_same_v) + m_currentState->constants.Append(Opcode{ SpvOpConstantComposite }, GetTypeId(ShaderNodes::BasicType::Float3), constantId, GetConstantId(arg.x), GetConstantId(arg.y), GetConstantId(arg.z)); + else if constexpr (std::is_same_v) + m_currentState->constants.Append(Opcode{ SpvOpConstantComposite }, GetTypeId(ShaderNodes::BasicType::Float3), constantId, GetConstantId(arg.x), GetConstantId(arg.y), GetConstantId(arg.z), GetConstantId(arg.w)); + else + static_assert(AlwaysFalse::value, "non-exhaustive visitor"); + }, value); + } + } + void SpirvWriter::AppendHeader() { - Append(SpvMagicNumber); //< Spir-V magic number + m_currentState->header.Append(SpvMagicNumber); //< Spir-V magic number UInt32 version = (m_environment.spvMajorVersion << 16) | m_environment.spvMinorVersion << 8; - Append(version); //< Spir-V version number (1.0 for compatibility) - Append(0); //< Generator identifier (TODO: Register generator to Khronos) + m_currentState->header.Append(version); //< Spir-V version number (1.0 for compatibility) + m_currentState->header.Append(0); //< Generator identifier (TODO: Register generator to Khronos) - m_currentState->boundIndex = Append(0); //< Bound (ID count), will be filled later - Append(0); //< Instruction schema (required to be 0 for now) + m_currentState->header.Append(m_currentState->nextVarIndex); //< Bound (ID count) + m_currentState->header.Append(0); //< Instruction schema (required to be 0 for now) - Append(Opcode{ SpvOpCapability }, SpvCapabilityShader); + m_currentState->header.Append(Opcode{ SpvOpCapability }, SpvCapabilityShader); for (const auto& [extInst, resultId] : m_currentState->extensionInstructions) - Append(Opcode{ SpvOpExtInstImport }, resultId, extInst); + m_currentState->header.Append(Opcode{ SpvOpExtInstImport }, resultId, extInst); - Append(Opcode{ SpvOpMemoryModel }, SpvAddressingModelLogical, SpvMemoryModelGLSL450); + m_currentState->header.Append(Opcode{ SpvOpMemoryModel }, SpvAddressingModelLogical, SpvMemoryModelGLSL450); + } + + void SpirvWriter::AppendStructType(std::size_t structIndex, UInt32 resultId) + { + const ShaderAst::Struct& s = m_context.shader->GetStruct(structIndex); + + m_currentState->types.Append(Opcode{ SpvOpTypeStruct }, WordCount{ static_cast(1 + 1 + s.members.size()) }); + m_currentState->types.Append(resultId); + + m_currentState->debugInfo.Append(Opcode{ SpvOpName }, resultId, s.name); + + m_currentState->annotations.Append(Opcode{ SpvOpDecorate }, resultId, SpvDecorationBlock); + + FieldOffsets structOffsets(StructLayout_Std140); + + for (std::size_t memberIndex = 0; memberIndex < s.members.size(); ++memberIndex) + { + const auto& member = s.members[memberIndex]; + m_currentState->types.Append(GetTypeId(member.type)); + m_currentState->debugInfo.Append(Opcode{ SpvOpMemberName }, resultId, memberIndex, member.name); + + std::visit([&](auto&& arg) + { + using T = std::decay_t; + if constexpr (std::is_same_v) + { + std::size_t offset = [&] { + switch (arg) + { + case ShaderNodes::BasicType::Boolean: return structOffsets.AddField(StructFieldType_Bool1); + case ShaderNodes::BasicType::Float1: return structOffsets.AddField(StructFieldType_Float1); + case ShaderNodes::BasicType::Float2: return structOffsets.AddField(StructFieldType_Float2); + case ShaderNodes::BasicType::Float3: return structOffsets.AddField(StructFieldType_Float3); + case ShaderNodes::BasicType::Float4: return structOffsets.AddField(StructFieldType_Float4); + case ShaderNodes::BasicType::Mat4x4: return structOffsets.AddMatrix(StructFieldType_Float1, 4, 4, true); + case ShaderNodes::BasicType::Sampler2D: throw std::runtime_error("unexpected sampler2D as struct member"); + case ShaderNodes::BasicType::Void: throw std::runtime_error("unexpected void as struct member"); + } + + assert(false); + throw std::runtime_error("unhandled type"); + }(); + + m_currentState->annotations.Append(Opcode{ SpvOpMemberDecorate }, resultId, memberIndex, SpvDecorationOffset, offset); + + if (arg == ShaderNodes::BasicType::Mat4x4) + { + m_currentState->annotations.Append(Opcode{ SpvOpMemberDecorate }, resultId, memberIndex, SpvDecorationColMajor); + m_currentState->annotations.Append(Opcode{ SpvOpMemberDecorate }, resultId, memberIndex, SpvDecorationMatrixStride, 16); + } + } + else if constexpr (std::is_same_v) + { + // Register struct members type + const auto& structs = m_context.shader->GetStructs(); + auto it = std::find_if(structs.begin(), structs.end(), [&](const auto& s) { return s.name == arg; }); + if (it == structs.end()) + throw std::runtime_error("struct " + arg + " has not been defined"); + + std::size_t nestedStructIndex = std::distance(structs.begin(), it); + std::optional nestedFieldOffset = m_currentState->structFields[nestedStructIndex]; + if (!nestedFieldOffset) + throw std::runtime_error("struct dependency cycle"); + + structOffsets.AddStruct(nestedFieldOffset.value()); + } + else + static_assert(AlwaysFalse::value, "non-exhaustive visitor"); + }, member.type); + } + + m_currentState->structFields[structIndex] = structOffsets; } void SpirvWriter::AppendTypes() @@ -287,28 +524,127 @@ namespace Nz using T = std::decay_t; if constexpr (std::is_same_v) { - // In SPIR-V, vec3 (for example) depends on float - UInt32 depResultId; - if (ShaderNodes::Node::GetComponentCount(arg) != 1) - depResultId = ProcessType(ShaderNodes::Node::GetComponentType(arg)); - switch (arg) { case ShaderNodes::BasicType::Boolean: - Append(Opcode{ SpvOpTypeBool }, resultId); + m_currentState->types.Append(Opcode{ SpvOpTypeBool }, resultId); break; case ShaderNodes::BasicType::Float1: - Append(Opcode{ SpvOpTypeFloat }, resultId); + m_currentState->types.Append(Opcode{ SpvOpTypeFloat }, resultId, 32); break; case ShaderNodes::BasicType::Float2: case ShaderNodes::BasicType::Float3: case ShaderNodes::BasicType::Float4: + { + UInt32 vecSize = UInt32(arg) - UInt32(ShaderNodes::BasicType::Float2) + 1; + + m_currentState->types.Append(Opcode{ SpvOpTypeVector }, resultId, GetTypeId(ShaderNodes::BasicType::Float1), vecSize); + break; + } + case ShaderNodes::BasicType::Mat4x4: + { + m_currentState->types.Append(Opcode{ SpvOpTypeMatrix }, resultId, GetTypeId(ShaderNodes::BasicType::Float4), 4); + break; + } + case ShaderNodes::BasicType::Sampler2D: + { + UInt32 imageTypeId = resultId - 1; + + m_currentState->types.Append(Opcode{ SpvOpTypeImage }, imageTypeId, GetTypeId(ShaderNodes::BasicType::Float1), SpvDim2D, 0, 0, 0, 1, SpvImageFormatUnknown); + m_currentState->types.Append(Opcode{ SpvOpTypeSampledImage }, resultId, imageTypeId); + break; + } + case ShaderNodes::BasicType::Void: - Append(Opcode{ SpvOpTypeVoid }, resultId); + m_currentState->types.Append(Opcode{ SpvOpTypeVoid }, resultId); + break; + } + } + else if constexpr (std::is_same_v) + { + // Register struct members type + const auto& structs = m_context.shader->GetStructs(); + auto it = std::find_if(structs.begin(), structs.end(), [&](const auto& s) { return s.name == arg; }); + if (it == structs.end()) + throw std::runtime_error("struct " + arg + " has not been defined"); + + std::size_t structIndex = std::distance(structs.begin(), it); + AppendStructType(structIndex, resultId); + } + else + static_assert(AlwaysFalse::value, "non-exhaustive visitor"); + }, type); + } + } + + UInt32 SpirvWriter::GetConstantId(const ShaderNodes::Constant::Variant& value) const + { + auto typeIt = m_currentState->constantIds.find(value); + assert(typeIt != m_currentState->constantIds.end()); + + return typeIt->second; + } + + UInt32 SpirvWriter::GetTypeId(const ShaderExpressionType& type) const + { + auto typeIt = m_currentState->typeIds.find(type); + assert(typeIt != m_currentState->typeIds.end()); + + return typeIt->second; + } + + void SpirvWriter::PushResultId(UInt32 value) + { + m_currentState->resultIds.push_back(value); + } + + UInt32 SpirvWriter::PopResultId() + { + if (m_currentState->resultIds.empty()) + throw std::runtime_error("invalid operation"); + + UInt32 resultId = m_currentState->resultIds.back(); + m_currentState->resultIds.pop_back(); + + return resultId; + } + + UInt32 SpirvWriter::RegisterType(ShaderExpressionType type) + { + auto it = m_currentState->typeIds.find(type); + if (it == m_currentState->typeIds.end()) + { + // Register sub-types, if any + std::visit([&](auto&& arg) + { + using T = std::decay_t; + if constexpr (std::is_same_v) + { + switch (arg) + { + case ShaderNodes::BasicType::Boolean: + case ShaderNodes::BasicType::Float1: + case ShaderNodes::BasicType::Void: + break; //< Nothing to do + + // In SPIR-V, vec3 (for example) depends on float + case ShaderNodes::BasicType::Float2: + case ShaderNodes::BasicType::Float3: + case ShaderNodes::BasicType::Float4: + RegisterType(ShaderNodes::BasicType::Float1); + break; + + case ShaderNodes::BasicType::Mat4x4: + RegisterType(ShaderNodes::BasicType::Float4); + break; + + case ShaderNodes::BasicType::Sampler2D: + RegisterType(ShaderNodes::BasicType::Float1); + AllocateResultId(); //< Reserve a result id for the image type break; } } @@ -322,46 +658,7 @@ namespace Nz const ShaderAst::Struct& s = *it; for (const auto& member : s.members) - ProcessType(member.type); - } - else - static_assert(AlwaysFalse::value, "non-exhaustive visitor"); - }, type); - } - } - - std::size_t SpirvWriter::GetOutputOffset() const - { - assert(m_currentState); - return m_currentState->output->size(); - } - - UInt32 SpirvWriter::ProcessType(ShaderExpressionType type) - { - auto it = m_currentState->typeIds.find(type); - if (it == m_currentState->typeIds.end()) - { - // Register sub-types, if any - std::visit([&](auto&& arg) - { - using T = std::decay_t; - if constexpr (std::is_same_v) - { - // In SPIR-V, vec3 (for example) depends on float - if (ShaderNodes::Node::GetComponentCount(arg) != 1) - ProcessType(ShaderNodes::Node::GetComponentType(arg)); - } - else if constexpr (std::is_same_v) - { - // Register struct members type - const auto& structs = m_context.shader->GetStructs(); - auto it = std::find_if(structs.begin(), structs.end(), [&](const auto& s) { return s.name == arg; }); - if (it == structs.end()) - throw std::runtime_error("struct " + arg + " has not been defined"); - - const ShaderAst::Struct& s = *it; - for (const auto& member : s.members) - ProcessType(member.type); + RegisterType(member.type); } else static_assert(AlwaysFalse::value, "non-exhaustive visitor"); @@ -373,56 +670,147 @@ namespace Nz return it->second; } - void SpirvWriter::Visit(const ShaderNodes::ExpressionPtr& expr, bool encloseIfRequired) - { - } - void SpirvWriter::Visit(const ShaderNodes::AccessMember& /*node*/) - { - } - void SpirvWriter::Visit(const ShaderNodes::AssignOp& /*node*/) - { - } - void SpirvWriter::Visit(const ShaderNodes::Branch& /*node*/) - { - } - void SpirvWriter::Visit(const ShaderNodes::BinaryOp& /*node*/) + void SpirvWriter::Visit(const ShaderNodes::AccessMember& node) { + Visit(node.structExpr); } - void SpirvWriter::Visit(const ShaderNodes::Cast& /*node*/) - { - } - void SpirvWriter::Visit(const ShaderNodes::Constant& /*node*/) - { - } - void SpirvWriter::Visit(const ShaderNodes::DeclareVariable& /*node*/) - { - } - void SpirvWriter::Visit(const ShaderNodes::ExpressionStatement& /*node*/) - { - } - void SpirvWriter::Visit(const ShaderNodes::Identifier& /*node*/) + void SpirvWriter::Visit(const ShaderNodes::AssignOp& node) { + Visit(node.left); + Visit(node.right); } - void SpirvWriter::Visit(const ShaderNodes::IntrinsicCall& /*node*/) + void SpirvWriter::Visit(const ShaderNodes::Branch& node) { + throw std::runtime_error("not yet implemented"); } - void SpirvWriter::Visit(const ShaderNodes::Sample2D& /*node*/) - { - } - void SpirvWriter::Visit(const ShaderNodes::StatementBlock& /*node*/) - { - } - void SpirvWriter::Visit(const ShaderNodes::SwizzleOp& /*node*/) + void SpirvWriter::Visit(const ShaderNodes::BinaryOp& node) { + Visit(node.left); + Visit(node.right); + + UInt32 resultId = AllocateResultId(); + UInt32 leftOperand = PopResultId(); + UInt32 rightOperand = PopResultId(); + + SpvOp op = [&] { + switch (node.op) + { + case ShaderNodes::BinaryType::Add: return SpvOpFAdd; + case ShaderNodes::BinaryType::Substract: return SpvOpFSub; + case ShaderNodes::BinaryType::Multiply: return SpvOpFMul; + case ShaderNodes::BinaryType::Divide: return SpvOpFDiv; + case ShaderNodes::BinaryType::Equality: return SpvOpFOrdEqual; + } + + assert(false); + throw std::runtime_error("unexpected binary operation"); + }(); + + m_currentState->instructions.Append(Opcode{ op }, GetTypeId(ShaderNodes::BasicType::Float3), resultId, leftOperand, rightOperand); } - void SpirvWriter::MergeBlocks(std::vector& output, const std::vector& from) + void SpirvWriter::Visit(const ShaderNodes::Cast& node) + { + for (auto& expr : node.expressions) + { + if (!expr) + break; + + Visit(expr); + } + } + + void SpirvWriter::Visit(const ShaderNodes::Constant& node) + { + std::visit([&] (const auto& value) + { + PushResultId(GetConstantId(value)); + }, node.value); + } + + void SpirvWriter::Visit(const ShaderNodes::DeclareVariable& node) + { + if (node.expression) + Visit(node.expression); + } + + void SpirvWriter::Visit(const ShaderNodes::ExpressionStatement& node) + { + Visit(node.expression); + } + + void SpirvWriter::Visit(const ShaderNodes::Identifier& node) + { + PushResultId(42); + } + + void SpirvWriter::Visit(const ShaderNodes::IntrinsicCall& node) + { + for (auto& param : node.parameters) + Visit(param); + } + + void SpirvWriter::Visit(const ShaderNodes::Sample2D& node) + { + Visit(node.sampler); + Visit(node.coordinates); + } + + void SpirvWriter::Visit(const ShaderNodes::StatementBlock& node) + { + for (auto& statement : node.statements) + Visit(statement); + } + + void SpirvWriter::Visit(const ShaderNodes::SwizzleOp& node) + { + Visit(node.expression); + } + + void SpirvWriter::MergeBlocks(std::vector& output, const Section& from) { std::size_t prevSize = output.size(); - output.resize(prevSize + from.size()); - std::copy(from.begin(), from.end(), output.begin() + prevSize); + output.resize(prevSize + from.data.size()); + std::copy(from.data.begin(), from.data.end(), output.begin() + prevSize); + } + + std::size_t SpirvWriter::Section::Append(const Opcode& opcode, const WordCount& wordCount) + { + return Append(UInt32(opcode.op) | UInt32(wordCount.wc) << 16); + } + + std::size_t SpirvWriter::Section::Append(const Raw& raw) + { + std::size_t offset = GetOutputOffset(); + + const UInt8* ptr = static_cast(raw.ptr); + + std::size_t size4 = CountWord(raw); + 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 < raw.size) + codepoint |= UInt32(ptr[pos]) << (j * 8); + } + +#ifdef NAZARA_BIG_ENDIAN + SwapBytes(codepoint); +#endif + + Append(codepoint); + } + + return offset; + } + + unsigned int SpirvWriter::Section::CountWord(const Raw& raw) + { + return (raw.size + sizeof(UInt32) - 1) / sizeof(UInt32); } } From 74fb01af28bec892838f47ac14cd26cb15900cc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Tue, 4 Aug 2020 15:31:47 +0200 Subject: [PATCH 080/105] Rename a few classes --- include/Nazara/Renderer.hpp | 9 +- include/Nazara/Renderer/GlslWriter.hpp | 6 +- ...itor.hpp => ShaderAstRecursiveVisitor.hpp} | 12 +-- ...itor.inl => ShaderAstRecursiveVisitor.inl} | 2 +- ...Serializer.hpp => ShaderAstSerializer.hpp} | 24 ++--- ...Serializer.inl => ShaderAstSerializer.inl} | 20 ++-- ...erValidator.hpp => ShaderAstValidator.hpp} | 16 +-- ...erValidator.inl => ShaderAstValidator.inl} | 4 +- ...ShaderVisitor.hpp => ShaderAstVisitor.hpp} | 10 +- include/Nazara/Renderer/ShaderNodes.hpp | 32 +++--- include/Nazara/Renderer/SpirvWriter.hpp | 6 +- include/Nazara/Utility.hpp | 1 + .../OpenGLRenderer/OpenGLShaderStage.cpp | 2 +- src/Nazara/Renderer/GlslWriter.cpp | 4 +- .../Renderer/ShaderAstRecursiveVisitor.cpp | 93 ++++++++++++++++ ...Serializer.cpp => ShaderAstSerializer.cpp} | 102 +++++++++--------- ...erValidator.cpp => ShaderAstValidator.cpp} | 74 ++++++------- ...ShaderVisitor.cpp => ShaderAstVisitor.cpp} | 10 +- src/Nazara/Renderer/ShaderNodes.cpp | 32 +++--- .../Renderer/ShaderRecursiveVisitor.cpp | 93 ---------------- src/Nazara/Renderer/SpirvWriter.cpp | 14 +-- src/ShaderNode/Widgets/MainWindow.cpp | 2 +- 22 files changed, 286 insertions(+), 282 deletions(-) rename include/Nazara/Renderer/{ShaderRecursiveVisitor.hpp => ShaderAstRecursiveVisitor.hpp} (79%) rename include/Nazara/Renderer/{ShaderRecursiveVisitor.inl => ShaderAstRecursiveVisitor.inl} (82%) rename include/Nazara/Renderer/{ShaderSerializer.hpp => ShaderAstSerializer.hpp} (85%) rename include/Nazara/Renderer/{ShaderSerializer.inl => ShaderAstSerializer.inl} (74%) rename include/Nazara/Renderer/{ShaderValidator.hpp => ShaderAstValidator.hpp} (83%) rename include/Nazara/Renderer/{ShaderValidator.inl => ShaderAstValidator.inl} (72%) rename include/Nazara/Renderer/{ShaderVisitor.hpp => ShaderAstVisitor.hpp} (87%) create mode 100644 src/Nazara/Renderer/ShaderAstRecursiveVisitor.cpp rename src/Nazara/Renderer/{ShaderSerializer.cpp => ShaderAstSerializer.cpp} (81%) rename src/Nazara/Renderer/{ShaderValidator.cpp => ShaderAstValidator.cpp} (79%) rename src/Nazara/Renderer/{ShaderVisitor.cpp => ShaderAstVisitor.cpp} (55%) delete mode 100644 src/Nazara/Renderer/ShaderRecursiveVisitor.cpp diff --git a/include/Nazara/Renderer.hpp b/include/Nazara/Renderer.hpp index 32e4f43de..8271bd3c8 100644 --- a/include/Nazara/Renderer.hpp +++ b/include/Nazara/Renderer.hpp @@ -53,17 +53,20 @@ #include #include #include +#include +#include +#include +#include #include #include #include +#include #include -#include #include -#include #include #include -#include #include +#include #include #include #include diff --git a/include/Nazara/Renderer/GlslWriter.hpp b/include/Nazara/Renderer/GlslWriter.hpp index f9694a8f1..8178c73d4 100644 --- a/include/Nazara/Renderer/GlslWriter.hpp +++ b/include/Nazara/Renderer/GlslWriter.hpp @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include #include @@ -20,7 +20,7 @@ namespace Nz { - class NAZARA_RENDERER_API GlslWriter : public ShaderWriter, public ShaderVarVisitor, public ShaderVisitor + class NAZARA_RENDERER_API GlslWriter : public ShaderWriter, public ShaderVarVisitor, public ShaderAstVisitor { public: struct Environment; @@ -60,7 +60,7 @@ namespace Nz void LeaveScope(); using ShaderVarVisitor::Visit; - using ShaderVisitor::Visit; + using ShaderAstVisitor::Visit; void Visit(const ShaderNodes::ExpressionPtr& expr, bool encloseIfRequired = false); void Visit(const ShaderNodes::AccessMember& node) override; void Visit(const ShaderNodes::AssignOp& node) override; diff --git a/include/Nazara/Renderer/ShaderRecursiveVisitor.hpp b/include/Nazara/Renderer/ShaderAstRecursiveVisitor.hpp similarity index 79% rename from include/Nazara/Renderer/ShaderRecursiveVisitor.hpp rename to include/Nazara/Renderer/ShaderAstRecursiveVisitor.hpp index 0e1087a58..622c1aef0 100644 --- a/include/Nazara/Renderer/ShaderRecursiveVisitor.hpp +++ b/include/Nazara/Renderer/ShaderAstRecursiveVisitor.hpp @@ -9,17 +9,17 @@ #include #include -#include +#include namespace Nz { - class NAZARA_RENDERER_API ShaderRecursiveVisitor : public ShaderVisitor + class NAZARA_RENDERER_API ShaderAstRecursiveVisitor : public ShaderAstVisitor { public: - ShaderRecursiveVisitor() = default; - ~ShaderRecursiveVisitor() = default; + ShaderAstRecursiveVisitor() = default; + ~ShaderAstRecursiveVisitor() = default; - using ShaderVisitor::Visit; + using ShaderAstVisitor::Visit; void Visit(const ShaderNodes::AccessMember& node) override; void Visit(const ShaderNodes::AssignOp& node) override; @@ -37,6 +37,6 @@ namespace Nz }; } -#include +#include #endif diff --git a/include/Nazara/Renderer/ShaderRecursiveVisitor.inl b/include/Nazara/Renderer/ShaderAstRecursiveVisitor.inl similarity index 82% rename from include/Nazara/Renderer/ShaderRecursiveVisitor.inl rename to include/Nazara/Renderer/ShaderAstRecursiveVisitor.inl index b107f06e7..3b2c6be62 100644 --- a/include/Nazara/Renderer/ShaderRecursiveVisitor.inl +++ b/include/Nazara/Renderer/ShaderAstRecursiveVisitor.inl @@ -2,7 +2,7 @@ // This file is part of the "Nazara Engine - Renderer module" // For conditions of distribution and use, see copyright notice in Config.hpp -#include +#include #include namespace Nz diff --git a/include/Nazara/Renderer/ShaderSerializer.hpp b/include/Nazara/Renderer/ShaderAstSerializer.hpp similarity index 85% rename from include/Nazara/Renderer/ShaderSerializer.hpp rename to include/Nazara/Renderer/ShaderAstSerializer.hpp index c6596b58d..68380054c 100644 --- a/include/Nazara/Renderer/ShaderSerializer.hpp +++ b/include/Nazara/Renderer/ShaderAstSerializer.hpp @@ -17,13 +17,13 @@ namespace Nz { - class NAZARA_RENDERER_API ShaderSerializerBase + class NAZARA_RENDERER_API ShaderAstSerializerBase { public: - ShaderSerializerBase() = default; - ShaderSerializerBase(const ShaderSerializerBase&) = delete; - ShaderSerializerBase(ShaderSerializerBase&&) = delete; - ~ShaderSerializerBase() = default; + ShaderAstSerializerBase() = default; + ShaderAstSerializerBase(const ShaderAstSerializerBase&) = delete; + ShaderAstSerializerBase(ShaderAstSerializerBase&&) = delete; + ~ShaderAstSerializerBase() = default; void Serialize(ShaderNodes::AccessMember& node); void Serialize(ShaderNodes::AssignOp& node); @@ -69,11 +69,11 @@ namespace Nz template void Variable(std::shared_ptr& var); }; - class NAZARA_RENDERER_API ShaderSerializer final : public ShaderSerializerBase + class NAZARA_RENDERER_API ShaderAstSerializer final : public ShaderAstSerializerBase { public: - inline ShaderSerializer(ByteStream& stream); - ~ShaderSerializer() = default; + inline ShaderAstSerializer(ByteStream& stream); + ~ShaderAstSerializer() = default; void Serialize(const ShaderAst& shader); @@ -96,11 +96,11 @@ namespace Nz ByteStream& m_stream; }; - class NAZARA_RENDERER_API ShaderUnserializer final : public ShaderSerializerBase + class NAZARA_RENDERER_API ShaderAstUnserializer final : public ShaderAstSerializerBase { public: - ShaderUnserializer(ByteStream& stream); - ~ShaderUnserializer() = default; + ShaderAstUnserializer(ByteStream& stream); + ~ShaderAstUnserializer() = default; ShaderAst Unserialize(); @@ -126,6 +126,6 @@ namespace Nz NAZARA_RENDERER_API ShaderAst UnserializeShader(ByteStream& stream); } -#include +#include #endif diff --git a/include/Nazara/Renderer/ShaderSerializer.inl b/include/Nazara/Renderer/ShaderAstSerializer.inl similarity index 74% rename from include/Nazara/Renderer/ShaderSerializer.inl rename to include/Nazara/Renderer/ShaderAstSerializer.inl index 51187d520..dd272e1fa 100644 --- a/include/Nazara/Renderer/ShaderSerializer.inl +++ b/include/Nazara/Renderer/ShaderAstSerializer.inl @@ -2,13 +2,13 @@ // This file is part of the "Nazara Engine - Renderer module" // For conditions of distribution and use, see copyright notice in Config.hpp -#include +#include #include namespace Nz { template - void ShaderSerializerBase::Container(T& container) + void ShaderAstSerializerBase::Container(T& container) { bool isWriting = IsWriting(); @@ -23,7 +23,7 @@ namespace Nz template - void ShaderSerializerBase::Enum(T& enumVal) + void ShaderAstSerializerBase::Enum(T& enumVal) { bool isWriting = IsWriting(); @@ -37,7 +37,7 @@ namespace Nz } template - void ShaderSerializerBase::OptEnum(std::optional& optVal) + void ShaderAstSerializerBase::OptEnum(std::optional& optVal) { bool isWriting = IsWriting(); @@ -55,7 +55,7 @@ namespace Nz } template - void ShaderSerializerBase::OptVal(std::optional& optVal) + void ShaderAstSerializerBase::OptVal(std::optional& optVal) { bool isWriting = IsWriting(); @@ -73,7 +73,7 @@ namespace Nz } template - void ShaderSerializerBase::Node(std::shared_ptr& node) + void ShaderAstSerializerBase::Node(std::shared_ptr& node) { bool isWriting = IsWriting(); @@ -87,7 +87,7 @@ namespace Nz } template - void ShaderSerializerBase::Variable(std::shared_ptr& var) + void ShaderAstSerializerBase::Variable(std::shared_ptr& var) { bool isWriting = IsWriting(); @@ -100,7 +100,7 @@ namespace Nz var = std::static_pointer_cast(value); } - inline void ShaderSerializerBase::Value(std::size_t& val) + inline void ShaderAstSerializerBase::Value(std::size_t& val) { bool isWriting = IsWriting(); @@ -113,12 +113,12 @@ namespace Nz val = static_cast(value); } - inline ShaderSerializer::ShaderSerializer(ByteStream& stream) : + inline ShaderAstSerializer::ShaderAstSerializer(ByteStream& stream) : m_stream(stream) { } - inline ShaderUnserializer::ShaderUnserializer(ByteStream& stream) : + inline ShaderAstUnserializer::ShaderAstUnserializer(ByteStream& stream) : m_stream(stream) { } diff --git a/include/Nazara/Renderer/ShaderValidator.hpp b/include/Nazara/Renderer/ShaderAstValidator.hpp similarity index 83% rename from include/Nazara/Renderer/ShaderValidator.hpp rename to include/Nazara/Renderer/ShaderAstValidator.hpp index edf54370f..aa586f99b 100644 --- a/include/Nazara/Renderer/ShaderValidator.hpp +++ b/include/Nazara/Renderer/ShaderAstValidator.hpp @@ -12,18 +12,18 @@ #include #include #include -#include +#include #include namespace Nz { - class NAZARA_RENDERER_API ShaderValidator : public ShaderRecursiveVisitor, public ShaderVarVisitor + class NAZARA_RENDERER_API ShaderAstValidator : public ShaderAstRecursiveVisitor, public ShaderVarVisitor { public: - inline ShaderValidator(const ShaderAst& shader); - ShaderValidator(const ShaderValidator&) = delete; - ShaderValidator(ShaderValidator&&) = delete; - ~ShaderValidator() = default; + inline ShaderAstValidator(const ShaderAst& shader); + ShaderAstValidator(const ShaderAstValidator&) = delete; + ShaderAstValidator(ShaderAstValidator&&) = delete; + ~ShaderAstValidator() = default; bool Validate(std::string* error = nullptr); @@ -33,7 +33,7 @@ namespace Nz void TypeMustMatch(const ShaderNodes::ExpressionPtr& left, const ShaderNodes::ExpressionPtr& right); void TypeMustMatch(const ShaderExpressionType& left, const ShaderExpressionType& right); - using ShaderRecursiveVisitor::Visit; + using ShaderAstRecursiveVisitor::Visit; void Visit(const ShaderNodes::AccessMember& node) override; void Visit(const ShaderNodes::AssignOp& node) override; void Visit(const ShaderNodes::BinaryOp& node) override; @@ -65,6 +65,6 @@ namespace Nz NAZARA_RENDERER_API bool ValidateShader(const ShaderAst& shader, std::string* error = nullptr); } -#include +#include #endif diff --git a/include/Nazara/Renderer/ShaderValidator.inl b/include/Nazara/Renderer/ShaderAstValidator.inl similarity index 72% rename from include/Nazara/Renderer/ShaderValidator.inl rename to include/Nazara/Renderer/ShaderAstValidator.inl index e609a144a..ee2628ce5 100644 --- a/include/Nazara/Renderer/ShaderValidator.inl +++ b/include/Nazara/Renderer/ShaderAstValidator.inl @@ -2,12 +2,12 @@ // This file is part of the "Nazara Engine - Renderer module" // For conditions of distribution and use, see copyright notice in Config.hpp -#include +#include #include namespace Nz { - ShaderValidator::ShaderValidator(const ShaderAst& shader) : + ShaderAstValidator::ShaderAstValidator(const ShaderAst& shader) : m_shader(shader) { } diff --git a/include/Nazara/Renderer/ShaderVisitor.hpp b/include/Nazara/Renderer/ShaderAstVisitor.hpp similarity index 87% rename from include/Nazara/Renderer/ShaderVisitor.hpp rename to include/Nazara/Renderer/ShaderAstVisitor.hpp index 1cd98fac3..d955f17e9 100644 --- a/include/Nazara/Renderer/ShaderVisitor.hpp +++ b/include/Nazara/Renderer/ShaderAstVisitor.hpp @@ -15,13 +15,13 @@ namespace Nz { - class NAZARA_RENDERER_API ShaderVisitor + class NAZARA_RENDERER_API ShaderAstVisitor { public: - ShaderVisitor() = default; - ShaderVisitor(const ShaderVisitor&) = delete; - ShaderVisitor(ShaderVisitor&&) = delete; - virtual ~ShaderVisitor(); + ShaderAstVisitor() = default; + ShaderAstVisitor(const ShaderAstVisitor&) = delete; + ShaderAstVisitor(ShaderAstVisitor&&) = delete; + virtual ~ShaderAstVisitor(); void EnableCondition(const std::string& name, bool cond); diff --git a/include/Nazara/Renderer/ShaderNodes.hpp b/include/Nazara/Renderer/ShaderNodes.hpp index 0b6daec79..5bfd47f6b 100644 --- a/include/Nazara/Renderer/ShaderNodes.hpp +++ b/include/Nazara/Renderer/ShaderNodes.hpp @@ -21,7 +21,7 @@ namespace Nz { - class ShaderVisitor; + class ShaderAstVisitor; namespace ShaderNodes { @@ -37,7 +37,7 @@ namespace Nz inline NodeType GetType() const; inline bool IsStatement() const; - virtual void Visit(ShaderVisitor& visitor) = 0; + virtual void Visit(ShaderAstVisitor& visitor) = 0; static inline unsigned int GetComponentCount(BasicType type); static inline BasicType GetComponentType(BasicType type); @@ -77,7 +77,7 @@ namespace Nz { inline ExpressionStatement(); - void Visit(ShaderVisitor& visitor) override; + void Visit(ShaderAstVisitor& visitor) override; ExpressionPtr expression; @@ -90,7 +90,7 @@ namespace Nz { inline ConditionalStatement(); - void Visit(ShaderVisitor& visitor) override; + void Visit(ShaderAstVisitor& visitor) override; std::string conditionName; StatementPtr statement; @@ -102,7 +102,7 @@ namespace Nz { inline StatementBlock(); - void Visit(ShaderVisitor& visitor) override; + void Visit(ShaderAstVisitor& visitor) override; std::vector statements; @@ -113,7 +113,7 @@ namespace Nz { inline DeclareVariable(); - void Visit(ShaderVisitor& visitor) override; + void Visit(ShaderAstVisitor& visitor) override; LocalVariablePtr variable; ExpressionPtr expression; @@ -127,7 +127,7 @@ namespace Nz ExpressionCategory GetExpressionCategory() const override; ShaderExpressionType GetExpressionType() const override; - void Visit(ShaderVisitor& visitor) override; + void Visit(ShaderAstVisitor& visitor) override; VariablePtr var; @@ -140,7 +140,7 @@ namespace Nz ExpressionCategory GetExpressionCategory() const override; ShaderExpressionType GetExpressionType() const override; - void Visit(ShaderVisitor& visitor) override; + void Visit(ShaderAstVisitor& visitor) override; std::size_t memberIndex; ExpressionPtr structExpr; @@ -156,7 +156,7 @@ namespace Nz inline AssignOp(); ShaderExpressionType GetExpressionType() const override; - void Visit(ShaderVisitor& visitor) override; + void Visit(ShaderAstVisitor& visitor) override; AssignType op; ExpressionPtr left; @@ -170,7 +170,7 @@ namespace Nz inline BinaryOp(); ShaderExpressionType GetExpressionType() const override; - void Visit(ShaderVisitor& visitor) override; + void Visit(ShaderAstVisitor& visitor) override; BinaryType op; ExpressionPtr left; @@ -185,7 +185,7 @@ namespace Nz inline Branch(); - void Visit(ShaderVisitor& visitor) override; + void Visit(ShaderAstVisitor& visitor) override; std::vector condStatements; StatementPtr elseStatement; @@ -204,7 +204,7 @@ namespace Nz inline Cast(); ShaderExpressionType GetExpressionType() const override; - void Visit(ShaderVisitor& visitor) override; + void Visit(ShaderAstVisitor& visitor) override; BasicType exprType; std::array expressions; @@ -218,7 +218,7 @@ namespace Nz inline Constant(); ShaderExpressionType GetExpressionType() const override; - void Visit(ShaderVisitor& visitor) override; + void Visit(ShaderAstVisitor& visitor) override; using Variant = std::variant< bool, @@ -239,7 +239,7 @@ namespace Nz ExpressionCategory GetExpressionCategory() const override; ShaderExpressionType GetExpressionType() const override; - void Visit(ShaderVisitor& visitor) override; + void Visit(ShaderAstVisitor& visitor) override; std::array components; std::size_t componentCount; @@ -255,7 +255,7 @@ namespace Nz inline Sample2D(); ShaderExpressionType GetExpressionType() const override; - void Visit(ShaderVisitor& visitor) override; + void Visit(ShaderAstVisitor& visitor) override; ExpressionPtr sampler; ExpressionPtr coordinates; @@ -270,7 +270,7 @@ namespace Nz inline IntrinsicCall(); ShaderExpressionType GetExpressionType() const override; - void Visit(ShaderVisitor& visitor) override; + void Visit(ShaderAstVisitor& visitor) override; IntrinsicType intrinsic; std::vector parameters; diff --git a/include/Nazara/Renderer/SpirvWriter.hpp b/include/Nazara/Renderer/SpirvWriter.hpp index 5786ea55b..2301d6caf 100644 --- a/include/Nazara/Renderer/SpirvWriter.hpp +++ b/include/Nazara/Renderer/SpirvWriter.hpp @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include #include @@ -20,7 +20,7 @@ namespace Nz { - class NAZARA_RENDERER_API SpirvWriter : public ShaderVisitor + class NAZARA_RENDERER_API SpirvWriter : public ShaderAstVisitor { public: struct Environment; @@ -84,7 +84,7 @@ namespace Nz UInt32 RegisterType(ShaderExpressionType type); - using ShaderVisitor::Visit; + using ShaderAstVisitor::Visit; void Visit(const ShaderNodes::AccessMember& node) override; void Visit(const ShaderNodes::AssignOp& node) override; void Visit(const ShaderNodes::Branch& node) override; diff --git a/include/Nazara/Utility.hpp b/include/Nazara/Utility.hpp index 735b83c32..29acfe8b9 100644 --- a/include/Nazara/Utility.hpp +++ b/include/Nazara/Utility.hpp @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include diff --git a/src/Nazara/OpenGLRenderer/OpenGLShaderStage.cpp b/src/Nazara/OpenGLRenderer/OpenGLShaderStage.cpp index a2a3fbf7a..07f6de975 100644 --- a/src/Nazara/OpenGLRenderer/OpenGLShaderStage.cpp +++ b/src/Nazara/OpenGLRenderer/OpenGLShaderStage.cpp @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/Nazara/Renderer/GlslWriter.cpp b/src/Nazara/Renderer/GlslWriter.cpp index fcb1847a7..1383da334 100644 --- a/src/Nazara/Renderer/GlslWriter.cpp +++ b/src/Nazara/Renderer/GlslWriter.cpp @@ -5,7 +5,7 @@ #include #include #include -#include +#include #include #include @@ -305,7 +305,7 @@ namespace Nz if (enclose) Append("("); - ShaderVisitor::Visit(expr); + ShaderAstVisitor::Visit(expr); if (enclose) Append(")"); diff --git a/src/Nazara/Renderer/ShaderAstRecursiveVisitor.cpp b/src/Nazara/Renderer/ShaderAstRecursiveVisitor.cpp new file mode 100644 index 000000000..81344bcf0 --- /dev/null +++ b/src/Nazara/Renderer/ShaderAstRecursiveVisitor.cpp @@ -0,0 +1,93 @@ +// Copyright (C) 2015 Jérôme Leclercq +// This file is part of the "Nazara Engine - Renderer module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include + +namespace Nz +{ + void ShaderAstRecursiveVisitor::Visit(const ShaderNodes::AccessMember& node) + { + Visit(node.structExpr); + } + + void ShaderAstRecursiveVisitor::Visit(const ShaderNodes::AssignOp& node) + { + Visit(node.left); + Visit(node.right); + } + + void ShaderAstRecursiveVisitor::Visit(const ShaderNodes::BinaryOp& node) + { + Visit(node.left); + Visit(node.right); + } + + void ShaderAstRecursiveVisitor::Visit(const ShaderNodes::Branch& node) + { + for (auto& cond : node.condStatements) + { + Visit(cond.condition); + Visit(cond.statement); + } + + if (node.elseStatement) + Visit(node.elseStatement); + } + + void ShaderAstRecursiveVisitor::Visit(const ShaderNodes::Cast& node) + { + for (auto& expr : node.expressions) + { + if (!expr) + break; + + Visit(expr); + } + } + + void ShaderAstRecursiveVisitor::Visit(const ShaderNodes::Constant& /*node*/) + { + /* Nothing to do */ + } + + void ShaderAstRecursiveVisitor::Visit(const ShaderNodes::DeclareVariable& node) + { + if (node.expression) + Visit(node.expression); + } + + void ShaderAstRecursiveVisitor::Visit(const ShaderNodes::ExpressionStatement& node) + { + Visit(node.expression); + } + + void ShaderAstRecursiveVisitor::Visit(const ShaderNodes::Identifier& /*node*/) + { + /* Nothing to do */ + } + + void ShaderAstRecursiveVisitor::Visit(const ShaderNodes::IntrinsicCall& node) + { + for (auto& param : node.parameters) + Visit(param); + } + + void ShaderAstRecursiveVisitor::Visit(const ShaderNodes::Sample2D& node) + { + Visit(node.sampler); + Visit(node.coordinates); + } + + void ShaderAstRecursiveVisitor::Visit(const ShaderNodes::StatementBlock& node) + { + for (auto& statement : node.statements) + Visit(statement); + } + + void ShaderAstRecursiveVisitor::Visit(const ShaderNodes::SwizzleOp& node) + { + Visit(node.expression); + } +} diff --git a/src/Nazara/Renderer/ShaderSerializer.cpp b/src/Nazara/Renderer/ShaderAstSerializer.cpp similarity index 81% rename from src/Nazara/Renderer/ShaderSerializer.cpp rename to src/Nazara/Renderer/ShaderAstSerializer.cpp index 2433bf070..b4de31cc7 100644 --- a/src/Nazara/Renderer/ShaderSerializer.cpp +++ b/src/Nazara/Renderer/ShaderAstSerializer.cpp @@ -2,9 +2,9 @@ // This file is part of the "Nazara Engine - Renderer module" // For conditions of distribution and use, see copyright notice in Config.hpp -#include +#include #include -#include +#include #include namespace Nz @@ -14,10 +14,10 @@ namespace Nz constexpr UInt32 s_magicNumber = 0x4E534852; constexpr UInt32 s_currentVersion = 1; - class ShaderSerializerVisitor : public ShaderVisitor, public ShaderVarVisitor + class ShaderSerializerVisitor : public ShaderAstVisitor, public ShaderVarVisitor { public: - ShaderSerializerVisitor(ShaderSerializerBase& serializer) : + ShaderSerializerVisitor(ShaderAstSerializerBase& serializer) : m_serializer(serializer) { } @@ -126,32 +126,32 @@ namespace Nz m_serializer.Serialize(const_cast(node)); } - ShaderSerializerBase& m_serializer; + ShaderAstSerializerBase& m_serializer; }; } - void ShaderSerializerBase::Serialize(ShaderNodes::AccessMember& node) + void ShaderAstSerializerBase::Serialize(ShaderNodes::AccessMember& node) { Value(node.memberIndex); Node(node.structExpr); Type(node.exprType); } - void ShaderSerializerBase::Serialize(ShaderNodes::AssignOp& node) + void ShaderAstSerializerBase::Serialize(ShaderNodes::AssignOp& node) { Enum(node.op); Node(node.left); Node(node.right); } - void ShaderSerializerBase::Serialize(ShaderNodes::BinaryOp& node) + void ShaderAstSerializerBase::Serialize(ShaderNodes::BinaryOp& node) { Enum(node.op); Node(node.left); Node(node.right); } - void ShaderSerializerBase::Serialize(ShaderNodes::Branch& node) + void ShaderAstSerializerBase::Serialize(ShaderNodes::Branch& node) { Container(node.condStatements); for (auto& condStatement : node.condStatements) @@ -163,20 +163,20 @@ namespace Nz Node(node.elseStatement); } - void ShaderSerializerBase::Serialize(ShaderNodes::BuiltinVariable& node) + void ShaderAstSerializerBase::Serialize(ShaderNodes::BuiltinVariable& node) { Enum(node.entry); Type(node.type); } - void ShaderSerializerBase::Serialize(ShaderNodes::Cast& node) + void ShaderAstSerializerBase::Serialize(ShaderNodes::Cast& node) { Enum(node.exprType); for (auto& expr : node.expressions) Node(expr); } - void ShaderSerializerBase::Serialize(ShaderNodes::Constant& node) + void ShaderAstSerializerBase::Serialize(ShaderNodes::Constant& node) { UInt32 typeIndex; if (IsWriting()) @@ -205,23 +205,23 @@ namespace Nz } } - void ShaderSerializerBase::Serialize(ShaderNodes::DeclareVariable& node) + void ShaderAstSerializerBase::Serialize(ShaderNodes::DeclareVariable& node) { Variable(node.variable); Node(node.expression); } - void ShaderSerializerBase::Serialize(ShaderNodes::ExpressionStatement& node) + void ShaderAstSerializerBase::Serialize(ShaderNodes::ExpressionStatement& node) { Node(node.expression); } - void ShaderSerializerBase::Serialize(ShaderNodes::Identifier& node) + void ShaderAstSerializerBase::Serialize(ShaderNodes::Identifier& node) { Variable(node.var); } - void ShaderSerializerBase::Serialize(ShaderNodes::IntrinsicCall& node) + void ShaderAstSerializerBase::Serialize(ShaderNodes::IntrinsicCall& node) { Enum(node.intrinsic); Container(node.parameters); @@ -229,26 +229,26 @@ namespace Nz Node(param); } - void ShaderSerializerBase::Serialize(ShaderNodes::NamedVariable& node) + void ShaderAstSerializerBase::Serialize(ShaderNodes::NamedVariable& node) { Value(node.name); Type(node.type); } - void ShaderSerializerBase::Serialize(ShaderNodes::Sample2D& node) + void ShaderAstSerializerBase::Serialize(ShaderNodes::Sample2D& node) { Node(node.sampler); Node(node.coordinates); } - void ShaderSerializerBase::Serialize(ShaderNodes::StatementBlock& node) + void ShaderAstSerializerBase::Serialize(ShaderNodes::StatementBlock& node) { Container(node.statements); for (auto& statement : node.statements) Node(statement); } - void ShaderSerializerBase::Serialize(ShaderNodes::SwizzleOp& node) + void ShaderAstSerializerBase::Serialize(ShaderNodes::SwizzleOp& node) { Value(node.componentCount); Node(node.expression); @@ -258,7 +258,7 @@ namespace Nz } - void ShaderSerializer::Serialize(const ShaderAst& shader) + void ShaderAstSerializer::Serialize(const ShaderAst& shader) { m_stream << s_magicNumber << s_currentVersion; @@ -346,12 +346,12 @@ namespace Nz m_stream.FlushBits(); } - bool ShaderSerializer::IsWriting() const + bool ShaderAstSerializer::IsWriting() const { return true; } - void ShaderSerializer::Node(ShaderNodes::NodePtr& node) + void ShaderAstSerializer::Node(ShaderNodes::NodePtr& node) { ShaderNodes::NodeType nodeType = (node) ? node->GetType() : ShaderNodes::NodeType::None; m_stream << static_cast(nodeType); @@ -363,7 +363,7 @@ namespace Nz } } - void ShaderSerializer::Type(ShaderExpressionType& type) + void ShaderAstSerializer::Type(ShaderExpressionType& type) { std::visit([&](auto&& arg) { @@ -383,57 +383,57 @@ namespace Nz }, type); } - void ShaderSerializer::Node(const ShaderNodes::NodePtr& node) + void ShaderAstSerializer::Node(const ShaderNodes::NodePtr& node) { Node(const_cast(node)); //< Yes const_cast is ugly but it won't be used for writing } - void ShaderSerializer::Value(bool& val) + void ShaderAstSerializer::Value(bool& val) { m_stream << val; } - void ShaderSerializer::Value(float& val) + void ShaderAstSerializer::Value(float& val) { m_stream << val; } - void ShaderSerializer::Value(std::string& val) + void ShaderAstSerializer::Value(std::string& val) { m_stream << val; } - void ShaderSerializer::Value(Vector2f& val) + void ShaderAstSerializer::Value(Vector2f& val) { m_stream << val; } - void ShaderSerializer::Value(Vector3f& val) + void ShaderAstSerializer::Value(Vector3f& val) { m_stream << val; } - void ShaderSerializer::Value(Vector4f& val) + void ShaderAstSerializer::Value(Vector4f& val) { m_stream << val; } - void ShaderSerializer::Value(UInt8& val) + void ShaderAstSerializer::Value(UInt8& val) { m_stream << val; } - void ShaderSerializer::Value(UInt16& val) + void ShaderAstSerializer::Value(UInt16& val) { m_stream << val; } - void ShaderSerializer::Value(UInt32& val) + void ShaderAstSerializer::Value(UInt32& val) { m_stream << val; } - void ShaderSerializer::Variable(ShaderNodes::VariablePtr& var) + void ShaderAstSerializer::Variable(ShaderNodes::VariablePtr& var) { ShaderNodes::VariableType nodeType = (var) ? var->GetType() : ShaderNodes::VariableType::None; m_stream << static_cast(nodeType); @@ -445,7 +445,7 @@ namespace Nz } } - ShaderAst ShaderUnserializer::Unserialize() + ShaderAst ShaderAstUnserializer::Unserialize() { UInt32 magicNumber; UInt32 version; @@ -558,12 +558,12 @@ namespace Nz return shader; } - bool ShaderUnserializer::IsWriting() const + bool ShaderAstUnserializer::IsWriting() const { return false; } - void ShaderUnserializer::Node(ShaderNodes::NodePtr& node) + void ShaderAstUnserializer::Node(ShaderNodes::NodePtr& node) { Int32 nodeTypeInt; m_stream >> nodeTypeInt; @@ -599,7 +599,7 @@ namespace Nz } } - void ShaderUnserializer::Type(ShaderExpressionType& type) + void ShaderAstUnserializer::Type(ShaderExpressionType& type) { UInt8 typeIndex; Value(typeIndex); @@ -629,52 +629,52 @@ namespace Nz } } - void ShaderUnserializer::Value(bool& val) + void ShaderAstUnserializer::Value(bool& val) { m_stream >> val; } - void ShaderUnserializer::Value(float& val) + void ShaderAstUnserializer::Value(float& val) { m_stream >> val; } - void ShaderUnserializer::Value(std::string& val) + void ShaderAstUnserializer::Value(std::string& val) { m_stream >> val; } - void ShaderUnserializer::Value(Vector2f& val) + void ShaderAstUnserializer::Value(Vector2f& val) { m_stream >> val; } - void ShaderUnserializer::Value(Vector3f& val) + void ShaderAstUnserializer::Value(Vector3f& val) { m_stream >> val; } - void ShaderUnserializer::Value(Vector4f& val) + void ShaderAstUnserializer::Value(Vector4f& val) { m_stream >> val; } - void ShaderUnserializer::Value(UInt8& val) + void ShaderAstUnserializer::Value(UInt8& val) { m_stream >> val; } - void ShaderUnserializer::Value(UInt16& val) + void ShaderAstUnserializer::Value(UInt16& val) { m_stream >> val; } - void ShaderUnserializer::Value(UInt32& val) + void ShaderAstUnserializer::Value(UInt32& val) { m_stream >> val; } - void ShaderUnserializer::Variable(ShaderNodes::VariablePtr& var) + void ShaderAstUnserializer::Variable(ShaderNodes::VariablePtr& var) { Int32 nodeTypeInt; m_stream >> nodeTypeInt; @@ -707,7 +707,7 @@ namespace Nz ByteArray byteArray; ByteStream stream(&byteArray, OpenModeFlags(OpenMode_WriteOnly)); - ShaderSerializer serializer(stream); + ShaderAstSerializer serializer(stream); serializer.Serialize(shader); return byteArray; @@ -715,7 +715,7 @@ namespace Nz ShaderAst UnserializeShader(ByteStream& stream) { - ShaderUnserializer unserializer(stream); + ShaderAstUnserializer unserializer(stream); return unserializer.Unserialize(); } } diff --git a/src/Nazara/Renderer/ShaderValidator.cpp b/src/Nazara/Renderer/ShaderAstValidator.cpp similarity index 79% rename from src/Nazara/Renderer/ShaderValidator.cpp rename to src/Nazara/Renderer/ShaderAstValidator.cpp index 351a46839..57404ba6b 100644 --- a/src/Nazara/Renderer/ShaderValidator.cpp +++ b/src/Nazara/Renderer/ShaderAstValidator.cpp @@ -2,7 +2,7 @@ // This file is part of the "Nazara Engine - Renderer module" // For conditions of distribution and use, see copyright notice in Config.hpp -#include +#include #include #include #include @@ -16,7 +16,7 @@ namespace Nz std::string errMsg; }; - struct ShaderValidator::Context + struct ShaderAstValidator::Context { struct Local { @@ -29,7 +29,7 @@ namespace Nz std::vector blockLocalIndex; }; - bool ShaderValidator::Validate(std::string* error) + bool ShaderAstValidator::Validate(std::string* error) { try { @@ -57,14 +57,14 @@ namespace Nz } } - const ShaderNodes::ExpressionPtr& ShaderValidator::MandatoryExpr(const ShaderNodes::ExpressionPtr& node) + const ShaderNodes::ExpressionPtr& ShaderAstValidator::MandatoryExpr(const ShaderNodes::ExpressionPtr& node) { MandatoryNode(node); return node; } - const ShaderNodes::NodePtr& ShaderValidator::MandatoryNode(const ShaderNodes::NodePtr& node) + const ShaderNodes::NodePtr& ShaderAstValidator::MandatoryNode(const ShaderNodes::NodePtr& node) { if (!node) throw AstError{ "Invalid node" }; @@ -72,18 +72,18 @@ namespace Nz return node; } - void ShaderValidator::TypeMustMatch(const ShaderNodes::ExpressionPtr& left, const ShaderNodes::ExpressionPtr& right) + void ShaderAstValidator::TypeMustMatch(const ShaderNodes::ExpressionPtr& left, const ShaderNodes::ExpressionPtr& right) { return TypeMustMatch(left->GetExpressionType(), right->GetExpressionType()); } - void ShaderValidator::TypeMustMatch(const ShaderExpressionType& left, const ShaderExpressionType& right) + void ShaderAstValidator::TypeMustMatch(const ShaderExpressionType& left, const ShaderExpressionType& right) { if (left != right) throw AstError{ "Left expression type must match right expression type" }; } - void ShaderValidator::Visit(const ShaderNodes::AccessMember& node) + void ShaderAstValidator::Visit(const ShaderNodes::AccessMember& node) { const ShaderExpressionType& exprType = MandatoryExpr(node.structExpr)->GetExpressionType(); if (!std::holds_alternative(exprType)) @@ -105,7 +105,7 @@ namespace Nz throw AstError{ "member type does not match node type" }; } - void ShaderValidator::Visit(const ShaderNodes::AssignOp& node) + void ShaderAstValidator::Visit(const ShaderNodes::AssignOp& node) { MandatoryNode(node.left); MandatoryNode(node.right); @@ -114,10 +114,10 @@ namespace Nz if (node.left->GetExpressionCategory() != ShaderNodes::ExpressionCategory::LValue) throw AstError { "Assignation is only possible with a l-value" }; - ShaderRecursiveVisitor::Visit(node); + ShaderAstRecursiveVisitor::Visit(node); } - void ShaderValidator::Visit(const ShaderNodes::BinaryOp& node) + void ShaderAstValidator::Visit(const ShaderNodes::BinaryOp& node) { MandatoryNode(node.left); MandatoryNode(node.right); @@ -186,10 +186,10 @@ namespace Nz } } - ShaderRecursiveVisitor::Visit(node); + ShaderAstRecursiveVisitor::Visit(node); } - void ShaderValidator::Visit(const ShaderNodes::Branch& node) + void ShaderAstValidator::Visit(const ShaderNodes::Branch& node) { for (const auto& condStatement : node.condStatements) { @@ -197,10 +197,10 @@ namespace Nz MandatoryNode(condStatement.statement); } - ShaderRecursiveVisitor::Visit(node); + ShaderAstRecursiveVisitor::Visit(node); } - void ShaderValidator::Visit(const ShaderNodes::Cast& node) + void ShaderAstValidator::Visit(const ShaderNodes::Cast& node) { unsigned int componentCount = 0; unsigned int requiredComponents = node.GetComponentCount(node.exprType); @@ -219,14 +219,14 @@ namespace Nz if (componentCount != requiredComponents) throw AstError{ "Component count doesn't match required component count" }; - ShaderRecursiveVisitor::Visit(node); + ShaderAstRecursiveVisitor::Visit(node); } - void ShaderValidator::Visit(const ShaderNodes::Constant& /*node*/) + void ShaderAstValidator::Visit(const ShaderNodes::Constant& /*node*/) { } - void ShaderValidator::Visit(const ShaderNodes::DeclareVariable& node) + void ShaderAstValidator::Visit(const ShaderNodes::DeclareVariable& node) { assert(m_context); @@ -234,17 +234,17 @@ namespace Nz local.name = node.variable->name; local.type = node.variable->type; - ShaderRecursiveVisitor::Visit(node); + ShaderAstRecursiveVisitor::Visit(node); } - void ShaderValidator::Visit(const ShaderNodes::ExpressionStatement& node) + void ShaderAstValidator::Visit(const ShaderNodes::ExpressionStatement& node) { MandatoryNode(node.expression); - ShaderRecursiveVisitor::Visit(node); + ShaderAstRecursiveVisitor::Visit(node); } - void ShaderValidator::Visit(const ShaderNodes::Identifier& node) + void ShaderAstValidator::Visit(const ShaderNodes::Identifier& node) { assert(m_context); @@ -254,7 +254,7 @@ namespace Nz Visit(node.var); } - void ShaderValidator::Visit(const ShaderNodes::IntrinsicCall& node) + void ShaderAstValidator::Visit(const ShaderNodes::IntrinsicCall& node) { switch (node.intrinsic) { @@ -292,10 +292,10 @@ namespace Nz break; } - ShaderRecursiveVisitor::Visit(node); + ShaderAstRecursiveVisitor::Visit(node); } - void ShaderValidator::Visit(const ShaderNodes::Sample2D& node) + void ShaderAstValidator::Visit(const ShaderNodes::Sample2D& node) { if (MandatoryExpr(node.sampler)->GetExpressionType() != ShaderExpressionType{ ShaderNodes::BasicType::Sampler2D }) throw AstError{ "Sampler must be a Sampler2D" }; @@ -303,10 +303,10 @@ namespace Nz if (MandatoryExpr(node.coordinates)->GetExpressionType() != ShaderExpressionType{ ShaderNodes::BasicType::Float2 }) throw AstError{ "Coordinates must be a Float2" }; - ShaderRecursiveVisitor::Visit(node); + ShaderAstRecursiveVisitor::Visit(node); } - void ShaderValidator::Visit(const ShaderNodes::StatementBlock& node) + void ShaderAstValidator::Visit(const ShaderNodes::StatementBlock& node) { assert(m_context); @@ -319,10 +319,10 @@ namespace Nz m_context->declaredLocals.resize(m_context->blockLocalIndex.back()); m_context->blockLocalIndex.pop_back(); - ShaderRecursiveVisitor::Visit(node); + ShaderAstRecursiveVisitor::Visit(node); } - void ShaderValidator::Visit(const ShaderNodes::SwizzleOp& node) + void ShaderAstValidator::Visit(const ShaderNodes::SwizzleOp& node) { if (node.componentCount > 4) throw AstError{ "Cannot swizzle more than four elements" }; @@ -343,15 +343,15 @@ namespace Nz throw AstError{ "Cannot swizzle this type" }; } - ShaderRecursiveVisitor::Visit(node); + ShaderAstRecursiveVisitor::Visit(node); } - void ShaderValidator::Visit(const ShaderNodes::BuiltinVariable& /*var*/) + void ShaderAstValidator::Visit(const ShaderNodes::BuiltinVariable& /*var*/) { /* Nothing to do */ } - void ShaderValidator::Visit(const ShaderNodes::InputVariable& var) + void ShaderAstValidator::Visit(const ShaderNodes::InputVariable& var) { for (std::size_t i = 0; i < m_shader.GetInputCount(); ++i) { @@ -366,7 +366,7 @@ namespace Nz throw AstError{ "Input not found" }; } - void ShaderValidator::Visit(const ShaderNodes::LocalVariable& var) + void ShaderAstValidator::Visit(const ShaderNodes::LocalVariable& var) { const auto& vars = m_context->declaredLocals; @@ -377,7 +377,7 @@ namespace Nz TypeMustMatch(it->type, var.type); } - void ShaderValidator::Visit(const ShaderNodes::OutputVariable& var) + void ShaderAstValidator::Visit(const ShaderNodes::OutputVariable& var) { for (std::size_t i = 0; i < m_shader.GetOutputCount(); ++i) { @@ -392,7 +392,7 @@ namespace Nz throw AstError{ "Output not found" }; } - void ShaderValidator::Visit(const ShaderNodes::ParameterVariable& var) + void ShaderAstValidator::Visit(const ShaderNodes::ParameterVariable& var) { assert(m_context->currentFunction); @@ -405,7 +405,7 @@ namespace Nz TypeMustMatch(it->type, var.type); } - void ShaderValidator::Visit(const ShaderNodes::UniformVariable& var) + void ShaderAstValidator::Visit(const ShaderNodes::UniformVariable& var) { for (std::size_t i = 0; i < m_shader.GetUniformCount(); ++i) { @@ -422,7 +422,7 @@ namespace Nz bool ValidateShader(const ShaderAst& shader, std::string* error) { - ShaderValidator validator(shader); + ShaderAstValidator validator(shader); return validator.Validate(error); } } diff --git a/src/Nazara/Renderer/ShaderVisitor.cpp b/src/Nazara/Renderer/ShaderAstVisitor.cpp similarity index 55% rename from src/Nazara/Renderer/ShaderVisitor.cpp rename to src/Nazara/Renderer/ShaderAstVisitor.cpp index dd7e01542..49760f028 100644 --- a/src/Nazara/Renderer/ShaderVisitor.cpp +++ b/src/Nazara/Renderer/ShaderAstVisitor.cpp @@ -2,14 +2,14 @@ // This file is part of the "Nazara Engine - Renderer module" // For conditions of distribution and use, see copyright notice in Config.hpp -#include +#include #include namespace Nz { - ShaderVisitor::~ShaderVisitor() = default; + ShaderAstVisitor::~ShaderAstVisitor() = default; - void ShaderVisitor::EnableCondition(const std::string& name, bool cond) + void ShaderAstVisitor::EnableCondition(const std::string& name, bool cond) { if (cond) m_conditions.insert(name); @@ -17,12 +17,12 @@ namespace Nz m_conditions.erase(name); } - bool ShaderVisitor::IsConditionEnabled(const std::string& name) const + bool ShaderAstVisitor::IsConditionEnabled(const std::string& name) const { return m_conditions.count(name) != 0; } - void ShaderVisitor::Visit(const ShaderNodes::NodePtr& node) + void ShaderAstVisitor::Visit(const ShaderNodes::NodePtr& node) { node->Visit(*this); } diff --git a/src/Nazara/Renderer/ShaderNodes.cpp b/src/Nazara/Renderer/ShaderNodes.cpp index da2157826..7ea148cb6 100644 --- a/src/Nazara/Renderer/ShaderNodes.cpp +++ b/src/Nazara/Renderer/ShaderNodes.cpp @@ -4,8 +4,8 @@ #include #include -#include -#include +#include +#include #include #include @@ -18,26 +18,26 @@ namespace Nz::ShaderNodes return ExpressionCategory::RValue; } - void ExpressionStatement::Visit(ShaderVisitor& visitor) + void ExpressionStatement::Visit(ShaderAstVisitor& visitor) { visitor.Visit(*this); } - void ConditionalStatement::Visit(ShaderVisitor& visitor) + void ConditionalStatement::Visit(ShaderAstVisitor& visitor) { if (visitor.IsConditionEnabled(conditionName)) statement->Visit(visitor); } - void StatementBlock::Visit(ShaderVisitor& visitor) + void StatementBlock::Visit(ShaderAstVisitor& visitor) { visitor.Visit(*this); } - void DeclareVariable::Visit(ShaderVisitor& visitor) + void DeclareVariable::Visit(ShaderAstVisitor& visitor) { visitor.Visit(*this); } @@ -54,7 +54,7 @@ namespace Nz::ShaderNodes return var->type; } - void Identifier::Visit(ShaderVisitor& visitor) + void Identifier::Visit(ShaderAstVisitor& visitor) { visitor.Visit(*this); } @@ -69,7 +69,7 @@ namespace Nz::ShaderNodes return exprType; } - void AccessMember::Visit(ShaderVisitor& visitor) + void AccessMember::Visit(ShaderAstVisitor& visitor) { visitor.Visit(*this); } @@ -79,7 +79,7 @@ namespace Nz::ShaderNodes return left->GetExpressionType(); } - void AssignOp::Visit(ShaderVisitor& visitor) + void AssignOp::Visit(ShaderAstVisitor& visitor) { visitor.Visit(*this); } @@ -137,13 +137,13 @@ namespace Nz::ShaderNodes return *exprType; } - void BinaryOp::Visit(ShaderVisitor& visitor) + void BinaryOp::Visit(ShaderAstVisitor& visitor) { visitor.Visit(*this); } - void Branch::Visit(ShaderVisitor& visitor) + void Branch::Visit(ShaderAstVisitor& visitor) { visitor.Visit(*this); } @@ -170,7 +170,7 @@ namespace Nz::ShaderNodes }, value); } - void Constant::Visit(ShaderVisitor& visitor) + void Constant::Visit(ShaderAstVisitor& visitor) { visitor.Visit(*this); } @@ -180,7 +180,7 @@ namespace Nz::ShaderNodes return exprType; } - void Cast::Visit(ShaderVisitor& visitor) + void Cast::Visit(ShaderAstVisitor& visitor) { visitor.Visit(*this); } @@ -199,7 +199,7 @@ namespace Nz::ShaderNodes return static_cast(UnderlyingCast(GetComponentType(std::get(exprType))) + componentCount - 1); } - void SwizzleOp::Visit(ShaderVisitor& visitor) + void SwizzleOp::Visit(ShaderAstVisitor& visitor) { visitor.Visit(*this); } @@ -210,7 +210,7 @@ namespace Nz::ShaderNodes return BasicType::Float4; } - void Sample2D::Visit(ShaderVisitor& visitor) + void Sample2D::Visit(ShaderAstVisitor& visitor) { visitor.Visit(*this); } @@ -231,7 +231,7 @@ namespace Nz::ShaderNodes return BasicType::Void; } - void IntrinsicCall::Visit(ShaderVisitor& visitor) + void IntrinsicCall::Visit(ShaderAstVisitor& visitor) { visitor.Visit(*this); } diff --git a/src/Nazara/Renderer/ShaderRecursiveVisitor.cpp b/src/Nazara/Renderer/ShaderRecursiveVisitor.cpp deleted file mode 100644 index 2116da21c..000000000 --- a/src/Nazara/Renderer/ShaderRecursiveVisitor.cpp +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright (C) 2015 Jérôme Leclercq -// This file is part of the "Nazara Engine - Renderer module" -// For conditions of distribution and use, see copyright notice in Config.hpp - -#include -#include - -namespace Nz -{ - void ShaderRecursiveVisitor::Visit(const ShaderNodes::AccessMember& node) - { - Visit(node.structExpr); - } - - void ShaderRecursiveVisitor::Visit(const ShaderNodes::AssignOp& node) - { - Visit(node.left); - Visit(node.right); - } - - void ShaderRecursiveVisitor::Visit(const ShaderNodes::BinaryOp& node) - { - Visit(node.left); - Visit(node.right); - } - - void ShaderRecursiveVisitor::Visit(const ShaderNodes::Branch& node) - { - for (auto& cond : node.condStatements) - { - Visit(cond.condition); - Visit(cond.statement); - } - - if (node.elseStatement) - Visit(node.elseStatement); - } - - void ShaderRecursiveVisitor::Visit(const ShaderNodes::Cast& node) - { - for (auto& expr : node.expressions) - { - if (!expr) - break; - - Visit(expr); - } - } - - void ShaderRecursiveVisitor::Visit(const ShaderNodes::Constant& /*node*/) - { - /* Nothing to do */ - } - - void ShaderRecursiveVisitor::Visit(const ShaderNodes::DeclareVariable& node) - { - if (node.expression) - Visit(node.expression); - } - - void ShaderRecursiveVisitor::Visit(const ShaderNodes::ExpressionStatement& node) - { - Visit(node.expression); - } - - void ShaderRecursiveVisitor::Visit(const ShaderNodes::Identifier& /*node*/) - { - /* Nothing to do */ - } - - void ShaderRecursiveVisitor::Visit(const ShaderNodes::IntrinsicCall& node) - { - for (auto& param : node.parameters) - Visit(param); - } - - void ShaderRecursiveVisitor::Visit(const ShaderNodes::Sample2D& node) - { - Visit(node.sampler); - Visit(node.coordinates); - } - - void ShaderRecursiveVisitor::Visit(const ShaderNodes::StatementBlock& node) - { - for (auto& statement : node.statements) - Visit(statement); - } - - void ShaderRecursiveVisitor::Visit(const ShaderNodes::SwizzleOp& node) - { - Visit(node.expression); - } -} diff --git a/src/Nazara/Renderer/SpirvWriter.cpp b/src/Nazara/Renderer/SpirvWriter.cpp index 1ccf23f97..a94cd6ec9 100644 --- a/src/Nazara/Renderer/SpirvWriter.cpp +++ b/src/Nazara/Renderer/SpirvWriter.cpp @@ -5,7 +5,7 @@ #include #include #include -#include +#include #include #include #include @@ -22,7 +22,7 @@ namespace Nz { using ConstantVariant = ShaderNodes::Constant::Variant; - class PreVisitor : public ShaderRecursiveVisitor, public ShaderVarVisitor + class PreVisitor : public ShaderAstRecursiveVisitor, public ShaderVarVisitor { public: using BuiltinContainer = std::unordered_set>; @@ -31,7 +31,7 @@ namespace Nz using LocalContainer = std::unordered_set>; using ParameterContainer = std::unordered_set< std::shared_ptr>; - using ShaderRecursiveVisitor::Visit; + using ShaderAstRecursiveVisitor::Visit; using ShaderVarVisitor::Visit; void Visit(const ShaderNodes::Constant& node) override @@ -68,26 +68,26 @@ namespace Nz }, node.value); - ShaderRecursiveVisitor::Visit(node); + ShaderAstRecursiveVisitor::Visit(node); } void Visit(const ShaderNodes::DeclareVariable& node) override { Visit(node.variable); - ShaderRecursiveVisitor::Visit(node); + ShaderAstRecursiveVisitor::Visit(node); } void Visit(const ShaderNodes::Identifier& node) override { Visit(node.var); - ShaderRecursiveVisitor::Visit(node); + ShaderAstRecursiveVisitor::Visit(node); } void Visit(const ShaderNodes::IntrinsicCall& node) override { - ShaderRecursiveVisitor::Visit(node); + ShaderAstRecursiveVisitor::Visit(node); switch (node.intrinsic) { diff --git a/src/ShaderNode/Widgets/MainWindow.cpp b/src/ShaderNode/Widgets/MainWindow.cpp index f25f95a18..31665bb8d 100644 --- a/src/ShaderNode/Widgets/MainWindow.cpp +++ b/src/ShaderNode/Widgets/MainWindow.cpp @@ -1,7 +1,7 @@ #include #include #include -#include +#include #include #include #include From d6d452d43dbed397957f74407491eef0d70738ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Wed, 5 Aug 2020 15:30:23 +0200 Subject: [PATCH 081/105] Add ShaderAstCloner --- include/Nazara/Renderer.hpp | 1 + include/Nazara/Renderer/ShaderAstCloner.hpp | 73 ++++++ include/Nazara/Renderer/ShaderAstCloner.inl | 12 + include/Nazara/Renderer/ShaderNodes.hpp | 9 +- include/Nazara/Renderer/ShaderNodes.inl | 33 ++- src/Nazara/Renderer/GlslWriter.cpp | 8 +- src/Nazara/Renderer/ShaderAstCloner.cpp | 246 ++++++++++++++++++++ src/Nazara/Renderer/ShaderAstValidator.cpp | 9 +- 8 files changed, 383 insertions(+), 8 deletions(-) create mode 100644 include/Nazara/Renderer/ShaderAstCloner.hpp create mode 100644 include/Nazara/Renderer/ShaderAstCloner.inl create mode 100644 src/Nazara/Renderer/ShaderAstCloner.cpp diff --git a/include/Nazara/Renderer.hpp b/include/Nazara/Renderer.hpp index 8271bd3c8..ff9193d3f 100644 --- a/include/Nazara/Renderer.hpp +++ b/include/Nazara/Renderer.hpp @@ -53,6 +53,7 @@ #include #include #include +#include #include #include #include diff --git a/include/Nazara/Renderer/ShaderAstCloner.hpp b/include/Nazara/Renderer/ShaderAstCloner.hpp new file mode 100644 index 000000000..b48de17b8 --- /dev/null +++ b/include/Nazara/Renderer/ShaderAstCloner.hpp @@ -0,0 +1,73 @@ +// Copyright (C) 2015 Jérôme Leclercq +// This file is part of the "Nazara Engine - Renderer module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_SHADERASTCLONER_HPP +#define NAZARA_SHADERASTCLONER_HPP + +#include +#include +#include +#include +#include + +namespace Nz +{ + class NAZARA_RENDERER_API ShaderAstCloner : public ShaderAstVisitor, public ShaderVarVisitor + { + public: + ShaderAstCloner() = default; + ShaderAstCloner(const ShaderAstCloner&) = default; + ShaderAstCloner(ShaderAstCloner&&) = default; + ~ShaderAstCloner() = default; + + ShaderNodes::StatementPtr Clone(const ShaderNodes::StatementPtr& statement); + + ShaderAstCloner& operator=(const ShaderAstCloner&) = default; + ShaderAstCloner& operator=(ShaderAstCloner&&) = default; + + private: + void Visit(const ShaderNodes::ExpressionPtr& expr); + void Visit(const ShaderNodes::StatementPtr& statement); + + void Visit(const ShaderNodes::AccessMember& node) override; + void Visit(const ShaderNodes::AssignOp& node) override; + void Visit(const ShaderNodes::BinaryOp& node) override; + void Visit(const ShaderNodes::Branch& node) override; + void Visit(const ShaderNodes::Cast& node) override; + void Visit(const ShaderNodes::Constant& node) override; + void Visit(const ShaderNodes::DeclareVariable& node) override; + void Visit(const ShaderNodes::ExpressionStatement& node) override; + void Visit(const ShaderNodes::Identifier& node) override; + void Visit(const ShaderNodes::IntrinsicCall& node) override; + void Visit(const ShaderNodes::Sample2D& node) override; + void Visit(const ShaderNodes::StatementBlock& node) override; + void Visit(const ShaderNodes::SwizzleOp& node) override; + + using ShaderVarVisitor::Visit; + void Visit(const ShaderNodes::BuiltinVariable& var) override; + void Visit(const ShaderNodes::InputVariable& var) override; + void Visit(const ShaderNodes::LocalVariable& var) override; + void Visit(const ShaderNodes::OutputVariable& var) override; + void Visit(const ShaderNodes::ParameterVariable& var) override; + void Visit(const ShaderNodes::UniformVariable& var) override; + + void PushExpression(ShaderNodes::ExpressionPtr expression); + void PushStatement(ShaderNodes::StatementPtr statement); + void PushVariable(ShaderNodes::VariablePtr variable); + + ShaderNodes::ExpressionPtr PopExpression(); + ShaderNodes::StatementPtr PopStatement(); + ShaderNodes::VariablePtr PopVariable(); + + std::vector m_expressionStack; + std::vector m_statementStack; + std::vector m_variableStack; + }; +} + +#include + +#endif diff --git a/include/Nazara/Renderer/ShaderAstCloner.inl b/include/Nazara/Renderer/ShaderAstCloner.inl new file mode 100644 index 000000000..1acdd41ab --- /dev/null +++ b/include/Nazara/Renderer/ShaderAstCloner.inl @@ -0,0 +1,12 @@ +// Copyright (C) 2020 Jérôme Leclercq +// This file is part of the "Nazara Engine - Renderer module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include + +namespace Nz +{ +} + +#include diff --git a/include/Nazara/Renderer/ShaderNodes.hpp b/include/Nazara/Renderer/ShaderNodes.hpp index 5bfd47f6b..c0b8688e2 100644 --- a/include/Nazara/Renderer/ShaderNodes.hpp +++ b/include/Nazara/Renderer/ShaderNodes.hpp @@ -106,6 +106,7 @@ namespace Nz std::vector statements; + static inline std::shared_ptr Build(std::vector statements); template static std::shared_ptr Build(Args&&... args); }; @@ -115,10 +116,10 @@ namespace Nz void Visit(ShaderAstVisitor& visitor) override; - LocalVariablePtr variable; ExpressionPtr expression; + VariablePtr variable; - static inline std::shared_ptr Build(LocalVariablePtr variable, ExpressionPtr expression = nullptr); + static inline std::shared_ptr Build(VariablePtr variable, ExpressionPtr expression = nullptr); }; struct NAZARA_RENDERER_API Identifier : public Expression @@ -196,7 +197,8 @@ namespace Nz StatementPtr statement; }; - inline std::shared_ptr Build(ExpressionPtr condition, StatementPtr trueStatement, StatementPtr falseStatement = nullptr); + static inline std::shared_ptr Build(ExpressionPtr condition, StatementPtr trueStatement, StatementPtr falseStatement = nullptr); + static inline std::shared_ptr Build(std::vector statements, StatementPtr elseStatement = nullptr); }; struct NAZARA_RENDERER_API Cast : public Expression @@ -246,6 +248,7 @@ namespace Nz ExpressionPtr expression; static inline std::shared_ptr Build(ExpressionPtr expressionPtr, std::initializer_list swizzleComponents); + static inline std::shared_ptr Build(ExpressionPtr expressionPtr, const SwizzleComponent* components, std::size_t componentCount); }; ////////////////////////////////////////////////////////////////////////// diff --git a/include/Nazara/Renderer/ShaderNodes.inl b/include/Nazara/Renderer/ShaderNodes.inl index 27d387bcd..0e9307ff4 100644 --- a/include/Nazara/Renderer/ShaderNodes.inl +++ b/include/Nazara/Renderer/ShaderNodes.inl @@ -107,6 +107,14 @@ namespace Nz::ShaderNodes { } + inline std::shared_ptr StatementBlock::Build(std::vector statements) + { + auto node = std::make_shared(); + node->statements = std::move(statements); + + return node; + } + template std::shared_ptr StatementBlock::Build(Args&&... args) { @@ -122,7 +130,7 @@ namespace Nz::ShaderNodes { } - inline std::shared_ptr DeclareVariable::Build(LocalVariablePtr variable, ExpressionPtr expression) + inline std::shared_ptr DeclareVariable::Build(VariablePtr variable, ExpressionPtr expression) { auto node = std::make_shared(); node->expression = std::move(expression); @@ -208,6 +216,15 @@ namespace Nz::ShaderNodes return node; } + inline std::shared_ptr Branch::Build(std::vector statements, StatementPtr elseStatement) + { + auto node = std::make_shared(); + node->condStatements = std::move(statements); + node->elseStatement = std::move(elseStatement); + + return node; + } + inline Cast::Cast() : Expression(NodeType::Cast) @@ -265,6 +282,20 @@ namespace Nz::ShaderNodes return node; } + inline std::shared_ptr SwizzleOp::Build(ExpressionPtr expressionPtr, const SwizzleComponent* components, std::size_t componentCount) + { + auto node = std::make_shared(); + + assert(componentCount < node->components.size()); + + node->componentCount = componentCount; + node->expression = std::move(expressionPtr); + + std::copy(components, components + componentCount, node->components.begin()); + + return node; + } + inline Sample2D::Sample2D() : Expression(NodeType::Sample2D) diff --git a/src/Nazara/Renderer/GlslWriter.cpp b/src/Nazara/Renderer/GlslWriter.cpp index 1383da334..8fa23755a 100644 --- a/src/Nazara/Renderer/GlslWriter.cpp +++ b/src/Nazara/Renderer/GlslWriter.cpp @@ -448,9 +448,13 @@ namespace Nz void GlslWriter::Visit(const ShaderNodes::DeclareVariable& node) { - Append(node.variable->type); + assert(node.variable->GetType() == ShaderNodes::VariableType::LocalVariable); + + const auto& localVar = static_cast(*node.variable); + + Append(localVar.type); Append(" "); - Append(node.variable->name); + Append(localVar.name); if (node.expression) { Append(" = "); diff --git a/src/Nazara/Renderer/ShaderAstCloner.cpp b/src/Nazara/Renderer/ShaderAstCloner.cpp new file mode 100644 index 000000000..f4ec37329 --- /dev/null +++ b/src/Nazara/Renderer/ShaderAstCloner.cpp @@ -0,0 +1,246 @@ +// Copyright (C) 2015 Jérôme Leclercq +// This file is part of the "Nazara Engine - Renderer module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include + +namespace Nz +{ + ShaderNodes::StatementPtr ShaderAstCloner::Clone(const ShaderNodes::StatementPtr& statement) + { + ShaderAstVisitor::Visit(statement); + + if (!m_expressionStack.empty() || !m_variableStack.empty() || m_statementStack.size() != 1) + throw std::runtime_error("An error occured during clone"); + + return PopStatement(); + } + + void ShaderAstCloner::Visit(const ShaderNodes::ExpressionPtr& expr) + { + if (expr) + ShaderAstVisitor::Visit(expr); + else + PushExpression(nullptr); + } + + void ShaderAstCloner::Visit(const ShaderNodes::StatementPtr& statement) + { + if (statement) + ShaderAstVisitor::Visit(statement); + else + PushStatement(nullptr); + } + + void ShaderAstCloner::Visit(const ShaderNodes::AccessMember& node) + { + Visit(node.structExpr); + + PushExpression(ShaderNodes::AccessMember::Build(PopExpression(), node.memberIndex, node.exprType)); + } + + void ShaderAstCloner::Visit(const ShaderNodes::AssignOp& node) + { + Visit(node.left); + Visit(node.right); + + auto right = PopExpression(); + auto left = PopExpression(); + + PushExpression(ShaderNodes::AssignOp::Build(node.op, std::move(left), std::move(right))); + } + + void ShaderAstCloner::Visit(const ShaderNodes::BinaryOp& node) + { + Visit(node.left); + Visit(node.right); + + auto right = PopExpression(); + auto left = PopExpression(); + + PushExpression(ShaderNodes::BinaryOp::Build(node.op, std::move(left), std::move(right))); + } + + void ShaderAstCloner::Visit(const ShaderNodes::Branch& node) + { + for (auto& cond : node.condStatements) + { + Visit(cond.condition); + Visit(cond.statement); + } + + Visit(node.elseStatement); + + auto elseStatement = PopStatement(); + + std::vector condStatements(node.condStatements.size()); + for (std::size_t i = 0; i < condStatements.size(); ++i) + { + auto& condStatement = condStatements[condStatements.size() - i - 1]; + condStatement.condition = PopExpression(); + condStatement.statement = PopStatement(); + } + + PushStatement(ShaderNodes::Branch::Build(std::move(condStatements), std::move(elseStatement))); + } + + void ShaderAstCloner::Visit(const ShaderNodes::Cast& node) + { + std::size_t expressionCount = 0; + std::array expressions; + for (const auto& expr : node.expressions) + { + Visit(expr); + expressionCount++; + } + + for (std::size_t i = 0; i < expressionCount; ++i) + expressions[expressionCount - i - 1] = PopExpression(); + + PushExpression(ShaderNodes::Cast::Build(node.exprType, expressions.data(), expressionCount)); + } + + void ShaderAstCloner::Visit(const ShaderNodes::Constant& node) + { + PushExpression(ShaderNodes::Constant::Build(node.value)); + } + + void ShaderAstCloner::Visit(const ShaderNodes::DeclareVariable& node) + { + Visit(node.expression); + Visit(node.variable); + + PushStatement(ShaderNodes::DeclareVariable::Build(PopVariable(), PopExpression())); + } + + void ShaderAstCloner::Visit(const ShaderNodes::ExpressionStatement& node) + { + Visit(node.expression); + + PushStatement(ShaderNodes::ExpressionStatement::Build(PopExpression())); + } + + void ShaderAstCloner::Visit(const ShaderNodes::Identifier& node) + { + Visit(node.var); + + PushExpression(ShaderNodes::Identifier::Build(PopVariable())); + } + + void ShaderAstCloner::Visit(const ShaderNodes::IntrinsicCall& node) + { + for (auto& parameter : node.parameters) + Visit(parameter); + + std::vector parameters(node.parameters.size()); + for (std::size_t i = 0; i < parameters.size(); ++i) + parameters[parameters.size() - i - 1] = PopExpression(); + + PushExpression(ShaderNodes::IntrinsicCall::Build(node.intrinsic, std::move(parameters))); + } + + void ShaderAstCloner::Visit(const ShaderNodes::Sample2D& node) + { + Visit(node.coordinates); + Visit(node.sampler); + + auto sampler = PopExpression(); + auto coordinates = PopExpression(); + + PushExpression(ShaderNodes::Sample2D::Build(std::move(sampler), std::move(coordinates))); + } + + void ShaderAstCloner::Visit(const ShaderNodes::StatementBlock& node) + { + for (auto& statement : node.statements) + Visit(statement); + + std::vector statements(node.statements.size()); + for (std::size_t i = 0; i < statements.size(); ++i) + statements[statements.size() - i - 1] = PopStatement(); + + PushStatement(ShaderNodes::StatementBlock::Build(std::move(statements))); + } + + void ShaderAstCloner::Visit(const ShaderNodes::SwizzleOp& node) + { + PushExpression(ShaderNodes::SwizzleOp::Build(PopExpression(), node.components.data(), node.componentCount)); + } + + void ShaderAstCloner::Visit(const ShaderNodes::BuiltinVariable& var) + { + PushVariable(ShaderNodes::BuiltinVariable::Build(var.entry, var.type)); + } + + void ShaderAstCloner::Visit(const ShaderNodes::InputVariable& var) + { + PushVariable(ShaderNodes::InputVariable::Build(var.name, var.type)); + } + + void ShaderAstCloner::Visit(const ShaderNodes::LocalVariable& var) + { + PushVariable(ShaderNodes::LocalVariable::Build(var.name, var.type)); + } + + void ShaderAstCloner::Visit(const ShaderNodes::OutputVariable& var) + { + PushVariable(ShaderNodes::OutputVariable::Build(var.name, var.type)); + } + + void ShaderAstCloner::Visit(const ShaderNodes::ParameterVariable& var) + { + PushVariable(ShaderNodes::ParameterVariable::Build(var.name, var.type)); + } + + void ShaderAstCloner::Visit(const ShaderNodes::UniformVariable& var) + { + PushVariable(ShaderNodes::UniformVariable::Build(var.name, var.type)); + } + + void ShaderAstCloner::PushExpression(ShaderNodes::ExpressionPtr expression) + { + m_expressionStack.emplace_back(std::move(expression)); + } + + void ShaderAstCloner::PushStatement(ShaderNodes::StatementPtr statement) + { + m_statementStack.emplace_back(std::move(statement)); + } + + void ShaderAstCloner::PushVariable(ShaderNodes::VariablePtr variable) + { + m_variableStack.emplace_back(std::move(variable)); + } + + ShaderNodes::ExpressionPtr ShaderAstCloner::PopExpression() + { + assert(!m_expressionStack.empty()); + + ShaderNodes::ExpressionPtr expr = std::move(m_expressionStack.back()); + m_expressionStack.pop_back(); + + return expr; + } + + ShaderNodes::StatementPtr ShaderAstCloner::PopStatement() + { + assert(!m_statementStack.empty()); + + ShaderNodes::StatementPtr expr = std::move(m_statementStack.back()); + m_statementStack.pop_back(); + + return expr; + } + + ShaderNodes::VariablePtr ShaderAstCloner::PopVariable() + { + assert(!m_variableStack.empty()); + + ShaderNodes::VariablePtr var = std::move(m_variableStack.back()); + m_variableStack.pop_back(); + + return var; + } +} diff --git a/src/Nazara/Renderer/ShaderAstValidator.cpp b/src/Nazara/Renderer/ShaderAstValidator.cpp index 57404ba6b..8e161d532 100644 --- a/src/Nazara/Renderer/ShaderAstValidator.cpp +++ b/src/Nazara/Renderer/ShaderAstValidator.cpp @@ -230,9 +230,14 @@ namespace Nz { assert(m_context); + if (node.variable->GetType() != ShaderNodes::VariableType::LocalVariable) + throw AstError{ "Only local variables can be declared in a statement" }; + + const auto& localVar = static_cast(*node.variable); + auto& local = m_context->declaredLocals.emplace_back(); - local.name = node.variable->name; - local.type = node.variable->type; + local.name = localVar.name; + local.type = localVar.type; ShaderAstRecursiveVisitor::Visit(node); } From 3829f0a002ffbb77ad5f24f1699f7598b19557cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Wed, 5 Aug 2020 16:28:41 +0200 Subject: [PATCH 082/105] ShaderAstCloner: Improve code readability --- include/Nazara/Renderer/ShaderAstCloner.hpp | 6 +- src/Nazara/Renderer/ShaderAstCloner.cpp | 124 ++++++++------------ 2 files changed, 52 insertions(+), 78 deletions(-) diff --git a/include/Nazara/Renderer/ShaderAstCloner.hpp b/include/Nazara/Renderer/ShaderAstCloner.hpp index b48de17b8..20d1ed52b 100644 --- a/include/Nazara/Renderer/ShaderAstCloner.hpp +++ b/include/Nazara/Renderer/ShaderAstCloner.hpp @@ -29,8 +29,9 @@ namespace Nz ShaderAstCloner& operator=(ShaderAstCloner&&) = default; private: - void Visit(const ShaderNodes::ExpressionPtr& expr); - void Visit(const ShaderNodes::StatementPtr& statement); + ShaderNodes::ExpressionPtr CloneExpression(const ShaderNodes::ExpressionPtr& expr); + ShaderNodes::StatementPtr CloneStatement(const ShaderNodes::StatementPtr& statement); + ShaderNodes::VariablePtr CloneVariable(const ShaderNodes::VariablePtr& statement); void Visit(const ShaderNodes::AccessMember& node) override; void Visit(const ShaderNodes::AssignOp& node) override; @@ -46,7 +47,6 @@ namespace Nz void Visit(const ShaderNodes::StatementBlock& node) override; void Visit(const ShaderNodes::SwizzleOp& node) override; - using ShaderVarVisitor::Visit; void Visit(const ShaderNodes::BuiltinVariable& var) override; void Visit(const ShaderNodes::InputVariable& var) override; void Visit(const ShaderNodes::LocalVariable& var) override; diff --git a/src/Nazara/Renderer/ShaderAstCloner.cpp b/src/Nazara/Renderer/ShaderAstCloner.cpp index f4ec37329..75ac0634c 100644 --- a/src/Nazara/Renderer/ShaderAstCloner.cpp +++ b/src/Nazara/Renderer/ShaderAstCloner.cpp @@ -13,92 +13,81 @@ namespace Nz ShaderAstVisitor::Visit(statement); if (!m_expressionStack.empty() || !m_variableStack.empty() || m_statementStack.size() != 1) - throw std::runtime_error("An error occured during clone"); + throw std::runtime_error("An error occurred during clone"); return PopStatement(); } - void ShaderAstCloner::Visit(const ShaderNodes::ExpressionPtr& expr) + ShaderNodes::ExpressionPtr ShaderAstCloner::CloneExpression(const ShaderNodes::ExpressionPtr& expr) { - if (expr) - ShaderAstVisitor::Visit(expr); - else - PushExpression(nullptr); + if (!expr) + return nullptr; + + ShaderAstVisitor::Visit(expr); + return PopExpression(); } - void ShaderAstCloner::Visit(const ShaderNodes::StatementPtr& statement) + ShaderNodes::StatementPtr ShaderAstCloner::CloneStatement(const ShaderNodes::StatementPtr& statement) { - if (statement) - ShaderAstVisitor::Visit(statement); - else - PushStatement(nullptr); + if (!statement) + return nullptr; + + ShaderAstVisitor::Visit(statement); + return PopStatement(); + } + + ShaderNodes::VariablePtr ShaderAstCloner::CloneVariable(const ShaderNodes::VariablePtr& variable) + { + if (!variable) + return nullptr; + + ShaderVarVisitor::Visit(variable); + return PopVariable(); } void ShaderAstCloner::Visit(const ShaderNodes::AccessMember& node) { - Visit(node.structExpr); - - PushExpression(ShaderNodes::AccessMember::Build(PopExpression(), node.memberIndex, node.exprType)); + PushExpression(ShaderNodes::AccessMember::Build(CloneExpression(node.structExpr), node.memberIndex, node.exprType)); } void ShaderAstCloner::Visit(const ShaderNodes::AssignOp& node) { - Visit(node.left); - Visit(node.right); - - auto right = PopExpression(); - auto left = PopExpression(); - - PushExpression(ShaderNodes::AssignOp::Build(node.op, std::move(left), std::move(right))); + PushExpression(ShaderNodes::AssignOp::Build(node.op, CloneExpression(node.left), CloneExpression(node.right))); } void ShaderAstCloner::Visit(const ShaderNodes::BinaryOp& node) { - Visit(node.left); - Visit(node.right); - - auto right = PopExpression(); - auto left = PopExpression(); - - PushExpression(ShaderNodes::BinaryOp::Build(node.op, std::move(left), std::move(right))); + PushExpression(ShaderNodes::BinaryOp::Build(node.op, CloneExpression(node.left), CloneExpression(node.right))); } void ShaderAstCloner::Visit(const ShaderNodes::Branch& node) { + std::vector condStatements; + condStatements.reserve(node.condStatements.size()); + for (auto& cond : node.condStatements) { - Visit(cond.condition); - Visit(cond.statement); + auto& condStatement = condStatements.emplace_back(); + condStatement.condition = CloneExpression(cond.condition); + condStatement.statement = CloneStatement(cond.statement); } - Visit(node.elseStatement); - - auto elseStatement = PopStatement(); - - std::vector condStatements(node.condStatements.size()); - for (std::size_t i = 0; i < condStatements.size(); ++i) - { - auto& condStatement = condStatements[condStatements.size() - i - 1]; - condStatement.condition = PopExpression(); - condStatement.statement = PopStatement(); - } - - PushStatement(ShaderNodes::Branch::Build(std::move(condStatements), std::move(elseStatement))); + PushStatement(ShaderNodes::Branch::Build(std::move(condStatements), CloneStatement(node.elseStatement))); } void ShaderAstCloner::Visit(const ShaderNodes::Cast& node) { std::size_t expressionCount = 0; std::array expressions; - for (const auto& expr : node.expressions) + for (auto& expr : node.expressions) { - Visit(expr); + if (!expr) + break; + + expressions[expressionCount] = CloneExpression(expr); expressionCount++; } - for (std::size_t i = 0; i < expressionCount; ++i) - expressions[expressionCount - i - 1] = PopExpression(); - PushExpression(ShaderNodes::Cast::Build(node.exprType, expressions.data(), expressionCount)); } @@ -109,57 +98,42 @@ namespace Nz void ShaderAstCloner::Visit(const ShaderNodes::DeclareVariable& node) { - Visit(node.expression); - Visit(node.variable); - - PushStatement(ShaderNodes::DeclareVariable::Build(PopVariable(), PopExpression())); + PushStatement(ShaderNodes::DeclareVariable::Build(CloneVariable(node.variable), CloneExpression(node.expression))); } void ShaderAstCloner::Visit(const ShaderNodes::ExpressionStatement& node) { - Visit(node.expression); - - PushStatement(ShaderNodes::ExpressionStatement::Build(PopExpression())); + PushStatement(ShaderNodes::ExpressionStatement::Build(CloneExpression(node.expression))); } void ShaderAstCloner::Visit(const ShaderNodes::Identifier& node) { - Visit(node.var); - - PushExpression(ShaderNodes::Identifier::Build(PopVariable())); + PushExpression(ShaderNodes::Identifier::Build(CloneVariable(node.var))); } void ShaderAstCloner::Visit(const ShaderNodes::IntrinsicCall& node) { - for (auto& parameter : node.parameters) - Visit(parameter); + std::vector parameters; + parameters.reserve(node.parameters.size()); - std::vector parameters(node.parameters.size()); - for (std::size_t i = 0; i < parameters.size(); ++i) - parameters[parameters.size() - i - 1] = PopExpression(); + for (auto& parameter : node.parameters) + parameters.push_back(CloneExpression(parameter)); PushExpression(ShaderNodes::IntrinsicCall::Build(node.intrinsic, std::move(parameters))); } void ShaderAstCloner::Visit(const ShaderNodes::Sample2D& node) { - Visit(node.coordinates); - Visit(node.sampler); - - auto sampler = PopExpression(); - auto coordinates = PopExpression(); - - PushExpression(ShaderNodes::Sample2D::Build(std::move(sampler), std::move(coordinates))); + PushExpression(ShaderNodes::Sample2D::Build(CloneExpression(node.sampler), CloneExpression(node.coordinates))); } void ShaderAstCloner::Visit(const ShaderNodes::StatementBlock& node) { - for (auto& statement : node.statements) - Visit(statement); + std::vector statements; + statements.reserve(node.statements.size()); - std::vector statements(node.statements.size()); - for (std::size_t i = 0; i < statements.size(); ++i) - statements[statements.size() - i - 1] = PopStatement(); + for (auto& statement : node.statements) + statements.push_back(CloneStatement(statement)); PushStatement(ShaderNodes::StatementBlock::Build(std::move(statements))); } From 0da2ee6c99adf1b47b2c342af4c6ed18dc05e1bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Sun, 9 Aug 2020 00:24:07 +0200 Subject: [PATCH 083/105] First rendering using Spir-V generated shaders \o/ --- examples/VulkanTest/main.cpp | 7 +- examples/bin/frag.shader | Bin 610 -> 610 bytes examples/bin/test.spirv | Bin 0 -> 824 bytes examples/bin/vert.shader | Bin 695 -> 695 bytes include/Nazara/Renderer/GlslWriter.hpp | 40 +- include/Nazara/Renderer/ShaderAstCloner.hpp | 38 +- .../Renderer/ShaderAstRecursiveVisitor.hpp | 26 +- .../Nazara/Renderer/ShaderAstSerializer.hpp | 12 + .../Nazara/Renderer/ShaderAstValidator.hpp | 38 +- include/Nazara/Renderer/ShaderAstVisitor.hpp | 26 +- include/Nazara/Renderer/ShaderEnums.hpp | 20 +- include/Nazara/Renderer/ShaderNodes.hpp | 8 +- include/Nazara/Renderer/ShaderNodes.inl | 8 + include/Nazara/Renderer/ShaderVarVisitor.hpp | 13 +- include/Nazara/Renderer/SpirvWriter.hpp | 42 +- src/Nazara/Renderer/GlslWriter.cpp | 87 +- src/Nazara/Renderer/Renderer.cpp | 2 +- src/Nazara/Renderer/ShaderAstCloner.cpp | 38 +- .../Renderer/ShaderAstRecursiveVisitor.cpp | 26 +- src/Nazara/Renderer/ShaderAstSerializer.cpp | 91 +- src/Nazara/Renderer/ShaderAstValidator.cpp | 63 +- src/Nazara/Renderer/ShaderNodes.cpp | 14 +- src/Nazara/Renderer/SpirvWriter.cpp | 829 +++++++++++++++--- src/Nazara/VulkanRenderer/Vulkan.cpp | 2 +- .../VulkanRenderer/VulkanShaderStage.cpp | 60 +- 25 files changed, 1117 insertions(+), 373 deletions(-) create mode 100644 examples/bin/test.spirv diff --git a/examples/VulkanTest/main.cpp b/examples/VulkanTest/main.cpp index 9a5313f9a..706cf047c 100644 --- a/examples/VulkanTest/main.cpp +++ b/examples/VulkanTest/main.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -7,8 +8,8 @@ #define SPIRV 0 int main() -{ - { +{ + /*{ Nz::File file("frag.shader"); if (!file.Open(Nz::OpenMode_ReadOnly)) return __LINE__; @@ -39,7 +40,7 @@ int main() return 0; } - + */ Nz::Initializer loader; if (!loader) { diff --git a/examples/bin/frag.shader b/examples/bin/frag.shader index 1fbcce530ddddc3a7d749a622786ce22b08df3f9..cd71692bdb4ea28ccc2c395eea9cff48ef20d9e3 100644 GIT binary patch delta 80 zcmaFF@`zlC Sro`NWoYW!^lWXz{#$5nOYYy-L delta 68 zcmaFF@`zCB;>BD7r@2sA+Spq8|L{*)*pT>s zce@Eo9=mVe?97{ma_M;4Y{^)I{M)Q)r94u%avnk5w3=14H-t%)qzEg*ny?`>l#8Zf z7U+YPq_=O`BpU0eNF~or(#NNQSMz&!arzQx4^j3SPfzo_K)uYS@yC5Mc^}7Fad)xr zjcQT+3pm7a!*?h51(X9wp} z@WSuR!rPx*b+uo~AN}?O-seZT`0cqEKFDFteSsO_yxW1mn?36ez4=d&L;Tyt`Yukr VFBc1S#wXgfy7R7~Fqg{<;U7&^Dfa*X literal 0 HcmV?d00001 diff --git a/examples/bin/vert.shader b/examples/bin/vert.shader index b1fa132bbaea340fd46bf5c9b7f93ea34411ff74..2d5c2daca53655ae10ead8e456b58e596ff8c89c 100644 GIT binary patch delta 74 zcmdnax}9}`jtnOQ0|RS$eo;;ekih`rv6N+|mV-GHJ=Sn?gIGYoJGqfje6k4RIY!RO Qj~O+9Bo7maG-YZ603DzXasU7T delta 74 zcmdnax}9}`jtnaU0|RS$eo;;ekih`rv6N+|mV-GHJ=SotgIGYoJGqfje6k4RIY!pW Qj~O+9Bo7maG-YZ602&YuRsaA1 diff --git a/include/Nazara/Renderer/GlslWriter.hpp b/include/Nazara/Renderer/GlslWriter.hpp index 8178c73d4..d7229f1d9 100644 --- a/include/Nazara/Renderer/GlslWriter.hpp +++ b/include/Nazara/Renderer/GlslWriter.hpp @@ -61,26 +61,26 @@ namespace Nz using ShaderVarVisitor::Visit; using ShaderAstVisitor::Visit; - void Visit(const ShaderNodes::ExpressionPtr& expr, bool encloseIfRequired = false); - void Visit(const ShaderNodes::AccessMember& node) override; - void Visit(const ShaderNodes::AssignOp& node) override; - void Visit(const ShaderNodes::Branch& node) override; - void Visit(const ShaderNodes::BinaryOp& node) override; - void Visit(const ShaderNodes::BuiltinVariable& var) override; - void Visit(const ShaderNodes::Cast& node) override; - void Visit(const ShaderNodes::Constant& node) override; - void Visit(const ShaderNodes::DeclareVariable& node) override; - void Visit(const ShaderNodes::ExpressionStatement& node) override; - void Visit(const ShaderNodes::Identifier& node) override; - void Visit(const ShaderNodes::InputVariable& var) override; - void Visit(const ShaderNodes::IntrinsicCall& node) override; - void Visit(const ShaderNodes::LocalVariable& var) override; - void Visit(const ShaderNodes::ParameterVariable& var) override; - void Visit(const ShaderNodes::OutputVariable& var) override; - void Visit(const ShaderNodes::Sample2D& node) override; - void Visit(const ShaderNodes::StatementBlock& node) override; - void Visit(const ShaderNodes::SwizzleOp& node) override; - void Visit(const ShaderNodes::UniformVariable& var) override; + void Visit(ShaderNodes::ExpressionPtr& expr, bool encloseIfRequired = false); + 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::BuiltinVariable& var) 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::InputVariable& var) override; + void Visit(ShaderNodes::IntrinsicCall& node) override; + void Visit(ShaderNodes::LocalVariable& var) override; + void Visit(ShaderNodes::ParameterVariable& var) override; + void Visit(ShaderNodes::OutputVariable& var) override; + void Visit(ShaderNodes::Sample2D& node) override; + void Visit(ShaderNodes::StatementBlock& node) override; + void Visit(ShaderNodes::SwizzleOp& node) override; + void Visit(ShaderNodes::UniformVariable& var) override; static bool HasExplicitBinding(const ShaderAst& shader); static bool HasExplicitLocation(const ShaderAst& shader); diff --git a/include/Nazara/Renderer/ShaderAstCloner.hpp b/include/Nazara/Renderer/ShaderAstCloner.hpp index 20d1ed52b..ff1f9c5a4 100644 --- a/include/Nazara/Renderer/ShaderAstCloner.hpp +++ b/include/Nazara/Renderer/ShaderAstCloner.hpp @@ -33,26 +33,26 @@ namespace Nz ShaderNodes::StatementPtr CloneStatement(const ShaderNodes::StatementPtr& statement); ShaderNodes::VariablePtr CloneVariable(const ShaderNodes::VariablePtr& statement); - void Visit(const ShaderNodes::AccessMember& node) override; - void Visit(const ShaderNodes::AssignOp& node) override; - void Visit(const ShaderNodes::BinaryOp& node) override; - void Visit(const ShaderNodes::Branch& node) override; - void Visit(const ShaderNodes::Cast& node) override; - void Visit(const ShaderNodes::Constant& node) override; - void Visit(const ShaderNodes::DeclareVariable& node) override; - void Visit(const ShaderNodes::ExpressionStatement& node) override; - void Visit(const ShaderNodes::Identifier& node) override; - void Visit(const ShaderNodes::IntrinsicCall& node) override; - void Visit(const ShaderNodes::Sample2D& node) override; - void Visit(const ShaderNodes::StatementBlock& node) override; - void Visit(const ShaderNodes::SwizzleOp& node) override; + 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; - void Visit(const ShaderNodes::BuiltinVariable& var) override; - void Visit(const ShaderNodes::InputVariable& var) override; - void Visit(const ShaderNodes::LocalVariable& var) override; - void Visit(const ShaderNodes::OutputVariable& var) override; - void Visit(const ShaderNodes::ParameterVariable& var) override; - void Visit(const ShaderNodes::UniformVariable& var) override; + void 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 PushExpression(ShaderNodes::ExpressionPtr expression); void PushStatement(ShaderNodes::StatementPtr statement); diff --git a/include/Nazara/Renderer/ShaderAstRecursiveVisitor.hpp b/include/Nazara/Renderer/ShaderAstRecursiveVisitor.hpp index 622c1aef0..0482ea009 100644 --- a/include/Nazara/Renderer/ShaderAstRecursiveVisitor.hpp +++ b/include/Nazara/Renderer/ShaderAstRecursiveVisitor.hpp @@ -21,19 +21,19 @@ namespace Nz using ShaderAstVisitor::Visit; - void Visit(const ShaderNodes::AccessMember& node) override; - void Visit(const ShaderNodes::AssignOp& node) override; - void Visit(const ShaderNodes::BinaryOp& node) override; - void Visit(const ShaderNodes::Branch& node) override; - void Visit(const ShaderNodes::Cast& node) override; - void Visit(const ShaderNodes::Constant& node) override; - void Visit(const ShaderNodes::DeclareVariable& node) override; - void Visit(const ShaderNodes::ExpressionStatement& node) override; - void Visit(const ShaderNodes::Identifier& node) override; - void Visit(const ShaderNodes::IntrinsicCall& node) override; - void Visit(const ShaderNodes::Sample2D& node) override; - void Visit(const ShaderNodes::StatementBlock& node) override; - void Visit(const ShaderNodes::SwizzleOp& node) override; + 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; }; } diff --git a/include/Nazara/Renderer/ShaderAstSerializer.hpp b/include/Nazara/Renderer/ShaderAstSerializer.hpp index 68380054c..3298d81e6 100644 --- a/include/Nazara/Renderer/ShaderAstSerializer.hpp +++ b/include/Nazara/Renderer/ShaderAstSerializer.hpp @@ -57,9 +57,13 @@ namespace Nz virtual void Value(bool& val) = 0; virtual void Value(float& val) = 0; virtual void Value(std::string& val) = 0; + virtual void Value(Int32& val) = 0; virtual void Value(Vector2f& val) = 0; virtual void Value(Vector3f& val) = 0; virtual void Value(Vector4f& val) = 0; + virtual void Value(Vector2i32& val) = 0; + virtual void Value(Vector3i32& val) = 0; + virtual void Value(Vector4i32& val) = 0; virtual void Value(UInt8& val) = 0; virtual void Value(UInt16& val) = 0; virtual void Value(UInt32& val) = 0; @@ -85,9 +89,13 @@ namespace Nz void Value(bool& val) override; void Value(float& val) override; void Value(std::string& val) override; + void Value(Int32& val) override; void Value(Vector2f& val) override; void Value(Vector3f& val) override; void Value(Vector4f& val) override; + void Value(Vector2i32& val) override; + void Value(Vector3i32& val) override; + void Value(Vector4i32& val) override; void Value(UInt8& val) override; void Value(UInt16& val) override; void Value(UInt32& val) override; @@ -111,9 +119,13 @@ namespace Nz void Value(bool& val) override; void Value(float& val) override; void Value(std::string& val) override; + void Value(Int32& val) override; void Value(Vector2f& val) override; void Value(Vector3f& val) override; void Value(Vector4f& val) override; + void Value(Vector2i32& val) override; + void Value(Vector3i32& val) override; + void Value(Vector4i32& val) override; void Value(UInt8& val) override; void Value(UInt16& val) override; void Value(UInt32& val) override; diff --git a/include/Nazara/Renderer/ShaderAstValidator.hpp b/include/Nazara/Renderer/ShaderAstValidator.hpp index aa586f99b..90aec52aa 100644 --- a/include/Nazara/Renderer/ShaderAstValidator.hpp +++ b/include/Nazara/Renderer/ShaderAstValidator.hpp @@ -34,27 +34,27 @@ namespace Nz void TypeMustMatch(const ShaderExpressionType& left, const ShaderExpressionType& right); using ShaderAstRecursiveVisitor::Visit; - void Visit(const ShaderNodes::AccessMember& node) override; - void Visit(const ShaderNodes::AssignOp& node) override; - void Visit(const ShaderNodes::BinaryOp& node) override; - void Visit(const ShaderNodes::Branch& node) override; - void Visit(const ShaderNodes::Cast& node) override; - void Visit(const ShaderNodes::Constant& node) override; - void Visit(const ShaderNodes::DeclareVariable& node) override; - void Visit(const ShaderNodes::ExpressionStatement& node) override; - void Visit(const ShaderNodes::Identifier& node) override; - void Visit(const ShaderNodes::IntrinsicCall& node) override; - void Visit(const ShaderNodes::Sample2D& node) override; - void Visit(const ShaderNodes::StatementBlock& node) override; - void Visit(const ShaderNodes::SwizzleOp& node) override; + 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; using ShaderVarVisitor::Visit; - void Visit(const ShaderNodes::BuiltinVariable& var) override; - void Visit(const ShaderNodes::InputVariable& var) override; - void Visit(const ShaderNodes::LocalVariable& var) override; - void Visit(const ShaderNodes::OutputVariable& var) override; - void Visit(const ShaderNodes::ParameterVariable& var) override; - void Visit(const ShaderNodes::UniformVariable& var) override; + void 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; struct Context; diff --git a/include/Nazara/Renderer/ShaderAstVisitor.hpp b/include/Nazara/Renderer/ShaderAstVisitor.hpp index d955f17e9..3ce83f406 100644 --- a/include/Nazara/Renderer/ShaderAstVisitor.hpp +++ b/include/Nazara/Renderer/ShaderAstVisitor.hpp @@ -27,20 +27,20 @@ namespace Nz bool IsConditionEnabled(const std::string& name) const; - virtual void Visit(const ShaderNodes::AccessMember& node) = 0; - virtual void Visit(const ShaderNodes::AssignOp& node) = 0; - virtual void Visit(const ShaderNodes::BinaryOp& node) = 0; - virtual void Visit(const ShaderNodes::Branch& node) = 0; - virtual void Visit(const ShaderNodes::Cast& node) = 0; - virtual void Visit(const ShaderNodes::Constant& node) = 0; - virtual void Visit(const ShaderNodes::DeclareVariable& node) = 0; - virtual void Visit(const ShaderNodes::ExpressionStatement& node) = 0; - virtual void Visit(const ShaderNodes::Identifier& node) = 0; - virtual void Visit(const ShaderNodes::IntrinsicCall& node) = 0; void Visit(const ShaderNodes::NodePtr& node); - virtual void Visit(const ShaderNodes::Sample2D& node) = 0; - virtual void Visit(const ShaderNodes::StatementBlock& node) = 0; - virtual void Visit(const ShaderNodes::SwizzleOp& node) = 0; + virtual void Visit(ShaderNodes::AccessMember& node) = 0; + virtual void Visit(ShaderNodes::AssignOp& node) = 0; + virtual void Visit(ShaderNodes::BinaryOp& node) = 0; + virtual void Visit(ShaderNodes::Branch& node) = 0; + virtual void Visit(ShaderNodes::Cast& node) = 0; + virtual void Visit(ShaderNodes::Constant& node) = 0; + virtual void Visit(ShaderNodes::DeclareVariable& node) = 0; + virtual void Visit(ShaderNodes::ExpressionStatement& node) = 0; + virtual void Visit(ShaderNodes::Identifier& node) = 0; + virtual void Visit(ShaderNodes::IntrinsicCall& node) = 0; + virtual void Visit(ShaderNodes::Sample2D& node) = 0; + virtual void Visit(ShaderNodes::StatementBlock& node) = 0; + virtual void Visit(ShaderNodes::SwizzleOp& node) = 0; private: std::unordered_set m_conditions; diff --git a/include/Nazara/Renderer/ShaderEnums.hpp b/include/Nazara/Renderer/ShaderEnums.hpp index ab9ed4953..46e6a3d74 100644 --- a/include/Nazara/Renderer/ShaderEnums.hpp +++ b/include/Nazara/Renderer/ShaderEnums.hpp @@ -18,15 +18,19 @@ namespace Nz::ShaderNodes enum class BasicType { - Boolean, // bool - Float1, // float - Float2, // vec2 - Float3, // vec3 - Float4, // vec4 - Mat4x4, // mat4 - Sampler2D, // sampler2D + Boolean, //< bool + Float1, //< float + Float2, //< vec2 + Float3, //< vec3 + Float4, //< vec4 + Int1, //< int + Int2, //< ivec2 + Int3, //< ivec3 + Int4, //< ivec4 + Mat4x4, //< mat4 + Sampler2D, //< sampler2D - Void // void + Void //< void }; enum class BinaryType diff --git a/include/Nazara/Renderer/ShaderNodes.hpp b/include/Nazara/Renderer/ShaderNodes.hpp index c0b8688e2..985cde039 100644 --- a/include/Nazara/Renderer/ShaderNodes.hpp +++ b/include/Nazara/Renderer/ShaderNodes.hpp @@ -145,7 +145,7 @@ namespace Nz std::size_t memberIndex; ExpressionPtr structExpr; - ShaderExpressionType exprType; //< FIXME: Use ShaderAst to automate + ShaderExpressionType exprType; static inline std::shared_ptr Build(ExpressionPtr structExpr, std::size_t memberIndex, ShaderExpressionType exprType); }; @@ -225,9 +225,13 @@ namespace Nz using Variant = std::variant< bool, float, + Int32, Vector2f, Vector3f, - Vector4f + Vector4f, + Vector2i32, + Vector3i32, + Vector4i32 >; Variant value; diff --git a/include/Nazara/Renderer/ShaderNodes.inl b/include/Nazara/Renderer/ShaderNodes.inl index 0e9307ff4..e6dbec2ba 100644 --- a/include/Nazara/Renderer/ShaderNodes.inl +++ b/include/Nazara/Renderer/ShaderNodes.inl @@ -28,12 +28,15 @@ namespace Nz::ShaderNodes switch (type) { case BasicType::Float2: + case BasicType::Int2: return 2; case BasicType::Float3: + case BasicType::Int3: return 3; case BasicType::Float4: + case BasicType::Int4: return 4; case BasicType::Mat4x4: @@ -53,6 +56,11 @@ namespace Nz::ShaderNodes case BasicType::Float4: return BasicType::Float1; + case BasicType::Int2: + case BasicType::Int3: + case BasicType::Int4: + return BasicType::Int1; + case BasicType::Mat4x4: return BasicType::Float4; diff --git a/include/Nazara/Renderer/ShaderVarVisitor.hpp b/include/Nazara/Renderer/ShaderVarVisitor.hpp index 6df035d74..bda5e0b4d 100644 --- a/include/Nazara/Renderer/ShaderVarVisitor.hpp +++ b/include/Nazara/Renderer/ShaderVarVisitor.hpp @@ -21,13 +21,14 @@ namespace Nz ShaderVarVisitor(ShaderVarVisitor&&) = delete; virtual ~ShaderVarVisitor(); - virtual void Visit(const ShaderNodes::BuiltinVariable& var) = 0; - virtual void Visit(const ShaderNodes::InputVariable& var) = 0; - virtual void Visit(const ShaderNodes::LocalVariable& var) = 0; - virtual void Visit(const ShaderNodes::OutputVariable& var) = 0; - virtual void Visit(const ShaderNodes::ParameterVariable& var) = 0; - virtual void Visit(const ShaderNodes::UniformVariable& var) = 0; void Visit(const ShaderNodes::VariablePtr& node); + + virtual void Visit(ShaderNodes::BuiltinVariable& var) = 0; + virtual void Visit(ShaderNodes::InputVariable& var) = 0; + virtual void Visit(ShaderNodes::LocalVariable& var) = 0; + virtual void Visit(ShaderNodes::OutputVariable& var) = 0; + virtual void Visit(ShaderNodes::ParameterVariable& var) = 0; + virtual void Visit(ShaderNodes::UniformVariable& var) = 0; }; } diff --git a/include/Nazara/Renderer/SpirvWriter.hpp b/include/Nazara/Renderer/SpirvWriter.hpp index 2301d6caf..b9e48dd12 100644 --- a/include/Nazara/Renderer/SpirvWriter.hpp +++ b/include/Nazara/Renderer/SpirvWriter.hpp @@ -10,8 +10,8 @@ #include #include #include -#include #include +#include #include #include #include @@ -20,7 +20,7 @@ namespace Nz { - class NAZARA_RENDERER_API SpirvWriter : public ShaderAstVisitor + class NAZARA_RENDERER_API SpirvWriter : public ShaderAstVisitor, public ShaderVarVisitor { public: struct Environment; @@ -41,6 +41,7 @@ namespace Nz }; private: + struct ExtVar; struct Opcode; struct Raw; struct WordCount; @@ -76,28 +77,39 @@ namespace Nz void AppendStructType(std::size_t structIndex, UInt32 resultId); void AppendTypes(); + UInt32 EvaluateExpression(const ShaderNodes::ExpressionPtr& expr); + UInt32 GetConstantId(const ShaderNodes::Constant::Variant& value) const; UInt32 GetTypeId(const ShaderExpressionType& type) const; void PushResultId(UInt32 value); UInt32 PopResultId(); + UInt32 ReadVariable(ExtVar& var); UInt32 RegisterType(ShaderExpressionType type); using ShaderAstVisitor::Visit; - void Visit(const ShaderNodes::AccessMember& node) override; - void Visit(const ShaderNodes::AssignOp& node) override; - void Visit(const ShaderNodes::Branch& node) override; - void Visit(const ShaderNodes::BinaryOp& node) override; - void Visit(const ShaderNodes::Cast& node) override; - void Visit(const ShaderNodes::Constant& node) override; - void Visit(const ShaderNodes::DeclareVariable& node) override; - void Visit(const ShaderNodes::ExpressionStatement& node) override; - void Visit(const ShaderNodes::Identifier& node) override; - void Visit(const ShaderNodes::IntrinsicCall& node) override; - void Visit(const ShaderNodes::Sample2D& node) override; - void Visit(const ShaderNodes::StatementBlock& node) override; - void Visit(const ShaderNodes::SwizzleOp& node) override; + 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; static void MergeBlocks(std::vector& output, const Section& from); diff --git a/src/Nazara/Renderer/GlslWriter.cpp b/src/Nazara/Renderer/GlslWriter.cpp index 8fa23755a..3d651a84f 100644 --- a/src/Nazara/Renderer/GlslWriter.cpp +++ b/src/Nazara/Renderer/GlslWriter.cpp @@ -188,30 +188,18 @@ namespace Nz { switch (type) { - case ShaderNodes::BasicType::Boolean: - Append("bool"); - break; - case ShaderNodes::BasicType::Float1: - Append("float"); - break; - case ShaderNodes::BasicType::Float2: - Append("vec2"); - break; - case ShaderNodes::BasicType::Float3: - Append("vec3"); - break; - case ShaderNodes::BasicType::Float4: - Append("vec4"); - break; - case ShaderNodes::BasicType::Mat4x4: - Append("mat4"); - break; - case ShaderNodes::BasicType::Sampler2D: - Append("sampler2D"); - break; - case ShaderNodes::BasicType::Void: - Append("void"); - break; + case ShaderNodes::BasicType::Boolean: return Append("bool"); + case ShaderNodes::BasicType::Float1: return Append("float"); + case ShaderNodes::BasicType::Float2: return Append("vec2"); + case ShaderNodes::BasicType::Float3: return Append("vec3"); + case ShaderNodes::BasicType::Float4: return Append("vec4"); + case ShaderNodes::BasicType::Int1: return Append("int"); + case ShaderNodes::BasicType::Int2: return Append("ivec2"); + case ShaderNodes::BasicType::Int3: return Append("ivec3"); + case ShaderNodes::BasicType::Int4: return Append("ivec4"); + case ShaderNodes::BasicType::Mat4x4: return Append("mat4"); + case ShaderNodes::BasicType::Sampler2D: return Append("sampler2D"); + case ShaderNodes::BasicType::Void: return Append("void"); } } @@ -298,7 +286,7 @@ namespace Nz AppendLine("}"); } - void GlslWriter::Visit(const ShaderNodes::ExpressionPtr& expr, bool encloseIfRequired) + void GlslWriter::Visit(ShaderNodes::ExpressionPtr& expr, bool encloseIfRequired) { bool enclose = encloseIfRequired && (expr->GetExpressionCategory() != ShaderNodes::ExpressionCategory::LValue); @@ -311,7 +299,7 @@ namespace Nz Append(")"); } - void GlslWriter::Visit(const ShaderNodes::AccessMember& node) + void GlslWriter::Visit(ShaderNodes::AccessMember& node) { Visit(node.structExpr, true); @@ -332,7 +320,7 @@ namespace Nz Append(member.name); } - void GlslWriter::Visit(const ShaderNodes::AssignOp& node) + void GlslWriter::Visit(ShaderNodes::AssignOp& node) { Visit(node.left); @@ -346,7 +334,7 @@ namespace Nz Visit(node.right); } - void GlslWriter::Visit(const ShaderNodes::Branch& node) + void GlslWriter::Visit(ShaderNodes::Branch& node) { bool first = true; for (const auto& statement : node.condStatements) @@ -375,7 +363,7 @@ namespace Nz } } - void GlslWriter::Visit(const ShaderNodes::BinaryOp& node) + void GlslWriter::Visit(ShaderNodes::BinaryOp& node) { Visit(node.left, true); @@ -401,12 +389,12 @@ namespace Nz Visit(node.right, true); } - void GlslWriter::Visit(const ShaderNodes::BuiltinVariable& var) + void GlslWriter::Visit(ShaderNodes::BuiltinVariable& var) { Append(var.entry); } - void GlslWriter::Visit(const ShaderNodes::Cast& node) + void GlslWriter::Visit(ShaderNodes::Cast& node) { Append(node.exprType); Append("("); @@ -425,28 +413,31 @@ namespace Nz Append(")"); } - void GlslWriter::Visit(const ShaderNodes::Constant& node) + void GlslWriter::Visit(ShaderNodes::Constant& node) { std::visit([&](auto&& arg) { using T = std::decay_t; + if constexpr (std::is_same_v || std::is_same_v || std::is_same_v) + Append("i"); //< for ivec + if constexpr (std::is_same_v) Append((arg) ? "true" : "false"); - else if constexpr (std::is_same_v) + else if constexpr (std::is_same_v || std::is_same_v) Append(std::to_string(arg)); - else if constexpr (std::is_same_v) + else if constexpr (std::is_same_v || std::is_same_v) Append("vec2(" + std::to_string(arg.x) + ", " + std::to_string(arg.y) + ")"); - else if constexpr (std::is_same_v) + else if constexpr (std::is_same_v || std::is_same_v) Append("vec3(" + std::to_string(arg.x) + ", " + std::to_string(arg.y) + ", " + std::to_string(arg.z) + ")"); - else if constexpr (std::is_same_v) + else if constexpr (std::is_same_v || std::is_same_v) Append("vec4(" + std::to_string(arg.x) + ", " + std::to_string(arg.y) + ", " + std::to_string(arg.z) + ", " + std::to_string(arg.w) + ")"); else static_assert(AlwaysFalse::value, "non-exhaustive visitor"); }, node.value); } - void GlslWriter::Visit(const ShaderNodes::DeclareVariable& node) + void GlslWriter::Visit(ShaderNodes::DeclareVariable& node) { assert(node.variable->GetType() == ShaderNodes::VariableType::LocalVariable); @@ -464,23 +455,23 @@ namespace Nz AppendLine(";"); } - void GlslWriter::Visit(const ShaderNodes::ExpressionStatement& node) + void GlslWriter::Visit(ShaderNodes::ExpressionStatement& node) { Visit(node.expression); Append(";"); } - void GlslWriter::Visit(const ShaderNodes::Identifier& node) + void GlslWriter::Visit(ShaderNodes::Identifier& node) { Visit(node.var); } - void GlslWriter::Visit(const ShaderNodes::InputVariable& var) + void GlslWriter::Visit(ShaderNodes::InputVariable& var) { Append(var.name); } - void GlslWriter::Visit(const ShaderNodes::IntrinsicCall& node) + void GlslWriter::Visit(ShaderNodes::IntrinsicCall& node) { switch (node.intrinsic) { @@ -504,22 +495,22 @@ namespace Nz Append(")"); } - void GlslWriter::Visit(const ShaderNodes::LocalVariable& var) + void GlslWriter::Visit(ShaderNodes::LocalVariable& var) { Append(var.name); } - void GlslWriter::Visit(const ShaderNodes::ParameterVariable& var) + void GlslWriter::Visit(ShaderNodes::ParameterVariable& var) { Append(var.name); } - void GlslWriter::Visit(const ShaderNodes::OutputVariable& var) + void GlslWriter::Visit(ShaderNodes::OutputVariable& var) { Append(var.name); } - void GlslWriter::Visit(const ShaderNodes::Sample2D& node) + void GlslWriter::Visit(ShaderNodes::Sample2D& node) { Append("texture("); Visit(node.sampler); @@ -528,7 +519,7 @@ namespace Nz Append(")"); } - void GlslWriter::Visit(const ShaderNodes::StatementBlock& node) + void GlslWriter::Visit(ShaderNodes::StatementBlock& node) { bool first = true; for (const ShaderNodes::StatementPtr& statement : node.statements) @@ -542,7 +533,7 @@ namespace Nz } } - void GlslWriter::Visit(const ShaderNodes::SwizzleOp& node) + void GlslWriter::Visit(ShaderNodes::SwizzleOp& node) { Visit(node.expression); Append("."); @@ -570,7 +561,7 @@ namespace Nz } } - void GlslWriter::Visit(const ShaderNodes::UniformVariable& var) + void GlslWriter::Visit(ShaderNodes::UniformVariable& var) { Append(var.name); } diff --git a/src/Nazara/Renderer/Renderer.cpp b/src/Nazara/Renderer/Renderer.cpp index 9df137326..6954f5cf0 100644 --- a/src/Nazara/Renderer/Renderer.cpp +++ b/src/Nazara/Renderer/Renderer.cpp @@ -69,7 +69,7 @@ namespace Nz }; RegisterImpl("NazaraOpenGLRenderer" NazaraRendererDebugSuffix, [] { return 50; }); - //RegisterImpl("NazaraVulkanRenderer" NazaraRendererDebugSuffix, [] { return 100; }); + RegisterImpl("NazaraVulkanRenderer" NazaraRendererDebugSuffix, [] { return 100; }); std::sort(implementations.begin(), implementations.end(), [](const auto& lhs, const auto& rhs) { return lhs.score > rhs.score; }); diff --git a/src/Nazara/Renderer/ShaderAstCloner.cpp b/src/Nazara/Renderer/ShaderAstCloner.cpp index 75ac0634c..2b712075c 100644 --- a/src/Nazara/Renderer/ShaderAstCloner.cpp +++ b/src/Nazara/Renderer/ShaderAstCloner.cpp @@ -45,22 +45,22 @@ namespace Nz return PopVariable(); } - void ShaderAstCloner::Visit(const ShaderNodes::AccessMember& node) + void ShaderAstCloner::Visit(ShaderNodes::AccessMember& node) { PushExpression(ShaderNodes::AccessMember::Build(CloneExpression(node.structExpr), node.memberIndex, node.exprType)); } - void ShaderAstCloner::Visit(const ShaderNodes::AssignOp& node) + void ShaderAstCloner::Visit(ShaderNodes::AssignOp& node) { PushExpression(ShaderNodes::AssignOp::Build(node.op, CloneExpression(node.left), CloneExpression(node.right))); } - void ShaderAstCloner::Visit(const ShaderNodes::BinaryOp& node) + void ShaderAstCloner::Visit(ShaderNodes::BinaryOp& node) { PushExpression(ShaderNodes::BinaryOp::Build(node.op, CloneExpression(node.left), CloneExpression(node.right))); } - void ShaderAstCloner::Visit(const ShaderNodes::Branch& node) + void ShaderAstCloner::Visit(ShaderNodes::Branch& node) { std::vector condStatements; condStatements.reserve(node.condStatements.size()); @@ -75,7 +75,7 @@ namespace Nz PushStatement(ShaderNodes::Branch::Build(std::move(condStatements), CloneStatement(node.elseStatement))); } - void ShaderAstCloner::Visit(const ShaderNodes::Cast& node) + void ShaderAstCloner::Visit(ShaderNodes::Cast& node) { std::size_t expressionCount = 0; std::array expressions; @@ -91,27 +91,27 @@ namespace Nz PushExpression(ShaderNodes::Cast::Build(node.exprType, expressions.data(), expressionCount)); } - void ShaderAstCloner::Visit(const ShaderNodes::Constant& node) + void ShaderAstCloner::Visit(ShaderNodes::Constant& node) { PushExpression(ShaderNodes::Constant::Build(node.value)); } - void ShaderAstCloner::Visit(const ShaderNodes::DeclareVariable& node) + void ShaderAstCloner::Visit(ShaderNodes::DeclareVariable& node) { PushStatement(ShaderNodes::DeclareVariable::Build(CloneVariable(node.variable), CloneExpression(node.expression))); } - void ShaderAstCloner::Visit(const ShaderNodes::ExpressionStatement& node) + void ShaderAstCloner::Visit(ShaderNodes::ExpressionStatement& node) { PushStatement(ShaderNodes::ExpressionStatement::Build(CloneExpression(node.expression))); } - void ShaderAstCloner::Visit(const ShaderNodes::Identifier& node) + void ShaderAstCloner::Visit(ShaderNodes::Identifier& node) { PushExpression(ShaderNodes::Identifier::Build(CloneVariable(node.var))); } - void ShaderAstCloner::Visit(const ShaderNodes::IntrinsicCall& node) + void ShaderAstCloner::Visit(ShaderNodes::IntrinsicCall& node) { std::vector parameters; parameters.reserve(node.parameters.size()); @@ -122,12 +122,12 @@ namespace Nz PushExpression(ShaderNodes::IntrinsicCall::Build(node.intrinsic, std::move(parameters))); } - void ShaderAstCloner::Visit(const ShaderNodes::Sample2D& node) + void ShaderAstCloner::Visit(ShaderNodes::Sample2D& node) { PushExpression(ShaderNodes::Sample2D::Build(CloneExpression(node.sampler), CloneExpression(node.coordinates))); } - void ShaderAstCloner::Visit(const ShaderNodes::StatementBlock& node) + void ShaderAstCloner::Visit(ShaderNodes::StatementBlock& node) { std::vector statements; statements.reserve(node.statements.size()); @@ -138,37 +138,37 @@ namespace Nz PushStatement(ShaderNodes::StatementBlock::Build(std::move(statements))); } - void ShaderAstCloner::Visit(const ShaderNodes::SwizzleOp& node) + void ShaderAstCloner::Visit(ShaderNodes::SwizzleOp& node) { PushExpression(ShaderNodes::SwizzleOp::Build(PopExpression(), node.components.data(), node.componentCount)); } - void ShaderAstCloner::Visit(const ShaderNodes::BuiltinVariable& var) + void ShaderAstCloner::Visit(ShaderNodes::BuiltinVariable& var) { PushVariable(ShaderNodes::BuiltinVariable::Build(var.entry, var.type)); } - void ShaderAstCloner::Visit(const ShaderNodes::InputVariable& var) + void ShaderAstCloner::Visit(ShaderNodes::InputVariable& var) { PushVariable(ShaderNodes::InputVariable::Build(var.name, var.type)); } - void ShaderAstCloner::Visit(const ShaderNodes::LocalVariable& var) + void ShaderAstCloner::Visit(ShaderNodes::LocalVariable& var) { PushVariable(ShaderNodes::LocalVariable::Build(var.name, var.type)); } - void ShaderAstCloner::Visit(const ShaderNodes::OutputVariable& var) + void ShaderAstCloner::Visit(ShaderNodes::OutputVariable& var) { PushVariable(ShaderNodes::OutputVariable::Build(var.name, var.type)); } - void ShaderAstCloner::Visit(const ShaderNodes::ParameterVariable& var) + void ShaderAstCloner::Visit(ShaderNodes::ParameterVariable& var) { PushVariable(ShaderNodes::ParameterVariable::Build(var.name, var.type)); } - void ShaderAstCloner::Visit(const ShaderNodes::UniformVariable& var) + void ShaderAstCloner::Visit(ShaderNodes::UniformVariable& var) { PushVariable(ShaderNodes::UniformVariable::Build(var.name, var.type)); } diff --git a/src/Nazara/Renderer/ShaderAstRecursiveVisitor.cpp b/src/Nazara/Renderer/ShaderAstRecursiveVisitor.cpp index 81344bcf0..5a39e68c5 100644 --- a/src/Nazara/Renderer/ShaderAstRecursiveVisitor.cpp +++ b/src/Nazara/Renderer/ShaderAstRecursiveVisitor.cpp @@ -7,24 +7,24 @@ namespace Nz { - void ShaderAstRecursiveVisitor::Visit(const ShaderNodes::AccessMember& node) + void ShaderAstRecursiveVisitor::Visit(ShaderNodes::AccessMember& node) { Visit(node.structExpr); } - void ShaderAstRecursiveVisitor::Visit(const ShaderNodes::AssignOp& node) + void ShaderAstRecursiveVisitor::Visit(ShaderNodes::AssignOp& node) { Visit(node.left); Visit(node.right); } - void ShaderAstRecursiveVisitor::Visit(const ShaderNodes::BinaryOp& node) + void ShaderAstRecursiveVisitor::Visit(ShaderNodes::BinaryOp& node) { Visit(node.left); Visit(node.right); } - void ShaderAstRecursiveVisitor::Visit(const ShaderNodes::Branch& node) + void ShaderAstRecursiveVisitor::Visit(ShaderNodes::Branch& node) { for (auto& cond : node.condStatements) { @@ -36,7 +36,7 @@ namespace Nz Visit(node.elseStatement); } - void ShaderAstRecursiveVisitor::Visit(const ShaderNodes::Cast& node) + void ShaderAstRecursiveVisitor::Visit(ShaderNodes::Cast& node) { for (auto& expr : node.expressions) { @@ -47,46 +47,46 @@ namespace Nz } } - void ShaderAstRecursiveVisitor::Visit(const ShaderNodes::Constant& /*node*/) + void ShaderAstRecursiveVisitor::Visit(ShaderNodes::Constant& /*node*/) { /* Nothing to do */ } - void ShaderAstRecursiveVisitor::Visit(const ShaderNodes::DeclareVariable& node) + void ShaderAstRecursiveVisitor::Visit(ShaderNodes::DeclareVariable& node) { if (node.expression) Visit(node.expression); } - void ShaderAstRecursiveVisitor::Visit(const ShaderNodes::ExpressionStatement& node) + void ShaderAstRecursiveVisitor::Visit(ShaderNodes::ExpressionStatement& node) { Visit(node.expression); } - void ShaderAstRecursiveVisitor::Visit(const ShaderNodes::Identifier& /*node*/) + void ShaderAstRecursiveVisitor::Visit(ShaderNodes::Identifier& /*node*/) { /* Nothing to do */ } - void ShaderAstRecursiveVisitor::Visit(const ShaderNodes::IntrinsicCall& node) + void ShaderAstRecursiveVisitor::Visit(ShaderNodes::IntrinsicCall& node) { for (auto& param : node.parameters) Visit(param); } - void ShaderAstRecursiveVisitor::Visit(const ShaderNodes::Sample2D& node) + void ShaderAstRecursiveVisitor::Visit(ShaderNodes::Sample2D& node) { Visit(node.sampler); Visit(node.coordinates); } - void ShaderAstRecursiveVisitor::Visit(const ShaderNodes::StatementBlock& node) + void ShaderAstRecursiveVisitor::Visit(ShaderNodes::StatementBlock& node) { for (auto& statement : node.statements) Visit(statement); } - void ShaderAstRecursiveVisitor::Visit(const ShaderNodes::SwizzleOp& node) + void ShaderAstRecursiveVisitor::Visit(ShaderNodes::SwizzleOp& node) { Visit(node.expression); } diff --git a/src/Nazara/Renderer/ShaderAstSerializer.cpp b/src/Nazara/Renderer/ShaderAstSerializer.cpp index b4de31cc7..f8afa178c 100644 --- a/src/Nazara/Renderer/ShaderAstSerializer.cpp +++ b/src/Nazara/Renderer/ShaderAstSerializer.cpp @@ -22,98 +22,98 @@ namespace Nz { } - void Visit(const ShaderNodes::AccessMember& node) override + void Visit(ShaderNodes::AccessMember& node) override { Serialize(node); } - void Visit(const ShaderNodes::AssignOp& node) override + void Visit(ShaderNodes::AssignOp& node) override { Serialize(node); } - void Visit(const ShaderNodes::BinaryOp& node) override + void Visit(ShaderNodes::BinaryOp& node) override { Serialize(node); } - void Visit(const ShaderNodes::Branch& node) override + void Visit(ShaderNodes::Branch& node) override { Serialize(node); } - void Visit(const ShaderNodes::Cast& node) override + void Visit(ShaderNodes::Cast& node) override { Serialize(node); } - void Visit(const ShaderNodes::Constant& node) override + void Visit(ShaderNodes::Constant& node) override { Serialize(node); } - void Visit(const ShaderNodes::DeclareVariable& node) override + void Visit(ShaderNodes::DeclareVariable& node) override { Serialize(node); } - void Visit(const ShaderNodes::ExpressionStatement& node) override + void Visit(ShaderNodes::ExpressionStatement& node) override { Serialize(node); } - void Visit(const ShaderNodes::Identifier& node) override + void Visit(ShaderNodes::Identifier& node) override { Serialize(node); } - void Visit(const ShaderNodes::IntrinsicCall& node) override + void Visit(ShaderNodes::IntrinsicCall& node) override { Serialize(node); } - void Visit(const ShaderNodes::Sample2D& node) override + void Visit(ShaderNodes::Sample2D& node) override { Serialize(node); } - void Visit(const ShaderNodes::StatementBlock& node) override + void Visit(ShaderNodes::StatementBlock& node) override { Serialize(node); } - void Visit(const ShaderNodes::SwizzleOp& node) override + void Visit(ShaderNodes::SwizzleOp& node) override { Serialize(node); } - void Visit(const ShaderNodes::BuiltinVariable& var) override + void Visit(ShaderNodes::BuiltinVariable& var) override { Serialize(var); } - void Visit(const ShaderNodes::InputVariable& var) override + void Visit(ShaderNodes::InputVariable& var) override { Serialize(var); } - void Visit(const ShaderNodes::LocalVariable& var) override + void Visit(ShaderNodes::LocalVariable& var) override { Serialize(var); } - void Visit(const ShaderNodes::OutputVariable& var) override + void Visit(ShaderNodes::OutputVariable& var) override { Serialize(var); } - void Visit(const ShaderNodes::ParameterVariable& var) override + void Visit(ShaderNodes::ParameterVariable& var) override { Serialize(var); } - void Visit(const ShaderNodes::UniformVariable& var) override + void Visit(ShaderNodes::UniformVariable& var) override { Serialize(var); } @@ -193,14 +193,18 @@ namespace Nz Value(value); }; - static_assert(std::variant_size_v == 5); + static_assert(std::variant_size_v == 9); switch (typeIndex) { case 0: SerializeValue(bool()); break; case 1: SerializeValue(float()); break; - case 2: SerializeValue(Vector2f()); break; - case 3: SerializeValue(Vector3f()); break; - case 4: SerializeValue(Vector4f()); break; + case 2: SerializeValue(Int32()); break; + case 3: SerializeValue(Vector2f()); break; + case 4: SerializeValue(Vector3f()); break; + case 5: SerializeValue(Vector4f()); break; + case 6: SerializeValue(Vector2i32()); break; + case 7: SerializeValue(Vector3i32()); break; + case 8: SerializeValue(Vector4i32()); break; default: throw std::runtime_error("unexpected data type"); } } @@ -403,6 +407,11 @@ namespace Nz m_stream << val; } + void ShaderAstSerializer::Value(Int32& val) + { + m_stream << val; + } + void ShaderAstSerializer::Value(Vector2f& val) { m_stream << val; @@ -418,6 +427,21 @@ namespace Nz m_stream << val; } + void ShaderAstSerializer::Value(Vector2i32& val) + { + m_stream << val; + } + + void ShaderAstSerializer::Value(Vector3i32& val) + { + m_stream << val; + } + + void ShaderAstSerializer::Value(Vector4i32& val) + { + m_stream << val; + } + void ShaderAstSerializer::Value(UInt8& val) { m_stream << val; @@ -644,6 +668,11 @@ namespace Nz m_stream >> val; } + void ShaderAstUnserializer::Value(Int32& val) + { + m_stream >> val; + } + void ShaderAstUnserializer::Value(Vector2f& val) { m_stream >> val; @@ -659,6 +688,21 @@ namespace Nz m_stream >> val; } + void ShaderAstUnserializer::Value(Vector2i32& val) + { + m_stream >> val; + } + + void ShaderAstUnserializer::Value(Vector3i32& val) + { + m_stream >> val; + } + + void ShaderAstUnserializer::Value(Vector4i32& val) + { + m_stream >> val; + } + void ShaderAstUnserializer::Value(UInt8& val) { m_stream >> val; @@ -689,6 +733,7 @@ namespace Nz HandleType(BuiltinVariable); HandleType(InputVariable); HandleType(LocalVariable); + HandleType(ParameterVariable); HandleType(OutputVariable); HandleType(UniformVariable); } diff --git a/src/Nazara/Renderer/ShaderAstValidator.cpp b/src/Nazara/Renderer/ShaderAstValidator.cpp index 8e161d532..81970e766 100644 --- a/src/Nazara/Renderer/ShaderAstValidator.cpp +++ b/src/Nazara/Renderer/ShaderAstValidator.cpp @@ -83,7 +83,7 @@ namespace Nz throw AstError{ "Left expression type must match right expression type" }; } - void ShaderAstValidator::Visit(const ShaderNodes::AccessMember& node) + void ShaderAstValidator::Visit(ShaderNodes::AccessMember& node) { const ShaderExpressionType& exprType = MandatoryExpr(node.structExpr)->GetExpressionType(); if (!std::holds_alternative(exprType)) @@ -105,7 +105,7 @@ namespace Nz throw AstError{ "member type does not match node type" }; } - void ShaderAstValidator::Visit(const ShaderNodes::AssignOp& node) + void ShaderAstValidator::Visit(ShaderNodes::AssignOp& node) { MandatoryNode(node.left); MandatoryNode(node.right); @@ -117,7 +117,7 @@ namespace Nz ShaderAstRecursiveVisitor::Visit(node); } - void ShaderAstValidator::Visit(const ShaderNodes::BinaryOp& node) + void ShaderAstValidator::Visit(ShaderNodes::BinaryOp& node) { MandatoryNode(node.left); MandatoryNode(node.right); @@ -147,8 +147,9 @@ namespace Nz switch (leftType) { case ShaderNodes::BasicType::Float1: + case ShaderNodes::BasicType::Int1: { - if (ShaderNodes::Node::GetComponentType(rightType) != ShaderNodes::BasicType::Float1) + if (ShaderNodes::Node::GetComponentType(rightType) != leftType) throw AstError{ "Left expression type is not compatible with right expression type" }; break; @@ -157,8 +158,11 @@ namespace Nz case ShaderNodes::BasicType::Float2: case ShaderNodes::BasicType::Float3: case ShaderNodes::BasicType::Float4: + case ShaderNodes::BasicType::Int2: + case ShaderNodes::BasicType::Int3: + case ShaderNodes::BasicType::Int4: { - if (leftType != rightType && rightType != ShaderNodes::BasicType::Float1) + if (leftType != rightType && rightType != ShaderNodes::Node::GetComponentType(leftType)) throw AstError{ "Left expression type is not compatible with right expression type" }; break; @@ -189,7 +193,7 @@ namespace Nz ShaderAstRecursiveVisitor::Visit(node); } - void ShaderAstValidator::Visit(const ShaderNodes::Branch& node) + void ShaderAstValidator::Visit(ShaderNodes::Branch& node) { for (const auto& condStatement : node.condStatements) { @@ -200,7 +204,7 @@ namespace Nz ShaderAstRecursiveVisitor::Visit(node); } - void ShaderAstValidator::Visit(const ShaderNodes::Cast& node) + void ShaderAstValidator::Visit(ShaderNodes::Cast& node) { unsigned int componentCount = 0; unsigned int requiredComponents = node.GetComponentCount(node.exprType); @@ -222,11 +226,11 @@ namespace Nz ShaderAstRecursiveVisitor::Visit(node); } - void ShaderAstValidator::Visit(const ShaderNodes::Constant& /*node*/) + void ShaderAstValidator::Visit(ShaderNodes::Constant& /*node*/) { } - void ShaderAstValidator::Visit(const ShaderNodes::DeclareVariable& node) + void ShaderAstValidator::Visit(ShaderNodes::DeclareVariable& node) { assert(m_context); @@ -242,14 +246,14 @@ namespace Nz ShaderAstRecursiveVisitor::Visit(node); } - void ShaderAstValidator::Visit(const ShaderNodes::ExpressionStatement& node) + void ShaderAstValidator::Visit(ShaderNodes::ExpressionStatement& node) { MandatoryNode(node.expression); ShaderAstRecursiveVisitor::Visit(node); } - void ShaderAstValidator::Visit(const ShaderNodes::Identifier& node) + void ShaderAstValidator::Visit(ShaderNodes::Identifier& node) { assert(m_context); @@ -259,7 +263,7 @@ namespace Nz Visit(node.var); } - void ShaderAstValidator::Visit(const ShaderNodes::IntrinsicCall& node) + void ShaderAstValidator::Visit(ShaderNodes::IntrinsicCall& node) { switch (node.intrinsic) { @@ -300,7 +304,7 @@ namespace Nz ShaderAstRecursiveVisitor::Visit(node); } - void ShaderAstValidator::Visit(const ShaderNodes::Sample2D& node) + void ShaderAstValidator::Visit(ShaderNodes::Sample2D& node) { if (MandatoryExpr(node.sampler)->GetExpressionType() != ShaderExpressionType{ ShaderNodes::BasicType::Sampler2D }) throw AstError{ "Sampler must be a Sampler2D" }; @@ -311,7 +315,7 @@ namespace Nz ShaderAstRecursiveVisitor::Visit(node); } - void ShaderAstValidator::Visit(const ShaderNodes::StatementBlock& node) + void ShaderAstValidator::Visit(ShaderNodes::StatementBlock& node) { assert(m_context); @@ -327,7 +331,7 @@ namespace Nz ShaderAstRecursiveVisitor::Visit(node); } - void ShaderAstValidator::Visit(const ShaderNodes::SwizzleOp& node) + void ShaderAstValidator::Visit(ShaderNodes::SwizzleOp& node) { if (node.componentCount > 4) throw AstError{ "Cannot swizzle more than four elements" }; @@ -342,6 +346,10 @@ namespace Nz case ShaderNodes::BasicType::Float2: case ShaderNodes::BasicType::Float3: case ShaderNodes::BasicType::Float4: + case ShaderNodes::BasicType::Int1: + case ShaderNodes::BasicType::Int2: + case ShaderNodes::BasicType::Int3: + case ShaderNodes::BasicType::Int4: break; default: @@ -351,12 +359,23 @@ namespace Nz ShaderAstRecursiveVisitor::Visit(node); } - void ShaderAstValidator::Visit(const ShaderNodes::BuiltinVariable& /*var*/) + void ShaderAstValidator::Visit(ShaderNodes::BuiltinVariable& var) { - /* Nothing to do */ + switch (var.entry) + { + case ShaderNodes::BuiltinEntry::VertexPosition: + if (!std::holds_alternative(var.type) || + std::get(var.type) != ShaderNodes::BasicType::Float4) + throw AstError{ "Builtin is not of the expected type" }; + + break; + + default: + break; + } } - void ShaderAstValidator::Visit(const ShaderNodes::InputVariable& var) + void ShaderAstValidator::Visit(ShaderNodes::InputVariable& var) { for (std::size_t i = 0; i < m_shader.GetInputCount(); ++i) { @@ -371,7 +390,7 @@ namespace Nz throw AstError{ "Input not found" }; } - void ShaderAstValidator::Visit(const ShaderNodes::LocalVariable& var) + void ShaderAstValidator::Visit(ShaderNodes::LocalVariable& var) { const auto& vars = m_context->declaredLocals; @@ -382,7 +401,7 @@ namespace Nz TypeMustMatch(it->type, var.type); } - void ShaderAstValidator::Visit(const ShaderNodes::OutputVariable& var) + void ShaderAstValidator::Visit(ShaderNodes::OutputVariable& var) { for (std::size_t i = 0; i < m_shader.GetOutputCount(); ++i) { @@ -397,7 +416,7 @@ namespace Nz throw AstError{ "Output not found" }; } - void ShaderAstValidator::Visit(const ShaderNodes::ParameterVariable& var) + void ShaderAstValidator::Visit(ShaderNodes::ParameterVariable& var) { assert(m_context->currentFunction); @@ -410,7 +429,7 @@ namespace Nz TypeMustMatch(it->type, var.type); } - void ShaderAstValidator::Visit(const ShaderNodes::UniformVariable& var) + void ShaderAstValidator::Visit(ShaderNodes::UniformVariable& var) { for (std::size_t i = 0; i < m_shader.GetUniformCount(); ++i) { diff --git a/src/Nazara/Renderer/ShaderNodes.cpp b/src/Nazara/Renderer/ShaderNodes.cpp index 7ea148cb6..29ffb8508 100644 --- a/src/Nazara/Renderer/ShaderNodes.cpp +++ b/src/Nazara/Renderer/ShaderNodes.cpp @@ -59,7 +59,7 @@ namespace Nz::ShaderNodes visitor.Visit(*this); } - ExpressionCategory ShaderNodes::AccessMember::GetExpressionCategory() const + ExpressionCategory AccessMember::GetExpressionCategory() const { return ExpressionCategory::LValue; } @@ -111,10 +111,14 @@ namespace Nz::ShaderNodes case BasicType::Float2: case BasicType::Float3: case BasicType::Float4: + case BasicType::Int2: + case BasicType::Int3: + case BasicType::Int4: exprType = leftExprType; break; case BasicType::Float1: + case BasicType::Int1: case BasicType::Mat4x4: exprType = rightExprType; break; @@ -159,12 +163,20 @@ namespace Nz::ShaderNodes return ShaderNodes::BasicType::Boolean; else if constexpr (std::is_same_v) return ShaderNodes::BasicType::Float1; + else if constexpr (std::is_same_v) + return ShaderNodes::BasicType::Int1; else if constexpr (std::is_same_v) return ShaderNodes::BasicType::Float2; else if constexpr (std::is_same_v) return ShaderNodes::BasicType::Float3; else if constexpr (std::is_same_v) return ShaderNodes::BasicType::Float4; + else if constexpr (std::is_same_v) + return ShaderNodes::BasicType::Int2; + else if constexpr (std::is_same_v) + return ShaderNodes::BasicType::Int3; + else if constexpr (std::is_same_v) + return ShaderNodes::BasicType::Int4; else static_assert(AlwaysFalse::value, "non-exhaustive visitor"); }, value); diff --git a/src/Nazara/Renderer/SpirvWriter.cpp b/src/Nazara/Renderer/SpirvWriter.cpp index a94cd6ec9..1e9218e34 100644 --- a/src/Nazara/Renderer/SpirvWriter.cpp +++ b/src/Nazara/Renderer/SpirvWriter.cpp @@ -5,6 +5,8 @@ #include #include #include +#include +#include #include #include #include @@ -34,28 +36,35 @@ namespace Nz using ShaderAstRecursiveVisitor::Visit; using ShaderVarVisitor::Visit; - void Visit(const ShaderNodes::Constant& node) override + void Visit(ShaderNodes::AccessMember& node) override + { + constants.emplace(Int32(node.memberIndex)); + + ShaderAstRecursiveVisitor::Visit(node); + } + + void Visit(ShaderNodes::Constant& node) override { std::visit([&](auto&& arg) { using T = std::decay_t; - if constexpr (std::is_same_v || std::is_same_v) + if constexpr (std::is_same_v || std::is_same_v || std::is_same_v) constants.emplace(arg); - else if constexpr (std::is_same_v) + else if constexpr (std::is_same_v || std::is_same_v) { constants.emplace(arg.x); constants.emplace(arg.y); constants.emplace(arg); } - else if constexpr (std::is_same_v) + else if constexpr (std::is_same_v || std::is_same_v) { constants.emplace(arg.x); constants.emplace(arg.y); constants.emplace(arg.z); constants.emplace(arg); } - else if constexpr (std::is_same_v) + else if constexpr (std::is_same_v || std::is_same_v) { constants.emplace(arg.x); constants.emplace(arg.y); @@ -71,21 +80,21 @@ namespace Nz ShaderAstRecursiveVisitor::Visit(node); } - void Visit(const ShaderNodes::DeclareVariable& node) override + void Visit(ShaderNodes::DeclareVariable& node) override { Visit(node.variable); ShaderAstRecursiveVisitor::Visit(node); } - void Visit(const ShaderNodes::Identifier& node) override + void Visit(ShaderNodes::Identifier& node) override { Visit(node.var); ShaderAstRecursiveVisitor::Visit(node); } - void Visit(const ShaderNodes::IntrinsicCall& node) override + void Visit(ShaderNodes::IntrinsicCall& node) override { ShaderAstRecursiveVisitor::Visit(node); @@ -102,32 +111,32 @@ namespace Nz } } - void Visit(const ShaderNodes::BuiltinVariable& var) override + void Visit(ShaderNodes::BuiltinVariable& var) override { builtinVars.insert(std::static_pointer_cast(var.shared_from_this())); } - void Visit(const ShaderNodes::InputVariable& var) override + void Visit(ShaderNodes::InputVariable& var) override { /* Handled by ShaderAst */ } - void Visit(const ShaderNodes::LocalVariable& var) override + void Visit(ShaderNodes::LocalVariable& var) override { localVars.insert(std::static_pointer_cast(var.shared_from_this())); } - void Visit(const ShaderNodes::OutputVariable& var) override + void Visit(ShaderNodes::OutputVariable& var) override { /* Handled by ShaderAst */ } - void Visit(const ShaderNodes::ParameterVariable& var) override + void Visit(ShaderNodes::ParameterVariable& var) override { paramVars.insert(std::static_pointer_cast(var.shared_from_this())); } - void Visit(const ShaderNodes::UniformVariable& var) override + void Visit(ShaderNodes::UniformVariable& var) override { /* Handled by ShaderAst */ } @@ -138,8 +147,57 @@ namespace Nz LocalContainer localVars; ParameterContainer paramVars; }; + + class AssignVisitor : public ShaderAstRecursiveVisitor + { + public: + void Visit(ShaderNodes::AccessMember& node) override + { + } + + void Visit(ShaderNodes::Identifier& node) override + { + } + + void Visit(ShaderNodes::SwizzleOp& node) override + { + } + }; + + template + constexpr ShaderNodes::BasicType GetBasicType() + { + if constexpr (std::is_same_v) + return ShaderNodes::BasicType::Boolean; + else if constexpr (std::is_same_v) + return(ShaderNodes::BasicType::Float1); + else if constexpr (std::is_same_v) + return(ShaderNodes::BasicType::Int1); + else if constexpr (std::is_same_v) + return(ShaderNodes::BasicType::Float2); + else if constexpr (std::is_same_v) + return(ShaderNodes::BasicType::Float3); + else if constexpr (std::is_same_v) + return(ShaderNodes::BasicType::Float4); + else if constexpr (std::is_same_v) + return(ShaderNodes::BasicType::Int2); + else if constexpr (std::is_same_v) + return(ShaderNodes::BasicType::Int3); + else if constexpr (std::is_same_v) + return(ShaderNodes::BasicType::Int4); + else + static_assert(AlwaysFalse::value, "unhandled type"); + } } + struct SpirvWriter::ExtVar + { + UInt32 pointerTypeId; + UInt32 typeId; + UInt32 varId; + std::optional valueId; + }; + struct SpirvWriter::Opcode { SpvOp op; @@ -165,20 +223,15 @@ namespace Nz std::vector paramsId; }; - struct ExtVar - { - UInt32 pointerTypeId; - UInt32 varId; - }; - std::unordered_map extensionInstructions; - std::unordered_map builtinIds; + std::unordered_map builtinIds; + std::unordered_map varToResult; tsl::ordered_map constantIds; tsl::ordered_map typeIds; std::vector funcs; - std::vector inputIds; - std::vector outputIds; - std::vector uniformIds; + tsl::ordered_map inputIds; + tsl::ordered_map outputIds; + tsl::ordered_map uniformIds; std::vector> structFields; std::vector resultIds; UInt32 nextVarIndex = 1; @@ -213,14 +266,17 @@ namespace Nz }); state.structFields.resize(shader.GetStructCount()); - state.annotations.Append(Opcode{ SpvOpNop }); - state.constants.Append(Opcode{ SpvOpNop }); - state.debugInfo.Append(Opcode{ SpvOpNop }); - state.types.Append(Opcode{ SpvOpNop }); + + std::vector functionStatements; + + ShaderAstCloner cloner; PreVisitor preVisitor; for (const auto& func : shader.GetFunctions()) + { + functionStatements.emplace_back(cloner.Clone(func.statement)); preVisitor.Visit(func.statement); + } // Register all extended instruction sets for (const std::string& extInst : preVisitor.extInsts) @@ -246,39 +302,67 @@ namespace Nz for (const auto& local : preVisitor.localVars) RegisterType(local->type); + for (const auto& builtin : preVisitor.builtinVars) + RegisterType(builtin->type); + // Register constant types for (const auto& constant : preVisitor.constants) { std::visit([&](auto&& arg) { using T = std::decay_t; - - if constexpr (std::is_same_v) - RegisterType(ShaderNodes::BasicType::Boolean); - else if constexpr (std::is_same_v) - RegisterType(ShaderNodes::BasicType::Float1); - else if constexpr (std::is_same_v) - RegisterType(ShaderNodes::BasicType::Float2); - else if constexpr (std::is_same_v) - RegisterType(ShaderNodes::BasicType::Float3); - else if constexpr (std::is_same_v) - RegisterType(ShaderNodes::BasicType::Float4); - else - static_assert(AlwaysFalse::value, "non-exhaustive visitor"); + RegisterType(GetBasicType()); }, constant); } AppendTypes(); // Register result id and debug infos for global variables/functions + for (const auto& builtin : preVisitor.builtinVars) + { + const ShaderExpressionType& builtinExprType = builtin->type; + assert(std::holds_alternative(builtinExprType)); + + ShaderNodes::BasicType builtinType = std::get(builtinExprType); + + ExtVar builtinData; + builtinData.pointerTypeId = AllocateResultId(); + builtinData.typeId = GetTypeId(builtinType); + builtinData.varId = AllocateResultId(); + + SpvBuiltIn spvBuiltin; + std::string debugName; + switch (builtin->entry) + { + case ShaderNodes::BuiltinEntry::VertexPosition: + debugName = "builtin_VertexPosition"; + spvBuiltin = SpvBuiltInPosition; + break; + + default: + throw std::runtime_error("unexpected builtin type"); + } + + state.debugInfo.Append(Opcode{ SpvOpName }, builtinData.varId, debugName); + state.types.Append(Opcode{ SpvOpTypePointer }, builtinData.pointerTypeId, SpvStorageClassOutput, builtinData.typeId); + state.types.Append(Opcode{ SpvOpVariable }, builtinData.pointerTypeId, builtinData.varId, SpvStorageClassOutput); + + state.annotations.Append(Opcode{ SpvOpDecorate }, builtinData.varId, SpvDecorationBuiltIn, spvBuiltin); + + state.builtinIds.emplace(builtin->entry, builtinData); + } + for (const auto& input : shader.GetInputs()) { - auto& inputData = state.inputIds.emplace_back(); + ExtVar inputData; inputData.pointerTypeId = AllocateResultId(); + inputData.typeId = GetTypeId(input.type); inputData.varId = AllocateResultId(); + state.inputIds.emplace(input.name, inputData); + state.debugInfo.Append(Opcode{ SpvOpName }, inputData.varId, input.name); - state.types.Append(Opcode{ SpvOpTypePointer }, inputData.pointerTypeId, SpvStorageClassInput, GetTypeId(input.type)); + state.types.Append(Opcode{ SpvOpTypePointer }, inputData.pointerTypeId, SpvStorageClassInput, inputData.typeId); state.types.Append(Opcode{ SpvOpVariable }, inputData.pointerTypeId, inputData.varId, SpvStorageClassInput); if (input.locationIndex) @@ -287,12 +371,15 @@ namespace Nz for (const auto& output : shader.GetOutputs()) { - auto& outputData = state.outputIds.emplace_back(); + ExtVar outputData; outputData.pointerTypeId = AllocateResultId(); + outputData.typeId = GetTypeId(output.type); outputData.varId = AllocateResultId(); + state.outputIds.emplace(output.name, outputData); + state.debugInfo.Append(Opcode{ SpvOpName }, outputData.varId, output.name); - state.types.Append(Opcode{ SpvOpTypePointer }, outputData.pointerTypeId, SpvStorageClassOutput, GetTypeId(output.type)); + state.types.Append(Opcode{ SpvOpTypePointer }, outputData.pointerTypeId, SpvStorageClassOutput, outputData.typeId); state.types.Append(Opcode{ SpvOpVariable }, outputData.pointerTypeId, outputData.varId, SpvStorageClassOutput); if (output.locationIndex) @@ -301,12 +388,15 @@ namespace Nz for (const auto& uniform : shader.GetUniforms()) { - auto& uniformData = state.uniformIds.emplace_back(); + ExtVar uniformData; uniformData.pointerTypeId = AllocateResultId(); + uniformData.typeId = GetTypeId(uniform.type); uniformData.varId = AllocateResultId(); + state.uniformIds.emplace(uniform.name, uniformData); + state.debugInfo.Append(Opcode{ SpvOpName }, uniformData.varId, uniform.name); - state.types.Append(Opcode{ SpvOpTypePointer }, uniformData.pointerTypeId, SpvStorageClassUniform, GetTypeId(uniform.type)); + state.types.Append(Opcode{ SpvOpTypePointer }, uniformData.pointerTypeId, SpvStorageClassUniform, uniformData.typeId); state.types.Append(Opcode{ SpvOpVariable }, uniformData.pointerTypeId, uniformData.varId, SpvStorageClassUniform); if (uniform.bindingIndex) @@ -338,16 +428,20 @@ namespace Nz AppendConstants(); + std::size_t entryPointIndex = std::numeric_limits::max(); + for (std::size_t funcIndex = 0; funcIndex < shader.GetFunctionCount(); ++funcIndex) { const auto& func = shader.GetFunction(funcIndex); + if (func.name == "main") + entryPointIndex = funcIndex; auto& funcData = state.funcs[funcIndex]; - state.instructions.Append(Opcode{ SpvOpNop }); - state.instructions.Append(Opcode{ SpvOpFunction }, GetTypeId(func.returnType), funcData.id, 0, funcData.typeId); + state.instructions.Append(Opcode{ SpvOpLabel }, AllocateResultId()); + for (const auto& param : func.parameters) { UInt32 paramResultId = AllocateResultId(); @@ -356,24 +450,56 @@ namespace Nz state.instructions.Append(Opcode{ SpvOpFunctionParameter }, GetTypeId(param.type), paramResultId); } - Visit(func.statement); + Visit(functionStatements[funcIndex]); + + if (func.returnType == ShaderNodes::BasicType::Void) + state.instructions.Append(Opcode{ SpvOpReturn }); state.instructions.Append(Opcode{ SpvOpFunctionEnd }); } + assert(entryPointIndex != std::numeric_limits::max()); + AppendHeader(); - /*assert(m_context.shader); + SpvExecutionModel execModel; + const auto& entryFuncData = shader.GetFunction(entryPointIndex); + const auto& entryFunc = m_currentState->funcs[entryPointIndex]; + + assert(m_context.shader); switch (m_context.shader->GetStage()) { case ShaderStageType::Fragment: + execModel = SpvExecutionModelFragment; break; + case ShaderStageType::Vertex: + execModel = SpvExecutionModelVertex; break; default: - break; - }*/ + throw std::runtime_error("not yet implemented"); + } + + // OpEntryPoint Vertex %main "main" %outNormal %inNormals %outTexCoords %inTexCoord %_ %inPos + + std::size_t nameSize = state.header.CountWord(entryFuncData.name); + + state.header.Append(Opcode{ SpvOpEntryPoint }, WordCount{ static_cast(3 + nameSize + m_currentState->builtinIds.size() + m_currentState->inputIds.size() + m_currentState->outputIds.size()) }); + state.header.Append(execModel); + state.header.Append(entryFunc.id); + state.header.Append(entryFuncData.name); + for (const auto& [name, varData] : m_currentState->builtinIds) + state.header.Append(varData.varId); + + for (const auto& [name, varData] : m_currentState->inputIds) + state.header.Append(varData.varId); + + for (const auto& [name, varData] : m_currentState->outputIds) + state.header.Append(varData.varId); + + if (m_context.shader->GetStage() == ShaderStageType::Fragment) + state.header.Append(Opcode{ SpvOpExecutionMode }, entryFunc.id, SpvExecutionModeOriginUpperLeft); std::vector ret; MergeBlocks(ret, state.header); @@ -407,14 +533,14 @@ namespace Nz if constexpr (std::is_same_v) m_currentState->constants.Append(Opcode{ (arg) ? SpvOpConstantTrue : SpvOpConstantFalse }, constantId); - else if constexpr (std::is_same_v) - m_currentState->constants.Append(Opcode{ SpvOpConstant }, GetTypeId(ShaderNodes::BasicType::Float1), constantId, Raw{ &arg, sizeof(arg) }); - else if constexpr (std::is_same_v) - m_currentState->constants.Append(Opcode{ SpvOpConstantComposite }, GetTypeId(ShaderNodes::BasicType::Float2), constantId, GetConstantId(arg.x), GetConstantId(arg.y)); - else if constexpr (std::is_same_v) - m_currentState->constants.Append(Opcode{ SpvOpConstantComposite }, GetTypeId(ShaderNodes::BasicType::Float3), constantId, GetConstantId(arg.x), GetConstantId(arg.y), GetConstantId(arg.z)); - else if constexpr (std::is_same_v) - m_currentState->constants.Append(Opcode{ SpvOpConstantComposite }, GetTypeId(ShaderNodes::BasicType::Float3), constantId, GetConstantId(arg.x), GetConstantId(arg.y), GetConstantId(arg.z), GetConstantId(arg.w)); + else if constexpr (std::is_same_v || std::is_same_v) + m_currentState->constants.Append(Opcode{ SpvOpConstant }, GetTypeId(GetBasicType()), constantId, Raw{ &arg, sizeof(arg) }); + else if constexpr (std::is_same_v || std::is_same_v) + m_currentState->constants.Append(Opcode{ SpvOpConstantComposite }, GetTypeId(GetBasicType()), constantId, GetConstantId(arg.x), GetConstantId(arg.y)); + else if constexpr (std::is_same_v || std::is_same_v) + m_currentState->constants.Append(Opcode{ SpvOpConstantComposite }, GetTypeId(GetBasicType()), constantId, GetConstantId(arg.x), GetConstantId(arg.y), GetConstantId(arg.z)); + else if constexpr (std::is_same_v || std::is_same_v) + m_currentState->constants.Append(Opcode{ SpvOpConstantComposite }, GetTypeId(GetBasicType()), constantId, GetConstantId(arg.x), GetConstantId(arg.y), GetConstantId(arg.z), GetConstantId(arg.w)); else static_assert(AlwaysFalse::value, "non-exhaustive visitor"); }, value); @@ -467,14 +593,18 @@ namespace Nz std::size_t offset = [&] { switch (arg) { - case ShaderNodes::BasicType::Boolean: return structOffsets.AddField(StructFieldType_Bool1); - case ShaderNodes::BasicType::Float1: return structOffsets.AddField(StructFieldType_Float1); - case ShaderNodes::BasicType::Float2: return structOffsets.AddField(StructFieldType_Float2); - case ShaderNodes::BasicType::Float3: return structOffsets.AddField(StructFieldType_Float3); - case ShaderNodes::BasicType::Float4: return structOffsets.AddField(StructFieldType_Float4); - case ShaderNodes::BasicType::Mat4x4: return structOffsets.AddMatrix(StructFieldType_Float1, 4, 4, true); + case ShaderNodes::BasicType::Boolean: return structOffsets.AddField(StructFieldType_Bool1); + case ShaderNodes::BasicType::Float1: return structOffsets.AddField(StructFieldType_Float1); + case ShaderNodes::BasicType::Float2: return structOffsets.AddField(StructFieldType_Float2); + case ShaderNodes::BasicType::Float3: return structOffsets.AddField(StructFieldType_Float3); + case ShaderNodes::BasicType::Float4: return structOffsets.AddField(StructFieldType_Float4); + case ShaderNodes::BasicType::Int1: return structOffsets.AddField(StructFieldType_Int1); + case ShaderNodes::BasicType::Int2: return structOffsets.AddField(StructFieldType_Int2); + case ShaderNodes::BasicType::Int3: return structOffsets.AddField(StructFieldType_Int3); + case ShaderNodes::BasicType::Int4: return structOffsets.AddField(StructFieldType_Int4); + case ShaderNodes::BasicType::Mat4x4: return structOffsets.AddMatrix(StructFieldType_Float1, 4, 4, true); case ShaderNodes::BasicType::Sampler2D: throw std::runtime_error("unexpected sampler2D as struct member"); - case ShaderNodes::BasicType::Void: throw std::runtime_error("unexpected void as struct member"); + case ShaderNodes::BasicType::Void: throw std::runtime_error("unexpected void as struct member"); } assert(false); @@ -537,13 +667,22 @@ namespace Nz case ShaderNodes::BasicType::Float2: case ShaderNodes::BasicType::Float3: case ShaderNodes::BasicType::Float4: + case ShaderNodes::BasicType::Int2: + case ShaderNodes::BasicType::Int3: + case ShaderNodes::BasicType::Int4: { - UInt32 vecSize = UInt32(arg) - UInt32(ShaderNodes::BasicType::Float2) + 1; + ShaderNodes::BasicType baseType = ShaderNodes::Node::GetComponentType(arg); - m_currentState->types.Append(Opcode{ SpvOpTypeVector }, resultId, GetTypeId(ShaderNodes::BasicType::Float1), vecSize); + UInt32 vecSize = UInt32(arg) - UInt32(baseType) + 1; + + m_currentState->types.Append(Opcode{ SpvOpTypeVector }, resultId, GetTypeId(baseType), vecSize); break; } + case ShaderNodes::BasicType::Int1: + m_currentState->types.Append(Opcode{ SpvOpTypeInt }, resultId, 32, 1); + break; + case ShaderNodes::BasicType::Mat4x4: { m_currentState->types.Append(Opcode{ SpvOpTypeMatrix }, resultId, GetTypeId(ShaderNodes::BasicType::Float4), 4); @@ -581,6 +720,12 @@ namespace Nz } } + UInt32 SpirvWriter::EvaluateExpression(const ShaderNodes::ExpressionPtr& expr) + { + Visit(expr); + return PopResultId(); + } + UInt32 SpirvWriter::GetConstantId(const ShaderNodes::Constant::Variant& value) const { auto typeIt = m_currentState->constantIds.find(value); @@ -613,6 +758,19 @@ namespace Nz return resultId; } + UInt32 SpirvWriter::ReadVariable(ExtVar& var) + { + if (!var.valueId.has_value()) + { + UInt32 resultId = AllocateResultId(); + m_currentState->instructions.Append(Opcode{ SpvOpLoad }, var.typeId, resultId, var.varId); + + var.valueId = resultId; + } + + return var.valueId.value(); + } + UInt32 SpirvWriter::RegisterType(ShaderExpressionType type) { auto it = m_currentState->typeIds.find(type); @@ -628,6 +786,7 @@ namespace Nz { case ShaderNodes::BasicType::Boolean: case ShaderNodes::BasicType::Float1: + case ShaderNodes::BasicType::Int1: case ShaderNodes::BasicType::Void: break; //< Nothing to do @@ -635,11 +794,11 @@ namespace Nz case ShaderNodes::BasicType::Float2: case ShaderNodes::BasicType::Float3: case ShaderNodes::BasicType::Float4: - RegisterType(ShaderNodes::BasicType::Float1); - break; - + case ShaderNodes::BasicType::Int2: + case ShaderNodes::BasicType::Int3: + case ShaderNodes::BasicType::Int4: case ShaderNodes::BasicType::Mat4x4: - RegisterType(ShaderNodes::BasicType::Float4); + RegisterType(ShaderNodes::Node::GetComponentType(arg)); break; case ShaderNodes::BasicType::Sampler2D: @@ -670,60 +829,392 @@ namespace Nz return it->second; } - void SpirvWriter::Visit(const ShaderNodes::AccessMember& node) + void SpirvWriter::Visit(ShaderNodes::AccessMember& node) { - Visit(node.structExpr); + UInt32 pointerId; + SpvStorageClass storage; + + switch (node.structExpr->GetType()) + { + case ShaderNodes::NodeType::Identifier: + { + auto& identifier = static_cast(*node.structExpr); + switch (identifier.var->GetType()) + { + case ShaderNodes::VariableType::BuiltinVariable: + { + auto& builtinvar = static_cast(*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(*identifier.var); + auto it = m_currentState->inputIds.find(inputVar.name); + assert(it != m_currentState->inputIds.end()); + + storage = SpvStorageClassInput; + + pointerId = it->second.varId; + break; + } + + case ShaderNodes::VariableType::OutputVariable: + { + auto& outputVar = static_cast(*identifier.var); + auto it = m_currentState->outputIds.find(outputVar.name); + assert(it != m_currentState->outputIds.end()); + + storage = SpvStorageClassOutput; + + pointerId = it->second.varId; + break; + } + + case ShaderNodes::VariableType::UniformVariable: + { + auto& uniformVar = static_cast(*identifier.var); + auto it = m_currentState->uniformIds.find(uniformVar.name); + assert(it != m_currentState->uniformIds.end()); + + storage = SpvStorageClassUniform; + + 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 = AllocateResultId(); + UInt32 typeId = GetTypeId(node.exprType); + UInt32 indexId = GetConstantId(Int32(node.memberIndex)); + + m_currentState->types.Append(Opcode{ SpvOpTypePointer }, pointerType, storage, typeId); + + m_currentState->instructions.Append(Opcode{ SpvOpAccessChain }, pointerType, memberPointerId, pointerId, indexId); + + UInt32 resultId = AllocateResultId(); + + m_currentState->instructions.Append(Opcode{ SpvOpLoad }, typeId, resultId, memberPointerId); + + PushResultId(resultId); } - void SpirvWriter::Visit(const ShaderNodes::AssignOp& node) + void SpirvWriter::Visit(ShaderNodes::AssignOp& node) { - Visit(node.left); - Visit(node.right); + UInt32 result = EvaluateExpression(node.right); + + switch (node.left->GetType()) + { + case ShaderNodes::NodeType::Identifier: + { + auto& identifier = static_cast(*node.left); + switch (identifier.var->GetType()) + { + case ShaderNodes::VariableType::BuiltinVariable: + { + auto& builtinvar = static_cast(*identifier.var); + auto it = m_currentState->builtinIds.find(builtinvar.entry); + assert(it != m_currentState->builtinIds.end()); + + m_currentState->instructions.Append(Opcode{ SpvOpStore }, it->second.varId, result); + PushResultId(result); + break; + } + + case ShaderNodes::VariableType::OutputVariable: + { + auto& outputVar = static_cast(*identifier.var); + auto it = m_currentState->outputIds.find(outputVar.name); + assert(it != m_currentState->outputIds.end()); + + m_currentState->instructions.Append(Opcode{ SpvOpStore }, 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(const ShaderNodes::Branch& node) + void SpirvWriter::Visit(ShaderNodes::Branch& node) { throw std::runtime_error("not yet implemented"); } - void SpirvWriter::Visit(const ShaderNodes::BinaryOp& node) + void SpirvWriter::Visit(ShaderNodes::BinaryOp& node) { - Visit(node.left); - Visit(node.right); + 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 = AllocateResultId(); - UInt32 leftOperand = PopResultId(); - UInt32 rightOperand = PopResultId(); - SpvOp op = [&] { + bool swapOperands = false; + + SpvOp op = [&] + { switch (node.op) { - case ShaderNodes::BinaryType::Add: return SpvOpFAdd; - case ShaderNodes::BinaryType::Substract: return SpvOpFSub; - case ShaderNodes::BinaryType::Multiply: return SpvOpFMul; - case ShaderNodes::BinaryType::Divide: return SpvOpFDiv; - case ShaderNodes::BinaryType::Equality: return SpvOpFOrdEqual; + 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 SpvOpFAdd; + + case ShaderNodes::BasicType::Int1: + case ShaderNodes::BasicType::Int2: + case ShaderNodes::BasicType::Int3: + case ShaderNodes::BasicType::Int4: + return SpvOpIAdd; + + 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 SpvOpFSub; + + case ShaderNodes::BasicType::Int1: + case ShaderNodes::BasicType::Int2: + case ShaderNodes::BasicType::Int3: + case ShaderNodes::BasicType::Int4: + return SpvOpISub; + + 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 SpvOpFDiv; + + case ShaderNodes::BasicType::Int1: + case ShaderNodes::BasicType::Int2: + case ShaderNodes::BasicType::Int3: + case ShaderNodes::BasicType::Int4: + return SpvOpSDiv; + + case ShaderNodes::BasicType::Boolean: + case ShaderNodes::BasicType::Sampler2D: + case ShaderNodes::BasicType::Void: + break; + } + } + + case ShaderNodes::BinaryType::Equality: + { + switch (leftType) + { + case ShaderNodes::BasicType::Boolean: + return SpvOpLogicalEqual; + + case ShaderNodes::BasicType::Float1: + case ShaderNodes::BasicType::Float2: + case ShaderNodes::BasicType::Float3: + case ShaderNodes::BasicType::Float4: + case ShaderNodes::BasicType::Mat4x4: + return SpvOpFOrdEqual; + + case ShaderNodes::BasicType::Int1: + case ShaderNodes::BasicType::Int2: + case ShaderNodes::BasicType::Int3: + case ShaderNodes::BasicType::Int4: + return SpvOpIEqual; + + 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 SpvOpFMul; + + case ShaderNodes::BasicType::Float2: + case ShaderNodes::BasicType::Float3: + case ShaderNodes::BasicType::Float4: + swapOperands = true; + return SpvOpVectorTimesScalar; + + case ShaderNodes::BasicType::Mat4x4: + swapOperands = true; + return SpvOpMatrixTimesScalar; + + default: + break; + } + + break; + } + + case ShaderNodes::BasicType::Float2: + case ShaderNodes::BasicType::Float3: + case ShaderNodes::BasicType::Float4: + { + switch (rightType) + { + case ShaderNodes::BasicType::Float1: + return SpvOpVectorTimesScalar; + + case ShaderNodes::BasicType::Float2: + case ShaderNodes::BasicType::Float3: + case ShaderNodes::BasicType::Float4: + return SpvOpFMul; + + case ShaderNodes::BasicType::Mat4x4: + return SpvOpVectorTimesMatrix; + + default: + break; + } + + break; + } + + case ShaderNodes::BasicType::Int1: + case ShaderNodes::BasicType::Int2: + case ShaderNodes::BasicType::Int3: + case ShaderNodes::BasicType::Int4: + return SpvOpIMul; + + case ShaderNodes::BasicType::Mat4x4: + { + switch (rightType) + { + case ShaderNodes::BasicType::Float1: return SpvOpMatrixTimesScalar; + case ShaderNodes::BasicType::Float4: return SpvOpMatrixTimesVector; + case ShaderNodes::BasicType::Mat4x4: return SpvOpMatrixTimesMatrix; + + default: + break; + } + + break; + } + + default: + break; + } + break; + } } assert(false); throw std::runtime_error("unexpected binary operation"); }(); - m_currentState->instructions.Append(Opcode{ op }, GetTypeId(ShaderNodes::BasicType::Float3), resultId, leftOperand, rightOperand); + if (swapOperands) + std::swap(leftOperand, rightOperand); + + m_currentState->instructions.Append(Opcode{ op }, GetTypeId(resultType), resultId, leftOperand, rightOperand); + PushResultId(resultId); } - void SpirvWriter::Visit(const ShaderNodes::Cast& node) + void SpirvWriter::Visit(ShaderNodes::Cast& node) { - for (auto& expr : node.expressions) + 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 (!expr) + if (!exprPtr) break; - Visit(expr); + exprResults.push_back(EvaluateExpression(exprPtr)); } + + UInt32 resultId = AllocateResultId(); + + m_currentState->instructions.Append(Opcode{ SpvOpCompositeConstruct }, WordCount { static_cast(3 + exprResults.size()) }); + m_currentState->instructions.Append(GetTypeId(targetType)); + m_currentState->instructions.Append(resultId); + + for (UInt32 resultId : exprResults) + m_currentState->instructions.Append(resultId); + + PushResultId(resultId); } - void SpirvWriter::Visit(const ShaderNodes::Constant& node) + void SpirvWriter::Visit(ShaderNodes::Constant& node) { std::visit([&] (const auto& value) { @@ -731,43 +1222,150 @@ namespace Nz }, node.value); } - void SpirvWriter::Visit(const ShaderNodes::DeclareVariable& node) + void SpirvWriter::Visit(ShaderNodes::DeclareVariable& node) { if (node.expression) - Visit(node.expression); + { + assert(node.variable->GetType() == ShaderNodes::VariableType::LocalVariable); + + const auto& localVar = static_cast(*node.variable); + m_currentState->varToResult[localVar.name] = EvaluateExpression(node.expression); + } } - void SpirvWriter::Visit(const ShaderNodes::ExpressionStatement& node) + void SpirvWriter::Visit(ShaderNodes::ExpressionStatement& node) { Visit(node.expression); + PopResultId(); } - void SpirvWriter::Visit(const ShaderNodes::Identifier& node) + void SpirvWriter::Visit(ShaderNodes::Identifier& node) { - PushResultId(42); + Visit(node.var); } - void SpirvWriter::Visit(const ShaderNodes::IntrinsicCall& node) + void SpirvWriter::Visit(ShaderNodes::IntrinsicCall& node) { - for (auto& param : node.parameters) - Visit(param); + 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 = GetTypeId(node.GetComponentType(vecType)); + + UInt32 vec1 = EvaluateExpression(node.parameters[0]); + UInt32 vec2 = EvaluateExpression(node.parameters[1]); + + UInt32 resultId = AllocateResultId(); + + m_currentState->instructions.Append(Opcode{ SpvOpDot }, typeId, resultId, vec1, vec2); + PushResultId(resultId); + break; + } + + case ShaderNodes::IntrinsicType::CrossProduct: + default: + throw std::runtime_error("not yet implemented"); + } } - void SpirvWriter::Visit(const ShaderNodes::Sample2D& node) + void SpirvWriter::Visit(ShaderNodes::Sample2D& node) { - Visit(node.sampler); - Visit(node.coordinates); + // OpImageSampleImplicitLod %v4float %31 %35 + + UInt32 typeId = GetTypeId(ShaderNodes::BasicType::Float4); + + UInt32 samplerId = EvaluateExpression(node.sampler); + UInt32 coordinatesId = EvaluateExpression(node.coordinates); + UInt32 resultId = AllocateResultId(); + + m_currentState->instructions.Append(Opcode{ SpvOpImageSampleImplicitLod }, typeId, resultId, samplerId, coordinatesId); + PushResultId(resultId); } - void SpirvWriter::Visit(const ShaderNodes::StatementBlock& node) + void SpirvWriter::Visit(ShaderNodes::StatementBlock& node) { for (auto& statement : node.statements) Visit(statement); } - void SpirvWriter::Visit(const ShaderNodes::SwizzleOp& node) + void SpirvWriter::Visit(ShaderNodes::SwizzleOp& node) { - Visit(node.expression); + const ShaderExpressionType& targetExprType = node.GetExpressionType(); + assert(std::holds_alternative(targetExprType)); + + ShaderNodes::BasicType targetType = std::get(targetExprType); + + UInt32 exprResultId = EvaluateExpression(node.expression); + UInt32 resultId = AllocateResultId(); + + if (node.componentCount > 1) + { + // Swizzling is implemented via SpvOpVectorShuffle using the same vector twice as operands + m_currentState->instructions.Append(Opcode{ SpvOpVectorShuffle }, WordCount{ static_cast(5 + node.componentCount) }); + m_currentState->instructions.Append(GetTypeId(targetType)); + m_currentState->instructions.Append(resultId); + m_currentState->instructions.Append(exprResultId); + m_currentState->instructions.Append(exprResultId); + + for (std::size_t i = 0; i < node.componentCount; ++i) + m_currentState->instructions.Append(UInt32(node.components[0]) - UInt32(node.components[i])); + } + else + { + // Extract a single component from the vector + assert(node.componentCount == 1); + + m_currentState->instructions.Append(Opcode{ SpvOpCompositeExtract }, 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())); } void SpirvWriter::MergeBlocks(std::vector& output, const Section& from) @@ -794,15 +1392,16 @@ namespace Nz UInt32 codepoint = 0; for (std::size_t j = 0; j < 4; ++j) { +#ifdef NAZARA_BIG_ENDIAN + std::size_t pos = i * 4 + (3 - j); +#else std::size_t pos = i * 4 + j; +#endif + if (pos < raw.size) codepoint |= UInt32(ptr[pos]) << (j * 8); } -#ifdef NAZARA_BIG_ENDIAN - SwapBytes(codepoint); -#endif - Append(codepoint); } diff --git a/src/Nazara/VulkanRenderer/Vulkan.cpp b/src/Nazara/VulkanRenderer/Vulkan.cpp index e6e2d4cfd..4f55223e1 100644 --- a/src/Nazara/VulkanRenderer/Vulkan.cpp +++ b/src/Nazara/VulkanRenderer/Vulkan.cpp @@ -57,7 +57,7 @@ namespace Nz String appName = "Another application made with Nazara Engine"; String engineName = "Nazara Engine - Vulkan Renderer"; - constexpr UInt32 appVersion = VK_MAKE_VERSION(1, 0, 0); + UInt32 appVersion = VK_MAKE_VERSION(1, 0, 0); UInt32 engineVersion = VK_MAKE_VERSION(1, 0, 0); parameters.GetStringParameter("VkAppInfo_OverrideApplicationName", &appName); diff --git a/src/Nazara/VulkanRenderer/VulkanShaderStage.cpp b/src/Nazara/VulkanRenderer/VulkanShaderStage.cpp index 238bb6468..c0b510dd8 100644 --- a/src/Nazara/VulkanRenderer/VulkanShaderStage.cpp +++ b/src/Nazara/VulkanRenderer/VulkanShaderStage.cpp @@ -3,25 +3,61 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include +#include +#include +#include #include namespace Nz { bool VulkanShaderStage::Create(Vk::Device& device, ShaderStageType type, ShaderLanguage lang, const void* source, std::size_t sourceSize) { - if (lang != ShaderLanguage::SpirV) - { - NazaraError("Only Spir-V is supported for now"); - return false; - } - - if (!m_shaderModule.Create(device, reinterpret_cast(source), sourceSize)) - { - NazaraError("Failed to create shader module"); - return false; - } - m_stage = type; + + switch (lang) + { + case ShaderLanguage::NazaraBinary: + { + ByteStream byteStream(source, sourceSize); + auto shader = Nz::UnserializeShader(byteStream); + + if (shader.GetStage() != type) + throw std::runtime_error("incompatible shader stage"); + + SpirvWriter::Environment env; + + SpirvWriter writer; + writer.SetEnv(env); + + std::vector code = writer.Generate(shader); + + if (!m_shaderModule.Create(device, code.data(), code.size() * sizeof(UInt32))) + { + NazaraError("Failed to create shader module"); + return false; + } + + break; + } + + case ShaderLanguage::SpirV: + { + if (!m_shaderModule.Create(device, reinterpret_cast(source), sourceSize)) + { + NazaraError("Failed to create shader module"); + return false; + } + + break; + } + + default: + { + NazaraError("this language is not supported"); + return false; + } + } + return true; } } From ac7b523bc7e287ea187d6df587819bd83097f435 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Sun, 9 Aug 2020 18:38:58 +0200 Subject: [PATCH 084/105] OpenGLRenderer: Fix textures --- include/Nazara/OpenGLRenderer/Utils.hpp | 14 ++++++ include/Nazara/OpenGLRenderer/Utils.inl | 13 ++++++ .../Nazara/OpenGLRenderer/Wrapper/Texture.hpp | 4 +- .../Nazara/OpenGLRenderer/Wrapper/Texture.inl | 34 ++++++++------ src/Nazara/OpenGLRenderer/OpenGLTexture.cpp | 46 +++++-------------- 5 files changed, 60 insertions(+), 51 deletions(-) diff --git a/include/Nazara/OpenGLRenderer/Utils.hpp b/include/Nazara/OpenGLRenderer/Utils.hpp index 55f1d6cff..71c23106c 100644 --- a/include/Nazara/OpenGLRenderer/Utils.hpp +++ b/include/Nazara/OpenGLRenderer/Utils.hpp @@ -12,10 +12,24 @@ #include #include #include +#include #include namespace Nz { + struct GLTextureFormat + { + GLint internalFormat; + GLenum format; + GLenum type; + GLenum swizzleR; + GLenum swizzleG; + GLenum swizzleB; + GLenum swizzleA; + }; + + inline std::optional DescribeTextureFormat(PixelFormat pixelFormat); + inline GLenum ToOpenGL(BlendFunc blendFunc); inline GLenum ToOpenGL(FaceSide filter); inline GLenum ToOpenGL(SamplerFilter filter); diff --git a/include/Nazara/OpenGLRenderer/Utils.inl b/include/Nazara/OpenGLRenderer/Utils.inl index 6d64a18ec..621704a82 100644 --- a/include/Nazara/OpenGLRenderer/Utils.inl +++ b/include/Nazara/OpenGLRenderer/Utils.inl @@ -10,6 +10,19 @@ namespace Nz { + inline std::optional DescribeTextureFormat(PixelFormat pixelFormat) + { + switch (pixelFormat) + { + case PixelFormat_A8: return GLTextureFormat { GL_R8, GL_RED, GL_UNSIGNED_BYTE, GL_ZERO, GL_ZERO, GL_ZERO, GL_RED }; + case PixelFormat_RGB8: return GLTextureFormat { GL_SRGB8, GL_RGB, GL_UNSIGNED_BYTE, GL_RED, GL_GREEN, GL_BLUE, GL_ZERO }; + case PixelFormat_RGBA8: return GLTextureFormat { GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA }; + } + + NazaraError("Unhandled PixelFormat 0x" + String::Number(UnderlyingCast(pixelFormat), 16)); + return {}; + } + inline GLenum ToOpenGL(BlendFunc blendFunc) { switch (blendFunc) diff --git a/include/Nazara/OpenGLRenderer/Wrapper/Texture.hpp b/include/Nazara/OpenGLRenderer/Wrapper/Texture.hpp index 12b3e5c08..0b04a5e4a 100644 --- a/include/Nazara/OpenGLRenderer/Wrapper/Texture.hpp +++ b/include/Nazara/OpenGLRenderer/Wrapper/Texture.hpp @@ -29,7 +29,7 @@ namespace Nz::GL inline void SetParameterfv(GLenum pname, const GLfloat* param); inline void SetParameteriv(GLenum pname, const GLint* param); - inline void TexImage2D(GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLint border); + inline void TexImage2D(GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type); inline void TexImage2D(GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void* data); inline void TexSubImage2D(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void* data); @@ -39,6 +39,8 @@ namespace Nz::GL private: static inline GLuint CreateHelper(OpenGLDevice& device, const Context& context); static inline void DestroyHelper(OpenGLDevice& device, const Context& context, GLuint objectId); + + TextureTarget m_target; }; } diff --git a/include/Nazara/OpenGLRenderer/Wrapper/Texture.inl b/include/Nazara/OpenGLRenderer/Wrapper/Texture.inl index b63dcb0fe..b94bbe5d4 100644 --- a/include/Nazara/OpenGLRenderer/Wrapper/Texture.inl +++ b/include/Nazara/OpenGLRenderer/Wrapper/Texture.inl @@ -13,7 +13,8 @@ namespace Nz::GL assert(m_objectId); const Context& context = EnsureDeviceContext(); - context.glTexParameterf(m_objectId, pname, param); + context.BindTexture(m_target, m_objectId); + context.glTexParameterf(ToOpenGL(m_target), pname, param); } inline void Texture::SetParameteri(GLenum pname, GLint param) @@ -21,7 +22,8 @@ namespace Nz::GL assert(m_objectId); const Context& context = EnsureDeviceContext(); - context.glTexParameteri(m_objectId, pname, param); + context.BindTexture(m_target, m_objectId); + context.glTexParameteri(ToOpenGL(m_target), pname, param); } inline void Texture::SetParameterfv(GLenum pname, const GLfloat* param) @@ -29,7 +31,8 @@ namespace Nz::GL assert(m_objectId); const Context& context = EnsureDeviceContext(); - context.glTexParameterfv(m_objectId, pname, param); + context.BindTexture(m_target, m_objectId); + context.glTexParameterfv(ToOpenGL(m_target), pname, param); } inline void Texture::SetParameteriv(GLenum pname, const GLint* param) @@ -37,38 +40,39 @@ namespace Nz::GL assert(m_objectId); const Context& context = EnsureDeviceContext(); - context.glTexParameteriv(m_objectId, pname, param); + context.BindTexture(m_target, m_objectId); + context.glTexParameteriv(ToOpenGL(m_target), pname, param); } - inline void Texture::TexImage2D(GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLint border) + inline void Texture::TexImage2D(GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type) { - return TexImage2D(level, internalFormat, width, height, border, GL_RGB, GL_UNSIGNED_BYTE, nullptr); + return TexImage2D(level, internalFormat, width, height, border, format, type, nullptr); } inline void Texture::TexImage2D(GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void* data) { - const Context& context = EnsureDeviceContext(); - context.BindTexture(TextureTarget::Target2D, m_objectId); + m_target = TextureTarget::Target2D; - context.glTexImage2D(GL_TEXTURE_2D, level, internalFormat, width, height, border, format, type, data); + const Context& context = EnsureDeviceContext(); + context.BindTexture(m_target, m_objectId); + context.glTexImage2D(ToOpenGL(m_target), level, internalFormat, width, height, border, format, type, data); //< TODO: Handle errors } inline void Texture::TexSubImage2D(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void* data) { const Context& context = EnsureDeviceContext(); - context.BindTexture(TextureTarget::Target2D, m_objectId); - - context.glTexSubImage2D(GL_TEXTURE_2D, level, xoffset, yoffset, width, height, format, type, data); + context.BindTexture(m_target, m_objectId); + context.glTexSubImage2D(ToOpenGL(m_target), level, xoffset, yoffset, width, height, format, type, data); //< TODO: Handle errors } inline GLuint Texture::CreateHelper(OpenGLDevice& device, const Context& context) { - GLuint sampler = 0; - context.glGenTextures(1U, &sampler); + GLuint texture = 0; + context.glGenTextures(1U, &texture); - return sampler; + return texture; } inline void Texture::DestroyHelper(OpenGLDevice& device, const Context& context, GLuint objectId) diff --git a/src/Nazara/OpenGLRenderer/OpenGLTexture.cpp b/src/Nazara/OpenGLRenderer/OpenGLTexture.cpp index d89da0d49..8019a7d29 100644 --- a/src/Nazara/OpenGLRenderer/OpenGLTexture.cpp +++ b/src/Nazara/OpenGLRenderer/OpenGLTexture.cpp @@ -17,21 +17,9 @@ namespace Nz if (!m_texture.Create(device)) throw std::runtime_error("failed to create texture object"); - GLint internalFormat; - switch (params.pixelFormat) - { - case PixelFormat_RGB8: - { - internalFormat = GL_SRGB8; - break; - } - - case PixelFormat_RGBA8: - { - internalFormat = GL_SRGB8_ALPHA8; - break; - } - } + auto format = DescribeTextureFormat(params.pixelFormat); + if (!format) + throw std::runtime_error("unsupported texture format"); switch (params.type) { @@ -43,7 +31,7 @@ namespace Nz case ImageType_2D: for (unsigned int level = 0; level < m_params.mipmapLevel; ++level) - m_texture.TexImage2D(0, internalFormat, GetLevelSize(params.width, level), GetLevelSize(params.height, level), 0); + m_texture.TexImage2D(0, format->internalFormat, GetLevelSize(params.width, level), GetLevelSize(params.height, level), 0, format->format, format->type); break; case ImageType_2D_Array: @@ -60,6 +48,10 @@ namespace Nz } m_texture.SetParameteri(GL_TEXTURE_MAX_LEVEL, m_params.mipmapLevel); + m_texture.SetParameteri(GL_TEXTURE_SWIZZLE_R, format->swizzleR); + m_texture.SetParameteri(GL_TEXTURE_SWIZZLE_G, format->swizzleG); + m_texture.SetParameteri(GL_TEXTURE_SWIZZLE_B, format->swizzleB); + m_texture.SetParameteri(GL_TEXTURE_SWIZZLE_A, format->swizzleA); } PixelFormat OpenGLTexture::GetFormat() const @@ -84,25 +76,9 @@ namespace Nz bool OpenGLTexture::Update(const void* ptr) { - GLint format; - GLint type; - switch (m_params.pixelFormat) - { - case PixelFormat_RGB8: - { - format = GL_RGB; - type = GL_UNSIGNED_BYTE; - break; - } + auto format = DescribeTextureFormat(m_params.pixelFormat); + assert(format); - case PixelFormat_RGBA8: - { - format = GL_RGBA; - type = GL_UNSIGNED_BYTE; - break; - } - } - switch (m_params.type) { case ImageType_1D: @@ -112,7 +88,7 @@ namespace Nz break; case ImageType_2D: - m_texture.TexSubImage2D(0, 0, 0, m_params.width, m_params.height, format, type, ptr); + m_texture.TexSubImage2D(0, 0, 0, m_params.width, m_params.height, format->format, format->type, ptr); break; case ImageType_2D_Array: From d4f60c174ea601805a6ab2c604da5cb39d20a05d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Sun, 9 Aug 2020 18:40:59 +0200 Subject: [PATCH 085/105] OpenGLRenderer: Flip screenspace --- include/Nazara/Renderer/GlslWriter.hpp | 1 + include/Nazara/Renderer/ShaderAstCloner.hpp | 3 +- .../OpenGLRenderer/OpenGLShaderStage.cpp | 1 + src/Nazara/Renderer/GlslWriter.cpp | 37 ++++++++++++++++++- 4 files changed, 40 insertions(+), 2 deletions(-) diff --git a/include/Nazara/Renderer/GlslWriter.hpp b/include/Nazara/Renderer/GlslWriter.hpp index d7229f1d9..d423286db 100644 --- a/include/Nazara/Renderer/GlslWriter.hpp +++ b/include/Nazara/Renderer/GlslWriter.hpp @@ -41,6 +41,7 @@ namespace Nz unsigned int glMajorVersion = 3; unsigned int glMinorVersion = 0; bool glES = false; + bool flipYPosition = false; }; private: diff --git a/include/Nazara/Renderer/ShaderAstCloner.hpp b/include/Nazara/Renderer/ShaderAstCloner.hpp index ff1f9c5a4..c8b61b02c 100644 --- a/include/Nazara/Renderer/ShaderAstCloner.hpp +++ b/include/Nazara/Renderer/ShaderAstCloner.hpp @@ -28,7 +28,7 @@ namespace Nz ShaderAstCloner& operator=(const ShaderAstCloner&) = default; ShaderAstCloner& operator=(ShaderAstCloner&&) = default; - private: + protected: ShaderNodes::ExpressionPtr CloneExpression(const ShaderNodes::ExpressionPtr& expr); ShaderNodes::StatementPtr CloneStatement(const ShaderNodes::StatementPtr& statement); ShaderNodes::VariablePtr CloneVariable(const ShaderNodes::VariablePtr& statement); @@ -62,6 +62,7 @@ namespace Nz ShaderNodes::StatementPtr PopStatement(); ShaderNodes::VariablePtr PopVariable(); + private: std::vector m_expressionStack; std::vector m_statementStack; std::vector m_variableStack; diff --git a/src/Nazara/OpenGLRenderer/OpenGLShaderStage.cpp b/src/Nazara/OpenGLRenderer/OpenGLShaderStage.cpp index 07f6de975..7f6e92a34 100644 --- a/src/Nazara/OpenGLRenderer/OpenGLShaderStage.cpp +++ b/src/Nazara/OpenGLRenderer/OpenGLShaderStage.cpp @@ -45,6 +45,7 @@ namespace Nz { return context.IsExtensionSupported(std::string(ext)); }; + env.flipYPosition = true; GlslWriter writer; writer.SetEnv(env); diff --git a/src/Nazara/Renderer/GlslWriter.cpp b/src/Nazara/Renderer/GlslWriter.cpp index 3d651a84f..f851a3aa0 100644 --- a/src/Nazara/Renderer/GlslWriter.cpp +++ b/src/Nazara/Renderer/GlslWriter.cpp @@ -5,12 +5,44 @@ #include #include #include +#include +#include #include #include #include namespace Nz { + namespace + { + struct AstAdapter : ShaderAstCloner + { + void Visit(ShaderNodes::AssignOp& node) override + { + if (!flipYPosition) + return ShaderAstCloner::Visit(node); + + if (node.left->GetType() != ShaderNodes::NodeType::Identifier) + return ShaderAstCloner::Visit(node); + + const auto& identifier = static_cast(*node.left); + if (identifier.var->GetType() != ShaderNodes::VariableType::BuiltinVariable) + return ShaderAstCloner::Visit(node); + + const auto& builtinVar = static_cast(*identifier.var); + if (builtinVar.entry != ShaderNodes::BuiltinEntry::VertexPosition) + return ShaderAstCloner::Visit(node); + + auto fixYConstant = ShaderBuilder::Constant(Nz::Vector4f(1.f, -1.f, 1.f, 1.f)); + auto mulFix = ShaderBuilder::Multiply(CloneExpression(node.right), fixYConstant); + + PushExpression(ShaderNodes::AssignOp::Build(node.op, CloneExpression(node.left), mulFix)); + } + + bool flipYPosition = false; + }; + } + GlslWriter::GlslWriter() : m_currentState(nullptr) { @@ -237,7 +269,10 @@ namespace Nz EnterScope(); { - Visit(func.statement); + AstAdapter adapter; + adapter.flipYPosition = m_environment.flipYPosition; + + Visit(adapter.Clone(func.statement)); } LeaveScope(); } From d9b34b4ba8d478c289f292a6090b02be5f3a6dbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Sun, 9 Aug 2020 18:41:28 +0200 Subject: [PATCH 086/105] OpenGLRenderer: Handle GL_DEBUG_SEVERITY_NOTIFICATION --- src/Nazara/OpenGLRenderer/Wrapper/Context.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Nazara/OpenGLRenderer/Wrapper/Context.cpp b/src/Nazara/OpenGLRenderer/Wrapper/Context.cpp index 2cd045504..aeb2fe934 100644 --- a/src/Nazara/OpenGLRenderer/Wrapper/Context.cpp +++ b/src/Nazara/OpenGLRenderer/Wrapper/Context.cpp @@ -633,6 +633,10 @@ namespace Nz::GL ss << "Low"; break; + case GL_DEBUG_SEVERITY_NOTIFICATION: + ss << "Notification"; + break; + default: ss << "Unknown"; break; From 777121dbcedf6616ec71bfd6925d9f94ae8fcf69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Sun, 9 Aug 2020 18:42:01 +0200 Subject: [PATCH 087/105] Remove SPIRV handling in demo --- examples/VulkanTest/main.cpp | 52 +----------------------------------- 1 file changed, 1 insertion(+), 51 deletions(-) diff --git a/examples/VulkanTest/main.cpp b/examples/VulkanTest/main.cpp index 706cf047c..cd7132e4a 100644 --- a/examples/VulkanTest/main.cpp +++ b/examples/VulkanTest/main.cpp @@ -5,42 +5,8 @@ #include #include -#define SPIRV 0 - int main() -{ - /*{ - Nz::File file("frag.shader"); - if (!file.Open(Nz::OpenMode_ReadOnly)) - return __LINE__; - - std::size_t length = static_cast(file.GetSize()); - - std::vector source(length); - if (file.Read(&source[0], length) != length) - { - NazaraError("Failed to read program file"); - return {}; - } - - - - Nz::SpirvWriter writer; - - Nz::ByteStream byteStream(source.data(), source.size()); - auto shader = Nz::UnserializeShader(byteStream); - - std::vector result = writer.Generate(shader); - - Nz::File target("test.spirv"); - if (!target.Open(Nz::OpenMode_WriteOnly | Nz::OpenMode_Truncate)) - return __LINE__; - - target.Write(result.data(), result.size() * sizeof(Nz::UInt32)); - - return 0; - } - */ +{ Nz::Initializer loader; if (!loader) { @@ -63,21 +29,6 @@ int main() std::shared_ptr device = window.GetRenderDevice(); -#if SPIRV - auto fragmentShader = device->InstantiateShaderStage(Nz::ShaderStageType::Fragment, Nz::ShaderLanguage::SpirV, "resources/shaders/triangle.frag.spv"); - if (!fragmentShader) - { - std::cout << "Failed to instantiate fragment shader" << std::endl; - return __LINE__; - } - - auto vertexShader = device->InstantiateShaderStage(Nz::ShaderStageType::Vertex, Nz::ShaderLanguage::SpirV, "resources/shaders/triangle.vert.spv"); - if (!vertexShader) - { - std::cout << "Failed to instantiate fragment shader" << std::endl; - return __LINE__; - } -#else auto fragmentShader = device->InstantiateShaderStage(Nz::ShaderStageType::Fragment, Nz::ShaderLanguage::NazaraBinary, "frag.shader"); if (!fragmentShader) { @@ -91,7 +42,6 @@ int main() std::cout << "Failed to instantiate fragment shader" << std::endl; return __LINE__; } -#endif Nz::MeshRef drfreak = Nz::Mesh::LoadFromFile("resources/Spaceship/spaceship.obj", meshParams); From 0313f2d0a65c4e1af34be92eae14079b3dc3c5fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Sun, 9 Aug 2020 18:43:44 +0200 Subject: [PATCH 088/105] Enable GL_DEBUG_OUTPUT --- src/Nazara/OpenGLRenderer/Wrapper/Context.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Nazara/OpenGLRenderer/Wrapper/Context.cpp b/src/Nazara/OpenGLRenderer/Wrapper/Context.cpp index aeb2fe934..81fc4e0af 100644 --- a/src/Nazara/OpenGLRenderer/Wrapper/Context.cpp +++ b/src/Nazara/OpenGLRenderer/Wrapper/Context.cpp @@ -247,6 +247,11 @@ namespace Nz::GL // Set debug callback (if supported) if (glDebugMessageCallback) { + glEnable(GL_DEBUG_OUTPUT); +#ifdef NAZARA_DEBUG + glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); +#endif + glDebugMessageCallback([](GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void* userParam) { const Context* context = static_cast(userParam); From 837a6585a187006ae28167df269cd9fc26a07b78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Tue, 11 Aug 2020 00:00:36 +0200 Subject: [PATCH 089/105] Split shader generation to a new module --- build/scripts/modules/renderer.lua | 16 +---- build/scripts/modules/shader.lua | 6 ++ build/scripts/tools/shadernodes.lua | 2 +- examples/VulkanTest/main.cpp | 2 - include/Nazara/OpenGLRenderer/Config.hpp | 2 +- include/Nazara/OpenGLRenderer/ConfigCheck.hpp | 8 +-- include/Nazara/OpenGLRenderer/Debug.hpp | 2 +- include/Nazara/OpenGLRenderer/DebugOff.hpp | 2 +- .../Nazara/OpenGLRenderer/DummySurface.hpp | 2 +- .../Nazara/OpenGLRenderer/OpenGLBuffer.hpp | 2 +- .../Nazara/OpenGLRenderer/OpenGLDevice.hpp | 2 +- .../OpenGLRenderer/OpenGLRenderWindow.hpp | 2 +- .../OpenGLRenderer/OpenGLShaderStage.hpp | 2 +- .../Nazara/OpenGLRenderer/OpenGLVaoCache.hpp | 2 +- include/Nazara/Renderer.hpp | 15 ---- include/Nazara/Renderer/Enums.hpp | 18 ----- .../Nazara/Renderer/RenderPipelineLayout.hpp | 1 + include/Nazara/Renderer/ShaderAstCloner.inl | 12 ---- .../Renderer/ShaderAstRecursiveVisitor.inl | 12 ---- include/Nazara/Shader.hpp | 50 +++++++++++++ include/Nazara/Shader/Config.hpp | 53 ++++++++++++++ include/Nazara/Shader/ConfigCheck.hpp | 22 ++++++ include/Nazara/Shader/Debug.hpp | 8 +++ include/Nazara/Shader/DebugOff.hpp | 9 +++ .../{Renderer => Shader}/GlslWriter.hpp | 14 ++-- .../{Renderer => Shader}/GlslWriter.inl | 8 +-- include/Nazara/Shader/Shader.hpp | 33 +++++++++ .../Nazara/{Renderer => Shader}/ShaderAst.hpp | 10 +-- .../Nazara/{Renderer => Shader}/ShaderAst.inl | 8 +-- .../{Renderer => Shader}/ShaderAstCloner.hpp | 14 ++-- include/Nazara/Shader/ShaderAstCloner.inl | 12 ++++ .../ShaderAstRecursiveVisitor.hpp | 10 +-- .../Shader/ShaderAstRecursiveVisitor.inl | 12 ++++ .../ShaderAstSerializer.hpp | 22 +++--- .../ShaderAstSerializer.inl | 8 +-- .../ShaderAstValidator.hpp | 16 ++--- .../ShaderAstValidator.inl | 8 +-- .../{Renderer => Shader}/ShaderAstVisitor.hpp | 10 +-- .../{Renderer => Shader}/ShaderBuilder.hpp | 6 +- .../{Renderer => Shader}/ShaderBuilder.inl | 8 +-- .../{Renderer => Shader}/ShaderEnums.hpp | 2 +- .../ShaderExpressionType.hpp | 4 +- .../{Renderer => Shader}/ShaderNodes.hpp | 46 ++++++------ .../{Renderer => Shader}/ShaderNodes.inl | 8 +-- .../{Renderer => Shader}/ShaderVarVisitor.hpp | 8 +-- .../{Renderer => Shader}/ShaderVariables.hpp | 24 +++---- .../{Renderer => Shader}/ShaderVariables.inl | 8 +-- .../{Renderer => Shader}/ShaderWriter.hpp | 6 +- .../{Renderer => Shader}/SpirvWriter.hpp | 16 ++--- .../{Renderer => Shader}/SpirvWriter.inl | 8 +-- include/Nazara/Utility/Enums.hpp | 18 +++++ src/Nazara/Renderer/ShaderWriter.cpp | 11 --- src/Nazara/Shader/Debug/NewOverload.cpp | 31 ++++++++ .../{Renderer => Shader}/GlslWriter.cpp | 14 ++-- src/Nazara/Shader/Shader.cpp | 70 +++++++++++++++++++ src/Nazara/{Renderer => Shader}/ShaderAst.cpp | 6 +- .../{Renderer => Shader}/ShaderAstCloner.cpp | 8 +-- .../ShaderAstRecursiveVisitor.cpp | 8 +-- .../ShaderAstSerializer.cpp | 10 +-- .../ShaderAstValidator.cpp | 12 ++-- .../{Renderer => Shader}/ShaderAstVisitor.cpp | 8 +-- .../{Renderer => Shader}/ShaderNodes.cpp | 16 ++--- .../{Renderer => Shader}/ShaderVarVisitor.cpp | 8 +-- .../{Renderer => Shader}/ShaderVariables.cpp | 8 +-- src/Nazara/Shader/ShaderWriter.cpp | 11 +++ .../{Renderer => Shader}/SpirvWriter.cpp | 12 ++-- src/ShaderNode/DataModels/BufferField.cpp | 2 +- src/ShaderNode/DataModels/Cast.inl | 2 +- src/ShaderNode/DataModels/FloatValue.cpp | 2 +- src/ShaderNode/DataModels/InputValue.cpp | 2 +- src/ShaderNode/DataModels/Mat4BinOp.inl | 2 +- src/ShaderNode/DataModels/Mat4VecMul.cpp | 2 +- src/ShaderNode/DataModels/OutputValue.cpp | 2 +- .../DataModels/PositionOutputValue.cpp | 2 +- src/ShaderNode/DataModels/SampleTexture.cpp | 2 +- src/ShaderNode/DataModels/ShaderNode.hpp | 2 +- src/ShaderNode/DataModels/TextureValue.cpp | 2 +- src/ShaderNode/DataModels/VecBinOp.inl | 2 +- src/ShaderNode/DataModels/VecDot.cpp | 2 +- src/ShaderNode/DataModels/VecFloatMul.cpp | 2 +- src/ShaderNode/DataModels/VecValue.inl | 2 +- src/ShaderNode/DataTypes/Matrix4Data.hpp | 2 +- src/ShaderNode/DataTypes/TextureData.hpp | 2 +- src/ShaderNode/DataTypes/VecData.hpp | 2 +- src/ShaderNode/ShaderGraph.hpp | 4 +- src/ShaderNode/Widgets/MainWindow.cpp | 4 +- 86 files changed, 564 insertions(+), 312 deletions(-) create mode 100644 build/scripts/modules/shader.lua delete mode 100644 include/Nazara/Renderer/ShaderAstCloner.inl delete mode 100644 include/Nazara/Renderer/ShaderAstRecursiveVisitor.inl create mode 100644 include/Nazara/Shader.hpp create mode 100644 include/Nazara/Shader/Config.hpp create mode 100644 include/Nazara/Shader/ConfigCheck.hpp create mode 100644 include/Nazara/Shader/Debug.hpp create mode 100644 include/Nazara/Shader/DebugOff.hpp rename include/Nazara/{Renderer => Shader}/GlslWriter.hpp (89%) rename include/Nazara/{Renderer => Shader}/GlslWriter.inl (93%) create mode 100644 include/Nazara/Shader/Shader.hpp rename include/Nazara/{Renderer => Shader}/ShaderAst.hpp (94%) rename include/Nazara/{Renderer => Shader}/ShaderAst.inl (91%) rename include/Nazara/{Renderer => Shader}/ShaderAstCloner.hpp (86%) create mode 100644 include/Nazara/Shader/ShaderAstCloner.inl rename include/Nazara/{Renderer => Shader}/ShaderAstRecursiveVisitor.hpp (80%) create mode 100644 include/Nazara/Shader/ShaderAstRecursiveVisitor.inl rename include/Nazara/{Renderer => Shader}/ShaderAstSerializer.hpp (87%) rename include/Nazara/{Renderer => Shader}/ShaderAstSerializer.inl (92%) rename include/Nazara/{Renderer => Shader}/ShaderAstValidator.hpp (81%) rename include/Nazara/{Renderer => Shader}/ShaderAstValidator.inl (54%) rename include/Nazara/{Renderer => Shader}/ShaderAstVisitor.hpp (86%) rename include/Nazara/{Renderer => Shader}/ShaderBuilder.hpp (94%) rename include/Nazara/{Renderer => Shader}/ShaderBuilder.inl (89%) rename include/Nazara/{Renderer => Shader}/ShaderEnums.hpp (96%) rename include/Nazara/{Renderer => Shader}/ShaderExpressionType.hpp (80%) rename include/Nazara/{Renderer => Shader}/ShaderNodes.hpp (84%) rename include/Nazara/{Renderer => Shader}/ShaderNodes.inl (97%) rename include/Nazara/{Renderer => Shader}/ShaderVarVisitor.hpp (82%) rename include/Nazara/{Renderer => Shader}/ShaderVariables.hpp (78%) rename include/Nazara/{Renderer => Shader}/ShaderVariables.inl (89%) rename include/Nazara/{Renderer => Shader}/ShaderWriter.hpp (79%) rename include/Nazara/{Renderer => Shader}/SpirvWriter.hpp (90%) rename include/Nazara/{Renderer => Shader}/SpirvWriter.inl (93%) delete mode 100644 src/Nazara/Renderer/ShaderWriter.cpp create mode 100644 src/Nazara/Shader/Debug/NewOverload.cpp rename src/Nazara/{Renderer => Shader}/GlslWriter.cpp (97%) create mode 100644 src/Nazara/Shader/Shader.cpp rename src/Nazara/{Renderer => Shader}/ShaderAst.cpp (92%) rename src/Nazara/{Renderer => Shader}/ShaderAstCloner.cpp (97%) rename src/Nazara/{Renderer => Shader}/ShaderAstRecursiveVisitor.cpp (90%) rename src/Nazara/{Renderer => Shader}/ShaderAstSerializer.cpp (98%) rename src/Nazara/{Renderer => Shader}/ShaderAstValidator.cpp (97%) rename src/Nazara/{Renderer => Shader}/ShaderAstVisitor.cpp (73%) rename src/Nazara/{Renderer => Shader}/ShaderNodes.cpp (93%) rename src/Nazara/{Renderer => Shader}/ShaderVarVisitor.cpp (56%) rename src/Nazara/{Renderer => Shader}/ShaderVariables.cpp (86%) create mode 100644 src/Nazara/Shader/ShaderWriter.cpp rename src/Nazara/{Renderer => Shader}/SpirvWriter.cpp (99%) diff --git a/build/scripts/modules/renderer.lua b/build/scripts/modules/renderer.lua index df10e2910..2e3a6619a 100644 --- a/build/scripts/modules/renderer.lua +++ b/build/scripts/modules/renderer.lua @@ -2,12 +2,9 @@ MODULE.Name = "Renderer" MODULE.ClientOnly = true -MODULE.Defines = { - "NAZARA_RENDERER_OPENGL" -} - MODULE.Libraries = { "NazaraCore", + "NazaraShader", "NazaraUtility", "NazaraPlatform" } @@ -22,14 +19,3 @@ MODULE.OsFiles.Posix = { "../src/Nazara/Renderer/GLX/**.cpp" } -MODULE.OsLibraries.Windows = { - "gdi32", - "opengl32", - "winmm" -} - -MODULE.OsLibraries.Posix = { - "GL", - "X11" -} - diff --git a/build/scripts/modules/shader.lua b/build/scripts/modules/shader.lua new file mode 100644 index 000000000..a0a22a663 --- /dev/null +++ b/build/scripts/modules/shader.lua @@ -0,0 +1,6 @@ +MODULE.Name = "Shader" + +MODULE.Libraries = { + "NazaraCore", + "NazaraUtility" +} diff --git a/build/scripts/tools/shadernodes.lua b/build/scripts/tools/shadernodes.lua index 3abeaa658..bcf9a1593 100644 --- a/build/scripts/tools/shadernodes.lua +++ b/build/scripts/tools/shadernodes.lua @@ -28,7 +28,7 @@ TOOL.Files = { TOOL.Libraries = { "NazaraCore", - "NazaraRenderer", + "NazaraShader", "NazaraUtility", "Qt5Cored", "Qt5Guid", diff --git a/examples/VulkanTest/main.cpp b/examples/VulkanTest/main.cpp index cd7132e4a..54c34762c 100644 --- a/examples/VulkanTest/main.cpp +++ b/examples/VulkanTest/main.cpp @@ -1,7 +1,5 @@ #include #include -#include -#include #include #include diff --git a/include/Nazara/OpenGLRenderer/Config.hpp b/include/Nazara/OpenGLRenderer/Config.hpp index 1ffd4999f..3cc4856f1 100644 --- a/include/Nazara/OpenGLRenderer/Config.hpp +++ b/include/Nazara/OpenGLRenderer/Config.hpp @@ -50,4 +50,4 @@ #define NAZARA_OPENGLRENDERER_API #endif -#endif // NAZARA_CONFIG_MODULENAME_HPP +#endif // NAZARA_CONFIG_OPENGLRENDERER_HPP diff --git a/include/Nazara/OpenGLRenderer/ConfigCheck.hpp b/include/Nazara/OpenGLRenderer/ConfigCheck.hpp index 793b04818..9f59a0119 100644 --- a/include/Nazara/OpenGLRenderer/ConfigCheck.hpp +++ b/include/Nazara/OpenGLRenderer/ConfigCheck.hpp @@ -4,8 +4,8 @@ #pragma once -#ifndef NAZARA_CONFIG_CHECK_OPENGLE_HPP -#define NAZARA_CONFIG_CHECK_OPENGLE_HPP +#ifndef NAZARA_CONFIG_CHECK_OPENGLRENDERER_HPP +#define NAZARA_CONFIG_CHECK_OPENGLRENDERER_HPP /// Ce fichier sert à vérifier la valeur des constantes du fichier Config.hpp @@ -15,8 +15,8 @@ // On force la valeur de MANAGE_MEMORY en mode debug #if defined(NAZARA_DEBUG) && !NAZARA_OPENGLRENDERER_MANAGE_MEMORY - #undef NAZARA_MODULENAME_MANAGE_MEMORY - #define NAZARA_MODULENAME_MANAGE_MEMORY 0 + #undef NAZARA_OPENGLRENDERER_MANAGE_MEMORY + #define NAZARA_OPENGLRENDERER_MANAGE_MEMORY 0 #endif #endif // NAZARA_CONFIG_CHECK_OPENGLRENDERER_HPP diff --git a/include/Nazara/OpenGLRenderer/Debug.hpp b/include/Nazara/OpenGLRenderer/Debug.hpp index 36e55c909..181fe26d0 100644 --- a/include/Nazara/OpenGLRenderer/Debug.hpp +++ b/include/Nazara/OpenGLRenderer/Debug.hpp @@ -3,6 +3,6 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include -#if NAZARA_MODULENAME_MANAGE_MEMORY +#if NAZARA_OPENGLRENDERER_MANAGE_MEMORY #include #endif diff --git a/include/Nazara/OpenGLRenderer/DebugOff.hpp b/include/Nazara/OpenGLRenderer/DebugOff.hpp index c8ee4e470..600f6f117 100644 --- a/include/Nazara/OpenGLRenderer/DebugOff.hpp +++ b/include/Nazara/OpenGLRenderer/DebugOff.hpp @@ -3,7 +3,7 @@ // For conditions of distribution and use, see copyright notice in Config.hpp // On suppose que Debug.hpp a déjà été inclus, tout comme Config.hpp -#if NAZARA_MODULENAME_MANAGE_MEMORY +#if NAZARA_OPENGLRENDERER_MANAGE_MEMORY #undef delete #undef new #endif diff --git a/include/Nazara/OpenGLRenderer/DummySurface.hpp b/include/Nazara/OpenGLRenderer/DummySurface.hpp index 10246a9d1..51a60783f 100644 --- a/include/Nazara/OpenGLRenderer/DummySurface.hpp +++ b/include/Nazara/OpenGLRenderer/DummySurface.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2015 Jérôme Leclercq +// Copyright (C) 2020 Jérôme Leclercq // This file is part of the "Nazara Engine - OpenGL Renderer" // For conditions of distribution and use, see copyright notice in Config.hpp diff --git a/include/Nazara/OpenGLRenderer/OpenGLBuffer.hpp b/include/Nazara/OpenGLRenderer/OpenGLBuffer.hpp index c00ad0710..17688b5d9 100644 --- a/include/Nazara/OpenGLRenderer/OpenGLBuffer.hpp +++ b/include/Nazara/OpenGLRenderer/OpenGLBuffer.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2015 Jérôme Leclercq +// Copyright (C) 2020 Jérôme Leclercq // This file is part of the "Nazara Engine - OpenGL Renderer" // For conditions of distribution and use, see copyright notice in Config.hpp diff --git a/include/Nazara/OpenGLRenderer/OpenGLDevice.hpp b/include/Nazara/OpenGLRenderer/OpenGLDevice.hpp index 2bbb95c33..9d9b6adef 100644 --- a/include/Nazara/OpenGLRenderer/OpenGLDevice.hpp +++ b/include/Nazara/OpenGLRenderer/OpenGLDevice.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2015 Jérôme Leclercq +// Copyright (C) 2020 Jérôme Leclercq // This file is part of the "Nazara Engine - OpenGL Renderer" // For conditions of distribution and use, see copyright notice in Config.hpp diff --git a/include/Nazara/OpenGLRenderer/OpenGLRenderWindow.hpp b/include/Nazara/OpenGLRenderer/OpenGLRenderWindow.hpp index 9fdb69561..ceb7b2489 100644 --- a/include/Nazara/OpenGLRenderer/OpenGLRenderWindow.hpp +++ b/include/Nazara/OpenGLRenderer/OpenGLRenderWindow.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2015 Jérôme Leclercq +// Copyright (C) 2020 Jérôme Leclercq // This file is part of the "Nazara Engine - OpenGL Renderer" // For conditions of distribution and use, see copyright notice in Config.hpp diff --git a/include/Nazara/OpenGLRenderer/OpenGLShaderStage.hpp b/include/Nazara/OpenGLRenderer/OpenGLShaderStage.hpp index f72f282ad..8768befb7 100644 --- a/include/Nazara/OpenGLRenderer/OpenGLShaderStage.hpp +++ b/include/Nazara/OpenGLRenderer/OpenGLShaderStage.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2015 Jérôme Leclercq +// Copyright (C) 2020 Jérôme Leclercq // This file is part of the "Nazara Engine - OpenGL Renderer" // For conditions of distribution and use, see copyright notice in Config.hpp diff --git a/include/Nazara/OpenGLRenderer/OpenGLVaoCache.hpp b/include/Nazara/OpenGLRenderer/OpenGLVaoCache.hpp index 0a9bc14d1..8f7cca48d 100644 --- a/include/Nazara/OpenGLRenderer/OpenGLVaoCache.hpp +++ b/include/Nazara/OpenGLRenderer/OpenGLVaoCache.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2015 Jérôme Leclercq +// Copyright (C) 2020 Jérôme Leclercq // This file is part of the "Nazara Engine - OpenGL Renderer" // For conditions of distribution and use, see copyright notice in Config.hpp diff --git a/include/Nazara/Renderer.hpp b/include/Nazara/Renderer.hpp index ff9193d3f..69153a0d4 100644 --- a/include/Nazara/Renderer.hpp +++ b/include/Nazara/Renderer.hpp @@ -36,7 +36,6 @@ #include #include #include -#include #include #include #include @@ -52,22 +51,8 @@ #include #include #include -#include -#include -#include -#include -#include -#include #include -#include -#include -#include -#include #include -#include -#include -#include -#include #include #include #include diff --git a/include/Nazara/Renderer/Enums.hpp b/include/Nazara/Renderer/Enums.hpp index 05daee7a5..0b44ae629 100644 --- a/include/Nazara/Renderer/Enums.hpp +++ b/include/Nazara/Renderer/Enums.hpp @@ -53,24 +53,6 @@ namespace Nz SpirV }; - enum class ShaderStageType - { - Fragment, - Vertex, - - Max = Vertex - }; - - template<> - struct EnumAsFlags - { - static constexpr ShaderStageType max = ShaderStageType::Max; - }; - - using ShaderStageTypeFlags = Flags; - - constexpr ShaderStageTypeFlags ShaderStageType_All = ShaderStageType::Fragment | ShaderStageType::Vertex; - enum class QueueType { Compute, diff --git a/include/Nazara/Renderer/RenderPipelineLayout.hpp b/include/Nazara/Renderer/RenderPipelineLayout.hpp index c15787c35..38c1b6ef3 100644 --- a/include/Nazara/Renderer/RenderPipelineLayout.hpp +++ b/include/Nazara/Renderer/RenderPipelineLayout.hpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include diff --git a/include/Nazara/Renderer/ShaderAstCloner.inl b/include/Nazara/Renderer/ShaderAstCloner.inl deleted file mode 100644 index 1acdd41ab..000000000 --- a/include/Nazara/Renderer/ShaderAstCloner.inl +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (C) 2020 Jérôme Leclercq -// This file is part of the "Nazara Engine - Renderer module" -// For conditions of distribution and use, see copyright notice in Config.hpp - -#include -#include - -namespace Nz -{ -} - -#include diff --git a/include/Nazara/Renderer/ShaderAstRecursiveVisitor.inl b/include/Nazara/Renderer/ShaderAstRecursiveVisitor.inl deleted file mode 100644 index 3b2c6be62..000000000 --- a/include/Nazara/Renderer/ShaderAstRecursiveVisitor.inl +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (C) 2020 Jérôme Leclercq -// This file is part of the "Nazara Engine - Renderer module" -// For conditions of distribution and use, see copyright notice in Config.hpp - -#include -#include - -namespace Nz -{ -} - -#include diff --git a/include/Nazara/Shader.hpp b/include/Nazara/Shader.hpp new file mode 100644 index 000000000..cd9e02507 --- /dev/null +++ b/include/Nazara/Shader.hpp @@ -0,0 +1,50 @@ +// This file was automatically generated + +/* + Nazara Engine - Module name + + Copyright (C) 2020 Jérôme "Lynix" Leclercq (lynix680@gmail.com) + + Permission is hereby granted, free of charge, to any person obtaining a copy of + this software and associated documentation files (the "Software"), to deal in + the Software without restriction, including without limitation the rights to + use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is furnished to do + so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ + +#pragma once + +#ifndef NAZARA_GLOBAL_SHADER_HPP +#define NAZARA_GLOBAL_SHADER_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#endif // NAZARA_GLOBAL_SHADER_HPP diff --git a/include/Nazara/Shader/Config.hpp b/include/Nazara/Shader/Config.hpp new file mode 100644 index 000000000..e357579aa --- /dev/null +++ b/include/Nazara/Shader/Config.hpp @@ -0,0 +1,53 @@ +/* + Nazara Engine - Shader generator + + Copyright (C) 2020 Jérôme "Lynix" Leclercq (lynix680@gmail.com) + + Permission is hereby granted, free of charge, to any person obtaining a copy of + this software and associated documentation files (the "Software"), to deal in + the Software without restriction, including without limitation the rights to + use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is furnished to do + so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ + +#pragma once + +#ifndef NAZARA_CONFIG_SHADER_HPP +#define NAZARA_CONFIG_SHADER_HPP + +/// Each modification of a parameter needs a recompilation of the module + +// Use the MemoryManager to manage dynamic allocations (can detect memory leak but allocations/frees are slower) +#define NAZARA_SHADER_MANAGE_MEMORY 0 + +// Activate the security tests based on the code (Advised for development) +#define NAZARA_SHADER_SAFE 1 + +/// Each modification of a parameter following implies a modification (often minor) of the code + +/// Checking the values and types of certain constants +#include + +#if !defined(NAZARA_STATIC) + #ifdef NAZARA_SHADER_BUILD + #define NAZARA_SHADER_API NAZARA_EXPORT + #else + #define NAZARA_SHADER_API NAZARA_IMPORT + #endif +#else + #define NAZARA_SHADER_API +#endif + +#endif // NAZARA_CONFIG_SHADER_HPP diff --git a/include/Nazara/Shader/ConfigCheck.hpp b/include/Nazara/Shader/ConfigCheck.hpp new file mode 100644 index 000000000..48252e452 --- /dev/null +++ b/include/Nazara/Shader/ConfigCheck.hpp @@ -0,0 +1,22 @@ +// Copyright (C) YEAR AUTHORS +// 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_CONFIG_CHECK_SHADER_HPP +#define NAZARA_CONFIG_CHECK_SHADER_HPP + +/// This file is used to check the constant values defined in Config.hpp + +#include +#define CheckType(name, type, err) static_assert(std::is_ ##type ::value, #type err) +#define CheckTypeAndVal(name, type, op, val, err) static_assert(std::is_ ##type ::value && name op val, #type err) + +// We force the value of MANAGE_MEMORY in debug +#if defined(NAZARA_DEBUG) && !NAZARA_SHADER_MANAGE_MEMORY + #undef NAZARA_SHADER_MANAGE_MEMORY + #define NAZARA_SHADER_MANAGE_MEMORY 0 +#endif + +#endif // NAZARA_CONFIG_CHECK_SHADER_HPP diff --git a/include/Nazara/Shader/Debug.hpp b/include/Nazara/Shader/Debug.hpp new file mode 100644 index 000000000..32333d44d --- /dev/null +++ b/include/Nazara/Shader/Debug.hpp @@ -0,0 +1,8 @@ +// Copyright (C) YEAR AUTHORS +// This file is part of the "Nazara Engine - Shader generator" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#if NAZARA_SHADER_MANAGE_MEMORY + #include +#endif diff --git a/include/Nazara/Shader/DebugOff.hpp b/include/Nazara/Shader/DebugOff.hpp new file mode 100644 index 000000000..bca09b27c --- /dev/null +++ b/include/Nazara/Shader/DebugOff.hpp @@ -0,0 +1,9 @@ +// Copyright (C) YEAR AUTHORS +// This file is part of the "Nazara Engine - Shader generator" +// For conditions of distribution and use, see copyright notice in Config.hpp + +// We suppose that Debug.hpp is already included, same goes for Config.hpp +#if NAZARA_SHADER_MANAGE_MEMORY + #undef delete + #undef new +#endif diff --git a/include/Nazara/Renderer/GlslWriter.hpp b/include/Nazara/Shader/GlslWriter.hpp similarity index 89% rename from include/Nazara/Renderer/GlslWriter.hpp rename to include/Nazara/Shader/GlslWriter.hpp index d423286db..3212d81cd 100644 --- a/include/Nazara/Renderer/GlslWriter.hpp +++ b/include/Nazara/Shader/GlslWriter.hpp @@ -8,11 +8,11 @@ #define NAZARA_GLSLWRITER_HPP #include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include #include #include @@ -20,7 +20,7 @@ namespace Nz { - class NAZARA_RENDERER_API GlslWriter : public ShaderWriter, public ShaderVarVisitor, public ShaderAstVisitor + class NAZARA_SHADER_API GlslWriter : public ShaderWriter, public ShaderVarVisitor, public ShaderAstVisitor { public: struct Environment; @@ -104,6 +104,6 @@ namespace Nz }; } -#include +#include #endif // NAZARA_GLSLWRITER_HPP diff --git a/include/Nazara/Renderer/GlslWriter.inl b/include/Nazara/Shader/GlslWriter.inl similarity index 93% rename from include/Nazara/Renderer/GlslWriter.inl rename to include/Nazara/Shader/GlslWriter.inl index e543f870f..76972eec1 100644 --- a/include/Nazara/Renderer/GlslWriter.inl +++ b/include/Nazara/Shader/GlslWriter.inl @@ -1,10 +1,10 @@ // Copyright (C) 2020 Jérôme Leclercq -// This file is part of the "Nazara Engine - Renderer module" +// 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 { @@ -129,4 +129,4 @@ namespace Nz } } -#include +#include diff --git a/include/Nazara/Shader/Shader.hpp b/include/Nazara/Shader/Shader.hpp new file mode 100644 index 000000000..e40bd1212 --- /dev/null +++ b/include/Nazara/Shader/Shader.hpp @@ -0,0 +1,33 @@ +// Copyright (C) YEAR AUTHORS +// This file is part of the "Nazara Engine - Module name" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_SHADER_HPP +#define NAZARA_SHADER_HPP + +#include +#include +#include + +namespace Nz +{ + class NAZARA_SHADER_API Shader + { + public: + Shader() = delete; + ~Shader() = delete; + + static bool Initialize(); + + static bool IsInitialized(); + + static void Uninitialize(); + + private: + static unsigned int s_moduleReferenceCounter; + }; +} + +#endif // NAZARA_SHADER_HPP diff --git a/include/Nazara/Renderer/ShaderAst.hpp b/include/Nazara/Shader/ShaderAst.hpp similarity index 94% rename from include/Nazara/Renderer/ShaderAst.hpp rename to include/Nazara/Shader/ShaderAst.hpp index 51117c1d7..11b39d5e9 100644 --- a/include/Nazara/Renderer/ShaderAst.hpp +++ b/include/Nazara/Shader/ShaderAst.hpp @@ -8,16 +8,16 @@ #define NAZARA_SHADER_AST_HPP #include -#include -#include -#include +#include +#include +#include #include #include #include namespace Nz { - class NAZARA_RENDERER_API ShaderAst + class NAZARA_SHADER_API ShaderAst { public: struct Function; @@ -110,6 +110,6 @@ namespace Nz }; } -#include +#include #endif // NAZARA_SHADER_AST_HPP diff --git a/include/Nazara/Renderer/ShaderAst.inl b/include/Nazara/Shader/ShaderAst.inl similarity index 91% rename from include/Nazara/Renderer/ShaderAst.inl rename to include/Nazara/Shader/ShaderAst.inl index f0bc1aebb..4c6c42833 100644 --- a/include/Nazara/Renderer/ShaderAst.inl +++ b/include/Nazara/Shader/ShaderAst.inl @@ -1,9 +1,9 @@ // Copyright (C) 2020 Jérôme Leclercq -// This file is part of the "Nazara Engine - Renderer module" +// 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 namespace Nz { @@ -98,4 +98,4 @@ namespace Nz } } -#include +#include diff --git a/include/Nazara/Renderer/ShaderAstCloner.hpp b/include/Nazara/Shader/ShaderAstCloner.hpp similarity index 86% rename from include/Nazara/Renderer/ShaderAstCloner.hpp rename to include/Nazara/Shader/ShaderAstCloner.hpp index c8b61b02c..4c24e689e 100644 --- a/include/Nazara/Renderer/ShaderAstCloner.hpp +++ b/include/Nazara/Shader/ShaderAstCloner.hpp @@ -1,5 +1,5 @@ -// Copyright (C) 2015 Jérôme Leclercq -// This file is part of the "Nazara Engine - Renderer module" +// 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 @@ -8,14 +8,14 @@ #define NAZARA_SHADERASTCLONER_HPP #include -#include -#include -#include +#include +#include +#include #include namespace Nz { - class NAZARA_RENDERER_API ShaderAstCloner : public ShaderAstVisitor, public ShaderVarVisitor + class NAZARA_SHADER_API ShaderAstCloner : public ShaderAstVisitor, public ShaderVarVisitor { public: ShaderAstCloner() = default; @@ -69,6 +69,6 @@ namespace Nz }; } -#include +#include #endif diff --git a/include/Nazara/Shader/ShaderAstCloner.inl b/include/Nazara/Shader/ShaderAstCloner.inl new file mode 100644 index 000000000..1182f110d --- /dev/null +++ b/include/Nazara/Shader/ShaderAstCloner.inl @@ -0,0 +1,12 @@ +// 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 +{ +} + +#include diff --git a/include/Nazara/Renderer/ShaderAstRecursiveVisitor.hpp b/include/Nazara/Shader/ShaderAstRecursiveVisitor.hpp similarity index 80% rename from include/Nazara/Renderer/ShaderAstRecursiveVisitor.hpp rename to include/Nazara/Shader/ShaderAstRecursiveVisitor.hpp index 0482ea009..367f9b4ca 100644 --- a/include/Nazara/Renderer/ShaderAstRecursiveVisitor.hpp +++ b/include/Nazara/Shader/ShaderAstRecursiveVisitor.hpp @@ -1,5 +1,5 @@ // Copyright (C) 2020 Jérôme Leclercq -// This file is part of the "Nazara Engine - Renderer module" +// This file is part of the "Nazara Engine - Shader generator" // For conditions of distribution and use, see copyright notice in Config.hpp #pragma once @@ -8,12 +8,12 @@ #define NAZARA_SHADER_RECURSIVE_VISITOR_HPP #include -#include -#include +#include +#include namespace Nz { - class NAZARA_RENDERER_API ShaderAstRecursiveVisitor : public ShaderAstVisitor + class NAZARA_SHADER_API ShaderAstRecursiveVisitor : public ShaderAstVisitor { public: ShaderAstRecursiveVisitor() = default; @@ -37,6 +37,6 @@ namespace Nz }; } -#include +#include #endif diff --git a/include/Nazara/Shader/ShaderAstRecursiveVisitor.inl b/include/Nazara/Shader/ShaderAstRecursiveVisitor.inl new file mode 100644 index 000000000..8de7f453c --- /dev/null +++ b/include/Nazara/Shader/ShaderAstRecursiveVisitor.inl @@ -0,0 +1,12 @@ +// 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 +{ +} + +#include diff --git a/include/Nazara/Renderer/ShaderAstSerializer.hpp b/include/Nazara/Shader/ShaderAstSerializer.hpp similarity index 87% rename from include/Nazara/Renderer/ShaderAstSerializer.hpp rename to include/Nazara/Shader/ShaderAstSerializer.hpp index 3298d81e6..2e0102e8e 100644 --- a/include/Nazara/Renderer/ShaderAstSerializer.hpp +++ b/include/Nazara/Shader/ShaderAstSerializer.hpp @@ -1,5 +1,5 @@ // Copyright (C) 2020 Jérôme Leclercq -// This file is part of the "Nazara Engine - Renderer module" +// This file is part of the "Nazara Engine - Shader generator" // For conditions of distribution and use, see copyright notice in Config.hpp #pragma once @@ -10,14 +10,14 @@ #include #include #include -#include -#include -#include -#include +#include +#include +#include +#include namespace Nz { - class NAZARA_RENDERER_API ShaderAstSerializerBase + class NAZARA_SHADER_API ShaderAstSerializerBase { public: ShaderAstSerializerBase() = default; @@ -73,7 +73,7 @@ namespace Nz template void Variable(std::shared_ptr& var); }; - class NAZARA_RENDERER_API ShaderAstSerializer final : public ShaderAstSerializerBase + class NAZARA_SHADER_API ShaderAstSerializer final : public ShaderAstSerializerBase { public: inline ShaderAstSerializer(ByteStream& stream); @@ -104,7 +104,7 @@ namespace Nz ByteStream& m_stream; }; - class NAZARA_RENDERER_API ShaderAstUnserializer final : public ShaderAstSerializerBase + class NAZARA_SHADER_API ShaderAstUnserializer final : public ShaderAstSerializerBase { public: ShaderAstUnserializer(ByteStream& stream); @@ -134,10 +134,10 @@ namespace Nz ByteStream& m_stream; }; - NAZARA_RENDERER_API ByteArray SerializeShader(const ShaderAst& shader); - NAZARA_RENDERER_API ShaderAst UnserializeShader(ByteStream& stream); + NAZARA_SHADER_API ByteArray SerializeShader(const ShaderAst& shader); + NAZARA_SHADER_API ShaderAst UnserializeShader(ByteStream& stream); } -#include +#include #endif diff --git a/include/Nazara/Renderer/ShaderAstSerializer.inl b/include/Nazara/Shader/ShaderAstSerializer.inl similarity index 92% rename from include/Nazara/Renderer/ShaderAstSerializer.inl rename to include/Nazara/Shader/ShaderAstSerializer.inl index dd272e1fa..a335f91c2 100644 --- a/include/Nazara/Renderer/ShaderAstSerializer.inl +++ b/include/Nazara/Shader/ShaderAstSerializer.inl @@ -1,9 +1,9 @@ // Copyright (C) 2020 Jérôme Leclercq -// This file is part of the "Nazara Engine - Renderer module" +// 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 namespace Nz { @@ -124,4 +124,4 @@ namespace Nz } } -#include +#include diff --git a/include/Nazara/Renderer/ShaderAstValidator.hpp b/include/Nazara/Shader/ShaderAstValidator.hpp similarity index 81% rename from include/Nazara/Renderer/ShaderAstValidator.hpp rename to include/Nazara/Shader/ShaderAstValidator.hpp index 90aec52aa..0f9e99347 100644 --- a/include/Nazara/Renderer/ShaderAstValidator.hpp +++ b/include/Nazara/Shader/ShaderAstValidator.hpp @@ -1,5 +1,5 @@ // Copyright (C) 2020 Jérôme Leclercq -// This file is part of the "Nazara Engine - Renderer module" +// This file is part of the "Nazara Engine - Shader generator" // For conditions of distribution and use, see copyright notice in Config.hpp #pragma once @@ -10,14 +10,14 @@ #include #include #include -#include -#include -#include -#include +#include +#include +#include +#include namespace Nz { - class NAZARA_RENDERER_API ShaderAstValidator : public ShaderAstRecursiveVisitor, public ShaderVarVisitor + class NAZARA_SHADER_API ShaderAstValidator : public ShaderAstRecursiveVisitor, public ShaderVarVisitor { public: inline ShaderAstValidator(const ShaderAst& shader); @@ -62,9 +62,9 @@ namespace Nz Context* m_context; }; - NAZARA_RENDERER_API bool ValidateShader(const ShaderAst& shader, std::string* error = nullptr); + NAZARA_SHADER_API bool ValidateShader(const ShaderAst& shader, std::string* error = nullptr); } -#include +#include #endif diff --git a/include/Nazara/Renderer/ShaderAstValidator.inl b/include/Nazara/Shader/ShaderAstValidator.inl similarity index 54% rename from include/Nazara/Renderer/ShaderAstValidator.inl rename to include/Nazara/Shader/ShaderAstValidator.inl index ee2628ce5..eed116766 100644 --- a/include/Nazara/Renderer/ShaderAstValidator.inl +++ b/include/Nazara/Shader/ShaderAstValidator.inl @@ -1,9 +1,9 @@ // Copyright (C) 2020 Jérôme Leclercq -// This file is part of the "Nazara Engine - Renderer module" +// 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 namespace Nz { @@ -13,4 +13,4 @@ namespace Nz } } -#include +#include diff --git a/include/Nazara/Renderer/ShaderAstVisitor.hpp b/include/Nazara/Shader/ShaderAstVisitor.hpp similarity index 86% rename from include/Nazara/Renderer/ShaderAstVisitor.hpp rename to include/Nazara/Shader/ShaderAstVisitor.hpp index 3ce83f406..a6896cb2c 100644 --- a/include/Nazara/Renderer/ShaderAstVisitor.hpp +++ b/include/Nazara/Shader/ShaderAstVisitor.hpp @@ -1,5 +1,5 @@ -// Copyright (C) 2015 Jérôme Leclercq -// This file is part of the "Nazara Engine - Renderer module" +// 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 @@ -8,14 +8,14 @@ #define NAZARA_SHADERVISITOR_HPP #include -#include -#include +#include +#include #include #include namespace Nz { - class NAZARA_RENDERER_API ShaderAstVisitor + class NAZARA_SHADER_API ShaderAstVisitor { public: ShaderAstVisitor() = default; diff --git a/include/Nazara/Renderer/ShaderBuilder.hpp b/include/Nazara/Shader/ShaderBuilder.hpp similarity index 94% rename from include/Nazara/Renderer/ShaderBuilder.hpp rename to include/Nazara/Shader/ShaderBuilder.hpp index 8f544e018..074434a44 100644 --- a/include/Nazara/Renderer/ShaderBuilder.hpp +++ b/include/Nazara/Shader/ShaderBuilder.hpp @@ -1,5 +1,5 @@ // Copyright (C) 2020 Jérôme Leclercq -// This file is part of the "Nazara Engine - Renderer module" +// This file is part of the "Nazara Engine - Shader generator" // For conditions of distribution and use, see copyright notice in Config.hpp #pragma once @@ -8,7 +8,7 @@ #define NAZARA_SHADER_BUILDER_HPP #include -#include +#include #include namespace Nz::ShaderBuilder @@ -71,6 +71,6 @@ namespace Nz::ShaderBuilder template std::shared_ptr Cast(Args&&... args); } -#include +#include #endif // NAZARA_SHADER_BUILDER_HPP diff --git a/include/Nazara/Renderer/ShaderBuilder.inl b/include/Nazara/Shader/ShaderBuilder.inl similarity index 89% rename from include/Nazara/Renderer/ShaderBuilder.inl rename to include/Nazara/Shader/ShaderBuilder.inl index 8ef833536..c3221c84f 100644 --- a/include/Nazara/Renderer/ShaderBuilder.inl +++ b/include/Nazara/Shader/ShaderBuilder.inl @@ -1,9 +1,9 @@ // Copyright (C) 2020 Jérôme Leclercq -// This file is part of the "Nazara Engine - Renderer module" +// 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 namespace Nz::ShaderBuilder { @@ -49,4 +49,4 @@ namespace Nz::ShaderBuilder } } -#include +#include diff --git a/include/Nazara/Renderer/ShaderEnums.hpp b/include/Nazara/Shader/ShaderEnums.hpp similarity index 96% rename from include/Nazara/Renderer/ShaderEnums.hpp rename to include/Nazara/Shader/ShaderEnums.hpp index 46e6a3d74..2ddbb5b97 100644 --- a/include/Nazara/Renderer/ShaderEnums.hpp +++ b/include/Nazara/Shader/ShaderEnums.hpp @@ -1,5 +1,5 @@ // Copyright (C) 2020 Jérôme Leclercq -// This file is part of the "Nazara Engine - Renderer module" +// This file is part of the "Nazara Engine - Shader generator" // For conditions of distribution and use, see copyright notice in Config.hpp #pragma once diff --git a/include/Nazara/Renderer/ShaderExpressionType.hpp b/include/Nazara/Shader/ShaderExpressionType.hpp similarity index 80% rename from include/Nazara/Renderer/ShaderExpressionType.hpp rename to include/Nazara/Shader/ShaderExpressionType.hpp index 68671b07c..69b53b06a 100644 --- a/include/Nazara/Renderer/ShaderExpressionType.hpp +++ b/include/Nazara/Shader/ShaderExpressionType.hpp @@ -1,5 +1,5 @@ // Copyright (C) 2020 Jérôme Leclercq -// This file is part of the "Nazara Engine - Renderer module" +// This file is part of the "Nazara Engine - Shader generator" // For conditions of distribution and use, see copyright notice in Config.hpp #pragma once @@ -8,7 +8,7 @@ #define NAZARA_SHADER_EXPRESSIONTYPE_HPP #include -#include +#include #include #include diff --git a/include/Nazara/Renderer/ShaderNodes.hpp b/include/Nazara/Shader/ShaderNodes.hpp similarity index 84% rename from include/Nazara/Renderer/ShaderNodes.hpp rename to include/Nazara/Shader/ShaderNodes.hpp index 985cde039..833af1248 100644 --- a/include/Nazara/Renderer/ShaderNodes.hpp +++ b/include/Nazara/Shader/ShaderNodes.hpp @@ -1,5 +1,5 @@ // Copyright (C) 2020 Jérôme Leclercq -// This file is part of the "Nazara Engine - Renderer module" +// This file is part of the "Nazara Engine - Shader generator" // For conditions of distribution and use, see copyright notice in Config.hpp #pragma once @@ -11,10 +11,10 @@ #include #include #include -#include -#include -#include -#include +#include +#include +#include +#include #include #include #include @@ -29,7 +29,7 @@ namespace Nz using NodePtr = std::shared_ptr; - class NAZARA_RENDERER_API Node + class NAZARA_SHADER_API Node { public: virtual ~Node(); @@ -54,7 +54,7 @@ namespace Nz using ExpressionPtr = std::shared_ptr; - class NAZARA_RENDERER_API Expression : public Node + class NAZARA_SHADER_API Expression : public Node { public: inline Expression(NodeType type); @@ -67,13 +67,13 @@ namespace Nz using StatementPtr = std::shared_ptr; - class NAZARA_RENDERER_API Statement : public Node + class NAZARA_SHADER_API Statement : public Node { public: inline Statement(NodeType type); }; - struct NAZARA_RENDERER_API ExpressionStatement : public Statement + struct NAZARA_SHADER_API ExpressionStatement : public Statement { inline ExpressionStatement(); @@ -86,7 +86,7 @@ namespace Nz ////////////////////////////////////////////////////////////////////////// - struct NAZARA_RENDERER_API ConditionalStatement : public Statement + struct NAZARA_SHADER_API ConditionalStatement : public Statement { inline ConditionalStatement(); @@ -98,7 +98,7 @@ namespace Nz static inline std::shared_ptr Build(std::string condition, StatementPtr statementPtr); }; - struct NAZARA_RENDERER_API StatementBlock : public Statement + struct NAZARA_SHADER_API StatementBlock : public Statement { inline StatementBlock(); @@ -110,7 +110,7 @@ namespace Nz template static std::shared_ptr Build(Args&&... args); }; - struct NAZARA_RENDERER_API DeclareVariable : public Statement + struct NAZARA_SHADER_API DeclareVariable : public Statement { inline DeclareVariable(); @@ -122,7 +122,7 @@ namespace Nz static inline std::shared_ptr Build(VariablePtr variable, ExpressionPtr expression = nullptr); }; - struct NAZARA_RENDERER_API Identifier : public Expression + struct NAZARA_SHADER_API Identifier : public Expression { inline Identifier(); @@ -135,7 +135,7 @@ namespace Nz static inline std::shared_ptr Build(VariablePtr variable); }; - struct NAZARA_RENDERER_API AccessMember : public Expression + struct NAZARA_SHADER_API AccessMember : public Expression { inline AccessMember(); @@ -152,7 +152,7 @@ namespace Nz ////////////////////////////////////////////////////////////////////////// - struct NAZARA_RENDERER_API AssignOp : public Expression + struct NAZARA_SHADER_API AssignOp : public Expression { inline AssignOp(); @@ -166,7 +166,7 @@ namespace Nz static inline std::shared_ptr Build(AssignType op, ExpressionPtr left, ExpressionPtr right); }; - struct NAZARA_RENDERER_API BinaryOp : public Expression + struct NAZARA_SHADER_API BinaryOp : public Expression { inline BinaryOp(); @@ -180,7 +180,7 @@ namespace Nz static inline std::shared_ptr Build(BinaryType op, ExpressionPtr left, ExpressionPtr right); }; - struct NAZARA_RENDERER_API Branch : public Statement + struct NAZARA_SHADER_API Branch : public Statement { struct ConditionalStatement; @@ -201,7 +201,7 @@ namespace Nz static inline std::shared_ptr Build(std::vector statements, StatementPtr elseStatement = nullptr); }; - struct NAZARA_RENDERER_API Cast : public Expression + struct NAZARA_SHADER_API Cast : public Expression { inline Cast(); @@ -215,7 +215,7 @@ namespace Nz static inline std::shared_ptr Build(BasicType castTo, ExpressionPtr* expressions, std::size_t expressionCount); }; - struct NAZARA_RENDERER_API Constant : public Expression + struct NAZARA_SHADER_API Constant : public Expression { inline Constant(); @@ -239,7 +239,7 @@ namespace Nz template static std::shared_ptr Build(const T& value); }; - struct NAZARA_RENDERER_API SwizzleOp : public Expression + struct NAZARA_SHADER_API SwizzleOp : public Expression { inline SwizzleOp(); @@ -257,7 +257,7 @@ namespace Nz ////////////////////////////////////////////////////////////////////////// - struct NAZARA_RENDERER_API Sample2D : public Expression + struct NAZARA_SHADER_API Sample2D : public Expression { inline Sample2D(); @@ -272,7 +272,7 @@ namespace Nz ////////////////////////////////////////////////////////////////////////// - struct NAZARA_RENDERER_API IntrinsicCall : public Expression + struct NAZARA_SHADER_API IntrinsicCall : public Expression { inline IntrinsicCall(); @@ -287,6 +287,6 @@ namespace Nz } } -#include +#include #endif diff --git a/include/Nazara/Renderer/ShaderNodes.inl b/include/Nazara/Shader/ShaderNodes.inl similarity index 97% rename from include/Nazara/Renderer/ShaderNodes.inl rename to include/Nazara/Shader/ShaderNodes.inl index e6dbec2ba..9265fe359 100644 --- a/include/Nazara/Renderer/ShaderNodes.inl +++ b/include/Nazara/Shader/ShaderNodes.inl @@ -1,9 +1,9 @@ // Copyright (C) 2020 Jérôme Leclercq -// This file is part of the "Nazara Engine - Renderer module" +// 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 namespace Nz::ShaderNodes { @@ -335,4 +335,4 @@ namespace Nz::ShaderNodes } } -#include +#include diff --git a/include/Nazara/Renderer/ShaderVarVisitor.hpp b/include/Nazara/Shader/ShaderVarVisitor.hpp similarity index 82% rename from include/Nazara/Renderer/ShaderVarVisitor.hpp rename to include/Nazara/Shader/ShaderVarVisitor.hpp index bda5e0b4d..ebee55ab6 100644 --- a/include/Nazara/Renderer/ShaderVarVisitor.hpp +++ b/include/Nazara/Shader/ShaderVarVisitor.hpp @@ -1,5 +1,5 @@ // Copyright (C) 2015 Jérôme Leclercq -// This file is part of the "Nazara Engine - Renderer module" +// This file is part of the "Nazara Engine - Shader generator" // For conditions of distribution and use, see copyright notice in Config.hpp #pragma once @@ -8,12 +8,12 @@ #define NAZARA_SHADERVARVISITOR_HPP #include -#include -#include +#include +#include namespace Nz { - class NAZARA_RENDERER_API ShaderVarVisitor + class NAZARA_SHADER_API ShaderVarVisitor { public: ShaderVarVisitor() = default; diff --git a/include/Nazara/Renderer/ShaderVariables.hpp b/include/Nazara/Shader/ShaderVariables.hpp similarity index 78% rename from include/Nazara/Renderer/ShaderVariables.hpp rename to include/Nazara/Shader/ShaderVariables.hpp index 4fac1681f..eb0bc8ede 100644 --- a/include/Nazara/Renderer/ShaderVariables.hpp +++ b/include/Nazara/Shader/ShaderVariables.hpp @@ -1,5 +1,5 @@ // Copyright (C) 2020 Jérôme Leclercq -// This file is part of the "Nazara Engine - Renderer module" +// This file is part of the "Nazara Engine - Shader generator" // For conditions of distribution and use, see copyright notice in Config.hpp #pragma once @@ -11,8 +11,8 @@ #include #include #include -#include -#include +#include +#include #include #include #include @@ -28,7 +28,7 @@ namespace Nz using VariablePtr = std::shared_ptr; - struct NAZARA_RENDERER_API Variable : std::enable_shared_from_this + struct NAZARA_SHADER_API Variable : std::enable_shared_from_this { virtual ~Variable(); @@ -42,7 +42,7 @@ namespace Nz using BuiltinVariablePtr = std::shared_ptr; - struct NAZARA_RENDERER_API BuiltinVariable : public Variable + struct NAZARA_SHADER_API BuiltinVariable : public Variable { BuiltinEntry entry; @@ -56,7 +56,7 @@ namespace Nz using NamedVariablePtr = std::shared_ptr; - struct NAZARA_RENDERER_API NamedVariable : public Variable + struct NAZARA_SHADER_API NamedVariable : public Variable { std::string name; }; @@ -65,7 +65,7 @@ namespace Nz using InputVariablePtr = std::shared_ptr; - struct NAZARA_RENDERER_API InputVariable : public NamedVariable + struct NAZARA_SHADER_API InputVariable : public NamedVariable { VariableType GetType() const override; void Visit(ShaderVarVisitor& visitor) override; @@ -77,7 +77,7 @@ namespace Nz using LocalVariablePtr = std::shared_ptr; - struct NAZARA_RENDERER_API LocalVariable : public NamedVariable + struct NAZARA_SHADER_API LocalVariable : public NamedVariable { VariableType GetType() const override; void Visit(ShaderVarVisitor& visitor) override; @@ -89,7 +89,7 @@ namespace Nz using OutputVariablePtr = std::shared_ptr; - struct NAZARA_RENDERER_API OutputVariable : public NamedVariable + struct NAZARA_SHADER_API OutputVariable : public NamedVariable { VariableType GetType() const override; void Visit(ShaderVarVisitor& visitor) override; @@ -101,7 +101,7 @@ namespace Nz using ParameterVariablePtr = std::shared_ptr; - struct NAZARA_RENDERER_API ParameterVariable : public NamedVariable + struct NAZARA_SHADER_API ParameterVariable : public NamedVariable { VariableType GetType() const override; void Visit(ShaderVarVisitor& visitor) override; @@ -113,7 +113,7 @@ namespace Nz using UniformVariablePtr = std::shared_ptr; - struct NAZARA_RENDERER_API UniformVariable : public NamedVariable + struct NAZARA_SHADER_API UniformVariable : public NamedVariable { VariableType GetType() const override; void Visit(ShaderVarVisitor& visitor) override; @@ -123,6 +123,6 @@ namespace Nz } } -#include +#include #endif diff --git a/include/Nazara/Renderer/ShaderVariables.inl b/include/Nazara/Shader/ShaderVariables.inl similarity index 89% rename from include/Nazara/Renderer/ShaderVariables.inl rename to include/Nazara/Shader/ShaderVariables.inl index 917459c67..9f2415708 100644 --- a/include/Nazara/Renderer/ShaderVariables.inl +++ b/include/Nazara/Shader/ShaderVariables.inl @@ -1,9 +1,9 @@ // Copyright (C) 2020 Jérôme Leclercq -// This file is part of the "Nazara Engine - Renderer module" +// 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 namespace Nz::ShaderNodes { @@ -62,4 +62,4 @@ namespace Nz::ShaderNodes } } -#include +#include diff --git a/include/Nazara/Renderer/ShaderWriter.hpp b/include/Nazara/Shader/ShaderWriter.hpp similarity index 79% rename from include/Nazara/Renderer/ShaderWriter.hpp rename to include/Nazara/Shader/ShaderWriter.hpp index e4fe2d835..0e896fa40 100644 --- a/include/Nazara/Renderer/ShaderWriter.hpp +++ b/include/Nazara/Shader/ShaderWriter.hpp @@ -1,5 +1,5 @@ // Copyright (C) 2015 Jérôme Leclercq -// This file is part of the "Nazara Engine - Renderer module" +// This file is part of the "Nazara Engine - Shader generator" // For conditions of distribution and use, see copyright notice in Config.hpp #pragma once @@ -8,14 +8,14 @@ #define NAZARA_SHADERWRITER_HPP #include -#include +#include #include namespace Nz { class ShaderAst; - class NAZARA_RENDERER_API ShaderWriter + class NAZARA_SHADER_API ShaderWriter { public: ShaderWriter() = default; diff --git a/include/Nazara/Renderer/SpirvWriter.hpp b/include/Nazara/Shader/SpirvWriter.hpp similarity index 90% rename from include/Nazara/Renderer/SpirvWriter.hpp rename to include/Nazara/Shader/SpirvWriter.hpp index b9e48dd12..90f6b0e3e 100644 --- a/include/Nazara/Renderer/SpirvWriter.hpp +++ b/include/Nazara/Shader/SpirvWriter.hpp @@ -1,5 +1,5 @@ // Copyright (C) 2020 Jérôme Leclercq -// This file is part of the "Nazara Engine - Renderer module" +// This file is part of the "Nazara Engine - Shader generator" // For conditions of distribution and use, see copyright notice in Config.hpp #pragma once @@ -8,11 +8,11 @@ #define NAZARA_SPIRVWRITER_HPP #include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include #include #include @@ -20,7 +20,7 @@ namespace Nz { - class NAZARA_RENDERER_API SpirvWriter : public ShaderAstVisitor, public ShaderVarVisitor + class NAZARA_SHADER_API SpirvWriter : public ShaderAstVisitor, public ShaderVarVisitor { public: struct Environment; @@ -127,6 +127,6 @@ namespace Nz }; } -#include +#include #endif diff --git a/include/Nazara/Renderer/SpirvWriter.inl b/include/Nazara/Shader/SpirvWriter.inl similarity index 93% rename from include/Nazara/Renderer/SpirvWriter.inl rename to include/Nazara/Shader/SpirvWriter.inl index 2e75f1271..4ef96c82b 100644 --- a/include/Nazara/Renderer/SpirvWriter.inl +++ b/include/Nazara/Shader/SpirvWriter.inl @@ -1,11 +1,11 @@ // Copyright (C) 2020 Jérôme Leclercq -// This file is part of the "Nazara Engine - Renderer module" +// 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 namespace Nz { @@ -108,4 +108,4 @@ namespace Nz } } -#include +#include diff --git a/include/Nazara/Utility/Enums.hpp b/include/Nazara/Utility/Enums.hpp index 0e652448e..99328ecde 100644 --- a/include/Nazara/Utility/Enums.hpp +++ b/include/Nazara/Utility/Enums.hpp @@ -309,6 +309,24 @@ namespace Nz SamplerWrap_Max = SamplerWrap_Repeat }; + enum class ShaderStageType + { + Fragment, + Vertex, + + Max = Vertex + }; + + template<> + struct EnumAsFlags + { + static constexpr ShaderStageType max = ShaderStageType::Max; + }; + + using ShaderStageTypeFlags = Flags; + + constexpr ShaderStageTypeFlags ShaderStageType_All = ShaderStageType::Fragment | ShaderStageType::Vertex; + enum StructFieldType { StructFieldType_Bool1, diff --git a/src/Nazara/Renderer/ShaderWriter.cpp b/src/Nazara/Renderer/ShaderWriter.cpp deleted file mode 100644 index 8ca48da3e..000000000 --- a/src/Nazara/Renderer/ShaderWriter.cpp +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright (C) 2015 Jérôme Leclercq -// This file is part of the "Nazara Engine - Renderer module" -// For conditions of distribution and use, see copyright notice in Config.hpp - -#include -#include - -namespace Nz -{ - ShaderWriter::~ShaderWriter() = default; -} diff --git a/src/Nazara/Shader/Debug/NewOverload.cpp b/src/Nazara/Shader/Debug/NewOverload.cpp new file mode 100644 index 000000000..d16399d8f --- /dev/null +++ b/src/Nazara/Shader/Debug/NewOverload.cpp @@ -0,0 +1,31 @@ +// 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 +#if NAZARA_SHADER_MANAGE_MEMORY + +#include +#include // Nécessaire ? + +void* operator new(std::size_t size) +{ + return Nz::MemoryManager::Allocate(size, false); +} + +void* operator new[](std::size_t size) +{ + return Nz::MemoryManager::Allocate(size, true); +} + +void operator delete(void* pointer) noexcept +{ + Nz::MemoryManager::Free(pointer, false); +} + +void operator delete[](void* pointer) noexcept +{ + Nz::MemoryManager::Free(pointer, true); +} + +#endif // NAZARA_SHADER_MANAGE_MEMORY diff --git a/src/Nazara/Renderer/GlslWriter.cpp b/src/Nazara/Shader/GlslWriter.cpp similarity index 97% rename from src/Nazara/Renderer/GlslWriter.cpp rename to src/Nazara/Shader/GlslWriter.cpp index f851a3aa0..b17c8d4a3 100644 --- a/src/Nazara/Renderer/GlslWriter.cpp +++ b/src/Nazara/Shader/GlslWriter.cpp @@ -1,15 +1,15 @@ -// Copyright (C) 2015 Jérôme Leclercq -// This file is part of the "Nazara Engine - Renderer module" +// 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 +#include +#include +#include #include -#include +#include namespace Nz { diff --git a/src/Nazara/Shader/Shader.cpp b/src/Nazara/Shader/Shader.cpp new file mode 100644 index 000000000..44d65fbe6 --- /dev/null +++ b/src/Nazara/Shader/Shader.cpp @@ -0,0 +1,70 @@ +// 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 +{ + bool Shader::Initialize() + { + if (s_moduleReferenceCounter > 0) + { + s_moduleReferenceCounter++; + return true; // Already initialized + } + + // Initialize module dependencies + if (!Core::Initialize()) + { + NazaraError("Failed to initialize shader module"); + return false; + } + + s_moduleReferenceCounter++; + + CallOnExit onExit(Shader::Uninitialize); + + // Initialize module here + + onExit.Reset(); + + NazaraNotice("Initialized: Shader module"); + return true; + } + + bool Shader::IsInitialized() + { + return s_moduleReferenceCounter != 0; + } + + void Shader::Uninitialize() + { + if (s_moduleReferenceCounter != 1) + { + // Either the module is not initialized, either it was initialized multiple times + if (s_moduleReferenceCounter > 1) + s_moduleReferenceCounter--; + + return; + } + + s_moduleReferenceCounter = 0; + + // Uninitialize module here + + NazaraNotice("Uninitialized: Shader module"); + + // Free module dependencies + Core::Uninitialize(); + } + + unsigned int Shader::s_moduleReferenceCounter = 0; +} + diff --git a/src/Nazara/Renderer/ShaderAst.cpp b/src/Nazara/Shader/ShaderAst.cpp similarity index 92% rename from src/Nazara/Renderer/ShaderAst.cpp rename to src/Nazara/Shader/ShaderAst.cpp index da009248b..236a5e28f 100644 --- a/src/Nazara/Renderer/ShaderAst.cpp +++ b/src/Nazara/Shader/ShaderAst.cpp @@ -1,9 +1,9 @@ // Copyright (C) 2020 Jérôme Leclercq -// This file is part of the "Nazara Engine - Renderer module" +// 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 namespace Nz { diff --git a/src/Nazara/Renderer/ShaderAstCloner.cpp b/src/Nazara/Shader/ShaderAstCloner.cpp similarity index 97% rename from src/Nazara/Renderer/ShaderAstCloner.cpp rename to src/Nazara/Shader/ShaderAstCloner.cpp index 2b712075c..1e0f04899 100644 --- a/src/Nazara/Renderer/ShaderAstCloner.cpp +++ b/src/Nazara/Shader/ShaderAstCloner.cpp @@ -1,10 +1,10 @@ -// Copyright (C) 2015 Jérôme Leclercq -// This file is part of the "Nazara Engine - Renderer module" +// 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 { diff --git a/src/Nazara/Renderer/ShaderAstRecursiveVisitor.cpp b/src/Nazara/Shader/ShaderAstRecursiveVisitor.cpp similarity index 90% rename from src/Nazara/Renderer/ShaderAstRecursiveVisitor.cpp rename to src/Nazara/Shader/ShaderAstRecursiveVisitor.cpp index 5a39e68c5..98fdbfee6 100644 --- a/src/Nazara/Renderer/ShaderAstRecursiveVisitor.cpp +++ b/src/Nazara/Shader/ShaderAstRecursiveVisitor.cpp @@ -1,9 +1,9 @@ -// Copyright (C) 2015 Jérôme Leclercq -// This file is part of the "Nazara Engine - Renderer module" +// 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 namespace Nz { diff --git a/src/Nazara/Renderer/ShaderAstSerializer.cpp b/src/Nazara/Shader/ShaderAstSerializer.cpp similarity index 98% rename from src/Nazara/Renderer/ShaderAstSerializer.cpp rename to src/Nazara/Shader/ShaderAstSerializer.cpp index f8afa178c..6d45cc711 100644 --- a/src/Nazara/Renderer/ShaderAstSerializer.cpp +++ b/src/Nazara/Shader/ShaderAstSerializer.cpp @@ -1,11 +1,11 @@ // Copyright (C) 2020 Jérôme Leclercq -// This file is part of the "Nazara Engine - Renderer module" +// 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 +#include namespace Nz { diff --git a/src/Nazara/Renderer/ShaderAstValidator.cpp b/src/Nazara/Shader/ShaderAstValidator.cpp similarity index 97% rename from src/Nazara/Renderer/ShaderAstValidator.cpp rename to src/Nazara/Shader/ShaderAstValidator.cpp index 81970e766..2f3177283 100644 --- a/src/Nazara/Renderer/ShaderAstValidator.cpp +++ b/src/Nazara/Shader/ShaderAstValidator.cpp @@ -1,13 +1,13 @@ -// Copyright (C) 2015 Jérôme Leclercq -// This file is part of the "Nazara Engine - Renderer module" +// 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 #include -#include +#include namespace Nz { diff --git a/src/Nazara/Renderer/ShaderAstVisitor.cpp b/src/Nazara/Shader/ShaderAstVisitor.cpp similarity index 73% rename from src/Nazara/Renderer/ShaderAstVisitor.cpp rename to src/Nazara/Shader/ShaderAstVisitor.cpp index 49760f028..53325c9ca 100644 --- a/src/Nazara/Renderer/ShaderAstVisitor.cpp +++ b/src/Nazara/Shader/ShaderAstVisitor.cpp @@ -1,9 +1,9 @@ -// Copyright (C) 2015 Jérôme Leclercq -// This file is part of the "Nazara Engine - Renderer module" +// 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 namespace Nz { diff --git a/src/Nazara/Renderer/ShaderNodes.cpp b/src/Nazara/Shader/ShaderNodes.cpp similarity index 93% rename from src/Nazara/Renderer/ShaderNodes.cpp rename to src/Nazara/Shader/ShaderNodes.cpp index 29ffb8508..2f72a1ea0 100644 --- a/src/Nazara/Renderer/ShaderNodes.cpp +++ b/src/Nazara/Shader/ShaderNodes.cpp @@ -1,13 +1,13 @@ // Copyright (C) 2020 Jérôme Leclercq -// This file is part of the "Nazara Engine - Renderer module" +// 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 +#include +#include +#include +#include namespace Nz::ShaderNodes { @@ -61,7 +61,7 @@ namespace Nz::ShaderNodes ExpressionCategory AccessMember::GetExpressionCategory() const { - return ExpressionCategory::LValue; + return structExpr->GetExpressionCategory(); } ShaderExpressionType AccessMember::GetExpressionType() const @@ -200,7 +200,7 @@ namespace Nz::ShaderNodes ExpressionCategory SwizzleOp::GetExpressionCategory() const { - return ExpressionCategory::LValue; + return expression->GetExpressionCategory(); } ShaderExpressionType SwizzleOp::GetExpressionType() const diff --git a/src/Nazara/Renderer/ShaderVarVisitor.cpp b/src/Nazara/Shader/ShaderVarVisitor.cpp similarity index 56% rename from src/Nazara/Renderer/ShaderVarVisitor.cpp rename to src/Nazara/Shader/ShaderVarVisitor.cpp index 6f3838f26..108d5c69a 100644 --- a/src/Nazara/Renderer/ShaderVarVisitor.cpp +++ b/src/Nazara/Shader/ShaderVarVisitor.cpp @@ -1,9 +1,9 @@ -// Copyright (C) 2015 Jérôme Leclercq -// This file is part of the "Nazara Engine - Renderer module" +// 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 namespace Nz { diff --git a/src/Nazara/Renderer/ShaderVariables.cpp b/src/Nazara/Shader/ShaderVariables.cpp similarity index 86% rename from src/Nazara/Renderer/ShaderVariables.cpp rename to src/Nazara/Shader/ShaderVariables.cpp index 93701c4ef..ebe520a0c 100644 --- a/src/Nazara/Renderer/ShaderVariables.cpp +++ b/src/Nazara/Shader/ShaderVariables.cpp @@ -1,10 +1,10 @@ // Copyright (C) 2020 Jérôme Leclercq -// This file is part of the "Nazara Engine - Renderer module" +// 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 namespace Nz::ShaderNodes { diff --git a/src/Nazara/Shader/ShaderWriter.cpp b/src/Nazara/Shader/ShaderWriter.cpp new file mode 100644 index 000000000..6e994f0f0 --- /dev/null +++ b/src/Nazara/Shader/ShaderWriter.cpp @@ -0,0 +1,11 @@ +// 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 +{ + ShaderWriter::~ShaderWriter() = default; +} diff --git a/src/Nazara/Renderer/SpirvWriter.cpp b/src/Nazara/Shader/SpirvWriter.cpp similarity index 99% rename from src/Nazara/Renderer/SpirvWriter.cpp rename to src/Nazara/Shader/SpirvWriter.cpp index 1e9218e34..b3b318c63 100644 --- a/src/Nazara/Renderer/SpirvWriter.cpp +++ b/src/Nazara/Shader/SpirvWriter.cpp @@ -1,13 +1,13 @@ -// Copyright (C) 2015 Jérôme Leclercq -// This file is part of the "Nazara Engine - Renderer module" +// 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 +#include +#include #include #include #include @@ -16,7 +16,7 @@ #include #include #include -#include +#include namespace Nz { diff --git a/src/ShaderNode/DataModels/BufferField.cpp b/src/ShaderNode/DataModels/BufferField.cpp index 844f56bd8..2d9cde16d 100644 --- a/src/ShaderNode/DataModels/BufferField.cpp +++ b/src/ShaderNode/DataModels/BufferField.cpp @@ -5,7 +5,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/ShaderNode/DataModels/Cast.inl b/src/ShaderNode/DataModels/Cast.inl index fb088b3a0..cd96d6ccc 100644 --- a/src/ShaderNode/DataModels/Cast.inl +++ b/src/ShaderNode/DataModels/Cast.inl @@ -1,5 +1,5 @@ #include -#include +#include #include #include #include diff --git a/src/ShaderNode/DataModels/FloatValue.cpp b/src/ShaderNode/DataModels/FloatValue.cpp index c30ea8874..23a4c766f 100644 --- a/src/ShaderNode/DataModels/FloatValue.cpp +++ b/src/ShaderNode/DataModels/FloatValue.cpp @@ -1,6 +1,6 @@ #include #include -#include +#include #include FloatValue::FloatValue(ShaderGraph& graph) : diff --git a/src/ShaderNode/DataModels/InputValue.cpp b/src/ShaderNode/DataModels/InputValue.cpp index c2c6f6b01..e4710e6f5 100644 --- a/src/ShaderNode/DataModels/InputValue.cpp +++ b/src/ShaderNode/DataModels/InputValue.cpp @@ -4,7 +4,7 @@ #include #include #include -#include +#include #include InputValue::InputValue(ShaderGraph& graph) : diff --git a/src/ShaderNode/DataModels/Mat4BinOp.inl b/src/ShaderNode/DataModels/Mat4BinOp.inl index 684a6ec79..05cdb0479 100644 --- a/src/ShaderNode/DataModels/Mat4BinOp.inl +++ b/src/ShaderNode/DataModels/Mat4BinOp.inl @@ -1,5 +1,5 @@ #include -#include +#include template Mat4BinOp::Mat4BinOp(ShaderGraph& graph) : diff --git a/src/ShaderNode/DataModels/Mat4VecMul.cpp b/src/ShaderNode/DataModels/Mat4VecMul.cpp index 2e530e496..983545973 100644 --- a/src/ShaderNode/DataModels/Mat4VecMul.cpp +++ b/src/ShaderNode/DataModels/Mat4VecMul.cpp @@ -1,5 +1,5 @@ #include -#include +#include Mat4VecMul::Mat4VecMul(ShaderGraph& graph) : ShaderNode(graph) diff --git a/src/ShaderNode/DataModels/OutputValue.cpp b/src/ShaderNode/DataModels/OutputValue.cpp index 6f30a9b66..63a481588 100644 --- a/src/ShaderNode/DataModels/OutputValue.cpp +++ b/src/ShaderNode/DataModels/OutputValue.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include #include #include diff --git a/src/ShaderNode/DataModels/PositionOutputValue.cpp b/src/ShaderNode/DataModels/PositionOutputValue.cpp index ee1be66a2..c3d252f54 100644 --- a/src/ShaderNode/DataModels/PositionOutputValue.cpp +++ b/src/ShaderNode/DataModels/PositionOutputValue.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include #include #include diff --git a/src/ShaderNode/DataModels/SampleTexture.cpp b/src/ShaderNode/DataModels/SampleTexture.cpp index 131a8b161..c784b83af 100644 --- a/src/ShaderNode/DataModels/SampleTexture.cpp +++ b/src/ShaderNode/DataModels/SampleTexture.cpp @@ -1,6 +1,6 @@ #include #include -#include +#include SampleTexture::SampleTexture(ShaderGraph& graph) : ShaderNode(graph) diff --git a/src/ShaderNode/DataModels/ShaderNode.hpp b/src/ShaderNode/DataModels/ShaderNode.hpp index 1becb5a3d..6d3dd5cc1 100644 --- a/src/ShaderNode/DataModels/ShaderNode.hpp +++ b/src/ShaderNode/DataModels/ShaderNode.hpp @@ -4,7 +4,7 @@ #define NAZARA_SHADERNODES_SHADERNODE_HPP #include -#include +#include #include #include #include diff --git a/src/ShaderNode/DataModels/TextureValue.cpp b/src/ShaderNode/DataModels/TextureValue.cpp index 79df6de5c..c400d0469 100644 --- a/src/ShaderNode/DataModels/TextureValue.cpp +++ b/src/ShaderNode/DataModels/TextureValue.cpp @@ -2,7 +2,7 @@ #include #include #include -#include +#include #include TextureValue::TextureValue(ShaderGraph& graph) : diff --git a/src/ShaderNode/DataModels/VecBinOp.inl b/src/ShaderNode/DataModels/VecBinOp.inl index d159545be..d16347799 100644 --- a/src/ShaderNode/DataModels/VecBinOp.inl +++ b/src/ShaderNode/DataModels/VecBinOp.inl @@ -1,5 +1,5 @@ #include -#include +#include template VecBinOp::VecBinOp(ShaderGraph& graph) : diff --git a/src/ShaderNode/DataModels/VecDot.cpp b/src/ShaderNode/DataModels/VecDot.cpp index 818a68a2a..b083623d0 100644 --- a/src/ShaderNode/DataModels/VecDot.cpp +++ b/src/ShaderNode/DataModels/VecDot.cpp @@ -1,5 +1,5 @@ #include -#include +#include VecDot::VecDot(ShaderGraph& graph) : ShaderNode(graph) diff --git a/src/ShaderNode/DataModels/VecFloatMul.cpp b/src/ShaderNode/DataModels/VecFloatMul.cpp index c1ecf50d2..9dd3b02c3 100644 --- a/src/ShaderNode/DataModels/VecFloatMul.cpp +++ b/src/ShaderNode/DataModels/VecFloatMul.cpp @@ -1,5 +1,5 @@ #include -#include +#include VecFloatMul::VecFloatMul(ShaderGraph& graph) : ShaderNode(graph) diff --git a/src/ShaderNode/DataModels/VecValue.inl b/src/ShaderNode/DataModels/VecValue.inl index 8b72d1186..b07c46a9b 100644 --- a/src/ShaderNode/DataModels/VecValue.inl +++ b/src/ShaderNode/DataModels/VecValue.inl @@ -1,6 +1,6 @@ #include #include -#include +#include #include #include #include diff --git a/src/ShaderNode/DataTypes/Matrix4Data.hpp b/src/ShaderNode/DataTypes/Matrix4Data.hpp index fdfbf1897..4eb63f136 100644 --- a/src/ShaderNode/DataTypes/Matrix4Data.hpp +++ b/src/ShaderNode/DataTypes/Matrix4Data.hpp @@ -3,7 +3,7 @@ #ifndef NAZARA_SHADERNODES_MATRIXDATA_HPP #define NAZARA_SHADERNODES_MATRIXDATA_HPP -#include +#include #include #include diff --git a/src/ShaderNode/DataTypes/TextureData.hpp b/src/ShaderNode/DataTypes/TextureData.hpp index b6f7b4433..28b2b73d0 100644 --- a/src/ShaderNode/DataTypes/TextureData.hpp +++ b/src/ShaderNode/DataTypes/TextureData.hpp @@ -4,7 +4,7 @@ #define NAZARA_SHADERNODES_TEXTUREDATA_HPP #include -#include +#include #include struct TextureData : public QtNodes::NodeData diff --git a/src/ShaderNode/DataTypes/VecData.hpp b/src/ShaderNode/DataTypes/VecData.hpp index 7c515a12a..d80bff106 100644 --- a/src/ShaderNode/DataTypes/VecData.hpp +++ b/src/ShaderNode/DataTypes/VecData.hpp @@ -3,7 +3,7 @@ #ifndef NAZARA_SHADERNODES_VECDATA_HPP #define NAZARA_SHADERNODES_VECDATA_HPP -#include +#include #include #include diff --git a/src/ShaderNode/ShaderGraph.hpp b/src/ShaderNode/ShaderGraph.hpp index be7aeba4c..1df336ce6 100644 --- a/src/ShaderNode/ShaderGraph.hpp +++ b/src/ShaderNode/ShaderGraph.hpp @@ -4,8 +4,8 @@ #define NAZARA_SHADERNODES_SHADERGRAPH_HPP #include -#include -#include +#include +#include #include #include #include diff --git a/src/ShaderNode/Widgets/MainWindow.cpp b/src/ShaderNode/Widgets/MainWindow.cpp index 31665bb8d..b88bef25f 100644 --- a/src/ShaderNode/Widgets/MainWindow.cpp +++ b/src/ShaderNode/Widgets/MainWindow.cpp @@ -1,7 +1,7 @@ #include #include -#include -#include +#include +#include #include #include #include From 1a12e18a3600075a09e6e0291653a5966443287d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Tue, 11 Aug 2020 00:01:49 +0200 Subject: [PATCH 090/105] Fix copyright dates and some defines --- include/Nazara/Math/Ray.inl | 2 +- include/Nazara/Utility/FieldOffsets.hpp | 2 +- include/Nazara/Utility/FieldOffsets.inl | 2 +- include/Nazara/VulkanRenderer/Config.hpp | 2 +- include/Nazara/VulkanRenderer/ConfigCheck.hpp | 8 ++++---- include/Nazara/VulkanRenderer/Debug.hpp | 2 +- include/Nazara/VulkanRenderer/DebugOff.hpp | 2 +- include/Nazara/VulkanRenderer/VkRenderWindow.hpp | 2 +- include/Nazara/VulkanRenderer/VulkanBuffer.hpp | 2 +- include/Nazara/VulkanRenderer/VulkanDevice.hpp | 2 +- include/Nazara/VulkanRenderer/VulkanShaderStage.hpp | 2 +- include/Nazara/VulkanRenderer/VulkanSurface.hpp | 2 +- src/Nazara/OpenGLRenderer/OpenGLRenderWindow.cpp | 2 +- src/Nazara/Platform/SDL2/CursorImpl.cpp | 2 +- src/Nazara/Platform/SDL2/IconImpl.cpp | 2 +- src/Nazara/Platform/SDL2/InputImpl.cpp | 2 +- src/Nazara/Platform/SDL2/SDLHelper.cpp | 2 +- src/Nazara/Platform/SDL2/SDLHelper.hpp | 2 +- src/Nazara/Platform/SDL2/VideoModeImpl.cpp | 2 +- src/Nazara/Platform/SDL2/WindowImpl.cpp | 2 +- src/Nazara/Renderer/CommandBuffer.cpp | 2 +- src/Nazara/Renderer/CommandBufferBuilder.cpp | 2 +- src/Nazara/Renderer/CommandPool.cpp | 2 +- src/Nazara/Renderer/Framebuffer.cpp | 2 +- src/Nazara/Renderer/RenderBuffer.cpp | 2 +- src/Nazara/Renderer/RenderDevice.cpp | 2 +- src/Nazara/Renderer/RenderImage.cpp | 2 +- src/Nazara/Renderer/RenderPass.cpp | 2 +- src/Nazara/Renderer/RenderPipeline.cpp | 2 +- src/Nazara/Renderer/RenderPipelineLayout.cpp | 2 +- src/Nazara/Renderer/RenderSurface.cpp | 2 +- src/Nazara/Renderer/RendererImpl.cpp | 2 +- src/Nazara/Renderer/RendererWindowImpl.cpp | 2 +- src/Nazara/Renderer/ShaderBinding.cpp | 2 +- src/Nazara/Renderer/ShaderStageImpl.cpp | 2 +- src/Nazara/Renderer/Texture.cpp | 2 +- src/Nazara/Renderer/TextureSampler.cpp | 2 +- src/Nazara/Utility/FieldOffsets.cpp | 2 +- src/Nazara/Utility/Formats/DDSConstants.hpp | 2 +- src/Nazara/VulkanRenderer/VkRenderWindow.cpp | 2 +- 40 files changed, 43 insertions(+), 43 deletions(-) diff --git a/include/Nazara/Math/Ray.inl b/include/Nazara/Math/Ray.inl index f2248baca..1f98a17ad 100644 --- a/include/Nazara/Math/Ray.inl +++ b/include/Nazara/Math/Ray.inl @@ -400,7 +400,7 @@ namespace Nz if (squaredDistance > squaredRadius) return false; // if the ray is further than the radius - // Calcul des points d'intersection si besoin + // Compute intersections points if required if (closestHit || furthestHit) { T deltaLambda = std::sqrt(squaredRadius - squaredDistance); diff --git a/include/Nazara/Utility/FieldOffsets.hpp b/include/Nazara/Utility/FieldOffsets.hpp index 7cdeb83a9..266f82cd7 100644 --- a/include/Nazara/Utility/FieldOffsets.hpp +++ b/include/Nazara/Utility/FieldOffsets.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2019 Jérôme Leclercq +// Copyright (C) 2020 Jérôme Leclercq // This file is part of the "Nazara Engine - Utility module" // For conditions of distribution and use, see copyright notice in Config.hpp diff --git a/include/Nazara/Utility/FieldOffsets.inl b/include/Nazara/Utility/FieldOffsets.inl index 899e6a241..5ca15e88f 100644 --- a/include/Nazara/Utility/FieldOffsets.inl +++ b/include/Nazara/Utility/FieldOffsets.inl @@ -1,4 +1,4 @@ -// Copyright (C) 2019 Jérôme Leclercq +// Copyright (C) 2020 Jérôme Leclercq // This file is part of the "Nazara Engine - Utility module" // For conditions of distribution and use, see copyright notice in Config.hpp diff --git a/include/Nazara/VulkanRenderer/Config.hpp b/include/Nazara/VulkanRenderer/Config.hpp index 12d6c6663..75a7dc4ca 100644 --- a/include/Nazara/VulkanRenderer/Config.hpp +++ b/include/Nazara/VulkanRenderer/Config.hpp @@ -50,4 +50,4 @@ #define NAZARA_VULKANRENDERER_API #endif -#endif // NAZARA_CONFIG_MODULENAME_HPP +#endif // NAZARA_CONFIG_VULKANRENDERER_HPP diff --git a/include/Nazara/VulkanRenderer/ConfigCheck.hpp b/include/Nazara/VulkanRenderer/ConfigCheck.hpp index 2944ecfb9..fb0f78baa 100644 --- a/include/Nazara/VulkanRenderer/ConfigCheck.hpp +++ b/include/Nazara/VulkanRenderer/ConfigCheck.hpp @@ -4,8 +4,8 @@ #pragma once -#ifndef NAZARA_CONFIG_CHECK_VULKANE_HPP -#define NAZARA_CONFIG_CHECK_VULKANE_HPP +#ifndef NAZARA_CONFIG_CHECK_VULKANRENDERER_HPP +#define NAZARA_CONFIG_CHECK_VULKANRENDERER_HPP /// Ce fichier sert à vérifier la valeur des constantes du fichier Config.hpp @@ -15,8 +15,8 @@ // On force la valeur de MANAGE_MEMORY en mode debug #if defined(NAZARA_DEBUG) && !NAZARA_VULKANRENDERER_MANAGE_MEMORY - #undef NAZARA_MODULENAME_MANAGE_MEMORY - #define NAZARA_MODULENAME_MANAGE_MEMORY 0 + #undef NAZARA_VULKANRENDERER_MANAGE_MEMORY + #define NAZARA_VULKANRENDERER_MANAGE_MEMORY 0 #endif #endif // NAZARA_CONFIG_CHECK_VULKANRENDERER_HPP diff --git a/include/Nazara/VulkanRenderer/Debug.hpp b/include/Nazara/VulkanRenderer/Debug.hpp index 1ef1a1f9a..236950793 100644 --- a/include/Nazara/VulkanRenderer/Debug.hpp +++ b/include/Nazara/VulkanRenderer/Debug.hpp @@ -3,6 +3,6 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include -#if NAZARA_MODULENAME_MANAGE_MEMORY +#if NAZARA_VULKANRENDERER_MANAGE_MEMORY #include #endif diff --git a/include/Nazara/VulkanRenderer/DebugOff.hpp b/include/Nazara/VulkanRenderer/DebugOff.hpp index f80fde373..bf3197f67 100644 --- a/include/Nazara/VulkanRenderer/DebugOff.hpp +++ b/include/Nazara/VulkanRenderer/DebugOff.hpp @@ -3,7 +3,7 @@ // For conditions of distribution and use, see copyright notice in Config.hpp // On suppose que Debug.hpp a déjà été inclus, tout comme Config.hpp -#if NAZARA_MODULENAME_MANAGE_MEMORY +#if NAZARA_VULKANRENDERER_MANAGE_MEMORY #undef delete #undef new #endif diff --git a/include/Nazara/VulkanRenderer/VkRenderWindow.hpp b/include/Nazara/VulkanRenderer/VkRenderWindow.hpp index 48c796288..3df9c1f66 100644 --- a/include/Nazara/VulkanRenderer/VkRenderWindow.hpp +++ b/include/Nazara/VulkanRenderer/VkRenderWindow.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2015 Jérôme Leclercq +// Copyright (C) 2020 Jérôme Leclercq // This file is part of the "Nazara Engine - Vulkan Renderer" // For conditions of distribution and use, see copyright notice in Config.hpp diff --git a/include/Nazara/VulkanRenderer/VulkanBuffer.hpp b/include/Nazara/VulkanRenderer/VulkanBuffer.hpp index cbee94283..ffdf39846 100644 --- a/include/Nazara/VulkanRenderer/VulkanBuffer.hpp +++ b/include/Nazara/VulkanRenderer/VulkanBuffer.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2015 Jérôme Leclercq +// Copyright (C) 2020 Jérôme Leclercq // This file is part of the "Nazara Engine - Vulkan Renderer" // For conditions of distribution and use, see copyright notice in Config.hpp diff --git a/include/Nazara/VulkanRenderer/VulkanDevice.hpp b/include/Nazara/VulkanRenderer/VulkanDevice.hpp index 658a81401..88711ba57 100644 --- a/include/Nazara/VulkanRenderer/VulkanDevice.hpp +++ b/include/Nazara/VulkanRenderer/VulkanDevice.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2015 Jérôme Leclercq +// Copyright (C) 2020 Jérôme Leclercq // This file is part of the "Nazara Engine - Vulkan Renderer" // For conditions of distribution and use, see copyright notice in Config.hpp diff --git a/include/Nazara/VulkanRenderer/VulkanShaderStage.hpp b/include/Nazara/VulkanRenderer/VulkanShaderStage.hpp index 5809ba4e7..f6505b1cb 100644 --- a/include/Nazara/VulkanRenderer/VulkanShaderStage.hpp +++ b/include/Nazara/VulkanRenderer/VulkanShaderStage.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2015 Jérôme Leclercq +// Copyright (C) 2020 Jérôme Leclercq // This file is part of the "Nazara Engine - Vulkan Renderer" // For conditions of distribution and use, see copyright notice in Config.hpp diff --git a/include/Nazara/VulkanRenderer/VulkanSurface.hpp b/include/Nazara/VulkanRenderer/VulkanSurface.hpp index 147753c65..4c3e4e416 100644 --- a/include/Nazara/VulkanRenderer/VulkanSurface.hpp +++ b/include/Nazara/VulkanRenderer/VulkanSurface.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2015 Jérôme Leclercq +// Copyright (C) 2020 Jérôme Leclercq // This file is part of the "Nazara Engine - Vulkan Renderer" // For conditions of distribution and use, see copyright notice in Config.hpp diff --git a/src/Nazara/OpenGLRenderer/OpenGLRenderWindow.cpp b/src/Nazara/OpenGLRenderer/OpenGLRenderWindow.cpp index 317c8d0ff..6ddb9f5bf 100644 --- a/src/Nazara/OpenGLRenderer/OpenGLRenderWindow.cpp +++ b/src/Nazara/OpenGLRenderer/OpenGLRenderWindow.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2015 Jérôme Leclercq +// Copyright (C) 2020 Jérôme Leclercq // This file is part of the "Nazara Engine - Renderer module" // For conditions of distribution and use, see copyright notice in Config.hpp diff --git a/src/Nazara/Platform/SDL2/CursorImpl.cpp b/src/Nazara/Platform/SDL2/CursorImpl.cpp index 60ddd4bd4..5c963ab99 100644 --- a/src/Nazara/Platform/SDL2/CursorImpl.cpp +++ b/src/Nazara/Platform/SDL2/CursorImpl.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2017 Jérôme Leclercq +// Copyright (C) 2020 Jérôme Leclercq // This file is part of the "Nazara Engine - Platform module" // For conditions of distribution and use, see copyright notice in Config.hpp diff --git a/src/Nazara/Platform/SDL2/IconImpl.cpp b/src/Nazara/Platform/SDL2/IconImpl.cpp index 50d1dff42..1ef8c4fd8 100644 --- a/src/Nazara/Platform/SDL2/IconImpl.cpp +++ b/src/Nazara/Platform/SDL2/IconImpl.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2017 Jérôme Leclercq +// Copyright (C) 2020 Jérôme Leclercq // This file is part of the "Nazara Engine - Platform module" // For conditions of distribution and use, see copyright notice in Config.hpp diff --git a/src/Nazara/Platform/SDL2/InputImpl.cpp b/src/Nazara/Platform/SDL2/InputImpl.cpp index 1b609e71c..933d40e60 100644 --- a/src/Nazara/Platform/SDL2/InputImpl.cpp +++ b/src/Nazara/Platform/SDL2/InputImpl.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2017 Jérôme Leclercq +// Copyright (C) 2020 Jérôme Leclercq // This file is part of the "Nazara Engine - Platform module" // For conditions of distribution and use, see copyright notice in Config.hpp diff --git a/src/Nazara/Platform/SDL2/SDLHelper.cpp b/src/Nazara/Platform/SDL2/SDLHelper.cpp index 447e21c69..41f681e94 100644 --- a/src/Nazara/Platform/SDL2/SDLHelper.cpp +++ b/src/Nazara/Platform/SDL2/SDLHelper.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2017 Jérôme Leclercq +// Copyright (C) 2020 Jérôme Leclercq // This file is part of the "Nazara Engine - Platform module" // For conditions of distribution and use, see copyright notice in Config.hpp diff --git a/src/Nazara/Platform/SDL2/SDLHelper.hpp b/src/Nazara/Platform/SDL2/SDLHelper.hpp index 700e111a8..ca39f5b1c 100644 --- a/src/Nazara/Platform/SDL2/SDLHelper.hpp +++ b/src/Nazara/Platform/SDL2/SDLHelper.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2017 Jérôme Leclercq +// Copyright (C) 2020 Jérôme Leclercq // This file is part of the "Nazara Engine - Platform module" // For conditions of distribution and use, see copyright notice in Config.hpp diff --git a/src/Nazara/Platform/SDL2/VideoModeImpl.cpp b/src/Nazara/Platform/SDL2/VideoModeImpl.cpp index a9661c572..621444627 100644 --- a/src/Nazara/Platform/SDL2/VideoModeImpl.cpp +++ b/src/Nazara/Platform/SDL2/VideoModeImpl.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2017 Jérôme Leclercq +// Copyright (C) 2020 Jérôme Leclercq // This file is part of the "Nazara Engine - Platform module" // For conditions of distribution and use, see copyright notice in Config.hpp diff --git a/src/Nazara/Platform/SDL2/WindowImpl.cpp b/src/Nazara/Platform/SDL2/WindowImpl.cpp index 20cd731df..6ca5857d3 100644 --- a/src/Nazara/Platform/SDL2/WindowImpl.cpp +++ b/src/Nazara/Platform/SDL2/WindowImpl.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2017 Jérôme Leclercq +// Copyright (C) 2020 Jérôme Leclercq // This file is part of the "Nazara Engine - Platform module" // For conditions of distribution and use, see copyright notice in Config.hpp diff --git a/src/Nazara/Renderer/CommandBuffer.cpp b/src/Nazara/Renderer/CommandBuffer.cpp index c93ff6fee..fe876c0c6 100644 --- a/src/Nazara/Renderer/CommandBuffer.cpp +++ b/src/Nazara/Renderer/CommandBuffer.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2015 Jérôme Leclercq +// Copyright (C) 2020 Jérôme Leclercq // This file is part of the "Nazara Engine - Renderer module" // For conditions of distribution and use, see copyright notice in Config.hpp diff --git a/src/Nazara/Renderer/CommandBufferBuilder.cpp b/src/Nazara/Renderer/CommandBufferBuilder.cpp index e45605d48..0d7d16410 100644 --- a/src/Nazara/Renderer/CommandBufferBuilder.cpp +++ b/src/Nazara/Renderer/CommandBufferBuilder.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2015 Jérôme Leclercq +// Copyright (C) 2020 Jérôme Leclercq // This file is part of the "Nazara Engine - Renderer module" // For conditions of distribution and use, see copyright notice in Config.hpp diff --git a/src/Nazara/Renderer/CommandPool.cpp b/src/Nazara/Renderer/CommandPool.cpp index 6d0b412e4..342210e77 100644 --- a/src/Nazara/Renderer/CommandPool.cpp +++ b/src/Nazara/Renderer/CommandPool.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2015 Jérôme Leclercq +// Copyright (C) 2020 Jérôme Leclercq // This file is part of the "Nazara Engine - Renderer module" // For conditions of distribution and use, see copyright notice in Config.hpp diff --git a/src/Nazara/Renderer/Framebuffer.cpp b/src/Nazara/Renderer/Framebuffer.cpp index 4fff69eb4..220215d83 100644 --- a/src/Nazara/Renderer/Framebuffer.cpp +++ b/src/Nazara/Renderer/Framebuffer.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2015 Jérôme Leclercq +// Copyright (C) 2020 Jérôme Leclercq // This file is part of the "Nazara Engine - Renderer module" // For conditions of distribution and use, see copyright notice in Config.hpp diff --git a/src/Nazara/Renderer/RenderBuffer.cpp b/src/Nazara/Renderer/RenderBuffer.cpp index 4526d79f3..96f4bf05d 100644 --- a/src/Nazara/Renderer/RenderBuffer.cpp +++ b/src/Nazara/Renderer/RenderBuffer.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2015 Jérôme Leclercq +// Copyright (C) 2020 Jérôme Leclercq // This file is part of the "Nazara Engine - Renderer module" // For conditions of distribution and use, see copyright notice in Config.hpp diff --git a/src/Nazara/Renderer/RenderDevice.cpp b/src/Nazara/Renderer/RenderDevice.cpp index 2ef01974a..a4d377db6 100644 --- a/src/Nazara/Renderer/RenderDevice.cpp +++ b/src/Nazara/Renderer/RenderDevice.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2015 Jérôme Leclercq +// Copyright (C) 2020 Jérôme Leclercq // This file is part of the "Nazara Engine - Renderer module" // For conditions of distribution and use, see copyright notice in Config.hpp diff --git a/src/Nazara/Renderer/RenderImage.cpp b/src/Nazara/Renderer/RenderImage.cpp index 9724386e2..68ba064c7 100644 --- a/src/Nazara/Renderer/RenderImage.cpp +++ b/src/Nazara/Renderer/RenderImage.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2015 Jérôme Leclercq +// Copyright (C) 2020 Jérôme Leclercq // This file is part of the "Nazara Engine - Renderer module" // For conditions of distribution and use, see copyright notice in Config.hpp diff --git a/src/Nazara/Renderer/RenderPass.cpp b/src/Nazara/Renderer/RenderPass.cpp index b6b870c72..aeae04fdb 100644 --- a/src/Nazara/Renderer/RenderPass.cpp +++ b/src/Nazara/Renderer/RenderPass.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2015 Jérôme Leclercq +// Copyright (C) 2020 Jérôme Leclercq // This file is part of the "Nazara Engine - Renderer module" // For conditions of distribution and use, see copyright notice in Config.hpp diff --git a/src/Nazara/Renderer/RenderPipeline.cpp b/src/Nazara/Renderer/RenderPipeline.cpp index c5faed12b..e8b585368 100644 --- a/src/Nazara/Renderer/RenderPipeline.cpp +++ b/src/Nazara/Renderer/RenderPipeline.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2015 Jérôme Leclercq +// Copyright (C) 2020 Jérôme Leclercq // This file is part of the "Nazara Engine - Renderer module" // For conditions of distribution and use, see copyright notice in Config.hpp diff --git a/src/Nazara/Renderer/RenderPipelineLayout.cpp b/src/Nazara/Renderer/RenderPipelineLayout.cpp index ec26fad08..b9a357448 100644 --- a/src/Nazara/Renderer/RenderPipelineLayout.cpp +++ b/src/Nazara/Renderer/RenderPipelineLayout.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2015 Jérôme Leclercq +// Copyright (C) 2020 Jérôme Leclercq // This file is part of the "Nazara Engine - Renderer module" // For conditions of distribution and use, see copyright notice in Config.hpp diff --git a/src/Nazara/Renderer/RenderSurface.cpp b/src/Nazara/Renderer/RenderSurface.cpp index e48c69f6c..6fe2c4026 100644 --- a/src/Nazara/Renderer/RenderSurface.cpp +++ b/src/Nazara/Renderer/RenderSurface.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2015 Jérôme Leclercq +// Copyright (C) 2020 Jérôme Leclercq // This file is part of the "Nazara Engine - Renderer module" // For conditions of distribution and use, see copyright notice in Config.hpp diff --git a/src/Nazara/Renderer/RendererImpl.cpp b/src/Nazara/Renderer/RendererImpl.cpp index f674e1098..9d16ff2fb 100644 --- a/src/Nazara/Renderer/RendererImpl.cpp +++ b/src/Nazara/Renderer/RendererImpl.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2015 Jérôme Leclercq +// Copyright (C) 2020 Jérôme Leclercq // This file is part of the "Nazara Engine - Renderer module" // For conditions of distribution and use, see copyright notice in Config.hpp diff --git a/src/Nazara/Renderer/RendererWindowImpl.cpp b/src/Nazara/Renderer/RendererWindowImpl.cpp index b1a2b946f..c677d8e34 100644 --- a/src/Nazara/Renderer/RendererWindowImpl.cpp +++ b/src/Nazara/Renderer/RendererWindowImpl.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2015 Jérôme Leclercq +// Copyright (C) 2020 Jérôme Leclercq // This file is part of the "Nazara Engine - Renderer module" // For conditions of distribution and use, see copyright notice in Config.hpp diff --git a/src/Nazara/Renderer/ShaderBinding.cpp b/src/Nazara/Renderer/ShaderBinding.cpp index 240d848c6..ee78fd716 100644 --- a/src/Nazara/Renderer/ShaderBinding.cpp +++ b/src/Nazara/Renderer/ShaderBinding.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2015 Jérôme Leclercq +// Copyright (C) 2020 Jérôme Leclercq // This file is part of the "Nazara Engine - Renderer module" // For conditions of distribution and use, see copyright notice in Config.hpp diff --git a/src/Nazara/Renderer/ShaderStageImpl.cpp b/src/Nazara/Renderer/ShaderStageImpl.cpp index 62ae7a7ed..dd3e48a63 100644 --- a/src/Nazara/Renderer/ShaderStageImpl.cpp +++ b/src/Nazara/Renderer/ShaderStageImpl.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2015 Jérôme Leclercq +// Copyright (C) 2020 Jérôme Leclercq // This file is part of the "Nazara Engine - Renderer module" // For conditions of distribution and use, see copyright notice in Config.hpp diff --git a/src/Nazara/Renderer/Texture.cpp b/src/Nazara/Renderer/Texture.cpp index 6a3e4b1fb..78e72e65c 100644 --- a/src/Nazara/Renderer/Texture.cpp +++ b/src/Nazara/Renderer/Texture.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2015 Jérôme Leclercq +// Copyright (C) 2020 Jérôme Leclercq // This file is part of the "Nazara Engine - Renderer module" // For conditions of distribution and use, see copyright notice in Config.hpp diff --git a/src/Nazara/Renderer/TextureSampler.cpp b/src/Nazara/Renderer/TextureSampler.cpp index e8571e775..f39f2dc73 100644 --- a/src/Nazara/Renderer/TextureSampler.cpp +++ b/src/Nazara/Renderer/TextureSampler.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2015 Jérôme Leclercq +// Copyright (C) 2020 Jérôme Leclercq // This file is part of the "Nazara Engine - Renderer module" // For conditions of distribution and use, see copyright notice in Config.hpp diff --git a/src/Nazara/Utility/FieldOffsets.cpp b/src/Nazara/Utility/FieldOffsets.cpp index 76cb50e71..5e9f229bb 100644 --- a/src/Nazara/Utility/FieldOffsets.cpp +++ b/src/Nazara/Utility/FieldOffsets.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2019 Jérôme Leclercq +// Copyright (C) 2020 Jérôme Leclercq // This file is part of the "Nazara Engine - Utility module" // For conditions of distribution and use, see copyright notice in Config.hpp diff --git a/src/Nazara/Utility/Formats/DDSConstants.hpp b/src/Nazara/Utility/Formats/DDSConstants.hpp index 7233e7497..81be1798e 100644 --- a/src/Nazara/Utility/Formats/DDSConstants.hpp +++ b/src/Nazara/Utility/Formats/DDSConstants.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2009 Cruden BV - 2014 Jérôme Leclercq +// Copyright (C) 2009 Cruden BV - 2020 Jérôme Leclercq // This file is part of the "Nazara Engine - Utility module" // For conditions of distribution and use, see copyright notice in Config.hpp diff --git a/src/Nazara/VulkanRenderer/VkRenderWindow.cpp b/src/Nazara/VulkanRenderer/VkRenderWindow.cpp index 6f53df0c1..bfba96bc1 100644 --- a/src/Nazara/VulkanRenderer/VkRenderWindow.cpp +++ b/src/Nazara/VulkanRenderer/VkRenderWindow.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2015 Jérôme Leclercq +// Copyright (C) 2020 Jérôme Leclercq // This file is part of the "Nazara Engine - Renderer module" // For conditions of distribution and use, see copyright notice in Config.hpp From 608b80981d7667ea464311d752c52c18306e5dfd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Tue, 11 Aug 2020 00:13:00 +0200 Subject: [PATCH 091/105] Fix OpenGL & Vulkan renderers --- build/scripts/tools/openglrenderer.lua | 1 + build/scripts/tools/vulkanrenderer.lua | 1 + src/Nazara/OpenGLRenderer/OpenGLShaderStage.cpp | 6 +++--- src/Nazara/VulkanRenderer/VulkanShaderStage.cpp | 6 +++--- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/build/scripts/tools/openglrenderer.lua b/build/scripts/tools/openglrenderer.lua index 32392739c..48b198327 100644 --- a/build/scripts/tools/openglrenderer.lua +++ b/build/scripts/tools/openglrenderer.lua @@ -27,6 +27,7 @@ TOOL.Files = { TOOL.Libraries = { "NazaraCore", "NazaraRenderer", + "NazaraShader", "NazaraUtility" } diff --git a/build/scripts/tools/vulkanrenderer.lua b/build/scripts/tools/vulkanrenderer.lua index 6e6a5bed2..4e7f2be10 100644 --- a/build/scripts/tools/vulkanrenderer.lua +++ b/build/scripts/tools/vulkanrenderer.lua @@ -28,6 +28,7 @@ TOOL.Files = { TOOL.Libraries = { "NazaraCore", "NazaraRenderer", + "NazaraShader", "NazaraUtility" } diff --git a/src/Nazara/OpenGLRenderer/OpenGLShaderStage.cpp b/src/Nazara/OpenGLRenderer/OpenGLShaderStage.cpp index 7f6e92a34..068ef9634 100644 --- a/src/Nazara/OpenGLRenderer/OpenGLShaderStage.cpp +++ b/src/Nazara/OpenGLRenderer/OpenGLShaderStage.cpp @@ -6,9 +6,9 @@ #include #include #include -#include -#include -#include +#include +#include +#include #include #include diff --git a/src/Nazara/VulkanRenderer/VulkanShaderStage.cpp b/src/Nazara/VulkanRenderer/VulkanShaderStage.cpp index c0b510dd8..9459ccfe3 100644 --- a/src/Nazara/VulkanRenderer/VulkanShaderStage.cpp +++ b/src/Nazara/VulkanRenderer/VulkanShaderStage.cpp @@ -3,9 +3,9 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include -#include -#include -#include +#include +#include +#include #include namespace Nz From 581a5344e6885c2e73b32e38632e25c2e4ca70b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Tue, 11 Aug 2020 00:15:34 +0200 Subject: [PATCH 092/105] OpenGLRenderer: Add wglSwapIntervalEXT --- include/Nazara/OpenGLRenderer/Wrapper/Win32/WGLFunctions.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/Nazara/OpenGLRenderer/Wrapper/Win32/WGLFunctions.hpp b/include/Nazara/OpenGLRenderer/Wrapper/Win32/WGLFunctions.hpp index d21480e96..655373ed8 100644 --- a/include/Nazara/OpenGLRenderer/Wrapper/Win32/WGLFunctions.hpp +++ b/include/Nazara/OpenGLRenderer/Wrapper/Win32/WGLFunctions.hpp @@ -38,6 +38,10 @@ extBegin(WGL_EXT_extensions_string) \ extFunc(wglGetExtensionsStringEXT, PFNWGLGETEXTENSIONSSTRINGEXTPROC) \ extEnd() \ + \ + extBegin(WGL_EXT_swap_control) \ + extFunc(wglSwapIntervalEXT, PFNWGLSWAPINTERVALEXTPROC) \ + extEnd() #define NAZARA_OPENGLRENDERER_FOREACH_GDI32_FUNC(func) \ func(ChoosePixelFormat, PFNCHOOSEPIXELFORMATPROC) \ From 73e88a2573118cb1863b86800b24eb75f0a77665 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Mon, 17 Aug 2020 23:59:08 +0200 Subject: [PATCH 093/105] Add Spir-V header/source generator --- build/scripts/actions/spirv.lua | 223 + include/Nazara/Shader/SpirvData.hpp | 1382 +++ src/Nazara/Shader/SpirvData.cpp | 11862 ++++++++++++++++++++++++++ 3 files changed, 13467 insertions(+) create mode 100644 build/scripts/actions/spirv.lua create mode 100644 include/Nazara/Shader/SpirvData.hpp create mode 100644 src/Nazara/Shader/SpirvData.cpp diff --git a/build/scripts/actions/spirv.lua b/build/scripts/actions/spirv.lua new file mode 100644 index 000000000..b47c81fa9 --- /dev/null +++ b/build/scripts/actions/spirv.lua @@ -0,0 +1,223 @@ +ACTION.Name = "UpdateSpirV" +ACTION.Description = "Download and parse the SpirV grammar and generate a .cpp file for it" + +local spirvGrammarURI = "https://raw.githubusercontent.com/KhronosGroup/SPIRV-Headers/master/include/spirv/unified1/spirv.core.grammar.json" + +ACTION.Function = function() + io.write("Downloading Spir-V grammar... ") + local content, resultStr, resultCode = http.get(spirvGrammarURI, { + headers = { "From: Premake", "Referer: Premake" } + }) + + if (resultCode ~= 200) then + error("Failed to download SpirV grammar: " .. resultStr) + end + + print("Done") + + local result, err = json.decode(content) + assert(result, err) + + local instructions = {} + local instructionById = {} + for _, instruction in pairs(result.instructions) do + local duplicateId = instructionById[instruction.opcode] + if (duplicateId == nil) then + table.insert(instructions, instruction) + instructionById[instruction.opcode] = #instructions + else + instructions[duplicateId] = instruction + end + end + + local operands = {} + local operandByInstruction = {} + for _, instruction in pairs(instructions) do + if (instruction.operands) then + local firstId = #operands + local operandCount = #instruction.operands + for _, operand in pairs(instruction.operands) do + table.insert(operands, operand) + end + + operandByInstruction[instruction.opcode] = { firstId = firstId, count = operandCount } + end + end + + local headerFile = io.open("../include/Nazara/Shader/SpirvData.hpp", "w+") + assert(headerFile, "failed to open Spir-V header") + + headerFile:write([[ +// Copyright (C) ]] .. os.date("%Y") .. [[ 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" + +// This file was generated automatically, please do not edit + +#pragma once + +#ifndef NAZARA_SPIRVDATA_HPP +#define NAZARA_SPIRVDATA_HPP + +#include +#include + +namespace Nz +{ +]]) + + -- SpirV operations + headerFile:write([[ + enum class SpirvOp + { +]]) + + for _, instruction in pairs(result.instructions) do + headerFile:write("\t\t" .. instruction.opname .. " = " .. instruction.opcode .. ",\n") + end + +headerFile:write([[ + }; + +]]) + + -- SpirV operands + headerFile:write([[ + enum class SpirvOperandKind + { +]]) + + for _, operand in pairs(result.operand_kinds) do + headerFile:write("\t\t" .. operand.kind .. ",\n") + end + + headerFile:write([[ + }; + +]]) + + -- SpirV enums + for _, operand in pairs(result.operand_kinds) do + if (operand.category == "ValueEnum") then + headerFile:write([[ + enum class Spirv]] .. operand.kind .. [[ + + { +]]) + + for _, enumerant in pairs(operand.enumerants) do + local eName = enumerant.enumerant:match("^%d") and operand.kind .. enumerant.enumerant or enumerant.enumerant + headerFile:write([[ + ]] .. eName .. [[ = ]] .. enumerant.value .. [[, +]]) + end + + headerFile:write([[ + }; + +]]) + end + end + + -- Struct + headerFile:write([[ + struct SpirvInstruction + { + struct Operand + { + SpirvOperandKind kind; + const char* name; + }; + + SpirvOp op; + const char* name; + const Operand* operands; + std::size_t minOperandCount; + }; + +]]) + + -- Functions signatures + headerFile:write([[ + NAZARA_SHADER_API const SpirvInstruction* GetInstructionData(UInt16 op); +]]) + +headerFile:write([[ +} + +#endif +]]) + + local sourceFile = io.open("../src/Nazara/Shader/SpirvData.cpp", "w+") + assert(sourceFile, "failed to open Spir-V source") + + sourceFile:write([[ +// Copyright (C) ]] .. os.date("%Y") .. [[ 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" + +// This file was generated automatically, please do not edit + +#include +#include +#include +#include + +namespace Nz +{ + static constexpr std::array s_operands = { + { +]]) + for _, operand in pairs(operands) do + sourceFile:write([[ + { + SpirvOperandKind::]] .. operand.kind .. [[, + R"(]] .. (operand.name or operand.kind) .. [[)" + }, +]]) + end + + sourceFile:write([[ + } + }; + + static std::array s_instructions = { + { +]]) + + for _, instruction in pairs(instructions) do + local opByInstruction = operandByInstruction[instruction.opcode] + + sourceFile:write([[ + { + SpirvOp::]] .. instruction.opname .. [[, + R"(]] .. instruction.opname .. [[)", + ]] .. (opByInstruction and "&s_operands[" .. opByInstruction.firstId .. "]" or "nullptr") .. [[, + ]] .. (opByInstruction and opByInstruction.count or "0") .. [[, + }, +]]) + end + + sourceFile:write([[ + } + }; + +]]) + + -- Operand to string + sourceFile:write([[ + const SpirvInstruction* GetInstructionData(UInt16 op) + { + auto it = std::lower_bound(std::begin(s_instructions), std::end(s_instructions), op, [](const SpirvInstruction& inst, UInt16 op) { return UInt16(inst.op) < op; }); + if (it != std::end(s_instructions) && UInt16(it->op) == op) + return &*it; + else + return nullptr; + } +]]) + + sourceFile:write([[ +} +]]) + +end \ No newline at end of file diff --git a/include/Nazara/Shader/SpirvData.hpp b/include/Nazara/Shader/SpirvData.hpp new file mode 100644 index 000000000..eccc122ad --- /dev/null +++ b/include/Nazara/Shader/SpirvData.hpp @@ -0,0 +1,1382 @@ +// 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" + +// This file was generated automatically, please do not edit + +#pragma once + +#ifndef NAZARA_SPIRVDATA_HPP +#define NAZARA_SPIRVDATA_HPP + +#include +#include + +namespace Nz +{ + enum class SpirvOp + { + OpNop = 0, + OpUndef = 1, + OpSourceContinued = 2, + OpSource = 3, + OpSourceExtension = 4, + OpName = 5, + OpMemberName = 6, + OpString = 7, + OpLine = 8, + OpExtension = 10, + OpExtInstImport = 11, + OpExtInst = 12, + OpMemoryModel = 14, + OpEntryPoint = 15, + OpExecutionMode = 16, + OpCapability = 17, + OpTypeVoid = 19, + OpTypeBool = 20, + OpTypeInt = 21, + OpTypeFloat = 22, + OpTypeVector = 23, + OpTypeMatrix = 24, + OpTypeImage = 25, + OpTypeSampler = 26, + OpTypeSampledImage = 27, + OpTypeArray = 28, + OpTypeRuntimeArray = 29, + OpTypeStruct = 30, + OpTypeOpaque = 31, + OpTypePointer = 32, + OpTypeFunction = 33, + OpTypeEvent = 34, + OpTypeDeviceEvent = 35, + OpTypeReserveId = 36, + OpTypeQueue = 37, + OpTypePipe = 38, + OpTypeForwardPointer = 39, + OpConstantTrue = 41, + OpConstantFalse = 42, + OpConstant = 43, + OpConstantComposite = 44, + OpConstantSampler = 45, + OpConstantNull = 46, + OpSpecConstantTrue = 48, + OpSpecConstantFalse = 49, + OpSpecConstant = 50, + OpSpecConstantComposite = 51, + OpSpecConstantOp = 52, + OpFunction = 54, + OpFunctionParameter = 55, + OpFunctionEnd = 56, + OpFunctionCall = 57, + OpVariable = 59, + OpImageTexelPointer = 60, + OpLoad = 61, + OpStore = 62, + OpCopyMemory = 63, + OpCopyMemorySized = 64, + OpAccessChain = 65, + OpInBoundsAccessChain = 66, + OpPtrAccessChain = 67, + OpArrayLength = 68, + OpGenericPtrMemSemantics = 69, + OpInBoundsPtrAccessChain = 70, + OpDecorate = 71, + OpMemberDecorate = 72, + OpDecorationGroup = 73, + OpGroupDecorate = 74, + OpGroupMemberDecorate = 75, + OpVectorExtractDynamic = 77, + OpVectorInsertDynamic = 78, + OpVectorShuffle = 79, + OpCompositeConstruct = 80, + OpCompositeExtract = 81, + OpCompositeInsert = 82, + OpCopyObject = 83, + OpTranspose = 84, + OpSampledImage = 86, + OpImageSampleImplicitLod = 87, + OpImageSampleExplicitLod = 88, + OpImageSampleDrefImplicitLod = 89, + OpImageSampleDrefExplicitLod = 90, + OpImageSampleProjImplicitLod = 91, + OpImageSampleProjExplicitLod = 92, + OpImageSampleProjDrefImplicitLod = 93, + OpImageSampleProjDrefExplicitLod = 94, + OpImageFetch = 95, + OpImageGather = 96, + OpImageDrefGather = 97, + OpImageRead = 98, + OpImageWrite = 99, + OpImage = 100, + OpImageQueryFormat = 101, + OpImageQueryOrder = 102, + OpImageQuerySizeLod = 103, + OpImageQuerySize = 104, + OpImageQueryLod = 105, + OpImageQueryLevels = 106, + OpImageQuerySamples = 107, + OpConvertFToU = 109, + OpConvertFToS = 110, + OpConvertSToF = 111, + OpConvertUToF = 112, + OpUConvert = 113, + OpSConvert = 114, + OpFConvert = 115, + OpQuantizeToF16 = 116, + OpConvertPtrToU = 117, + OpSatConvertSToU = 118, + OpSatConvertUToS = 119, + OpConvertUToPtr = 120, + OpPtrCastToGeneric = 121, + OpGenericCastToPtr = 122, + OpGenericCastToPtrExplicit = 123, + OpBitcast = 124, + OpSNegate = 126, + OpFNegate = 127, + OpIAdd = 128, + OpFAdd = 129, + OpISub = 130, + OpFSub = 131, + OpIMul = 132, + OpFMul = 133, + OpUDiv = 134, + OpSDiv = 135, + OpFDiv = 136, + OpUMod = 137, + OpSRem = 138, + OpSMod = 139, + OpFRem = 140, + OpFMod = 141, + OpVectorTimesScalar = 142, + OpMatrixTimesScalar = 143, + OpVectorTimesMatrix = 144, + OpMatrixTimesVector = 145, + OpMatrixTimesMatrix = 146, + OpOuterProduct = 147, + OpDot = 148, + OpIAddCarry = 149, + OpISubBorrow = 150, + OpUMulExtended = 151, + OpSMulExtended = 152, + OpAny = 154, + OpAll = 155, + OpIsNan = 156, + OpIsInf = 157, + OpIsFinite = 158, + OpIsNormal = 159, + OpSignBitSet = 160, + OpLessOrGreater = 161, + OpOrdered = 162, + OpUnordered = 163, + OpLogicalEqual = 164, + OpLogicalNotEqual = 165, + OpLogicalOr = 166, + OpLogicalAnd = 167, + OpLogicalNot = 168, + OpSelect = 169, + OpIEqual = 170, + OpINotEqual = 171, + OpUGreaterThan = 172, + OpSGreaterThan = 173, + OpUGreaterThanEqual = 174, + OpSGreaterThanEqual = 175, + OpULessThan = 176, + OpSLessThan = 177, + OpULessThanEqual = 178, + OpSLessThanEqual = 179, + OpFOrdEqual = 180, + OpFUnordEqual = 181, + OpFOrdNotEqual = 182, + OpFUnordNotEqual = 183, + OpFOrdLessThan = 184, + OpFUnordLessThan = 185, + OpFOrdGreaterThan = 186, + OpFUnordGreaterThan = 187, + OpFOrdLessThanEqual = 188, + OpFUnordLessThanEqual = 189, + OpFOrdGreaterThanEqual = 190, + OpFUnordGreaterThanEqual = 191, + OpShiftRightLogical = 194, + OpShiftRightArithmetic = 195, + OpShiftLeftLogical = 196, + OpBitwiseOr = 197, + OpBitwiseXor = 198, + OpBitwiseAnd = 199, + OpNot = 200, + OpBitFieldInsert = 201, + OpBitFieldSExtract = 202, + OpBitFieldUExtract = 203, + OpBitReverse = 204, + OpBitCount = 205, + OpDPdx = 207, + OpDPdy = 208, + OpFwidth = 209, + OpDPdxFine = 210, + OpDPdyFine = 211, + OpFwidthFine = 212, + OpDPdxCoarse = 213, + OpDPdyCoarse = 214, + OpFwidthCoarse = 215, + OpEmitVertex = 218, + OpEndPrimitive = 219, + OpEmitStreamVertex = 220, + OpEndStreamPrimitive = 221, + OpControlBarrier = 224, + OpMemoryBarrier = 225, + OpAtomicLoad = 227, + OpAtomicStore = 228, + OpAtomicExchange = 229, + OpAtomicCompareExchange = 230, + OpAtomicCompareExchangeWeak = 231, + OpAtomicIIncrement = 232, + OpAtomicIDecrement = 233, + OpAtomicIAdd = 234, + OpAtomicISub = 235, + OpAtomicSMin = 236, + OpAtomicUMin = 237, + OpAtomicSMax = 238, + OpAtomicUMax = 239, + OpAtomicAnd = 240, + OpAtomicOr = 241, + OpAtomicXor = 242, + OpPhi = 245, + OpLoopMerge = 246, + OpSelectionMerge = 247, + OpLabel = 248, + OpBranch = 249, + OpBranchConditional = 250, + OpSwitch = 251, + OpKill = 252, + OpReturn = 253, + OpReturnValue = 254, + OpUnreachable = 255, + OpLifetimeStart = 256, + OpLifetimeStop = 257, + OpGroupAsyncCopy = 259, + OpGroupWaitEvents = 260, + OpGroupAll = 261, + OpGroupAny = 262, + OpGroupBroadcast = 263, + OpGroupIAdd = 264, + OpGroupFAdd = 265, + OpGroupFMin = 266, + OpGroupUMin = 267, + OpGroupSMin = 268, + OpGroupFMax = 269, + OpGroupUMax = 270, + OpGroupSMax = 271, + OpReadPipe = 274, + OpWritePipe = 275, + OpReservedReadPipe = 276, + OpReservedWritePipe = 277, + OpReserveReadPipePackets = 278, + OpReserveWritePipePackets = 279, + OpCommitReadPipe = 280, + OpCommitWritePipe = 281, + OpIsValidReserveId = 282, + OpGetNumPipePackets = 283, + OpGetMaxPipePackets = 284, + OpGroupReserveReadPipePackets = 285, + OpGroupReserveWritePipePackets = 286, + OpGroupCommitReadPipe = 287, + OpGroupCommitWritePipe = 288, + OpEnqueueMarker = 291, + OpEnqueueKernel = 292, + OpGetKernelNDrangeSubGroupCount = 293, + OpGetKernelNDrangeMaxSubGroupSize = 294, + OpGetKernelWorkGroupSize = 295, + OpGetKernelPreferredWorkGroupSizeMultiple = 296, + OpRetainEvent = 297, + OpReleaseEvent = 298, + OpCreateUserEvent = 299, + OpIsValidEvent = 300, + OpSetUserEventStatus = 301, + OpCaptureEventProfilingInfo = 302, + OpGetDefaultQueue = 303, + OpBuildNDRange = 304, + OpImageSparseSampleImplicitLod = 305, + OpImageSparseSampleExplicitLod = 306, + OpImageSparseSampleDrefImplicitLod = 307, + OpImageSparseSampleDrefExplicitLod = 308, + OpImageSparseSampleProjImplicitLod = 309, + OpImageSparseSampleProjExplicitLod = 310, + OpImageSparseSampleProjDrefImplicitLod = 311, + OpImageSparseSampleProjDrefExplicitLod = 312, + OpImageSparseFetch = 313, + OpImageSparseGather = 314, + OpImageSparseDrefGather = 315, + OpImageSparseTexelsResident = 316, + OpNoLine = 317, + OpAtomicFlagTestAndSet = 318, + OpAtomicFlagClear = 319, + OpImageSparseRead = 320, + OpSizeOf = 321, + OpTypePipeStorage = 322, + OpConstantPipeStorage = 323, + OpCreatePipeFromPipeStorage = 324, + OpGetKernelLocalSizeForSubgroupCount = 325, + OpGetKernelMaxNumSubgroups = 326, + OpTypeNamedBarrier = 327, + OpNamedBarrierInitialize = 328, + OpMemoryNamedBarrier = 329, + OpModuleProcessed = 330, + OpExecutionModeId = 331, + OpDecorateId = 332, + OpGroupNonUniformElect = 333, + OpGroupNonUniformAll = 334, + OpGroupNonUniformAny = 335, + OpGroupNonUniformAllEqual = 336, + OpGroupNonUniformBroadcast = 337, + OpGroupNonUniformBroadcastFirst = 338, + OpGroupNonUniformBallot = 339, + OpGroupNonUniformInverseBallot = 340, + OpGroupNonUniformBallotBitExtract = 341, + OpGroupNonUniformBallotBitCount = 342, + OpGroupNonUniformBallotFindLSB = 343, + OpGroupNonUniformBallotFindMSB = 344, + OpGroupNonUniformShuffle = 345, + OpGroupNonUniformShuffleXor = 346, + OpGroupNonUniformShuffleUp = 347, + OpGroupNonUniformShuffleDown = 348, + OpGroupNonUniformIAdd = 349, + OpGroupNonUniformFAdd = 350, + OpGroupNonUniformIMul = 351, + OpGroupNonUniformFMul = 352, + OpGroupNonUniformSMin = 353, + OpGroupNonUniformUMin = 354, + OpGroupNonUniformFMin = 355, + OpGroupNonUniformSMax = 356, + OpGroupNonUniformUMax = 357, + OpGroupNonUniformFMax = 358, + OpGroupNonUniformBitwiseAnd = 359, + OpGroupNonUniformBitwiseOr = 360, + OpGroupNonUniformBitwiseXor = 361, + OpGroupNonUniformLogicalAnd = 362, + OpGroupNonUniformLogicalOr = 363, + OpGroupNonUniformLogicalXor = 364, + OpGroupNonUniformQuadBroadcast = 365, + OpGroupNonUniformQuadSwap = 366, + OpCopyLogical = 400, + OpPtrEqual = 401, + OpPtrNotEqual = 402, + OpPtrDiff = 403, + OpTerminateInvocation = 4416, + OpSubgroupBallotKHR = 4421, + OpSubgroupFirstInvocationKHR = 4422, + OpSubgroupAllKHR = 4428, + OpSubgroupAnyKHR = 4429, + OpSubgroupAllEqualKHR = 4430, + OpSubgroupReadInvocationKHR = 4432, + OpTypeRayQueryProvisionalKHR = 4472, + OpRayQueryInitializeKHR = 4473, + OpRayQueryTerminateKHR = 4474, + OpRayQueryGenerateIntersectionKHR = 4475, + OpRayQueryConfirmIntersectionKHR = 4476, + OpRayQueryProceedKHR = 4477, + OpRayQueryGetIntersectionTypeKHR = 4479, + OpGroupIAddNonUniformAMD = 5000, + OpGroupFAddNonUniformAMD = 5001, + OpGroupFMinNonUniformAMD = 5002, + OpGroupUMinNonUniformAMD = 5003, + OpGroupSMinNonUniformAMD = 5004, + OpGroupFMaxNonUniformAMD = 5005, + OpGroupUMaxNonUniformAMD = 5006, + OpGroupSMaxNonUniformAMD = 5007, + OpFragmentMaskFetchAMD = 5011, + OpFragmentFetchAMD = 5012, + OpReadClockKHR = 5056, + OpImageSampleFootprintNV = 5283, + OpGroupNonUniformPartitionNV = 5296, + OpWritePackedPrimitiveIndices4x8NV = 5299, + OpReportIntersectionNV = 5334, + OpReportIntersectionKHR = 5334, + OpIgnoreIntersectionNV = 5335, + OpIgnoreIntersectionKHR = 5335, + OpTerminateRayNV = 5336, + OpTerminateRayKHR = 5336, + OpTraceNV = 5337, + OpTraceRayKHR = 5337, + OpTypeAccelerationStructureNV = 5341, + OpTypeAccelerationStructureKHR = 5341, + OpExecuteCallableNV = 5344, + OpExecuteCallableKHR = 5344, + OpTypeCooperativeMatrixNV = 5358, + OpCooperativeMatrixLoadNV = 5359, + OpCooperativeMatrixStoreNV = 5360, + OpCooperativeMatrixMulAddNV = 5361, + OpCooperativeMatrixLengthNV = 5362, + OpBeginInvocationInterlockEXT = 5364, + OpEndInvocationInterlockEXT = 5365, + OpDemoteToHelperInvocationEXT = 5380, + OpIsHelperInvocationEXT = 5381, + OpSubgroupShuffleINTEL = 5571, + OpSubgroupShuffleDownINTEL = 5572, + OpSubgroupShuffleUpINTEL = 5573, + OpSubgroupShuffleXorINTEL = 5574, + OpSubgroupBlockReadINTEL = 5575, + OpSubgroupBlockWriteINTEL = 5576, + OpSubgroupImageBlockReadINTEL = 5577, + OpSubgroupImageBlockWriteINTEL = 5578, + OpSubgroupImageMediaBlockReadINTEL = 5580, + OpSubgroupImageMediaBlockWriteINTEL = 5581, + OpUCountLeadingZerosINTEL = 5585, + OpUCountTrailingZerosINTEL = 5586, + OpAbsISubINTEL = 5587, + OpAbsUSubINTEL = 5588, + OpIAddSatINTEL = 5589, + OpUAddSatINTEL = 5590, + OpIAverageINTEL = 5591, + OpUAverageINTEL = 5592, + OpIAverageRoundedINTEL = 5593, + OpUAverageRoundedINTEL = 5594, + OpISubSatINTEL = 5595, + OpUSubSatINTEL = 5596, + OpIMul32x16INTEL = 5597, + OpUMul32x16INTEL = 5598, + OpFunctionPointerINTEL = 5600, + OpFunctionPointerCallINTEL = 5601, + OpDecorateString = 5632, + OpDecorateStringGOOGLE = 5632, + OpMemberDecorateString = 5633, + OpMemberDecorateStringGOOGLE = 5633, + OpVmeImageINTEL = 5699, + OpTypeVmeImageINTEL = 5700, + OpTypeAvcImePayloadINTEL = 5701, + OpTypeAvcRefPayloadINTEL = 5702, + OpTypeAvcSicPayloadINTEL = 5703, + OpTypeAvcMcePayloadINTEL = 5704, + OpTypeAvcMceResultINTEL = 5705, + OpTypeAvcImeResultINTEL = 5706, + OpTypeAvcImeResultSingleReferenceStreamoutINTEL = 5707, + OpTypeAvcImeResultDualReferenceStreamoutINTEL = 5708, + OpTypeAvcImeSingleReferenceStreaminINTEL = 5709, + OpTypeAvcImeDualReferenceStreaminINTEL = 5710, + OpTypeAvcRefResultINTEL = 5711, + OpTypeAvcSicResultINTEL = 5712, + OpSubgroupAvcMceGetDefaultInterBaseMultiReferencePenaltyINTEL = 5713, + OpSubgroupAvcMceSetInterBaseMultiReferencePenaltyINTEL = 5714, + OpSubgroupAvcMceGetDefaultInterShapePenaltyINTEL = 5715, + OpSubgroupAvcMceSetInterShapePenaltyINTEL = 5716, + OpSubgroupAvcMceGetDefaultInterDirectionPenaltyINTEL = 5717, + OpSubgroupAvcMceSetInterDirectionPenaltyINTEL = 5718, + OpSubgroupAvcMceGetDefaultIntraLumaShapePenaltyINTEL = 5719, + OpSubgroupAvcMceGetDefaultInterMotionVectorCostTableINTEL = 5720, + OpSubgroupAvcMceGetDefaultHighPenaltyCostTableINTEL = 5721, + OpSubgroupAvcMceGetDefaultMediumPenaltyCostTableINTEL = 5722, + OpSubgroupAvcMceGetDefaultLowPenaltyCostTableINTEL = 5723, + OpSubgroupAvcMceSetMotionVectorCostFunctionINTEL = 5724, + OpSubgroupAvcMceGetDefaultIntraLumaModePenaltyINTEL = 5725, + OpSubgroupAvcMceGetDefaultNonDcLumaIntraPenaltyINTEL = 5726, + OpSubgroupAvcMceGetDefaultIntraChromaModeBasePenaltyINTEL = 5727, + OpSubgroupAvcMceSetAcOnlyHaarINTEL = 5728, + OpSubgroupAvcMceSetSourceInterlacedFieldPolarityINTEL = 5729, + OpSubgroupAvcMceSetSingleReferenceInterlacedFieldPolarityINTEL = 5730, + OpSubgroupAvcMceSetDualReferenceInterlacedFieldPolaritiesINTEL = 5731, + OpSubgroupAvcMceConvertToImePayloadINTEL = 5732, + OpSubgroupAvcMceConvertToImeResultINTEL = 5733, + OpSubgroupAvcMceConvertToRefPayloadINTEL = 5734, + OpSubgroupAvcMceConvertToRefResultINTEL = 5735, + OpSubgroupAvcMceConvertToSicPayloadINTEL = 5736, + OpSubgroupAvcMceConvertToSicResultINTEL = 5737, + OpSubgroupAvcMceGetMotionVectorsINTEL = 5738, + OpSubgroupAvcMceGetInterDistortionsINTEL = 5739, + OpSubgroupAvcMceGetBestInterDistortionsINTEL = 5740, + OpSubgroupAvcMceGetInterMajorShapeINTEL = 5741, + OpSubgroupAvcMceGetInterMinorShapeINTEL = 5742, + OpSubgroupAvcMceGetInterDirectionsINTEL = 5743, + OpSubgroupAvcMceGetInterMotionVectorCountINTEL = 5744, + OpSubgroupAvcMceGetInterReferenceIdsINTEL = 5745, + OpSubgroupAvcMceGetInterReferenceInterlacedFieldPolaritiesINTEL = 5746, + OpSubgroupAvcImeInitializeINTEL = 5747, + OpSubgroupAvcImeSetSingleReferenceINTEL = 5748, + OpSubgroupAvcImeSetDualReferenceINTEL = 5749, + OpSubgroupAvcImeRefWindowSizeINTEL = 5750, + OpSubgroupAvcImeAdjustRefOffsetINTEL = 5751, + OpSubgroupAvcImeConvertToMcePayloadINTEL = 5752, + OpSubgroupAvcImeSetMaxMotionVectorCountINTEL = 5753, + OpSubgroupAvcImeSetUnidirectionalMixDisableINTEL = 5754, + OpSubgroupAvcImeSetEarlySearchTerminationThresholdINTEL = 5755, + OpSubgroupAvcImeSetWeightedSadINTEL = 5756, + OpSubgroupAvcImeEvaluateWithSingleReferenceINTEL = 5757, + OpSubgroupAvcImeEvaluateWithDualReferenceINTEL = 5758, + OpSubgroupAvcImeEvaluateWithSingleReferenceStreaminINTEL = 5759, + OpSubgroupAvcImeEvaluateWithDualReferenceStreaminINTEL = 5760, + OpSubgroupAvcImeEvaluateWithSingleReferenceStreamoutINTEL = 5761, + OpSubgroupAvcImeEvaluateWithDualReferenceStreamoutINTEL = 5762, + OpSubgroupAvcImeEvaluateWithSingleReferenceStreaminoutINTEL = 5763, + OpSubgroupAvcImeEvaluateWithDualReferenceStreaminoutINTEL = 5764, + OpSubgroupAvcImeConvertToMceResultINTEL = 5765, + OpSubgroupAvcImeGetSingleReferenceStreaminINTEL = 5766, + OpSubgroupAvcImeGetDualReferenceStreaminINTEL = 5767, + OpSubgroupAvcImeStripSingleReferenceStreamoutINTEL = 5768, + OpSubgroupAvcImeStripDualReferenceStreamoutINTEL = 5769, + OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeMotionVectorsINTEL = 5770, + OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeDistortionsINTEL = 5771, + OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeReferenceIdsINTEL = 5772, + OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeMotionVectorsINTEL = 5773, + OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeDistortionsINTEL = 5774, + OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeReferenceIdsINTEL = 5775, + OpSubgroupAvcImeGetBorderReachedINTEL = 5776, + OpSubgroupAvcImeGetTruncatedSearchIndicationINTEL = 5777, + OpSubgroupAvcImeGetUnidirectionalEarlySearchTerminationINTEL = 5778, + OpSubgroupAvcImeGetWeightingPatternMinimumMotionVectorINTEL = 5779, + OpSubgroupAvcImeGetWeightingPatternMinimumDistortionINTEL = 5780, + OpSubgroupAvcFmeInitializeINTEL = 5781, + OpSubgroupAvcBmeInitializeINTEL = 5782, + OpSubgroupAvcRefConvertToMcePayloadINTEL = 5783, + OpSubgroupAvcRefSetBidirectionalMixDisableINTEL = 5784, + OpSubgroupAvcRefSetBilinearFilterEnableINTEL = 5785, + OpSubgroupAvcRefEvaluateWithSingleReferenceINTEL = 5786, + OpSubgroupAvcRefEvaluateWithDualReferenceINTEL = 5787, + OpSubgroupAvcRefEvaluateWithMultiReferenceINTEL = 5788, + OpSubgroupAvcRefEvaluateWithMultiReferenceInterlacedINTEL = 5789, + OpSubgroupAvcRefConvertToMceResultINTEL = 5790, + OpSubgroupAvcSicInitializeINTEL = 5791, + OpSubgroupAvcSicConfigureSkcINTEL = 5792, + OpSubgroupAvcSicConfigureIpeLumaINTEL = 5793, + OpSubgroupAvcSicConfigureIpeLumaChromaINTEL = 5794, + OpSubgroupAvcSicGetMotionVectorMaskINTEL = 5795, + OpSubgroupAvcSicConvertToMcePayloadINTEL = 5796, + OpSubgroupAvcSicSetIntraLumaShapePenaltyINTEL = 5797, + OpSubgroupAvcSicSetIntraLumaModeCostFunctionINTEL = 5798, + OpSubgroupAvcSicSetIntraChromaModeCostFunctionINTEL = 5799, + OpSubgroupAvcSicSetBilinearFilterEnableINTEL = 5800, + OpSubgroupAvcSicSetSkcForwardTransformEnableINTEL = 5801, + OpSubgroupAvcSicSetBlockBasedRawSkipSadINTEL = 5802, + OpSubgroupAvcSicEvaluateIpeINTEL = 5803, + OpSubgroupAvcSicEvaluateWithSingleReferenceINTEL = 5804, + OpSubgroupAvcSicEvaluateWithDualReferenceINTEL = 5805, + OpSubgroupAvcSicEvaluateWithMultiReferenceINTEL = 5806, + OpSubgroupAvcSicEvaluateWithMultiReferenceInterlacedINTEL = 5807, + OpSubgroupAvcSicConvertToMceResultINTEL = 5808, + OpSubgroupAvcSicGetIpeLumaShapeINTEL = 5809, + OpSubgroupAvcSicGetBestIpeLumaDistortionINTEL = 5810, + OpSubgroupAvcSicGetBestIpeChromaDistortionINTEL = 5811, + OpSubgroupAvcSicGetPackedIpeLumaModesINTEL = 5812, + OpSubgroupAvcSicGetIpeChromaModeINTEL = 5813, + OpSubgroupAvcSicGetPackedSkcLumaCountThresholdINTEL = 5814, + OpSubgroupAvcSicGetPackedSkcLumaSumThresholdINTEL = 5815, + OpSubgroupAvcSicGetInterRawSadsINTEL = 5816, + OpLoopControlINTEL = 5887, + OpReadPipeBlockingINTEL = 5946, + OpWritePipeBlockingINTEL = 5947, + OpFPGARegINTEL = 5949, + OpRayQueryGetRayTMinKHR = 6016, + OpRayQueryGetRayFlagsKHR = 6017, + OpRayQueryGetIntersectionTKHR = 6018, + OpRayQueryGetIntersectionInstanceCustomIndexKHR = 6019, + OpRayQueryGetIntersectionInstanceIdKHR = 6020, + OpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffsetKHR = 6021, + OpRayQueryGetIntersectionGeometryIndexKHR = 6022, + OpRayQueryGetIntersectionPrimitiveIndexKHR = 6023, + OpRayQueryGetIntersectionBarycentricsKHR = 6024, + OpRayQueryGetIntersectionFrontFaceKHR = 6025, + OpRayQueryGetIntersectionCandidateAABBOpaqueKHR = 6026, + OpRayQueryGetIntersectionObjectRayDirectionKHR = 6027, + OpRayQueryGetIntersectionObjectRayOriginKHR = 6028, + OpRayQueryGetWorldRayDirectionKHR = 6029, + OpRayQueryGetWorldRayOriginKHR = 6030, + OpRayQueryGetIntersectionObjectToWorldKHR = 6031, + OpRayQueryGetIntersectionWorldToObjectKHR = 6032, + OpAtomicFAddEXT = 6035, + }; + + enum class SpirvOperandKind + { + ImageOperands, + FPFastMathMode, + SelectionControl, + LoopControl, + FunctionControl, + MemorySemantics, + MemoryAccess, + KernelProfilingInfo, + RayFlags, + SourceLanguage, + ExecutionModel, + AddressingModel, + MemoryModel, + ExecutionMode, + StorageClass, + Dim, + SamplerAddressingMode, + SamplerFilterMode, + ImageFormat, + ImageChannelOrder, + ImageChannelDataType, + FPRoundingMode, + LinkageType, + AccessQualifier, + FunctionParameterAttribute, + Decoration, + BuiltIn, + Scope, + GroupOperation, + KernelEnqueueFlags, + Capability, + RayQueryIntersection, + RayQueryCommittedIntersectionType, + RayQueryCandidateIntersectionType, + IdResultType, + IdResult, + IdMemorySemantics, + IdScope, + IdRef, + LiteralInteger, + LiteralString, + LiteralContextDependentNumber, + LiteralExtInstInteger, + LiteralSpecConstantOpInteger, + PairLiteralIntegerIdRef, + PairIdRefLiteralInteger, + PairIdRefIdRef, + }; + + enum class SpirvSourceLanguage + { + Unknown = 0, + ESSL = 1, + GLSL = 2, + OpenCL_C = 3, + OpenCL_CPP = 4, + HLSL = 5, + }; + + enum class SpirvExecutionModel + { + Vertex = 0, + TessellationControl = 1, + TessellationEvaluation = 2, + Geometry = 3, + Fragment = 4, + GLCompute = 5, + Kernel = 6, + TaskNV = 5267, + MeshNV = 5268, + RayGenerationNV = 5313, + RayGenerationKHR = 5313, + IntersectionNV = 5314, + IntersectionKHR = 5314, + AnyHitNV = 5315, + AnyHitKHR = 5315, + ClosestHitNV = 5316, + ClosestHitKHR = 5316, + MissNV = 5317, + MissKHR = 5317, + CallableNV = 5318, + CallableKHR = 5318, + }; + + enum class SpirvAddressingModel + { + Logical = 0, + Physical32 = 1, + Physical64 = 2, + PhysicalStorageBuffer64 = 5348, + PhysicalStorageBuffer64EXT = 5348, + }; + + enum class SpirvMemoryModel + { + Simple = 0, + GLSL450 = 1, + OpenCL = 2, + Vulkan = 3, + VulkanKHR = 3, + }; + + enum class SpirvExecutionMode + { + Invocations = 0, + SpacingEqual = 1, + SpacingFractionalEven = 2, + SpacingFractionalOdd = 3, + VertexOrderCw = 4, + VertexOrderCcw = 5, + PixelCenterInteger = 6, + OriginUpperLeft = 7, + OriginLowerLeft = 8, + EarlyFragmentTests = 9, + PointMode = 10, + Xfb = 11, + DepthReplacing = 12, + DepthGreater = 14, + DepthLess = 15, + DepthUnchanged = 16, + LocalSize = 17, + LocalSizeHint = 18, + InputPoints = 19, + InputLines = 20, + InputLinesAdjacency = 21, + Triangles = 22, + InputTrianglesAdjacency = 23, + Quads = 24, + Isolines = 25, + OutputVertices = 26, + OutputPoints = 27, + OutputLineStrip = 28, + OutputTriangleStrip = 29, + VecTypeHint = 30, + ContractionOff = 31, + Initializer = 33, + Finalizer = 34, + SubgroupSize = 35, + SubgroupsPerWorkgroup = 36, + SubgroupsPerWorkgroupId = 37, + LocalSizeId = 38, + LocalSizeHintId = 39, + PostDepthCoverage = 4446, + DenormPreserve = 4459, + DenormFlushToZero = 4460, + SignedZeroInfNanPreserve = 4461, + RoundingModeRTE = 4462, + RoundingModeRTZ = 4463, + StencilRefReplacingEXT = 5027, + OutputLinesNV = 5269, + OutputPrimitivesNV = 5270, + DerivativeGroupQuadsNV = 5289, + DerivativeGroupLinearNV = 5290, + OutputTrianglesNV = 5298, + PixelInterlockOrderedEXT = 5366, + PixelInterlockUnorderedEXT = 5367, + SampleInterlockOrderedEXT = 5368, + SampleInterlockUnorderedEXT = 5369, + ShadingRateInterlockOrderedEXT = 5370, + ShadingRateInterlockUnorderedEXT = 5371, + MaxWorkgroupSizeINTEL = 5893, + MaxWorkDimINTEL = 5894, + NoGlobalOffsetINTEL = 5895, + NumSIMDWorkitemsINTEL = 5896, + }; + + enum class SpirvStorageClass + { + UniformConstant = 0, + Input = 1, + Uniform = 2, + Output = 3, + Workgroup = 4, + CrossWorkgroup = 5, + Private = 6, + Function = 7, + Generic = 8, + PushConstant = 9, + AtomicCounter = 10, + Image = 11, + StorageBuffer = 12, + CallableDataNV = 5328, + CallableDataKHR = 5328, + IncomingCallableDataNV = 5329, + IncomingCallableDataKHR = 5329, + RayPayloadNV = 5338, + RayPayloadKHR = 5338, + HitAttributeNV = 5339, + HitAttributeKHR = 5339, + IncomingRayPayloadNV = 5342, + IncomingRayPayloadKHR = 5342, + ShaderRecordBufferNV = 5343, + ShaderRecordBufferKHR = 5343, + PhysicalStorageBuffer = 5349, + PhysicalStorageBufferEXT = 5349, + CodeSectionINTEL = 5605, + }; + + enum class SpirvDim + { + Dim1D = 0, + Dim2D = 1, + Dim3D = 2, + Cube = 3, + Rect = 4, + Buffer = 5, + SubpassData = 6, + }; + + enum class SpirvSamplerAddressingMode + { + None = 0, + ClampToEdge = 1, + Clamp = 2, + Repeat = 3, + RepeatMirrored = 4, + }; + + enum class SpirvSamplerFilterMode + { + Nearest = 0, + Linear = 1, + }; + + enum class SpirvImageFormat + { + Unknown = 0, + Rgba32f = 1, + Rgba16f = 2, + R32f = 3, + Rgba8 = 4, + Rgba8Snorm = 5, + Rg32f = 6, + Rg16f = 7, + R11fG11fB10f = 8, + R16f = 9, + Rgba16 = 10, + Rgb10A2 = 11, + Rg16 = 12, + Rg8 = 13, + R16 = 14, + R8 = 15, + Rgba16Snorm = 16, + Rg16Snorm = 17, + Rg8Snorm = 18, + R16Snorm = 19, + R8Snorm = 20, + Rgba32i = 21, + Rgba16i = 22, + Rgba8i = 23, + R32i = 24, + Rg32i = 25, + Rg16i = 26, + Rg8i = 27, + R16i = 28, + R8i = 29, + Rgba32ui = 30, + Rgba16ui = 31, + Rgba8ui = 32, + R32ui = 33, + Rgb10a2ui = 34, + Rg32ui = 35, + Rg16ui = 36, + Rg8ui = 37, + R16ui = 38, + R8ui = 39, + }; + + enum class SpirvImageChannelOrder + { + R = 0, + A = 1, + RG = 2, + RA = 3, + RGB = 4, + RGBA = 5, + BGRA = 6, + ARGB = 7, + Intensity = 8, + Luminance = 9, + Rx = 10, + RGx = 11, + RGBx = 12, + Depth = 13, + DepthStencil = 14, + sRGB = 15, + sRGBx = 16, + sRGBA = 17, + sBGRA = 18, + ABGR = 19, + }; + + enum class SpirvImageChannelDataType + { + SnormInt8 = 0, + SnormInt16 = 1, + UnormInt8 = 2, + UnormInt16 = 3, + UnormShort565 = 4, + UnormShort555 = 5, + UnormInt101010 = 6, + SignedInt8 = 7, + SignedInt16 = 8, + SignedInt32 = 9, + UnsignedInt8 = 10, + UnsignedInt16 = 11, + UnsignedInt32 = 12, + HalfFloat = 13, + Float = 14, + UnormInt24 = 15, + UnormInt101010_2 = 16, + }; + + enum class SpirvFPRoundingMode + { + RTE = 0, + RTZ = 1, + RTP = 2, + RTN = 3, + }; + + enum class SpirvLinkageType + { + Export = 0, + Import = 1, + }; + + enum class SpirvAccessQualifier + { + ReadOnly = 0, + WriteOnly = 1, + ReadWrite = 2, + }; + + enum class SpirvFunctionParameterAttribute + { + Zext = 0, + Sext = 1, + ByVal = 2, + Sret = 3, + NoAlias = 4, + NoCapture = 5, + NoWrite = 6, + NoReadWrite = 7, + }; + + enum class SpirvDecoration + { + RelaxedPrecision = 0, + SpecId = 1, + Block = 2, + BufferBlock = 3, + RowMajor = 4, + ColMajor = 5, + ArrayStride = 6, + MatrixStride = 7, + GLSLShared = 8, + GLSLPacked = 9, + CPacked = 10, + BuiltIn = 11, + NoPerspective = 13, + Flat = 14, + Patch = 15, + Centroid = 16, + Sample = 17, + Invariant = 18, + Restrict = 19, + Aliased = 20, + Volatile = 21, + Constant = 22, + Coherent = 23, + NonWritable = 24, + NonReadable = 25, + Uniform = 26, + UniformId = 27, + SaturatedConversion = 28, + Stream = 29, + Location = 30, + Component = 31, + Index = 32, + Binding = 33, + DescriptorSet = 34, + Offset = 35, + XfbBuffer = 36, + XfbStride = 37, + FuncParamAttr = 38, + FPRoundingMode = 39, + FPFastMathMode = 40, + LinkageAttributes = 41, + NoContraction = 42, + InputAttachmentIndex = 43, + Alignment = 44, + MaxByteOffset = 45, + AlignmentId = 46, + MaxByteOffsetId = 47, + NoSignedWrap = 4469, + NoUnsignedWrap = 4470, + ExplicitInterpAMD = 4999, + OverrideCoverageNV = 5248, + PassthroughNV = 5250, + ViewportRelativeNV = 5252, + SecondaryViewportRelativeNV = 5256, + PerPrimitiveNV = 5271, + PerViewNV = 5272, + PerTaskNV = 5273, + PerVertexNV = 5285, + NonUniform = 5300, + NonUniformEXT = 5300, + RestrictPointer = 5355, + RestrictPointerEXT = 5355, + AliasedPointer = 5356, + AliasedPointerEXT = 5356, + ReferencedIndirectlyINTEL = 5602, + CounterBuffer = 5634, + HlslCounterBufferGOOGLE = 5634, + UserSemantic = 5635, + HlslSemanticGOOGLE = 5635, + UserTypeGOOGLE = 5636, + RegisterINTEL = 5825, + MemoryINTEL = 5826, + NumbanksINTEL = 5827, + BankwidthINTEL = 5828, + MaxPrivateCopiesINTEL = 5829, + SinglepumpINTEL = 5830, + DoublepumpINTEL = 5831, + MaxReplicatesINTEL = 5832, + SimpleDualPortINTEL = 5833, + MergeINTEL = 5834, + BankBitsINTEL = 5835, + ForcePow2DepthINTEL = 5836, + }; + + enum class SpirvBuiltIn + { + Position = 0, + PointSize = 1, + ClipDistance = 3, + CullDistance = 4, + VertexId = 5, + InstanceId = 6, + PrimitiveId = 7, + InvocationId = 8, + Layer = 9, + ViewportIndex = 10, + TessLevelOuter = 11, + TessLevelInner = 12, + TessCoord = 13, + PatchVertices = 14, + FragCoord = 15, + PointCoord = 16, + FrontFacing = 17, + SampleId = 18, + SamplePosition = 19, + SampleMask = 20, + FragDepth = 22, + HelperInvocation = 23, + NumWorkgroups = 24, + WorkgroupSize = 25, + WorkgroupId = 26, + LocalInvocationId = 27, + GlobalInvocationId = 28, + LocalInvocationIndex = 29, + WorkDim = 30, + GlobalSize = 31, + EnqueuedWorkgroupSize = 32, + GlobalOffset = 33, + GlobalLinearId = 34, + SubgroupSize = 36, + SubgroupMaxSize = 37, + NumSubgroups = 38, + NumEnqueuedSubgroups = 39, + SubgroupId = 40, + SubgroupLocalInvocationId = 41, + VertexIndex = 42, + InstanceIndex = 43, + SubgroupEqMask = 4416, + SubgroupGeMask = 4417, + SubgroupGtMask = 4418, + SubgroupLeMask = 4419, + SubgroupLtMask = 4420, + SubgroupEqMaskKHR = 4416, + SubgroupGeMaskKHR = 4417, + SubgroupGtMaskKHR = 4418, + SubgroupLeMaskKHR = 4419, + SubgroupLtMaskKHR = 4420, + BaseVertex = 4424, + BaseInstance = 4425, + DrawIndex = 4426, + DeviceIndex = 4438, + ViewIndex = 4440, + BaryCoordNoPerspAMD = 4992, + BaryCoordNoPerspCentroidAMD = 4993, + BaryCoordNoPerspSampleAMD = 4994, + BaryCoordSmoothAMD = 4995, + BaryCoordSmoothCentroidAMD = 4996, + BaryCoordSmoothSampleAMD = 4997, + BaryCoordPullModelAMD = 4998, + FragStencilRefEXT = 5014, + ViewportMaskNV = 5253, + SecondaryPositionNV = 5257, + SecondaryViewportMaskNV = 5258, + PositionPerViewNV = 5261, + ViewportMaskPerViewNV = 5262, + FullyCoveredEXT = 5264, + TaskCountNV = 5274, + PrimitiveCountNV = 5275, + PrimitiveIndicesNV = 5276, + ClipDistancePerViewNV = 5277, + CullDistancePerViewNV = 5278, + LayerPerViewNV = 5279, + MeshViewCountNV = 5280, + MeshViewIndicesNV = 5281, + BaryCoordNV = 5286, + BaryCoordNoPerspNV = 5287, + FragSizeEXT = 5292, + FragmentSizeNV = 5292, + FragInvocationCountEXT = 5293, + InvocationsPerPixelNV = 5293, + LaunchIdNV = 5319, + LaunchIdKHR = 5319, + LaunchSizeNV = 5320, + LaunchSizeKHR = 5320, + WorldRayOriginNV = 5321, + WorldRayOriginKHR = 5321, + WorldRayDirectionNV = 5322, + WorldRayDirectionKHR = 5322, + ObjectRayOriginNV = 5323, + ObjectRayOriginKHR = 5323, + ObjectRayDirectionNV = 5324, + ObjectRayDirectionKHR = 5324, + RayTminNV = 5325, + RayTminKHR = 5325, + RayTmaxNV = 5326, + RayTmaxKHR = 5326, + InstanceCustomIndexNV = 5327, + InstanceCustomIndexKHR = 5327, + ObjectToWorldNV = 5330, + ObjectToWorldKHR = 5330, + WorldToObjectNV = 5331, + WorldToObjectKHR = 5331, + HitTNV = 5332, + HitTKHR = 5332, + HitKindNV = 5333, + HitKindKHR = 5333, + IncomingRayFlagsNV = 5351, + IncomingRayFlagsKHR = 5351, + RayGeometryIndexKHR = 5352, + WarpsPerSMNV = 5374, + SMCountNV = 5375, + WarpIDNV = 5376, + SMIDNV = 5377, + }; + + enum class SpirvScope + { + CrossDevice = 0, + Device = 1, + Workgroup = 2, + Subgroup = 3, + Invocation = 4, + QueueFamily = 5, + QueueFamilyKHR = 5, + ShaderCallKHR = 6, + }; + + enum class SpirvGroupOperation + { + Reduce = 0, + InclusiveScan = 1, + ExclusiveScan = 2, + ClusteredReduce = 3, + PartitionedReduceNV = 6, + PartitionedInclusiveScanNV = 7, + PartitionedExclusiveScanNV = 8, + }; + + enum class SpirvKernelEnqueueFlags + { + NoWait = 0, + WaitKernel = 1, + WaitWorkGroup = 2, + }; + + enum class SpirvCapability + { + Matrix = 0, + Shader = 1, + Geometry = 2, + Tessellation = 3, + Addresses = 4, + Linkage = 5, + Kernel = 6, + Vector16 = 7, + Float16Buffer = 8, + Float16 = 9, + Float64 = 10, + Int64 = 11, + Int64Atomics = 12, + ImageBasic = 13, + ImageReadWrite = 14, + ImageMipmap = 15, + Pipes = 17, + Groups = 18, + DeviceEnqueue = 19, + LiteralSampler = 20, + AtomicStorage = 21, + Int16 = 22, + TessellationPointSize = 23, + GeometryPointSize = 24, + ImageGatherExtended = 25, + StorageImageMultisample = 27, + UniformBufferArrayDynamicIndexing = 28, + SampledImageArrayDynamicIndexing = 29, + StorageBufferArrayDynamicIndexing = 30, + StorageImageArrayDynamicIndexing = 31, + ClipDistance = 32, + CullDistance = 33, + ImageCubeArray = 34, + SampleRateShading = 35, + ImageRect = 36, + SampledRect = 37, + GenericPointer = 38, + Int8 = 39, + InputAttachment = 40, + SparseResidency = 41, + MinLod = 42, + Sampled1D = 43, + Image1D = 44, + SampledCubeArray = 45, + SampledBuffer = 46, + ImageBuffer = 47, + ImageMSArray = 48, + StorageImageExtendedFormats = 49, + ImageQuery = 50, + DerivativeControl = 51, + InterpolationFunction = 52, + TransformFeedback = 53, + GeometryStreams = 54, + StorageImageReadWithoutFormat = 55, + StorageImageWriteWithoutFormat = 56, + MultiViewport = 57, + SubgroupDispatch = 58, + NamedBarrier = 59, + PipeStorage = 60, + GroupNonUniform = 61, + GroupNonUniformVote = 62, + GroupNonUniformArithmetic = 63, + GroupNonUniformBallot = 64, + GroupNonUniformShuffle = 65, + GroupNonUniformShuffleRelative = 66, + GroupNonUniformClustered = 67, + GroupNonUniformQuad = 68, + ShaderLayer = 69, + ShaderViewportIndex = 70, + SubgroupBallotKHR = 4423, + DrawParameters = 4427, + SubgroupVoteKHR = 4431, + StorageBuffer16BitAccess = 4433, + StorageUniformBufferBlock16 = 4433, + UniformAndStorageBuffer16BitAccess = 4434, + StorageUniform16 = 4434, + StoragePushConstant16 = 4435, + StorageInputOutput16 = 4436, + DeviceGroup = 4437, + MultiView = 4439, + VariablePointersStorageBuffer = 4441, + VariablePointers = 4442, + AtomicStorageOps = 4445, + SampleMaskPostDepthCoverage = 4447, + StorageBuffer8BitAccess = 4448, + UniformAndStorageBuffer8BitAccess = 4449, + StoragePushConstant8 = 4450, + DenormPreserve = 4464, + DenormFlushToZero = 4465, + SignedZeroInfNanPreserve = 4466, + RoundingModeRTE = 4467, + RoundingModeRTZ = 4468, + RayQueryProvisionalKHR = 4471, + RayTraversalPrimitiveCullingProvisionalKHR = 4478, + Float16ImageAMD = 5008, + ImageGatherBiasLodAMD = 5009, + FragmentMaskAMD = 5010, + StencilExportEXT = 5013, + ImageReadWriteLodAMD = 5015, + ShaderClockKHR = 5055, + SampleMaskOverrideCoverageNV = 5249, + GeometryShaderPassthroughNV = 5251, + ShaderViewportIndexLayerEXT = 5254, + ShaderViewportIndexLayerNV = 5254, + ShaderViewportMaskNV = 5255, + ShaderStereoViewNV = 5259, + PerViewAttributesNV = 5260, + FragmentFullyCoveredEXT = 5265, + MeshShadingNV = 5266, + ImageFootprintNV = 5282, + FragmentBarycentricNV = 5284, + ComputeDerivativeGroupQuadsNV = 5288, + FragmentDensityEXT = 5291, + ShadingRateNV = 5291, + GroupNonUniformPartitionedNV = 5297, + ShaderNonUniform = 5301, + ShaderNonUniformEXT = 5301, + RuntimeDescriptorArray = 5302, + RuntimeDescriptorArrayEXT = 5302, + InputAttachmentArrayDynamicIndexing = 5303, + InputAttachmentArrayDynamicIndexingEXT = 5303, + UniformTexelBufferArrayDynamicIndexing = 5304, + UniformTexelBufferArrayDynamicIndexingEXT = 5304, + StorageTexelBufferArrayDynamicIndexing = 5305, + StorageTexelBufferArrayDynamicIndexingEXT = 5305, + UniformBufferArrayNonUniformIndexing = 5306, + UniformBufferArrayNonUniformIndexingEXT = 5306, + SampledImageArrayNonUniformIndexing = 5307, + SampledImageArrayNonUniformIndexingEXT = 5307, + StorageBufferArrayNonUniformIndexing = 5308, + StorageBufferArrayNonUniformIndexingEXT = 5308, + StorageImageArrayNonUniformIndexing = 5309, + StorageImageArrayNonUniformIndexingEXT = 5309, + InputAttachmentArrayNonUniformIndexing = 5310, + InputAttachmentArrayNonUniformIndexingEXT = 5310, + UniformTexelBufferArrayNonUniformIndexing = 5311, + UniformTexelBufferArrayNonUniformIndexingEXT = 5311, + StorageTexelBufferArrayNonUniformIndexing = 5312, + StorageTexelBufferArrayNonUniformIndexingEXT = 5312, + RayTracingNV = 5340, + VulkanMemoryModel = 5345, + VulkanMemoryModelKHR = 5345, + VulkanMemoryModelDeviceScope = 5346, + VulkanMemoryModelDeviceScopeKHR = 5346, + PhysicalStorageBufferAddresses = 5347, + PhysicalStorageBufferAddressesEXT = 5347, + ComputeDerivativeGroupLinearNV = 5350, + RayTracingProvisionalKHR = 5353, + CooperativeMatrixNV = 5357, + FragmentShaderSampleInterlockEXT = 5363, + FragmentShaderShadingRateInterlockEXT = 5372, + ShaderSMBuiltinsNV = 5373, + FragmentShaderPixelInterlockEXT = 5378, + DemoteToHelperInvocationEXT = 5379, + SubgroupShuffleINTEL = 5568, + SubgroupBufferBlockIOINTEL = 5569, + SubgroupImageBlockIOINTEL = 5570, + SubgroupImageMediaBlockIOINTEL = 5579, + IntegerFunctions2INTEL = 5584, + FunctionPointersINTEL = 5603, + IndirectReferencesINTEL = 5604, + SubgroupAvcMotionEstimationINTEL = 5696, + SubgroupAvcMotionEstimationIntraINTEL = 5697, + SubgroupAvcMotionEstimationChromaINTEL = 5698, + FPGAMemoryAttributesINTEL = 5824, + UnstructuredLoopControlsINTEL = 5886, + FPGALoopControlsINTEL = 5888, + KernelAttributesINTEL = 5892, + FPGAKernelAttributesINTEL = 5897, + BlockingPipesINTEL = 5945, + FPGARegINTEL = 5948, + AtomicFloat32AddEXT = 6033, + AtomicFloat64AddEXT = 6034, + }; + + enum class SpirvRayQueryIntersection + { + RayQueryCandidateIntersectionKHR = 0, + RayQueryCommittedIntersectionKHR = 1, + }; + + enum class SpirvRayQueryCommittedIntersectionType + { + RayQueryCommittedIntersectionNoneKHR = 0, + RayQueryCommittedIntersectionTriangleKHR = 1, + RayQueryCommittedIntersectionGeneratedKHR = 2, + }; + + enum class SpirvRayQueryCandidateIntersectionType + { + RayQueryCandidateIntersectionTriangleKHR = 0, + RayQueryCandidateIntersectionAABBKHR = 1, + }; + + struct SpirvInstruction + { + struct Operand + { + SpirvOperandKind kind; + const char* name; + }; + + SpirvOp op; + const char* name; + const Operand* operands; + std::size_t minOperandCount; + }; + + NAZARA_SHADER_API const SpirvInstruction* GetInstructionData(UInt16 op); +} + +#endif diff --git a/src/Nazara/Shader/SpirvData.cpp b/src/Nazara/Shader/SpirvData.cpp new file mode 100644 index 000000000..dae33b777 --- /dev/null +++ b/src/Nazara/Shader/SpirvData.cpp @@ -0,0 +1,11862 @@ +// 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" + +// This file was generated automatically, please do not edit + +#include +#include +#include +#include + +namespace Nz +{ + static constexpr std::array s_operands = { + { + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::LiteralString, + R"('Continued Source')" + }, + { + SpirvOperandKind::SourceLanguage, + R"(SourceLanguage)" + }, + { + SpirvOperandKind::LiteralInteger, + R"('Version')" + }, + { + SpirvOperandKind::IdRef, + R"('File')" + }, + { + SpirvOperandKind::LiteralString, + R"('Source')" + }, + { + SpirvOperandKind::LiteralString, + R"('Extension')" + }, + { + SpirvOperandKind::IdRef, + R"('Target')" + }, + { + SpirvOperandKind::LiteralString, + R"('Name')" + }, + { + SpirvOperandKind::IdRef, + R"('Type')" + }, + { + SpirvOperandKind::LiteralInteger, + R"('Member')" + }, + { + SpirvOperandKind::LiteralString, + R"('Name')" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::LiteralString, + R"('String')" + }, + { + SpirvOperandKind::IdRef, + R"('File')" + }, + { + SpirvOperandKind::LiteralInteger, + R"('Line')" + }, + { + SpirvOperandKind::LiteralInteger, + R"('Column')" + }, + { + SpirvOperandKind::LiteralString, + R"('Name')" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::LiteralString, + R"('Name')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Set')" + }, + { + SpirvOperandKind::LiteralExtInstInteger, + R"('Instruction')" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 1', + +'Operand 2', + +...)" + }, + { + SpirvOperandKind::AddressingModel, + R"(AddressingModel)" + }, + { + SpirvOperandKind::MemoryModel, + R"(MemoryModel)" + }, + { + SpirvOperandKind::ExecutionModel, + R"(ExecutionModel)" + }, + { + SpirvOperandKind::IdRef, + R"('Entry Point')" + }, + { + SpirvOperandKind::LiteralString, + R"('Name')" + }, + { + SpirvOperandKind::IdRef, + R"('Interface')" + }, + { + SpirvOperandKind::IdRef, + R"('Entry Point')" + }, + { + SpirvOperandKind::ExecutionMode, + R"('Mode')" + }, + { + SpirvOperandKind::Capability, + R"('Capability')" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::LiteralInteger, + R"('Width')" + }, + { + SpirvOperandKind::LiteralInteger, + R"('Signedness')" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::LiteralInteger, + R"('Width')" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Component Type')" + }, + { + SpirvOperandKind::LiteralInteger, + R"('Component Count')" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Column Type')" + }, + { + SpirvOperandKind::LiteralInteger, + R"('Column Count')" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Sampled Type')" + }, + { + SpirvOperandKind::Dim, + R"(Dim)" + }, + { + SpirvOperandKind::LiteralInteger, + R"('Depth')" + }, + { + SpirvOperandKind::LiteralInteger, + R"('Arrayed')" + }, + { + SpirvOperandKind::LiteralInteger, + R"('MS')" + }, + { + SpirvOperandKind::LiteralInteger, + R"('Sampled')" + }, + { + SpirvOperandKind::ImageFormat, + R"(ImageFormat)" + }, + { + SpirvOperandKind::AccessQualifier, + R"(AccessQualifier)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Image Type')" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Element Type')" + }, + { + SpirvOperandKind::IdRef, + R"('Length')" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Element Type')" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Member 0 type', + +'member 1 type', + +...)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::LiteralString, + R"(The name of the opaque type.)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::StorageClass, + R"(StorageClass)" + }, + { + SpirvOperandKind::IdRef, + R"('Type')" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Return Type')" + }, + { + SpirvOperandKind::IdRef, + R"('Parameter 0 Type', + +'Parameter 1 Type', + +...)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::AccessQualifier, + R"('Qualifier')" + }, + { + SpirvOperandKind::IdRef, + R"('Pointer Type')" + }, + { + SpirvOperandKind::StorageClass, + R"(StorageClass)" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::LiteralContextDependentNumber, + R"('Value')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Constituents')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::SamplerAddressingMode, + R"(SamplerAddressingMode)" + }, + { + SpirvOperandKind::LiteralInteger, + R"('Param')" + }, + { + SpirvOperandKind::SamplerFilterMode, + R"(SamplerFilterMode)" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::LiteralContextDependentNumber, + R"('Value')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Constituents')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::LiteralSpecConstantOpInteger, + R"('Opcode')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::FunctionControl, + R"(FunctionControl)" + }, + { + SpirvOperandKind::IdRef, + R"('Function Type')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Function')" + }, + { + SpirvOperandKind::IdRef, + R"('Argument 0', + +'Argument 1', + +...)" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::StorageClass, + R"(StorageClass)" + }, + { + SpirvOperandKind::IdRef, + R"('Initializer')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Image')" + }, + { + SpirvOperandKind::IdRef, + R"('Coordinate')" + }, + { + SpirvOperandKind::IdRef, + R"('Sample')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Pointer')" + }, + { + SpirvOperandKind::MemoryAccess, + R"(MemoryAccess)" + }, + { + SpirvOperandKind::IdRef, + R"('Pointer')" + }, + { + SpirvOperandKind::IdRef, + R"('Object')" + }, + { + SpirvOperandKind::MemoryAccess, + R"(MemoryAccess)" + }, + { + SpirvOperandKind::IdRef, + R"('Target')" + }, + { + SpirvOperandKind::IdRef, + R"('Source')" + }, + { + SpirvOperandKind::MemoryAccess, + R"(MemoryAccess)" + }, + { + SpirvOperandKind::MemoryAccess, + R"(MemoryAccess)" + }, + { + SpirvOperandKind::IdRef, + R"('Target')" + }, + { + SpirvOperandKind::IdRef, + R"('Source')" + }, + { + SpirvOperandKind::IdRef, + R"('Size')" + }, + { + SpirvOperandKind::MemoryAccess, + R"(MemoryAccess)" + }, + { + SpirvOperandKind::MemoryAccess, + R"(MemoryAccess)" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Base')" + }, + { + SpirvOperandKind::IdRef, + R"('Indexes')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Base')" + }, + { + SpirvOperandKind::IdRef, + R"('Indexes')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Base')" + }, + { + SpirvOperandKind::IdRef, + R"('Element')" + }, + { + SpirvOperandKind::IdRef, + R"('Indexes')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Structure')" + }, + { + SpirvOperandKind::LiteralInteger, + R"('Array member')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Pointer')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Base')" + }, + { + SpirvOperandKind::IdRef, + R"('Element')" + }, + { + SpirvOperandKind::IdRef, + R"('Indexes')" + }, + { + SpirvOperandKind::IdRef, + R"('Target')" + }, + { + SpirvOperandKind::Decoration, + R"(Decoration)" + }, + { + SpirvOperandKind::IdRef, + R"('Structure Type')" + }, + { + SpirvOperandKind::LiteralInteger, + R"('Member')" + }, + { + SpirvOperandKind::Decoration, + R"(Decoration)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Decoration Group')" + }, + { + SpirvOperandKind::IdRef, + R"('Targets')" + }, + { + SpirvOperandKind::IdRef, + R"('Decoration Group')" + }, + { + SpirvOperandKind::PairIdRefLiteralInteger, + R"('Targets')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Vector')" + }, + { + SpirvOperandKind::IdRef, + R"('Index')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Vector')" + }, + { + SpirvOperandKind::IdRef, + R"('Component')" + }, + { + SpirvOperandKind::IdRef, + R"('Index')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Vector 1')" + }, + { + SpirvOperandKind::IdRef, + R"('Vector 2')" + }, + { + SpirvOperandKind::LiteralInteger, + R"('Components')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Constituents')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Composite')" + }, + { + SpirvOperandKind::LiteralInteger, + R"('Indexes')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Object')" + }, + { + SpirvOperandKind::IdRef, + R"('Composite')" + }, + { + SpirvOperandKind::LiteralInteger, + R"('Indexes')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Operand')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Matrix')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Image')" + }, + { + SpirvOperandKind::IdRef, + R"('Sampler')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Sampled Image')" + }, + { + SpirvOperandKind::IdRef, + R"('Coordinate')" + }, + { + SpirvOperandKind::ImageOperands, + R"(ImageOperands)" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Sampled Image')" + }, + { + SpirvOperandKind::IdRef, + R"('Coordinate')" + }, + { + SpirvOperandKind::ImageOperands, + R"(ImageOperands)" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Sampled Image')" + }, + { + SpirvOperandKind::IdRef, + R"('Coordinate')" + }, + { + SpirvOperandKind::IdRef, + R"('D~ref~')" + }, + { + SpirvOperandKind::ImageOperands, + R"(ImageOperands)" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Sampled Image')" + }, + { + SpirvOperandKind::IdRef, + R"('Coordinate')" + }, + { + SpirvOperandKind::IdRef, + R"('D~ref~')" + }, + { + SpirvOperandKind::ImageOperands, + R"(ImageOperands)" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Sampled Image')" + }, + { + SpirvOperandKind::IdRef, + R"('Coordinate')" + }, + { + SpirvOperandKind::ImageOperands, + R"(ImageOperands)" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Sampled Image')" + }, + { + SpirvOperandKind::IdRef, + R"('Coordinate')" + }, + { + SpirvOperandKind::ImageOperands, + R"(ImageOperands)" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Sampled Image')" + }, + { + SpirvOperandKind::IdRef, + R"('Coordinate')" + }, + { + SpirvOperandKind::IdRef, + R"('D~ref~')" + }, + { + SpirvOperandKind::ImageOperands, + R"(ImageOperands)" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Sampled Image')" + }, + { + SpirvOperandKind::IdRef, + R"('Coordinate')" + }, + { + SpirvOperandKind::IdRef, + R"('D~ref~')" + }, + { + SpirvOperandKind::ImageOperands, + R"(ImageOperands)" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Image')" + }, + { + SpirvOperandKind::IdRef, + R"('Coordinate')" + }, + { + SpirvOperandKind::ImageOperands, + R"(ImageOperands)" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Sampled Image')" + }, + { + SpirvOperandKind::IdRef, + R"('Coordinate')" + }, + { + SpirvOperandKind::IdRef, + R"('Component')" + }, + { + SpirvOperandKind::ImageOperands, + R"(ImageOperands)" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Sampled Image')" + }, + { + SpirvOperandKind::IdRef, + R"('Coordinate')" + }, + { + SpirvOperandKind::IdRef, + R"('D~ref~')" + }, + { + SpirvOperandKind::ImageOperands, + R"(ImageOperands)" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Image')" + }, + { + SpirvOperandKind::IdRef, + R"('Coordinate')" + }, + { + SpirvOperandKind::ImageOperands, + R"(ImageOperands)" + }, + { + SpirvOperandKind::IdRef, + R"('Image')" + }, + { + SpirvOperandKind::IdRef, + R"('Coordinate')" + }, + { + SpirvOperandKind::IdRef, + R"('Texel')" + }, + { + SpirvOperandKind::ImageOperands, + R"(ImageOperands)" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Sampled Image')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Image')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Image')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Image')" + }, + { + SpirvOperandKind::IdRef, + R"('Level of Detail')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Image')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Sampled Image')" + }, + { + SpirvOperandKind::IdRef, + R"('Coordinate')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Image')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Image')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Float Value')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Float Value')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Signed Value')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Unsigned Value')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Unsigned Value')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Signed Value')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Float Value')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Value')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Pointer')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Signed Value')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Unsigned Value')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Integer Value')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Pointer')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Pointer')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Pointer')" + }, + { + SpirvOperandKind::StorageClass, + R"('Storage')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Operand')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Operand')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Operand')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 1')" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 2')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 1')" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 2')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 1')" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 2')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 1')" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 2')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 1')" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 2')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 1')" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 2')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 1')" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 2')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 1')" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 2')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 1')" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 2')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 1')" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 2')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 1')" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 2')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 1')" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 2')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 1')" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 2')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 1')" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 2')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Vector')" + }, + { + SpirvOperandKind::IdRef, + R"('Scalar')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Matrix')" + }, + { + SpirvOperandKind::IdRef, + R"('Scalar')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Vector')" + }, + { + SpirvOperandKind::IdRef, + R"('Matrix')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Matrix')" + }, + { + SpirvOperandKind::IdRef, + R"('Vector')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('LeftMatrix')" + }, + { + SpirvOperandKind::IdRef, + R"('RightMatrix')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Vector 1')" + }, + { + SpirvOperandKind::IdRef, + R"('Vector 2')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Vector 1')" + }, + { + SpirvOperandKind::IdRef, + R"('Vector 2')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 1')" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 2')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 1')" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 2')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 1')" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 2')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 1')" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 2')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Vector')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Vector')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('x')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('x')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('x')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('x')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('x')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('x')" + }, + { + SpirvOperandKind::IdRef, + R"('y')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('x')" + }, + { + SpirvOperandKind::IdRef, + R"('y')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('x')" + }, + { + SpirvOperandKind::IdRef, + R"('y')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 1')" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 2')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 1')" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 2')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 1')" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 2')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 1')" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 2')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Operand')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Condition')" + }, + { + SpirvOperandKind::IdRef, + R"('Object 1')" + }, + { + SpirvOperandKind::IdRef, + R"('Object 2')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 1')" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 2')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 1')" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 2')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 1')" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 2')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 1')" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 2')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 1')" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 2')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 1')" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 2')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 1')" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 2')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 1')" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 2')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 1')" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 2')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 1')" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 2')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 1')" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 2')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 1')" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 2')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 1')" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 2')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 1')" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 2')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 1')" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 2')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 1')" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 2')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 1')" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 2')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 1')" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 2')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 1')" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 2')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 1')" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 2')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 1')" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 2')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 1')" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 2')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Base')" + }, + { + SpirvOperandKind::IdRef, + R"('Shift')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Base')" + }, + { + SpirvOperandKind::IdRef, + R"('Shift')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Base')" + }, + { + SpirvOperandKind::IdRef, + R"('Shift')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 1')" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 2')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 1')" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 2')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 1')" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 2')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Operand')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Base')" + }, + { + SpirvOperandKind::IdRef, + R"('Insert')" + }, + { + SpirvOperandKind::IdRef, + R"('Offset')" + }, + { + SpirvOperandKind::IdRef, + R"('Count')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Base')" + }, + { + SpirvOperandKind::IdRef, + R"('Offset')" + }, + { + SpirvOperandKind::IdRef, + R"('Count')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Base')" + }, + { + SpirvOperandKind::IdRef, + R"('Offset')" + }, + { + SpirvOperandKind::IdRef, + R"('Count')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Base')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Base')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('P')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('P')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('P')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('P')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('P')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('P')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('P')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('P')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('P')" + }, + { + SpirvOperandKind::IdRef, + R"('Stream')" + }, + { + SpirvOperandKind::IdRef, + R"('Stream')" + }, + { + SpirvOperandKind::IdScope, + R"('Execution')" + }, + { + SpirvOperandKind::IdScope, + R"('Memory')" + }, + { + SpirvOperandKind::IdMemorySemantics, + R"('Semantics')" + }, + { + SpirvOperandKind::IdScope, + R"('Memory')" + }, + { + SpirvOperandKind::IdMemorySemantics, + R"('Semantics')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Pointer')" + }, + { + SpirvOperandKind::IdScope, + R"('Memory')" + }, + { + SpirvOperandKind::IdMemorySemantics, + R"('Semantics')" + }, + { + SpirvOperandKind::IdRef, + R"('Pointer')" + }, + { + SpirvOperandKind::IdScope, + R"('Memory')" + }, + { + SpirvOperandKind::IdMemorySemantics, + R"('Semantics')" + }, + { + SpirvOperandKind::IdRef, + R"('Value')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Pointer')" + }, + { + SpirvOperandKind::IdScope, + R"('Memory')" + }, + { + SpirvOperandKind::IdMemorySemantics, + R"('Semantics')" + }, + { + SpirvOperandKind::IdRef, + R"('Value')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Pointer')" + }, + { + SpirvOperandKind::IdScope, + R"('Memory')" + }, + { + SpirvOperandKind::IdMemorySemantics, + R"('Equal')" + }, + { + SpirvOperandKind::IdMemorySemantics, + R"('Unequal')" + }, + { + SpirvOperandKind::IdRef, + R"('Value')" + }, + { + SpirvOperandKind::IdRef, + R"('Comparator')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Pointer')" + }, + { + SpirvOperandKind::IdScope, + R"('Memory')" + }, + { + SpirvOperandKind::IdMemorySemantics, + R"('Equal')" + }, + { + SpirvOperandKind::IdMemorySemantics, + R"('Unequal')" + }, + { + SpirvOperandKind::IdRef, + R"('Value')" + }, + { + SpirvOperandKind::IdRef, + R"('Comparator')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Pointer')" + }, + { + SpirvOperandKind::IdScope, + R"('Memory')" + }, + { + SpirvOperandKind::IdMemorySemantics, + R"('Semantics')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Pointer')" + }, + { + SpirvOperandKind::IdScope, + R"('Memory')" + }, + { + SpirvOperandKind::IdMemorySemantics, + R"('Semantics')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Pointer')" + }, + { + SpirvOperandKind::IdScope, + R"('Memory')" + }, + { + SpirvOperandKind::IdMemorySemantics, + R"('Semantics')" + }, + { + SpirvOperandKind::IdRef, + R"('Value')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Pointer')" + }, + { + SpirvOperandKind::IdScope, + R"('Memory')" + }, + { + SpirvOperandKind::IdMemorySemantics, + R"('Semantics')" + }, + { + SpirvOperandKind::IdRef, + R"('Value')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Pointer')" + }, + { + SpirvOperandKind::IdScope, + R"('Memory')" + }, + { + SpirvOperandKind::IdMemorySemantics, + R"('Semantics')" + }, + { + SpirvOperandKind::IdRef, + R"('Value')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Pointer')" + }, + { + SpirvOperandKind::IdScope, + R"('Memory')" + }, + { + SpirvOperandKind::IdMemorySemantics, + R"('Semantics')" + }, + { + SpirvOperandKind::IdRef, + R"('Value')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Pointer')" + }, + { + SpirvOperandKind::IdScope, + R"('Memory')" + }, + { + SpirvOperandKind::IdMemorySemantics, + R"('Semantics')" + }, + { + SpirvOperandKind::IdRef, + R"('Value')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Pointer')" + }, + { + SpirvOperandKind::IdScope, + R"('Memory')" + }, + { + SpirvOperandKind::IdMemorySemantics, + R"('Semantics')" + }, + { + SpirvOperandKind::IdRef, + R"('Value')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Pointer')" + }, + { + SpirvOperandKind::IdScope, + R"('Memory')" + }, + { + SpirvOperandKind::IdMemorySemantics, + R"('Semantics')" + }, + { + SpirvOperandKind::IdRef, + R"('Value')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Pointer')" + }, + { + SpirvOperandKind::IdScope, + R"('Memory')" + }, + { + SpirvOperandKind::IdMemorySemantics, + R"('Semantics')" + }, + { + SpirvOperandKind::IdRef, + R"('Value')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Pointer')" + }, + { + SpirvOperandKind::IdScope, + R"('Memory')" + }, + { + SpirvOperandKind::IdMemorySemantics, + R"('Semantics')" + }, + { + SpirvOperandKind::IdRef, + R"('Value')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::PairIdRefIdRef, + R"('Variable, Parent, ...')" + }, + { + SpirvOperandKind::IdRef, + R"('Merge Block')" + }, + { + SpirvOperandKind::IdRef, + R"('Continue Target')" + }, + { + SpirvOperandKind::LoopControl, + R"(LoopControl)" + }, + { + SpirvOperandKind::IdRef, + R"('Merge Block')" + }, + { + SpirvOperandKind::SelectionControl, + R"(SelectionControl)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Target Label')" + }, + { + SpirvOperandKind::IdRef, + R"('Condition')" + }, + { + SpirvOperandKind::IdRef, + R"('True Label')" + }, + { + SpirvOperandKind::IdRef, + R"('False Label')" + }, + { + SpirvOperandKind::LiteralInteger, + R"('Branch weights')" + }, + { + SpirvOperandKind::IdRef, + R"('Selector')" + }, + { + SpirvOperandKind::IdRef, + R"('Default')" + }, + { + SpirvOperandKind::PairLiteralIntegerIdRef, + R"('Target')" + }, + { + SpirvOperandKind::IdRef, + R"('Value')" + }, + { + SpirvOperandKind::IdRef, + R"('Pointer')" + }, + { + SpirvOperandKind::LiteralInteger, + R"('Size')" + }, + { + SpirvOperandKind::IdRef, + R"('Pointer')" + }, + { + SpirvOperandKind::LiteralInteger, + R"('Size')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdScope, + R"('Execution')" + }, + { + SpirvOperandKind::IdRef, + R"('Destination')" + }, + { + SpirvOperandKind::IdRef, + R"('Source')" + }, + { + SpirvOperandKind::IdRef, + R"('Num Elements')" + }, + { + SpirvOperandKind::IdRef, + R"('Stride')" + }, + { + SpirvOperandKind::IdRef, + R"('Event')" + }, + { + SpirvOperandKind::IdScope, + R"('Execution')" + }, + { + SpirvOperandKind::IdRef, + R"('Num Events')" + }, + { + SpirvOperandKind::IdRef, + R"('Events List')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdScope, + R"('Execution')" + }, + { + SpirvOperandKind::IdRef, + R"('Predicate')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdScope, + R"('Execution')" + }, + { + SpirvOperandKind::IdRef, + R"('Predicate')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdScope, + R"('Execution')" + }, + { + SpirvOperandKind::IdRef, + R"('Value')" + }, + { + SpirvOperandKind::IdRef, + R"('LocalId')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdScope, + R"('Execution')" + }, + { + SpirvOperandKind::GroupOperation, + R"('Operation')" + }, + { + SpirvOperandKind::IdRef, + R"('X')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdScope, + R"('Execution')" + }, + { + SpirvOperandKind::GroupOperation, + R"('Operation')" + }, + { + SpirvOperandKind::IdRef, + R"('X')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdScope, + R"('Execution')" + }, + { + SpirvOperandKind::GroupOperation, + R"('Operation')" + }, + { + SpirvOperandKind::IdRef, + R"('X')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdScope, + R"('Execution')" + }, + { + SpirvOperandKind::GroupOperation, + R"('Operation')" + }, + { + SpirvOperandKind::IdRef, + R"('X')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdScope, + R"('Execution')" + }, + { + SpirvOperandKind::GroupOperation, + R"('Operation')" + }, + { + SpirvOperandKind::IdRef, + R"('X')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdScope, + R"('Execution')" + }, + { + SpirvOperandKind::GroupOperation, + R"('Operation')" + }, + { + SpirvOperandKind::IdRef, + R"('X')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdScope, + R"('Execution')" + }, + { + SpirvOperandKind::GroupOperation, + R"('Operation')" + }, + { + SpirvOperandKind::IdRef, + R"('X')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdScope, + R"('Execution')" + }, + { + SpirvOperandKind::GroupOperation, + R"('Operation')" + }, + { + SpirvOperandKind::IdRef, + R"('X')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Pipe')" + }, + { + SpirvOperandKind::IdRef, + R"('Pointer')" + }, + { + SpirvOperandKind::IdRef, + R"('Packet Size')" + }, + { + SpirvOperandKind::IdRef, + R"('Packet Alignment')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Pipe')" + }, + { + SpirvOperandKind::IdRef, + R"('Pointer')" + }, + { + SpirvOperandKind::IdRef, + R"('Packet Size')" + }, + { + SpirvOperandKind::IdRef, + R"('Packet Alignment')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Pipe')" + }, + { + SpirvOperandKind::IdRef, + R"('Reserve Id')" + }, + { + SpirvOperandKind::IdRef, + R"('Index')" + }, + { + SpirvOperandKind::IdRef, + R"('Pointer')" + }, + { + SpirvOperandKind::IdRef, + R"('Packet Size')" + }, + { + SpirvOperandKind::IdRef, + R"('Packet Alignment')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Pipe')" + }, + { + SpirvOperandKind::IdRef, + R"('Reserve Id')" + }, + { + SpirvOperandKind::IdRef, + R"('Index')" + }, + { + SpirvOperandKind::IdRef, + R"('Pointer')" + }, + { + SpirvOperandKind::IdRef, + R"('Packet Size')" + }, + { + SpirvOperandKind::IdRef, + R"('Packet Alignment')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Pipe')" + }, + { + SpirvOperandKind::IdRef, + R"('Num Packets')" + }, + { + SpirvOperandKind::IdRef, + R"('Packet Size')" + }, + { + SpirvOperandKind::IdRef, + R"('Packet Alignment')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Pipe')" + }, + { + SpirvOperandKind::IdRef, + R"('Num Packets')" + }, + { + SpirvOperandKind::IdRef, + R"('Packet Size')" + }, + { + SpirvOperandKind::IdRef, + R"('Packet Alignment')" + }, + { + SpirvOperandKind::IdRef, + R"('Pipe')" + }, + { + SpirvOperandKind::IdRef, + R"('Reserve Id')" + }, + { + SpirvOperandKind::IdRef, + R"('Packet Size')" + }, + { + SpirvOperandKind::IdRef, + R"('Packet Alignment')" + }, + { + SpirvOperandKind::IdRef, + R"('Pipe')" + }, + { + SpirvOperandKind::IdRef, + R"('Reserve Id')" + }, + { + SpirvOperandKind::IdRef, + R"('Packet Size')" + }, + { + SpirvOperandKind::IdRef, + R"('Packet Alignment')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Reserve Id')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Pipe')" + }, + { + SpirvOperandKind::IdRef, + R"('Packet Size')" + }, + { + SpirvOperandKind::IdRef, + R"('Packet Alignment')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Pipe')" + }, + { + SpirvOperandKind::IdRef, + R"('Packet Size')" + }, + { + SpirvOperandKind::IdRef, + R"('Packet Alignment')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdScope, + R"('Execution')" + }, + { + SpirvOperandKind::IdRef, + R"('Pipe')" + }, + { + SpirvOperandKind::IdRef, + R"('Num Packets')" + }, + { + SpirvOperandKind::IdRef, + R"('Packet Size')" + }, + { + SpirvOperandKind::IdRef, + R"('Packet Alignment')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdScope, + R"('Execution')" + }, + { + SpirvOperandKind::IdRef, + R"('Pipe')" + }, + { + SpirvOperandKind::IdRef, + R"('Num Packets')" + }, + { + SpirvOperandKind::IdRef, + R"('Packet Size')" + }, + { + SpirvOperandKind::IdRef, + R"('Packet Alignment')" + }, + { + SpirvOperandKind::IdScope, + R"('Execution')" + }, + { + SpirvOperandKind::IdRef, + R"('Pipe')" + }, + { + SpirvOperandKind::IdRef, + R"('Reserve Id')" + }, + { + SpirvOperandKind::IdRef, + R"('Packet Size')" + }, + { + SpirvOperandKind::IdRef, + R"('Packet Alignment')" + }, + { + SpirvOperandKind::IdScope, + R"('Execution')" + }, + { + SpirvOperandKind::IdRef, + R"('Pipe')" + }, + { + SpirvOperandKind::IdRef, + R"('Reserve Id')" + }, + { + SpirvOperandKind::IdRef, + R"('Packet Size')" + }, + { + SpirvOperandKind::IdRef, + R"('Packet Alignment')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Queue')" + }, + { + SpirvOperandKind::IdRef, + R"('Num Events')" + }, + { + SpirvOperandKind::IdRef, + R"('Wait Events')" + }, + { + SpirvOperandKind::IdRef, + R"('Ret Event')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Queue')" + }, + { + SpirvOperandKind::IdRef, + R"('Flags')" + }, + { + SpirvOperandKind::IdRef, + R"('ND Range')" + }, + { + SpirvOperandKind::IdRef, + R"('Num Events')" + }, + { + SpirvOperandKind::IdRef, + R"('Wait Events')" + }, + { + SpirvOperandKind::IdRef, + R"('Ret Event')" + }, + { + SpirvOperandKind::IdRef, + R"('Invoke')" + }, + { + SpirvOperandKind::IdRef, + R"('Param')" + }, + { + SpirvOperandKind::IdRef, + R"('Param Size')" + }, + { + SpirvOperandKind::IdRef, + R"('Param Align')" + }, + { + SpirvOperandKind::IdRef, + R"('Local Size')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('ND Range')" + }, + { + SpirvOperandKind::IdRef, + R"('Invoke')" + }, + { + SpirvOperandKind::IdRef, + R"('Param')" + }, + { + SpirvOperandKind::IdRef, + R"('Param Size')" + }, + { + SpirvOperandKind::IdRef, + R"('Param Align')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('ND Range')" + }, + { + SpirvOperandKind::IdRef, + R"('Invoke')" + }, + { + SpirvOperandKind::IdRef, + R"('Param')" + }, + { + SpirvOperandKind::IdRef, + R"('Param Size')" + }, + { + SpirvOperandKind::IdRef, + R"('Param Align')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Invoke')" + }, + { + SpirvOperandKind::IdRef, + R"('Param')" + }, + { + SpirvOperandKind::IdRef, + R"('Param Size')" + }, + { + SpirvOperandKind::IdRef, + R"('Param Align')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Invoke')" + }, + { + SpirvOperandKind::IdRef, + R"('Param')" + }, + { + SpirvOperandKind::IdRef, + R"('Param Size')" + }, + { + SpirvOperandKind::IdRef, + R"('Param Align')" + }, + { + SpirvOperandKind::IdRef, + R"('Event')" + }, + { + SpirvOperandKind::IdRef, + R"('Event')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Event')" + }, + { + SpirvOperandKind::IdRef, + R"('Event')" + }, + { + SpirvOperandKind::IdRef, + R"('Status')" + }, + { + SpirvOperandKind::IdRef, + R"('Event')" + }, + { + SpirvOperandKind::IdRef, + R"('Profiling Info')" + }, + { + SpirvOperandKind::IdRef, + R"('Value')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('GlobalWorkSize')" + }, + { + SpirvOperandKind::IdRef, + R"('LocalWorkSize')" + }, + { + SpirvOperandKind::IdRef, + R"('GlobalWorkOffset')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Sampled Image')" + }, + { + SpirvOperandKind::IdRef, + R"('Coordinate')" + }, + { + SpirvOperandKind::ImageOperands, + R"(ImageOperands)" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Sampled Image')" + }, + { + SpirvOperandKind::IdRef, + R"('Coordinate')" + }, + { + SpirvOperandKind::ImageOperands, + R"(ImageOperands)" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Sampled Image')" + }, + { + SpirvOperandKind::IdRef, + R"('Coordinate')" + }, + { + SpirvOperandKind::IdRef, + R"('D~ref~')" + }, + { + SpirvOperandKind::ImageOperands, + R"(ImageOperands)" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Sampled Image')" + }, + { + SpirvOperandKind::IdRef, + R"('Coordinate')" + }, + { + SpirvOperandKind::IdRef, + R"('D~ref~')" + }, + { + SpirvOperandKind::ImageOperands, + R"(ImageOperands)" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Sampled Image')" + }, + { + SpirvOperandKind::IdRef, + R"('Coordinate')" + }, + { + SpirvOperandKind::ImageOperands, + R"(ImageOperands)" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Sampled Image')" + }, + { + SpirvOperandKind::IdRef, + R"('Coordinate')" + }, + { + SpirvOperandKind::ImageOperands, + R"(ImageOperands)" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Sampled Image')" + }, + { + SpirvOperandKind::IdRef, + R"('Coordinate')" + }, + { + SpirvOperandKind::IdRef, + R"('D~ref~')" + }, + { + SpirvOperandKind::ImageOperands, + R"(ImageOperands)" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Sampled Image')" + }, + { + SpirvOperandKind::IdRef, + R"('Coordinate')" + }, + { + SpirvOperandKind::IdRef, + R"('D~ref~')" + }, + { + SpirvOperandKind::ImageOperands, + R"(ImageOperands)" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Image')" + }, + { + SpirvOperandKind::IdRef, + R"('Coordinate')" + }, + { + SpirvOperandKind::ImageOperands, + R"(ImageOperands)" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Sampled Image')" + }, + { + SpirvOperandKind::IdRef, + R"('Coordinate')" + }, + { + SpirvOperandKind::IdRef, + R"('Component')" + }, + { + SpirvOperandKind::ImageOperands, + R"(ImageOperands)" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Sampled Image')" + }, + { + SpirvOperandKind::IdRef, + R"('Coordinate')" + }, + { + SpirvOperandKind::IdRef, + R"('D~ref~')" + }, + { + SpirvOperandKind::ImageOperands, + R"(ImageOperands)" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Resident Code')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Pointer')" + }, + { + SpirvOperandKind::IdScope, + R"('Memory')" + }, + { + SpirvOperandKind::IdMemorySemantics, + R"('Semantics')" + }, + { + SpirvOperandKind::IdRef, + R"('Pointer')" + }, + { + SpirvOperandKind::IdScope, + R"('Memory')" + }, + { + SpirvOperandKind::IdMemorySemantics, + R"('Semantics')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Image')" + }, + { + SpirvOperandKind::IdRef, + R"('Coordinate')" + }, + { + SpirvOperandKind::ImageOperands, + R"(ImageOperands)" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Pointer')" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::LiteralInteger, + R"('Packet Size')" + }, + { + SpirvOperandKind::LiteralInteger, + R"('Packet Alignment')" + }, + { + SpirvOperandKind::LiteralInteger, + R"('Capacity')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Pipe Storage')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Subgroup Count')" + }, + { + SpirvOperandKind::IdRef, + R"('Invoke')" + }, + { + SpirvOperandKind::IdRef, + R"('Param')" + }, + { + SpirvOperandKind::IdRef, + R"('Param Size')" + }, + { + SpirvOperandKind::IdRef, + R"('Param Align')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Invoke')" + }, + { + SpirvOperandKind::IdRef, + R"('Param')" + }, + { + SpirvOperandKind::IdRef, + R"('Param Size')" + }, + { + SpirvOperandKind::IdRef, + R"('Param Align')" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Subgroup Count')" + }, + { + SpirvOperandKind::IdRef, + R"('Named Barrier')" + }, + { + SpirvOperandKind::IdScope, + R"('Memory')" + }, + { + SpirvOperandKind::IdMemorySemantics, + R"('Semantics')" + }, + { + SpirvOperandKind::LiteralString, + R"('Process')" + }, + { + SpirvOperandKind::IdRef, + R"('Entry Point')" + }, + { + SpirvOperandKind::ExecutionMode, + R"('Mode')" + }, + { + SpirvOperandKind::IdRef, + R"('Target')" + }, + { + SpirvOperandKind::Decoration, + R"(Decoration)" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdScope, + R"('Execution')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdScope, + R"('Execution')" + }, + { + SpirvOperandKind::IdRef, + R"('Predicate')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdScope, + R"('Execution')" + }, + { + SpirvOperandKind::IdRef, + R"('Predicate')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdScope, + R"('Execution')" + }, + { + SpirvOperandKind::IdRef, + R"('Value')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdScope, + R"('Execution')" + }, + { + SpirvOperandKind::IdRef, + R"('Value')" + }, + { + SpirvOperandKind::IdRef, + R"('Id')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdScope, + R"('Execution')" + }, + { + SpirvOperandKind::IdRef, + R"('Value')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdScope, + R"('Execution')" + }, + { + SpirvOperandKind::IdRef, + R"('Predicate')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdScope, + R"('Execution')" + }, + { + SpirvOperandKind::IdRef, + R"('Value')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdScope, + R"('Execution')" + }, + { + SpirvOperandKind::IdRef, + R"('Value')" + }, + { + SpirvOperandKind::IdRef, + R"('Index')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdScope, + R"('Execution')" + }, + { + SpirvOperandKind::GroupOperation, + R"('Operation')" + }, + { + SpirvOperandKind::IdRef, + R"('Value')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdScope, + R"('Execution')" + }, + { + SpirvOperandKind::IdRef, + R"('Value')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdScope, + R"('Execution')" + }, + { + SpirvOperandKind::IdRef, + R"('Value')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdScope, + R"('Execution')" + }, + { + SpirvOperandKind::IdRef, + R"('Value')" + }, + { + SpirvOperandKind::IdRef, + R"('Id')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdScope, + R"('Execution')" + }, + { + SpirvOperandKind::IdRef, + R"('Value')" + }, + { + SpirvOperandKind::IdRef, + R"('Mask')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdScope, + R"('Execution')" + }, + { + SpirvOperandKind::IdRef, + R"('Value')" + }, + { + SpirvOperandKind::IdRef, + R"('Delta')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdScope, + R"('Execution')" + }, + { + SpirvOperandKind::IdRef, + R"('Value')" + }, + { + SpirvOperandKind::IdRef, + R"('Delta')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdScope, + R"('Execution')" + }, + { + SpirvOperandKind::GroupOperation, + R"('Operation')" + }, + { + SpirvOperandKind::IdRef, + R"('Value')" + }, + { + SpirvOperandKind::IdRef, + R"('ClusterSize')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdScope, + R"('Execution')" + }, + { + SpirvOperandKind::GroupOperation, + R"('Operation')" + }, + { + SpirvOperandKind::IdRef, + R"('Value')" + }, + { + SpirvOperandKind::IdRef, + R"('ClusterSize')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdScope, + R"('Execution')" + }, + { + SpirvOperandKind::GroupOperation, + R"('Operation')" + }, + { + SpirvOperandKind::IdRef, + R"('Value')" + }, + { + SpirvOperandKind::IdRef, + R"('ClusterSize')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdScope, + R"('Execution')" + }, + { + SpirvOperandKind::GroupOperation, + R"('Operation')" + }, + { + SpirvOperandKind::IdRef, + R"('Value')" + }, + { + SpirvOperandKind::IdRef, + R"('ClusterSize')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdScope, + R"('Execution')" + }, + { + SpirvOperandKind::GroupOperation, + R"('Operation')" + }, + { + SpirvOperandKind::IdRef, + R"('Value')" + }, + { + SpirvOperandKind::IdRef, + R"('ClusterSize')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdScope, + R"('Execution')" + }, + { + SpirvOperandKind::GroupOperation, + R"('Operation')" + }, + { + SpirvOperandKind::IdRef, + R"('Value')" + }, + { + SpirvOperandKind::IdRef, + R"('ClusterSize')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdScope, + R"('Execution')" + }, + { + SpirvOperandKind::GroupOperation, + R"('Operation')" + }, + { + SpirvOperandKind::IdRef, + R"('Value')" + }, + { + SpirvOperandKind::IdRef, + R"('ClusterSize')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdScope, + R"('Execution')" + }, + { + SpirvOperandKind::GroupOperation, + R"('Operation')" + }, + { + SpirvOperandKind::IdRef, + R"('Value')" + }, + { + SpirvOperandKind::IdRef, + R"('ClusterSize')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdScope, + R"('Execution')" + }, + { + SpirvOperandKind::GroupOperation, + R"('Operation')" + }, + { + SpirvOperandKind::IdRef, + R"('Value')" + }, + { + SpirvOperandKind::IdRef, + R"('ClusterSize')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdScope, + R"('Execution')" + }, + { + SpirvOperandKind::GroupOperation, + R"('Operation')" + }, + { + SpirvOperandKind::IdRef, + R"('Value')" + }, + { + SpirvOperandKind::IdRef, + R"('ClusterSize')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdScope, + R"('Execution')" + }, + { + SpirvOperandKind::GroupOperation, + R"('Operation')" + }, + { + SpirvOperandKind::IdRef, + R"('Value')" + }, + { + SpirvOperandKind::IdRef, + R"('ClusterSize')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdScope, + R"('Execution')" + }, + { + SpirvOperandKind::GroupOperation, + R"('Operation')" + }, + { + SpirvOperandKind::IdRef, + R"('Value')" + }, + { + SpirvOperandKind::IdRef, + R"('ClusterSize')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdScope, + R"('Execution')" + }, + { + SpirvOperandKind::GroupOperation, + R"('Operation')" + }, + { + SpirvOperandKind::IdRef, + R"('Value')" + }, + { + SpirvOperandKind::IdRef, + R"('ClusterSize')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdScope, + R"('Execution')" + }, + { + SpirvOperandKind::GroupOperation, + R"('Operation')" + }, + { + SpirvOperandKind::IdRef, + R"('Value')" + }, + { + SpirvOperandKind::IdRef, + R"('ClusterSize')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdScope, + R"('Execution')" + }, + { + SpirvOperandKind::GroupOperation, + R"('Operation')" + }, + { + SpirvOperandKind::IdRef, + R"('Value')" + }, + { + SpirvOperandKind::IdRef, + R"('ClusterSize')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdScope, + R"('Execution')" + }, + { + SpirvOperandKind::GroupOperation, + R"('Operation')" + }, + { + SpirvOperandKind::IdRef, + R"('Value')" + }, + { + SpirvOperandKind::IdRef, + R"('ClusterSize')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdScope, + R"('Execution')" + }, + { + SpirvOperandKind::IdRef, + R"('Value')" + }, + { + SpirvOperandKind::IdRef, + R"('Index')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdScope, + R"('Execution')" + }, + { + SpirvOperandKind::IdRef, + R"('Value')" + }, + { + SpirvOperandKind::IdRef, + R"('Direction')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Operand')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 1')" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 2')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 1')" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 2')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 1')" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 2')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Predicate')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Value')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Predicate')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Predicate')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Predicate')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Value')" + }, + { + SpirvOperandKind::IdRef, + R"('Index')" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('RayQuery')" + }, + { + SpirvOperandKind::IdRef, + R"('Accel')" + }, + { + SpirvOperandKind::IdRef, + R"('RayFlags')" + }, + { + SpirvOperandKind::IdRef, + R"('CullMask')" + }, + { + SpirvOperandKind::IdRef, + R"('RayOrigin')" + }, + { + SpirvOperandKind::IdRef, + R"('RayTMin')" + }, + { + SpirvOperandKind::IdRef, + R"('RayDirection')" + }, + { + SpirvOperandKind::IdRef, + R"('RayTMax')" + }, + { + SpirvOperandKind::IdRef, + R"('RayQuery')" + }, + { + SpirvOperandKind::IdRef, + R"('RayQuery')" + }, + { + SpirvOperandKind::IdRef, + R"('HitT')" + }, + { + SpirvOperandKind::IdRef, + R"('RayQuery')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('RayQuery')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('RayQuery')" + }, + { + SpirvOperandKind::IdRef, + R"('Intersection')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdScope, + R"('Execution')" + }, + { + SpirvOperandKind::GroupOperation, + R"('Operation')" + }, + { + SpirvOperandKind::IdRef, + R"('X')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdScope, + R"('Execution')" + }, + { + SpirvOperandKind::GroupOperation, + R"('Operation')" + }, + { + SpirvOperandKind::IdRef, + R"('X')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdScope, + R"('Execution')" + }, + { + SpirvOperandKind::GroupOperation, + R"('Operation')" + }, + { + SpirvOperandKind::IdRef, + R"('X')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdScope, + R"('Execution')" + }, + { + SpirvOperandKind::GroupOperation, + R"('Operation')" + }, + { + SpirvOperandKind::IdRef, + R"('X')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdScope, + R"('Execution')" + }, + { + SpirvOperandKind::GroupOperation, + R"('Operation')" + }, + { + SpirvOperandKind::IdRef, + R"('X')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdScope, + R"('Execution')" + }, + { + SpirvOperandKind::GroupOperation, + R"('Operation')" + }, + { + SpirvOperandKind::IdRef, + R"('X')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdScope, + R"('Execution')" + }, + { + SpirvOperandKind::GroupOperation, + R"('Operation')" + }, + { + SpirvOperandKind::IdRef, + R"('X')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdScope, + R"('Execution')" + }, + { + SpirvOperandKind::GroupOperation, + R"('Operation')" + }, + { + SpirvOperandKind::IdRef, + R"('X')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Image')" + }, + { + SpirvOperandKind::IdRef, + R"('Coordinate')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Image')" + }, + { + SpirvOperandKind::IdRef, + R"('Coordinate')" + }, + { + SpirvOperandKind::IdRef, + R"('Fragment Index')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdScope, + R"('Execution')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Sampled Image')" + }, + { + SpirvOperandKind::IdRef, + R"('Coordinate')" + }, + { + SpirvOperandKind::IdRef, + R"('Granularity')" + }, + { + SpirvOperandKind::IdRef, + R"('Coarse')" + }, + { + SpirvOperandKind::ImageOperands, + R"(ImageOperands)" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Value')" + }, + { + SpirvOperandKind::IdRef, + R"('Index Offset')" + }, + { + SpirvOperandKind::IdRef, + R"('Packed Indices')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Hit')" + }, + { + SpirvOperandKind::IdRef, + R"('HitKind')" + }, + { + SpirvOperandKind::IdRef, + R"('Accel')" + }, + { + SpirvOperandKind::IdRef, + R"('Ray Flags')" + }, + { + SpirvOperandKind::IdRef, + R"('Cull Mask')" + }, + { + SpirvOperandKind::IdRef, + R"('SBT Offset')" + }, + { + SpirvOperandKind::IdRef, + R"('SBT Stride')" + }, + { + SpirvOperandKind::IdRef, + R"('Miss Index')" + }, + { + SpirvOperandKind::IdRef, + R"('Ray Origin')" + }, + { + SpirvOperandKind::IdRef, + R"('Ray Tmin')" + }, + { + SpirvOperandKind::IdRef, + R"('Ray Direction')" + }, + { + SpirvOperandKind::IdRef, + R"('Ray Tmax')" + }, + { + SpirvOperandKind::IdRef, + R"('PayloadId')" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('SBT Index')" + }, + { + SpirvOperandKind::IdRef, + R"('Callable DataId')" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Component Type')" + }, + { + SpirvOperandKind::IdScope, + R"('Execution')" + }, + { + SpirvOperandKind::IdRef, + R"('Rows')" + }, + { + SpirvOperandKind::IdRef, + R"('Columns')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Pointer')" + }, + { + SpirvOperandKind::IdRef, + R"('Stride')" + }, + { + SpirvOperandKind::IdRef, + R"('Column Major')" + }, + { + SpirvOperandKind::MemoryAccess, + R"(MemoryAccess)" + }, + { + SpirvOperandKind::IdRef, + R"('Pointer')" + }, + { + SpirvOperandKind::IdRef, + R"('Object')" + }, + { + SpirvOperandKind::IdRef, + R"('Stride')" + }, + { + SpirvOperandKind::IdRef, + R"('Column Major')" + }, + { + SpirvOperandKind::MemoryAccess, + R"(MemoryAccess)" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('A')" + }, + { + SpirvOperandKind::IdRef, + R"('B')" + }, + { + SpirvOperandKind::IdRef, + R"('C')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Type')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Data')" + }, + { + SpirvOperandKind::IdRef, + R"('InvocationId')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Current')" + }, + { + SpirvOperandKind::IdRef, + R"('Next')" + }, + { + SpirvOperandKind::IdRef, + R"('Delta')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Previous')" + }, + { + SpirvOperandKind::IdRef, + R"('Current')" + }, + { + SpirvOperandKind::IdRef, + R"('Delta')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Data')" + }, + { + SpirvOperandKind::IdRef, + R"('Value')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Ptr')" + }, + { + SpirvOperandKind::IdRef, + R"('Ptr')" + }, + { + SpirvOperandKind::IdRef, + R"('Data')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Image')" + }, + { + SpirvOperandKind::IdRef, + R"('Coordinate')" + }, + { + SpirvOperandKind::IdRef, + R"('Image')" + }, + { + SpirvOperandKind::IdRef, + R"('Coordinate')" + }, + { + SpirvOperandKind::IdRef, + R"('Data')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Image')" + }, + { + SpirvOperandKind::IdRef, + R"('Coordinate')" + }, + { + SpirvOperandKind::IdRef, + R"('Width')" + }, + { + SpirvOperandKind::IdRef, + R"('Height')" + }, + { + SpirvOperandKind::IdRef, + R"('Image')" + }, + { + SpirvOperandKind::IdRef, + R"('Coordinate')" + }, + { + SpirvOperandKind::IdRef, + R"('Width')" + }, + { + SpirvOperandKind::IdRef, + R"('Height')" + }, + { + SpirvOperandKind::IdRef, + R"('Data')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Operand')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Operand')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 1')" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 2')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 1')" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 2')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 1')" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 2')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 1')" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 2')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 1')" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 2')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 1')" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 2')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 1')" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 2')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 1')" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 2')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 1')" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 2')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 1')" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 2')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 1')" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 2')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 1')" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 2')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Function')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Operand 1')" + }, + { + SpirvOperandKind::IdRef, + R"('Target')" + }, + { + SpirvOperandKind::Decoration, + R"(Decoration)" + }, + { + SpirvOperandKind::IdRef, + R"('Struct Type')" + }, + { + SpirvOperandKind::LiteralInteger, + R"('Member')" + }, + { + SpirvOperandKind::Decoration, + R"(Decoration)" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Image Type')" + }, + { + SpirvOperandKind::IdRef, + R"('Sampler')" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Image Type')" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Slice Type')" + }, + { + SpirvOperandKind::IdRef, + R"('Qp')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Reference Base Penalty')" + }, + { + SpirvOperandKind::IdRef, + R"('Payload')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Slice Type')" + }, + { + SpirvOperandKind::IdRef, + R"('Qp')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Packed Shape Penalty')" + }, + { + SpirvOperandKind::IdRef, + R"('Payload')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Slice Type')" + }, + { + SpirvOperandKind::IdRef, + R"('Qp')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Direction Cost')" + }, + { + SpirvOperandKind::IdRef, + R"('Payload')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Slice Type')" + }, + { + SpirvOperandKind::IdRef, + R"('Qp')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Slice Type')" + }, + { + SpirvOperandKind::IdRef, + R"('Qp')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Packed Cost Center Delta')" + }, + { + SpirvOperandKind::IdRef, + R"('Packed Cost Table')" + }, + { + SpirvOperandKind::IdRef, + R"('Cost Precision')" + }, + { + SpirvOperandKind::IdRef, + R"('Payload')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Slice Type')" + }, + { + SpirvOperandKind::IdRef, + R"('Qp')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Payload')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Source Field Polarity')" + }, + { + SpirvOperandKind::IdRef, + R"('Payload')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Reference Field Polarity')" + }, + { + SpirvOperandKind::IdRef, + R"('Payload')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Forward Reference Field Polarity')" + }, + { + SpirvOperandKind::IdRef, + R"('Backward Reference Field Polarity')" + }, + { + SpirvOperandKind::IdRef, + R"('Payload')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Payload')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Payload')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Payload')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Payload')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Payload')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Payload')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Payload')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Payload')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Payload')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Payload')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Payload')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Payload')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Payload')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Payload')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Packed Reference Ids')" + }, + { + SpirvOperandKind::IdRef, + R"('Packed Reference Parameter Field Polarities')" + }, + { + SpirvOperandKind::IdRef, + R"('Payload')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Src Coord')" + }, + { + SpirvOperandKind::IdRef, + R"('Partition Mask')" + }, + { + SpirvOperandKind::IdRef, + R"('SAD Adjustment')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Ref Offset')" + }, + { + SpirvOperandKind::IdRef, + R"('Search Window Config')" + }, + { + SpirvOperandKind::IdRef, + R"('Payload')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Fwd Ref Offset')" + }, + { + SpirvOperandKind::IdRef, + R"('Bwd Ref Offset')" + }, + { + SpirvOperandKind::IdRef, + R"('id> Search Window Config')" + }, + { + SpirvOperandKind::IdRef, + R"('Payload')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Search Window Config')" + }, + { + SpirvOperandKind::IdRef, + R"('Dual Ref')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Ref Offset')" + }, + { + SpirvOperandKind::IdRef, + R"('Src Coord')" + }, + { + SpirvOperandKind::IdRef, + R"('Ref Window Size')" + }, + { + SpirvOperandKind::IdRef, + R"('Image Size')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Payload')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Max Motion Vector Count')" + }, + { + SpirvOperandKind::IdRef, + R"('Payload')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Payload')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Threshold')" + }, + { + SpirvOperandKind::IdRef, + R"('Payload')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Packed Sad Weights')" + }, + { + SpirvOperandKind::IdRef, + R"('Payload')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Src Image')" + }, + { + SpirvOperandKind::IdRef, + R"('Ref Image')" + }, + { + SpirvOperandKind::IdRef, + R"('Payload')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Src Image')" + }, + { + SpirvOperandKind::IdRef, + R"('Fwd Ref Image')" + }, + { + SpirvOperandKind::IdRef, + R"('Bwd Ref Image')" + }, + { + SpirvOperandKind::IdRef, + R"('Payload')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Src Image')" + }, + { + SpirvOperandKind::IdRef, + R"('Ref Image')" + }, + { + SpirvOperandKind::IdRef, + R"('Payload')" + }, + { + SpirvOperandKind::IdRef, + R"('Streamin Components')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Src Image')" + }, + { + SpirvOperandKind::IdRef, + R"('Fwd Ref Image')" + }, + { + SpirvOperandKind::IdRef, + R"('Bwd Ref Image')" + }, + { + SpirvOperandKind::IdRef, + R"('Payload')" + }, + { + SpirvOperandKind::IdRef, + R"('Streamin Components')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Src Image')" + }, + { + SpirvOperandKind::IdRef, + R"('Ref Image')" + }, + { + SpirvOperandKind::IdRef, + R"('Payload')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Src Image')" + }, + { + SpirvOperandKind::IdRef, + R"('Fwd Ref Image')" + }, + { + SpirvOperandKind::IdRef, + R"('Bwd Ref Image')" + }, + { + SpirvOperandKind::IdRef, + R"('Payload')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Src Image')" + }, + { + SpirvOperandKind::IdRef, + R"('Ref Image')" + }, + { + SpirvOperandKind::IdRef, + R"('Payload')" + }, + { + SpirvOperandKind::IdRef, + R"('Streamin Components')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Src Image')" + }, + { + SpirvOperandKind::IdRef, + R"('Fwd Ref Image')" + }, + { + SpirvOperandKind::IdRef, + R"('Bwd Ref Image')" + }, + { + SpirvOperandKind::IdRef, + R"('Payload')" + }, + { + SpirvOperandKind::IdRef, + R"('Streamin Components')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Payload')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Payload')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Payload')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Payload')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Payload')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Payload')" + }, + { + SpirvOperandKind::IdRef, + R"('Major Shape')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Payload')" + }, + { + SpirvOperandKind::IdRef, + R"('Major Shape')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Payload')" + }, + { + SpirvOperandKind::IdRef, + R"('Major Shape')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Payload')" + }, + { + SpirvOperandKind::IdRef, + R"('Major Shape')" + }, + { + SpirvOperandKind::IdRef, + R"('Direction')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Payload')" + }, + { + SpirvOperandKind::IdRef, + R"('Major Shape')" + }, + { + SpirvOperandKind::IdRef, + R"('Direction')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Payload')" + }, + { + SpirvOperandKind::IdRef, + R"('Major Shape')" + }, + { + SpirvOperandKind::IdRef, + R"('Direction')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Image Select')" + }, + { + SpirvOperandKind::IdRef, + R"('Payload')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Payload')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Payload')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Payload')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Payload')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Src Coord')" + }, + { + SpirvOperandKind::IdRef, + R"('Motion Vectors')" + }, + { + SpirvOperandKind::IdRef, + R"('Major Shapes')" + }, + { + SpirvOperandKind::IdRef, + R"('Minor Shapes')" + }, + { + SpirvOperandKind::IdRef, + R"('Direction')" + }, + { + SpirvOperandKind::IdRef, + R"('Pixel Resolution')" + }, + { + SpirvOperandKind::IdRef, + R"('Sad Adjustment')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Src Coord')" + }, + { + SpirvOperandKind::IdRef, + R"('Motion Vectors')" + }, + { + SpirvOperandKind::IdRef, + R"('Major Shapes')" + }, + { + SpirvOperandKind::IdRef, + R"('Minor Shapes')" + }, + { + SpirvOperandKind::IdRef, + R"('Direction')" + }, + { + SpirvOperandKind::IdRef, + R"('Pixel Resolution')" + }, + { + SpirvOperandKind::IdRef, + R"('Bidirectional Weight')" + }, + { + SpirvOperandKind::IdRef, + R"('Sad Adjustment')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Payload')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Payload')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Payload')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Src Image')" + }, + { + SpirvOperandKind::IdRef, + R"('Ref Image')" + }, + { + SpirvOperandKind::IdRef, + R"('Payload')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Src Image')" + }, + { + SpirvOperandKind::IdRef, + R"('Fwd Ref Image')" + }, + { + SpirvOperandKind::IdRef, + R"('Bwd Ref Image')" + }, + { + SpirvOperandKind::IdRef, + R"('Payload')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Src Image')" + }, + { + SpirvOperandKind::IdRef, + R"('Packed Reference Ids')" + }, + { + SpirvOperandKind::IdRef, + R"('Payload')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Src Image')" + }, + { + SpirvOperandKind::IdRef, + R"('Packed Reference Ids')" + }, + { + SpirvOperandKind::IdRef, + R"('Packed Reference Field Polarities')" + }, + { + SpirvOperandKind::IdRef, + R"('Payload')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Payload')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Src Coord')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Skip Block Partition Type')" + }, + { + SpirvOperandKind::IdRef, + R"('Skip Motion Vector Mask')" + }, + { + SpirvOperandKind::IdRef, + R"('Motion Vectors')" + }, + { + SpirvOperandKind::IdRef, + R"('Bidirectional Weight')" + }, + { + SpirvOperandKind::IdRef, + R"('Sad Adjustment')" + }, + { + SpirvOperandKind::IdRef, + R"('Payload')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Luma Intra Partition Mask')" + }, + { + SpirvOperandKind::IdRef, + R"('Intra Neighbour Availabilty')" + }, + { + SpirvOperandKind::IdRef, + R"('Left Edge Luma Pixels')" + }, + { + SpirvOperandKind::IdRef, + R"('Upper Left Corner Luma Pixel')" + }, + { + SpirvOperandKind::IdRef, + R"('Upper Edge Luma Pixels')" + }, + { + SpirvOperandKind::IdRef, + R"('Upper Right Edge Luma Pixels')" + }, + { + SpirvOperandKind::IdRef, + R"('Sad Adjustment')" + }, + { + SpirvOperandKind::IdRef, + R"('Payload')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Luma Intra Partition Mask')" + }, + { + SpirvOperandKind::IdRef, + R"('Intra Neighbour Availabilty')" + }, + { + SpirvOperandKind::IdRef, + R"('Left Edge Luma Pixels')" + }, + { + SpirvOperandKind::IdRef, + R"('Upper Left Corner Luma Pixel')" + }, + { + SpirvOperandKind::IdRef, + R"('Upper Edge Luma Pixels')" + }, + { + SpirvOperandKind::IdRef, + R"('Upper Right Edge Luma Pixels')" + }, + { + SpirvOperandKind::IdRef, + R"('Left Edge Chroma Pixels')" + }, + { + SpirvOperandKind::IdRef, + R"('Upper Left Corner Chroma Pixel')" + }, + { + SpirvOperandKind::IdRef, + R"('Upper Edge Chroma Pixels')" + }, + { + SpirvOperandKind::IdRef, + R"('Sad Adjustment')" + }, + { + SpirvOperandKind::IdRef, + R"('Payload')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Skip Block Partition Type')" + }, + { + SpirvOperandKind::IdRef, + R"('Direction')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Payload')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Packed Shape Penalty')" + }, + { + SpirvOperandKind::IdRef, + R"('Payload')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Luma Mode Penalty')" + }, + { + SpirvOperandKind::IdRef, + R"('Luma Packed Neighbor Modes')" + }, + { + SpirvOperandKind::IdRef, + R"('Luma Packed Non Dc Penalty')" + }, + { + SpirvOperandKind::IdRef, + R"('Payload')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Chroma Mode Base Penalty')" + }, + { + SpirvOperandKind::IdRef, + R"('Payload')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Payload')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Packed Sad Coefficients')" + }, + { + SpirvOperandKind::IdRef, + R"('Payload')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Block Based Skip Type')" + }, + { + SpirvOperandKind::IdRef, + R"('Payload')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Src Image')" + }, + { + SpirvOperandKind::IdRef, + R"('Payload')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Src Image')" + }, + { + SpirvOperandKind::IdRef, + R"('Ref Image')" + }, + { + SpirvOperandKind::IdRef, + R"('Payload')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Src Image')" + }, + { + SpirvOperandKind::IdRef, + R"('Fwd Ref Image')" + }, + { + SpirvOperandKind::IdRef, + R"('Bwd Ref Image')" + }, + { + SpirvOperandKind::IdRef, + R"('Payload')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Src Image')" + }, + { + SpirvOperandKind::IdRef, + R"('Packed Reference Ids')" + }, + { + SpirvOperandKind::IdRef, + R"('Payload')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Src Image')" + }, + { + SpirvOperandKind::IdRef, + R"('Packed Reference Ids')" + }, + { + SpirvOperandKind::IdRef, + R"('Packed Reference Field Polarities')" + }, + { + SpirvOperandKind::IdRef, + R"('Payload')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Payload')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Payload')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Payload')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Payload')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Payload')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Payload')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Payload')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Payload')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Payload')" + }, + { + SpirvOperandKind::LiteralInteger, + R"('Loop Control Parameters')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Packet Size')" + }, + { + SpirvOperandKind::IdRef, + R"('Packet Alignment')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Packet Size')" + }, + { + SpirvOperandKind::IdRef, + R"('Packet Alignment')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Result')" + }, + { + SpirvOperandKind::IdRef, + R"('Input')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('RayQuery')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('RayQuery')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('RayQuery')" + }, + { + SpirvOperandKind::IdRef, + R"('Intersection')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('RayQuery')" + }, + { + SpirvOperandKind::IdRef, + R"('Intersection')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('RayQuery')" + }, + { + SpirvOperandKind::IdRef, + R"('Intersection')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('RayQuery')" + }, + { + SpirvOperandKind::IdRef, + R"('Intersection')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('RayQuery')" + }, + { + SpirvOperandKind::IdRef, + R"('Intersection')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('RayQuery')" + }, + { + SpirvOperandKind::IdRef, + R"('Intersection')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('RayQuery')" + }, + { + SpirvOperandKind::IdRef, + R"('Intersection')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('RayQuery')" + }, + { + SpirvOperandKind::IdRef, + R"('Intersection')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('RayQuery')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('RayQuery')" + }, + { + SpirvOperandKind::IdRef, + R"('Intersection')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('RayQuery')" + }, + { + SpirvOperandKind::IdRef, + R"('Intersection')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('RayQuery')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('RayQuery')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('RayQuery')" + }, + { + SpirvOperandKind::IdRef, + R"('Intersection')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('RayQuery')" + }, + { + SpirvOperandKind::IdRef, + R"('Intersection')" + }, + { + SpirvOperandKind::IdResultType, + R"(IdResultType)" + }, + { + SpirvOperandKind::IdResult, + R"(IdResult)" + }, + { + SpirvOperandKind::IdRef, + R"('Pointer')" + }, + { + SpirvOperandKind::IdScope, + R"('Memory')" + }, + { + SpirvOperandKind::IdMemorySemantics, + R"('Semantics')" + }, + { + SpirvOperandKind::IdRef, + R"('Value')" + }, + } + }; + + static std::array s_instructions = { + { + { + SpirvOp::OpNop, + R"(OpNop)", + nullptr, + 0, + }, + { + SpirvOp::OpUndef, + R"(OpUndef)", + &s_operands[0], + 2, + }, + { + SpirvOp::OpSourceContinued, + R"(OpSourceContinued)", + &s_operands[2], + 1, + }, + { + SpirvOp::OpSource, + R"(OpSource)", + &s_operands[3], + 4, + }, + { + SpirvOp::OpSourceExtension, + R"(OpSourceExtension)", + &s_operands[7], + 1, + }, + { + SpirvOp::OpName, + R"(OpName)", + &s_operands[8], + 2, + }, + { + SpirvOp::OpMemberName, + R"(OpMemberName)", + &s_operands[10], + 3, + }, + { + SpirvOp::OpString, + R"(OpString)", + &s_operands[13], + 2, + }, + { + SpirvOp::OpLine, + R"(OpLine)", + &s_operands[15], + 3, + }, + { + SpirvOp::OpExtension, + R"(OpExtension)", + &s_operands[18], + 1, + }, + { + SpirvOp::OpExtInstImport, + R"(OpExtInstImport)", + &s_operands[19], + 2, + }, + { + SpirvOp::OpExtInst, + R"(OpExtInst)", + &s_operands[21], + 5, + }, + { + SpirvOp::OpMemoryModel, + R"(OpMemoryModel)", + &s_operands[26], + 2, + }, + { + SpirvOp::OpEntryPoint, + R"(OpEntryPoint)", + &s_operands[28], + 4, + }, + { + SpirvOp::OpExecutionMode, + R"(OpExecutionMode)", + &s_operands[32], + 2, + }, + { + SpirvOp::OpCapability, + R"(OpCapability)", + &s_operands[34], + 1, + }, + { + SpirvOp::OpTypeVoid, + R"(OpTypeVoid)", + &s_operands[35], + 1, + }, + { + SpirvOp::OpTypeBool, + R"(OpTypeBool)", + &s_operands[36], + 1, + }, + { + SpirvOp::OpTypeInt, + R"(OpTypeInt)", + &s_operands[37], + 3, + }, + { + SpirvOp::OpTypeFloat, + R"(OpTypeFloat)", + &s_operands[40], + 2, + }, + { + SpirvOp::OpTypeVector, + R"(OpTypeVector)", + &s_operands[42], + 3, + }, + { + SpirvOp::OpTypeMatrix, + R"(OpTypeMatrix)", + &s_operands[45], + 3, + }, + { + SpirvOp::OpTypeImage, + R"(OpTypeImage)", + &s_operands[48], + 9, + }, + { + SpirvOp::OpTypeSampler, + R"(OpTypeSampler)", + &s_operands[57], + 1, + }, + { + SpirvOp::OpTypeSampledImage, + R"(OpTypeSampledImage)", + &s_operands[58], + 2, + }, + { + SpirvOp::OpTypeArray, + R"(OpTypeArray)", + &s_operands[60], + 3, + }, + { + SpirvOp::OpTypeRuntimeArray, + R"(OpTypeRuntimeArray)", + &s_operands[63], + 2, + }, + { + SpirvOp::OpTypeStruct, + R"(OpTypeStruct)", + &s_operands[65], + 2, + }, + { + SpirvOp::OpTypeOpaque, + R"(OpTypeOpaque)", + &s_operands[67], + 2, + }, + { + SpirvOp::OpTypePointer, + R"(OpTypePointer)", + &s_operands[69], + 3, + }, + { + SpirvOp::OpTypeFunction, + R"(OpTypeFunction)", + &s_operands[72], + 3, + }, + { + SpirvOp::OpTypeEvent, + R"(OpTypeEvent)", + &s_operands[75], + 1, + }, + { + SpirvOp::OpTypeDeviceEvent, + R"(OpTypeDeviceEvent)", + &s_operands[76], + 1, + }, + { + SpirvOp::OpTypeReserveId, + R"(OpTypeReserveId)", + &s_operands[77], + 1, + }, + { + SpirvOp::OpTypeQueue, + R"(OpTypeQueue)", + &s_operands[78], + 1, + }, + { + SpirvOp::OpTypePipe, + R"(OpTypePipe)", + &s_operands[79], + 2, + }, + { + SpirvOp::OpTypeForwardPointer, + R"(OpTypeForwardPointer)", + &s_operands[81], + 2, + }, + { + SpirvOp::OpConstantTrue, + R"(OpConstantTrue)", + &s_operands[83], + 2, + }, + { + SpirvOp::OpConstantFalse, + R"(OpConstantFalse)", + &s_operands[85], + 2, + }, + { + SpirvOp::OpConstant, + R"(OpConstant)", + &s_operands[87], + 3, + }, + { + SpirvOp::OpConstantComposite, + R"(OpConstantComposite)", + &s_operands[90], + 3, + }, + { + SpirvOp::OpConstantSampler, + R"(OpConstantSampler)", + &s_operands[93], + 5, + }, + { + SpirvOp::OpConstantNull, + R"(OpConstantNull)", + &s_operands[98], + 2, + }, + { + SpirvOp::OpSpecConstantTrue, + R"(OpSpecConstantTrue)", + &s_operands[100], + 2, + }, + { + SpirvOp::OpSpecConstantFalse, + R"(OpSpecConstantFalse)", + &s_operands[102], + 2, + }, + { + SpirvOp::OpSpecConstant, + R"(OpSpecConstant)", + &s_operands[104], + 3, + }, + { + SpirvOp::OpSpecConstantComposite, + R"(OpSpecConstantComposite)", + &s_operands[107], + 3, + }, + { + SpirvOp::OpSpecConstantOp, + R"(OpSpecConstantOp)", + &s_operands[110], + 3, + }, + { + SpirvOp::OpFunction, + R"(OpFunction)", + &s_operands[113], + 4, + }, + { + SpirvOp::OpFunctionParameter, + R"(OpFunctionParameter)", + &s_operands[117], + 2, + }, + { + SpirvOp::OpFunctionEnd, + R"(OpFunctionEnd)", + nullptr, + 0, + }, + { + SpirvOp::OpFunctionCall, + R"(OpFunctionCall)", + &s_operands[119], + 4, + }, + { + SpirvOp::OpVariable, + R"(OpVariable)", + &s_operands[123], + 4, + }, + { + SpirvOp::OpImageTexelPointer, + R"(OpImageTexelPointer)", + &s_operands[127], + 5, + }, + { + SpirvOp::OpLoad, + R"(OpLoad)", + &s_operands[132], + 4, + }, + { + SpirvOp::OpStore, + R"(OpStore)", + &s_operands[136], + 3, + }, + { + SpirvOp::OpCopyMemory, + R"(OpCopyMemory)", + &s_operands[139], + 4, + }, + { + SpirvOp::OpCopyMemorySized, + R"(OpCopyMemorySized)", + &s_operands[143], + 5, + }, + { + SpirvOp::OpAccessChain, + R"(OpAccessChain)", + &s_operands[148], + 4, + }, + { + SpirvOp::OpInBoundsAccessChain, + R"(OpInBoundsAccessChain)", + &s_operands[152], + 4, + }, + { + SpirvOp::OpPtrAccessChain, + R"(OpPtrAccessChain)", + &s_operands[156], + 5, + }, + { + SpirvOp::OpArrayLength, + R"(OpArrayLength)", + &s_operands[161], + 4, + }, + { + SpirvOp::OpGenericPtrMemSemantics, + R"(OpGenericPtrMemSemantics)", + &s_operands[165], + 3, + }, + { + SpirvOp::OpInBoundsPtrAccessChain, + R"(OpInBoundsPtrAccessChain)", + &s_operands[168], + 5, + }, + { + SpirvOp::OpDecorate, + R"(OpDecorate)", + &s_operands[173], + 2, + }, + { + SpirvOp::OpMemberDecorate, + R"(OpMemberDecorate)", + &s_operands[175], + 3, + }, + { + SpirvOp::OpDecorationGroup, + R"(OpDecorationGroup)", + &s_operands[178], + 1, + }, + { + SpirvOp::OpGroupDecorate, + R"(OpGroupDecorate)", + &s_operands[179], + 2, + }, + { + SpirvOp::OpGroupMemberDecorate, + R"(OpGroupMemberDecorate)", + &s_operands[181], + 2, + }, + { + SpirvOp::OpVectorExtractDynamic, + R"(OpVectorExtractDynamic)", + &s_operands[183], + 4, + }, + { + SpirvOp::OpVectorInsertDynamic, + R"(OpVectorInsertDynamic)", + &s_operands[187], + 5, + }, + { + SpirvOp::OpVectorShuffle, + R"(OpVectorShuffle)", + &s_operands[192], + 5, + }, + { + SpirvOp::OpCompositeConstruct, + R"(OpCompositeConstruct)", + &s_operands[197], + 3, + }, + { + SpirvOp::OpCompositeExtract, + R"(OpCompositeExtract)", + &s_operands[200], + 4, + }, + { + SpirvOp::OpCompositeInsert, + R"(OpCompositeInsert)", + &s_operands[204], + 5, + }, + { + SpirvOp::OpCopyObject, + R"(OpCopyObject)", + &s_operands[209], + 3, + }, + { + SpirvOp::OpTranspose, + R"(OpTranspose)", + &s_operands[212], + 3, + }, + { + SpirvOp::OpSampledImage, + R"(OpSampledImage)", + &s_operands[215], + 4, + }, + { + SpirvOp::OpImageSampleImplicitLod, + R"(OpImageSampleImplicitLod)", + &s_operands[219], + 5, + }, + { + SpirvOp::OpImageSampleExplicitLod, + R"(OpImageSampleExplicitLod)", + &s_operands[224], + 5, + }, + { + SpirvOp::OpImageSampleDrefImplicitLod, + R"(OpImageSampleDrefImplicitLod)", + &s_operands[229], + 6, + }, + { + SpirvOp::OpImageSampleDrefExplicitLod, + R"(OpImageSampleDrefExplicitLod)", + &s_operands[235], + 6, + }, + { + SpirvOp::OpImageSampleProjImplicitLod, + R"(OpImageSampleProjImplicitLod)", + &s_operands[241], + 5, + }, + { + SpirvOp::OpImageSampleProjExplicitLod, + R"(OpImageSampleProjExplicitLod)", + &s_operands[246], + 5, + }, + { + SpirvOp::OpImageSampleProjDrefImplicitLod, + R"(OpImageSampleProjDrefImplicitLod)", + &s_operands[251], + 6, + }, + { + SpirvOp::OpImageSampleProjDrefExplicitLod, + R"(OpImageSampleProjDrefExplicitLod)", + &s_operands[257], + 6, + }, + { + SpirvOp::OpImageFetch, + R"(OpImageFetch)", + &s_operands[263], + 5, + }, + { + SpirvOp::OpImageGather, + R"(OpImageGather)", + &s_operands[268], + 6, + }, + { + SpirvOp::OpImageDrefGather, + R"(OpImageDrefGather)", + &s_operands[274], + 6, + }, + { + SpirvOp::OpImageRead, + R"(OpImageRead)", + &s_operands[280], + 5, + }, + { + SpirvOp::OpImageWrite, + R"(OpImageWrite)", + &s_operands[285], + 4, + }, + { + SpirvOp::OpImage, + R"(OpImage)", + &s_operands[289], + 3, + }, + { + SpirvOp::OpImageQueryFormat, + R"(OpImageQueryFormat)", + &s_operands[292], + 3, + }, + { + SpirvOp::OpImageQueryOrder, + R"(OpImageQueryOrder)", + &s_operands[295], + 3, + }, + { + SpirvOp::OpImageQuerySizeLod, + R"(OpImageQuerySizeLod)", + &s_operands[298], + 4, + }, + { + SpirvOp::OpImageQuerySize, + R"(OpImageQuerySize)", + &s_operands[302], + 3, + }, + { + SpirvOp::OpImageQueryLod, + R"(OpImageQueryLod)", + &s_operands[305], + 4, + }, + { + SpirvOp::OpImageQueryLevels, + R"(OpImageQueryLevels)", + &s_operands[309], + 3, + }, + { + SpirvOp::OpImageQuerySamples, + R"(OpImageQuerySamples)", + &s_operands[312], + 3, + }, + { + SpirvOp::OpConvertFToU, + R"(OpConvertFToU)", + &s_operands[315], + 3, + }, + { + SpirvOp::OpConvertFToS, + R"(OpConvertFToS)", + &s_operands[318], + 3, + }, + { + SpirvOp::OpConvertSToF, + R"(OpConvertSToF)", + &s_operands[321], + 3, + }, + { + SpirvOp::OpConvertUToF, + R"(OpConvertUToF)", + &s_operands[324], + 3, + }, + { + SpirvOp::OpUConvert, + R"(OpUConvert)", + &s_operands[327], + 3, + }, + { + SpirvOp::OpSConvert, + R"(OpSConvert)", + &s_operands[330], + 3, + }, + { + SpirvOp::OpFConvert, + R"(OpFConvert)", + &s_operands[333], + 3, + }, + { + SpirvOp::OpQuantizeToF16, + R"(OpQuantizeToF16)", + &s_operands[336], + 3, + }, + { + SpirvOp::OpConvertPtrToU, + R"(OpConvertPtrToU)", + &s_operands[339], + 3, + }, + { + SpirvOp::OpSatConvertSToU, + R"(OpSatConvertSToU)", + &s_operands[342], + 3, + }, + { + SpirvOp::OpSatConvertUToS, + R"(OpSatConvertUToS)", + &s_operands[345], + 3, + }, + { + SpirvOp::OpConvertUToPtr, + R"(OpConvertUToPtr)", + &s_operands[348], + 3, + }, + { + SpirvOp::OpPtrCastToGeneric, + R"(OpPtrCastToGeneric)", + &s_operands[351], + 3, + }, + { + SpirvOp::OpGenericCastToPtr, + R"(OpGenericCastToPtr)", + &s_operands[354], + 3, + }, + { + SpirvOp::OpGenericCastToPtrExplicit, + R"(OpGenericCastToPtrExplicit)", + &s_operands[357], + 4, + }, + { + SpirvOp::OpBitcast, + R"(OpBitcast)", + &s_operands[361], + 3, + }, + { + SpirvOp::OpSNegate, + R"(OpSNegate)", + &s_operands[364], + 3, + }, + { + SpirvOp::OpFNegate, + R"(OpFNegate)", + &s_operands[367], + 3, + }, + { + SpirvOp::OpIAdd, + R"(OpIAdd)", + &s_operands[370], + 4, + }, + { + SpirvOp::OpFAdd, + R"(OpFAdd)", + &s_operands[374], + 4, + }, + { + SpirvOp::OpISub, + R"(OpISub)", + &s_operands[378], + 4, + }, + { + SpirvOp::OpFSub, + R"(OpFSub)", + &s_operands[382], + 4, + }, + { + SpirvOp::OpIMul, + R"(OpIMul)", + &s_operands[386], + 4, + }, + { + SpirvOp::OpFMul, + R"(OpFMul)", + &s_operands[390], + 4, + }, + { + SpirvOp::OpUDiv, + R"(OpUDiv)", + &s_operands[394], + 4, + }, + { + SpirvOp::OpSDiv, + R"(OpSDiv)", + &s_operands[398], + 4, + }, + { + SpirvOp::OpFDiv, + R"(OpFDiv)", + &s_operands[402], + 4, + }, + { + SpirvOp::OpUMod, + R"(OpUMod)", + &s_operands[406], + 4, + }, + { + SpirvOp::OpSRem, + R"(OpSRem)", + &s_operands[410], + 4, + }, + { + SpirvOp::OpSMod, + R"(OpSMod)", + &s_operands[414], + 4, + }, + { + SpirvOp::OpFRem, + R"(OpFRem)", + &s_operands[418], + 4, + }, + { + SpirvOp::OpFMod, + R"(OpFMod)", + &s_operands[422], + 4, + }, + { + SpirvOp::OpVectorTimesScalar, + R"(OpVectorTimesScalar)", + &s_operands[426], + 4, + }, + { + SpirvOp::OpMatrixTimesScalar, + R"(OpMatrixTimesScalar)", + &s_operands[430], + 4, + }, + { + SpirvOp::OpVectorTimesMatrix, + R"(OpVectorTimesMatrix)", + &s_operands[434], + 4, + }, + { + SpirvOp::OpMatrixTimesVector, + R"(OpMatrixTimesVector)", + &s_operands[438], + 4, + }, + { + SpirvOp::OpMatrixTimesMatrix, + R"(OpMatrixTimesMatrix)", + &s_operands[442], + 4, + }, + { + SpirvOp::OpOuterProduct, + R"(OpOuterProduct)", + &s_operands[446], + 4, + }, + { + SpirvOp::OpDot, + R"(OpDot)", + &s_operands[450], + 4, + }, + { + SpirvOp::OpIAddCarry, + R"(OpIAddCarry)", + &s_operands[454], + 4, + }, + { + SpirvOp::OpISubBorrow, + R"(OpISubBorrow)", + &s_operands[458], + 4, + }, + { + SpirvOp::OpUMulExtended, + R"(OpUMulExtended)", + &s_operands[462], + 4, + }, + { + SpirvOp::OpSMulExtended, + R"(OpSMulExtended)", + &s_operands[466], + 4, + }, + { + SpirvOp::OpAny, + R"(OpAny)", + &s_operands[470], + 3, + }, + { + SpirvOp::OpAll, + R"(OpAll)", + &s_operands[473], + 3, + }, + { + SpirvOp::OpIsNan, + R"(OpIsNan)", + &s_operands[476], + 3, + }, + { + SpirvOp::OpIsInf, + R"(OpIsInf)", + &s_operands[479], + 3, + }, + { + SpirvOp::OpIsFinite, + R"(OpIsFinite)", + &s_operands[482], + 3, + }, + { + SpirvOp::OpIsNormal, + R"(OpIsNormal)", + &s_operands[485], + 3, + }, + { + SpirvOp::OpSignBitSet, + R"(OpSignBitSet)", + &s_operands[488], + 3, + }, + { + SpirvOp::OpLessOrGreater, + R"(OpLessOrGreater)", + &s_operands[491], + 4, + }, + { + SpirvOp::OpOrdered, + R"(OpOrdered)", + &s_operands[495], + 4, + }, + { + SpirvOp::OpUnordered, + R"(OpUnordered)", + &s_operands[499], + 4, + }, + { + SpirvOp::OpLogicalEqual, + R"(OpLogicalEqual)", + &s_operands[503], + 4, + }, + { + SpirvOp::OpLogicalNotEqual, + R"(OpLogicalNotEqual)", + &s_operands[507], + 4, + }, + { + SpirvOp::OpLogicalOr, + R"(OpLogicalOr)", + &s_operands[511], + 4, + }, + { + SpirvOp::OpLogicalAnd, + R"(OpLogicalAnd)", + &s_operands[515], + 4, + }, + { + SpirvOp::OpLogicalNot, + R"(OpLogicalNot)", + &s_operands[519], + 3, + }, + { + SpirvOp::OpSelect, + R"(OpSelect)", + &s_operands[522], + 5, + }, + { + SpirvOp::OpIEqual, + R"(OpIEqual)", + &s_operands[527], + 4, + }, + { + SpirvOp::OpINotEqual, + R"(OpINotEqual)", + &s_operands[531], + 4, + }, + { + SpirvOp::OpUGreaterThan, + R"(OpUGreaterThan)", + &s_operands[535], + 4, + }, + { + SpirvOp::OpSGreaterThan, + R"(OpSGreaterThan)", + &s_operands[539], + 4, + }, + { + SpirvOp::OpUGreaterThanEqual, + R"(OpUGreaterThanEqual)", + &s_operands[543], + 4, + }, + { + SpirvOp::OpSGreaterThanEqual, + R"(OpSGreaterThanEqual)", + &s_operands[547], + 4, + }, + { + SpirvOp::OpULessThan, + R"(OpULessThan)", + &s_operands[551], + 4, + }, + { + SpirvOp::OpSLessThan, + R"(OpSLessThan)", + &s_operands[555], + 4, + }, + { + SpirvOp::OpULessThanEqual, + R"(OpULessThanEqual)", + &s_operands[559], + 4, + }, + { + SpirvOp::OpSLessThanEqual, + R"(OpSLessThanEqual)", + &s_operands[563], + 4, + }, + { + SpirvOp::OpFOrdEqual, + R"(OpFOrdEqual)", + &s_operands[567], + 4, + }, + { + SpirvOp::OpFUnordEqual, + R"(OpFUnordEqual)", + &s_operands[571], + 4, + }, + { + SpirvOp::OpFOrdNotEqual, + R"(OpFOrdNotEqual)", + &s_operands[575], + 4, + }, + { + SpirvOp::OpFUnordNotEqual, + R"(OpFUnordNotEqual)", + &s_operands[579], + 4, + }, + { + SpirvOp::OpFOrdLessThan, + R"(OpFOrdLessThan)", + &s_operands[583], + 4, + }, + { + SpirvOp::OpFUnordLessThan, + R"(OpFUnordLessThan)", + &s_operands[587], + 4, + }, + { + SpirvOp::OpFOrdGreaterThan, + R"(OpFOrdGreaterThan)", + &s_operands[591], + 4, + }, + { + SpirvOp::OpFUnordGreaterThan, + R"(OpFUnordGreaterThan)", + &s_operands[595], + 4, + }, + { + SpirvOp::OpFOrdLessThanEqual, + R"(OpFOrdLessThanEqual)", + &s_operands[599], + 4, + }, + { + SpirvOp::OpFUnordLessThanEqual, + R"(OpFUnordLessThanEqual)", + &s_operands[603], + 4, + }, + { + SpirvOp::OpFOrdGreaterThanEqual, + R"(OpFOrdGreaterThanEqual)", + &s_operands[607], + 4, + }, + { + SpirvOp::OpFUnordGreaterThanEqual, + R"(OpFUnordGreaterThanEqual)", + &s_operands[611], + 4, + }, + { + SpirvOp::OpShiftRightLogical, + R"(OpShiftRightLogical)", + &s_operands[615], + 4, + }, + { + SpirvOp::OpShiftRightArithmetic, + R"(OpShiftRightArithmetic)", + &s_operands[619], + 4, + }, + { + SpirvOp::OpShiftLeftLogical, + R"(OpShiftLeftLogical)", + &s_operands[623], + 4, + }, + { + SpirvOp::OpBitwiseOr, + R"(OpBitwiseOr)", + &s_operands[627], + 4, + }, + { + SpirvOp::OpBitwiseXor, + R"(OpBitwiseXor)", + &s_operands[631], + 4, + }, + { + SpirvOp::OpBitwiseAnd, + R"(OpBitwiseAnd)", + &s_operands[635], + 4, + }, + { + SpirvOp::OpNot, + R"(OpNot)", + &s_operands[639], + 3, + }, + { + SpirvOp::OpBitFieldInsert, + R"(OpBitFieldInsert)", + &s_operands[642], + 6, + }, + { + SpirvOp::OpBitFieldSExtract, + R"(OpBitFieldSExtract)", + &s_operands[648], + 5, + }, + { + SpirvOp::OpBitFieldUExtract, + R"(OpBitFieldUExtract)", + &s_operands[653], + 5, + }, + { + SpirvOp::OpBitReverse, + R"(OpBitReverse)", + &s_operands[658], + 3, + }, + { + SpirvOp::OpBitCount, + R"(OpBitCount)", + &s_operands[661], + 3, + }, + { + SpirvOp::OpDPdx, + R"(OpDPdx)", + &s_operands[664], + 3, + }, + { + SpirvOp::OpDPdy, + R"(OpDPdy)", + &s_operands[667], + 3, + }, + { + SpirvOp::OpFwidth, + R"(OpFwidth)", + &s_operands[670], + 3, + }, + { + SpirvOp::OpDPdxFine, + R"(OpDPdxFine)", + &s_operands[673], + 3, + }, + { + SpirvOp::OpDPdyFine, + R"(OpDPdyFine)", + &s_operands[676], + 3, + }, + { + SpirvOp::OpFwidthFine, + R"(OpFwidthFine)", + &s_operands[679], + 3, + }, + { + SpirvOp::OpDPdxCoarse, + R"(OpDPdxCoarse)", + &s_operands[682], + 3, + }, + { + SpirvOp::OpDPdyCoarse, + R"(OpDPdyCoarse)", + &s_operands[685], + 3, + }, + { + SpirvOp::OpFwidthCoarse, + R"(OpFwidthCoarse)", + &s_operands[688], + 3, + }, + { + SpirvOp::OpEmitVertex, + R"(OpEmitVertex)", + nullptr, + 0, + }, + { + SpirvOp::OpEndPrimitive, + R"(OpEndPrimitive)", + nullptr, + 0, + }, + { + SpirvOp::OpEmitStreamVertex, + R"(OpEmitStreamVertex)", + &s_operands[691], + 1, + }, + { + SpirvOp::OpEndStreamPrimitive, + R"(OpEndStreamPrimitive)", + &s_operands[692], + 1, + }, + { + SpirvOp::OpControlBarrier, + R"(OpControlBarrier)", + &s_operands[693], + 3, + }, + { + SpirvOp::OpMemoryBarrier, + R"(OpMemoryBarrier)", + &s_operands[696], + 2, + }, + { + SpirvOp::OpAtomicLoad, + R"(OpAtomicLoad)", + &s_operands[698], + 5, + }, + { + SpirvOp::OpAtomicStore, + R"(OpAtomicStore)", + &s_operands[703], + 4, + }, + { + SpirvOp::OpAtomicExchange, + R"(OpAtomicExchange)", + &s_operands[707], + 6, + }, + { + SpirvOp::OpAtomicCompareExchange, + R"(OpAtomicCompareExchange)", + &s_operands[713], + 8, + }, + { + SpirvOp::OpAtomicCompareExchangeWeak, + R"(OpAtomicCompareExchangeWeak)", + &s_operands[721], + 8, + }, + { + SpirvOp::OpAtomicIIncrement, + R"(OpAtomicIIncrement)", + &s_operands[729], + 5, + }, + { + SpirvOp::OpAtomicIDecrement, + R"(OpAtomicIDecrement)", + &s_operands[734], + 5, + }, + { + SpirvOp::OpAtomicIAdd, + R"(OpAtomicIAdd)", + &s_operands[739], + 6, + }, + { + SpirvOp::OpAtomicISub, + R"(OpAtomicISub)", + &s_operands[745], + 6, + }, + { + SpirvOp::OpAtomicSMin, + R"(OpAtomicSMin)", + &s_operands[751], + 6, + }, + { + SpirvOp::OpAtomicUMin, + R"(OpAtomicUMin)", + &s_operands[757], + 6, + }, + { + SpirvOp::OpAtomicSMax, + R"(OpAtomicSMax)", + &s_operands[763], + 6, + }, + { + SpirvOp::OpAtomicUMax, + R"(OpAtomicUMax)", + &s_operands[769], + 6, + }, + { + SpirvOp::OpAtomicAnd, + R"(OpAtomicAnd)", + &s_operands[775], + 6, + }, + { + SpirvOp::OpAtomicOr, + R"(OpAtomicOr)", + &s_operands[781], + 6, + }, + { + SpirvOp::OpAtomicXor, + R"(OpAtomicXor)", + &s_operands[787], + 6, + }, + { + SpirvOp::OpPhi, + R"(OpPhi)", + &s_operands[793], + 3, + }, + { + SpirvOp::OpLoopMerge, + R"(OpLoopMerge)", + &s_operands[796], + 3, + }, + { + SpirvOp::OpSelectionMerge, + R"(OpSelectionMerge)", + &s_operands[799], + 2, + }, + { + SpirvOp::OpLabel, + R"(OpLabel)", + &s_operands[801], + 1, + }, + { + SpirvOp::OpBranch, + R"(OpBranch)", + &s_operands[802], + 1, + }, + { + SpirvOp::OpBranchConditional, + R"(OpBranchConditional)", + &s_operands[803], + 4, + }, + { + SpirvOp::OpSwitch, + R"(OpSwitch)", + &s_operands[807], + 3, + }, + { + SpirvOp::OpKill, + R"(OpKill)", + nullptr, + 0, + }, + { + SpirvOp::OpReturn, + R"(OpReturn)", + nullptr, + 0, + }, + { + SpirvOp::OpReturnValue, + R"(OpReturnValue)", + &s_operands[810], + 1, + }, + { + SpirvOp::OpUnreachable, + R"(OpUnreachable)", + nullptr, + 0, + }, + { + SpirvOp::OpLifetimeStart, + R"(OpLifetimeStart)", + &s_operands[811], + 2, + }, + { + SpirvOp::OpLifetimeStop, + R"(OpLifetimeStop)", + &s_operands[813], + 2, + }, + { + SpirvOp::OpGroupAsyncCopy, + R"(OpGroupAsyncCopy)", + &s_operands[815], + 8, + }, + { + SpirvOp::OpGroupWaitEvents, + R"(OpGroupWaitEvents)", + &s_operands[823], + 3, + }, + { + SpirvOp::OpGroupAll, + R"(OpGroupAll)", + &s_operands[826], + 4, + }, + { + SpirvOp::OpGroupAny, + R"(OpGroupAny)", + &s_operands[830], + 4, + }, + { + SpirvOp::OpGroupBroadcast, + R"(OpGroupBroadcast)", + &s_operands[834], + 5, + }, + { + SpirvOp::OpGroupIAdd, + R"(OpGroupIAdd)", + &s_operands[839], + 5, + }, + { + SpirvOp::OpGroupFAdd, + R"(OpGroupFAdd)", + &s_operands[844], + 5, + }, + { + SpirvOp::OpGroupFMin, + R"(OpGroupFMin)", + &s_operands[849], + 5, + }, + { + SpirvOp::OpGroupUMin, + R"(OpGroupUMin)", + &s_operands[854], + 5, + }, + { + SpirvOp::OpGroupSMin, + R"(OpGroupSMin)", + &s_operands[859], + 5, + }, + { + SpirvOp::OpGroupFMax, + R"(OpGroupFMax)", + &s_operands[864], + 5, + }, + { + SpirvOp::OpGroupUMax, + R"(OpGroupUMax)", + &s_operands[869], + 5, + }, + { + SpirvOp::OpGroupSMax, + R"(OpGroupSMax)", + &s_operands[874], + 5, + }, + { + SpirvOp::OpReadPipe, + R"(OpReadPipe)", + &s_operands[879], + 6, + }, + { + SpirvOp::OpWritePipe, + R"(OpWritePipe)", + &s_operands[885], + 6, + }, + { + SpirvOp::OpReservedReadPipe, + R"(OpReservedReadPipe)", + &s_operands[891], + 8, + }, + { + SpirvOp::OpReservedWritePipe, + R"(OpReservedWritePipe)", + &s_operands[899], + 8, + }, + { + SpirvOp::OpReserveReadPipePackets, + R"(OpReserveReadPipePackets)", + &s_operands[907], + 6, + }, + { + SpirvOp::OpReserveWritePipePackets, + R"(OpReserveWritePipePackets)", + &s_operands[913], + 6, + }, + { + SpirvOp::OpCommitReadPipe, + R"(OpCommitReadPipe)", + &s_operands[919], + 4, + }, + { + SpirvOp::OpCommitWritePipe, + R"(OpCommitWritePipe)", + &s_operands[923], + 4, + }, + { + SpirvOp::OpIsValidReserveId, + R"(OpIsValidReserveId)", + &s_operands[927], + 3, + }, + { + SpirvOp::OpGetNumPipePackets, + R"(OpGetNumPipePackets)", + &s_operands[930], + 5, + }, + { + SpirvOp::OpGetMaxPipePackets, + R"(OpGetMaxPipePackets)", + &s_operands[935], + 5, + }, + { + SpirvOp::OpGroupReserveReadPipePackets, + R"(OpGroupReserveReadPipePackets)", + &s_operands[940], + 7, + }, + { + SpirvOp::OpGroupReserveWritePipePackets, + R"(OpGroupReserveWritePipePackets)", + &s_operands[947], + 7, + }, + { + SpirvOp::OpGroupCommitReadPipe, + R"(OpGroupCommitReadPipe)", + &s_operands[954], + 5, + }, + { + SpirvOp::OpGroupCommitWritePipe, + R"(OpGroupCommitWritePipe)", + &s_operands[959], + 5, + }, + { + SpirvOp::OpEnqueueMarker, + R"(OpEnqueueMarker)", + &s_operands[964], + 6, + }, + { + SpirvOp::OpEnqueueKernel, + R"(OpEnqueueKernel)", + &s_operands[970], + 13, + }, + { + SpirvOp::OpGetKernelNDrangeSubGroupCount, + R"(OpGetKernelNDrangeSubGroupCount)", + &s_operands[983], + 7, + }, + { + SpirvOp::OpGetKernelNDrangeMaxSubGroupSize, + R"(OpGetKernelNDrangeMaxSubGroupSize)", + &s_operands[990], + 7, + }, + { + SpirvOp::OpGetKernelWorkGroupSize, + R"(OpGetKernelWorkGroupSize)", + &s_operands[997], + 6, + }, + { + SpirvOp::OpGetKernelPreferredWorkGroupSizeMultiple, + R"(OpGetKernelPreferredWorkGroupSizeMultiple)", + &s_operands[1003], + 6, + }, + { + SpirvOp::OpRetainEvent, + R"(OpRetainEvent)", + &s_operands[1009], + 1, + }, + { + SpirvOp::OpReleaseEvent, + R"(OpReleaseEvent)", + &s_operands[1010], + 1, + }, + { + SpirvOp::OpCreateUserEvent, + R"(OpCreateUserEvent)", + &s_operands[1011], + 2, + }, + { + SpirvOp::OpIsValidEvent, + R"(OpIsValidEvent)", + &s_operands[1013], + 3, + }, + { + SpirvOp::OpSetUserEventStatus, + R"(OpSetUserEventStatus)", + &s_operands[1016], + 2, + }, + { + SpirvOp::OpCaptureEventProfilingInfo, + R"(OpCaptureEventProfilingInfo)", + &s_operands[1018], + 3, + }, + { + SpirvOp::OpGetDefaultQueue, + R"(OpGetDefaultQueue)", + &s_operands[1021], + 2, + }, + { + SpirvOp::OpBuildNDRange, + R"(OpBuildNDRange)", + &s_operands[1023], + 5, + }, + { + SpirvOp::OpImageSparseSampleImplicitLod, + R"(OpImageSparseSampleImplicitLod)", + &s_operands[1028], + 5, + }, + { + SpirvOp::OpImageSparseSampleExplicitLod, + R"(OpImageSparseSampleExplicitLod)", + &s_operands[1033], + 5, + }, + { + SpirvOp::OpImageSparseSampleDrefImplicitLod, + R"(OpImageSparseSampleDrefImplicitLod)", + &s_operands[1038], + 6, + }, + { + SpirvOp::OpImageSparseSampleDrefExplicitLod, + R"(OpImageSparseSampleDrefExplicitLod)", + &s_operands[1044], + 6, + }, + { + SpirvOp::OpImageSparseSampleProjImplicitLod, + R"(OpImageSparseSampleProjImplicitLod)", + &s_operands[1050], + 5, + }, + { + SpirvOp::OpImageSparseSampleProjExplicitLod, + R"(OpImageSparseSampleProjExplicitLod)", + &s_operands[1055], + 5, + }, + { + SpirvOp::OpImageSparseSampleProjDrefImplicitLod, + R"(OpImageSparseSampleProjDrefImplicitLod)", + &s_operands[1060], + 6, + }, + { + SpirvOp::OpImageSparseSampleProjDrefExplicitLod, + R"(OpImageSparseSampleProjDrefExplicitLod)", + &s_operands[1066], + 6, + }, + { + SpirvOp::OpImageSparseFetch, + R"(OpImageSparseFetch)", + &s_operands[1072], + 5, + }, + { + SpirvOp::OpImageSparseGather, + R"(OpImageSparseGather)", + &s_operands[1077], + 6, + }, + { + SpirvOp::OpImageSparseDrefGather, + R"(OpImageSparseDrefGather)", + &s_operands[1083], + 6, + }, + { + SpirvOp::OpImageSparseTexelsResident, + R"(OpImageSparseTexelsResident)", + &s_operands[1089], + 3, + }, + { + SpirvOp::OpNoLine, + R"(OpNoLine)", + nullptr, + 0, + }, + { + SpirvOp::OpAtomicFlagTestAndSet, + R"(OpAtomicFlagTestAndSet)", + &s_operands[1092], + 5, + }, + { + SpirvOp::OpAtomicFlagClear, + R"(OpAtomicFlagClear)", + &s_operands[1097], + 3, + }, + { + SpirvOp::OpImageSparseRead, + R"(OpImageSparseRead)", + &s_operands[1100], + 5, + }, + { + SpirvOp::OpSizeOf, + R"(OpSizeOf)", + &s_operands[1105], + 3, + }, + { + SpirvOp::OpTypePipeStorage, + R"(OpTypePipeStorage)", + &s_operands[1108], + 1, + }, + { + SpirvOp::OpConstantPipeStorage, + R"(OpConstantPipeStorage)", + &s_operands[1109], + 5, + }, + { + SpirvOp::OpCreatePipeFromPipeStorage, + R"(OpCreatePipeFromPipeStorage)", + &s_operands[1114], + 3, + }, + { + SpirvOp::OpGetKernelLocalSizeForSubgroupCount, + R"(OpGetKernelLocalSizeForSubgroupCount)", + &s_operands[1117], + 7, + }, + { + SpirvOp::OpGetKernelMaxNumSubgroups, + R"(OpGetKernelMaxNumSubgroups)", + &s_operands[1124], + 6, + }, + { + SpirvOp::OpTypeNamedBarrier, + R"(OpTypeNamedBarrier)", + &s_operands[1130], + 1, + }, + { + SpirvOp::OpNamedBarrierInitialize, + R"(OpNamedBarrierInitialize)", + &s_operands[1131], + 3, + }, + { + SpirvOp::OpMemoryNamedBarrier, + R"(OpMemoryNamedBarrier)", + &s_operands[1134], + 3, + }, + { + SpirvOp::OpModuleProcessed, + R"(OpModuleProcessed)", + &s_operands[1137], + 1, + }, + { + SpirvOp::OpExecutionModeId, + R"(OpExecutionModeId)", + &s_operands[1138], + 2, + }, + { + SpirvOp::OpDecorateId, + R"(OpDecorateId)", + &s_operands[1140], + 2, + }, + { + SpirvOp::OpGroupNonUniformElect, + R"(OpGroupNonUniformElect)", + &s_operands[1142], + 3, + }, + { + SpirvOp::OpGroupNonUniformAll, + R"(OpGroupNonUniformAll)", + &s_operands[1145], + 4, + }, + { + SpirvOp::OpGroupNonUniformAny, + R"(OpGroupNonUniformAny)", + &s_operands[1149], + 4, + }, + { + SpirvOp::OpGroupNonUniformAllEqual, + R"(OpGroupNonUniformAllEqual)", + &s_operands[1153], + 4, + }, + { + SpirvOp::OpGroupNonUniformBroadcast, + R"(OpGroupNonUniformBroadcast)", + &s_operands[1157], + 5, + }, + { + SpirvOp::OpGroupNonUniformBroadcastFirst, + R"(OpGroupNonUniformBroadcastFirst)", + &s_operands[1162], + 4, + }, + { + SpirvOp::OpGroupNonUniformBallot, + R"(OpGroupNonUniformBallot)", + &s_operands[1166], + 4, + }, + { + SpirvOp::OpGroupNonUniformInverseBallot, + R"(OpGroupNonUniformInverseBallot)", + &s_operands[1170], + 4, + }, + { + SpirvOp::OpGroupNonUniformBallotBitExtract, + R"(OpGroupNonUniformBallotBitExtract)", + &s_operands[1174], + 5, + }, + { + SpirvOp::OpGroupNonUniformBallotBitCount, + R"(OpGroupNonUniformBallotBitCount)", + &s_operands[1179], + 5, + }, + { + SpirvOp::OpGroupNonUniformBallotFindLSB, + R"(OpGroupNonUniformBallotFindLSB)", + &s_operands[1184], + 4, + }, + { + SpirvOp::OpGroupNonUniformBallotFindMSB, + R"(OpGroupNonUniformBallotFindMSB)", + &s_operands[1188], + 4, + }, + { + SpirvOp::OpGroupNonUniformShuffle, + R"(OpGroupNonUniformShuffle)", + &s_operands[1192], + 5, + }, + { + SpirvOp::OpGroupNonUniformShuffleXor, + R"(OpGroupNonUniformShuffleXor)", + &s_operands[1197], + 5, + }, + { + SpirvOp::OpGroupNonUniformShuffleUp, + R"(OpGroupNonUniformShuffleUp)", + &s_operands[1202], + 5, + }, + { + SpirvOp::OpGroupNonUniformShuffleDown, + R"(OpGroupNonUniformShuffleDown)", + &s_operands[1207], + 5, + }, + { + SpirvOp::OpGroupNonUniformIAdd, + R"(OpGroupNonUniformIAdd)", + &s_operands[1212], + 6, + }, + { + SpirvOp::OpGroupNonUniformFAdd, + R"(OpGroupNonUniformFAdd)", + &s_operands[1218], + 6, + }, + { + SpirvOp::OpGroupNonUniformIMul, + R"(OpGroupNonUniformIMul)", + &s_operands[1224], + 6, + }, + { + SpirvOp::OpGroupNonUniformFMul, + R"(OpGroupNonUniformFMul)", + &s_operands[1230], + 6, + }, + { + SpirvOp::OpGroupNonUniformSMin, + R"(OpGroupNonUniformSMin)", + &s_operands[1236], + 6, + }, + { + SpirvOp::OpGroupNonUniformUMin, + R"(OpGroupNonUniformUMin)", + &s_operands[1242], + 6, + }, + { + SpirvOp::OpGroupNonUniformFMin, + R"(OpGroupNonUniformFMin)", + &s_operands[1248], + 6, + }, + { + SpirvOp::OpGroupNonUniformSMax, + R"(OpGroupNonUniformSMax)", + &s_operands[1254], + 6, + }, + { + SpirvOp::OpGroupNonUniformUMax, + R"(OpGroupNonUniformUMax)", + &s_operands[1260], + 6, + }, + { + SpirvOp::OpGroupNonUniformFMax, + R"(OpGroupNonUniformFMax)", + &s_operands[1266], + 6, + }, + { + SpirvOp::OpGroupNonUniformBitwiseAnd, + R"(OpGroupNonUniformBitwiseAnd)", + &s_operands[1272], + 6, + }, + { + SpirvOp::OpGroupNonUniformBitwiseOr, + R"(OpGroupNonUniformBitwiseOr)", + &s_operands[1278], + 6, + }, + { + SpirvOp::OpGroupNonUniformBitwiseXor, + R"(OpGroupNonUniformBitwiseXor)", + &s_operands[1284], + 6, + }, + { + SpirvOp::OpGroupNonUniformLogicalAnd, + R"(OpGroupNonUniformLogicalAnd)", + &s_operands[1290], + 6, + }, + { + SpirvOp::OpGroupNonUniformLogicalOr, + R"(OpGroupNonUniformLogicalOr)", + &s_operands[1296], + 6, + }, + { + SpirvOp::OpGroupNonUniformLogicalXor, + R"(OpGroupNonUniformLogicalXor)", + &s_operands[1302], + 6, + }, + { + SpirvOp::OpGroupNonUniformQuadBroadcast, + R"(OpGroupNonUniformQuadBroadcast)", + &s_operands[1308], + 5, + }, + { + SpirvOp::OpGroupNonUniformQuadSwap, + R"(OpGroupNonUniformQuadSwap)", + &s_operands[1313], + 5, + }, + { + SpirvOp::OpCopyLogical, + R"(OpCopyLogical)", + &s_operands[1318], + 3, + }, + { + SpirvOp::OpPtrEqual, + R"(OpPtrEqual)", + &s_operands[1321], + 4, + }, + { + SpirvOp::OpPtrNotEqual, + R"(OpPtrNotEqual)", + &s_operands[1325], + 4, + }, + { + SpirvOp::OpPtrDiff, + R"(OpPtrDiff)", + &s_operands[1329], + 4, + }, + { + SpirvOp::OpTerminateInvocation, + R"(OpTerminateInvocation)", + nullptr, + 0, + }, + { + SpirvOp::OpSubgroupBallotKHR, + R"(OpSubgroupBallotKHR)", + &s_operands[1333], + 3, + }, + { + SpirvOp::OpSubgroupFirstInvocationKHR, + R"(OpSubgroupFirstInvocationKHR)", + &s_operands[1336], + 3, + }, + { + SpirvOp::OpSubgroupAllKHR, + R"(OpSubgroupAllKHR)", + &s_operands[1339], + 3, + }, + { + SpirvOp::OpSubgroupAnyKHR, + R"(OpSubgroupAnyKHR)", + &s_operands[1342], + 3, + }, + { + SpirvOp::OpSubgroupAllEqualKHR, + R"(OpSubgroupAllEqualKHR)", + &s_operands[1345], + 3, + }, + { + SpirvOp::OpSubgroupReadInvocationKHR, + R"(OpSubgroupReadInvocationKHR)", + &s_operands[1348], + 4, + }, + { + SpirvOp::OpTypeRayQueryProvisionalKHR, + R"(OpTypeRayQueryProvisionalKHR)", + &s_operands[1352], + 1, + }, + { + SpirvOp::OpRayQueryInitializeKHR, + R"(OpRayQueryInitializeKHR)", + &s_operands[1353], + 8, + }, + { + SpirvOp::OpRayQueryTerminateKHR, + R"(OpRayQueryTerminateKHR)", + &s_operands[1361], + 1, + }, + { + SpirvOp::OpRayQueryGenerateIntersectionKHR, + R"(OpRayQueryGenerateIntersectionKHR)", + &s_operands[1362], + 2, + }, + { + SpirvOp::OpRayQueryConfirmIntersectionKHR, + R"(OpRayQueryConfirmIntersectionKHR)", + &s_operands[1364], + 1, + }, + { + SpirvOp::OpRayQueryProceedKHR, + R"(OpRayQueryProceedKHR)", + &s_operands[1365], + 3, + }, + { + SpirvOp::OpRayQueryGetIntersectionTypeKHR, + R"(OpRayQueryGetIntersectionTypeKHR)", + &s_operands[1368], + 4, + }, + { + SpirvOp::OpGroupIAddNonUniformAMD, + R"(OpGroupIAddNonUniformAMD)", + &s_operands[1372], + 5, + }, + { + SpirvOp::OpGroupFAddNonUniformAMD, + R"(OpGroupFAddNonUniformAMD)", + &s_operands[1377], + 5, + }, + { + SpirvOp::OpGroupFMinNonUniformAMD, + R"(OpGroupFMinNonUniformAMD)", + &s_operands[1382], + 5, + }, + { + SpirvOp::OpGroupUMinNonUniformAMD, + R"(OpGroupUMinNonUniformAMD)", + &s_operands[1387], + 5, + }, + { + SpirvOp::OpGroupSMinNonUniformAMD, + R"(OpGroupSMinNonUniformAMD)", + &s_operands[1392], + 5, + }, + { + SpirvOp::OpGroupFMaxNonUniformAMD, + R"(OpGroupFMaxNonUniformAMD)", + &s_operands[1397], + 5, + }, + { + SpirvOp::OpGroupUMaxNonUniformAMD, + R"(OpGroupUMaxNonUniformAMD)", + &s_operands[1402], + 5, + }, + { + SpirvOp::OpGroupSMaxNonUniformAMD, + R"(OpGroupSMaxNonUniformAMD)", + &s_operands[1407], + 5, + }, + { + SpirvOp::OpFragmentMaskFetchAMD, + R"(OpFragmentMaskFetchAMD)", + &s_operands[1412], + 4, + }, + { + SpirvOp::OpFragmentFetchAMD, + R"(OpFragmentFetchAMD)", + &s_operands[1416], + 5, + }, + { + SpirvOp::OpReadClockKHR, + R"(OpReadClockKHR)", + &s_operands[1421], + 3, + }, + { + SpirvOp::OpImageSampleFootprintNV, + R"(OpImageSampleFootprintNV)", + &s_operands[1424], + 7, + }, + { + SpirvOp::OpGroupNonUniformPartitionNV, + R"(OpGroupNonUniformPartitionNV)", + &s_operands[1431], + 3, + }, + { + SpirvOp::OpWritePackedPrimitiveIndices4x8NV, + R"(OpWritePackedPrimitiveIndices4x8NV)", + &s_operands[1434], + 2, + }, + { + SpirvOp::OpReportIntersectionKHR, + R"(OpReportIntersectionKHR)", + &s_operands[1436], + 4, + }, + { + SpirvOp::OpIgnoreIntersectionKHR, + R"(OpIgnoreIntersectionKHR)", + nullptr, + 0, + }, + { + SpirvOp::OpTerminateRayKHR, + R"(OpTerminateRayKHR)", + nullptr, + 0, + }, + { + SpirvOp::OpTraceRayKHR, + R"(OpTraceRayKHR)", + &s_operands[1440], + 11, + }, + { + SpirvOp::OpTypeAccelerationStructureKHR, + R"(OpTypeAccelerationStructureKHR)", + &s_operands[1451], + 1, + }, + { + SpirvOp::OpExecuteCallableKHR, + R"(OpExecuteCallableKHR)", + &s_operands[1452], + 2, + }, + { + SpirvOp::OpTypeCooperativeMatrixNV, + R"(OpTypeCooperativeMatrixNV)", + &s_operands[1454], + 5, + }, + { + SpirvOp::OpCooperativeMatrixLoadNV, + R"(OpCooperativeMatrixLoadNV)", + &s_operands[1459], + 6, + }, + { + SpirvOp::OpCooperativeMatrixStoreNV, + R"(OpCooperativeMatrixStoreNV)", + &s_operands[1465], + 5, + }, + { + SpirvOp::OpCooperativeMatrixMulAddNV, + R"(OpCooperativeMatrixMulAddNV)", + &s_operands[1470], + 5, + }, + { + SpirvOp::OpCooperativeMatrixLengthNV, + R"(OpCooperativeMatrixLengthNV)", + &s_operands[1475], + 3, + }, + { + SpirvOp::OpBeginInvocationInterlockEXT, + R"(OpBeginInvocationInterlockEXT)", + nullptr, + 0, + }, + { + SpirvOp::OpEndInvocationInterlockEXT, + R"(OpEndInvocationInterlockEXT)", + nullptr, + 0, + }, + { + SpirvOp::OpDemoteToHelperInvocationEXT, + R"(OpDemoteToHelperInvocationEXT)", + nullptr, + 0, + }, + { + SpirvOp::OpIsHelperInvocationEXT, + R"(OpIsHelperInvocationEXT)", + &s_operands[1478], + 2, + }, + { + SpirvOp::OpSubgroupShuffleINTEL, + R"(OpSubgroupShuffleINTEL)", + &s_operands[1480], + 4, + }, + { + SpirvOp::OpSubgroupShuffleDownINTEL, + R"(OpSubgroupShuffleDownINTEL)", + &s_operands[1484], + 5, + }, + { + SpirvOp::OpSubgroupShuffleUpINTEL, + R"(OpSubgroupShuffleUpINTEL)", + &s_operands[1489], + 5, + }, + { + SpirvOp::OpSubgroupShuffleXorINTEL, + R"(OpSubgroupShuffleXorINTEL)", + &s_operands[1494], + 4, + }, + { + SpirvOp::OpSubgroupBlockReadINTEL, + R"(OpSubgroupBlockReadINTEL)", + &s_operands[1498], + 3, + }, + { + SpirvOp::OpSubgroupBlockWriteINTEL, + R"(OpSubgroupBlockWriteINTEL)", + &s_operands[1501], + 2, + }, + { + SpirvOp::OpSubgroupImageBlockReadINTEL, + R"(OpSubgroupImageBlockReadINTEL)", + &s_operands[1503], + 4, + }, + { + SpirvOp::OpSubgroupImageBlockWriteINTEL, + R"(OpSubgroupImageBlockWriteINTEL)", + &s_operands[1507], + 3, + }, + { + SpirvOp::OpSubgroupImageMediaBlockReadINTEL, + R"(OpSubgroupImageMediaBlockReadINTEL)", + &s_operands[1510], + 6, + }, + { + SpirvOp::OpSubgroupImageMediaBlockWriteINTEL, + R"(OpSubgroupImageMediaBlockWriteINTEL)", + &s_operands[1516], + 5, + }, + { + SpirvOp::OpUCountLeadingZerosINTEL, + R"(OpUCountLeadingZerosINTEL)", + &s_operands[1521], + 3, + }, + { + SpirvOp::OpUCountTrailingZerosINTEL, + R"(OpUCountTrailingZerosINTEL)", + &s_operands[1524], + 3, + }, + { + SpirvOp::OpAbsISubINTEL, + R"(OpAbsISubINTEL)", + &s_operands[1527], + 4, + }, + { + SpirvOp::OpAbsUSubINTEL, + R"(OpAbsUSubINTEL)", + &s_operands[1531], + 4, + }, + { + SpirvOp::OpIAddSatINTEL, + R"(OpIAddSatINTEL)", + &s_operands[1535], + 4, + }, + { + SpirvOp::OpUAddSatINTEL, + R"(OpUAddSatINTEL)", + &s_operands[1539], + 4, + }, + { + SpirvOp::OpIAverageINTEL, + R"(OpIAverageINTEL)", + &s_operands[1543], + 4, + }, + { + SpirvOp::OpUAverageINTEL, + R"(OpUAverageINTEL)", + &s_operands[1547], + 4, + }, + { + SpirvOp::OpIAverageRoundedINTEL, + R"(OpIAverageRoundedINTEL)", + &s_operands[1551], + 4, + }, + { + SpirvOp::OpUAverageRoundedINTEL, + R"(OpUAverageRoundedINTEL)", + &s_operands[1555], + 4, + }, + { + SpirvOp::OpISubSatINTEL, + R"(OpISubSatINTEL)", + &s_operands[1559], + 4, + }, + { + SpirvOp::OpUSubSatINTEL, + R"(OpUSubSatINTEL)", + &s_operands[1563], + 4, + }, + { + SpirvOp::OpIMul32x16INTEL, + R"(OpIMul32x16INTEL)", + &s_operands[1567], + 4, + }, + { + SpirvOp::OpUMul32x16INTEL, + R"(OpUMul32x16INTEL)", + &s_operands[1571], + 4, + }, + { + SpirvOp::OpFunctionPointerINTEL, + R"(OpFunctionPointerINTEL)", + &s_operands[1575], + 3, + }, + { + SpirvOp::OpFunctionPointerCallINTEL, + R"(OpFunctionPointerCallINTEL)", + &s_operands[1578], + 3, + }, + { + SpirvOp::OpDecorateStringGOOGLE, + R"(OpDecorateStringGOOGLE)", + &s_operands[1581], + 2, + }, + { + SpirvOp::OpMemberDecorateStringGOOGLE, + R"(OpMemberDecorateStringGOOGLE)", + &s_operands[1583], + 3, + }, + { + SpirvOp::OpVmeImageINTEL, + R"(OpVmeImageINTEL)", + &s_operands[1586], + 4, + }, + { + SpirvOp::OpTypeVmeImageINTEL, + R"(OpTypeVmeImageINTEL)", + &s_operands[1590], + 2, + }, + { + SpirvOp::OpTypeAvcImePayloadINTEL, + R"(OpTypeAvcImePayloadINTEL)", + &s_operands[1592], + 1, + }, + { + SpirvOp::OpTypeAvcRefPayloadINTEL, + R"(OpTypeAvcRefPayloadINTEL)", + &s_operands[1593], + 1, + }, + { + SpirvOp::OpTypeAvcSicPayloadINTEL, + R"(OpTypeAvcSicPayloadINTEL)", + &s_operands[1594], + 1, + }, + { + SpirvOp::OpTypeAvcMcePayloadINTEL, + R"(OpTypeAvcMcePayloadINTEL)", + &s_operands[1595], + 1, + }, + { + SpirvOp::OpTypeAvcMceResultINTEL, + R"(OpTypeAvcMceResultINTEL)", + &s_operands[1596], + 1, + }, + { + SpirvOp::OpTypeAvcImeResultINTEL, + R"(OpTypeAvcImeResultINTEL)", + &s_operands[1597], + 1, + }, + { + SpirvOp::OpTypeAvcImeResultSingleReferenceStreamoutINTEL, + R"(OpTypeAvcImeResultSingleReferenceStreamoutINTEL)", + &s_operands[1598], + 1, + }, + { + SpirvOp::OpTypeAvcImeResultDualReferenceStreamoutINTEL, + R"(OpTypeAvcImeResultDualReferenceStreamoutINTEL)", + &s_operands[1599], + 1, + }, + { + SpirvOp::OpTypeAvcImeSingleReferenceStreaminINTEL, + R"(OpTypeAvcImeSingleReferenceStreaminINTEL)", + &s_operands[1600], + 1, + }, + { + SpirvOp::OpTypeAvcImeDualReferenceStreaminINTEL, + R"(OpTypeAvcImeDualReferenceStreaminINTEL)", + &s_operands[1601], + 1, + }, + { + SpirvOp::OpTypeAvcRefResultINTEL, + R"(OpTypeAvcRefResultINTEL)", + &s_operands[1602], + 1, + }, + { + SpirvOp::OpTypeAvcSicResultINTEL, + R"(OpTypeAvcSicResultINTEL)", + &s_operands[1603], + 1, + }, + { + SpirvOp::OpSubgroupAvcMceGetDefaultInterBaseMultiReferencePenaltyINTEL, + R"(OpSubgroupAvcMceGetDefaultInterBaseMultiReferencePenaltyINTEL)", + &s_operands[1604], + 4, + }, + { + SpirvOp::OpSubgroupAvcMceSetInterBaseMultiReferencePenaltyINTEL, + R"(OpSubgroupAvcMceSetInterBaseMultiReferencePenaltyINTEL)", + &s_operands[1608], + 4, + }, + { + SpirvOp::OpSubgroupAvcMceGetDefaultInterShapePenaltyINTEL, + R"(OpSubgroupAvcMceGetDefaultInterShapePenaltyINTEL)", + &s_operands[1612], + 4, + }, + { + SpirvOp::OpSubgroupAvcMceSetInterShapePenaltyINTEL, + R"(OpSubgroupAvcMceSetInterShapePenaltyINTEL)", + &s_operands[1616], + 4, + }, + { + SpirvOp::OpSubgroupAvcMceGetDefaultInterDirectionPenaltyINTEL, + R"(OpSubgroupAvcMceGetDefaultInterDirectionPenaltyINTEL)", + &s_operands[1620], + 4, + }, + { + SpirvOp::OpSubgroupAvcMceSetInterDirectionPenaltyINTEL, + R"(OpSubgroupAvcMceSetInterDirectionPenaltyINTEL)", + &s_operands[1624], + 4, + }, + { + SpirvOp::OpSubgroupAvcMceGetDefaultIntraLumaShapePenaltyINTEL, + R"(OpSubgroupAvcMceGetDefaultIntraLumaShapePenaltyINTEL)", + &s_operands[1628], + 4, + }, + { + SpirvOp::OpSubgroupAvcMceGetDefaultInterMotionVectorCostTableINTEL, + R"(OpSubgroupAvcMceGetDefaultInterMotionVectorCostTableINTEL)", + &s_operands[1632], + 4, + }, + { + SpirvOp::OpSubgroupAvcMceGetDefaultHighPenaltyCostTableINTEL, + R"(OpSubgroupAvcMceGetDefaultHighPenaltyCostTableINTEL)", + &s_operands[1636], + 2, + }, + { + SpirvOp::OpSubgroupAvcMceGetDefaultMediumPenaltyCostTableINTEL, + R"(OpSubgroupAvcMceGetDefaultMediumPenaltyCostTableINTEL)", + &s_operands[1638], + 2, + }, + { + SpirvOp::OpSubgroupAvcMceGetDefaultLowPenaltyCostTableINTEL, + R"(OpSubgroupAvcMceGetDefaultLowPenaltyCostTableINTEL)", + &s_operands[1640], + 2, + }, + { + SpirvOp::OpSubgroupAvcMceSetMotionVectorCostFunctionINTEL, + R"(OpSubgroupAvcMceSetMotionVectorCostFunctionINTEL)", + &s_operands[1642], + 6, + }, + { + SpirvOp::OpSubgroupAvcMceGetDefaultIntraLumaModePenaltyINTEL, + R"(OpSubgroupAvcMceGetDefaultIntraLumaModePenaltyINTEL)", + &s_operands[1648], + 4, + }, + { + SpirvOp::OpSubgroupAvcMceGetDefaultNonDcLumaIntraPenaltyINTEL, + R"(OpSubgroupAvcMceGetDefaultNonDcLumaIntraPenaltyINTEL)", + &s_operands[1652], + 2, + }, + { + SpirvOp::OpSubgroupAvcMceGetDefaultIntraChromaModeBasePenaltyINTEL, + R"(OpSubgroupAvcMceGetDefaultIntraChromaModeBasePenaltyINTEL)", + &s_operands[1654], + 2, + }, + { + SpirvOp::OpSubgroupAvcMceSetAcOnlyHaarINTEL, + R"(OpSubgroupAvcMceSetAcOnlyHaarINTEL)", + &s_operands[1656], + 3, + }, + { + SpirvOp::OpSubgroupAvcMceSetSourceInterlacedFieldPolarityINTEL, + R"(OpSubgroupAvcMceSetSourceInterlacedFieldPolarityINTEL)", + &s_operands[1659], + 4, + }, + { + SpirvOp::OpSubgroupAvcMceSetSingleReferenceInterlacedFieldPolarityINTEL, + R"(OpSubgroupAvcMceSetSingleReferenceInterlacedFieldPolarityINTEL)", + &s_operands[1663], + 4, + }, + { + SpirvOp::OpSubgroupAvcMceSetDualReferenceInterlacedFieldPolaritiesINTEL, + R"(OpSubgroupAvcMceSetDualReferenceInterlacedFieldPolaritiesINTEL)", + &s_operands[1667], + 5, + }, + { + SpirvOp::OpSubgroupAvcMceConvertToImePayloadINTEL, + R"(OpSubgroupAvcMceConvertToImePayloadINTEL)", + &s_operands[1672], + 3, + }, + { + SpirvOp::OpSubgroupAvcMceConvertToImeResultINTEL, + R"(OpSubgroupAvcMceConvertToImeResultINTEL)", + &s_operands[1675], + 3, + }, + { + SpirvOp::OpSubgroupAvcMceConvertToRefPayloadINTEL, + R"(OpSubgroupAvcMceConvertToRefPayloadINTEL)", + &s_operands[1678], + 3, + }, + { + SpirvOp::OpSubgroupAvcMceConvertToRefResultINTEL, + R"(OpSubgroupAvcMceConvertToRefResultINTEL)", + &s_operands[1681], + 3, + }, + { + SpirvOp::OpSubgroupAvcMceConvertToSicPayloadINTEL, + R"(OpSubgroupAvcMceConvertToSicPayloadINTEL)", + &s_operands[1684], + 3, + }, + { + SpirvOp::OpSubgroupAvcMceConvertToSicResultINTEL, + R"(OpSubgroupAvcMceConvertToSicResultINTEL)", + &s_operands[1687], + 3, + }, + { + SpirvOp::OpSubgroupAvcMceGetMotionVectorsINTEL, + R"(OpSubgroupAvcMceGetMotionVectorsINTEL)", + &s_operands[1690], + 3, + }, + { + SpirvOp::OpSubgroupAvcMceGetInterDistortionsINTEL, + R"(OpSubgroupAvcMceGetInterDistortionsINTEL)", + &s_operands[1693], + 3, + }, + { + SpirvOp::OpSubgroupAvcMceGetBestInterDistortionsINTEL, + R"(OpSubgroupAvcMceGetBestInterDistortionsINTEL)", + &s_operands[1696], + 3, + }, + { + SpirvOp::OpSubgroupAvcMceGetInterMajorShapeINTEL, + R"(OpSubgroupAvcMceGetInterMajorShapeINTEL)", + &s_operands[1699], + 3, + }, + { + SpirvOp::OpSubgroupAvcMceGetInterMinorShapeINTEL, + R"(OpSubgroupAvcMceGetInterMinorShapeINTEL)", + &s_operands[1702], + 3, + }, + { + SpirvOp::OpSubgroupAvcMceGetInterDirectionsINTEL, + R"(OpSubgroupAvcMceGetInterDirectionsINTEL)", + &s_operands[1705], + 3, + }, + { + SpirvOp::OpSubgroupAvcMceGetInterMotionVectorCountINTEL, + R"(OpSubgroupAvcMceGetInterMotionVectorCountINTEL)", + &s_operands[1708], + 3, + }, + { + SpirvOp::OpSubgroupAvcMceGetInterReferenceIdsINTEL, + R"(OpSubgroupAvcMceGetInterReferenceIdsINTEL)", + &s_operands[1711], + 3, + }, + { + SpirvOp::OpSubgroupAvcMceGetInterReferenceInterlacedFieldPolaritiesINTEL, + R"(OpSubgroupAvcMceGetInterReferenceInterlacedFieldPolaritiesINTEL)", + &s_operands[1714], + 5, + }, + { + SpirvOp::OpSubgroupAvcImeInitializeINTEL, + R"(OpSubgroupAvcImeInitializeINTEL)", + &s_operands[1719], + 5, + }, + { + SpirvOp::OpSubgroupAvcImeSetSingleReferenceINTEL, + R"(OpSubgroupAvcImeSetSingleReferenceINTEL)", + &s_operands[1724], + 5, + }, + { + SpirvOp::OpSubgroupAvcImeSetDualReferenceINTEL, + R"(OpSubgroupAvcImeSetDualReferenceINTEL)", + &s_operands[1729], + 6, + }, + { + SpirvOp::OpSubgroupAvcImeRefWindowSizeINTEL, + R"(OpSubgroupAvcImeRefWindowSizeINTEL)", + &s_operands[1735], + 4, + }, + { + SpirvOp::OpSubgroupAvcImeAdjustRefOffsetINTEL, + R"(OpSubgroupAvcImeAdjustRefOffsetINTEL)", + &s_operands[1739], + 6, + }, + { + SpirvOp::OpSubgroupAvcImeConvertToMcePayloadINTEL, + R"(OpSubgroupAvcImeConvertToMcePayloadINTEL)", + &s_operands[1745], + 3, + }, + { + SpirvOp::OpSubgroupAvcImeSetMaxMotionVectorCountINTEL, + R"(OpSubgroupAvcImeSetMaxMotionVectorCountINTEL)", + &s_operands[1748], + 4, + }, + { + SpirvOp::OpSubgroupAvcImeSetUnidirectionalMixDisableINTEL, + R"(OpSubgroupAvcImeSetUnidirectionalMixDisableINTEL)", + &s_operands[1752], + 3, + }, + { + SpirvOp::OpSubgroupAvcImeSetEarlySearchTerminationThresholdINTEL, + R"(OpSubgroupAvcImeSetEarlySearchTerminationThresholdINTEL)", + &s_operands[1755], + 4, + }, + { + SpirvOp::OpSubgroupAvcImeSetWeightedSadINTEL, + R"(OpSubgroupAvcImeSetWeightedSadINTEL)", + &s_operands[1759], + 4, + }, + { + SpirvOp::OpSubgroupAvcImeEvaluateWithSingleReferenceINTEL, + R"(OpSubgroupAvcImeEvaluateWithSingleReferenceINTEL)", + &s_operands[1763], + 5, + }, + { + SpirvOp::OpSubgroupAvcImeEvaluateWithDualReferenceINTEL, + R"(OpSubgroupAvcImeEvaluateWithDualReferenceINTEL)", + &s_operands[1768], + 6, + }, + { + SpirvOp::OpSubgroupAvcImeEvaluateWithSingleReferenceStreaminINTEL, + R"(OpSubgroupAvcImeEvaluateWithSingleReferenceStreaminINTEL)", + &s_operands[1774], + 6, + }, + { + SpirvOp::OpSubgroupAvcImeEvaluateWithDualReferenceStreaminINTEL, + R"(OpSubgroupAvcImeEvaluateWithDualReferenceStreaminINTEL)", + &s_operands[1780], + 7, + }, + { + SpirvOp::OpSubgroupAvcImeEvaluateWithSingleReferenceStreamoutINTEL, + R"(OpSubgroupAvcImeEvaluateWithSingleReferenceStreamoutINTEL)", + &s_operands[1787], + 5, + }, + { + SpirvOp::OpSubgroupAvcImeEvaluateWithDualReferenceStreamoutINTEL, + R"(OpSubgroupAvcImeEvaluateWithDualReferenceStreamoutINTEL)", + &s_operands[1792], + 6, + }, + { + SpirvOp::OpSubgroupAvcImeEvaluateWithSingleReferenceStreaminoutINTEL, + R"(OpSubgroupAvcImeEvaluateWithSingleReferenceStreaminoutINTEL)", + &s_operands[1798], + 6, + }, + { + SpirvOp::OpSubgroupAvcImeEvaluateWithDualReferenceStreaminoutINTEL, + R"(OpSubgroupAvcImeEvaluateWithDualReferenceStreaminoutINTEL)", + &s_operands[1804], + 7, + }, + { + SpirvOp::OpSubgroupAvcImeConvertToMceResultINTEL, + R"(OpSubgroupAvcImeConvertToMceResultINTEL)", + &s_operands[1811], + 3, + }, + { + SpirvOp::OpSubgroupAvcImeGetSingleReferenceStreaminINTEL, + R"(OpSubgroupAvcImeGetSingleReferenceStreaminINTEL)", + &s_operands[1814], + 3, + }, + { + SpirvOp::OpSubgroupAvcImeGetDualReferenceStreaminINTEL, + R"(OpSubgroupAvcImeGetDualReferenceStreaminINTEL)", + &s_operands[1817], + 3, + }, + { + SpirvOp::OpSubgroupAvcImeStripSingleReferenceStreamoutINTEL, + R"(OpSubgroupAvcImeStripSingleReferenceStreamoutINTEL)", + &s_operands[1820], + 3, + }, + { + SpirvOp::OpSubgroupAvcImeStripDualReferenceStreamoutINTEL, + R"(OpSubgroupAvcImeStripDualReferenceStreamoutINTEL)", + &s_operands[1823], + 3, + }, + { + SpirvOp::OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeMotionVectorsINTEL, + R"(OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeMotionVectorsINTEL)", + &s_operands[1826], + 4, + }, + { + SpirvOp::OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeDistortionsINTEL, + R"(OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeDistortionsINTEL)", + &s_operands[1830], + 4, + }, + { + SpirvOp::OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeReferenceIdsINTEL, + R"(OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeReferenceIdsINTEL)", + &s_operands[1834], + 4, + }, + { + SpirvOp::OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeMotionVectorsINTEL, + R"(OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeMotionVectorsINTEL)", + &s_operands[1838], + 5, + }, + { + SpirvOp::OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeDistortionsINTEL, + R"(OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeDistortionsINTEL)", + &s_operands[1843], + 5, + }, + { + SpirvOp::OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeReferenceIdsINTEL, + R"(OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeReferenceIdsINTEL)", + &s_operands[1848], + 5, + }, + { + SpirvOp::OpSubgroupAvcImeGetBorderReachedINTEL, + R"(OpSubgroupAvcImeGetBorderReachedINTEL)", + &s_operands[1853], + 4, + }, + { + SpirvOp::OpSubgroupAvcImeGetTruncatedSearchIndicationINTEL, + R"(OpSubgroupAvcImeGetTruncatedSearchIndicationINTEL)", + &s_operands[1857], + 3, + }, + { + SpirvOp::OpSubgroupAvcImeGetUnidirectionalEarlySearchTerminationINTEL, + R"(OpSubgroupAvcImeGetUnidirectionalEarlySearchTerminationINTEL)", + &s_operands[1860], + 3, + }, + { + SpirvOp::OpSubgroupAvcImeGetWeightingPatternMinimumMotionVectorINTEL, + R"(OpSubgroupAvcImeGetWeightingPatternMinimumMotionVectorINTEL)", + &s_operands[1863], + 3, + }, + { + SpirvOp::OpSubgroupAvcImeGetWeightingPatternMinimumDistortionINTEL, + R"(OpSubgroupAvcImeGetWeightingPatternMinimumDistortionINTEL)", + &s_operands[1866], + 3, + }, + { + SpirvOp::OpSubgroupAvcFmeInitializeINTEL, + R"(OpSubgroupAvcFmeInitializeINTEL)", + &s_operands[1869], + 9, + }, + { + SpirvOp::OpSubgroupAvcBmeInitializeINTEL, + R"(OpSubgroupAvcBmeInitializeINTEL)", + &s_operands[1878], + 10, + }, + { + SpirvOp::OpSubgroupAvcRefConvertToMcePayloadINTEL, + R"(OpSubgroupAvcRefConvertToMcePayloadINTEL)", + &s_operands[1888], + 3, + }, + { + SpirvOp::OpSubgroupAvcRefSetBidirectionalMixDisableINTEL, + R"(OpSubgroupAvcRefSetBidirectionalMixDisableINTEL)", + &s_operands[1891], + 3, + }, + { + SpirvOp::OpSubgroupAvcRefSetBilinearFilterEnableINTEL, + R"(OpSubgroupAvcRefSetBilinearFilterEnableINTEL)", + &s_operands[1894], + 3, + }, + { + SpirvOp::OpSubgroupAvcRefEvaluateWithSingleReferenceINTEL, + R"(OpSubgroupAvcRefEvaluateWithSingleReferenceINTEL)", + &s_operands[1897], + 5, + }, + { + SpirvOp::OpSubgroupAvcRefEvaluateWithDualReferenceINTEL, + R"(OpSubgroupAvcRefEvaluateWithDualReferenceINTEL)", + &s_operands[1902], + 6, + }, + { + SpirvOp::OpSubgroupAvcRefEvaluateWithMultiReferenceINTEL, + R"(OpSubgroupAvcRefEvaluateWithMultiReferenceINTEL)", + &s_operands[1908], + 5, + }, + { + SpirvOp::OpSubgroupAvcRefEvaluateWithMultiReferenceInterlacedINTEL, + R"(OpSubgroupAvcRefEvaluateWithMultiReferenceInterlacedINTEL)", + &s_operands[1913], + 6, + }, + { + SpirvOp::OpSubgroupAvcRefConvertToMceResultINTEL, + R"(OpSubgroupAvcRefConvertToMceResultINTEL)", + &s_operands[1919], + 3, + }, + { + SpirvOp::OpSubgroupAvcSicInitializeINTEL, + R"(OpSubgroupAvcSicInitializeINTEL)", + &s_operands[1922], + 3, + }, + { + SpirvOp::OpSubgroupAvcSicConfigureSkcINTEL, + R"(OpSubgroupAvcSicConfigureSkcINTEL)", + &s_operands[1925], + 8, + }, + { + SpirvOp::OpSubgroupAvcSicConfigureIpeLumaINTEL, + R"(OpSubgroupAvcSicConfigureIpeLumaINTEL)", + &s_operands[1933], + 10, + }, + { + SpirvOp::OpSubgroupAvcSicConfigureIpeLumaChromaINTEL, + R"(OpSubgroupAvcSicConfigureIpeLumaChromaINTEL)", + &s_operands[1943], + 13, + }, + { + SpirvOp::OpSubgroupAvcSicGetMotionVectorMaskINTEL, + R"(OpSubgroupAvcSicGetMotionVectorMaskINTEL)", + &s_operands[1956], + 4, + }, + { + SpirvOp::OpSubgroupAvcSicConvertToMcePayloadINTEL, + R"(OpSubgroupAvcSicConvertToMcePayloadINTEL)", + &s_operands[1960], + 3, + }, + { + SpirvOp::OpSubgroupAvcSicSetIntraLumaShapePenaltyINTEL, + R"(OpSubgroupAvcSicSetIntraLumaShapePenaltyINTEL)", + &s_operands[1963], + 4, + }, + { + SpirvOp::OpSubgroupAvcSicSetIntraLumaModeCostFunctionINTEL, + R"(OpSubgroupAvcSicSetIntraLumaModeCostFunctionINTEL)", + &s_operands[1967], + 6, + }, + { + SpirvOp::OpSubgroupAvcSicSetIntraChromaModeCostFunctionINTEL, + R"(OpSubgroupAvcSicSetIntraChromaModeCostFunctionINTEL)", + &s_operands[1973], + 4, + }, + { + SpirvOp::OpSubgroupAvcSicSetBilinearFilterEnableINTEL, + R"(OpSubgroupAvcSicSetBilinearFilterEnableINTEL)", + &s_operands[1977], + 3, + }, + { + SpirvOp::OpSubgroupAvcSicSetSkcForwardTransformEnableINTEL, + R"(OpSubgroupAvcSicSetSkcForwardTransformEnableINTEL)", + &s_operands[1980], + 4, + }, + { + SpirvOp::OpSubgroupAvcSicSetBlockBasedRawSkipSadINTEL, + R"(OpSubgroupAvcSicSetBlockBasedRawSkipSadINTEL)", + &s_operands[1984], + 4, + }, + { + SpirvOp::OpSubgroupAvcSicEvaluateIpeINTEL, + R"(OpSubgroupAvcSicEvaluateIpeINTEL)", + &s_operands[1988], + 4, + }, + { + SpirvOp::OpSubgroupAvcSicEvaluateWithSingleReferenceINTEL, + R"(OpSubgroupAvcSicEvaluateWithSingleReferenceINTEL)", + &s_operands[1992], + 5, + }, + { + SpirvOp::OpSubgroupAvcSicEvaluateWithDualReferenceINTEL, + R"(OpSubgroupAvcSicEvaluateWithDualReferenceINTEL)", + &s_operands[1997], + 6, + }, + { + SpirvOp::OpSubgroupAvcSicEvaluateWithMultiReferenceINTEL, + R"(OpSubgroupAvcSicEvaluateWithMultiReferenceINTEL)", + &s_operands[2003], + 5, + }, + { + SpirvOp::OpSubgroupAvcSicEvaluateWithMultiReferenceInterlacedINTEL, + R"(OpSubgroupAvcSicEvaluateWithMultiReferenceInterlacedINTEL)", + &s_operands[2008], + 6, + }, + { + SpirvOp::OpSubgroupAvcSicConvertToMceResultINTEL, + R"(OpSubgroupAvcSicConvertToMceResultINTEL)", + &s_operands[2014], + 3, + }, + { + SpirvOp::OpSubgroupAvcSicGetIpeLumaShapeINTEL, + R"(OpSubgroupAvcSicGetIpeLumaShapeINTEL)", + &s_operands[2017], + 3, + }, + { + SpirvOp::OpSubgroupAvcSicGetBestIpeLumaDistortionINTEL, + R"(OpSubgroupAvcSicGetBestIpeLumaDistortionINTEL)", + &s_operands[2020], + 3, + }, + { + SpirvOp::OpSubgroupAvcSicGetBestIpeChromaDistortionINTEL, + R"(OpSubgroupAvcSicGetBestIpeChromaDistortionINTEL)", + &s_operands[2023], + 3, + }, + { + SpirvOp::OpSubgroupAvcSicGetPackedIpeLumaModesINTEL, + R"(OpSubgroupAvcSicGetPackedIpeLumaModesINTEL)", + &s_operands[2026], + 3, + }, + { + SpirvOp::OpSubgroupAvcSicGetIpeChromaModeINTEL, + R"(OpSubgroupAvcSicGetIpeChromaModeINTEL)", + &s_operands[2029], + 3, + }, + { + SpirvOp::OpSubgroupAvcSicGetPackedSkcLumaCountThresholdINTEL, + R"(OpSubgroupAvcSicGetPackedSkcLumaCountThresholdINTEL)", + &s_operands[2032], + 3, + }, + { + SpirvOp::OpSubgroupAvcSicGetPackedSkcLumaSumThresholdINTEL, + R"(OpSubgroupAvcSicGetPackedSkcLumaSumThresholdINTEL)", + &s_operands[2035], + 3, + }, + { + SpirvOp::OpSubgroupAvcSicGetInterRawSadsINTEL, + R"(OpSubgroupAvcSicGetInterRawSadsINTEL)", + &s_operands[2038], + 3, + }, + { + SpirvOp::OpLoopControlINTEL, + R"(OpLoopControlINTEL)", + &s_operands[2041], + 1, + }, + { + SpirvOp::OpReadPipeBlockingINTEL, + R"(OpReadPipeBlockingINTEL)", + &s_operands[2042], + 4, + }, + { + SpirvOp::OpWritePipeBlockingINTEL, + R"(OpWritePipeBlockingINTEL)", + &s_operands[2046], + 4, + }, + { + SpirvOp::OpFPGARegINTEL, + R"(OpFPGARegINTEL)", + &s_operands[2050], + 4, + }, + { + SpirvOp::OpRayQueryGetRayTMinKHR, + R"(OpRayQueryGetRayTMinKHR)", + &s_operands[2054], + 3, + }, + { + SpirvOp::OpRayQueryGetRayFlagsKHR, + R"(OpRayQueryGetRayFlagsKHR)", + &s_operands[2057], + 3, + }, + { + SpirvOp::OpRayQueryGetIntersectionTKHR, + R"(OpRayQueryGetIntersectionTKHR)", + &s_operands[2060], + 4, + }, + { + SpirvOp::OpRayQueryGetIntersectionInstanceCustomIndexKHR, + R"(OpRayQueryGetIntersectionInstanceCustomIndexKHR)", + &s_operands[2064], + 4, + }, + { + SpirvOp::OpRayQueryGetIntersectionInstanceIdKHR, + R"(OpRayQueryGetIntersectionInstanceIdKHR)", + &s_operands[2068], + 4, + }, + { + SpirvOp::OpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffsetKHR, + R"(OpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffsetKHR)", + &s_operands[2072], + 4, + }, + { + SpirvOp::OpRayQueryGetIntersectionGeometryIndexKHR, + R"(OpRayQueryGetIntersectionGeometryIndexKHR)", + &s_operands[2076], + 4, + }, + { + SpirvOp::OpRayQueryGetIntersectionPrimitiveIndexKHR, + R"(OpRayQueryGetIntersectionPrimitiveIndexKHR)", + &s_operands[2080], + 4, + }, + { + SpirvOp::OpRayQueryGetIntersectionBarycentricsKHR, + R"(OpRayQueryGetIntersectionBarycentricsKHR)", + &s_operands[2084], + 4, + }, + { + SpirvOp::OpRayQueryGetIntersectionFrontFaceKHR, + R"(OpRayQueryGetIntersectionFrontFaceKHR)", + &s_operands[2088], + 4, + }, + { + SpirvOp::OpRayQueryGetIntersectionCandidateAABBOpaqueKHR, + R"(OpRayQueryGetIntersectionCandidateAABBOpaqueKHR)", + &s_operands[2092], + 3, + }, + { + SpirvOp::OpRayQueryGetIntersectionObjectRayDirectionKHR, + R"(OpRayQueryGetIntersectionObjectRayDirectionKHR)", + &s_operands[2095], + 4, + }, + { + SpirvOp::OpRayQueryGetIntersectionObjectRayOriginKHR, + R"(OpRayQueryGetIntersectionObjectRayOriginKHR)", + &s_operands[2099], + 4, + }, + { + SpirvOp::OpRayQueryGetWorldRayDirectionKHR, + R"(OpRayQueryGetWorldRayDirectionKHR)", + &s_operands[2103], + 3, + }, + { + SpirvOp::OpRayQueryGetWorldRayOriginKHR, + R"(OpRayQueryGetWorldRayOriginKHR)", + &s_operands[2106], + 3, + }, + { + SpirvOp::OpRayQueryGetIntersectionObjectToWorldKHR, + R"(OpRayQueryGetIntersectionObjectToWorldKHR)", + &s_operands[2109], + 4, + }, + { + SpirvOp::OpRayQueryGetIntersectionWorldToObjectKHR, + R"(OpRayQueryGetIntersectionWorldToObjectKHR)", + &s_operands[2113], + 4, + }, + { + SpirvOp::OpAtomicFAddEXT, + R"(OpAtomicFAddEXT)", + &s_operands[2117], + 6, + }, + } + }; + + const SpirvInstruction* GetInstructionData(UInt16 op) + { + auto it = std::lower_bound(std::begin(s_instructions), std::end(s_instructions), op, [](const SpirvInstruction& inst, UInt16 op) { return UInt16(inst.op) < op; }); + if (it != std::end(s_instructions) && UInt16(it->op) == op) + return &*it; + else + return nullptr; + } +} From 0b507708f4985579d36d9e11155f53aaecca41a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Tue, 18 Aug 2020 00:00:05 +0200 Subject: [PATCH 094/105] Shader/SpirvWriter: Split section to another class + improve variadic parameters support --- include/Nazara/Shader/SpirvSection.hpp | 73 ++++++ include/Nazara/Shader/SpirvSection.inl | 146 ++++++++++++ include/Nazara/Shader/SpirvWriter.hpp | 31 +-- include/Nazara/Shader/SpirvWriter.inl | 99 --------- src/Nazara/Shader/SpirvSection.cpp | 38 ++++ src/Nazara/Shader/SpirvWriter.cpp | 295 +++++++++++-------------- 6 files changed, 387 insertions(+), 295 deletions(-) create mode 100644 include/Nazara/Shader/SpirvSection.hpp create mode 100644 include/Nazara/Shader/SpirvSection.inl create mode 100644 src/Nazara/Shader/SpirvSection.cpp diff --git a/include/Nazara/Shader/SpirvSection.hpp b/include/Nazara/Shader/SpirvSection.hpp new file mode 100644 index 000000000..b116b212f --- /dev/null +++ b/include/Nazara/Shader/SpirvSection.hpp @@ -0,0 +1,73 @@ +// 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_SPIRVSECTION_HPP +#define NAZARA_SPIRVSECTION_HPP + +#include +#include +#include +#include +#include + +namespace Nz +{ + class NAZARA_SHADER_API SpirvSection + { + public: + struct OpSize; + struct Raw; + + SpirvSection() = default; + SpirvSection(const SpirvSection& cache) = default; + SpirvSection(SpirvSection&& cache) = default; + ~SpirvSection() = default; + + inline std::size_t Append(const char* str); + inline std::size_t Append(const std::string_view& str); + inline std::size_t Append(const std::string& str); + inline std::size_t Append(UInt32 value); + inline std::size_t Append(SpirvOp opcode, const OpSize& wordCount); + std::size_t Append(const Raw& raw); + inline std::size_t Append(std::initializer_list codepoints); + template std::size_t Append(SpirvOp opcode, const Args&... args); + template std::size_t AppendVariadic(SpirvOp opcode, F&& callback); + template std::size_t Append(T value); + + inline unsigned int CountWord(const char* str); + inline unsigned int CountWord(const std::string_view& str); + inline unsigned int CountWord(const std::string& str); + inline unsigned int CountWord(const Raw& raw); + template unsigned int CountWord(const T& value); + template unsigned int CountWord(const T1& value, const T2& value2, const Args&... rest); + + inline const std::vector& GetBytecode() const; + inline std::size_t GetOutputOffset() const; + + SpirvSection& operator=(const SpirvSection& cache) = delete; + SpirvSection& operator=(SpirvSection&& cache) = default; + + struct OpSize + { + unsigned int wc; + }; + + struct Raw + { + const void* ptr; + std::size_t size; + }; + + static inline UInt32 BuildOpcode(SpirvOp opcode, unsigned int wordCount); + + private: + std::vector m_bytecode; + }; +} + +#include + +#endif diff --git a/include/Nazara/Shader/SpirvSection.inl b/include/Nazara/Shader/SpirvSection.inl new file mode 100644 index 000000000..f4770e3f3 --- /dev/null +++ b/include/Nazara/Shader/SpirvSection.inl @@ -0,0 +1,146 @@ +// 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 std::size_t SpirvSection::Append(const char* str) + { + return Append(std::string_view(str)); + } + + inline std::size_t SpirvSection::Append(const std::string_view& 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); + } + + return offset; + } + + inline std::size_t SpirvSection::Append(const std::string& str) + { + return Append(std::string_view(str)); + } + + inline std::size_t SpirvSection::Append(UInt32 value) + { + std::size_t offset = GetOutputOffset(); + m_bytecode.push_back(value); + + return offset; + } + + inline std::size_t SpirvSection::Append(SpirvOp opcode, const OpSize& wordCount) + { + return Append(BuildOpcode(opcode, wordCount.wc)); + } + + inline std::size_t SpirvSection::Append(std::initializer_list codepoints) + { + std::size_t offset = GetOutputOffset(); + + for (UInt32 cp : codepoints) + Append(cp); + + return offset; + } + + template + std::size_t SpirvSection::Append(SpirvOp opcode, const Args&... args) + { + unsigned int wordCount = 1 + (CountWord(args) + ... + 0); + std::size_t offset = Append(opcode, OpSize{ wordCount }); + if constexpr (sizeof...(args) > 0) + (Append(args), ...); + + return offset; + } + + template std::size_t SpirvSection::AppendVariadic(SpirvOp opcode, F&& callback) + { + std::size_t offset = Append(0); //< Will be filled later + + unsigned int wordCount = 1; + auto appendFunctor = [&](const auto& value) + { + wordCount += CountWord(value); + Append(value); + }; + callback(appendFunctor); + + m_bytecode[offset] = BuildOpcode(opcode, wordCount); + + return offset; + } + + template + std::size_t SpirvSection::Append(T value) + { + return Append(static_cast(value)); + } + + template + unsigned int SpirvSection::CountWord(const T& value) + { + return 1; + } + + template + unsigned int SpirvSection::CountWord(const T1& value, const T2& value2, const Args&... rest) + { + return CountWord(value) + CountWord(value2) + (CountWord(rest) + ...); + } + + inline unsigned int SpirvSection::CountWord(const char* str) + { + return CountWord(std::string_view(str)); + } + + inline unsigned int Nz::SpirvSection::CountWord(const std::string& str) + { + return CountWord(std::string_view(str)); + } + + inline unsigned int SpirvSection::CountWord(const Raw& raw) + { + return static_cast((raw.size + sizeof(UInt32) - 1) / sizeof(UInt32)); + } + + inline unsigned int SpirvSection::CountWord(const std::string_view& str) + { + return (static_cast(str.size() + 1) + sizeof(UInt32) - 1) / sizeof(UInt32); //< + 1 for null character + } + + inline const std::vector& SpirvSection::GetBytecode() const + { + return m_bytecode; + } + + inline std::size_t SpirvSection::GetOutputOffset() const + { + return m_bytecode.size(); + } + + inline UInt32 SpirvSection::BuildOpcode(SpirvOp opcode, unsigned int wordCount) + { + return UInt32(opcode) | UInt32(wordCount) << 16; + } +} + +#include diff --git a/include/Nazara/Shader/SpirvWriter.hpp b/include/Nazara/Shader/SpirvWriter.hpp index 90f6b0e3e..71a617eaa 100644 --- a/include/Nazara/Shader/SpirvWriter.hpp +++ b/include/Nazara/Shader/SpirvWriter.hpp @@ -20,6 +20,8 @@ namespace Nz { + class SpirvSection; + class NAZARA_SHADER_API SpirvWriter : public ShaderAstVisitor, public ShaderVarVisitor { public: @@ -42,33 +44,6 @@ namespace Nz private: struct ExtVar; - struct Opcode; - struct Raw; - struct WordCount; - - struct Section - { - inline std::size_t Append(const char* str); - inline std::size_t Append(const std::string_view& str); - inline std::size_t Append(const std::string& str); - inline std::size_t Append(UInt32 value); - std::size_t Append(const Opcode& opcode, const WordCount& wordCount); - std::size_t Append(const Raw& raw); - inline std::size_t Append(std::initializer_list codepoints); - template std::size_t Append(Opcode opcode, const Args&... args); - template std::size_t Append(T value); - - inline unsigned int CountWord(const char* str); - inline unsigned int CountWord(const std::string_view& str); - inline unsigned int CountWord(const std::string& str); - unsigned int CountWord(const Raw& raw); - template unsigned int CountWord(const T& value); - template unsigned int CountWord(const T1& value, const T2& value2, const Args&... rest); - - inline std::size_t GetOutputOffset() const; - - std::vector data; - }; UInt32 AllocateResultId(); @@ -111,7 +86,7 @@ namespace Nz void Visit(ShaderNodes::ParameterVariable& var) override; void Visit(ShaderNodes::UniformVariable& var) override; - static void MergeBlocks(std::vector& output, const Section& from); + static void MergeBlocks(std::vector& output, const SpirvSection& from); struct Context { diff --git a/include/Nazara/Shader/SpirvWriter.inl b/include/Nazara/Shader/SpirvWriter.inl index 4ef96c82b..26012e0d1 100644 --- a/include/Nazara/Shader/SpirvWriter.inl +++ b/include/Nazara/Shader/SpirvWriter.inl @@ -3,109 +3,10 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include -#include -#include #include namespace Nz { - inline std::size_t SpirvWriter::Section::Append(const char* str) - { - return Append(std::string_view(str)); - } - - inline std::size_t SpirvWriter::Section::Append(const std::string_view& 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); - } - - return offset; - } - - inline std::size_t SpirvWriter::Section::Append(const std::string& str) - { - return Append(std::string_view(str)); - } - - inline std::size_t SpirvWriter::Section::Append(UInt32 value) - { - std::size_t offset = GetOutputOffset(); - data.push_back(value); - - return offset; - } - - inline std::size_t SpirvWriter::Section::Append(std::initializer_list codepoints) - { - std::size_t offset = GetOutputOffset(); - - for (UInt32 cp : codepoints) - Append(cp); - - return offset; - } - - template - std::size_t SpirvWriter::Section::Append(Opcode opcode, const Args&... args) - { - unsigned int wordCount = 1 + (CountWord(args) + ... + 0); - std::size_t offset = Append(opcode, WordCount{ wordCount }); - if constexpr (sizeof...(args) > 0) - (Append(args), ...); - - return offset; - } - - template - std::size_t SpirvWriter::Section::Append(T value) - { - return Append(static_cast(value)); - } - - template - unsigned int SpirvWriter::Section::CountWord(const T& value) - { - return 1; - } - - template - unsigned int SpirvWriter::Section::CountWord(const T1& value, const T2& value2, const Args&... rest) - { - return CountWord(value) + CountWord(value2) + (CountWord(rest) + ...); - } - - inline unsigned int SpirvWriter::Section::CountWord(const char* str) - { - return CountWord(std::string_view(str)); - } - - inline unsigned int Nz::SpirvWriter::Section::CountWord(const std::string& str) - { - return CountWord(std::string_view(str)); - } - - inline unsigned int SpirvWriter::Section::CountWord(const std::string_view& str) - { - return (static_cast(str.size() + 1) + sizeof(UInt32) - 1) / sizeof(UInt32); //< + 1 for null character - } - - std::size_t SpirvWriter::Section::GetOutputOffset() const - { - return data.size(); - } } #include diff --git a/src/Nazara/Shader/SpirvSection.cpp b/src/Nazara/Shader/SpirvSection.cpp new file mode 100644 index 000000000..c3d62ade3 --- /dev/null +++ b/src/Nazara/Shader/SpirvSection.cpp @@ -0,0 +1,38 @@ +// 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 + +namespace Nz +{ + std::size_t SpirvSection::Append(const Raw& raw) + { + std::size_t offset = GetOutputOffset(); + + const UInt8* ptr = static_cast(raw.ptr); + + std::size_t size4 = CountWord(raw); + for (std::size_t i = 0; i < size4; ++i) + { + UInt32 codepoint = 0; + for (std::size_t j = 0; j < 4; ++j) + { +#ifdef NAZARA_BIG_ENDIAN + std::size_t pos = i * 4 + (3 - j); +#else + std::size_t pos = i * 4 + j; +#endif + + if (pos < raw.size) + codepoint |= UInt32(ptr[pos]) << (j * 8); + } + + Append(codepoint); + } + + return offset; + } +} diff --git a/src/Nazara/Shader/SpirvWriter.cpp b/src/Nazara/Shader/SpirvWriter.cpp index b3b318c63..fb767d0e8 100644 --- a/src/Nazara/Shader/SpirvWriter.cpp +++ b/src/Nazara/Shader/SpirvWriter.cpp @@ -8,6 +8,8 @@ #include #include #include +#include +#include #include #include #include @@ -198,22 +200,6 @@ namespace Nz std::optional valueId; }; - struct SpirvWriter::Opcode - { - SpvOp op; - }; - - struct SpirvWriter::Raw - { - const void* ptr; - std::size_t size; - }; - - struct SpirvWriter::WordCount - { - unsigned int wc; - }; - struct SpirvWriter::State { struct Func @@ -237,12 +223,12 @@ namespace Nz UInt32 nextVarIndex = 1; // Output - Section header; - Section constants; - Section debugInfo; - Section annotations; - Section types; - Section instructions; + SpirvSection header; + SpirvSection constants; + SpirvSection debugInfo; + SpirvSection annotations; + SpirvSection types; + SpirvSection instructions; }; SpirvWriter::SpirvWriter() : @@ -343,11 +329,11 @@ namespace Nz throw std::runtime_error("unexpected builtin type"); } - state.debugInfo.Append(Opcode{ SpvOpName }, builtinData.varId, debugName); - state.types.Append(Opcode{ SpvOpTypePointer }, builtinData.pointerTypeId, SpvStorageClassOutput, builtinData.typeId); - state.types.Append(Opcode{ SpvOpVariable }, builtinData.pointerTypeId, builtinData.varId, SpvStorageClassOutput); + state.debugInfo.Append(SpirvOp::OpName, builtinData.varId, debugName); + state.types.Append(SpirvOp::OpTypePointer, builtinData.pointerTypeId, SpvStorageClassOutput, builtinData.typeId); + state.types.Append(SpirvOp::OpVariable, builtinData.pointerTypeId, builtinData.varId, SpvStorageClassOutput); - state.annotations.Append(Opcode{ SpvOpDecorate }, builtinData.varId, SpvDecorationBuiltIn, spvBuiltin); + state.annotations.Append(SpirvOp::OpDecorate, builtinData.varId, SpvDecorationBuiltIn, spvBuiltin); state.builtinIds.emplace(builtin->entry, builtinData); } @@ -361,12 +347,12 @@ namespace Nz state.inputIds.emplace(input.name, inputData); - state.debugInfo.Append(Opcode{ SpvOpName }, inputData.varId, input.name); - state.types.Append(Opcode{ SpvOpTypePointer }, inputData.pointerTypeId, SpvStorageClassInput, inputData.typeId); - state.types.Append(Opcode{ SpvOpVariable }, inputData.pointerTypeId, inputData.varId, SpvStorageClassInput); + state.debugInfo.Append(SpirvOp::OpName, inputData.varId, input.name); + state.types.Append(SpirvOp::OpTypePointer, inputData.pointerTypeId, SpvStorageClassInput, inputData.typeId); + state.types.Append(SpirvOp::OpVariable, inputData.pointerTypeId, inputData.varId, SpvStorageClassInput); if (input.locationIndex) - state.annotations.Append(Opcode{ SpvOpDecorate }, inputData.varId, SpvDecorationLocation, *input.locationIndex); + state.annotations.Append(SpirvOp::OpDecorate, inputData.varId, SpvDecorationLocation, *input.locationIndex); } for (const auto& output : shader.GetOutputs()) @@ -378,12 +364,12 @@ namespace Nz state.outputIds.emplace(output.name, outputData); - state.debugInfo.Append(Opcode{ SpvOpName }, outputData.varId, output.name); - state.types.Append(Opcode{ SpvOpTypePointer }, outputData.pointerTypeId, SpvStorageClassOutput, outputData.typeId); - state.types.Append(Opcode{ SpvOpVariable }, outputData.pointerTypeId, outputData.varId, SpvStorageClassOutput); + state.debugInfo.Append(SpirvOp::OpName, outputData.varId, output.name); + state.types.Append(SpirvOp::OpTypePointer, outputData.pointerTypeId, SpvStorageClassOutput, outputData.typeId); + state.types.Append(SpirvOp::OpVariable, outputData.pointerTypeId, outputData.varId, SpvStorageClassOutput); if (output.locationIndex) - state.annotations.Append(Opcode{ SpvOpDecorate }, outputData.varId, SpvDecorationLocation, *output.locationIndex); + state.annotations.Append(SpirvOp::OpDecorate, outputData.varId, SpvDecorationLocation, *output.locationIndex); } for (const auto& uniform : shader.GetUniforms()) @@ -395,14 +381,14 @@ namespace Nz state.uniformIds.emplace(uniform.name, uniformData); - state.debugInfo.Append(Opcode{ SpvOpName }, uniformData.varId, uniform.name); - state.types.Append(Opcode{ SpvOpTypePointer }, uniformData.pointerTypeId, SpvStorageClassUniform, uniformData.typeId); - state.types.Append(Opcode{ SpvOpVariable }, uniformData.pointerTypeId, uniformData.varId, SpvStorageClassUniform); + state.debugInfo.Append(SpirvOp::OpName, uniformData.varId, uniform.name); + state.types.Append(SpirvOp::OpTypePointer, uniformData.pointerTypeId, SpvStorageClassUniform, uniformData.typeId); + state.types.Append(SpirvOp::OpVariable, uniformData.pointerTypeId, uniformData.varId, SpvStorageClassUniform); if (uniform.bindingIndex) { - state.annotations.Append(Opcode{ SpvOpDecorate }, uniformData.varId, SpvDecorationBinding, *uniform.bindingIndex); - state.annotations.Append(Opcode{ SpvOpDecorate }, uniformData.varId, SpvDecorationDescriptorSet, 0); + state.annotations.Append(SpirvOp::OpDecorate, uniformData.varId, SpvDecorationBinding, *uniform.bindingIndex); + state.annotations.Append(SpirvOp::OpDecorate, uniformData.varId, SpvDecorationDescriptorSet, 0); } } @@ -412,14 +398,16 @@ namespace Nz funcData.id = AllocateResultId(); funcData.typeId = AllocateResultId(); - state.debugInfo.Append(Opcode{ SpvOpName }, funcData.id, func.name); + state.debugInfo.Append(SpirvOp::OpName, funcData.id, func.name); - state.types.Append(Opcode{ SpvOpTypeFunction }, WordCount{ 3 + static_cast(func.parameters.size()) }); - state.types.Append(funcData.typeId); - state.types.Append(GetTypeId(func.returnType)); + state.types.AppendVariadic(SpirvOp::OpTypeFunction, [&](const auto& appender) + { + appender(funcData.typeId); + appender(GetTypeId(func.returnType)); - for (const auto& param : func.parameters) - state.types.Append(GetTypeId(param.type)); + for (const auto& param : func.parameters) + appender(GetTypeId(param.type)); + }); } // Register constants @@ -438,24 +426,24 @@ namespace Nz auto& funcData = state.funcs[funcIndex]; - state.instructions.Append(Opcode{ SpvOpFunction }, GetTypeId(func.returnType), funcData.id, 0, funcData.typeId); + state.instructions.Append(SpirvOp::OpFunction, GetTypeId(func.returnType), funcData.id, 0, funcData.typeId); - state.instructions.Append(Opcode{ SpvOpLabel }, AllocateResultId()); + state.instructions.Append(SpirvOp::OpLabel, AllocateResultId()); for (const auto& param : func.parameters) { UInt32 paramResultId = AllocateResultId(); funcData.paramsId.push_back(paramResultId); - state.instructions.Append(Opcode{ SpvOpFunctionParameter }, GetTypeId(param.type), paramResultId); + state.instructions.Append(SpirvOp::OpFunctionParameter, GetTypeId(param.type), paramResultId); } Visit(functionStatements[funcIndex]); if (func.returnType == ShaderNodes::BasicType::Void) - state.instructions.Append(Opcode{ SpvOpReturn }); + state.instructions.Append(SpirvOp::OpReturn); - state.instructions.Append(Opcode{ SpvOpFunctionEnd }); + state.instructions.Append(SpirvOp::OpFunctionEnd); } assert(entryPointIndex != std::numeric_limits::max()); @@ -485,21 +473,24 @@ namespace Nz std::size_t nameSize = state.header.CountWord(entryFuncData.name); - state.header.Append(Opcode{ SpvOpEntryPoint }, WordCount{ static_cast(3 + nameSize + m_currentState->builtinIds.size() + m_currentState->inputIds.size() + m_currentState->outputIds.size()) }); - state.header.Append(execModel); - state.header.Append(entryFunc.id); - state.header.Append(entryFuncData.name); - for (const auto& [name, varData] : m_currentState->builtinIds) - state.header.Append(varData.varId); + state.header.AppendVariadic(SpirvOp::OpEntryPoint, [&](const auto& appender) + { + appender(execModel); + appender(entryFunc.id); + appender(entryFuncData.name); - for (const auto& [name, varData] : m_currentState->inputIds) - state.header.Append(varData.varId); + for (const auto& [name, varData] : m_currentState->builtinIds) + appender(varData.varId); - for (const auto& [name, varData] : m_currentState->outputIds) - state.header.Append(varData.varId); + for (const auto& [name, varData] : m_currentState->inputIds) + appender(varData.varId); + + for (const auto& [name, varData] : m_currentState->outputIds) + appender(varData.varId); + }); if (m_context.shader->GetStage() == ShaderStageType::Fragment) - state.header.Append(Opcode{ SpvOpExecutionMode }, entryFunc.id, SpvExecutionModeOriginUpperLeft); + state.header.Append(SpirvOp::OpExecutionMode, entryFunc.id, SpvExecutionModeOriginUpperLeft); std::vector ret; MergeBlocks(ret, state.header); @@ -532,15 +523,15 @@ namespace Nz using T = std::decay_t; if constexpr (std::is_same_v) - m_currentState->constants.Append(Opcode{ (arg) ? SpvOpConstantTrue : SpvOpConstantFalse }, constantId); + m_currentState->constants.Append((arg) ? SpirvOp::OpConstantTrue : SpirvOp::OpConstantFalse, constantId); else if constexpr (std::is_same_v || std::is_same_v) - m_currentState->constants.Append(Opcode{ SpvOpConstant }, GetTypeId(GetBasicType()), constantId, Raw{ &arg, sizeof(arg) }); + m_currentState->constants.Append(SpirvOp::OpConstant, GetTypeId(GetBasicType()), constantId, SpirvSection::Raw{ &arg, sizeof(arg) }); else if constexpr (std::is_same_v || std::is_same_v) - m_currentState->constants.Append(Opcode{ SpvOpConstantComposite }, GetTypeId(GetBasicType()), constantId, GetConstantId(arg.x), GetConstantId(arg.y)); + m_currentState->constants.Append(SpirvOp::OpConstantComposite, GetTypeId(GetBasicType()), constantId, GetConstantId(arg.x), GetConstantId(arg.y)); else if constexpr (std::is_same_v || std::is_same_v) - m_currentState->constants.Append(Opcode{ SpvOpConstantComposite }, GetTypeId(GetBasicType()), constantId, GetConstantId(arg.x), GetConstantId(arg.y), GetConstantId(arg.z)); + m_currentState->constants.Append(SpirvOp::OpConstantComposite, GetTypeId(GetBasicType()), constantId, GetConstantId(arg.x), GetConstantId(arg.y), GetConstantId(arg.z)); else if constexpr (std::is_same_v || std::is_same_v) - m_currentState->constants.Append(Opcode{ SpvOpConstantComposite }, GetTypeId(GetBasicType()), constantId, GetConstantId(arg.x), GetConstantId(arg.y), GetConstantId(arg.z), GetConstantId(arg.w)); + m_currentState->constants.Append(SpirvOp::OpConstantComposite, GetTypeId(GetBasicType()), constantId, GetConstantId(arg.x), GetConstantId(arg.y), GetConstantId(arg.z), GetConstantId(arg.w)); else static_assert(AlwaysFalse::value, "non-exhaustive visitor"); }, value); @@ -558,24 +549,24 @@ namespace Nz m_currentState->header.Append(m_currentState->nextVarIndex); //< Bound (ID count) m_currentState->header.Append(0); //< Instruction schema (required to be 0 for now) - m_currentState->header.Append(Opcode{ SpvOpCapability }, SpvCapabilityShader); + m_currentState->header.Append(SpirvOp::OpCapability, SpvCapabilityShader); for (const auto& [extInst, resultId] : m_currentState->extensionInstructions) - m_currentState->header.Append(Opcode{ SpvOpExtInstImport }, resultId, extInst); + m_currentState->header.Append(SpirvOp::OpExtInstImport, resultId, extInst); - m_currentState->header.Append(Opcode{ SpvOpMemoryModel }, SpvAddressingModelLogical, SpvMemoryModelGLSL450); + m_currentState->header.Append(SpirvOp::OpMemoryModel, SpvAddressingModelLogical, SpvMemoryModelGLSL450); } void SpirvWriter::AppendStructType(std::size_t structIndex, UInt32 resultId) { const ShaderAst::Struct& s = m_context.shader->GetStruct(structIndex); - m_currentState->types.Append(Opcode{ SpvOpTypeStruct }, WordCount{ static_cast(1 + 1 + s.members.size()) }); + m_currentState->types.Append(SpirvOp::OpTypeStruct, SpirvSection::OpSize{ static_cast(1 + 1 + s.members.size()) }); m_currentState->types.Append(resultId); - m_currentState->debugInfo.Append(Opcode{ SpvOpName }, resultId, s.name); + m_currentState->debugInfo.Append(SpirvOp::OpName, resultId, s.name); - m_currentState->annotations.Append(Opcode{ SpvOpDecorate }, resultId, SpvDecorationBlock); + m_currentState->annotations.Append(SpirvOp::OpDecorate, resultId, SpvDecorationBlock); FieldOffsets structOffsets(StructLayout_Std140); @@ -583,7 +574,7 @@ namespace Nz { const auto& member = s.members[memberIndex]; m_currentState->types.Append(GetTypeId(member.type)); - m_currentState->debugInfo.Append(Opcode{ SpvOpMemberName }, resultId, memberIndex, member.name); + m_currentState->debugInfo.Append(SpirvOp::OpMemberName, resultId, memberIndex, member.name); std::visit([&](auto&& arg) { @@ -611,12 +602,12 @@ namespace Nz throw std::runtime_error("unhandled type"); }(); - m_currentState->annotations.Append(Opcode{ SpvOpMemberDecorate }, resultId, memberIndex, SpvDecorationOffset, offset); + m_currentState->annotations.Append(SpirvOp::OpMemberDecorate, resultId, memberIndex, SpvDecorationOffset, offset); if (arg == ShaderNodes::BasicType::Mat4x4) { - m_currentState->annotations.Append(Opcode{ SpvOpMemberDecorate }, resultId, memberIndex, SpvDecorationColMajor); - m_currentState->annotations.Append(Opcode{ SpvOpMemberDecorate }, resultId, memberIndex, SpvDecorationMatrixStride, 16); + m_currentState->annotations.Append(SpirvOp::OpMemberDecorate, resultId, memberIndex, SpvDecorationColMajor); + m_currentState->annotations.Append(SpirvOp::OpMemberDecorate, resultId, memberIndex, SpvDecorationMatrixStride, 16); } } else if constexpr (std::is_same_v) @@ -657,11 +648,11 @@ namespace Nz switch (arg) { case ShaderNodes::BasicType::Boolean: - m_currentState->types.Append(Opcode{ SpvOpTypeBool }, resultId); + m_currentState->types.Append(SpirvOp::OpTypeBool, resultId); break; case ShaderNodes::BasicType::Float1: - m_currentState->types.Append(Opcode{ SpvOpTypeFloat }, resultId, 32); + m_currentState->types.Append(SpirvOp::OpTypeFloat, resultId, 32); break; case ShaderNodes::BasicType::Float2: @@ -675,17 +666,17 @@ namespace Nz UInt32 vecSize = UInt32(arg) - UInt32(baseType) + 1; - m_currentState->types.Append(Opcode{ SpvOpTypeVector }, resultId, GetTypeId(baseType), vecSize); + m_currentState->types.Append(SpirvOp::OpTypeVector, resultId, GetTypeId(baseType), vecSize); break; } case ShaderNodes::BasicType::Int1: - m_currentState->types.Append(Opcode{ SpvOpTypeInt }, resultId, 32, 1); + m_currentState->types.Append(SpirvOp::OpTypeInt, resultId, 32, 1); break; case ShaderNodes::BasicType::Mat4x4: { - m_currentState->types.Append(Opcode{ SpvOpTypeMatrix }, resultId, GetTypeId(ShaderNodes::BasicType::Float4), 4); + m_currentState->types.Append(SpirvOp::OpTypeMatrix, resultId, GetTypeId(ShaderNodes::BasicType::Float4), 4); break; } @@ -693,13 +684,13 @@ namespace Nz { UInt32 imageTypeId = resultId - 1; - m_currentState->types.Append(Opcode{ SpvOpTypeImage }, imageTypeId, GetTypeId(ShaderNodes::BasicType::Float1), SpvDim2D, 0, 0, 0, 1, SpvImageFormatUnknown); - m_currentState->types.Append(Opcode{ SpvOpTypeSampledImage }, resultId, imageTypeId); + m_currentState->types.Append(SpirvOp::OpTypeImage, imageTypeId, GetTypeId(ShaderNodes::BasicType::Float1), SpvDim2D, 0, 0, 0, 1, SpvImageFormatUnknown); + m_currentState->types.Append(SpirvOp::OpTypeSampledImage, resultId, imageTypeId); break; } case ShaderNodes::BasicType::Void: - m_currentState->types.Append(Opcode{ SpvOpTypeVoid }, resultId); + m_currentState->types.Append(SpirvOp::OpTypeVoid, resultId); break; } } @@ -763,7 +754,7 @@ namespace Nz if (!var.valueId.has_value()) { UInt32 resultId = AllocateResultId(); - m_currentState->instructions.Append(Opcode{ SpvOpLoad }, var.typeId, resultId, var.varId); + m_currentState->instructions.Append(SpirvOp::OpLoad, var.typeId, resultId, var.varId); var.valueId = resultId; } @@ -905,13 +896,13 @@ namespace Nz UInt32 typeId = GetTypeId(node.exprType); UInt32 indexId = GetConstantId(Int32(node.memberIndex)); - m_currentState->types.Append(Opcode{ SpvOpTypePointer }, pointerType, storage, typeId); + m_currentState->types.Append(SpirvOp::OpTypePointer, pointerType, storage, typeId); - m_currentState->instructions.Append(Opcode{ SpvOpAccessChain }, pointerType, memberPointerId, pointerId, indexId); + m_currentState->instructions.Append(SpirvOp::OpAccessChain, pointerType, memberPointerId, pointerId, indexId); UInt32 resultId = AllocateResultId(); - m_currentState->instructions.Append(Opcode{ SpvOpLoad }, typeId, resultId, memberPointerId); + m_currentState->instructions.Append(SpirvOp::OpLoad, typeId, resultId, memberPointerId); PushResultId(resultId); } @@ -933,7 +924,7 @@ namespace Nz auto it = m_currentState->builtinIds.find(builtinvar.entry); assert(it != m_currentState->builtinIds.end()); - m_currentState->instructions.Append(Opcode{ SpvOpStore }, it->second.varId, result); + m_currentState->instructions.Append(SpirvOp::OpStore, it->second.varId, result); PushResultId(result); break; } @@ -944,7 +935,7 @@ namespace Nz auto it = m_currentState->outputIds.find(outputVar.name); assert(it != m_currentState->outputIds.end()); - m_currentState->instructions.Append(Opcode{ SpvOpStore }, it->second.varId, result); + m_currentState->instructions.Append(SpirvOp::OpStore, it->second.varId, result); PushResultId(result); break; } @@ -992,7 +983,7 @@ namespace Nz bool swapOperands = false; - SpvOp op = [&] + SpirvOp op = [&] { switch (node.op) { @@ -1005,13 +996,13 @@ namespace Nz case ShaderNodes::BasicType::Float3: case ShaderNodes::BasicType::Float4: case ShaderNodes::BasicType::Mat4x4: - return SpvOpFAdd; + return SpirvOp::OpFAdd; case ShaderNodes::BasicType::Int1: case ShaderNodes::BasicType::Int2: case ShaderNodes::BasicType::Int3: case ShaderNodes::BasicType::Int4: - return SpvOpIAdd; + return SpirvOp::OpIAdd; case ShaderNodes::BasicType::Boolean: case ShaderNodes::BasicType::Sampler2D: @@ -1029,13 +1020,13 @@ namespace Nz case ShaderNodes::BasicType::Float3: case ShaderNodes::BasicType::Float4: case ShaderNodes::BasicType::Mat4x4: - return SpvOpFSub; + return SpirvOp::OpFSub; case ShaderNodes::BasicType::Int1: case ShaderNodes::BasicType::Int2: case ShaderNodes::BasicType::Int3: case ShaderNodes::BasicType::Int4: - return SpvOpISub; + return SpirvOp::OpISub; case ShaderNodes::BasicType::Boolean: case ShaderNodes::BasicType::Sampler2D: @@ -1053,13 +1044,13 @@ namespace Nz case ShaderNodes::BasicType::Float3: case ShaderNodes::BasicType::Float4: case ShaderNodes::BasicType::Mat4x4: - return SpvOpFDiv; + return SpirvOp::OpFDiv; case ShaderNodes::BasicType::Int1: case ShaderNodes::BasicType::Int2: case ShaderNodes::BasicType::Int3: case ShaderNodes::BasicType::Int4: - return SpvOpSDiv; + return SpirvOp::OpSDiv; case ShaderNodes::BasicType::Boolean: case ShaderNodes::BasicType::Sampler2D: @@ -1073,20 +1064,20 @@ namespace Nz switch (leftType) { case ShaderNodes::BasicType::Boolean: - return SpvOpLogicalEqual; + return SpirvOp::OpLogicalEqual; case ShaderNodes::BasicType::Float1: case ShaderNodes::BasicType::Float2: case ShaderNodes::BasicType::Float3: case ShaderNodes::BasicType::Float4: case ShaderNodes::BasicType::Mat4x4: - return SpvOpFOrdEqual; + return SpirvOp::OpFOrdEqual; case ShaderNodes::BasicType::Int1: case ShaderNodes::BasicType::Int2: case ShaderNodes::BasicType::Int3: case ShaderNodes::BasicType::Int4: - return SpvOpIEqual; + return SpirvOp::OpIEqual; case ShaderNodes::BasicType::Sampler2D: case ShaderNodes::BasicType::Void: @@ -1103,17 +1094,17 @@ namespace Nz switch (rightType) { case ShaderNodes::BasicType::Float1: - return SpvOpFMul; + return SpirvOp::OpFMul; case ShaderNodes::BasicType::Float2: case ShaderNodes::BasicType::Float3: case ShaderNodes::BasicType::Float4: swapOperands = true; - return SpvOpVectorTimesScalar; + return SpirvOp::OpVectorTimesScalar; case ShaderNodes::BasicType::Mat4x4: swapOperands = true; - return SpvOpMatrixTimesScalar; + return SpirvOp::OpMatrixTimesScalar; default: break; @@ -1129,15 +1120,15 @@ namespace Nz switch (rightType) { case ShaderNodes::BasicType::Float1: - return SpvOpVectorTimesScalar; + return SpirvOp::OpVectorTimesScalar; case ShaderNodes::BasicType::Float2: case ShaderNodes::BasicType::Float3: case ShaderNodes::BasicType::Float4: - return SpvOpFMul; + return SpirvOp::OpFMul; case ShaderNodes::BasicType::Mat4x4: - return SpvOpVectorTimesMatrix; + return SpirvOp::OpVectorTimesMatrix; default: break; @@ -1150,15 +1141,15 @@ namespace Nz case ShaderNodes::BasicType::Int2: case ShaderNodes::BasicType::Int3: case ShaderNodes::BasicType::Int4: - return SpvOpIMul; + return SpirvOp::OpIMul; case ShaderNodes::BasicType::Mat4x4: { switch (rightType) { - case ShaderNodes::BasicType::Float1: return SpvOpMatrixTimesScalar; - case ShaderNodes::BasicType::Float4: return SpvOpMatrixTimesVector; - case ShaderNodes::BasicType::Mat4x4: return SpvOpMatrixTimesMatrix; + case ShaderNodes::BasicType::Float1: return SpirvOp::OpMatrixTimesScalar; + case ShaderNodes::BasicType::Float4: return SpirvOp::OpMatrixTimesVector; + case ShaderNodes::BasicType::Mat4x4: return SpirvOp::OpMatrixTimesMatrix; default: break; @@ -1181,7 +1172,7 @@ namespace Nz if (swapOperands) std::swap(leftOperand, rightOperand); - m_currentState->instructions.Append(Opcode{ op }, GetTypeId(resultType), resultId, leftOperand, rightOperand); + m_currentState->instructions.Append(op, GetTypeId(resultType), resultId, leftOperand, rightOperand); PushResultId(resultId); } @@ -1204,12 +1195,14 @@ namespace Nz UInt32 resultId = AllocateResultId(); - m_currentState->instructions.Append(Opcode{ SpvOpCompositeConstruct }, WordCount { static_cast(3 + exprResults.size()) }); - m_currentState->instructions.Append(GetTypeId(targetType)); - m_currentState->instructions.Append(resultId); + m_currentState->instructions.AppendVariadic(SpirvOp::OpCompositeConstruct, [&](const auto& appender) + { + appender(GetTypeId(targetType)); + appender(resultId); - for (UInt32 resultId : exprResults) - m_currentState->instructions.Append(resultId); + for (UInt32 exprResultId : exprResults) + appender(exprResultId); + }); PushResultId(resultId); } @@ -1262,7 +1255,7 @@ namespace Nz UInt32 resultId = AllocateResultId(); - m_currentState->instructions.Append(Opcode{ SpvOpDot }, typeId, resultId, vec1, vec2); + m_currentState->instructions.Append(SpirvOp::OpDot, typeId, resultId, vec1, vec2); PushResultId(resultId); break; } @@ -1283,7 +1276,7 @@ namespace Nz UInt32 coordinatesId = EvaluateExpression(node.coordinates); UInt32 resultId = AllocateResultId(); - m_currentState->instructions.Append(Opcode{ SpvOpImageSampleImplicitLod }, typeId, resultId, samplerId, coordinatesId); + m_currentState->instructions.Append(SpirvOp::OpImageSampleImplicitLod, typeId, resultId, samplerId, coordinatesId); PushResultId(resultId); } @@ -1305,22 +1298,24 @@ namespace Nz if (node.componentCount > 1) { - // Swizzling is implemented via SpvOpVectorShuffle using the same vector twice as operands - m_currentState->instructions.Append(Opcode{ SpvOpVectorShuffle }, WordCount{ static_cast(5 + node.componentCount) }); - m_currentState->instructions.Append(GetTypeId(targetType)); - m_currentState->instructions.Append(resultId); - m_currentState->instructions.Append(exprResultId); - m_currentState->instructions.Append(exprResultId); + // 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) - m_currentState->instructions.Append(UInt32(node.components[0]) - UInt32(node.components[i])); + 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(Opcode{ SpvOpCompositeExtract }, GetTypeId(targetType), resultId, exprResultId, UInt32(node.components[0]) - UInt32(ShaderNodes::SwizzleComponent::First) ); + m_currentState->instructions.Append(SpirvOp::OpCompositeExtract, GetTypeId(targetType), resultId, exprResultId, UInt32(node.components[0]) - UInt32(ShaderNodes::SwizzleComponent::First) ); } PushResultId(resultId); @@ -1368,48 +1363,12 @@ namespace Nz PushResultId(ReadVariable(it.value())); } - void SpirvWriter::MergeBlocks(std::vector& output, const Section& from) + void SpirvWriter::MergeBlocks(std::vector& output, const SpirvSection& from) { + const std::vector& bytecode = from.GetBytecode(); + std::size_t prevSize = output.size(); - output.resize(prevSize + from.data.size()); - std::copy(from.data.begin(), from.data.end(), output.begin() + prevSize); - } - - std::size_t SpirvWriter::Section::Append(const Opcode& opcode, const WordCount& wordCount) - { - return Append(UInt32(opcode.op) | UInt32(wordCount.wc) << 16); - } - - std::size_t SpirvWriter::Section::Append(const Raw& raw) - { - std::size_t offset = GetOutputOffset(); - - const UInt8* ptr = static_cast(raw.ptr); - - std::size_t size4 = CountWord(raw); - for (std::size_t i = 0; i < size4; ++i) - { - UInt32 codepoint = 0; - for (std::size_t j = 0; j < 4; ++j) - { -#ifdef NAZARA_BIG_ENDIAN - std::size_t pos = i * 4 + (3 - j); -#else - std::size_t pos = i * 4 + j; -#endif - - if (pos < raw.size) - codepoint |= UInt32(ptr[pos]) << (j * 8); - } - - Append(codepoint); - } - - return offset; - } - - unsigned int SpirvWriter::Section::CountWord(const Raw& raw) - { - return (raw.size + sizeof(UInt32) - 1) / sizeof(UInt32); + output.resize(prevSize + bytecode.size()); + std::copy(bytecode.begin(), bytecode.end(), output.begin() + prevSize); } } From 9df219e4027ff8a39c5bdd7f9603342318bf8683 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Thu, 20 Aug 2020 01:05:16 +0200 Subject: [PATCH 095/105] Add SpirvConstantCache And unsigned int types for shaders --- examples/bin/frag.shader | Bin 610 -> 610 bytes examples/bin/test.spirv | Bin 824 -> 1360 bytes include/Nazara/Shader/ShaderConstantValue.hpp | 32 + include/Nazara/Shader/ShaderEnums.hpp | 7 +- include/Nazara/Shader/ShaderNodes.hpp | 15 +- include/Nazara/Shader/SpirvConstantCache.hpp | 194 ++++ include/Nazara/Shader/SpirvConstantCache.inl | 12 + include/Nazara/Shader/SpirvSection.inl | 2 +- include/Nazara/Shader/SpirvWriter.hpp | 13 +- src/Nazara/Shader/GlslWriter.cpp | 6 +- src/Nazara/Shader/ShaderAstSerializer.cpp | 15 +- src/Nazara/Shader/ShaderNodes.cpp | 6 + src/Nazara/Shader/SpirvConstantCache.cpp | 897 ++++++++++++++++++ src/Nazara/Shader/SpirvWriter.cpp | 563 ++++------- 14 files changed, 1341 insertions(+), 421 deletions(-) create mode 100644 include/Nazara/Shader/ShaderConstantValue.hpp create mode 100644 include/Nazara/Shader/SpirvConstantCache.hpp create mode 100644 include/Nazara/Shader/SpirvConstantCache.inl create mode 100644 src/Nazara/Shader/SpirvConstantCache.cpp diff --git a/examples/bin/frag.shader b/examples/bin/frag.shader index cd71692bdb4ea28ccc2c395eea9cff48ef20d9e3..7ecc8951b3ed24eb9ba64553eefeae6fb464b1d8 100644 GIT binary patch delta 12 UcmaFF@`z=^7Dm>MTh}rI03(qFD*ylh delta 12 UcmaFF@`z=^7DkqhTh}rI03(bADgXcg diff --git a/examples/bin/test.spirv b/examples/bin/test.spirv index 3d47fe4e8ca7278bebda6c288f6ac90306dd15e6..b8858477532b82cee40f28bcdb11a8b7aa1776b0 100644 GIT binary patch literal 1360 zcmZ9LNpBND5QRH-#)K^)ge+{qj@ffZNQg}w$O+|uxFU!6Fv#(siA{3MUw~iB1&QzL zOrcR)DtEtE^{T3C+TG6ZQc4TSwVQuaT1}nIET?W}^sc0<`Fxk(qft2(+``te4QvzJ z!fslQ4%K{i z9+5V4<_`Y(L6tsI&sm&LC}nK@ZOo^Ir%SKk`D^~@pevm2{^7rfA5w*T08W5RE3*P literal 824 zcmYk4y-xx`5XDE}5Wf&aK}6-yQVI)WOpH?6S@>CB;>BD7r@2sA+Spq8|L{*)*pT>s zce@Eo9=mVe?97{ma_M;4Y{^)I{M)Q)r94u%avnk5w3=14H-t%)qzEg*ny?`>l#8Zf z7U+YPq_=O`BpU0eNF~or(#NNQSMz&!arzQx4^j3SPfzo_K)uYS@yC5Mc^}7Fad)xr zjcQT+3pm7a!*?h51(X9wp} z@WSuR!rPx*b+uo~AN}?O-seZT`0cqEKFDFteSsO_yxW1mn?36ez4=d&L;Tyt`Yukr VFBc1S#wXgfy7R7~Fqg{<;U7&^Dfa*X diff --git a/include/Nazara/Shader/ShaderConstantValue.hpp b/include/Nazara/Shader/ShaderConstantValue.hpp new file mode 100644 index 000000000..27c9e1d7e --- /dev/null +++ b/include/Nazara/Shader/ShaderConstantValue.hpp @@ -0,0 +1,32 @@ +// 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_SHADER_CONSTANTVALUE_HPP +#define NAZARA_SHADER_CONSTANTVALUE_HPP + +#include +#include +#include +#include +#include + +namespace Nz +{ + using ShaderConstantValue = std::variant< + bool, + float, + Int32, + UInt32, + Vector2f, + Vector3f, + Vector4f, + Vector2i32, + Vector3i32, + Vector4i32 + >; +} + +#endif diff --git a/include/Nazara/Shader/ShaderEnums.hpp b/include/Nazara/Shader/ShaderEnums.hpp index 2ddbb5b97..ed322e3e6 100644 --- a/include/Nazara/Shader/ShaderEnums.hpp +++ b/include/Nazara/Shader/ShaderEnums.hpp @@ -29,8 +29,11 @@ namespace Nz::ShaderNodes Int4, //< ivec4 Mat4x4, //< mat4 Sampler2D, //< sampler2D - - Void //< void + Void, //< void + UInt1, //< uint + UInt2, //< uvec2 + UInt3, //< uvec3 + UInt4 //< uvec4 }; enum class BinaryType diff --git a/include/Nazara/Shader/ShaderNodes.hpp b/include/Nazara/Shader/ShaderNodes.hpp index 833af1248..af96afeda 100644 --- a/include/Nazara/Shader/ShaderNodes.hpp +++ b/include/Nazara/Shader/ShaderNodes.hpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -222,19 +223,7 @@ namespace Nz ShaderExpressionType GetExpressionType() const override; void Visit(ShaderAstVisitor& visitor) override; - using Variant = std::variant< - bool, - float, - Int32, - Vector2f, - Vector3f, - Vector4f, - Vector2i32, - Vector3i32, - Vector4i32 - >; - - Variant value; + ShaderConstantValue value; template static std::shared_ptr Build(const T& value); }; diff --git a/include/Nazara/Shader/SpirvConstantCache.hpp b/include/Nazara/Shader/SpirvConstantCache.hpp new file mode 100644 index 000000000..95172c757 --- /dev/null +++ b/include/Nazara/Shader/SpirvConstantCache.hpp @@ -0,0 +1,194 @@ +// 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_SPIRVCONSTANTCACHE_HPP +#define NAZARA_SPIRVCONSTANTCACHE_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + class ShaderAst; + class SpirvSection; + + class NAZARA_SHADER_API SpirvConstantCache + { + public: + SpirvConstantCache(UInt32& resultId); + SpirvConstantCache(const SpirvConstantCache& cache) = delete; + SpirvConstantCache(SpirvConstantCache&& cache) noexcept; + ~SpirvConstantCache(); + + struct Constant; + struct Type; + + using ConstantPtr = std::shared_ptr; + using TypePtr = std::shared_ptr; + + struct Bool {}; + + struct Float + { + UInt32 width; + }; + + struct Integer + { + UInt32 width; + bool signedness; + }; + + struct Void {}; + + struct Vector + { + TypePtr componentType; + UInt32 componentCount; + }; + + struct Matrix + { + TypePtr columnType; + UInt32 columnCount; + }; + + struct Image + { + std::optional qualifier; + std::optional depth; + std::optional sampled; + SpirvDim dim; + SpirvImageFormat format; + TypePtr sampledType; + bool arrayed; + bool multisampled; + }; + + struct Pointer + { + TypePtr type; + SpirvStorageClass storageClass; + }; + + struct Function + { + TypePtr returnType; + std::vector parameters; + }; + + struct SampledImage + { + TypePtr image; + }; + + struct Structure + { + struct Member + { + std::string name; + TypePtr type; + }; + + std::string name; + std::vector members; + }; + + using AnyType = std::variant; + + struct ConstantBool + { + bool value; + }; + + struct ConstantComposite + { + TypePtr type; + std::vector values; + }; + + struct ConstantScalar + { + std::variant value; + }; + + using AnyConstant = std::variant; + + struct Variable + { + std::string debugName; + TypePtr type; + SpirvStorageClass storageClass; + std::optional initializer; + }; + + using BaseType = std::variant; + using CompositeValue = std::variant; + using PointerOrBaseType = std::variant; + using PrimitiveType = std::variant; + using ScalarType = std::variant; + + struct Constant + { + Constant(AnyConstant c) : + constant(std::move(c)) + { + } + + AnyConstant constant; + }; + + struct Type + { + Type(AnyType c) : + type(std::move(c)) + { + } + + AnyType type; + }; + + UInt32 GetId(const Constant& c); + UInt32 GetId(const Type& t); + UInt32 GetId(const Variable& v); + + UInt32 Register(Constant c); + UInt32 Register(Type t); + UInt32 Register(Variable v); + + void Write(SpirvSection& annotations, SpirvSection& constants, SpirvSection& debugInfos, SpirvSection& types); + + SpirvConstantCache& operator=(const SpirvConstantCache& cache) = delete; + SpirvConstantCache& operator=(SpirvConstantCache&& cache) noexcept; + + static ConstantPtr BuildConstant(const ShaderConstantValue& value); + static TypePtr BuildPointerType(const ShaderNodes::BasicType& type, SpirvStorageClass storageClass); + static TypePtr BuildPointerType(const ShaderAst& shader, const ShaderExpressionType& type, SpirvStorageClass storageClass); + static TypePtr BuildType(const ShaderNodes::BasicType& type); + static TypePtr BuildType(const ShaderAst& shader, const ShaderExpressionType& type); + + private: + struct DepRegisterer; + struct Eq; + struct Internal; + + void WriteStruct(const Structure& structData, UInt32 resultId, SpirvSection& annotations, SpirvSection& debugInfos, SpirvSection& types); + + std::unique_ptr m_internal; + }; +} + +#include + +#endif diff --git a/include/Nazara/Shader/SpirvConstantCache.inl b/include/Nazara/Shader/SpirvConstantCache.inl new file mode 100644 index 000000000..b007dbb7f --- /dev/null +++ b/include/Nazara/Shader/SpirvConstantCache.inl @@ -0,0 +1,12 @@ +// 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 +{ +} + +#include diff --git a/include/Nazara/Shader/SpirvSection.inl b/include/Nazara/Shader/SpirvSection.inl index f4770e3f3..e86eb59ff 100644 --- a/include/Nazara/Shader/SpirvSection.inl +++ b/include/Nazara/Shader/SpirvSection.inl @@ -96,7 +96,7 @@ namespace Nz } template - unsigned int SpirvSection::CountWord(const T& value) + unsigned int SpirvSection::CountWord(const T& /*value*/) { return 1; } diff --git a/include/Nazara/Shader/SpirvWriter.hpp b/include/Nazara/Shader/SpirvWriter.hpp index 71a617eaa..579ad1fef 100644 --- a/include/Nazara/Shader/SpirvWriter.hpp +++ b/include/Nazara/Shader/SpirvWriter.hpp @@ -11,9 +11,10 @@ #include #include #include +#include #include #include -#include +#include #include #include #include @@ -47,20 +48,22 @@ namespace Nz UInt32 AllocateResultId(); - void AppendConstants(); void AppendHeader(); - void AppendStructType(std::size_t structIndex, UInt32 resultId); - void AppendTypes(); UInt32 EvaluateExpression(const ShaderNodes::ExpressionPtr& expr); - UInt32 GetConstantId(const ShaderNodes::Constant::Variant& value) const; + UInt32 GetConstantId(const ShaderConstantValue& value) const; + UInt32 GetFunctionTypeId(ShaderExpressionType retType, const std::vector& parameters); + UInt32 GetPointerTypeId(const ShaderExpressionType& type, SpirvStorageClass storageClass) const; UInt32 GetTypeId(const ShaderExpressionType& type) const; void PushResultId(UInt32 value); UInt32 PopResultId(); UInt32 ReadVariable(ExtVar& var); + UInt32 RegisterConstant(const ShaderConstantValue& value); + UInt32 RegisterFunctionType(ShaderExpressionType retType, const std::vector& parameters); + UInt32 RegisterPointerType(ShaderExpressionType type, SpirvStorageClass storageClass); UInt32 RegisterType(ShaderExpressionType type); using ShaderAstVisitor::Visit; diff --git a/src/Nazara/Shader/GlslWriter.cpp b/src/Nazara/Shader/GlslWriter.cpp index b17c8d4a3..1e911ce13 100644 --- a/src/Nazara/Shader/GlslWriter.cpp +++ b/src/Nazara/Shader/GlslWriter.cpp @@ -231,6 +231,10 @@ namespace Nz case ShaderNodes::BasicType::Int4: return Append("ivec4"); case ShaderNodes::BasicType::Mat4x4: return Append("mat4"); case ShaderNodes::BasicType::Sampler2D: return Append("sampler2D"); + case ShaderNodes::BasicType::UInt1: return Append("uint"); + case ShaderNodes::BasicType::UInt2: return Append("uvec2"); + case ShaderNodes::BasicType::UInt3: return Append("uvec3"); + case ShaderNodes::BasicType::UInt4: return Append("uvec4"); case ShaderNodes::BasicType::Void: return Append("void"); } } @@ -459,7 +463,7 @@ namespace Nz if constexpr (std::is_same_v) Append((arg) ? "true" : "false"); - else if constexpr (std::is_same_v || std::is_same_v) + else if constexpr (std::is_same_v || std::is_same_v || std::is_same_v) Append(std::to_string(arg)); else if constexpr (std::is_same_v || std::is_same_v) Append("vec2(" + std::to_string(arg.x) + ", " + std::to_string(arg.y) + ")"); diff --git a/src/Nazara/Shader/ShaderAstSerializer.cpp b/src/Nazara/Shader/ShaderAstSerializer.cpp index 6d45cc711..396cd3d98 100644 --- a/src/Nazara/Shader/ShaderAstSerializer.cpp +++ b/src/Nazara/Shader/ShaderAstSerializer.cpp @@ -193,18 +193,19 @@ namespace Nz Value(value); }; - static_assert(std::variant_size_v == 9); + static_assert(std::variant_size_v == 10); switch (typeIndex) { case 0: SerializeValue(bool()); break; case 1: SerializeValue(float()); break; case 2: SerializeValue(Int32()); break; - case 3: SerializeValue(Vector2f()); break; - case 4: SerializeValue(Vector3f()); break; - case 5: SerializeValue(Vector4f()); break; - case 6: SerializeValue(Vector2i32()); break; - case 7: SerializeValue(Vector3i32()); break; - case 8: SerializeValue(Vector4i32()); break; + case 3: SerializeValue(UInt32()); break; + case 4: SerializeValue(Vector2f()); break; + case 5: SerializeValue(Vector3f()); break; + case 6: SerializeValue(Vector4f()); break; + case 7: SerializeValue(Vector2i32()); break; + case 8: SerializeValue(Vector3i32()); break; + case 9: SerializeValue(Vector4i32()); break; default: throw std::runtime_error("unexpected data type"); } } diff --git a/src/Nazara/Shader/ShaderNodes.cpp b/src/Nazara/Shader/ShaderNodes.cpp index 2f72a1ea0..15c7e40f0 100644 --- a/src/Nazara/Shader/ShaderNodes.cpp +++ b/src/Nazara/Shader/ShaderNodes.cpp @@ -114,12 +114,16 @@ namespace Nz::ShaderNodes case BasicType::Int2: case BasicType::Int3: case BasicType::Int4: + case BasicType::UInt2: + case BasicType::UInt3: + case BasicType::UInt4: exprType = leftExprType; break; case BasicType::Float1: case BasicType::Int1: case BasicType::Mat4x4: + case BasicType::UInt1: exprType = rightExprType; break; @@ -165,6 +169,8 @@ namespace Nz::ShaderNodes return ShaderNodes::BasicType::Float1; else if constexpr (std::is_same_v) return ShaderNodes::BasicType::Int1; + else if constexpr (std::is_same_v) + return ShaderNodes::BasicType::Int1; else if constexpr (std::is_same_v) return ShaderNodes::BasicType::Float2; else if constexpr (std::is_same_v) diff --git a/src/Nazara/Shader/SpirvConstantCache.cpp b/src/Nazara/Shader/SpirvConstantCache.cpp new file mode 100644 index 000000000..02f7b4f34 --- /dev/null +++ b/src/Nazara/Shader/SpirvConstantCache.cpp @@ -0,0 +1,897 @@ +// 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 +{ + struct SpirvConstantCache::Eq + { + bool Compare(const ConstantBool& lhs, const ConstantBool& rhs) const + { + return lhs.value == rhs.value; + } + + bool Compare(const ConstantComposite& lhs, const ConstantComposite& rhs) const + { + return Compare(lhs.type, rhs.type) && Compare(lhs.values, rhs.values); + } + + bool Compare(const ConstantScalar& lhs, const ConstantScalar& rhs) const + { + return lhs.value == rhs.value; + } + + bool Compare(const Bool& /*lhs*/, const Bool& /*rhs*/) const + { + return true; + } + + bool Compare(const Float& lhs, const Float& rhs) const + { + return lhs.width == rhs.width; + } + + bool Compare(const Function& lhs, const Function& rhs) const + { + return Compare(lhs.parameters, rhs.parameters) && Compare(lhs.returnType, rhs.returnType); + } + + bool Compare(const Image& lhs, const Image& rhs) const + { + return lhs.arrayed == rhs.arrayed + && lhs.dim == rhs.dim + && lhs.format == rhs.format + && lhs.multisampled == rhs.multisampled + && lhs.qualifier == rhs.qualifier + && Compare(lhs.sampledType, rhs.sampledType) + && lhs.depth == rhs.depth + && lhs.sampled == rhs.sampled; + } + + bool Compare(const Integer& lhs, const Integer& rhs) const + { + return lhs.width == rhs.width && lhs.signedness == rhs.signedness; + } + + bool Compare(const Matrix& lhs, const Matrix& rhs) const + { + return lhs.columnCount == rhs.columnCount && Compare(lhs.columnType, rhs.columnType); + } + + bool Compare(const Pointer& lhs, const Pointer& rhs) const + { + return lhs.storageClass == rhs.storageClass && Compare(lhs.type, rhs.type); + } + + bool Compare(const SampledImage& lhs, const SampledImage& rhs) const + { + return Compare(lhs.image, rhs.image); + } + + bool Compare(const Structure& lhs, const Structure& rhs) const + { + if (lhs.name != rhs.name) + return false; + + if (!Compare(lhs.members, rhs.members)) + return false; + + return true; + } + + bool Compare(const Structure::Member& lhs, const Structure::Member& rhs) const + { + if (!Compare(lhs.type, rhs.type)) + return false; + + if (lhs.name != rhs.name) + return false; + + return true; + } + + bool Compare(const Variable& lhs, const Variable& rhs) const + { + if (lhs.debugName != rhs.debugName) + return false; + + if (!Compare(lhs.initializer, rhs.initializer)) + return false; + + if (lhs.storageClass != rhs.storageClass) + return false; + + if (!Compare(lhs.type, rhs.type)) + return false; + + return true; + } + + bool Compare(const Vector& lhs, const Vector& rhs) const + { + return Compare(lhs.componentType, rhs.componentType) && lhs.componentCount == rhs.componentCount; + } + + bool Compare(const Void& /*lhs*/, const Void& /*rhs*/) const + { + return true; + } + + + bool Compare(const Constant& lhs, const Constant& rhs) const + { + return Compare(lhs.constant, rhs.constant); + } + + bool Compare(const Type& lhs, const Type& rhs) const + { + return Compare(lhs.type, rhs.type); + } + + + template + bool Compare(const std::optional& lhs, const std::optional& rhs) const + { + if (lhs.has_value() != rhs.has_value()) + return false; + + if (!lhs.has_value()) + return true; + + return Compare(*lhs, *rhs); + } + + template + bool Compare(const std::shared_ptr& lhs, const std::shared_ptr& rhs) const + { + if (bool(lhs) != bool(rhs)) + return false; + + if (!lhs) + return true; + + return Compare(*lhs, *rhs); + } + + template + bool Compare(const std::variant& lhs, const std::variant& rhs) const + { + if (lhs.index() != rhs.index()) + return false; + + return std::visit([&](auto&& arg) + { + using U = std::decay_t; + return Compare(arg, std::get(rhs)); + }, lhs); + } + + template + bool Compare(const std::vector& lhs, const std::vector& rhs) const + { + if (lhs.size() != rhs.size()) + return false; + + for (std::size_t i = 0; i < lhs.size(); ++i) + { + if (!Compare(lhs[i], rhs[i])) + return false; + } + + return true; + } + + template + bool Compare(const std::unique_ptr& lhs, const std::unique_ptr& rhs) const + { + if (bool(lhs) != bool(rhs)) + return false; + + if (!lhs) + return true; + + return Compare(*lhs, *rhs); + } + + template + bool operator()(const T& lhs, const T& rhs) const + { + return Compare(lhs, rhs); + } + }; + + struct SpirvConstantCache::DepRegisterer + { + DepRegisterer(SpirvConstantCache& c) : + cache(c) + { + } + + void Register(const Bool&) {} + void Register(const Float&) {} + void Register(const Integer&) {} + void Register(const Void&) {} + + void Register(const Image& image) + { + Register(image.sampledType); + } + + void Register(const Function& func) + { + Register(func.returnType); + Register(func.parameters); + } + + void Register(const Matrix& vec) + { + assert(vec.columnType); + cache.Register(*vec.columnType); + } + + void Register(const Pointer& ptr) + { + assert(ptr.type); + cache.Register(*ptr.type); + } + + void Register(const SampledImage& sampledImage) + { + assert(sampledImage.image); + cache.Register(*sampledImage.image); + } + + void Register(const Structure& s) + { + Register(s.members); + } + + void Register(const SpirvConstantCache::Structure::Member& m) + { + cache.Register(*m.type); + } + + void Register(const Variable& variable) + { + assert(variable.type); + cache.Register(*variable.type); + } + + void Register(const Vector& vec) + { + assert(vec.componentType); + cache.Register(*vec.componentType); + } + + void Register(const ConstantBool&) + { + cache.Register({ Bool{} }); + } + + void Register(const ConstantScalar& scalar) + { + std::visit([&](auto&& arg) + { + using T = std::decay_t; + + if constexpr (std::is_same_v) + cache.Register({ Float{ 64 } }); + else if constexpr (std::is_same_v) + cache.Register({ Float{ 32 } }); + else if constexpr (std::is_same_v) + cache.Register({ Integer{ 32, 1 } }); + else if constexpr (std::is_same_v) + cache.Register({ Integer{ 64, 1 } }); + else if constexpr (std::is_same_v) + cache.Register({ Integer{ 32, 0 } }); + else if constexpr (std::is_same_v) + cache.Register({ Integer{ 64, 0 } }); + else + static_assert(AlwaysFalse::value, "non-exhaustive visitor"); + + }, scalar.value); + } + + void Register(const ConstantComposite& composite) + { + assert(composite.type); + cache.Register(*composite.type); + + for (auto&& value : composite.values) + { + assert(value); + cache.Register(*value); + } + } + + + void Register(const Constant& c) + { + return Register(c.constant); + } + + void Register(const Type& t) + { + return Register(t.type); + } + + + template + void Register(const std::shared_ptr& ptr) + { + assert(ptr); + return Register(*ptr); + } + + template + void Register(const std::optional& opt) + { + if (opt) + Register(*opt); + } + + template + void Register(const std::variant& v) + { + return std::visit([&](auto&& arg) + { + return Register(arg); + }, v); + } + + template + void Register(const std::vector& lhs) + { + for (std::size_t i = 0; i < lhs.size(); ++i) + Register(lhs[i]); + } + + template + void Register(const std::unique_ptr& lhs) + { + assert(lhs); + return Register(*lhs); + } + + SpirvConstantCache& cache; + }; + + //< FIXME PLZ + struct AnyHasher + { + template + std::size_t operator()(const U&) const + { + return 42; + } + }; + + struct SpirvConstantCache::Internal + { + Internal(UInt32& resultId) : + nextResultId(resultId) + { + } + + tsl::ordered_map constantIds; + tsl::ordered_map typeIds; + tsl::ordered_map variableIds; + tsl::ordered_map structureSizes; + UInt32& nextResultId; + }; + + SpirvConstantCache::SpirvConstantCache(UInt32& resultId) + { + m_internal = std::make_unique(resultId); + } + + SpirvConstantCache::SpirvConstantCache(SpirvConstantCache&& cache) noexcept = default; + + SpirvConstantCache::~SpirvConstantCache() = default; + + UInt32 SpirvConstantCache::GetId(const Constant& c) + { + auto it = m_internal->constantIds.find(c.constant); + if (it == m_internal->constantIds.end()) + throw std::runtime_error("constant is not registered"); + + return it->second; + } + + UInt32 SpirvConstantCache::GetId(const Type& t) + { + auto it = m_internal->typeIds.find(t.type); + if (it == m_internal->typeIds.end()) + throw std::runtime_error("constant is not registered"); + + return it->second; + } + + UInt32 SpirvConstantCache::GetId(const Variable& v) + { + auto it = m_internal->variableIds.find(v); + if (it == m_internal->variableIds.end()) + throw std::runtime_error("variable is not registered"); + + return it->second; + } + + UInt32 SpirvConstantCache::Register(Constant c) + { + AnyConstant& constant = c.constant; + + DepRegisterer registerer(*this); + registerer.Register(constant); + + std::size_t h = m_internal->typeIds.hash_function()(constant); + auto it = m_internal->constantIds.find(constant, h); + if (it == m_internal->constantIds.end()) + { + UInt32 resultId = m_internal->nextResultId++; + it = m_internal->constantIds.emplace(std::move(constant), resultId).first; + } + + return it.value(); + } + + UInt32 SpirvConstantCache::Register(Type t) + { + AnyType& type = t.type; + + DepRegisterer registerer(*this); + registerer.Register(type); + + std::size_t h = m_internal->typeIds.hash_function()(type); + auto it = m_internal->typeIds.find(type, h); + if (it == m_internal->typeIds.end()) + { + UInt32 resultId = m_internal->nextResultId++; + it = m_internal->typeIds.emplace(std::move(type), resultId).first; + } + + return it.value(); + } + + UInt32 SpirvConstantCache::Register(Variable v) + { + DepRegisterer registerer(*this); + registerer.Register(v); + + std::size_t h = m_internal->variableIds.hash_function()(v); + auto it = m_internal->variableIds.find(v, h); + if (it == m_internal->variableIds.end()) + { + UInt32 resultId = m_internal->nextResultId++; + it = m_internal->variableIds.emplace(std::move(v), resultId).first; + } + + return it.value(); + } + + void SpirvConstantCache::Write(SpirvSection& annotations, SpirvSection& constants, SpirvSection& debugInfos, SpirvSection& types) + { + for (auto&& [type, id] : m_internal->typeIds) + { + UInt32 resultId = id; + + std::visit([&](auto&& arg) + { + using T = std::decay_t; + + if constexpr (std::is_same_v) + types.Append(SpirvOp::OpTypeBool, resultId); + else if constexpr (std::is_same_v) + types.Append(SpirvOp::OpTypeFloat, resultId, arg.width); + else if constexpr (std::is_same_v) + { + types.AppendVariadic(SpirvOp::OpTypeFunction, [&](const auto& appender) + { + appender(resultId); + appender(GetId(*arg.returnType)); + + for (const auto& param : arg.parameters) + appender(GetId(*param)); + }); + } + else if constexpr (std::is_same_v) + { + UInt32 depth; + if (arg.depth.has_value()) + depth = (*arg.depth) ? 1 : 0; + else + depth = 2; + + UInt32 sampled; + if (arg.sampled.has_value()) + sampled = (*arg.sampled) ? 1 : 0; + else + sampled = 2; + + types.AppendVariadic(SpirvOp::OpTypeImage, [&](const auto& appender) + { + appender(resultId); + appender(GetId(*arg.sampledType)); + appender(arg.dim); + appender(depth); + appender(arg.arrayed); + appender(arg.multisampled); + appender(sampled); + appender(arg.format); + + if (arg.qualifier) + appender(*arg.qualifier); + }); + } + else if constexpr (std::is_same_v) + types.Append(SpirvOp::OpTypeInt, resultId, arg.width, arg.signedness); + else if constexpr (std::is_same_v) + types.Append(SpirvOp::OpTypeMatrix, resultId, GetId(*arg.columnType), arg.columnCount); + else if constexpr (std::is_same_v) + types.Append(SpirvOp::OpTypePointer, resultId, arg.storageClass, GetId(*arg.type)); + else if constexpr (std::is_same_v) + types.Append(SpirvOp::OpTypeSampledImage, resultId, GetId(*arg.image)); + else if constexpr (std::is_same_v) + WriteStruct(arg, resultId, annotations, debugInfos, types); + else if constexpr (std::is_same_v) + types.Append(SpirvOp::OpTypeVector, resultId, GetId(*arg.componentType), arg.componentCount); + else if constexpr (std::is_same_v) + types.Append(SpirvOp::OpTypeVoid, resultId); + else + static_assert(AlwaysFalse::value, "non-exhaustive visitor"); + }, type); + } + + for (auto&& [constant, id] : m_internal->constantIds) + { + UInt32 resultId = id; + + std::visit([&](auto&& arg) + { + using T = std::decay_t; + + if constexpr (std::is_same_v) + constants.Append((arg.value) ? SpirvOp::OpConstantTrue : SpirvOp::OpConstantFalse, resultId); + else if constexpr (std::is_same_v) + { + constants.AppendVariadic(SpirvOp::OpConstantComposite, [&](const auto& appender) + { + appender(GetId(arg.type->type)); + appender(resultId); + + for (const auto& value : arg.values) + appender(GetId(value->constant)); + }); + } + else if constexpr (std::is_same_v) + { + std::visit([&](auto&& arg) + { + using T = std::decay_t; + + UInt32 typeId; + if constexpr (std::is_same_v) + typeId = GetId({ Float{ 64 } }); + else if constexpr (std::is_same_v) + typeId = GetId({ Float{ 32 } }); + else if constexpr (std::is_same_v) + typeId = GetId({ Integer{ 32, 1 } }); + else if constexpr (std::is_same_v) + typeId = GetId({ Integer{ 64, 1 } }); + else if constexpr (std::is_same_v) + typeId = GetId({ Integer{ 32, 0 } }); + else if constexpr (std::is_same_v) + typeId = GetId({ Integer{ 64, 0 } }); + else + static_assert(AlwaysFalse::value, "non-exhaustive visitor"); + + constants.Append(SpirvOp::OpConstant, typeId, resultId, SpirvSection::Raw{ &arg, sizeof(arg) }); + + }, arg.value); + } + else + static_assert(AlwaysFalse::value, "non-exhaustive visitor"); + }, constant); + } + + for (auto&& [variable, id] : m_internal->variableIds) + { + UInt32 resultId = id; + + if (!variable.debugName.empty()) + debugInfos.Append(SpirvOp::OpName, resultId, variable.debugName); + + constants.AppendVariadic(SpirvOp::OpVariable, [&](const auto& appender) + { + appender(GetId(*variable.type)); + appender(resultId); + appender(variable.storageClass); + + if (variable.initializer) + appender(GetId((*variable.initializer)->constant)); + }); + } + } + + SpirvConstantCache& SpirvConstantCache::operator=(SpirvConstantCache&& cache) noexcept = default; + + auto SpirvConstantCache::BuildConstant(const ShaderConstantValue& value) -> ConstantPtr + { + return std::make_shared(std::visit([&](auto&& arg) -> SpirvConstantCache::AnyConstant + { + using T = std::decay_t; + + if constexpr (std::is_same_v) + return ConstantBool{ arg }; + else if constexpr (std::is_same_v || std::is_same_v || std::is_same_v) + return ConstantScalar{ arg }; + else if constexpr (std::is_same_v || std::is_same_v) + { + return ConstantComposite{ + BuildType((std::is_same_v) ? ShaderNodes::BasicType::Float2 : ShaderNodes::BasicType::Int2), + { + BuildConstant(arg.x), + BuildConstant(arg.y) + } + }; + } + else if constexpr (std::is_same_v || std::is_same_v) + { + return ConstantComposite{ + BuildType((std::is_same_v) ? ShaderNodes::BasicType::Float3 : ShaderNodes::BasicType::Int3), + { + BuildConstant(arg.x), + BuildConstant(arg.y), + BuildConstant(arg.z) + } + }; + } + else if constexpr (std::is_same_v || std::is_same_v) + { + return ConstantComposite{ + BuildType((std::is_same_v) ? ShaderNodes::BasicType::Float4 : ShaderNodes::BasicType::Int4), + { + BuildConstant(arg.x), + BuildConstant(arg.y), + BuildConstant(arg.z), + BuildConstant(arg.w) + } + }; + } + else + static_assert(AlwaysFalse::value, "non-exhaustive visitor"); + }, value)); + } + + auto SpirvConstantCache::BuildPointerType(const ShaderNodes::BasicType& type, SpirvStorageClass storageClass) -> TypePtr + { + return std::make_shared(SpirvConstantCache::Pointer{ + SpirvConstantCache::BuildType(type), + storageClass + }); + } + + auto SpirvConstantCache::BuildPointerType(const ShaderAst& shader, const ShaderExpressionType& type, SpirvStorageClass storageClass) -> TypePtr + { + return std::make_shared(SpirvConstantCache::Pointer{ + SpirvConstantCache::BuildType(shader, type), + storageClass + }); + } + + auto SpirvConstantCache::BuildType(const ShaderNodes::BasicType& type) -> TypePtr + { + return std::make_shared([&]() -> AnyType + { + switch (type) + { + case ShaderNodes::BasicType::Boolean: + return Bool{}; + + case ShaderNodes::BasicType::Float1: + return Float{ 32 }; + + case ShaderNodes::BasicType::Int1: + return Integer{ 32, 1 }; + + case ShaderNodes::BasicType::Float2: + case ShaderNodes::BasicType::Float3: + case ShaderNodes::BasicType::Float4: + case ShaderNodes::BasicType::Int2: + case ShaderNodes::BasicType::Int3: + case ShaderNodes::BasicType::Int4: + case ShaderNodes::BasicType::UInt2: + case ShaderNodes::BasicType::UInt3: + case ShaderNodes::BasicType::UInt4: + { + auto vecType = BuildType(ShaderNodes::Node::GetComponentType(type)); + UInt32 componentCount = ShaderNodes::Node::GetComponentCount(type); + + return Vector{ vecType, componentCount }; + } + + case ShaderNodes::BasicType::Mat4x4: + return Matrix{ BuildType(ShaderNodes::BasicType::Float4), 4u }; + + case ShaderNodes::BasicType::UInt1: + return Integer{ 32, 0 }; + + case ShaderNodes::BasicType::Void: + return Void{}; + + case ShaderNodes::BasicType::Sampler2D: + { + auto imageType = Image{ + {}, //< qualifier + {}, //< depth + {}, //< sampled + SpirvDim::Dim2D, //< dim + SpirvImageFormat::Unknown, //< format + BuildType(ShaderNodes::BasicType::Float1), //< sampledType + false, //< arrayed, + false //< multisampled + }; + + return SampledImage{ std::make_shared(imageType) }; + } + } + + throw std::runtime_error("unexpected type"); + }()); + } + + auto SpirvConstantCache::BuildType(const ShaderAst& shader, const ShaderExpressionType& type) -> TypePtr + { + return std::visit([&](auto&& arg) -> TypePtr + { + using T = std::decay_t; + if constexpr (std::is_same_v) + return BuildType(arg); + else if constexpr (std::is_same_v) + { + // Register struct members type + const auto& structs = shader.GetStructs(); + auto it = std::find_if(structs.begin(), structs.end(), [&](const auto& s) { return s.name == arg; }); + if (it == structs.end()) + throw std::runtime_error("struct " + arg + " has not been defined"); + + const ShaderAst::Struct& s = *it; + + Structure sType; + sType.name = s.name; + + for (const auto& member : s.members) + { + auto& sMembers = sType.members.emplace_back(); + sMembers.name = member.name; + sMembers.type = BuildType(shader, member.type); + } + + return std::make_shared(std::move(sType)); + } + else + static_assert(AlwaysFalse::value, "non-exhaustive visitor"); + }, type); + } + + void SpirvConstantCache::WriteStruct(const Structure& structData, UInt32 resultId, SpirvSection& annotations, SpirvSection& debugInfos, SpirvSection& types) + { + types.AppendVariadic(SpirvOp::OpTypeStruct, [&](const auto& appender) + { + appender(resultId); + + for (const auto& member : structData.members) + appender(GetId(*member.type)); + }); + + debugInfos.Append(SpirvOp::OpName, resultId, structData.name); + + annotations.Append(SpirvOp::OpDecorate, resultId, SpirvDecoration::Block); + + FieldOffsets structOffsets(StructLayout_Std140); + + for (std::size_t memberIndex = 0; memberIndex < structData.members.size(); ++memberIndex) + { + const auto& member = structData.members[memberIndex]; + debugInfos.Append(SpirvOp::OpMemberName, resultId, memberIndex, member.name); + + std::size_t offset = std::visit([&](auto&& arg) -> std::size_t + { + using T = std::decay_t; + + if constexpr (std::is_same_v) + return structOffsets.AddField(StructFieldType_Bool1); + else if constexpr (std::is_same_v) + { + switch (arg.width) + { + case 32: return structOffsets.AddField(StructFieldType_Float1); + case 64: return structOffsets.AddField(StructFieldType_Double1); + default: throw std::runtime_error("unexpected float width " + std::to_string(arg.width)); + } + } + else if constexpr (std::is_same_v) + return structOffsets.AddField((arg.signedness) ? StructFieldType_Int1 : StructFieldType_UInt1); + else if constexpr (std::is_same_v) + { + assert(std::holds_alternative(arg.columnType->type)); + Vector& columnVec = std::get(arg.columnType->type); + + if (!std::holds_alternative(columnVec.componentType->type)) + throw std::runtime_error("unexpected vector type"); + + Float& vecType = std::get(columnVec.componentType->type); + + StructFieldType columnType; + switch (vecType.width) + { + case 32: columnType = StructFieldType_Float1; break; + case 64: columnType = StructFieldType_Double1; break; + default: throw std::runtime_error("unexpected float width " + std::to_string(vecType.width)); + } + + annotations.Append(SpirvOp::OpMemberDecorate, resultId, memberIndex, SpirvDecoration::ColMajor); + annotations.Append(SpirvOp::OpMemberDecorate, resultId, memberIndex, SpirvDecoration::MatrixStride, 16); + + return structOffsets.AddMatrix(columnType, arg.columnCount, columnVec.componentCount, true); + } + else if constexpr (std::is_same_v) + throw std::runtime_error("unhandled pointer in struct"); + else if constexpr (std::is_same_v) + { + auto it = m_internal->structureSizes.find(arg); + assert(it != m_internal->structureSizes.end()); + + return structOffsets.AddStruct(it->second); + } + else if constexpr (std::is_same_v) + { + if (std::holds_alternative(arg.componentType->type)) + return structOffsets.AddField(static_cast(StructFieldType_Bool1 + arg.componentCount - 1)); + else if (std::holds_alternative(arg.componentType->type)) + { + Float& floatData = std::get(arg.componentType->type); + switch (floatData.width) + { + case 32: return structOffsets.AddField(static_cast(StructFieldType_Float1 + arg.componentCount - 1)); + case 64: return structOffsets.AddField(static_cast(StructFieldType_Double1 + arg.componentCount - 1)); + default: throw std::runtime_error("unexpected float width " + std::to_string(floatData.width)); + } + } + else if (std::holds_alternative(arg.componentType->type)) + { + Integer& intData = std::get(arg.componentType->type); + if (intData.width != 32) + throw std::runtime_error("unexpected integer width " + std::to_string(intData.width)); + + if (intData.signedness) + return structOffsets.AddField(static_cast(StructFieldType_Int1 + arg.componentCount - 1)); + else + return structOffsets.AddField(static_cast(StructFieldType_UInt1 + arg.componentCount - 1)); + } + else + throw std::runtime_error("unexpected type for vector"); + } + else if constexpr (std::is_same_v) + throw std::runtime_error("unexpected function as struct member"); + else if constexpr (std::is_same_v || std::is_same_v) + throw std::runtime_error("unexpected opaque type as struct member"); + else if constexpr (std::is_same_v) + throw std::runtime_error("unexpected void as struct member"); + else + static_assert(AlwaysFalse::value, "non-exhaustive visitor"); + }, member.type->type); + + annotations.Append(SpirvOp::OpMemberDecorate, resultId, memberIndex, SpirvDecoration::Offset, offset); + } + + m_internal->structureSizes.emplace(structData, std::move(structOffsets)); + } +} diff --git a/src/Nazara/Shader/SpirvWriter.cpp b/src/Nazara/Shader/SpirvWriter.cpp index fb767d0e8..398ee8e71 100644 --- a/src/Nazara/Shader/SpirvWriter.cpp +++ b/src/Nazara/Shader/SpirvWriter.cpp @@ -4,10 +4,10 @@ #include #include -#include #include #include #include +#include #include #include #include @@ -24,23 +24,25 @@ namespace Nz { namespace { - using ConstantVariant = ShaderNodes::Constant::Variant; - class PreVisitor : public ShaderAstRecursiveVisitor, public ShaderVarVisitor { public: using BuiltinContainer = std::unordered_set>; - using ConstantContainer = tsl::ordered_set; using ExtInstList = std::unordered_set; using LocalContainer = std::unordered_set>; using ParameterContainer = std::unordered_set< std::shared_ptr>; + PreVisitor(SpirvConstantCache& constantCache) : + m_constantCache(constantCache) + { + } + using ShaderAstRecursiveVisitor::Visit; using ShaderVarVisitor::Visit; void Visit(ShaderNodes::AccessMember& node) override { - constants.emplace(Int32(node.memberIndex)); + m_constantCache.Register(*SpirvConstantCache::BuildConstant(UInt32(node.memberIndex))); ShaderAstRecursiveVisitor::Visit(node); } @@ -49,35 +51,8 @@ namespace Nz { std::visit([&](auto&& arg) { - using T = std::decay_t; - - if constexpr (std::is_same_v || std::is_same_v || std::is_same_v) - constants.emplace(arg); - else if constexpr (std::is_same_v || std::is_same_v) - { - constants.emplace(arg.x); - constants.emplace(arg.y); - constants.emplace(arg); - } - else if constexpr (std::is_same_v || std::is_same_v) - { - constants.emplace(arg.x); - constants.emplace(arg.y); - constants.emplace(arg.z); - constants.emplace(arg); - } - else if constexpr (std::is_same_v || std::is_same_v) - { - constants.emplace(arg.x); - constants.emplace(arg.y); - constants.emplace(arg.z); - constants.emplace(arg.w); - constants.emplace(arg); - } - else - static_assert(AlwaysFalse::value, "non-exhaustive visitor"); - }, - node.value); + m_constantCache.Register(*SpirvConstantCache::BuildConstant(arg)); + }, node.value); ShaderAstRecursiveVisitor::Visit(node); } @@ -118,7 +93,7 @@ namespace Nz builtinVars.insert(std::static_pointer_cast(var.shared_from_this())); } - void Visit(ShaderNodes::InputVariable& var) override + void Visit(ShaderNodes::InputVariable& /*var*/) override { /* Handled by ShaderAst */ } @@ -128,7 +103,7 @@ namespace Nz localVars.insert(std::static_pointer_cast(var.shared_from_this())); } - void Visit(ShaderNodes::OutputVariable& var) override + void Visit(ShaderNodes::OutputVariable& /*var*/) override { /* Handled by ShaderAst */ } @@ -138,32 +113,18 @@ namespace Nz paramVars.insert(std::static_pointer_cast(var.shared_from_this())); } - void Visit(ShaderNodes::UniformVariable& var) override + void Visit(ShaderNodes::UniformVariable& /*var*/) override { /* Handled by ShaderAst */ } BuiltinContainer builtinVars; - ConstantContainer constants; ExtInstList extInsts; LocalContainer localVars; ParameterContainer paramVars; - }; - class AssignVisitor : public ShaderAstRecursiveVisitor - { - public: - void Visit(ShaderNodes::AccessMember& node) override - { - } - - void Visit(ShaderNodes::Identifier& node) override - { - } - - void Visit(ShaderNodes::SwizzleOp& node) override - { - } + private: + SpirvConstantCache& m_constantCache; }; template @@ -202,6 +163,11 @@ namespace Nz struct SpirvWriter::State { + State() : + constantTypeCache(nextVarIndex) + { + } + struct Func { UInt32 typeId; @@ -209,18 +175,16 @@ namespace Nz std::vector paramsId; }; - std::unordered_map extensionInstructions; - std::unordered_map builtinIds; - std::unordered_map varToResult; - tsl::ordered_map constantIds; - tsl::ordered_map typeIds; - std::vector funcs; tsl::ordered_map inputIds; tsl::ordered_map outputIds; tsl::ordered_map uniformIds; - std::vector> structFields; + std::unordered_map extensionInstructions; + std::unordered_map builtinIds; + std::unordered_map varToResult; + std::vector funcs; std::vector resultIds; UInt32 nextVarIndex = 1; + SpirvConstantCache constantTypeCache; //< init after nextVarIndex // Output SpirvSection header; @@ -251,13 +215,11 @@ namespace Nz m_currentState = nullptr; }); - state.structFields.resize(shader.GetStructCount()); - std::vector functionStatements; ShaderAstCloner cloner; - PreVisitor preVisitor; + PreVisitor preVisitor(state.constantTypeCache); for (const auto& func : shader.GetFunctions()) { functionStatements.emplace_back(cloner.Clone(func.statement)); @@ -277,13 +239,16 @@ namespace Nz } for (const auto& input : shader.GetInputs()) - RegisterType(input.type); + RegisterPointerType(input.type, SpirvStorageClass::Input); for (const auto& output : shader.GetOutputs()) - RegisterType(output.type); + RegisterPointerType(output.type, SpirvStorageClass::Output); for (const auto& uniform : shader.GetUniforms()) - RegisterType(uniform.type); + RegisterPointerType(uniform.type, SpirvStorageClass::Uniform); + + for (const auto& func : shader.GetFunctions()) + RegisterFunctionType(func.returnType, func.parameters); for (const auto& local : preVisitor.localVars) RegisterType(local->type); @@ -291,104 +256,103 @@ namespace Nz for (const auto& builtin : preVisitor.builtinVars) RegisterType(builtin->type); - // Register constant types - for (const auto& constant : preVisitor.constants) - { - std::visit([&](auto&& arg) - { - using T = std::decay_t; - RegisterType(GetBasicType()); - }, constant); - } - - AppendTypes(); - // Register result id and debug infos for global variables/functions for (const auto& builtin : preVisitor.builtinVars) { - const ShaderExpressionType& builtinExprType = builtin->type; - assert(std::holds_alternative(builtinExprType)); - - ShaderNodes::BasicType builtinType = std::get(builtinExprType); - - ExtVar builtinData; - builtinData.pointerTypeId = AllocateResultId(); - builtinData.typeId = GetTypeId(builtinType); - builtinData.varId = AllocateResultId(); - - SpvBuiltIn spvBuiltin; - std::string debugName; + SpirvConstantCache::Variable variable; + SpirvBuiltIn builtinDecoration; switch (builtin->entry) { case ShaderNodes::BuiltinEntry::VertexPosition: - debugName = "builtin_VertexPosition"; - spvBuiltin = SpvBuiltInPosition; + variable.debugName = "builtin_VertexPosition"; + variable.storageClass = SpirvStorageClass::Output; + + builtinDecoration = SpirvBuiltIn::Position; break; default: throw std::runtime_error("unexpected builtin type"); } - state.debugInfo.Append(SpirvOp::OpName, builtinData.varId, debugName); - state.types.Append(SpirvOp::OpTypePointer, builtinData.pointerTypeId, SpvStorageClassOutput, builtinData.typeId); - state.types.Append(SpirvOp::OpVariable, builtinData.pointerTypeId, builtinData.varId, SpvStorageClassOutput); + const ShaderExpressionType& builtinExprType = builtin->type; + assert(std::holds_alternative(builtinExprType)); - state.annotations.Append(SpirvOp::OpDecorate, builtinData.varId, SpvDecorationBuiltIn, spvBuiltin); + ShaderNodes::BasicType builtinType = std::get(builtinExprType); + + variable.type = SpirvConstantCache::BuildPointerType(builtinType, variable.storageClass); + + UInt32 varId = m_currentState->constantTypeCache.Register(variable); + + ExtVar builtinData; + builtinData.pointerTypeId = GetPointerTypeId(builtinType, variable.storageClass); + builtinData.typeId = GetTypeId(builtinType); + builtinData.varId = varId; + + state.annotations.Append(SpirvOp::OpDecorate, builtinData.varId, SpvDecorationBuiltIn, builtinDecoration); state.builtinIds.emplace(builtin->entry, builtinData); } for (const auto& input : shader.GetInputs()) { + SpirvConstantCache::Variable variable; + variable.debugName = input.name; + variable.storageClass = SpirvStorageClass::Input; + variable.type = SpirvConstantCache::BuildPointerType(shader, input.type, variable.storageClass); + + UInt32 varId = m_currentState->constantTypeCache.Register(variable); + ExtVar inputData; - inputData.pointerTypeId = AllocateResultId(); + inputData.pointerTypeId = GetPointerTypeId(input.type, variable.storageClass); inputData.typeId = GetTypeId(input.type); - inputData.varId = AllocateResultId(); + inputData.varId = varId; - state.inputIds.emplace(input.name, inputData); - - state.debugInfo.Append(SpirvOp::OpName, inputData.varId, input.name); - state.types.Append(SpirvOp::OpTypePointer, inputData.pointerTypeId, SpvStorageClassInput, inputData.typeId); - state.types.Append(SpirvOp::OpVariable, inputData.pointerTypeId, inputData.varId, SpvStorageClassInput); + state.inputIds.emplace(input.name, std::move(inputData)); if (input.locationIndex) - state.annotations.Append(SpirvOp::OpDecorate, inputData.varId, SpvDecorationLocation, *input.locationIndex); + state.annotations.Append(SpirvOp::OpDecorate, varId, SpvDecorationLocation, *input.locationIndex); } for (const auto& output : shader.GetOutputs()) { + SpirvConstantCache::Variable variable; + variable.debugName = output.name; + variable.storageClass = SpirvStorageClass::Output; + variable.type = SpirvConstantCache::BuildPointerType(shader, output.type, variable.storageClass); + + UInt32 varId = m_currentState->constantTypeCache.Register(variable); + ExtVar outputData; - outputData.pointerTypeId = AllocateResultId(); + outputData.pointerTypeId = GetPointerTypeId(output.type, variable.storageClass); outputData.typeId = GetTypeId(output.type); - outputData.varId = AllocateResultId(); + outputData.varId = varId; - state.outputIds.emplace(output.name, outputData); - - state.debugInfo.Append(SpirvOp::OpName, outputData.varId, output.name); - state.types.Append(SpirvOp::OpTypePointer, outputData.pointerTypeId, SpvStorageClassOutput, outputData.typeId); - state.types.Append(SpirvOp::OpVariable, outputData.pointerTypeId, outputData.varId, SpvStorageClassOutput); + state.outputIds.emplace(output.name, std::move(outputData)); if (output.locationIndex) - state.annotations.Append(SpirvOp::OpDecorate, outputData.varId, SpvDecorationLocation, *output.locationIndex); + state.annotations.Append(SpirvOp::OpDecorate, varId, SpvDecorationLocation, *output.locationIndex); } for (const auto& uniform : shader.GetUniforms()) { + SpirvConstantCache::Variable variable; + variable.debugName = uniform.name; + variable.storageClass = SpirvStorageClass::Uniform; + variable.type = SpirvConstantCache::BuildPointerType(shader, uniform.type, variable.storageClass); + + UInt32 varId = m_currentState->constantTypeCache.Register(variable); + ExtVar uniformData; - uniformData.pointerTypeId = AllocateResultId(); + uniformData.pointerTypeId = GetPointerTypeId(uniform.type, variable.storageClass); uniformData.typeId = GetTypeId(uniform.type); - uniformData.varId = AllocateResultId(); + uniformData.varId = varId; - state.uniformIds.emplace(uniform.name, uniformData); - - state.debugInfo.Append(SpirvOp::OpName, uniformData.varId, uniform.name); - state.types.Append(SpirvOp::OpTypePointer, uniformData.pointerTypeId, SpvStorageClassUniform, uniformData.typeId); - state.types.Append(SpirvOp::OpVariable, uniformData.pointerTypeId, uniformData.varId, SpvStorageClassUniform); + state.uniformIds.emplace(uniform.name, std::move(uniformData)); if (uniform.bindingIndex) { - state.annotations.Append(SpirvOp::OpDecorate, uniformData.varId, SpvDecorationBinding, *uniform.bindingIndex); - state.annotations.Append(SpirvOp::OpDecorate, uniformData.varId, SpvDecorationDescriptorSet, 0); + state.annotations.Append(SpirvOp::OpDecorate, varId, SpvDecorationBinding, *uniform.bindingIndex); + state.annotations.Append(SpirvOp::OpDecorate, varId, SpvDecorationDescriptorSet, 0); } } @@ -396,26 +360,11 @@ namespace Nz { auto& funcData = state.funcs.emplace_back(); funcData.id = AllocateResultId(); - funcData.typeId = AllocateResultId(); + funcData.typeId = GetFunctionTypeId(func.returnType, func.parameters); state.debugInfo.Append(SpirvOp::OpName, funcData.id, func.name); - - state.types.AppendVariadic(SpirvOp::OpTypeFunction, [&](const auto& appender) - { - appender(funcData.typeId); - appender(GetTypeId(func.returnType)); - - for (const auto& param : func.parameters) - appender(GetTypeId(param.type)); - }); } - // Register constants - for (const auto& constant : preVisitor.constants) - state.constantIds[constant] = AllocateResultId(); - - AppendConstants(); - std::size_t entryPointIndex = std::numeric_limits::max(); for (std::size_t funcIndex = 0; funcIndex < shader.GetFunctionCount(); ++funcIndex) @@ -448,11 +397,13 @@ namespace Nz assert(entryPointIndex != std::numeric_limits::max()); + m_currentState->constantTypeCache.Write(m_currentState->annotations, m_currentState->constants, m_currentState->debugInfo, m_currentState->types); + AppendHeader(); SpvExecutionModel execModel; const auto& entryFuncData = shader.GetFunction(entryPointIndex); - const auto& entryFunc = m_currentState->funcs[entryPointIndex]; + const auto& entryFunc = state.funcs[entryPointIndex]; assert(m_context.shader); switch (m_context.shader->GetStage()) @@ -471,21 +422,19 @@ namespace Nz // OpEntryPoint Vertex %main "main" %outNormal %inNormals %outTexCoords %inTexCoord %_ %inPos - std::size_t nameSize = state.header.CountWord(entryFuncData.name); - state.header.AppendVariadic(SpirvOp::OpEntryPoint, [&](const auto& appender) { appender(execModel); appender(entryFunc.id); appender(entryFuncData.name); - for (const auto& [name, varData] : m_currentState->builtinIds) + for (const auto& [name, varData] : state.builtinIds) appender(varData.varId); - for (const auto& [name, varData] : m_currentState->inputIds) + for (const auto& [name, varData] : state.inputIds) appender(varData.varId); - for (const auto& [name, varData] : m_currentState->outputIds) + for (const auto& [name, varData] : state.outputIds) appender(varData.varId); }); @@ -513,31 +462,6 @@ namespace Nz return m_currentState->nextVarIndex++; } - void SpirvWriter::AppendConstants() - { - for (const auto& [value, resultId] : m_currentState->constantIds) - { - UInt32 constantId = resultId; - std::visit([&](auto&& arg) - { - using T = std::decay_t; - - if constexpr (std::is_same_v) - m_currentState->constants.Append((arg) ? SpirvOp::OpConstantTrue : SpirvOp::OpConstantFalse, constantId); - else if constexpr (std::is_same_v || std::is_same_v) - m_currentState->constants.Append(SpirvOp::OpConstant, GetTypeId(GetBasicType()), constantId, SpirvSection::Raw{ &arg, sizeof(arg) }); - else if constexpr (std::is_same_v || std::is_same_v) - m_currentState->constants.Append(SpirvOp::OpConstantComposite, GetTypeId(GetBasicType()), constantId, GetConstantId(arg.x), GetConstantId(arg.y)); - else if constexpr (std::is_same_v || std::is_same_v) - m_currentState->constants.Append(SpirvOp::OpConstantComposite, GetTypeId(GetBasicType()), constantId, GetConstantId(arg.x), GetConstantId(arg.y), GetConstantId(arg.z)); - else if constexpr (std::is_same_v || std::is_same_v) - m_currentState->constants.Append(SpirvOp::OpConstantComposite, GetTypeId(GetBasicType()), constantId, GetConstantId(arg.x), GetConstantId(arg.y), GetConstantId(arg.z), GetConstantId(arg.w)); - else - static_assert(AlwaysFalse::value, "non-exhaustive visitor"); - }, value); - } - } - void SpirvWriter::AppendHeader() { m_currentState->header.Append(SpvMagicNumber); //< Spir-V magic number @@ -557,180 +481,41 @@ namespace Nz m_currentState->header.Append(SpirvOp::OpMemoryModel, SpvAddressingModelLogical, SpvMemoryModelGLSL450); } - void SpirvWriter::AppendStructType(std::size_t structIndex, UInt32 resultId) - { - const ShaderAst::Struct& s = m_context.shader->GetStruct(structIndex); - - m_currentState->types.Append(SpirvOp::OpTypeStruct, SpirvSection::OpSize{ static_cast(1 + 1 + s.members.size()) }); - m_currentState->types.Append(resultId); - - m_currentState->debugInfo.Append(SpirvOp::OpName, resultId, s.name); - - m_currentState->annotations.Append(SpirvOp::OpDecorate, resultId, SpvDecorationBlock); - - FieldOffsets structOffsets(StructLayout_Std140); - - for (std::size_t memberIndex = 0; memberIndex < s.members.size(); ++memberIndex) - { - const auto& member = s.members[memberIndex]; - m_currentState->types.Append(GetTypeId(member.type)); - m_currentState->debugInfo.Append(SpirvOp::OpMemberName, resultId, memberIndex, member.name); - - std::visit([&](auto&& arg) - { - using T = std::decay_t; - if constexpr (std::is_same_v) - { - std::size_t offset = [&] { - switch (arg) - { - case ShaderNodes::BasicType::Boolean: return structOffsets.AddField(StructFieldType_Bool1); - case ShaderNodes::BasicType::Float1: return structOffsets.AddField(StructFieldType_Float1); - case ShaderNodes::BasicType::Float2: return structOffsets.AddField(StructFieldType_Float2); - case ShaderNodes::BasicType::Float3: return structOffsets.AddField(StructFieldType_Float3); - case ShaderNodes::BasicType::Float4: return structOffsets.AddField(StructFieldType_Float4); - case ShaderNodes::BasicType::Int1: return structOffsets.AddField(StructFieldType_Int1); - case ShaderNodes::BasicType::Int2: return structOffsets.AddField(StructFieldType_Int2); - case ShaderNodes::BasicType::Int3: return structOffsets.AddField(StructFieldType_Int3); - case ShaderNodes::BasicType::Int4: return structOffsets.AddField(StructFieldType_Int4); - case ShaderNodes::BasicType::Mat4x4: return structOffsets.AddMatrix(StructFieldType_Float1, 4, 4, true); - case ShaderNodes::BasicType::Sampler2D: throw std::runtime_error("unexpected sampler2D as struct member"); - case ShaderNodes::BasicType::Void: throw std::runtime_error("unexpected void as struct member"); - } - - assert(false); - throw std::runtime_error("unhandled type"); - }(); - - m_currentState->annotations.Append(SpirvOp::OpMemberDecorate, resultId, memberIndex, SpvDecorationOffset, offset); - - if (arg == ShaderNodes::BasicType::Mat4x4) - { - m_currentState->annotations.Append(SpirvOp::OpMemberDecorate, resultId, memberIndex, SpvDecorationColMajor); - m_currentState->annotations.Append(SpirvOp::OpMemberDecorate, resultId, memberIndex, SpvDecorationMatrixStride, 16); - } - } - else if constexpr (std::is_same_v) - { - // Register struct members type - const auto& structs = m_context.shader->GetStructs(); - auto it = std::find_if(structs.begin(), structs.end(), [&](const auto& s) { return s.name == arg; }); - if (it == structs.end()) - throw std::runtime_error("struct " + arg + " has not been defined"); - - std::size_t nestedStructIndex = std::distance(structs.begin(), it); - std::optional nestedFieldOffset = m_currentState->structFields[nestedStructIndex]; - if (!nestedFieldOffset) - throw std::runtime_error("struct dependency cycle"); - - structOffsets.AddStruct(nestedFieldOffset.value()); - } - else - static_assert(AlwaysFalse::value, "non-exhaustive visitor"); - }, member.type); - } - - m_currentState->structFields[structIndex] = structOffsets; - } - - void SpirvWriter::AppendTypes() - { - for (const auto& [type, typeId] : m_currentState->typeIds.values_container()) - { - UInt32 resultId = typeId; - - // Register sub-types, if any - std::visit([&](auto&& arg) - { - using T = std::decay_t; - if constexpr (std::is_same_v) - { - switch (arg) - { - case ShaderNodes::BasicType::Boolean: - m_currentState->types.Append(SpirvOp::OpTypeBool, resultId); - break; - - case ShaderNodes::BasicType::Float1: - m_currentState->types.Append(SpirvOp::OpTypeFloat, resultId, 32); - break; - - case ShaderNodes::BasicType::Float2: - case ShaderNodes::BasicType::Float3: - case ShaderNodes::BasicType::Float4: - case ShaderNodes::BasicType::Int2: - case ShaderNodes::BasicType::Int3: - case ShaderNodes::BasicType::Int4: - { - ShaderNodes::BasicType baseType = ShaderNodes::Node::GetComponentType(arg); - - UInt32 vecSize = UInt32(arg) - UInt32(baseType) + 1; - - m_currentState->types.Append(SpirvOp::OpTypeVector, resultId, GetTypeId(baseType), vecSize); - break; - } - - case ShaderNodes::BasicType::Int1: - m_currentState->types.Append(SpirvOp::OpTypeInt, resultId, 32, 1); - break; - - case ShaderNodes::BasicType::Mat4x4: - { - m_currentState->types.Append(SpirvOp::OpTypeMatrix, resultId, GetTypeId(ShaderNodes::BasicType::Float4), 4); - break; - } - - case ShaderNodes::BasicType::Sampler2D: - { - UInt32 imageTypeId = resultId - 1; - - m_currentState->types.Append(SpirvOp::OpTypeImage, imageTypeId, GetTypeId(ShaderNodes::BasicType::Float1), SpvDim2D, 0, 0, 0, 1, SpvImageFormatUnknown); - m_currentState->types.Append(SpirvOp::OpTypeSampledImage, resultId, imageTypeId); - break; - } - - case ShaderNodes::BasicType::Void: - m_currentState->types.Append(SpirvOp::OpTypeVoid, resultId); - break; - } - } - else if constexpr (std::is_same_v) - { - // Register struct members type - const auto& structs = m_context.shader->GetStructs(); - auto it = std::find_if(structs.begin(), structs.end(), [&](const auto& s) { return s.name == arg; }); - if (it == structs.end()) - throw std::runtime_error("struct " + arg + " has not been defined"); - - std::size_t structIndex = std::distance(structs.begin(), it); - AppendStructType(structIndex, resultId); - } - else - static_assert(AlwaysFalse::value, "non-exhaustive visitor"); - }, type); - } - } - UInt32 SpirvWriter::EvaluateExpression(const ShaderNodes::ExpressionPtr& expr) { Visit(expr); return PopResultId(); } - UInt32 SpirvWriter::GetConstantId(const ShaderNodes::Constant::Variant& value) const + UInt32 SpirvWriter::GetConstantId(const ShaderConstantValue& value) const { - auto typeIt = m_currentState->constantIds.find(value); - assert(typeIt != m_currentState->constantIds.end()); + return m_currentState->constantTypeCache.GetId(*SpirvConstantCache::BuildConstant(value)); + } - return typeIt->second; + UInt32 SpirvWriter::GetFunctionTypeId(ShaderExpressionType retType, const std::vector& parameters) + { + std::vector parameterTypes; + parameterTypes.reserve(parameters.size()); + + for (const auto& parameter : parameters) + parameterTypes.push_back(SpirvConstantCache::BuildType(*m_context.shader, parameter.type)); + + return m_currentState->constantTypeCache.GetId({ + SpirvConstantCache::Function { + SpirvConstantCache::BuildType(*m_context.shader, retType), + std::move(parameterTypes) + } + }); + } + + UInt32 SpirvWriter::GetPointerTypeId(const ShaderExpressionType& type, SpirvStorageClass storageClass) const + { + return m_currentState->constantTypeCache.GetId(*SpirvConstantCache::BuildPointerType(*m_context.shader, type, storageClass)); } UInt32 SpirvWriter::GetTypeId(const ShaderExpressionType& type) const { - auto typeIt = m_currentState->typeIds.find(type); - assert(typeIt != m_currentState->typeIds.end()); - - return typeIt->second; + return m_currentState->constantTypeCache.GetId(*SpirvConstantCache::BuildType(*m_context.shader, type)); } void SpirvWriter::PushResultId(UInt32 value) @@ -762,68 +547,42 @@ namespace Nz return var.valueId.value(); } + UInt32 SpirvWriter::RegisterConstant(const ShaderConstantValue& value) + { + return m_currentState->constantTypeCache.Register(*SpirvConstantCache::BuildConstant(value)); + } + + UInt32 SpirvWriter::RegisterFunctionType(ShaderExpressionType retType, const std::vector& parameters) + { + std::vector parameterTypes; + parameterTypes.reserve(parameters.size()); + + for (const auto& parameter : parameters) + parameterTypes.push_back(SpirvConstantCache::BuildType(*m_context.shader, parameter.type)); + + return m_currentState->constantTypeCache.Register({ + SpirvConstantCache::Function { + SpirvConstantCache::BuildType(*m_context.shader, retType), + std::move(parameterTypes) + } + }); + } + + UInt32 SpirvWriter::RegisterPointerType(ShaderExpressionType type, SpirvStorageClass storageClass) + { + return m_currentState->constantTypeCache.Register(*SpirvConstantCache::BuildPointerType(*m_context.shader, type, storageClass)); + } + UInt32 SpirvWriter::RegisterType(ShaderExpressionType type) { - auto it = m_currentState->typeIds.find(type); - if (it == m_currentState->typeIds.end()) - { - // Register sub-types, if any - std::visit([&](auto&& arg) - { - using T = std::decay_t; - if constexpr (std::is_same_v) - { - switch (arg) - { - case ShaderNodes::BasicType::Boolean: - case ShaderNodes::BasicType::Float1: - case ShaderNodes::BasicType::Int1: - case ShaderNodes::BasicType::Void: - break; //< Nothing to do - - // In SPIR-V, vec3 (for example) depends on float - case ShaderNodes::BasicType::Float2: - case ShaderNodes::BasicType::Float3: - case ShaderNodes::BasicType::Float4: - case ShaderNodes::BasicType::Int2: - case ShaderNodes::BasicType::Int3: - case ShaderNodes::BasicType::Int4: - case ShaderNodes::BasicType::Mat4x4: - RegisterType(ShaderNodes::Node::GetComponentType(arg)); - break; - - case ShaderNodes::BasicType::Sampler2D: - RegisterType(ShaderNodes::BasicType::Float1); - AllocateResultId(); //< Reserve a result id for the image type - break; - } - } - else if constexpr (std::is_same_v) - { - // Register struct members type - const auto& structs = m_context.shader->GetStructs(); - auto it = std::find_if(structs.begin(), structs.end(), [&](const auto& s) { return s.name == arg; }); - if (it == structs.end()) - throw std::runtime_error("struct " + arg + " has not been defined"); - - const ShaderAst::Struct& s = *it; - for (const auto& member : s.members) - RegisterType(member.type); - } - else - static_assert(AlwaysFalse::value, "non-exhaustive visitor"); - }, type); - - it = m_currentState->typeIds.emplace(std::move(type), AllocateResultId()).first; - } - - return it->second; + assert(m_currentState); + return m_currentState->constantTypeCache.Register(*SpirvConstantCache::BuildType(*m_context.shader, type)); } void SpirvWriter::Visit(ShaderNodes::AccessMember& node) { UInt32 pointerId; - SpvStorageClass storage; + SpirvStorageClass storage; switch (node.structExpr->GetType()) { @@ -848,7 +607,7 @@ namespace Nz auto it = m_currentState->inputIds.find(inputVar.name); assert(it != m_currentState->inputIds.end()); - storage = SpvStorageClassInput; + storage = SpirvStorageClass::Input; pointerId = it->second.varId; break; @@ -860,7 +619,7 @@ namespace Nz auto it = m_currentState->outputIds.find(outputVar.name); assert(it != m_currentState->outputIds.end()); - storage = SpvStorageClassOutput; + storage = SpirvStorageClass::Output; pointerId = it->second.varId; break; @@ -872,7 +631,7 @@ namespace Nz auto it = m_currentState->uniformIds.find(uniformVar.name); assert(it != m_currentState->uniformIds.end()); - storage = SpvStorageClassUniform; + storage = SpirvStorageClass::Uniform; pointerId = it->second.varId; break; @@ -892,11 +651,9 @@ namespace Nz } UInt32 memberPointerId = AllocateResultId(); - UInt32 pointerType = AllocateResultId(); + UInt32 pointerType = RegisterPointerType(node.exprType, storage); //< FIXME UInt32 typeId = GetTypeId(node.exprType); - UInt32 indexId = GetConstantId(Int32(node.memberIndex)); - - m_currentState->types.Append(SpirvOp::OpTypePointer, pointerType, storage, typeId); + UInt32 indexId = GetConstantId(UInt32(node.memberIndex)); m_currentState->instructions.Append(SpirvOp::OpAccessChain, pointerType, memberPointerId, pointerId, indexId); @@ -1002,6 +759,10 @@ namespace Nz 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: @@ -1026,6 +787,10 @@ namespace Nz 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: @@ -1052,6 +817,12 @@ namespace Nz 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: @@ -1077,6 +848,10 @@ namespace Nz 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: @@ -1141,6 +916,10 @@ namespace Nz 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: From cd23c01ace125b4a48147667f12ce6a8e54b39ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Fri, 21 Aug 2020 22:50:30 +0200 Subject: [PATCH 096/105] Shader: AccessMember can now access nested fields --- include/Nazara/Shader/GlslWriter.hpp | 1 + include/Nazara/Shader/ShaderAstValidator.hpp | 2 ++ include/Nazara/Shader/ShaderNodes.hpp | 3 +- include/Nazara/Shader/ShaderNodes.inl | 7 +++- src/Nazara/Shader/GlslWriter.cpp | 33 +++++++++++------- src/Nazara/Shader/ShaderAstCloner.cpp | 2 +- src/Nazara/Shader/ShaderAstSerializer.cpp | 5 ++- src/Nazara/Shader/ShaderAstValidator.cpp | 35 ++++++++++++++------ src/Nazara/Shader/SpirvWriter.cpp | 16 ++++++--- src/ShaderNode/DataModels/BufferField.cpp | 9 +++-- 10 files changed, 80 insertions(+), 33 deletions(-) diff --git a/include/Nazara/Shader/GlslWriter.hpp b/include/Nazara/Shader/GlslWriter.hpp index 3212d81cd..ad76fbe18 100644 --- a/include/Nazara/Shader/GlslWriter.hpp +++ b/include/Nazara/Shader/GlslWriter.hpp @@ -51,6 +51,7 @@ namespace Nz void Append(ShaderNodes::MemoryLayout layout); template void Append(const T& param); void AppendCommentSection(const std::string& section); + void AppendField(const std::string& structName, std::size_t* memberIndex, std::size_t remainingMembers); void AppendFunction(const ShaderAst::Function& func); void AppendFunctionPrototype(const ShaderAst::Function& func); void AppendLine(const std::string& txt = {}); diff --git a/include/Nazara/Shader/ShaderAstValidator.hpp b/include/Nazara/Shader/ShaderAstValidator.hpp index 0f9e99347..8195494b6 100644 --- a/include/Nazara/Shader/ShaderAstValidator.hpp +++ b/include/Nazara/Shader/ShaderAstValidator.hpp @@ -33,6 +33,8 @@ namespace Nz void TypeMustMatch(const ShaderNodes::ExpressionPtr& left, const ShaderNodes::ExpressionPtr& right); void TypeMustMatch(const ShaderExpressionType& left, const ShaderExpressionType& right); + const ShaderAst::StructMember& CheckField(const std::string& structName, std::size_t* memberIndex, std::size_t remainingMembers); + using ShaderAstRecursiveVisitor::Visit; void Visit(ShaderNodes::AccessMember& node) override; void Visit(ShaderNodes::AssignOp& node) override; diff --git a/include/Nazara/Shader/ShaderNodes.hpp b/include/Nazara/Shader/ShaderNodes.hpp index af96afeda..15898af3f 100644 --- a/include/Nazara/Shader/ShaderNodes.hpp +++ b/include/Nazara/Shader/ShaderNodes.hpp @@ -144,11 +144,12 @@ namespace Nz ShaderExpressionType GetExpressionType() const override; void Visit(ShaderAstVisitor& visitor) override; - std::size_t memberIndex; ExpressionPtr structExpr; ShaderExpressionType exprType; + std::vector memberIndices; static inline std::shared_ptr Build(ExpressionPtr structExpr, std::size_t memberIndex, ShaderExpressionType exprType); + static inline std::shared_ptr Build(ExpressionPtr structExpr, std::vector memberIndices, ShaderExpressionType exprType); }; ////////////////////////////////////////////////////////////////////////// diff --git a/include/Nazara/Shader/ShaderNodes.inl b/include/Nazara/Shader/ShaderNodes.inl index 9265fe359..77bc813f3 100644 --- a/include/Nazara/Shader/ShaderNodes.inl +++ b/include/Nazara/Shader/ShaderNodes.inl @@ -168,10 +168,15 @@ namespace Nz::ShaderNodes } inline std::shared_ptr AccessMember::Build(ExpressionPtr structExpr, std::size_t memberIndex, ShaderExpressionType exprType) + { + return Build(std::move(structExpr), std::vector{ memberIndex }, exprType); + } + + inline std::shared_ptr AccessMember::Build(ExpressionPtr structExpr, std::vector memberIndices, ShaderExpressionType exprType) { auto node = std::make_shared(); node->exprType = std::move(exprType); - node->memberIndex = memberIndex; + node->memberIndices = std::move(memberIndices); node->structExpr = std::move(structExpr); return node; diff --git a/src/Nazara/Shader/GlslWriter.cpp b/src/Nazara/Shader/GlslWriter.cpp index 1e911ce13..39f2ec3ce 100644 --- a/src/Nazara/Shader/GlslWriter.cpp +++ b/src/Nazara/Shader/GlslWriter.cpp @@ -258,6 +258,26 @@ namespace Nz AppendLine(); } + void GlslWriter::AppendField(const std::string& structName, std::size_t* memberIndex, std::size_t remainingMembers) + { + const auto& structs = m_context.shader->GetStructs(); + auto it = std::find_if(structs.begin(), structs.end(), [&](const auto& s) { return s.name == structName; }); + assert(it != structs.end()); + + const ShaderAst::Struct& s = *it; + assert(*memberIndex < s.members.size()); + + const auto& member = s.members[*memberIndex]; + Append("."); + Append(member.name); + + if (remainingMembers > 1) + { + assert(std::holds_alternative(member.type)); + AppendField(std::get(member.type), memberIndex + 1, remainingMembers - 1); + } + } + void GlslWriter::AppendFunction(const ShaderAst::Function& func) { NazaraAssert(!m_context.currentFunction, "A function is already being processed"); @@ -345,18 +365,7 @@ namespace Nz const ShaderExpressionType& exprType = node.structExpr->GetExpressionType(); assert(std::holds_alternative(exprType)); - const std::string& structName = std::get(exprType); - - const auto& structs = m_context.shader->GetStructs(); - auto it = std::find_if(structs.begin(), structs.end(), [&](const auto& s) { return s.name == structName; }); - assert(it != structs.end()); - - const ShaderAst::Struct& s = *it; - assert(node.memberIndex < s.members.size()); - - const auto& member = s.members[node.memberIndex]; - Append("."); - Append(member.name); + AppendField(std::get(exprType), node.memberIndices.data(), node.memberIndices.size()); } void GlslWriter::Visit(ShaderNodes::AssignOp& node) diff --git a/src/Nazara/Shader/ShaderAstCloner.cpp b/src/Nazara/Shader/ShaderAstCloner.cpp index 1e0f04899..39754b7a9 100644 --- a/src/Nazara/Shader/ShaderAstCloner.cpp +++ b/src/Nazara/Shader/ShaderAstCloner.cpp @@ -47,7 +47,7 @@ namespace Nz void ShaderAstCloner::Visit(ShaderNodes::AccessMember& node) { - PushExpression(ShaderNodes::AccessMember::Build(CloneExpression(node.structExpr), node.memberIndex, node.exprType)); + PushExpression(ShaderNodes::AccessMember::Build(CloneExpression(node.structExpr), node.memberIndices, node.exprType)); } void ShaderAstCloner::Visit(ShaderNodes::AssignOp& node) diff --git a/src/Nazara/Shader/ShaderAstSerializer.cpp b/src/Nazara/Shader/ShaderAstSerializer.cpp index 396cd3d98..03cd36d8b 100644 --- a/src/Nazara/Shader/ShaderAstSerializer.cpp +++ b/src/Nazara/Shader/ShaderAstSerializer.cpp @@ -132,9 +132,12 @@ namespace Nz void ShaderAstSerializerBase::Serialize(ShaderNodes::AccessMember& node) { - Value(node.memberIndex); Node(node.structExpr); Type(node.exprType); + + Container(node.memberIndices); + for (std::size_t& index : node.memberIndices) + Value(index); } void ShaderAstSerializerBase::Serialize(ShaderNodes::AssignOp& node) diff --git a/src/Nazara/Shader/ShaderAstValidator.cpp b/src/Nazara/Shader/ShaderAstValidator.cpp index 2f3177283..b614ec4a2 100644 --- a/src/Nazara/Shader/ShaderAstValidator.cpp +++ b/src/Nazara/Shader/ShaderAstValidator.cpp @@ -83,6 +83,30 @@ namespace Nz throw AstError{ "Left expression type must match right expression type" }; } + const ShaderAst::StructMember& ShaderAstValidator::CheckField(const std::string& structName, std::size_t* memberIndex, std::size_t remainingMembers) + { + const auto& structs = m_shader.GetStructs(); + auto it = std::find_if(structs.begin(), structs.end(), [&](const auto& s) { return s.name == structName; }); + if (it == structs.end()) + throw AstError{ "invalid structure" }; + + const ShaderAst::Struct& s = *it; + if (*memberIndex >= s.members.size()) + throw AstError{ "member index out of bounds" }; + + const auto& member = s.members[*memberIndex]; + + if (remainingMembers > 1) + { + if (!std::holds_alternative(member.type)) + throw AstError{ "member type does not match node type" }; + + return CheckField(std::get(member.type), memberIndex + 1, remainingMembers - 1); + } + else + return member; + } + void ShaderAstValidator::Visit(ShaderNodes::AccessMember& node) { const ShaderExpressionType& exprType = MandatoryExpr(node.structExpr)->GetExpressionType(); @@ -91,16 +115,7 @@ namespace Nz const std::string& structName = std::get(exprType); - const auto& structs = m_shader.GetStructs(); - auto it = std::find_if(structs.begin(), structs.end(), [&](const auto& s) { return s.name == structName; }); - if (it == structs.end()) - throw AstError{ "invalid structure" }; - - const ShaderAst::Struct& s = *it; - if (node.memberIndex >= s.members.size()) - throw AstError{ "member index out of bounds" }; - - const auto& member = s.members[node.memberIndex]; + const auto& member = CheckField(structName, node.memberIndices.data(), node.memberIndices.size()); if (member.type != node.exprType) throw AstError{ "member type does not match node type" }; } diff --git a/src/Nazara/Shader/SpirvWriter.cpp b/src/Nazara/Shader/SpirvWriter.cpp index 398ee8e71..92630d506 100644 --- a/src/Nazara/Shader/SpirvWriter.cpp +++ b/src/Nazara/Shader/SpirvWriter.cpp @@ -42,7 +42,8 @@ namespace Nz void Visit(ShaderNodes::AccessMember& node) override { - m_constantCache.Register(*SpirvConstantCache::BuildConstant(UInt32(node.memberIndex))); + for (std::size_t index : node.memberIndices) + m_constantCache.Register(*SpirvConstantCache::BuildConstant(Int32(index))); ShaderAstRecursiveVisitor::Visit(node); } @@ -653,9 +654,16 @@ namespace Nz UInt32 memberPointerId = AllocateResultId(); UInt32 pointerType = RegisterPointerType(node.exprType, storage); //< FIXME UInt32 typeId = GetTypeId(node.exprType); - UInt32 indexId = GetConstantId(UInt32(node.memberIndex)); - m_currentState->instructions.Append(SpirvOp::OpAccessChain, pointerType, memberPointerId, pointerId, indexId); + 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(); @@ -1047,8 +1055,6 @@ namespace Nz void SpirvWriter::Visit(ShaderNodes::Sample2D& node) { - // OpImageSampleImplicitLod %v4float %31 %35 - UInt32 typeId = GetTypeId(ShaderNodes::BasicType::Float4); UInt32 samplerId = EvaluateExpression(node.sampler); diff --git a/src/ShaderNode/DataModels/BufferField.cpp b/src/ShaderNode/DataModels/BufferField.cpp index 2d9cde16d..3f3986fb5 100644 --- a/src/ShaderNode/DataModels/BufferField.cpp +++ b/src/ShaderNode/DataModels/BufferField.cpp @@ -76,6 +76,9 @@ Nz::ShaderNodes::ExpressionPtr BufferField::GetExpression(Nz::ShaderNodes::Expre Nz::ShaderNodes::ExpressionPtr sourceExpr = Nz::ShaderBuilder::Identifier(varPtr); + std::vector memberIndices; + memberIndices.reserve(currentField.nestedFields.size() + 1); + const ShaderGraph::StructEntry* sourceStruct = &structEntry; for (std::size_t nestedIndex : currentField.nestedFields) { @@ -86,14 +89,16 @@ Nz::ShaderNodes::ExpressionPtr BufferField::GetExpression(Nz::ShaderNodes::Expre std::size_t nestedStructIndex = std::get(memberEntry.type); sourceStruct = &graph.GetStruct(nestedStructIndex); - sourceExpr = Nz::ShaderBuilder::AccessMember(std::move(sourceExpr), 0, graph.ToShaderExpressionType(memberEntry.type)); + memberIndices.push_back(nestedIndex); } + memberIndices.push_back(currentField.finalFieldIndex); + assert(currentField.finalFieldIndex < sourceStruct->members.size()); const auto& memberEntry = sourceStruct->members[currentField.finalFieldIndex]; assert(std::holds_alternative(memberEntry.type)); - return Nz::ShaderBuilder::AccessMember(std::move(sourceExpr), currentField.finalFieldIndex, graph.ToShaderExpressionType(std::get(memberEntry.type))); + return Nz::ShaderBuilder::AccessMember(std::move(sourceExpr), std::move(memberIndices), graph.ToShaderExpressionType(std::get(memberEntry.type))); } unsigned int BufferField::nPorts(QtNodes::PortType portType) const From 66a14721cb0786e345d04d35ee39175a96822966 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Fri, 21 Aug 2020 22:51:11 +0200 Subject: [PATCH 097/105] Shader/Spirv: Put types and constants in the same section --- include/Nazara/Shader/SpirvConstantCache.hpp | 7 +- src/Nazara/Shader/SpirvConstantCache.cpp | 278 ++++++++++--------- src/Nazara/Shader/SpirvWriter.cpp | 4 +- 3 files changed, 151 insertions(+), 138 deletions(-) diff --git a/include/Nazara/Shader/SpirvConstantCache.hpp b/include/Nazara/Shader/SpirvConstantCache.hpp index 95172c757..279f71b07 100644 --- a/include/Nazara/Shader/SpirvConstantCache.hpp +++ b/include/Nazara/Shader/SpirvConstantCache.hpp @@ -167,7 +167,7 @@ namespace Nz UInt32 Register(Type t); UInt32 Register(Variable v); - void Write(SpirvSection& annotations, SpirvSection& constants, SpirvSection& debugInfos, SpirvSection& types); + void Write(SpirvSection& annotations, SpirvSection& constants, SpirvSection& debugInfos); SpirvConstantCache& operator=(const SpirvConstantCache& cache) = delete; SpirvConstantCache& operator=(SpirvConstantCache&& cache) noexcept; @@ -183,7 +183,10 @@ namespace Nz struct Eq; struct Internal; - void WriteStruct(const Structure& structData, UInt32 resultId, SpirvSection& annotations, SpirvSection& debugInfos, SpirvSection& types); + void Write(const AnyConstant& constant, UInt32 resultId, SpirvSection& constants); + void Write(const AnyType& type, UInt32 resultId, SpirvSection& annotations, SpirvSection& constants, SpirvSection& debugInfos); + + void WriteStruct(const Structure& structData, UInt32 resultId, SpirvSection& annotations, SpirvSection& constants, SpirvSection& debugInfos); std::unique_ptr m_internal; }; diff --git a/src/Nazara/Shader/SpirvConstantCache.cpp b/src/Nazara/Shader/SpirvConstantCache.cpp index 02f7b4f34..db2bdb7ee 100644 --- a/src/Nazara/Shader/SpirvConstantCache.cpp +++ b/src/Nazara/Shader/SpirvConstantCache.cpp @@ -12,6 +12,12 @@ namespace Nz { + namespace + { + template struct overloaded : Ts... { using Ts::operator()...; }; + + template overloaded(Ts...)->overloaded; + } struct SpirvConstantCache::Eq { bool Compare(const ConstantBool& lhs, const ConstantBool& rhs) const @@ -381,8 +387,7 @@ namespace Nz { } - tsl::ordered_map constantIds; - tsl::ordered_map typeIds; + tsl::ordered_map, UInt32 /*id*/, AnyHasher, Eq> ids; tsl::ordered_map variableIds; tsl::ordered_map structureSizes; UInt32& nextResultId; @@ -399,8 +404,8 @@ namespace Nz UInt32 SpirvConstantCache::GetId(const Constant& c) { - auto it = m_internal->constantIds.find(c.constant); - if (it == m_internal->constantIds.end()) + auto it = m_internal->ids.find(c.constant); + if (it == m_internal->ids.end()) throw std::runtime_error("constant is not registered"); return it->second; @@ -408,8 +413,8 @@ namespace Nz UInt32 SpirvConstantCache::GetId(const Type& t) { - auto it = m_internal->typeIds.find(t.type); - if (it == m_internal->typeIds.end()) + auto it = m_internal->ids.find(t.type); + if (it == m_internal->ids.end()) throw std::runtime_error("constant is not registered"); return it->second; @@ -431,12 +436,12 @@ namespace Nz DepRegisterer registerer(*this); registerer.Register(constant); - std::size_t h = m_internal->typeIds.hash_function()(constant); - auto it = m_internal->constantIds.find(constant, h); - if (it == m_internal->constantIds.end()) + std::size_t h = m_internal->ids.hash_function()(constant); + auto it = m_internal->ids.find(constant, h); + if (it == m_internal->ids.end()) { UInt32 resultId = m_internal->nextResultId++; - it = m_internal->constantIds.emplace(std::move(constant), resultId).first; + it = m_internal->ids.emplace(std::move(constant), resultId).first; } return it.value(); @@ -449,12 +454,12 @@ namespace Nz DepRegisterer registerer(*this); registerer.Register(type); - std::size_t h = m_internal->typeIds.hash_function()(type); - auto it = m_internal->typeIds.find(type, h); - if (it == m_internal->typeIds.end()) + std::size_t h = m_internal->ids.hash_function()(type); + auto it = m_internal->ids.find(type, h); + if (it == m_internal->ids.end()) { UInt32 resultId = m_internal->nextResultId++; - it = m_internal->typeIds.emplace(std::move(type), resultId).first; + it = m_internal->ids.emplace(std::move(type), resultId).first; } return it.value(); @@ -476,131 +481,19 @@ namespace Nz return it.value(); } - void SpirvConstantCache::Write(SpirvSection& annotations, SpirvSection& constants, SpirvSection& debugInfos, SpirvSection& types) + void SpirvConstantCache::Write(SpirvSection& annotations, SpirvSection& constants, SpirvSection& debugInfos) { - for (auto&& [type, id] : m_internal->typeIds) + for (auto&& [type, id] : m_internal->ids) { UInt32 resultId = id; - std::visit([&](auto&& arg) + std::visit(overloaded { - using T = std::decay_t; - - if constexpr (std::is_same_v) - types.Append(SpirvOp::OpTypeBool, resultId); - else if constexpr (std::is_same_v) - types.Append(SpirvOp::OpTypeFloat, resultId, arg.width); - else if constexpr (std::is_same_v) - { - types.AppendVariadic(SpirvOp::OpTypeFunction, [&](const auto& appender) - { - appender(resultId); - appender(GetId(*arg.returnType)); - - for (const auto& param : arg.parameters) - appender(GetId(*param)); - }); - } - else if constexpr (std::is_same_v) - { - UInt32 depth; - if (arg.depth.has_value()) - depth = (*arg.depth) ? 1 : 0; - else - depth = 2; - - UInt32 sampled; - if (arg.sampled.has_value()) - sampled = (*arg.sampled) ? 1 : 0; - else - sampled = 2; - - types.AppendVariadic(SpirvOp::OpTypeImage, [&](const auto& appender) - { - appender(resultId); - appender(GetId(*arg.sampledType)); - appender(arg.dim); - appender(depth); - appender(arg.arrayed); - appender(arg.multisampled); - appender(sampled); - appender(arg.format); - - if (arg.qualifier) - appender(*arg.qualifier); - }); - } - else if constexpr (std::is_same_v) - types.Append(SpirvOp::OpTypeInt, resultId, arg.width, arg.signedness); - else if constexpr (std::is_same_v) - types.Append(SpirvOp::OpTypeMatrix, resultId, GetId(*arg.columnType), arg.columnCount); - else if constexpr (std::is_same_v) - types.Append(SpirvOp::OpTypePointer, resultId, arg.storageClass, GetId(*arg.type)); - else if constexpr (std::is_same_v) - types.Append(SpirvOp::OpTypeSampledImage, resultId, GetId(*arg.image)); - else if constexpr (std::is_same_v) - WriteStruct(arg, resultId, annotations, debugInfos, types); - else if constexpr (std::is_same_v) - types.Append(SpirvOp::OpTypeVector, resultId, GetId(*arg.componentType), arg.componentCount); - else if constexpr (std::is_same_v) - types.Append(SpirvOp::OpTypeVoid, resultId); - else - static_assert(AlwaysFalse::value, "non-exhaustive visitor"); + [&](const AnyConstant& constant) { Write(constant, resultId, constants); }, + [&](const AnyType& type) { Write(type, resultId, annotations, constants, debugInfos); }, }, type); } - for (auto&& [constant, id] : m_internal->constantIds) - { - UInt32 resultId = id; - - std::visit([&](auto&& arg) - { - using T = std::decay_t; - - if constexpr (std::is_same_v) - constants.Append((arg.value) ? SpirvOp::OpConstantTrue : SpirvOp::OpConstantFalse, resultId); - else if constexpr (std::is_same_v) - { - constants.AppendVariadic(SpirvOp::OpConstantComposite, [&](const auto& appender) - { - appender(GetId(arg.type->type)); - appender(resultId); - - for (const auto& value : arg.values) - appender(GetId(value->constant)); - }); - } - else if constexpr (std::is_same_v) - { - std::visit([&](auto&& arg) - { - using T = std::decay_t; - - UInt32 typeId; - if constexpr (std::is_same_v) - typeId = GetId({ Float{ 64 } }); - else if constexpr (std::is_same_v) - typeId = GetId({ Float{ 32 } }); - else if constexpr (std::is_same_v) - typeId = GetId({ Integer{ 32, 1 } }); - else if constexpr (std::is_same_v) - typeId = GetId({ Integer{ 64, 1 } }); - else if constexpr (std::is_same_v) - typeId = GetId({ Integer{ 32, 0 } }); - else if constexpr (std::is_same_v) - typeId = GetId({ Integer{ 64, 0 } }); - else - static_assert(AlwaysFalse::value, "non-exhaustive visitor"); - - constants.Append(SpirvOp::OpConstant, typeId, resultId, SpirvSection::Raw{ &arg, sizeof(arg) }); - - }, arg.value); - } - else - static_assert(AlwaysFalse::value, "non-exhaustive visitor"); - }, constant); - } - for (auto&& [variable, id] : m_internal->variableIds) { UInt32 resultId = id; @@ -781,9 +674,128 @@ namespace Nz }, type); } - void SpirvConstantCache::WriteStruct(const Structure& structData, UInt32 resultId, SpirvSection& annotations, SpirvSection& debugInfos, SpirvSection& types) + void SpirvConstantCache::Write(const AnyConstant& constant, UInt32 resultId, SpirvSection& constants) { - types.AppendVariadic(SpirvOp::OpTypeStruct, [&](const auto& appender) + std::visit([&](auto&& arg) + { + using T = std::decay_t; + + if constexpr (std::is_same_v) + constants.Append((arg.value) ? SpirvOp::OpConstantTrue : SpirvOp::OpConstantFalse, resultId); + else if constexpr (std::is_same_v) + { + constants.AppendVariadic(SpirvOp::OpConstantComposite, [&](const auto& appender) + { + appender(GetId(arg.type->type)); + appender(resultId); + + for (const auto& value : arg.values) + appender(GetId(value->constant)); + }); + } + else if constexpr (std::is_same_v) + { + std::visit([&](auto&& arg) + { + using T = std::decay_t; + + UInt32 typeId; + if constexpr (std::is_same_v) + typeId = GetId({ Float{ 64 } }); + else if constexpr (std::is_same_v) + typeId = GetId({ Float{ 32 } }); + else if constexpr (std::is_same_v) + typeId = GetId({ Integer{ 32, 1 } }); + else if constexpr (std::is_same_v) + typeId = GetId({ Integer{ 64, 1 } }); + else if constexpr (std::is_same_v) + typeId = GetId({ Integer{ 32, 0 } }); + else if constexpr (std::is_same_v) + typeId = GetId({ Integer{ 64, 0 } }); + else + static_assert(AlwaysFalse::value, "non-exhaustive visitor"); + + constants.Append(SpirvOp::OpConstant, typeId, resultId, SpirvSection::Raw{ &arg, sizeof(arg) }); + + }, arg.value); + } + else + static_assert(AlwaysFalse::value, "non-exhaustive visitor"); + }, constant); + } + + void SpirvConstantCache::Write(const AnyType& type, UInt32 resultId, SpirvSection& annotations, SpirvSection& constants, SpirvSection& debugInfos) + { + std::visit([&](auto&& arg) + { + using T = std::decay_t; + + if constexpr (std::is_same_v) + constants.Append(SpirvOp::OpTypeBool, resultId); + else if constexpr (std::is_same_v) + constants.Append(SpirvOp::OpTypeFloat, resultId, arg.width); + else if constexpr (std::is_same_v) + { + constants.AppendVariadic(SpirvOp::OpTypeFunction, [&](const auto& appender) + { + appender(resultId); + appender(GetId(*arg.returnType)); + + for (const auto& param : arg.parameters) + appender(GetId(*param)); + }); + } + else if constexpr (std::is_same_v) + { + UInt32 depth; + if (arg.depth.has_value()) + depth = (*arg.depth) ? 1 : 0; + else + depth = 2; + + UInt32 sampled; + if (arg.sampled.has_value()) + sampled = (*arg.sampled) ? 1 : 0; + else + sampled = 2; + + constants.AppendVariadic(SpirvOp::OpTypeImage, [&](const auto& appender) + { + appender(resultId); + appender(GetId(*arg.sampledType)); + appender(arg.dim); + appender(depth); + appender(arg.arrayed); + appender(arg.multisampled); + appender(sampled); + appender(arg.format); + + if (arg.qualifier) + appender(*arg.qualifier); + }); + } + else if constexpr (std::is_same_v) + constants.Append(SpirvOp::OpTypeInt, resultId, arg.width, arg.signedness); + else if constexpr (std::is_same_v) + constants.Append(SpirvOp::OpTypeMatrix, resultId, GetId(*arg.columnType), arg.columnCount); + else if constexpr (std::is_same_v) + constants.Append(SpirvOp::OpTypePointer, resultId, arg.storageClass, GetId(*arg.type)); + else if constexpr (std::is_same_v) + constants.Append(SpirvOp::OpTypeSampledImage, resultId, GetId(*arg.image)); + else if constexpr (std::is_same_v) + WriteStruct(arg, resultId, annotations, constants, debugInfos); + else if constexpr (std::is_same_v) + constants.Append(SpirvOp::OpTypeVector, resultId, GetId(*arg.componentType), arg.componentCount); + else if constexpr (std::is_same_v) + constants.Append(SpirvOp::OpTypeVoid, resultId); + else + static_assert(AlwaysFalse::value, "non-exhaustive visitor"); + }, type); + } + + void SpirvConstantCache::WriteStruct(const Structure& structData, UInt32 resultId, SpirvSection& annotations, SpirvSection& constants, SpirvSection& debugInfos) + { + constants.AppendVariadic(SpirvOp::OpTypeStruct, [&](const auto& appender) { appender(resultId); diff --git a/src/Nazara/Shader/SpirvWriter.cpp b/src/Nazara/Shader/SpirvWriter.cpp index 92630d506..7a1f41bff 100644 --- a/src/Nazara/Shader/SpirvWriter.cpp +++ b/src/Nazara/Shader/SpirvWriter.cpp @@ -192,7 +192,6 @@ namespace Nz SpirvSection constants; SpirvSection debugInfo; SpirvSection annotations; - SpirvSection types; SpirvSection instructions; }; @@ -398,7 +397,7 @@ namespace Nz assert(entryPointIndex != std::numeric_limits::max()); - m_currentState->constantTypeCache.Write(m_currentState->annotations, m_currentState->constants, m_currentState->debugInfo, m_currentState->types); + m_currentState->constantTypeCache.Write(m_currentState->annotations, m_currentState->constants, m_currentState->debugInfo); AppendHeader(); @@ -446,7 +445,6 @@ namespace Nz MergeBlocks(ret, state.header); MergeBlocks(ret, state.debugInfo); MergeBlocks(ret, state.annotations); - MergeBlocks(ret, state.types); MergeBlocks(ret, state.constants); MergeBlocks(ret, state.instructions); From 93de44d29304283ca2e0489269a40cf0cf33d7b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Sun, 23 Aug 2020 18:32:28 +0200 Subject: [PATCH 098/105] Big SpirVWriter refactor --- include/Nazara/Shader/ShaderAstVisitor.hpp | 4 +- .../Nazara/Shader/ShaderAstVisitorExcept.hpp | 36 + .../Nazara/Shader/ShaderVarVisitorExcept.hpp | 28 + include/Nazara/Shader/SpirvExpressionLoad.hpp | 64 ++ include/Nazara/Shader/SpirvExpressionLoad.inl | 16 + .../SpirvExpressionLoadAccessMember.hpp | 62 ++ .../SpirvExpressionLoadAccessMember.inl | 16 + .../Nazara/Shader/SpirvExpressionStore.hpp | 63 ++ .../Nazara/Shader/SpirvExpressionStore.inl | 16 + include/Nazara/Shader/SpirvPrinter.hpp | 42 ++ include/Nazara/Shader/SpirvPrinter.inl | 16 + .../Nazara/Shader/SpirvStatementVisitor.hpp | 43 ++ .../Nazara/Shader/SpirvStatementVisitor.inl | 16 + include/Nazara/Shader/SpirvWriter.hpp | 57 +- src/Nazara/Shader/ShaderAstVisitorExcept.cpp | 75 ++ src/Nazara/Shader/ShaderVarVisitorExcept.cpp | 40 ++ src/Nazara/Shader/SpirvExpressionLoad.cpp | 448 ++++++++++++ .../SpirvExpressionLoadAccessMember.cpp | 116 +++ src/Nazara/Shader/SpirvExpressionStore.cpp | 104 +++ src/Nazara/Shader/SpirvPrinter.cpp | 231 ++++++ src/Nazara/Shader/SpirvStatementVisitor.cpp | 49 ++ src/Nazara/Shader/SpirvWriter.cpp | 680 +++--------------- 22 files changed, 1604 insertions(+), 618 deletions(-) create mode 100644 include/Nazara/Shader/ShaderAstVisitorExcept.hpp create mode 100644 include/Nazara/Shader/ShaderVarVisitorExcept.hpp create mode 100644 include/Nazara/Shader/SpirvExpressionLoad.hpp create mode 100644 include/Nazara/Shader/SpirvExpressionLoad.inl create mode 100644 include/Nazara/Shader/SpirvExpressionLoadAccessMember.hpp create mode 100644 include/Nazara/Shader/SpirvExpressionLoadAccessMember.inl create mode 100644 include/Nazara/Shader/SpirvExpressionStore.hpp create mode 100644 include/Nazara/Shader/SpirvExpressionStore.inl create mode 100644 include/Nazara/Shader/SpirvPrinter.hpp create mode 100644 include/Nazara/Shader/SpirvPrinter.inl create mode 100644 include/Nazara/Shader/SpirvStatementVisitor.hpp create mode 100644 include/Nazara/Shader/SpirvStatementVisitor.inl create mode 100644 src/Nazara/Shader/ShaderAstVisitorExcept.cpp create mode 100644 src/Nazara/Shader/ShaderVarVisitorExcept.cpp create mode 100644 src/Nazara/Shader/SpirvExpressionLoad.cpp create mode 100644 src/Nazara/Shader/SpirvExpressionLoadAccessMember.cpp create mode 100644 src/Nazara/Shader/SpirvExpressionStore.cpp create mode 100644 src/Nazara/Shader/SpirvPrinter.cpp create mode 100644 src/Nazara/Shader/SpirvStatementVisitor.cpp diff --git a/include/Nazara/Shader/ShaderAstVisitor.hpp b/include/Nazara/Shader/ShaderAstVisitor.hpp index a6896cb2c..64dc35559 100644 --- a/include/Nazara/Shader/ShaderAstVisitor.hpp +++ b/include/Nazara/Shader/ShaderAstVisitor.hpp @@ -4,8 +4,8 @@ #pragma once -#ifndef NAZARA_SHADERVISITOR_HPP -#define NAZARA_SHADERVISITOR_HPP +#ifndef NAZARA_SHADERASTVISITOR_HPP +#define NAZARA_SHADERASTVISITOR_HPP #include #include diff --git a/include/Nazara/Shader/ShaderAstVisitorExcept.hpp b/include/Nazara/Shader/ShaderAstVisitorExcept.hpp new file mode 100644 index 000000000..40635477c --- /dev/null +++ b/include/Nazara/Shader/ShaderAstVisitorExcept.hpp @@ -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 +#include +#include + +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 diff --git a/include/Nazara/Shader/ShaderVarVisitorExcept.hpp b/include/Nazara/Shader/ShaderVarVisitorExcept.hpp new file mode 100644 index 000000000..3fa769e21 --- /dev/null +++ b/include/Nazara/Shader/ShaderVarVisitorExcept.hpp @@ -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 +#include + +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 diff --git a/include/Nazara/Shader/SpirvExpressionLoad.hpp b/include/Nazara/Shader/SpirvExpressionLoad.hpp new file mode 100644 index 000000000..a766e568d --- /dev/null +++ b/include/Nazara/Shader/SpirvExpressionLoad.hpp @@ -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 +#include +#include +#include +#include + +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 m_resultIds; + SpirvWriter& m_writer; + }; +} + +#include + +#endif diff --git a/include/Nazara/Shader/SpirvExpressionLoad.inl b/include/Nazara/Shader/SpirvExpressionLoad.inl new file mode 100644 index 000000000..966aae912 --- /dev/null +++ b/include/Nazara/Shader/SpirvExpressionLoad.inl @@ -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 +#include + +namespace Nz +{ + inline SpirvExpressionLoad::SpirvExpressionLoad(SpirvWriter& writer) : + m_writer(writer) + { + } +} + +#include diff --git a/include/Nazara/Shader/SpirvExpressionLoadAccessMember.hpp b/include/Nazara/Shader/SpirvExpressionLoadAccessMember.hpp new file mode 100644 index 000000000..8e2e0ff3b --- /dev/null +++ b/include/Nazara/Shader/SpirvExpressionLoadAccessMember.hpp @@ -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 +#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 new file mode 100644 index 000000000..d81cfbb9c --- /dev/null +++ b/include/Nazara/Shader/SpirvExpressionLoadAccessMember.inl @@ -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 +#include + +namespace Nz +{ + inline SpirvExpressionLoadAccessMember::SpirvExpressionLoadAccessMember(SpirvWriter& writer) : + m_writer(writer) + { + } +} + +#include diff --git a/include/Nazara/Shader/SpirvExpressionStore.hpp b/include/Nazara/Shader/SpirvExpressionStore.hpp new file mode 100644 index 000000000..d7d37e39d --- /dev/null +++ b/include/Nazara/Shader/SpirvExpressionStore.hpp @@ -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 +#include +#include +#include +#include + +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 m_value; + }; +} + +#include + +#endif diff --git a/include/Nazara/Shader/SpirvExpressionStore.inl b/include/Nazara/Shader/SpirvExpressionStore.inl new file mode 100644 index 000000000..558a2aee8 --- /dev/null +++ b/include/Nazara/Shader/SpirvExpressionStore.inl @@ -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 +#include + +namespace Nz +{ + inline SpirvExpressionStore::SpirvExpressionStore(SpirvWriter& writer) : + m_writer(writer) + { + } +} + +#include diff --git a/include/Nazara/Shader/SpirvPrinter.hpp b/include/Nazara/Shader/SpirvPrinter.hpp new file mode 100644 index 000000000..b3e359fb5 --- /dev/null +++ b/include/Nazara/Shader/SpirvPrinter.hpp @@ -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 +#include +#include + +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 + +#endif diff --git a/include/Nazara/Shader/SpirvPrinter.inl b/include/Nazara/Shader/SpirvPrinter.inl new file mode 100644 index 000000000..f81ee5c21 --- /dev/null +++ b/include/Nazara/Shader/SpirvPrinter.inl @@ -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 +#include + +namespace Nz +{ + inline SpirvPrinter::SpirvPrinter() : + m_currentState(nullptr) + { + } +} + +#include diff --git a/include/Nazara/Shader/SpirvStatementVisitor.hpp b/include/Nazara/Shader/SpirvStatementVisitor.hpp new file mode 100644 index 000000000..1ba88942c --- /dev/null +++ b/include/Nazara/Shader/SpirvStatementVisitor.hpp @@ -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 +#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/SpirvStatementVisitor.inl b/include/Nazara/Shader/SpirvStatementVisitor.inl new file mode 100644 index 000000000..fc2274c10 --- /dev/null +++ b/include/Nazara/Shader/SpirvStatementVisitor.inl @@ -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 +#include + +namespace Nz +{ + inline SpirvStatementVisitor::SpirvStatementVisitor(SpirvWriter& writer) : + m_writer(writer) + { + } +} + +#include diff --git a/include/Nazara/Shader/SpirvWriter.hpp b/include/Nazara/Shader/SpirvWriter.hpp index 579ad1fef..8bb38087b 100644 --- a/include/Nazara/Shader/SpirvWriter.hpp +++ b/include/Nazara/Shader/SpirvWriter.hpp @@ -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& 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 ReadInputVariable(const std::string& name, OnlyCache); + UInt32 ReadLocalVariable(const std::string& name); + std::optional ReadLocalVariable(const std::string& name, OnlyCache); + UInt32 ReadUniformVariable(const std::string& name); + std::optional ReadUniformVariable(const std::string& name, OnlyCache); UInt32 ReadVariable(ExtVar& var); + std::optional ReadVariable(const ExtVar& var, OnlyCache); + UInt32 RegisterConstant(const ShaderConstantValue& value); UInt32 RegisterFunctionType(ShaderExpressionType retType, const std::vector& 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& 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 valueId; + }; + struct State; Context m_context; diff --git a/src/Nazara/Shader/ShaderAstVisitorExcept.cpp b/src/Nazara/Shader/ShaderAstVisitorExcept.cpp new file mode 100644 index 000000000..e61fcdb8c --- /dev/null +++ b/src/Nazara/Shader/ShaderAstVisitorExcept.cpp @@ -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 +#include +#include + +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"); + } +} diff --git a/src/Nazara/Shader/ShaderVarVisitorExcept.cpp b/src/Nazara/Shader/ShaderVarVisitorExcept.cpp new file mode 100644 index 000000000..57b5bdddc --- /dev/null +++ b/src/Nazara/Shader/ShaderVarVisitorExcept.cpp @@ -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 +#include +#include + +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"); + } +} diff --git a/src/Nazara/Shader/SpirvExpressionLoad.cpp b/src/Nazara/Shader/SpirvExpressionLoad.cpp new file mode 100644 index 000000000..b032326fb --- /dev/null +++ b/src/Nazara/Shader/SpirvExpressionLoad.cpp @@ -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 +#include +#include +#include +#include +#include +#include + +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(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 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(); + } + + 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(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)); + } + + 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; + } +} diff --git a/src/Nazara/Shader/SpirvExpressionLoadAccessMember.cpp b/src/Nazara/Shader/SpirvExpressionLoadAccessMember.cpp new file mode 100644 index 000000000..c59bd806d --- /dev/null +++ b/src/Nazara/Shader/SpirvExpressionLoadAccessMember.cpp @@ -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 +#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/SpirvExpressionStore.cpp b/src/Nazara/Shader/SpirvExpressionStore.cpp new file mode 100644 index 000000000..109ad53c3 --- /dev/null +++ b/src/Nazara/Shader/SpirvExpressionStore.cpp @@ -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 +#include +#include +#include + +namespace Nz +{ + namespace + { + template struct overloaded : Ts... { using Ts::operator()...; }; + template overloaded(Ts...)->overloaded; + } + + 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 }; + } +} diff --git a/src/Nazara/Shader/SpirvPrinter.cpp b/src/Nazara/Shader/SpirvPrinter.cpp new file mode 100644 index 000000000..4b21ed840 --- /dev/null +++ b/src/Nazara/Shader/SpirvPrinter.cpp @@ -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 +#include +#include +#include +#include +#include +#include +#include + +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((firstWord >> 16) & 0xFFFF); + UInt16 opcode = static_cast(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((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++]; + } +} diff --git a/src/Nazara/Shader/SpirvStatementVisitor.cpp b/src/Nazara/Shader/SpirvStatementVisitor.cpp new file mode 100644 index 000000000..312879375 --- /dev/null +++ b/src/Nazara/Shader/SpirvStatementVisitor.cpp @@ -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 +#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 7a1f41bff..8412a1491 100644 --- a/src/Nazara/Shader/SpirvWriter.cpp +++ b/src/Nazara/Shader/SpirvWriter.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -154,14 +155,6 @@ namespace Nz } } - struct SpirvWriter::ExtVar - { - UInt32 pointerTypeId; - UInt32 typeId; - UInt32 varId; - std::optional 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 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 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 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 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(*node.structExpr); - switch (identifier.var->GetType()) - { - case ShaderNodes::VariableType::BuiltinVariable: - { - auto& builtinvar = static_cast(*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(*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(*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(*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(*node.left); - switch (identifier.var->GetType()) - { - case ShaderNodes::VariableType::BuiltinVariable: - { - auto& builtinvar = static_cast(*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(*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(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 = 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(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 = 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(*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(vecExprType)); - - ShaderNodes::BasicType vecType = std::get(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(targetExprType)); - - ShaderNodes::BasicType targetType = std::get(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& output, const SpirvSection& from) From 6c379eff68b05a10b7c6b33911388b422f99bdde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Sun, 23 Aug 2020 18:32:31 +0200 Subject: [PATCH 099/105] Update vert.shader --- examples/bin/vert.shader | Bin 695 -> 695 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/examples/bin/vert.shader b/examples/bin/vert.shader index 2d5c2daca53655ae10ead8e456b58e596ff8c89c..69183b00d8989495f81ecd69d9b201ca392f5af0 100644 GIT binary patch delta 41 ucmdnax}9~yLB`2P85J2BC+}j^VP#}sU|^cOk5L26Vw`NsWHh;$$prxJUJ0@Q delta 43 scmdnax}9~yLB`2@8C6*sfPiW8K1LNVixI?{?82l!xrb44atD(>0R89+?*IS* 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 100/105] 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) From ba777ebbcac9dfad05e3511e4ee38a8ff440ee64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Mon, 24 Aug 2020 16:49:14 +0200 Subject: [PATCH 101/105] Shader/SpirvPrinter: Add settings --- include/Nazara/Shader/SpirvPrinter.hpp | 10 +- src/Nazara/Shader/SpirvPrinter.cpp | 259 +++++++++++++------------ 2 files changed, 146 insertions(+), 123 deletions(-) diff --git a/include/Nazara/Shader/SpirvPrinter.hpp b/include/Nazara/Shader/SpirvPrinter.hpp index b3e359fb5..101a49437 100644 --- a/include/Nazara/Shader/SpirvPrinter.hpp +++ b/include/Nazara/Shader/SpirvPrinter.hpp @@ -16,16 +16,24 @@ namespace Nz class NAZARA_SHADER_API SpirvPrinter { public: + struct Settings; + inline SpirvPrinter(); SpirvPrinter(const SpirvPrinter&) = default; SpirvPrinter(SpirvPrinter&&) = default; ~SpirvPrinter() = default; - std::string Print(const UInt32* codepoints, std::size_t count); + std::string Print(const UInt32* codepoints, std::size_t count, const Settings& settings = Settings()); SpirvPrinter& operator=(const SpirvPrinter&) = default; SpirvPrinter& operator=(SpirvPrinter&&) = default; + struct Settings + { + bool printHeader = true; + bool printParameters = true; + }; + private: void AppendInstruction(); std::string ReadString(); diff --git a/src/Nazara/Shader/SpirvPrinter.cpp b/src/Nazara/Shader/SpirvPrinter.cpp index 4b21ed840..964baf129 100644 --- a/src/Nazara/Shader/SpirvPrinter.cpp +++ b/src/Nazara/Shader/SpirvPrinter.cpp @@ -19,13 +19,18 @@ namespace Nz std::size_t index = 0; std::size_t count; std::ostringstream stream; + const Settings& settings; }; - std::string SpirvPrinter::Print(const UInt32* codepoints, std::size_t count) + std::string SpirvPrinter::Print(const UInt32* codepoints, std::size_t count, const Settings& settings) { - State state; - state.codepoints = codepoints; - state.count = count; + State state = { + codepoints, + 0, + count, + {}, + settings + }; m_currentState = &state; CallOnExit resetOnExit([&] { m_currentState = nullptr; }); @@ -34,7 +39,8 @@ namespace Nz if (magicNumber != SpvMagicNumber) throw std::runtime_error("invalid Spir-V: magic number didn't match"); - m_currentState->stream << "Spir-V module\n"; + if (m_currentState->settings.printHeader) + m_currentState->stream << "Spir-V module\n"; UInt32 versionNumber = ReadWord(); if (versionNumber > SpvVersion) @@ -43,17 +49,17 @@ namespace Nz 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"; + + if (m_currentState->settings.printHeader) + { + m_currentState->stream << "Version " + std::to_string(+majorVersion) << "." << std::to_string(+minorVersion) << "\n"; + m_currentState->stream << "Generator: " << std::to_string(generatorId) << "\n"; + m_currentState->stream << "Bound: " << std::to_string(bound) << "\n"; + m_currentState->stream << "Schema: " << std::to_string(schema) << "\n"; + } while (m_currentState->index < m_currentState->count) AppendInstruction(); @@ -76,126 +82,135 @@ namespace Nz m_currentState->stream << inst->name; - std::size_t currentOperand = 0; - std::size_t instructionEnd = startIndex + wordCount; - while (m_currentState->index < instructionEnd) + if (m_currentState->settings.printParameters) { - const SpirvInstruction::Operand* operand = &inst->operands[currentOperand]; - - m_currentState->stream << " " << operand->name << "("; - - switch (operand->kind) + std::size_t currentOperand = 0; + std::size_t instructionEnd = startIndex + wordCount; + while (m_currentState->index < instructionEnd) { - 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 + const SpirvInstruction::Operand* operand = &inst->operands[currentOperand]; + + m_currentState->stream << " " << operand->name << "("; + + switch (operand->kind) { - 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) + 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 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); + 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; } - */ - break; - } - case SpirvOperandKind::PairLiteralIntegerIdRef: - { - ReadWord(); - ReadWord(); - 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; + } - 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 << ")"; - - if (currentOperand < inst->minOperandCount - 1) - currentOperand++; + } + else + { + m_currentState->index += wordCount - 1; + if (m_currentState->index > m_currentState->count) + throw std::runtime_error("unexpected end of stream"); } m_currentState->stream << "\n"; From f5fa211609e1e9833aa515651a0f4869b96a7ca7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Mon, 24 Aug 2020 16:49:38 +0200 Subject: [PATCH 102/105] ShaderAstCloner: Fix Swizzle case --- src/Nazara/Shader/ShaderAstCloner.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Nazara/Shader/ShaderAstCloner.cpp b/src/Nazara/Shader/ShaderAstCloner.cpp index 39754b7a9..90c7c909d 100644 --- a/src/Nazara/Shader/ShaderAstCloner.cpp +++ b/src/Nazara/Shader/ShaderAstCloner.cpp @@ -140,7 +140,7 @@ namespace Nz void ShaderAstCloner::Visit(ShaderNodes::SwizzleOp& node) { - PushExpression(ShaderNodes::SwizzleOp::Build(PopExpression(), node.components.data(), node.componentCount)); + PushExpression(ShaderNodes::SwizzleOp::Build(CloneExpression(node.expression), node.components.data(), node.componentCount)); } void ShaderAstCloner::Visit(ShaderNodes::BuiltinVariable& var) From 63f259b907f6610c246b0b40b73fa36b5f352b19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Mon, 24 Aug 2020 16:49:59 +0200 Subject: [PATCH 103/105] SpirvAstVisitor: Add safety assert --- src/Nazara/Shader/SpirvAstVisitor.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Nazara/Shader/SpirvAstVisitor.cpp b/src/Nazara/Shader/SpirvAstVisitor.cpp index d66f76170..6cf45cee7 100644 --- a/src/Nazara/Shader/SpirvAstVisitor.cpp +++ b/src/Nazara/Shader/SpirvAstVisitor.cpp @@ -15,6 +15,8 @@ namespace Nz UInt32 SpirvAstVisitor::EvaluateExpression(const ShaderNodes::ExpressionPtr& expr) { Visit(expr); + + assert(m_resultIds.size() == 1); return PopResultId(); } From 9b313dac2e5539e34318d9c740fb7bd027508e8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Mon, 24 Aug 2020 17:14:01 +0200 Subject: [PATCH 104/105] Quality of life improvements --- include/Nazara/Shader/ShaderAst.hpp | 6 +++--- include/Nazara/Shader/ShaderNodes.hpp | 1 + include/Nazara/Shader/ShaderNodes.inl | 5 +++++ 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/include/Nazara/Shader/ShaderAst.hpp b/include/Nazara/Shader/ShaderAst.hpp index 11b39d5e9..6f384c18f 100644 --- a/include/Nazara/Shader/ShaderAst.hpp +++ b/include/Nazara/Shader/ShaderAst.hpp @@ -34,10 +34,10 @@ namespace Nz ~ShaderAst() = default; void AddFunction(std::string name, ShaderNodes::StatementPtr statement, std::vector parameters = {}, ShaderNodes::BasicType returnType = ShaderNodes::BasicType::Void); - void AddInput(std::string name, ShaderExpressionType type, std::optional locationIndex); - void AddOutput(std::string name, ShaderExpressionType type, std::optional locationIndex); + void AddInput(std::string name, ShaderExpressionType type, std::optional locationIndex = {}); + void AddOutput(std::string name, ShaderExpressionType type, std::optional locationIndex = {}); void AddStruct(std::string name, std::vector members); - void AddUniform(std::string name, ShaderExpressionType type, std::optional bindingIndex, std::optional memoryLayout); + void AddUniform(std::string name, ShaderExpressionType type, std::optional bindingIndex = {}, std::optional memoryLayout = {}); inline const Function& GetFunction(std::size_t i) const; inline std::size_t GetFunctionCount() const; diff --git a/include/Nazara/Shader/ShaderNodes.hpp b/include/Nazara/Shader/ShaderNodes.hpp index 15898af3f..b3af5f1aa 100644 --- a/include/Nazara/Shader/ShaderNodes.hpp +++ b/include/Nazara/Shader/ShaderNodes.hpp @@ -241,6 +241,7 @@ namespace Nz std::size_t componentCount; ExpressionPtr expression; + static inline std::shared_ptr Build(ExpressionPtr expressionPtr, SwizzleComponent swizzleComponent); static inline std::shared_ptr Build(ExpressionPtr expressionPtr, std::initializer_list swizzleComponents); static inline std::shared_ptr Build(ExpressionPtr expressionPtr, const SwizzleComponent* components, std::size_t componentCount); }; diff --git a/include/Nazara/Shader/ShaderNodes.inl b/include/Nazara/Shader/ShaderNodes.inl index 77bc813f3..1e0817b62 100644 --- a/include/Nazara/Shader/ShaderNodes.inl +++ b/include/Nazara/Shader/ShaderNodes.inl @@ -284,6 +284,11 @@ namespace Nz::ShaderNodes { } + inline std::shared_ptr SwizzleOp::Build(ExpressionPtr expressionPtr, SwizzleComponent swizzleComponent) + { + return Build(std::move(expressionPtr), { swizzleComponent }); + } + inline std::shared_ptr SwizzleOp::Build(ExpressionPtr expressionPtr, std::initializer_list swizzleComponents) { auto node = std::make_shared(); From f24e48e2dc955dfd0131915e501f76f0773212df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Tue, 25 Aug 2020 12:16:17 +0200 Subject: [PATCH 105/105] Rework build system to handle better external libs --- build/{config.lua => config.lua.default.lua} | 15 ++++ build/scripts/common.lua | 49 +++++++----- build/scripts/tools/shadernodes.lua | 84 ++++++++++++++++---- 3 files changed, 109 insertions(+), 39 deletions(-) rename build/{config.lua => config.lua.default.lua} (57%) diff --git a/build/config.lua b/build/config.lua.default.lua similarity index 57% rename from build/config.lua rename to build/config.lua.default.lua index 16bf08d33..b30566fcb 100644 --- a/build/config.lua +++ b/build/config.lua.default.lua @@ -24,3 +24,18 @@ ServerMode = false -- Builds modules as one united library (useless on POSIX systems) UniteModules = false + +-- Qt5 directories (required for ShaderNodes editor) +--Qt5IncludeDir = [[C:\Projets\Libs\Qt\5.15.0\msvc2019\include]] +--Qt5BinDir_x86 = [[C:\Projets\Libs\Qt\5.15.0\msvc2019\bin]] +--Qt5BinDir_x64 = [[C:\Projets\Libs\Qt\5.15.0\msvc2019_64\bin]] +--Qt5LibDir_x86 = [[C:\Projets\Libs\Qt\5.15.0\msvc2019\lib]] +--Qt5LibDir_x64 = [[C:\Projets\Libs\Qt\5.15.0\msvc2019_64\lib]] + + +-- QtNodes directories (required for ShaderNodes editor) +--QtNodesIncludeDir = [[C:\Projets\Libs\nodeeditor\include]] +--QtNodesBinDir_x86 = [[C:\Projets\Libs\nodeeditor\build32\bin\Release]] +--QtNodesBinDir_x64 = [[C:\Projets\Libs\nodeeditor\build64\bin\Release]] +--QtNodesLibDir_x86 = [[C:\Projets\Libs\nodeeditor\build32\lib\Release]] +--QtNodesLibDir_x64 = [[C:\Projets\Libs\nodeeditor\build64\lib\Release]] \ No newline at end of file diff --git a/build/scripts/common.lua b/build/scripts/common.lua index 1564b9505..1edf10fd3 100644 --- a/build/scripts/common.lua +++ b/build/scripts/common.lua @@ -699,6 +699,24 @@ local PosixOSes = { ["solaris"] = true } +local function ProcessOption(libName, option, enable) + return libName:gsub("%%" .. option .. "%((.+)%)", enable and "%1" or "") +end + +local function HandleLib(infoTable, libName) + local debugDynamic = ProcessOption(ProcessOption(libName, "d", true), "s", false) + local debugStatic = ProcessOption(ProcessOption(libName, "d", true), "s", true) + local releaseStatic = ProcessOption(ProcessOption(libName, "d", false), "s", true) + local releaseDynamic = ProcessOption(ProcessOption(libName, "d", false), "s", false) + + table.insert(infoTable.ConfigurationLibraries.DebugStatic, debugStatic) + table.insert(infoTable.ConfigurationLibraries.ReleaseStatic, releaseStatic) + table.insert(infoTable.ConfigurationLibraries.ReleaseWithDebugStatic, releaseStatic) + table.insert(infoTable.ConfigurationLibraries.DebugDynamic, debugDynamic) + table.insert(infoTable.ConfigurationLibraries.ReleaseDynamic, releaseDynamic) + table.insert(infoTable.ConfigurationLibraries.ReleaseWithDebugDynamic, releaseDynamic) +end + function NazaraBuild:Process(infoTable) if (infoTable.Excluded) then return false @@ -718,16 +736,11 @@ function NazaraBuild:Process(infoTable) if (_OPTIONS["united"]) then library = "NazaraEngine" else - library = "Nazara" .. libraryTable.Name + library = "Nazara" .. libraryTable.Name .. "%s(-s)%d(-d)" end if (not self.Config["UniteModules"] or infoTable.Type ~= "Module") then - table.insert(infoTable.ConfigurationLibraries.DebugStatic, library .. "-s-d") - table.insert(infoTable.ConfigurationLibraries.ReleaseStatic, library .. "-s") - table.insert(infoTable.ConfigurationLibraries.ReleaseWithDebugStatic, library .. "-s") - table.insert(infoTable.ConfigurationLibraries.DebugDynamic, library .. "-d") - table.insert(infoTable.ConfigurationLibraries.ReleaseDynamic, library) - table.insert(infoTable.ConfigurationLibraries.ReleaseWithDebugDynamic, library) + HandleLib(infoTable, library) end elseif (libraryTable.Type == "ExternLib") then library = libraryTable.Name @@ -735,15 +748,10 @@ function NazaraBuild:Process(infoTable) if (self.Config["BuildDependencies"]) then table.insert(libraries, library) else - table.insert(infoTable.ConfigurationLibraries.DebugStatic, library .. "-s-d") - table.insert(infoTable.ConfigurationLibraries.ReleaseStatic, library .. "-s") - table.insert(infoTable.ConfigurationLibraries.ReleaseWithDebugStatic, library .. "-s") - table.insert(infoTable.ConfigurationLibraries.DebugDynamic, library .. "-s-d") - table.insert(infoTable.ConfigurationLibraries.ReleaseDynamic, library .. "-s") - table.insert(infoTable.ConfigurationLibraries.ReleaseWithDebugDynamic, library .. "-s") + HandleLib(infoTable, library) end elseif (libraryTable.Type == "Tool") then - library = "Nazara" .. libraryTable.Name + library = "Nazara" .. libraryTable.Name .. "%s(-s)%d(-d)" -- Import tools includes for k,v in ipairs(libraryTable.Includes) do @@ -761,19 +769,14 @@ function NazaraBuild:Process(infoTable) end end - table.insert(infoTable.ConfigurationLibraries.DebugStatic, library .. "-s-d") - table.insert(infoTable.ConfigurationLibraries.ReleaseStatic, library .. "-s") - table.insert(infoTable.ConfigurationLibraries.ReleaseWithDebugStatic, library .. "-s") - table.insert(infoTable.ConfigurationLibraries.DebugDynamic, library .. "-d") - table.insert(infoTable.ConfigurationLibraries.ReleaseDynamic, library) - table.insert(infoTable.ConfigurationLibraries.ReleaseWithDebugDynamic, library) + HandleLib(infoTable, library) else infoTable.Excluded = true infoTable.ExcludeReason = "dependency " .. library .. " has invalid type \"" .. libraryTable.Type .. "\"" return false end else - table.insert(libraries, library) + HandleLib(infoTable, library) end end infoTable.Libraries = libraries @@ -881,9 +884,11 @@ function NazaraBuild:PreconfigGenericProject() filter("configurations:*Dynamic") kind("SharedLib") - -- Enable MSVC conformance (not required but better) + -- Enable MSVC conformance (not required but better) and some extra warnings filter("action:vs*") buildoptions({"/permissive-", "/Zc:__cplusplus", "/Zc:referenceBinding", "/Zc:throwingNew"}) + --enablewarnings("4062") -- switch case not handled + buildoptions("/w44062") -- looks like enablewarnings is broken currently for msvc -- Enable SSE math and vectorization optimizations filter({"configurations:Release*", clangGccActions}) diff --git a/build/scripts/tools/shadernodes.lua b/build/scripts/tools/shadernodes.lua index bcf9a1593..cc0b63cb3 100644 --- a/build/scripts/tools/shadernodes.lua +++ b/build/scripts/tools/shadernodes.lua @@ -12,12 +12,7 @@ TOOL.Defines = { TOOL.Includes = { "../include", "../extlibs/include", - "../src", - [[C:\Projets\Libs\Qt\5.15.0\msvc2019_64\include]], - [[C:\Projets\Libs\Qt\5.15.0\msvc2019_64\include\QtCore]], - [[C:\Projets\Libs\Qt\5.15.0\msvc2019_64\include\QtGui]], - [[C:\Projets\Libs\Qt\5.15.0\msvc2019_64\include\QtWidgets]], - [[C:\Projets\Libs\nodeeditor\include]], + "../src" } TOOL.Files = { @@ -27,16 +22,71 @@ TOOL.Files = { } TOOL.Libraries = { - "NazaraCore", - "NazaraShader", - "NazaraUtility", - "Qt5Cored", - "Qt5Guid", - "Qt5Widgetsd", - "nodes" + "NazaraCore%s(-s)%d(-d)", + "NazaraShader%s(-s)%d(-d)", + "NazaraUtility%s(-s)%d(-d)", + "Qt5Core%d(d)", + "Qt5Gui%d(d)", + "Qt5Widgets%d(d)", + "nodes%d(d)" } -TOOL.LibraryPaths.x64 = { - [[C:\Projets\Libs\Qt\5.15.0\msvc2019_64\lib]], - [[C:\Projets\Libs\nodeeditor\build\lib\Debug]] -} +local function AppendValues(tab, value) + if (type(value) == "table") then + for _, v in pairs(value) do + AppendValues(tab, v) + end + else + table.insert(tab, value) + end +end + +function TOOL:ValidateLib(libName) + local config = NazaraBuild:GetConfig() + local includes = config[libName .. "IncludeDir"] + local binDir32 = config[libName .. "BinDir_x86"] + local binDir64 = config[libName .. "BinDir_x64"] + local libDir32 = config[libName .. "LibDir_x86"] + local libDir64 = config[libName .. "LibDir_x64"] + if (not includes) then + return false, "missing " .. libName .. " includes directories in config.lua" + end + + if (not libDir32 and not libDir64) then + return false, "missing " .. libName .. " library search directories in config.lua" + end + + AppendValues(self.Includes, includes) + + if (binDir32) then + AppendValues(self.BinaryPaths.x86, binDir32) + end + + if (binDir64) then + AppendValues(self.BinaryPaths.x64, binDir64) + end + + if (libDir32) then + AppendValues(self.LibraryPaths.x86, libDir32) + end + + if (libDir64) then + AppendValues(self.LibraryPaths.x64, libDir64) + end + + return true +end + +function TOOL:Validate() + local success, err = self:ValidateLib("Qt5") + if (not success) then + return false, err + end + + local success, err = self:ValidateLib("QtNodes") + if (not success) then + return false, err + end + + return true +end \ No newline at end of file