diff --git a/.gitignore b/.gitignore index 89008725c..478682d63 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,10 @@ # Nazara build build/config.lua +# Nazara binaries +bin/* + +# Build files build/gmake*/ build/vs*/ 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/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/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/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/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/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/shadernodes.lua b/build/scripts/tools/shadernodes.lua new file mode 100644 index 000000000..cc0b63cb3 --- /dev/null +++ b/build/scripts/tools/shadernodes.lua @@ -0,0 +1,92 @@ +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" +} + +TOOL.Files = { + "../src/ShaderNode/**.hpp", + "../src/ShaderNode/**.inl", + "../src/ShaderNode/**.cpp" +} + +TOOL.Libraries = { + "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)" +} + +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 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/examples/VulkanTest/main.cpp b/examples/VulkanTest/main.cpp index bfda1e2b2..54c34762c 100644 --- a/examples/VulkanTest/main.cpp +++ b/examples/VulkanTest/main.cpp @@ -3,8 +3,6 @@ #include #include -#define SPIRV 1 - int main() { Nz::Initializer loader; @@ -29,35 +27,19 @@ 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"); + 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::SpirV, "resources/shaders/triangle.vert.spv"); + auto vertexShader = device->InstantiateShaderStage(Nz::ShaderStageType::Vertex, Nz::ShaderLanguage::NazaraBinary, "vert.shader"); if (!vertexShader) { std::cout << "Failed to instantiate fragment shader" << std::endl; return __LINE__; } -#else - auto fragmentShader = device->InstantiateShaderStage(Nz::ShaderStageType::Fragment, Nz::ShaderLanguage::GLSL, "resources/shaders/triangle.frag"); - 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"); - if (!vertexShader) - { - std::cout << "Failed to instantiate fragment shader" << std::endl; - return __LINE__; - } -#endif Nz::MeshRef drfreak = Nz::Mesh::LoadFromFile("resources/Spaceship/spaceship.obj", meshParams); @@ -229,6 +211,8 @@ int main() Nz::Clock secondClock; unsigned int fps = 0; + Nz::Mouse::SetRelativeMouseMode(true); + while (window.IsOpen()) { Nz::WindowEvent event; @@ -252,10 +236,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; } } diff --git a/examples/bin/frag.shader b/examples/bin/frag.shader new file mode 100644 index 000000000..7ecc8951b Binary files /dev/null and b/examples/bin/frag.shader differ diff --git a/examples/bin/test.spirv b/examples/bin/test.spirv new file mode 100644 index 000000000..b88584775 Binary files /dev/null and b/examples/bin/test.spirv differ diff --git a/examples/bin/vert.shader b/examples/bin/vert.shader new file mode 100644 index 000000000..69183b00d Binary files /dev/null and b/examples/bin/vert.shader differ 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/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/Math/Vector2.hpp b/include/Nazara/Math/Vector2.hpp index c9dba6bfa..75e86f709 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); @@ -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 e22e00bc2..22eb72566 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]; @@ -451,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 99e3696df..4fd965484 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); @@ -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 1dcf48fe7..f9585d91e 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]; @@ -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 2938df3bb..5c5c9721f 100644 --- a/include/Nazara/Math/Vector4.hpp +++ b/include/Nazara/Math/Vector4.hpp @@ -54,15 +54,15 @@ 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); 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 6deadf5f5..dfc39aafe 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]; @@ -495,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/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/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/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/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/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/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) \ diff --git a/include/Nazara/Renderer.hpp b/include/Nazara/Renderer.hpp index fad7760fc..69153a0d4 100644 --- a/include/Nazara/Renderer.hpp +++ b/include/Nazara/Renderer.hpp @@ -36,7 +36,6 @@ #include #include #include -#include #include #include #include @@ -52,11 +51,8 @@ #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 a9b33ba5f..0b44ae629 100644 --- a/include/Nazara/Renderer/Enums.hpp +++ b/include/Nazara/Renderer/Enums.hpp @@ -49,27 +49,10 @@ namespace Nz GLSL, HLSL, MSL, + NazaraBinary, 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/GlslWriter.hpp b/include/Nazara/Renderer/GlslWriter.hpp deleted file mode 100644 index 8a06a3fbe..000000000 --- a/include/Nazara/Renderer/GlslWriter.hpp +++ /dev/null @@ -1,88 +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 - -#pragma once - -#ifndef NAZARA_GLSLWRITER_HPP -#define NAZARA_GLSLWRITER_HPP - -#include -#include -#include -#include -#include -#include - -namespace Nz -{ - class NAZARA_RENDERER_API GlslWriter : public ShaderWriter - { - public: - GlslWriter(); - GlslWriter(const GlslWriter&) = delete; - 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; - - void SetGlslVersion(unsigned int version); - - void Write(const ShaderAst::AssignOp& node) override; - void Write(const ShaderAst::Branch& 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::ExpressionStatement& node) override; - void Write(const ShaderAst::NamedVariable& node) override; - void Write(const ShaderAst::NodePtr& node) override; - void Write(const ShaderAst::StatementBlock& node) override; - void Write(const ShaderAst::SwizzleOp& node) override; - - private: - struct Function; - using VariableContainer = std::set>; - - 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()); - - void EnterScope(); - void LeaveScope(); - - - struct Function - { - VariableContainer variables; - std::vector parameters; - ShaderAst::ExpressionType retType; - ShaderAst::StatementPtr node; - String name; - }; - - struct State - { - VariableContainer inputs; - VariableContainer outputs; - VariableContainer uniforms; - StringStream stream; - unsigned int indentLevel = 0; - }; - - std::unordered_map m_functions; - Function* m_currentFunction; - State* m_currentState; - unsigned int m_glslVersion; - }; -} - -#endif // NAZARA_GLSLWRITER_HPP 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/ShaderAst.hpp b/include/Nazara/Renderer/ShaderAst.hpp deleted file mode 100644 index 549b45194..000000000 --- a/include/Nazara/Renderer/ShaderAst.hpp +++ /dev/null @@ -1,292 +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 - -#pragma once - -#ifndef NAZARA_SHADER_AST_HPP -#define NAZARA_SHADER_AST_HPP - -#include -#include -#include -#include -#include -#include -#include - -namespace Nz -{ - class ShaderWriter; - - namespace ShaderAst - { - enum class AssignType - { - Simple //< = - }; - - enum class BinaryType - { - Add, //< + - Substract, //< - - Multiply, //< * - Divide, //< / - Equality //< == - }; - - enum class BuiltinEntry - { - VertexPosition, // gl_Position - }; - - enum class ExpressionType - { - Boolean, // bool - Float1, // float - Float2, // vec2 - Float3, // vec3 - Float4, // vec4 - Mat4x4, // mat4 - - Void // void - }; - - 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() = default; - - virtual void Register(ShaderWriter& visitor) = 0; - virtual void Visit(ShaderWriter& visitor) = 0; - - static inline unsigned int GetComponentCount(ExpressionType type); - static inline ExpressionType GetComponentType(ExpressionType type); - }; - - class Statement; - - using StatementPtr = std::shared_ptr; - - class NAZARA_RENDERER_API Statement : public Node - { - }; - - class Expression; - - using ExpressionPtr = std::shared_ptr; - - class NAZARA_RENDERER_API Expression : public Node - { - public: - virtual ExpressionType GetExpressionType() const = 0; - }; - - class NAZARA_RENDERER_API ExpressionStatement : public Statement - { - public: - inline explicit ExpressionStatement(ExpressionPtr expr); - - void Register(ShaderWriter& visitor) override; - void Visit(ShaderWriter& visitor) override; - - ExpressionPtr expression; - }; - - ////////////////////////////////////////////////////////////////////////// - - class NAZARA_RENDERER_API ConditionalStatement : public Statement - { - public: - inline ConditionalStatement(const String& condition, StatementPtr statementPtr); - - void Register(ShaderWriter& visitor) override; - void Visit(ShaderWriter& visitor) override; - - String conditionName; - StatementPtr statement; - }; - - class NAZARA_RENDERER_API StatementBlock : public Statement - { - public: - template explicit StatementBlock(Args&&... args); - - void Register(ShaderWriter& visitor) override; - void Visit(ShaderWriter& visitor) override; - - std::vector statements; - }; - - class Variable; - - using VariablePtr = std::shared_ptr; - - class NAZARA_RENDERER_API Variable : public Expression - { - public: - inline Variable(VariableType varKind, ExpressionType varType); - - ExpressionType GetExpressionType() const override; - - ExpressionType type; - VariableType kind; - }; - - - class NAZARA_RENDERER_API BuiltinVariable : public Variable - { - public: - inline BuiltinVariable(BuiltinEntry variable, ExpressionType varType); - - void Register(ShaderWriter& visitor) override; - void Visit(ShaderWriter& visitor) override; - - BuiltinEntry var; - }; - - - class NamedVariable; - - using NamedVariablePtr = std::shared_ptr; - - class NAZARA_RENDERER_API NamedVariable : public Variable - { - public: - inline NamedVariable(VariableType varKind, const Nz::String& varName, ExpressionType varType); - - void Register(ShaderWriter& visitor) override; - void Visit(ShaderWriter& visitor) override; - - Nz::String name; - }; - - ////////////////////////////////////////////////////////////////////////// - - class NAZARA_RENDERER_API AssignOp : public Expression - { - public: - inline AssignOp(AssignType Op, VariablePtr Var, ExpressionPtr Right); - - ExpressionType GetExpressionType() const override; - void Register(ShaderWriter& visitor) override; - void Visit(ShaderWriter& visitor) override; - - AssignType op; - VariablePtr variable; - ExpressionPtr right; - }; - - class NAZARA_RENDERER_API BinaryOp : public Expression - { - public: - inline BinaryOp(BinaryType Op, ExpressionPtr Left, ExpressionPtr Right); - - ExpressionType GetExpressionType() const override; - void Register(ShaderWriter& visitor) override; - void Visit(ShaderWriter& visitor) override; - - BinaryType op; - ExpressionPtr left; - ExpressionPtr right; - }; - - class NAZARA_RENDERER_API Branch : public Statement - { - public: - inline Branch(ExpressionPtr condition, StatementPtr trueStatement, StatementPtr falseStatement = nullptr); - - void Register(ShaderWriter& visitor) override; - void Visit(ShaderWriter& visitor) override; - - struct ConditionalStatement - { - ExpressionPtr condition; - StatementPtr statement; - }; - - std::vector condStatements; - StatementPtr elseStatement; - }; - - class NAZARA_RENDERER_API Cast : public Expression - { - public: - inline Cast(ExpressionType castTo, ExpressionPtr first, ExpressionPtr second = nullptr, ExpressionPtr third = nullptr, ExpressionPtr fourth = nullptr); - - ExpressionType GetExpressionType() const override; - void Register(ShaderWriter& visitor) override; - void Visit(ShaderWriter& visitor) override; - - ExpressionType exprType; - std::array expressions; - }; - - class 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); - - ExpressionType GetExpressionType() const override; - void Register(ShaderWriter& visitor) override; - void Visit(ShaderWriter& visitor) override; - - ExpressionType exprType; - - union - { - bool bool1; - float vec1; - Vector2f vec2; - Vector3f vec3; - Vector4f vec4; - } values; - }; - - class NAZARA_RENDERER_API SwizzleOp : public Expression - { - public: - inline SwizzleOp(ExpressionPtr expressionPtr, std::initializer_list swizzleComponents); - - ExpressionType GetExpressionType() const override; - void Register(ShaderWriter& visitor) override; - void Visit(ShaderWriter& visitor) override; - - std::array components; - std::size_t componentCount; - ExpressionPtr expression; - }; - } -} - -#include - -#endif // NAZARA_SHADER_AST_HPP diff --git a/include/Nazara/Renderer/ShaderAst.inl b/include/Nazara/Renderer/ShaderAst.inl deleted file mode 100644 index 2235c9a74..000000000 --- a/include/Nazara/Renderer/ShaderAst.inl +++ /dev/null @@ -1,231 +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 - -namespace Nz -{ - namespace ShaderAst - { - 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(ExpressionPtr expr) : - expression(std::move(expr)) - { - } - - inline ConditionalStatement::ConditionalStatement(const String& condition, StatementPtr statementPtr) : - conditionName(condition), - statement(std::move(statementPtr)) - { - } - - template - StatementBlock::StatementBlock(Args&& ...args) : - statements({std::forward(args)...}) - { - } - - inline Variable::Variable(VariableType varKind, ExpressionType varType) : - type(varType), - kind(varKind) - { - } - - inline BuiltinVariable::BuiltinVariable(BuiltinEntry variable, ExpressionType varType) : - Variable(VariableType::Builtin, varType), - var(variable) - { - } - - inline NamedVariable::NamedVariable(VariableType varKind, const Nz::String& varName, ExpressionType varType) : - Variable(varKind, varType), - name(varName) - { - } - - inline AssignOp::AssignOp(AssignType Op, VariablePtr Var, ExpressionPtr Right) : - op(Op), - variable(std::move(Var)), - right(std::move(Right)) - { - } - - inline BinaryOp::BinaryOp(BinaryType Op, ExpressionPtr Left, ExpressionPtr Right) : - op(Op), - left(std::move(Left)), - right(std::move(Right)) - { - 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) - { - condStatements.emplace_back(ConditionalStatement{ std::move(condition), std::move(trueStatement) }); - elseStatement = std::move(falseStatement); - } - - inline Cast::Cast(ExpressionType castTo, ExpressionPtr first, ExpressionPtr second, ExpressionPtr third, ExpressionPtr fourth) : - exprType(castTo), - expressions({ {first, second, third, fourth} }) - { - 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"); - } - - inline Constant::Constant(bool value) : - exprType(ExpressionType::Boolean) - { - values.bool1 = value; - } - - inline Constant::Constant(float value) : - exprType(ExpressionType::Float1) - { - values.vec1 = value; - } - - inline Constant::Constant(const Vector2f& value) : - exprType(ExpressionType::Float2) - { - values.vec2 = value; - } - - inline Constant::Constant(const Vector3f& value) : - exprType(ExpressionType::Float3) - { - values.vec3 = value; - } - - inline Constant::Constant(const Vector4f& value) : - exprType(ExpressionType::Float4) - { - values.vec4 = value; - } - - inline SwizzleOp::SwizzleOp(ExpressionPtr expressionPtr, std::initializer_list swizzleComponents) : - componentCount(swizzleComponents.size()), - expression(expressionPtr) - { - if (componentCount > 4) - throw std::runtime_error("Cannot swizzle more than four elements"); - - 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()); - } - } -} - -#include diff --git a/include/Nazara/Renderer/ShaderBuilder.hpp b/include/Nazara/Renderer/ShaderBuilder.hpp deleted file mode 100644 index 79512e90f..000000000 --- a/include/Nazara/Renderer/ShaderBuilder.hpp +++ /dev/null @@ -1,79 +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 - -#pragma once - -#ifndef NAZARA_SHADER_BUILDER_HPP -#define NAZARA_SHADER_BUILDER_HPP - -#include -#include -#include - -namespace Nz { namespace ShaderBuilder -{ - template - struct AssignOpBuilder - { - constexpr AssignOpBuilder() {} - - std::shared_ptr operator()(const ShaderAst::VariablePtr& left, const ShaderAst::ExpressionPtr& right) const; - }; - - template - struct BinOpBuilder - { - constexpr BinOpBuilder() {} - - std::shared_ptr operator()(const ShaderAst::ExpressionPtr& left, const ShaderAst::ExpressionPtr& right) const; - }; - - struct BuiltinBuilder - { - constexpr BuiltinBuilder() {} - - inline std::shared_ptr operator()(ShaderAst::BuiltinEntry builtin) const; - }; - - template - struct GenBuilder - { - constexpr GenBuilder() {} - - template std::shared_ptr operator()(Args&&... args) const; - }; - - template - struct VarBuilder - { - constexpr VarBuilder() {} - - template std::shared_ptr operator()(Args&&... args) const; - }; - - constexpr BinOpBuilder Add; - constexpr AssignOpBuilder Assign; - constexpr BuiltinBuilder Builtin; - constexpr GenBuilder Block; - constexpr GenBuilder Branch; - constexpr GenBuilder ConditionalStatement; - constexpr GenBuilder Constant; - constexpr BinOpBuilder Divide; - constexpr BinOpBuilder Equal; - constexpr GenBuilder ExprStatement; - constexpr VarBuilder Input; - constexpr BinOpBuilder Multiply; - constexpr VarBuilder Output; - constexpr VarBuilder Parameter; - constexpr GenBuilder Swizzle; - constexpr BinOpBuilder Substract; - constexpr VarBuilder Uniform; - constexpr VarBuilder Variable; - - template std::shared_ptr Cast(Args&&... args); -} } - -#include - -#endif // NAZARA_SHADER_BUILDER_HPP diff --git a/include/Nazara/Renderer/ShaderBuilder.inl b/include/Nazara/Renderer/ShaderBuilder.inl deleted file mode 100644 index 89fa14c35..000000000 --- a/include/Nazara/Renderer/ShaderBuilder.inl +++ /dev/null @@ -1,59 +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 { namespace ShaderBuilder -{ - template - template - std::shared_ptr GenBuilder::operator()(Args&&... args) const - { - return std::make_shared(std::forward(args)...); - } - - template - std::shared_ptr AssignOpBuilder::operator()(const ShaderAst::VariablePtr& left, const ShaderAst::ExpressionPtr& right) const - { - return std::make_shared(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); - } - - inline std::shared_ptr BuiltinBuilder::operator()(ShaderAst::BuiltinEntry builtin) const - { - ShaderAst::ExpressionType exprType = ShaderAst::ExpressionType::Void; - - switch (builtin) - { - case ShaderAst::BuiltinEntry::VertexPosition: - exprType = ShaderAst::ExpressionType::Float4; - break; - } - - NazaraAssert(exprType != ShaderAst::ExpressionType::Void, "Unhandled builtin"); - - return std::make_shared(builtin, exprType); - } - - template - template - std::shared_ptr VarBuilder::operator()(Args&&... args) const - { - return std::make_shared(type, std::forward(args)...); - } - - template - std::shared_ptr Cast(Args&&... args) - { - return std::make_shared(Type, std::forward(args)...); - } -} } - -#include diff --git a/include/Nazara/Renderer/ShaderWriter.hpp b/include/Nazara/Renderer/ShaderWriter.hpp deleted file mode 100644 index f20061e05..000000000 --- a/include/Nazara/Renderer/ShaderWriter.hpp +++ /dev/null @@ -1,52 +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 - -#pragma once - -#ifndef NAZARA_SHADERWRITER_HPP -#define NAZARA_SHADERWRITER_HPP - -#include -#include -#include -#include -#include - -namespace Nz -{ - class NAZARA_RENDERER_API ShaderWriter - { - 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; - - 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::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::ExpressionStatement& node) = 0; - virtual void Write(const ShaderAst::NamedVariable& node) = 0; - virtual void Write(const ShaderAst::NodePtr& node) = 0; - virtual void Write(const ShaderAst::StatementBlock& node) = 0; - virtual void Write(const ShaderAst::SwizzleOp& node) = 0; - - private: - std::unordered_set m_conditions; - }; -} - -#endif // NAZARA_SHADERWRITER_HPP 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/Shader/GlslWriter.hpp b/include/Nazara/Shader/GlslWriter.hpp new file mode 100644 index 000000000..ad76fbe18 --- /dev/null +++ b/include/Nazara/Shader/GlslWriter.hpp @@ -0,0 +1,110 @@ +// 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_GLSLWRITER_HPP +#define NAZARA_GLSLWRITER_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + class NAZARA_SHADER_API GlslWriter : public ShaderWriter, public ShaderVarVisitor, public ShaderAstVisitor + { + public: + struct Environment; + using ExtSupportCallback = std::function; + + GlslWriter(); + GlslWriter(const GlslWriter&) = delete; + GlslWriter(GlslWriter&&) = delete; + ~GlslWriter() = default; + + std::string Generate(const ShaderAst& shader) override; + + void SetEnv(Environment environment); + + struct Environment + { + ExtSupportCallback extCallback; + unsigned int glMajorVersion = 3; + unsigned int glMinorVersion = 0; + bool glES = false; + bool flipYPosition = false; + }; + + private: + void Append(ShaderExpressionType type); + void Append(ShaderNodes::BuiltinEntry builtin); + void Append(ShaderNodes::BasicType type); + 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 = {}); + + template void DeclareVariables(const ShaderAst& shader, const std::vector& variables, const std::string& keyword = {}, const std::string& section = {}); + + void EnterScope(); + void LeaveScope(); + + using ShaderVarVisitor::Visit; + using ShaderAstVisitor::Visit; + 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); + + struct Context + { + const ShaderAst* shader = nullptr; + const ShaderAst::Function* currentFunction = nullptr; + }; + + struct State + { + std::stringstream stream; + unsigned int indentLevel = 0; + }; + + Context m_context; + Environment m_environment; + State* m_currentState; + }; +} + +#include + +#endif // NAZARA_GLSLWRITER_HPP diff --git a/include/Nazara/Shader/GlslWriter.inl b/include/Nazara/Shader/GlslWriter.inl new file mode 100644 index 000000000..76972eec1 --- /dev/null +++ b/include/Nazara/Shader/GlslWriter.inl @@ -0,0 +1,132 @@ +// 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 +{ + 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 ShaderAst& shader, 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(") "); + } + + if (!keyword.empty()) + { + Append(keyword); + Append(" "); + } + + Append(var.type); + Append(" "); + Append(var.name); + AppendLine(";"); + } + else if constexpr (std::is_same_v) + { + if (var.bindingIndex || var.memoryLayout) + { + 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(" "); + } + + 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(); + } + } +} + +#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/Shader/ShaderAst.hpp b/include/Nazara/Shader/ShaderAst.hpp new file mode 100644 index 000000000..6f384c18f --- /dev/null +++ b/include/Nazara/Shader/ShaderAst.hpp @@ -0,0 +1,115 @@ +// 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_AST_HPP +#define NAZARA_SHADER_AST_HPP + +#include +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + class NAZARA_SHADER_API ShaderAst + { + public: + struct Function; + struct FunctionParameter; + struct InputOutput; + struct Struct; + struct StructMember; + struct Uniform; + struct VariableBase; + + 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); + 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 = {}); + + 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 ShaderStageType GetStage() 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; + + ShaderAst& operator=(const ShaderAst&) = default; + ShaderAst& operator=(ShaderAst&&) = default; + + struct VariableBase + { + std::string name; + ShaderExpressionType type; + }; + + struct FunctionParameter : VariableBase + { + }; + + struct Function + { + std::string name; + std::vector parameters; + ShaderNodes::BasicType returnType; + ShaderNodes::StatementPtr statement; + }; + + struct InputOutput : VariableBase + { + std::optional locationIndex; + }; + + struct Uniform : VariableBase + { + std::optional bindingIndex; + std::optional memoryLayout; + }; + + struct Struct + { + std::string name; + std::vector members; + }; + + struct StructMember + { + std::string name; + ShaderExpressionType type; + }; + + private: + std::vector m_functions; + std::vector m_inputs; + std::vector m_outputs; + std::vector m_structs; + std::vector m_uniforms; + ShaderStageType m_stage; + }; +} + +#include + +#endif // NAZARA_SHADER_AST_HPP diff --git a/include/Nazara/Shader/ShaderAst.inl b/include/Nazara/Shader/ShaderAst.inl new file mode 100644 index 000000000..4c6c42833 --- /dev/null +++ b/include/Nazara/Shader/ShaderAst.inl @@ -0,0 +1,101 @@ +// 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 ShaderAst::ShaderAst(ShaderStageType shaderStage) : + m_stage(shaderStage) + { + } + + inline auto ShaderAst::GetFunction(std::size_t i) const -> const Function& + { + 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 ShaderStageType ShaderAst::GetStage() const + { + return m_stage; + } + + 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()); + 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; + } +} + +#include diff --git a/include/Nazara/Shader/ShaderAstCloner.hpp b/include/Nazara/Shader/ShaderAstCloner.hpp new file mode 100644 index 000000000..4c24e689e --- /dev/null +++ b/include/Nazara/Shader/ShaderAstCloner.hpp @@ -0,0 +1,74 @@ +// 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_SHADERASTCLONER_HPP +#define NAZARA_SHADERASTCLONER_HPP + +#include +#include +#include +#include +#include + +namespace Nz +{ + class NAZARA_SHADER_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; + + protected: + ShaderNodes::ExpressionPtr CloneExpression(const ShaderNodes::ExpressionPtr& expr); + ShaderNodes::StatementPtr CloneStatement(const ShaderNodes::StatementPtr& statement); + ShaderNodes::VariablePtr CloneVariable(const ShaderNodes::VariablePtr& statement); + + 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(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); + void PushVariable(ShaderNodes::VariablePtr variable); + + ShaderNodes::ExpressionPtr PopExpression(); + ShaderNodes::StatementPtr PopStatement(); + ShaderNodes::VariablePtr PopVariable(); + + private: + std::vector m_expressionStack; + std::vector m_statementStack; + std::vector m_variableStack; + }; +} + +#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/Shader/ShaderAstRecursiveVisitor.hpp b/include/Nazara/Shader/ShaderAstRecursiveVisitor.hpp new file mode 100644 index 000000000..367f9b4ca --- /dev/null +++ b/include/Nazara/Shader/ShaderAstRecursiveVisitor.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_SHADER_RECURSIVE_VISITOR_HPP +#define NAZARA_SHADER_RECURSIVE_VISITOR_HPP + +#include +#include +#include + +namespace Nz +{ + class NAZARA_SHADER_API ShaderAstRecursiveVisitor : public ShaderAstVisitor + { + public: + ShaderAstRecursiveVisitor() = default; + ~ShaderAstRecursiveVisitor() = default; + + 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; + }; +} + +#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/Shader/ShaderAstSerializer.hpp b/include/Nazara/Shader/ShaderAstSerializer.hpp new file mode 100644 index 000000000..2e0102e8e --- /dev/null +++ b/include/Nazara/Shader/ShaderAstSerializer.hpp @@ -0,0 +1,143 @@ +// 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_SHADERSERIALIZER_HPP +#define NAZARA_SHADERSERIALIZER_HPP + +#include +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + class NAZARA_SHADER_API ShaderAstSerializerBase + { + public: + ShaderAstSerializerBase() = default; + ShaderAstSerializerBase(const ShaderAstSerializerBase&) = delete; + ShaderAstSerializerBase(ShaderAstSerializerBase&&) = delete; + ~ShaderAstSerializerBase() = default; + + void Serialize(ShaderNodes::AccessMember& 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 OptEnum(std::optional& optVal); + template void OptVal(std::optional& optVal); + + virtual bool IsWriting() const = 0; + + 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; + 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; + inline void Value(std::size_t& val); + + virtual void Variable(ShaderNodes::VariablePtr& var) = 0; + template void Variable(std::shared_ptr& var); + }; + + class NAZARA_SHADER_API ShaderAstSerializer final : public ShaderAstSerializerBase + { + public: + inline ShaderAstSerializer(ByteStream& stream); + ~ShaderAstSerializer() = default; + + void Serialize(const ShaderAst& shader); + + private: + 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; + 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; + void Variable(ShaderNodes::VariablePtr& var) override; + + ByteStream& m_stream; + }; + + class NAZARA_SHADER_API ShaderAstUnserializer final : public ShaderAstSerializerBase + { + public: + ShaderAstUnserializer(ByteStream& stream); + ~ShaderAstUnserializer() = default; + + ShaderAst Unserialize(); + + private: + bool IsWriting() const override; + 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; + 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; + void Variable(ShaderNodes::VariablePtr& var) override; + + ByteStream& m_stream; + }; + + NAZARA_SHADER_API ByteArray SerializeShader(const ShaderAst& shader); + NAZARA_SHADER_API ShaderAst UnserializeShader(ByteStream& stream); +} + +#include + +#endif diff --git a/include/Nazara/Shader/ShaderAstSerializer.inl b/include/Nazara/Shader/ShaderAstSerializer.inl new file mode 100644 index 000000000..a335f91c2 --- /dev/null +++ b/include/Nazara/Shader/ShaderAstSerializer.inl @@ -0,0 +1,127 @@ +// 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 +{ + template + void ShaderAstSerializerBase::Container(T& container) + { + bool isWriting = IsWriting(); + + UInt32 size; + if (isWriting) + size = UInt32(container.size()); + + Value(size); + if (!isWriting) + container.resize(size); + } + + + template + void ShaderAstSerializerBase::Enum(T& enumVal) + { + bool isWriting = IsWriting(); + + UInt32 value; + if (isWriting) + value = static_cast(enumVal); + + Value(value); + if (!isWriting) + enumVal = static_cast(value); + } + + template + void ShaderAstSerializerBase::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 ShaderAstSerializerBase::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 ShaderAstSerializerBase::Node(std::shared_ptr& node) + { + bool isWriting = IsWriting(); + + ShaderNodes::NodePtr value; + if (isWriting) + value = node; + + Node(value); + if (!isWriting) + node = std::static_pointer_cast(value); + } + + template + void ShaderAstSerializerBase::Variable(std::shared_ptr& var) + { + bool isWriting = IsWriting(); + + ShaderNodes::VariablePtr value; + if (isWriting) + value = var; + + Variable(value); + if (!isWriting) + var = std::static_pointer_cast(value); + } + + inline void ShaderAstSerializerBase::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 ShaderAstSerializer::ShaderAstSerializer(ByteStream& stream) : + m_stream(stream) + { + } + + inline ShaderAstUnserializer::ShaderAstUnserializer(ByteStream& stream) : + m_stream(stream) + { + } +} + +#include diff --git a/include/Nazara/Shader/ShaderAstValidator.hpp b/include/Nazara/Shader/ShaderAstValidator.hpp new file mode 100644 index 000000000..8195494b6 --- /dev/null +++ b/include/Nazara/Shader/ShaderAstValidator.hpp @@ -0,0 +1,72 @@ +// 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_SHADERVALIDATOR_HPP +#define NAZARA_SHADERVALIDATOR_HPP + +#include +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + class NAZARA_SHADER_API ShaderAstValidator : public ShaderAstRecursiveVisitor, public ShaderVarVisitor + { + public: + inline ShaderAstValidator(const ShaderAst& shader); + ShaderAstValidator(const ShaderAstValidator&) = delete; + ShaderAstValidator(ShaderAstValidator&&) = delete; + ~ShaderAstValidator() = default; + + bool Validate(std::string* error = nullptr); + + private: + 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 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; + 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(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; + + const ShaderAst& m_shader; + Context* m_context; + }; + + NAZARA_SHADER_API bool ValidateShader(const ShaderAst& shader, std::string* error = nullptr); +} + +#include + +#endif diff --git a/include/Nazara/Shader/ShaderAstValidator.inl b/include/Nazara/Shader/ShaderAstValidator.inl new file mode 100644 index 000000000..eed116766 --- /dev/null +++ b/include/Nazara/Shader/ShaderAstValidator.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 +{ + ShaderAstValidator::ShaderAstValidator(const ShaderAst& shader) : + m_shader(shader) + { + } +} + +#include diff --git a/include/Nazara/Shader/ShaderAstVisitor.hpp b/include/Nazara/Shader/ShaderAstVisitor.hpp new file mode 100644 index 000000000..64dc35559 --- /dev/null +++ b/include/Nazara/Shader/ShaderAstVisitor.hpp @@ -0,0 +1,50 @@ +// 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_SHADERASTVISITOR_HPP +#define NAZARA_SHADERASTVISITOR_HPP + +#include +#include +#include +#include +#include + +namespace Nz +{ + class NAZARA_SHADER_API ShaderAstVisitor + { + public: + ShaderAstVisitor() = default; + ShaderAstVisitor(const ShaderAstVisitor&) = delete; + ShaderAstVisitor(ShaderAstVisitor&&) = delete; + virtual ~ShaderAstVisitor(); + + void EnableCondition(const std::string& name, bool cond); + + bool IsConditionEnabled(const std::string& name) const; + + void Visit(const ShaderNodes::NodePtr& node); + 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; + }; +} + +#endif 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/ShaderBuilder.hpp b/include/Nazara/Shader/ShaderBuilder.hpp new file mode 100644 index 000000000..074434a44 --- /dev/null +++ b/include/Nazara/Shader/ShaderBuilder.hpp @@ -0,0 +1,76 @@ +// 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_BUILDER_HPP +#define NAZARA_SHADER_BUILDER_HPP + +#include +#include +#include + +namespace Nz::ShaderBuilder +{ + template + struct AssignOpBuilder + { + constexpr AssignOpBuilder() = default; + + std::shared_ptr operator()(const ShaderNodes::ExpressionPtr& left, const ShaderNodes::ExpressionPtr& right) const; + }; + + template + struct BinOpBuilder + { + constexpr BinOpBuilder() = default; + + std::shared_ptr operator()(const ShaderNodes::ExpressionPtr& left, const ShaderNodes::ExpressionPtr& right) const; + }; + + struct BuiltinBuilder + { + constexpr BuiltinBuilder() = default; + + inline std::shared_ptr operator()(ShaderNodes::BuiltinEntry builtin) const; + }; + + template + struct GenBuilder + { + constexpr GenBuilder() = default; + + template std::shared_ptr operator()(Args&&... args) const; + }; + + constexpr GenBuilder AccessMember; + 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 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); +} + +#include + +#endif // NAZARA_SHADER_BUILDER_HPP diff --git a/include/Nazara/Shader/ShaderBuilder.inl b/include/Nazara/Shader/ShaderBuilder.inl new file mode 100644 index 000000000..c3221c84f --- /dev/null +++ b/include/Nazara/Shader/ShaderBuilder.inl @@ -0,0 +1,52 @@ +// 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::ShaderBuilder +{ + template + template + std::shared_ptr GenBuilder::operator()(Args&&... args) const + { + return T::Build(std::forward(args)...); + } + + template + std::shared_ptr AssignOpBuilder::operator()(const ShaderNodes::ExpressionPtr& left, const ShaderNodes::ExpressionPtr& right) const + { + return ShaderNodes::AssignOp::Build(op, left, right); + } + + template + std::shared_ptr BinOpBuilder::operator()(const ShaderNodes::ExpressionPtr& left, const ShaderNodes::ExpressionPtr& right) const + { + return ShaderNodes::BinaryOp::Build(op, left, right); + } + + inline std::shared_ptr BuiltinBuilder::operator()(ShaderNodes::BuiltinEntry builtin) const + { + ShaderNodes::BasicType exprType = ShaderNodes::BasicType::Void; + + switch (builtin) + { + case ShaderNodes::BuiltinEntry::VertexPosition: + exprType = ShaderNodes::BasicType::Float4; + break; + } + + NazaraAssert(exprType != ShaderNodes::BasicType::Void, "Unhandled builtin"); + + return ShaderNodes::BuiltinVariable::Build(builtin, exprType); + } + + template + std::shared_ptr Cast(Args&&... args) + { + return ShaderNodes::Cast::Build(Type, std::forward(args)...); + } +} + +#include 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 new file mode 100644 index 000000000..ed322e3e6 --- /dev/null +++ b/include/Nazara/Shader/ShaderEnums.hpp @@ -0,0 +1,121 @@ +// 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_ENUMS_HPP +#define NAZARA_SHADER_ENUMS_HPP + +#include + +namespace Nz::ShaderNodes +{ + enum class AssignType + { + Simple //< = + }; + + enum class BasicType + { + Boolean, //< bool + Float1, //< float + Float2, //< vec2 + Float3, //< vec3 + Float4, //< vec4 + Int1, //< int + Int2, //< ivec2 + Int3, //< ivec3 + Int4, //< ivec4 + Mat4x4, //< mat4 + Sampler2D, //< sampler2D + Void, //< void + UInt1, //< uint + UInt2, //< uvec2 + UInt3, //< uvec3 + UInt4 //< uvec4 + }; + + enum class BinaryType + { + Add, //< + + Substract, //< - + Multiply, //< * + Divide, //< / + + Equality //< == + }; + + enum class BuiltinEntry + { + VertexPosition, // gl_Position + }; + + enum class ExpressionCategory + { + LValue, + RValue + }; + + enum class IntrinsicType + { + CrossProduct, + DotProduct + }; + + enum class MemoryLayout + { + Std140 + }; + + enum class NodeType + { + None = -1, + + AccessMember, + AssignOp, + BinaryOp, + Branch, + Cast, + Constant, + ConditionalStatement, + DeclareVariable, + ExpressionStatement, + Identifier, + IntrinsicCall, + Sample2D, + SwizzleOp, + StatementBlock + }; + + enum class SsaInstruction + { + OpAdd, + OpDiv, + OpMul, + OpSub, + OpSample + }; + + 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/Shader/ShaderExpressionType.hpp b/include/Nazara/Shader/ShaderExpressionType.hpp new file mode 100644 index 000000000..69b53b06a --- /dev/null +++ b/include/Nazara/Shader/ShaderExpressionType.hpp @@ -0,0 +1,20 @@ +// 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_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/Shader/ShaderNodes.hpp b/include/Nazara/Shader/ShaderNodes.hpp new file mode 100644 index 000000000..b3af5f1aa --- /dev/null +++ b/include/Nazara/Shader/ShaderNodes.hpp @@ -0,0 +1,283 @@ +// 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_NODES_HPP +#define NAZARA_SHADER_NODES_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + class ShaderAstVisitor; + + namespace ShaderNodes + { + class Node; + + using NodePtr = std::shared_ptr; + + class NAZARA_SHADER_API Node + { + public: + virtual ~Node(); + + inline NodeType GetType() const; + inline bool IsStatement() const; + + virtual void Visit(ShaderAstVisitor& visitor) = 0; + + static inline unsigned int GetComponentCount(BasicType type); + static inline BasicType GetComponentType(BasicType type); + + protected: + inline Node(NodeType type, bool isStatement); + + private: + NodeType m_type; + bool m_isStatement; + }; + + class Expression; + + using ExpressionPtr = std::shared_ptr; + + class NAZARA_SHADER_API Expression : public Node + { + public: + inline Expression(NodeType type); + + virtual ExpressionCategory GetExpressionCategory() const; + virtual ShaderExpressionType GetExpressionType() const = 0; + }; + + class Statement; + + using StatementPtr = std::shared_ptr; + + class NAZARA_SHADER_API Statement : public Node + { + public: + inline Statement(NodeType type); + }; + + struct NAZARA_SHADER_API ExpressionStatement : public Statement + { + inline ExpressionStatement(); + + void Visit(ShaderAstVisitor& visitor) override; + + ExpressionPtr expression; + + static inline std::shared_ptr Build(ExpressionPtr expr); + }; + + ////////////////////////////////////////////////////////////////////////// + + struct NAZARA_SHADER_API ConditionalStatement : public Statement + { + inline ConditionalStatement(); + + void Visit(ShaderAstVisitor& visitor) override; + + std::string conditionName; + StatementPtr statement; + + static inline std::shared_ptr Build(std::string condition, StatementPtr statementPtr); + }; + + struct NAZARA_SHADER_API StatementBlock : public Statement + { + inline StatementBlock(); + + void Visit(ShaderAstVisitor& visitor) override; + + std::vector statements; + + static inline std::shared_ptr Build(std::vector statements); + template static std::shared_ptr Build(Args&&... args); + }; + + struct NAZARA_SHADER_API DeclareVariable : public Statement + { + inline DeclareVariable(); + + void Visit(ShaderAstVisitor& visitor) override; + + ExpressionPtr expression; + VariablePtr variable; + + static inline std::shared_ptr Build(VariablePtr variable, ExpressionPtr expression = nullptr); + }; + + struct NAZARA_SHADER_API Identifier : public Expression + { + inline Identifier(); + + ExpressionCategory GetExpressionCategory() const override; + ShaderExpressionType GetExpressionType() const override; + void Visit(ShaderAstVisitor& visitor) override; + + VariablePtr var; + + static inline std::shared_ptr Build(VariablePtr variable); + }; + + struct NAZARA_SHADER_API AccessMember : public Expression + { + inline AccessMember(); + + ExpressionCategory GetExpressionCategory() const override; + ShaderExpressionType GetExpressionType() const override; + void Visit(ShaderAstVisitor& visitor) override; + + 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); + }; + + ////////////////////////////////////////////////////////////////////////// + + struct NAZARA_SHADER_API AssignOp : public Expression + { + inline AssignOp(); + + ShaderExpressionType GetExpressionType() const override; + void Visit(ShaderAstVisitor& visitor) override; + + AssignType op; + ExpressionPtr left; + ExpressionPtr right; + + static inline std::shared_ptr Build(AssignType op, ExpressionPtr left, ExpressionPtr right); + }; + + struct NAZARA_SHADER_API BinaryOp : public Expression + { + inline BinaryOp(); + + ShaderExpressionType GetExpressionType() const override; + void Visit(ShaderAstVisitor& visitor) override; + + BinaryType op; + ExpressionPtr left; + ExpressionPtr right; + + static inline std::shared_ptr Build(BinaryType op, ExpressionPtr left, ExpressionPtr right); + }; + + struct NAZARA_SHADER_API Branch : public Statement + { + struct ConditionalStatement; + + inline Branch(); + + void Visit(ShaderAstVisitor& visitor) override; + + std::vector condStatements; + StatementPtr elseStatement; + + struct ConditionalStatement + { + ExpressionPtr condition; + StatementPtr statement; + }; + + 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_SHADER_API Cast : public Expression + { + inline Cast(); + + ShaderExpressionType GetExpressionType() const override; + void Visit(ShaderAstVisitor& visitor) override; + + BasicType exprType; + std::array expressions; + + 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_SHADER_API Constant : public Expression + { + inline Constant(); + + ShaderExpressionType GetExpressionType() const override; + void Visit(ShaderAstVisitor& visitor) override; + + ShaderConstantValue value; + + template static std::shared_ptr Build(const T& value); + }; + + struct NAZARA_SHADER_API SwizzleOp : public Expression + { + inline SwizzleOp(); + + ExpressionCategory GetExpressionCategory() const override; + ShaderExpressionType GetExpressionType() const override; + void Visit(ShaderAstVisitor& visitor) override; + + std::array components; + 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); + }; + + ////////////////////////////////////////////////////////////////////////// + + struct NAZARA_SHADER_API Sample2D : public Expression + { + inline Sample2D(); + + ShaderExpressionType GetExpressionType() const override; + void Visit(ShaderAstVisitor& visitor) override; + + ExpressionPtr sampler; + ExpressionPtr coordinates; + + static inline std::shared_ptr Build(ExpressionPtr samplerPtr, ExpressionPtr coordinatesPtr); + }; + + ////////////////////////////////////////////////////////////////////////// + + struct NAZARA_SHADER_API IntrinsicCall : public Expression + { + inline IntrinsicCall(); + + ShaderExpressionType GetExpressionType() const override; + void Visit(ShaderAstVisitor& 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/Shader/ShaderNodes.inl b/include/Nazara/Shader/ShaderNodes.inl new file mode 100644 index 000000000..1e0817b62 --- /dev/null +++ b/include/Nazara/Shader/ShaderNodes.inl @@ -0,0 +1,348 @@ +// 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::ShaderNodes +{ + inline Node::Node(NodeType type, bool isStatement) : + m_type(type), + m_isStatement(isStatement) + { + } + + inline NodeType ShaderNodes::Node::GetType() const + { + return m_type; + } + + inline bool Node::IsStatement() const + { + return m_isStatement; + } + + inline unsigned int Node::GetComponentCount(BasicType type) + { + 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: + return 4; + + default: + return 1; + } + } + + inline BasicType Node::GetComponentType(BasicType type) + { + switch (type) + { + case BasicType::Float2: + case BasicType::Float3: + case BasicType::Float4: + return BasicType::Float1; + + case BasicType::Int2: + case BasicType::Int3: + case BasicType::Int4: + return BasicType::Int1; + + case BasicType::Mat4x4: + return BasicType::Float4; + + default: + return type; + } + } + + + inline Expression::Expression(NodeType type) : + Node(type, false) + { + } + + inline Statement::Statement(NodeType type) : + Node(type, true) + { + } + + + + 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) + { + } + + 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) + { + 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(VariablePtr 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 AccessMember::AccessMember() : + Expression(NodeType::AccessMember) + { + } + + 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->memberIndices = std::move(memberIndices); + node->structExpr = std::move(structExpr); + + 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 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) + { + } + + inline std::shared_ptr Cast::Build(BasicType 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(BasicType 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) + { + } + + template + std::shared_ptr Nz::ShaderNodes::Constant::Build(const T& value) + { + auto node = std::make_shared(); + node->value = value; + + return node; + } + + + inline SwizzleOp::SwizzleOp() : + Expression(NodeType::SwizzleOp) + { + } + + 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(); + node->componentCount = swizzleComponents.size(); + node->expression = std::move(expressionPtr); + + std::copy(swizzleComponents.begin(), swizzleComponents.end(), node->components.begin()); + + 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) + { + } + + 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/Shader/ShaderVarVisitor.hpp b/include/Nazara/Shader/ShaderVarVisitor.hpp new file mode 100644 index 000000000..ebee55ab6 --- /dev/null +++ b/include/Nazara/Shader/ShaderVarVisitor.hpp @@ -0,0 +1,35 @@ +// 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_SHADERVARVISITOR_HPP +#define NAZARA_SHADERVARVISITOR_HPP + +#include +#include +#include + +namespace Nz +{ + class NAZARA_SHADER_API ShaderVarVisitor + { + public: + ShaderVarVisitor() = default; + ShaderVarVisitor(const ShaderVarVisitor&) = delete; + ShaderVarVisitor(ShaderVarVisitor&&) = delete; + virtual ~ShaderVarVisitor(); + + 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; + }; +} + +#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/ShaderVariables.hpp b/include/Nazara/Shader/ShaderVariables.hpp new file mode 100644 index 000000000..eb0bc8ede --- /dev/null +++ b/include/Nazara/Shader/ShaderVariables.hpp @@ -0,0 +1,128 @@ +// 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_VARIABLES_HPP +#define NAZARA_SHADER_VARIABLES_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + class ShaderVarVisitor; + + namespace ShaderNodes + { + struct Variable; + + using VariablePtr = std::shared_ptr; + + struct NAZARA_SHADER_API Variable : std::enable_shared_from_this + { + virtual ~Variable(); + + virtual VariableType GetType() const = 0; + virtual void Visit(ShaderVarVisitor& visitor) = 0; + + ShaderExpressionType type; + }; + + struct BuiltinVariable; + + using BuiltinVariablePtr = std::shared_ptr; + + struct NAZARA_SHADER_API BuiltinVariable : public Variable + { + BuiltinEntry entry; + + VariableType GetType() const override; + void Visit(ShaderVarVisitor& visitor) override; + + static inline std::shared_ptr Build(BuiltinEntry entry, ShaderExpressionType varType); + }; + + struct NamedVariable; + + using NamedVariablePtr = std::shared_ptr; + + struct NAZARA_SHADER_API NamedVariable : public Variable + { + std::string name; + }; + + struct InputVariable; + + using InputVariablePtr = std::shared_ptr; + + struct NAZARA_SHADER_API InputVariable : public NamedVariable + { + VariableType GetType() const override; + void Visit(ShaderVarVisitor& visitor) override; + + static inline std::shared_ptr Build(std::string varName, ShaderExpressionType varType); + }; + + struct LocalVariable; + + using LocalVariablePtr = std::shared_ptr; + + struct NAZARA_SHADER_API LocalVariable : public NamedVariable + { + VariableType GetType() const override; + void Visit(ShaderVarVisitor& visitor) override; + + static inline std::shared_ptr Build(std::string varName, ShaderExpressionType varType); + }; + + struct OutputVariable; + + using OutputVariablePtr = std::shared_ptr; + + struct NAZARA_SHADER_API OutputVariable : public NamedVariable + { + VariableType GetType() const override; + void Visit(ShaderVarVisitor& visitor) override; + + static inline std::shared_ptr Build(std::string varName, ShaderExpressionType varType); + }; + + struct ParameterVariable; + + using ParameterVariablePtr = std::shared_ptr; + + struct NAZARA_SHADER_API ParameterVariable : public NamedVariable + { + VariableType GetType() const override; + void Visit(ShaderVarVisitor& visitor) override; + + static inline std::shared_ptr Build(std::string varName, ShaderExpressionType varType); + }; + + struct UniformVariable; + + using UniformVariablePtr = std::shared_ptr; + + struct NAZARA_SHADER_API UniformVariable : public NamedVariable + { + VariableType GetType() const override; + void Visit(ShaderVarVisitor& visitor) override; + + static inline std::shared_ptr Build(std::string varName, ShaderExpressionType varType); + }; + } +} + +#include + +#endif diff --git a/include/Nazara/Shader/ShaderVariables.inl b/include/Nazara/Shader/ShaderVariables.inl new file mode 100644 index 000000000..9f2415708 --- /dev/null +++ b/include/Nazara/Shader/ShaderVariables.inl @@ -0,0 +1,65 @@ +// 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::ShaderNodes +{ + inline std::shared_ptr BuiltinVariable::Build(BuiltinEntry variable, ShaderExpressionType varType) + { + auto node = std::make_shared(); + node->entry = variable; + node->type = varType; + + return node; + } + + inline std::shared_ptr InputVariable::Build(std::string varName, ShaderExpressionType 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, ShaderExpressionType 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, ShaderExpressionType 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, ShaderExpressionType 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, ShaderExpressionType varType) + { + auto node = std::make_shared(); + node->name = std::move(varName); + node->type = varType; + + return node; + } +} + +#include diff --git a/include/Nazara/Shader/ShaderWriter.hpp b/include/Nazara/Shader/ShaderWriter.hpp new file mode 100644 index 000000000..0e896fa40 --- /dev/null +++ b/include/Nazara/Shader/ShaderWriter.hpp @@ -0,0 +1,30 @@ +// 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_SHADERWRITER_HPP +#define NAZARA_SHADERWRITER_HPP + +#include +#include +#include + +namespace Nz +{ + class ShaderAst; + + class NAZARA_SHADER_API ShaderWriter + { + public: + ShaderWriter() = default; + ShaderWriter(const ShaderWriter&) = default; + ShaderWriter(ShaderWriter&&) = default; + virtual ~ShaderWriter(); + + virtual std::string Generate(const ShaderAst& shader) = 0; + }; +} + +#endif // NAZARA_SHADERWRITER_HPP 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/SpirvAstVisitor.inl b/include/Nazara/Shader/SpirvAstVisitor.inl new file mode 100644 index 000000000..87dc93a54 --- /dev/null +++ b/include/Nazara/Shader/SpirvAstVisitor.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 SpirvAstVisitor::SpirvAstVisitor(SpirvWriter& writer) : + m_writer(writer) + { + } +} + +#include diff --git a/include/Nazara/Shader/SpirvConstantCache.hpp b/include/Nazara/Shader/SpirvConstantCache.hpp new file mode 100644 index 000000000..279f71b07 --- /dev/null +++ b/include/Nazara/Shader/SpirvConstantCache.hpp @@ -0,0 +1,197 @@ +// 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); + + 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 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; + }; +} + +#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/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/include/Nazara/Shader/SpirvExpressionLoad.hpp b/include/Nazara/Shader/SpirvExpressionLoad.hpp new file mode 100644 index 000000000..b237c720a --- /dev/null +++ b/include/Nazara/Shader/SpirvExpressionLoad.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_SPIRVEXPRESSIONLOADACCESSMEMBER_HPP +#define NAZARA_SPIRVEXPRESSIONLOADACCESSMEMBER_HPP + +#include +#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 Evaluate(ShaderNodes::Expression& node); + + 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::LocalVariable& var) override; + void Visit(ShaderNodes::UniformVariable& var) override; + + SpirvExpressionLoad& operator=(const SpirvExpressionLoad&) = delete; + SpirvExpressionLoad& operator=(SpirvExpressionLoad&&) = 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/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/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..101a49437 --- /dev/null +++ b/include/Nazara/Shader/SpirvPrinter.hpp @@ -0,0 +1,50 @@ +// 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: + struct Settings; + + inline SpirvPrinter(); + SpirvPrinter(const SpirvPrinter&) = default; + SpirvPrinter(SpirvPrinter&&) = default; + ~SpirvPrinter() = default; + + 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(); + 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/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..e86eb59ff --- /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 new file mode 100644 index 000000000..6b21de0ba --- /dev/null +++ b/include/Nazara/Shader/SpirvWriter.hpp @@ -0,0 +1,111 @@ +// 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_SPIRVWRITER_HPP +#define NAZARA_SPIRVWRITER_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + class SpirvSection; + + class NAZARA_SHADER_API SpirvWriter + { + friend class SpirvAstVisitor; + friend class SpirvExpressionLoad; + friend class SpirvExpressionStore; + friend class SpirvVisitor; + + 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 + { + UInt32 spvMajorVersion = 1; + UInt32 spvMinorVersion = 0; + }; + + private: + struct ExtVar; + struct OnlyCache {}; + + UInt32 AllocateResultId(); + + void AppendHeader(); + + 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; + + 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); + + void WriteLocalVariable(std::string name, UInt32 resultId); + + static void MergeBlocks(std::vector& output, const SpirvSection& from); + + struct Context + { + const ShaderAst* shader = nullptr; + const ShaderAst::Function* currentFunction = nullptr; + }; + + struct ExtVar + { + UInt32 pointerTypeId; + UInt32 typeId; + UInt32 varId; + std::optional valueId; + }; + + struct State; + + Context m_context; + Environment m_environment; + State* m_currentState; + }; +} + +#include + +#endif diff --git a/include/Nazara/Shader/SpirvWriter.inl b/include/Nazara/Shader/SpirvWriter.inl new file mode 100644 index 000000000..26012e0d1 --- /dev/null +++ b/include/Nazara/Shader/SpirvWriter.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/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/include/Nazara/Utility/Enums.hpp b/include/Nazara/Utility/Enums.hpp index 7ac18a697..99328ecde 100644 --- a/include/Nazara/Utility/Enums.hpp +++ b/include/Nazara/Utility/Enums.hpp @@ -309,6 +309,58 @@ 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, + 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..266f82cd7 --- /dev/null +++ b/include/Nazara/Utility/FieldOffsets.hpp @@ -0,0 +1,52 @@ +// 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 + +#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..5ca15e88f --- /dev/null +++ b/include/Nazara/Utility/FieldOffsets.inl @@ -0,0 +1,169 @@ +// 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 + +#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/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/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/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/OpenGLRenderer/OpenGLShaderStage.cpp b/src/Nazara/OpenGLRenderer/OpenGLShaderStage.cpp index 3364e4f11..068ef9634 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,37 @@ namespace Nz m_shader.Compile(); break; + case ShaderLanguage::NazaraBinary: + { + 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(); + + GlslWriter::Environment env; + 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)); + }; + env.flipYPosition = true; + + 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)) 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: diff --git a/src/Nazara/OpenGLRenderer/Wrapper/Context.cpp b/src/Nazara/OpenGLRenderer/Wrapper/Context.cpp index 902f22813..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); @@ -278,6 +283,8 @@ namespace Nz::GL glGetIntegerv(GL_VIEWPORT, res.data()); m_state.viewport = { res[0], res[1], res[2], res[3] }; + EnableVerticalSync(false); + return true; } @@ -631,6 +638,10 @@ namespace Nz::GL ss << "Low"; break; + case GL_DEBUG_SEVERITY_NOTIFICATION: + ss << "Notification"; + break; + default: ss << "Unknown"; break; 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/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/GlslWriter.cpp b/src/Nazara/Renderer/GlslWriter.cpp deleted file mode 100644 index 3d023993c..000000000 --- a/src/Nazara/Renderer/GlslWriter.cpp +++ /dev/null @@ -1,451 +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 -#include - -namespace Nz -{ - GlslWriter::GlslWriter() : - m_currentFunction(nullptr), - m_currentState(nullptr), - m_glslVersion(110) - { - } - - String GlslWriter::Generate(const ShaderAst::StatementPtr& node) - { - State state; - m_currentState = &state; - CallOnExit onExit([this]() - { - m_currentState = nullptr; - }); - - // Register global variables (uniforms, varying, ..) - node->Register(*this); - - // Header - Append("#version "); - AppendLine(String::Number(m_glslVersion)); - AppendLine(); - - // Global variables (uniforms, input and outputs) - DeclareVariables(state.uniforms, "uniform", "Uniforms"); - DeclareVariables(state.inputs, "in", "Inputs"); - DeclareVariables(state.outputs, "out", "Outputs"); - - Function entryPoint; - entryPoint.name = "main"; //< GLSL has only one entry point name possible - entryPoint.node = node; - entryPoint.retType = ShaderAst::ExpressionType::Void; - - AppendFunction(entryPoint); - - return state.stream; - } - - 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) - { - case ShaderAst::VariableType::Builtin: //< Only there to make compiler happy - break; - - case ShaderAst::VariableType::Input: - m_currentState->inputs.insert(std::make_pair(type, name)); - break; - - case ShaderAst::VariableType::Output: - m_currentState->outputs.insert(std::make_pair(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.insert(std::make_pair(type, name)); - break; - - case ShaderAst::VariableType::Variable: - { - if (m_currentFunction) - m_currentFunction->variables.insert(std::make_pair(type, name)); - - break; - } - } - } - - void GlslWriter::SetGlslVersion(unsigned int version) - { - m_glslVersion = version; - } - - void GlslWriter::Write(const ShaderAst::NodePtr& node) - { - node->Visit(*this); - } - - void GlslWriter::Write(const ShaderAst::AssignOp& node) - { - Write(node.variable); - - switch (node.op) - { - case ShaderAst::AssignType::Simple: - Append(" = "); - break; - } - - Write(node.right); - } - - void GlslWriter::Write(const ShaderAst::Branch& node) - { - bool first = true; - for (const auto& statement : node.condStatements) - { - if (!first) - Append("else "); - - Append("if ("); - Write(statement.condition); - AppendLine(")"); - - EnterScope(); - Write(statement.statement); - LeaveScope(); - - first = false; - } - - if (node.elseStatement) - { - AppendLine("else"); - - EnterScope(); - Write(node.elseStatement); - LeaveScope(); - } - } - - void GlslWriter::Write(const ShaderAst::BinaryOp& node) - { - Write(node.left); - - switch (node.op) - { - case ShaderAst::BinaryType::Add: - Append(" + "); - break; - case ShaderAst::BinaryType::Substract: - Append(" - "); - break; - case ShaderAst::BinaryType::Multiply: - Append(" * "); - break; - case ShaderAst::BinaryType::Divide: - Append(" / "); - break; - case ShaderAst::BinaryType::Equality: - Append(" == "); - break; - } - - Write(node.right); - } - - void GlslWriter::Write(const ShaderAst::BuiltinVariable& node) - { - Append(node.var); - } - - void GlslWriter::Write(const ShaderAst::Cast& node) - { - Append(node.exprType); - Append("("); - - unsigned int i = 0; - unsigned int requiredComponents = ShaderAst::Node::GetComponentCount(node.exprType); - while (requiredComponents > 0) - { - if (i != 0) - m_currentState->stream << ", "; - - const auto& exprPtr = node.expressions[i++]; - NazaraAssert(exprPtr, "Invalid expression"); - - Write(exprPtr); - requiredComponents -= ShaderAst::Node::GetComponentCount(exprPtr->GetExpressionType()); - } - - Append(")"); - } - - void GlslWriter::Write(const ShaderAst::Constant& node) - { - switch (node.exprType) - { - case ShaderAst::ExpressionType::Boolean: - Append((node.values.bool1) ? "true" : "false"); - break; - - case ShaderAst::ExpressionType::Float1: - Append(String::Number(node.values.vec1)); - break; - - case ShaderAst::ExpressionType::Float2: - Append("vec2(" + String::Number(node.values.vec2.x) + ", " + String::Number(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) + ")"); - 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) + ")"); - break; - - default: - throw std::runtime_error("Unhandled expression type"); - } - } - - void GlslWriter::Write(const ShaderAst::ExpressionStatement& node) - { - Write(node.expression); - Append(";"); - } - - void GlslWriter::Write(const ShaderAst::NamedVariable& node) - { - Append(node.name); - } - - void GlslWriter::Write(const ShaderAst::StatementBlock& node) - { - bool first = true; - for (const ShaderAst::StatementPtr& statement : node.statements) - { - if (!first) - AppendLine(); - - Write(statement); - - first = false; - } - } - - void GlslWriter::Write(const ShaderAst::SwizzleOp& node) - { - Write(node.expression); - Append("."); - - for (std::size_t i = 0; i < node.componentCount; ++i) - { - switch (node.components[i]) - { - case ShaderAst::SwizzleComponent::First: - Append("x"); - break; - - case ShaderAst::SwizzleComponent::Second: - Append("y"); - break; - - case ShaderAst::SwizzleComponent::Third: - Append("z"); - break; - - case ShaderAst::SwizzleComponent::Fourth: - Append("w"); - break; - } - } - } - - void GlslWriter::Append(ShaderAst::BuiltinEntry builtin) - { - switch (builtin) - { - case ShaderAst::BuiltinEntry::VertexPosition: - Append("gl_Position"); - break; - } - } - - void GlslWriter::Append(ShaderAst::ExpressionType type) - { - switch (type) - { - 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::Void: - Append("void"); - break; - } - } - - 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] () - { - 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); - } - m_currentState->stream << ")\n"; - - EnterScope(); - { - DeclareVariables(func.variables); - - Write(func.node); - } - LeaveScope(); - } - - 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/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/ShaderAst.cpp b/src/Nazara/Renderer/ShaderAst.cpp deleted file mode 100644 index 180930595..000000000 --- a/src/Nazara/Renderer/ShaderAst.cpp +++ /dev/null @@ -1,196 +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 -#include - -namespace Nz { namespace ShaderAst -{ - void ExpressionStatement::Register(ShaderWriter& visitor) - { - expression->Register(visitor); - } - - void ExpressionStatement::Visit(ShaderWriter& visitor) - { - visitor.Write(*this); - } - - - void ConditionalStatement::Register(ShaderWriter& visitor) - { - if (visitor.IsConditionEnabled(conditionName)) - statement->Register(visitor); - } - - void ConditionalStatement::Visit(ShaderWriter& visitor) - { - if (visitor.IsConditionEnabled(conditionName)) - statement->Visit(visitor); - } - - - void StatementBlock::Register(ShaderWriter& visitor) - { - for (auto& statementPtr : statements) - statementPtr->Register(visitor); - } - - void StatementBlock::Visit(ShaderWriter& visitor) - { - visitor.Write(*this); - } - - - ExpressionType Variable::GetExpressionType() const - { - return type; - } - - void NamedVariable::Register(ShaderWriter& visitor) - { - visitor.RegisterVariable(kind, name, type); - } - - void NamedVariable::Visit(ShaderWriter& visitor) - { - visitor.Write(*this); - } - - - void BuiltinVariable::Register(ShaderWriter& visitor) - { - } - - void BuiltinVariable::Visit(ShaderWriter& visitor) - { - visitor.Write(*this); - } - - - ExpressionType AssignOp::GetExpressionType() const - { - return variable->GetExpressionType(); - } - - void AssignOp::Register(ShaderWriter& visitor) - { - variable->Register(visitor); - right->Register(visitor); - } - - void AssignOp::Visit(ShaderWriter& visitor) - { - visitor.Write(*this); - } - - - ExpressionType BinaryOp::GetExpressionType() const - { - ShaderAst::ExpressionType exprType = ShaderAst::ExpressionType::Void; - - 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::Equality: - exprType = ExpressionType::Boolean; - } - - NazaraAssert(exprType != ShaderAst::ExpressionType::Void, "Unhandled builtin"); - - return exprType; - } - - void BinaryOp::Register(ShaderWriter& visitor) - { - left->Register(visitor); - right->Register(visitor); - } - - void BinaryOp::Visit(ShaderWriter& visitor) - { - visitor.Write(*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(ShaderWriter& visitor) - { - visitor.Write(*this); - } - - - ExpressionType Constant::GetExpressionType() const - { - return exprType; - } - - void Constant::Register(ShaderWriter&) - { - } - - void Constant::Visit(ShaderWriter& visitor) - { - visitor.Write(*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(ShaderWriter& visitor) - { - visitor.Write(*this); - } - - - ExpressionType ShaderAst::SwizzleOp::GetExpressionType() const - { - return GetComponentType(expression->GetExpressionType()); - } - - void SwizzleOp::Register(ShaderWriter& visitor) - { - expression->Register(visitor); - } - - void SwizzleOp::Visit(ShaderWriter& visitor) - { - visitor.Write(*this); - } -} -} 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/ShaderWriter.cpp b/src/Nazara/Renderer/ShaderWriter.cpp deleted file mode 100644 index c862572ab..000000000 --- a/src/Nazara/Renderer/ShaderWriter.cpp +++ /dev/null @@ -1,24 +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; - - 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/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/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/Shader/GlslWriter.cpp b/src/Nazara/Shader/GlslWriter.cpp new file mode 100644 index 000000000..39f2ec3ce --- /dev/null +++ b/src/Nazara/Shader/GlslWriter.cpp @@ -0,0 +1,644 @@ +// 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 +{ + 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) + { + } + + std::string GlslWriter::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; + }); + + 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 "); + Append(glslVersion); + if (m_environment.glES) + Append(" es"); + + AppendLine(); + AppendLine(); + + // Extensions + + std::vector requiredExtensions; + + 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_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()) + { + for (const std::string& ext : requiredExtensions) + AppendLine("#extension " + ext + " : require"); + + AppendLine(); + } + + if (m_environment.glES) + { + AppendLine("#if GL_FRAGMENT_PRECISION_HIGH"); + AppendLine("precision highp float;"); + AppendLine("#else"); + AppendLine("precision mediump float;"); + AppendLine("#endif"); + 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, 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) + { + 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::SetEnv(Environment environment) + { + m_environment = std::move(environment); + } + + void GlslWriter::Append(ShaderExpressionType type) + { + std::visit([&](auto&& arg) + { + Append(arg); + }, type); + } + + void GlslWriter::Append(ShaderNodes::BuiltinEntry builtin) + { + switch (builtin) + { + case ShaderNodes::BuiltinEntry::VertexPosition: + Append("gl_Position"); + break; + } + } + + void GlslWriter::Append(ShaderNodes::BasicType type) + { + switch (type) + { + 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::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"); + } + } + + 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"); + + String stars((section.size() < 33) ? (36 - section.size()) / 2 : 3, '*'); + m_currentState->stream << "/*" << stars << ' ' << section << ' ' << stars << "*/"; + 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"); + 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(); + { + AstAdapter adapter; + adapter.flipYPosition = m_environment.flipYPosition; + + Visit(adapter.Clone(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(ShaderNodes::ExpressionPtr& expr, bool encloseIfRequired) + { + bool enclose = encloseIfRequired && (expr->GetExpressionCategory() != ShaderNodes::ExpressionCategory::LValue); + + if (enclose) + Append("("); + + ShaderAstVisitor::Visit(expr); + + if (enclose) + Append(")"); + } + + void GlslWriter::Visit(ShaderNodes::AccessMember& node) + { + Visit(node.structExpr, true); + + const ShaderExpressionType& exprType = node.structExpr->GetExpressionType(); + assert(std::holds_alternative(exprType)); + + AppendField(std::get(exprType), node.memberIndices.data(), node.memberIndices.size()); + } + + void GlslWriter::Visit(ShaderNodes::AssignOp& node) + { + Visit(node.left); + + switch (node.op) + { + case ShaderNodes::AssignType::Simple: + Append(" = "); + break; + } + + Visit(node.right); + } + + void GlslWriter::Visit(ShaderNodes::Branch& node) + { + bool first = true; + for (const auto& statement : node.condStatements) + { + if (!first) + Append("else "); + + Append("if ("); + Visit(statement.condition); + AppendLine(")"); + + EnterScope(); + Visit(statement.statement); + LeaveScope(); + + first = false; + } + + if (node.elseStatement) + { + AppendLine("else"); + + EnterScope(); + Visit(node.elseStatement); + LeaveScope(); + } + } + + void GlslWriter::Visit(ShaderNodes::BinaryOp& node) + { + Visit(node.left, true); + + switch (node.op) + { + case ShaderNodes::BinaryType::Add: + Append(" + "); + break; + case ShaderNodes::BinaryType::Substract: + Append(" - "); + break; + case ShaderNodes::BinaryType::Multiply: + Append(" * "); + break; + case ShaderNodes::BinaryType::Divide: + Append(" / "); + break; + case ShaderNodes::BinaryType::Equality: + Append(" == "); + break; + } + + Visit(node.right, true); + } + + void GlslWriter::Visit(ShaderNodes::BuiltinVariable& var) + { + Append(var.entry); + } + + void GlslWriter::Visit(ShaderNodes::Cast& node) + { + Append(node.exprType); + Append("("); + + for (std::size_t i = 0; node.expressions[i]; ++i) + { + if (i != 0) + m_currentState->stream << ", "; + + const auto& exprPtr = node.expressions[i]; + NazaraAssert(exprPtr, "Invalid expression"); + + Visit(exprPtr); + } + + Append(")"); + } + + 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 || 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) + ")"); + 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 || 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(ShaderNodes::DeclareVariable& node) + { + assert(node.variable->GetType() == ShaderNodes::VariableType::LocalVariable); + + const auto& localVar = static_cast(*node.variable); + + Append(localVar.type); + Append(" "); + Append(localVar.name); + if (node.expression) + { + Append(" = "); + Visit(node.expression); + } + + AppendLine(";"); + } + + void GlslWriter::Visit(ShaderNodes::ExpressionStatement& node) + { + Visit(node.expression); + Append(";"); + } + + void GlslWriter::Visit(ShaderNodes::Identifier& node) + { + Visit(node.var); + } + + void GlslWriter::Visit(ShaderNodes::InputVariable& var) + { + Append(var.name); + } + + void GlslWriter::Visit(ShaderNodes::IntrinsicCall& node) + { + switch (node.intrinsic) + { + case ShaderNodes::IntrinsicType::CrossProduct: + Append("cross"); + break; + + case ShaderNodes::IntrinsicType::DotProduct: + Append("dot"); + break; + } + + Append("("); + for (std::size_t i = 0; i < node.parameters.size(); ++i) + { + if (i != 0) + Append(", "); + + Visit(node.parameters[i]); + } + Append(")"); + } + + void GlslWriter::Visit(ShaderNodes::LocalVariable& var) + { + Append(var.name); + } + + void GlslWriter::Visit(ShaderNodes::ParameterVariable& var) + { + Append(var.name); + } + + void GlslWriter::Visit(ShaderNodes::OutputVariable& var) + { + Append(var.name); + } + + void GlslWriter::Visit(ShaderNodes::Sample2D& node) + { + Append("texture("); + Visit(node.sampler); + Append(", "); + Visit(node.coordinates); + Append(")"); + } + + void GlslWriter::Visit(ShaderNodes::StatementBlock& node) + { + bool first = true; + for (const ShaderNodes::StatementPtr& statement : node.statements) + { + if (!first) + AppendLine(); + + Visit(statement); + + first = false; + } + } + + void GlslWriter::Visit(ShaderNodes::SwizzleOp& node) + { + Visit(node.expression); + Append("."); + + for (std::size_t i = 0; i < node.componentCount; ++i) + { + switch (node.components[i]) + { + case ShaderNodes::SwizzleComponent::First: + Append("x"); + break; + + case ShaderNodes::SwizzleComponent::Second: + Append("y"); + break; + + case ShaderNodes::SwizzleComponent::Third: + Append("z"); + break; + + case ShaderNodes::SwizzleComponent::Fourth: + Append("w"); + break; + } + } + } + + void GlslWriter::Visit(ShaderNodes::UniformVariable& var) + { + Append(var.name); + } + + bool GlslWriter::HasExplicitBinding(const ShaderAst& shader) + { + for (const auto& uniform : shader.GetUniforms()) + { + if (uniform.bindingIndex.has_value()) + return true; + } + + return false; + } + + bool GlslWriter::HasExplicitLocation(const ShaderAst& shader) + { + for (const auto& input : shader.GetInputs()) + { + if (input.locationIndex.has_value()) + return true; + } + + for (const auto& output : shader.GetOutputs()) + { + if (output.locationIndex.has_value()) + return true; + } + + return false; + } +} 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/Shader/ShaderAst.cpp b/src/Nazara/Shader/ShaderAst.cpp new file mode 100644 index 000000000..236a5e28f --- /dev/null +++ b/src/Nazara/Shader/ShaderAst.cpp @@ -0,0 +1,50 @@ +// 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 +{ + 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); + functionEntry.parameters = std::move(parameters); + functionEntry.returnType = returnType; + functionEntry.statement = std::move(statement); + } + + void ShaderAst::AddInput(std::string name, ShaderExpressionType type, std::optional locationIndex) + { + auto& inputEntry = m_inputs.emplace_back(); + inputEntry.name = std::move(name); + inputEntry.locationIndex = std::move(locationIndex); + inputEntry.type = std::move(type); + } + + void ShaderAst::AddOutput(std::string name, ShaderExpressionType type, std::optional locationIndex) + { + auto& outputEntry = m_outputs.emplace_back(); + outputEntry.name = std::move(name); + outputEntry.locationIndex = std::move(locationIndex); + outputEntry.type = std::move(type); + } + + 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, ShaderExpressionType 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 = std::move(type); + } +} diff --git a/src/Nazara/Shader/ShaderAstCloner.cpp b/src/Nazara/Shader/ShaderAstCloner.cpp new file mode 100644 index 000000000..90c7c909d --- /dev/null +++ b/src/Nazara/Shader/ShaderAstCloner.cpp @@ -0,0 +1,220 @@ +// 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 +{ + 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 occurred during clone"); + + return PopStatement(); + } + + ShaderNodes::ExpressionPtr ShaderAstCloner::CloneExpression(const ShaderNodes::ExpressionPtr& expr) + { + if (!expr) + return nullptr; + + ShaderAstVisitor::Visit(expr); + return PopExpression(); + } + + ShaderNodes::StatementPtr ShaderAstCloner::CloneStatement(const ShaderNodes::StatementPtr& statement) + { + 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(ShaderNodes::AccessMember& node) + { + PushExpression(ShaderNodes::AccessMember::Build(CloneExpression(node.structExpr), node.memberIndices, node.exprType)); + } + + void ShaderAstCloner::Visit(ShaderNodes::AssignOp& node) + { + PushExpression(ShaderNodes::AssignOp::Build(node.op, CloneExpression(node.left), CloneExpression(node.right))); + } + + void ShaderAstCloner::Visit(ShaderNodes::BinaryOp& node) + { + PushExpression(ShaderNodes::BinaryOp::Build(node.op, CloneExpression(node.left), CloneExpression(node.right))); + } + + void ShaderAstCloner::Visit(ShaderNodes::Branch& node) + { + std::vector condStatements; + condStatements.reserve(node.condStatements.size()); + + for (auto& cond : node.condStatements) + { + auto& condStatement = condStatements.emplace_back(); + condStatement.condition = CloneExpression(cond.condition); + condStatement.statement = CloneStatement(cond.statement); + } + + PushStatement(ShaderNodes::Branch::Build(std::move(condStatements), CloneStatement(node.elseStatement))); + } + + void ShaderAstCloner::Visit(ShaderNodes::Cast& node) + { + std::size_t expressionCount = 0; + std::array expressions; + for (auto& expr : node.expressions) + { + if (!expr) + break; + + expressions[expressionCount] = CloneExpression(expr); + expressionCount++; + } + + PushExpression(ShaderNodes::Cast::Build(node.exprType, expressions.data(), expressionCount)); + } + + void ShaderAstCloner::Visit(ShaderNodes::Constant& node) + { + PushExpression(ShaderNodes::Constant::Build(node.value)); + } + + void ShaderAstCloner::Visit(ShaderNodes::DeclareVariable& node) + { + PushStatement(ShaderNodes::DeclareVariable::Build(CloneVariable(node.variable), CloneExpression(node.expression))); + } + + void ShaderAstCloner::Visit(ShaderNodes::ExpressionStatement& node) + { + PushStatement(ShaderNodes::ExpressionStatement::Build(CloneExpression(node.expression))); + } + + void ShaderAstCloner::Visit(ShaderNodes::Identifier& node) + { + PushExpression(ShaderNodes::Identifier::Build(CloneVariable(node.var))); + } + + void ShaderAstCloner::Visit(ShaderNodes::IntrinsicCall& node) + { + std::vector parameters; + parameters.reserve(node.parameters.size()); + + for (auto& parameter : node.parameters) + parameters.push_back(CloneExpression(parameter)); + + PushExpression(ShaderNodes::IntrinsicCall::Build(node.intrinsic, std::move(parameters))); + } + + void ShaderAstCloner::Visit(ShaderNodes::Sample2D& node) + { + PushExpression(ShaderNodes::Sample2D::Build(CloneExpression(node.sampler), CloneExpression(node.coordinates))); + } + + void ShaderAstCloner::Visit(ShaderNodes::StatementBlock& node) + { + std::vector statements; + statements.reserve(node.statements.size()); + + for (auto& statement : node.statements) + statements.push_back(CloneStatement(statement)); + + PushStatement(ShaderNodes::StatementBlock::Build(std::move(statements))); + } + + void ShaderAstCloner::Visit(ShaderNodes::SwizzleOp& node) + { + PushExpression(ShaderNodes::SwizzleOp::Build(CloneExpression(node.expression), node.components.data(), node.componentCount)); + } + + void ShaderAstCloner::Visit(ShaderNodes::BuiltinVariable& var) + { + PushVariable(ShaderNodes::BuiltinVariable::Build(var.entry, var.type)); + } + + void ShaderAstCloner::Visit(ShaderNodes::InputVariable& var) + { + PushVariable(ShaderNodes::InputVariable::Build(var.name, var.type)); + } + + void ShaderAstCloner::Visit(ShaderNodes::LocalVariable& var) + { + PushVariable(ShaderNodes::LocalVariable::Build(var.name, var.type)); + } + + void ShaderAstCloner::Visit(ShaderNodes::OutputVariable& var) + { + PushVariable(ShaderNodes::OutputVariable::Build(var.name, var.type)); + } + + void ShaderAstCloner::Visit(ShaderNodes::ParameterVariable& var) + { + PushVariable(ShaderNodes::ParameterVariable::Build(var.name, var.type)); + } + + void ShaderAstCloner::Visit(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/Shader/ShaderAstRecursiveVisitor.cpp b/src/Nazara/Shader/ShaderAstRecursiveVisitor.cpp new file mode 100644 index 000000000..98fdbfee6 --- /dev/null +++ b/src/Nazara/Shader/ShaderAstRecursiveVisitor.cpp @@ -0,0 +1,93 @@ +// 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 +{ + void ShaderAstRecursiveVisitor::Visit(ShaderNodes::AccessMember& node) + { + Visit(node.structExpr); + } + + void ShaderAstRecursiveVisitor::Visit(ShaderNodes::AssignOp& node) + { + Visit(node.left); + Visit(node.right); + } + + void ShaderAstRecursiveVisitor::Visit(ShaderNodes::BinaryOp& node) + { + Visit(node.left); + Visit(node.right); + } + + void ShaderAstRecursiveVisitor::Visit(ShaderNodes::Branch& node) + { + for (auto& cond : node.condStatements) + { + Visit(cond.condition); + Visit(cond.statement); + } + + if (node.elseStatement) + Visit(node.elseStatement); + } + + void ShaderAstRecursiveVisitor::Visit(ShaderNodes::Cast& node) + { + for (auto& expr : node.expressions) + { + if (!expr) + break; + + Visit(expr); + } + } + + void ShaderAstRecursiveVisitor::Visit(ShaderNodes::Constant& /*node*/) + { + /* Nothing to do */ + } + + void ShaderAstRecursiveVisitor::Visit(ShaderNodes::DeclareVariable& node) + { + if (node.expression) + Visit(node.expression); + } + + void ShaderAstRecursiveVisitor::Visit(ShaderNodes::ExpressionStatement& node) + { + Visit(node.expression); + } + + void ShaderAstRecursiveVisitor::Visit(ShaderNodes::Identifier& /*node*/) + { + /* Nothing to do */ + } + + void ShaderAstRecursiveVisitor::Visit(ShaderNodes::IntrinsicCall& node) + { + for (auto& param : node.parameters) + Visit(param); + } + + void ShaderAstRecursiveVisitor::Visit(ShaderNodes::Sample2D& node) + { + Visit(node.sampler); + Visit(node.coordinates); + } + + void ShaderAstRecursiveVisitor::Visit(ShaderNodes::StatementBlock& node) + { + for (auto& statement : node.statements) + Visit(statement); + } + + void ShaderAstRecursiveVisitor::Visit(ShaderNodes::SwizzleOp& node) + { + Visit(node.expression); + } +} diff --git a/src/Nazara/Shader/ShaderAstSerializer.cpp b/src/Nazara/Shader/ShaderAstSerializer.cpp new file mode 100644 index 000000000..03cd36d8b --- /dev/null +++ b/src/Nazara/Shader/ShaderAstSerializer.cpp @@ -0,0 +1,771 @@ +// 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 + { + constexpr UInt32 s_magicNumber = 0x4E534852; + constexpr UInt32 s_currentVersion = 1; + + class ShaderSerializerVisitor : public ShaderAstVisitor, public ShaderVarVisitor + { + public: + ShaderSerializerVisitor(ShaderAstSerializerBase& serializer) : + m_serializer(serializer) + { + } + + void Visit(ShaderNodes::AccessMember& node) override + { + Serialize(node); + } + + void Visit(ShaderNodes::AssignOp& node) override + { + Serialize(node); + } + + void Visit(ShaderNodes::BinaryOp& node) override + { + Serialize(node); + } + + void Visit(ShaderNodes::Branch& node) override + { + Serialize(node); + } + + void Visit(ShaderNodes::Cast& node) override + { + Serialize(node); + } + + void Visit(ShaderNodes::Constant& node) override + { + Serialize(node); + } + + void Visit(ShaderNodes::DeclareVariable& node) override + { + Serialize(node); + } + + void Visit(ShaderNodes::ExpressionStatement& node) override + { + Serialize(node); + } + + void Visit(ShaderNodes::Identifier& node) override + { + Serialize(node); + } + + void Visit(ShaderNodes::IntrinsicCall& node) override + { + Serialize(node); + } + + void Visit(ShaderNodes::Sample2D& node) override + { + Serialize(node); + } + + void Visit(ShaderNodes::StatementBlock& node) override + { + Serialize(node); + } + + void Visit(ShaderNodes::SwizzleOp& node) override + { + Serialize(node); + } + + + void Visit(ShaderNodes::BuiltinVariable& var) override + { + Serialize(var); + } + + void Visit(ShaderNodes::InputVariable& var) override + { + Serialize(var); + } + + void Visit(ShaderNodes::LocalVariable& var) override + { + Serialize(var); + } + + void Visit(ShaderNodes::OutputVariable& var) override + { + Serialize(var); + } + + void Visit(ShaderNodes::ParameterVariable& var) override + { + Serialize(var); + } + + void Visit(ShaderNodes::UniformVariable& var) override + { + Serialize(var); + } + + 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)); + } + + ShaderAstSerializerBase& m_serializer; + }; + } + + void ShaderAstSerializerBase::Serialize(ShaderNodes::AccessMember& node) + { + Node(node.structExpr); + Type(node.exprType); + + Container(node.memberIndices); + for (std::size_t& index : node.memberIndices) + Value(index); + } + + void ShaderAstSerializerBase::Serialize(ShaderNodes::AssignOp& node) + { + Enum(node.op); + Node(node.left); + Node(node.right); + } + + void ShaderAstSerializerBase::Serialize(ShaderNodes::BinaryOp& node) + { + Enum(node.op); + Node(node.left); + Node(node.right); + } + + void ShaderAstSerializerBase::Serialize(ShaderNodes::Branch& node) + { + Container(node.condStatements); + for (auto& condStatement : node.condStatements) + { + Node(condStatement.condition); + Node(condStatement.statement); + } + + Node(node.elseStatement); + } + + void ShaderAstSerializerBase::Serialize(ShaderNodes::BuiltinVariable& node) + { + Enum(node.entry); + Type(node.type); + } + + void ShaderAstSerializerBase::Serialize(ShaderNodes::Cast& node) + { + Enum(node.exprType); + for (auto& expr : node.expressions) + Node(expr); + } + + void ShaderAstSerializerBase::Serialize(ShaderNodes::Constant& node) + { + UInt32 typeIndex; + if (IsWriting()) + typeIndex = UInt32(node.value.index()); + + Value(typeIndex); + + // Waiting for template lambda in C++20 + auto SerializeValue = [&](auto dummyType) + { + using T = std::decay_t; + + auto& value = (IsWriting()) ? std::get(node.value) : node.value.emplace(); + Value(value); + }; + + 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(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"); + } + } + + void ShaderAstSerializerBase::Serialize(ShaderNodes::DeclareVariable& node) + { + Variable(node.variable); + Node(node.expression); + } + + void ShaderAstSerializerBase::Serialize(ShaderNodes::ExpressionStatement& node) + { + Node(node.expression); + } + + void ShaderAstSerializerBase::Serialize(ShaderNodes::Identifier& node) + { + Variable(node.var); + } + + void ShaderAstSerializerBase::Serialize(ShaderNodes::IntrinsicCall& node) + { + Enum(node.intrinsic); + Container(node.parameters); + for (auto& param : node.parameters) + Node(param); + } + + void ShaderAstSerializerBase::Serialize(ShaderNodes::NamedVariable& node) + { + Value(node.name); + Type(node.type); + } + + void ShaderAstSerializerBase::Serialize(ShaderNodes::Sample2D& node) + { + Node(node.sampler); + Node(node.coordinates); + } + + void ShaderAstSerializerBase::Serialize(ShaderNodes::StatementBlock& node) + { + Container(node.statements); + for (auto& statement : node.statements) + Node(statement); + } + + void ShaderAstSerializerBase::Serialize(ShaderNodes::SwizzleOp& node) + { + Value(node.componentCount); + Node(node.expression); + + for (std::size_t i = 0; i < node.componentCount; ++i) + Enum(node.components[i]); + } + + + void ShaderAstSerializer::Serialize(const ShaderAst& shader) + { + m_stream << s_magicNumber << s_currentVersion; + + m_stream << UInt32(shader.GetStage()); + + auto SerializeType = [&](const 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); + }; + + auto SerializeInputOutput = [&](auto& inout) + { + m_stream << UInt32(inout.size()); + for (const auto& data : inout) + { + m_stream << data.name; + SerializeType(data.type); + + m_stream << data.locationIndex.has_value(); + if (data.locationIndex) + m_stream << UInt32(data.locationIndex.value()); + } + }; + + 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; + 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()); + 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; + SerializeType(param.type); + } + + Node(func.statement); + } + + m_stream.FlushBits(); + } + + bool ShaderAstSerializer::IsWriting() const + { + return true; + } + + void ShaderAstSerializer::Node(ShaderNodes::NodePtr& node) + { + ShaderNodes::NodeType nodeType = (node) ? node->GetType() : ShaderNodes::NodeType::None; + m_stream << static_cast(nodeType); + + if (node) + { + ShaderSerializerVisitor visitor(*this); + node->Visit(visitor); + } + } + + void ShaderAstSerializer::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 ShaderAstSerializer::Node(const ShaderNodes::NodePtr& node) + { + Node(const_cast(node)); //< Yes const_cast is ugly but it won't be used for writing + } + + void ShaderAstSerializer::Value(bool& val) + { + m_stream << val; + } + + void ShaderAstSerializer::Value(float& val) + { + m_stream << val; + } + + void ShaderAstSerializer::Value(std::string& val) + { + m_stream << val; + } + + void ShaderAstSerializer::Value(Int32& val) + { + m_stream << val; + } + + void ShaderAstSerializer::Value(Vector2f& val) + { + m_stream << val; + } + + void ShaderAstSerializer::Value(Vector3f& val) + { + m_stream << val; + } + + void ShaderAstSerializer::Value(Vector4f& val) + { + 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; + } + + void ShaderAstSerializer::Value(UInt16& val) + { + m_stream << val; + } + + void ShaderAstSerializer::Value(UInt32& val) + { + m_stream << val; + } + + void ShaderAstSerializer::Variable(ShaderNodes::VariablePtr& var) + { + ShaderNodes::VariableType nodeType = (var) ? var->GetType() : ShaderNodes::VariableType::None; + m_stream << static_cast(nodeType); + + if (var) + { + ShaderSerializerVisitor visitor(*this); + var->Visit(visitor); + } + } + + ShaderAst ShaderAstUnserializer::Unserialize() + { + UInt32 magicNumber; + UInt32 version; + m_stream >> magicNumber; + if (magicNumber != s_magicNumber) + throw std::runtime_error("invalid shader file"); + + m_stream >> version; + if (version > s_currentVersion) + throw std::runtime_error("unsupported version"); + + UInt32 shaderStage; + m_stream >> shaderStage; + + ShaderAst shader(static_cast(shaderStage)); + + 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; + ShaderExpressionType inputType; + std::optional location; + + Value(inputName); + Type(inputType); + OptVal(location); + + shader.AddInput(std::move(inputName), std::move(inputType), location); + } + + UInt32 outputCount; + m_stream >> outputCount; + for (UInt32 i = 0; i < outputCount; ++i) + { + std::string outputName; + ShaderExpressionType outputType; + std::optional location; + + Value(outputName); + Type(outputType); + OptVal(location); + + shader.AddOutput(std::move(outputName), std::move(outputType), location); + } + + UInt32 uniformCount; + m_stream >> uniformCount; + for (UInt32 i = 0; i < uniformCount; ++i) + { + std::string name; + ShaderExpressionType type; + std::optional binding; + std::optional memLayout; + + Value(name); + Type(type); + OptVal(binding); + OptEnum(memLayout); + + shader.AddUniform(std::move(name), std::move(type), std::move(binding), std::move(memLayout)); + } + + UInt32 funcCount; + m_stream >> funcCount; + for (UInt32 i = 0; i < funcCount; ++i) + { + std::string name; + ShaderNodes::BasicType retType; + std::vector parameters; + + Value(name); + Enum(retType); + Container(parameters); + for (auto& param : parameters) + { + Value(param.name); + Type(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 ShaderAstUnserializer::IsWriting() const + { + return false; + } + + void ShaderAstUnserializer::Node(ShaderNodes::NodePtr& node) + { + Int32 nodeTypeInt; + m_stream >> nodeTypeInt; + + ShaderNodes::NodeType nodeType = static_cast(nodeTypeInt); + +#define HandleType(Type) case ShaderNodes::NodeType:: Type : node = std::make_shared(); break + switch (nodeType) + { + case ShaderNodes::NodeType::None: break; + + HandleType(AccessMember); + 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 HandleType + + if (node) + { + ShaderSerializerVisitor visitor(*this); + node->Visit(visitor); + } + } + + void ShaderAstUnserializer::Type(ShaderExpressionType& type) + { + UInt8 typeIndex; + Value(typeIndex); + + switch (typeIndex) + { + case 0: //< Primitive + { + ShaderNodes::BasicType exprType; + Enum(exprType); + + type = exprType; + break; + } + + case 1: //< Struct (name) + { + std::string structName; + Value(structName); + + type = std::move(structName); + break; + } + + default: + break; + } + } + + void ShaderAstUnserializer::Value(bool& val) + { + m_stream >> val; + } + + void ShaderAstUnserializer::Value(float& val) + { + m_stream >> val; + } + + void ShaderAstUnserializer::Value(std::string& val) + { + m_stream >> val; + } + + void ShaderAstUnserializer::Value(Int32& val) + { + m_stream >> val; + } + + void ShaderAstUnserializer::Value(Vector2f& val) + { + m_stream >> val; + } + + void ShaderAstUnserializer::Value(Vector3f& val) + { + m_stream >> val; + } + + void ShaderAstUnserializer::Value(Vector4f& val) + { + 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; + } + + void ShaderAstUnserializer::Value(UInt16& val) + { + m_stream >> val; + } + + void ShaderAstUnserializer::Value(UInt32& val) + { + m_stream >> val; + } + + void ShaderAstUnserializer::Variable(ShaderNodes::VariablePtr& var) + { + Int32 nodeTypeInt; + m_stream >> nodeTypeInt; + + ShaderNodes::VariableType nodeType = static_cast(nodeTypeInt); + +#define HandleType(Type) case ShaderNodes::VariableType:: Type : var = std::make_shared(); break + switch (nodeType) + { + case ShaderNodes::VariableType::None: break; + + HandleType(BuiltinVariable); + HandleType(InputVariable); + HandleType(LocalVariable); + HandleType(ParameterVariable); + HandleType(OutputVariable); + HandleType(UniformVariable); + } +#undef HandleType + + if (var) + { + ShaderSerializerVisitor visitor(*this); + var->Visit(visitor); + } + } + + + ByteArray SerializeShader(const ShaderAst& shader) + { + ByteArray byteArray; + ByteStream stream(&byteArray, OpenModeFlags(OpenMode_WriteOnly)); + + ShaderAstSerializer serializer(stream); + serializer.Serialize(shader); + + return byteArray; + } + + ShaderAst UnserializeShader(ByteStream& stream) + { + ShaderAstUnserializer unserializer(stream); + return unserializer.Unserialize(); + } +} + diff --git a/src/Nazara/Shader/ShaderAstValidator.cpp b/src/Nazara/Shader/ShaderAstValidator.cpp new file mode 100644 index 000000000..b614ec4a2 --- /dev/null +++ b/src/Nazara/Shader/ShaderAstValidator.cpp @@ -0,0 +1,467 @@ +// 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 + +namespace Nz +{ + struct AstError + { + std::string errMsg; + }; + + struct ShaderAstValidator::Context + { + struct Local + { + std::string name; + ShaderExpressionType type; + }; + + const ShaderAst::Function* currentFunction; + std::vector declaredLocals; + std::vector blockLocalIndex; + }; + + bool ShaderAstValidator::Validate(std::string* error) + { + try + { + 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) + { + if (error) + *error = e.errMsg; + + return false; + } + } + + const ShaderNodes::ExpressionPtr& ShaderAstValidator::MandatoryExpr(const ShaderNodes::ExpressionPtr& node) + { + MandatoryNode(node); + + return node; + } + + const ShaderNodes::NodePtr& ShaderAstValidator::MandatoryNode(const ShaderNodes::NodePtr& node) + { + if (!node) + throw AstError{ "Invalid node" }; + + return node; + } + + void ShaderAstValidator::TypeMustMatch(const ShaderNodes::ExpressionPtr& left, const ShaderNodes::ExpressionPtr& right) + { + return TypeMustMatch(left->GetExpressionType(), right->GetExpressionType()); + } + + void ShaderAstValidator::TypeMustMatch(const ShaderExpressionType& left, const ShaderExpressionType& right) + { + if (left != right) + 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(); + if (!std::holds_alternative(exprType)) + throw AstError{ "expression is not a structure" }; + + const std::string& structName = std::get(exprType); + + 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" }; + } + + void ShaderAstValidator::Visit(ShaderNodes::AssignOp& node) + { + MandatoryNode(node.left); + MandatoryNode(node.right); + TypeMustMatch(node.left, node.right); + + if (node.left->GetExpressionCategory() != ShaderNodes::ExpressionCategory::LValue) + throw AstError { "Assignation is only possible with a l-value" }; + + ShaderAstRecursiveVisitor::Visit(node); + } + + void ShaderAstValidator::Visit(ShaderNodes::BinaryOp& node) + { + MandatoryNode(node.left); + MandatoryNode(node.right); + + 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) + { + case ShaderNodes::BinaryType::Add: + case ShaderNodes::BinaryType::Equality: + case ShaderNodes::BinaryType::Substract: + TypeMustMatch(node.left, node.right); + break; + + case ShaderNodes::BinaryType::Multiply: + case ShaderNodes::BinaryType::Divide: + { + switch (leftType) + { + case ShaderNodes::BasicType::Float1: + case ShaderNodes::BasicType::Int1: + { + if (ShaderNodes::Node::GetComponentType(rightType) != leftType) + throw AstError{ "Left expression type is not compatible with right expression type" }; + + 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: + { + if (leftType != rightType && rightType != ShaderNodes::Node::GetComponentType(leftType)) + throw AstError{ "Left expression type is not compatible with right expression type" }; + + break; + } + + case ShaderNodes::BasicType::Mat4x4: + { + switch (rightType) + { + case ShaderNodes::BasicType::Float1: + case ShaderNodes::BasicType::Float4: + case ShaderNodes::BasicType::Mat4x4: + break; + + default: + TypeMustMatch(node.left, node.right); + } + + break; + } + + default: + TypeMustMatch(node.left, node.right); + } + } + } + + ShaderAstRecursiveVisitor::Visit(node); + } + + void ShaderAstValidator::Visit(ShaderNodes::Branch& node) + { + for (const auto& condStatement : node.condStatements) + { + MandatoryNode(condStatement.condition); + MandatoryNode(condStatement.statement); + } + + ShaderAstRecursiveVisitor::Visit(node); + } + + void ShaderAstValidator::Visit(ShaderNodes::Cast& node) + { + unsigned int componentCount = 0; + unsigned int requiredComponents = node.GetComponentCount(node.exprType); + for (const auto& exprPtr : node.expressions) + { + if (!exprPtr) + break; + + const ShaderExpressionType& exprType = exprPtr->GetExpressionType(); + if (!std::holds_alternative(exprType)) + throw AstError{ "incompatible type" }; + + componentCount += node.GetComponentCount(std::get(exprType)); + } + + if (componentCount != requiredComponents) + throw AstError{ "Component count doesn't match required component count" }; + + ShaderAstRecursiveVisitor::Visit(node); + } + + void ShaderAstValidator::Visit(ShaderNodes::Constant& /*node*/) + { + } + + void ShaderAstValidator::Visit(ShaderNodes::DeclareVariable& node) + { + 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 = localVar.name; + local.type = localVar.type; + + ShaderAstRecursiveVisitor::Visit(node); + } + + void ShaderAstValidator::Visit(ShaderNodes::ExpressionStatement& node) + { + MandatoryNode(node.expression); + + ShaderAstRecursiveVisitor::Visit(node); + } + + void ShaderAstValidator::Visit(ShaderNodes::Identifier& node) + { + assert(m_context); + + if (!node.var) + throw AstError{ "Invalid variable" }; + + Visit(node.var); + } + + void ShaderAstValidator::Visit(ShaderNodes::IntrinsicCall& node) + { + 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); + + ShaderExpressionType 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() != ShaderExpressionType{ ShaderNodes::BasicType::Float3 }) + throw AstError{ "CrossProduct only works with Float3 expressions" }; + + break; + } + + case ShaderNodes::IntrinsicType::DotProduct: + break; + } + + ShaderAstRecursiveVisitor::Visit(node); + } + + void ShaderAstValidator::Visit(ShaderNodes::Sample2D& node) + { + if (MandatoryExpr(node.sampler)->GetExpressionType() != ShaderExpressionType{ ShaderNodes::BasicType::Sampler2D }) + throw AstError{ "Sampler must be a Sampler2D" }; + + if (MandatoryExpr(node.coordinates)->GetExpressionType() != ShaderExpressionType{ ShaderNodes::BasicType::Float2 }) + throw AstError{ "Coordinates must be a Float2" }; + + ShaderAstRecursiveVisitor::Visit(node); + } + + void ShaderAstValidator::Visit(ShaderNodes::StatementBlock& node) + { + assert(m_context); + + m_context->blockLocalIndex.push_back(m_context->declaredLocals.size()); + + for (const auto& statement : node.statements) + MandatoryNode(statement); + + assert(m_context->declaredLocals.size() >= m_context->blockLocalIndex.back()); + m_context->declaredLocals.resize(m_context->blockLocalIndex.back()); + m_context->blockLocalIndex.pop_back(); + + ShaderAstRecursiveVisitor::Visit(node); + } + + void ShaderAstValidator::Visit(ShaderNodes::SwizzleOp& node) + { + if (node.componentCount > 4) + throw AstError{ "Cannot swizzle more than four elements" }; + + 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: + 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: + throw AstError{ "Cannot swizzle this type" }; + } + + ShaderAstRecursiveVisitor::Visit(node); + } + + void ShaderAstValidator::Visit(ShaderNodes::BuiltinVariable& var) + { + 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(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 ShaderAstValidator::Visit(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 ShaderAstValidator::Visit(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 ShaderAstValidator::Visit(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 ShaderAstValidator::Visit(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) + { + ShaderAstValidator validator(shader); + return validator.Validate(error); + } +} diff --git a/src/Nazara/Shader/ShaderAstVisitor.cpp b/src/Nazara/Shader/ShaderAstVisitor.cpp new file mode 100644 index 000000000..53325c9ca --- /dev/null +++ b/src/Nazara/Shader/ShaderAstVisitor.cpp @@ -0,0 +1,29 @@ +// 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 +{ + ShaderAstVisitor::~ShaderAstVisitor() = default; + + void ShaderAstVisitor::EnableCondition(const std::string& name, bool cond) + { + if (cond) + m_conditions.insert(name); + else + m_conditions.erase(name); + } + + bool ShaderAstVisitor::IsConditionEnabled(const std::string& name) const + { + return m_conditions.count(name) != 0; + } + + void ShaderAstVisitor::Visit(const ShaderNodes::NodePtr& node) + { + node->Visit(*this); + } +} 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/ShaderNodes.cpp b/src/Nazara/Shader/ShaderNodes.cpp new file mode 100644 index 000000000..15c7e40f0 --- /dev/null +++ b/src/Nazara/Shader/ShaderNodes.cpp @@ -0,0 +1,256 @@ +// 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 + +namespace Nz::ShaderNodes +{ + Node::~Node() = default; + + ExpressionCategory Expression::GetExpressionCategory() const + { + return ExpressionCategory::RValue; + } + + void ExpressionStatement::Visit(ShaderAstVisitor& visitor) + { + visitor.Visit(*this); + } + + + void ConditionalStatement::Visit(ShaderAstVisitor& visitor) + { + if (visitor.IsConditionEnabled(conditionName)) + statement->Visit(visitor); + } + + + void StatementBlock::Visit(ShaderAstVisitor& visitor) + { + visitor.Visit(*this); + } + + + void DeclareVariable::Visit(ShaderAstVisitor& visitor) + { + visitor.Visit(*this); + } + + + ExpressionCategory Identifier::GetExpressionCategory() const + { + return ExpressionCategory::LValue; + } + + ShaderExpressionType Identifier::GetExpressionType() const + { + assert(var); + return var->type; + } + + void Identifier::Visit(ShaderAstVisitor& visitor) + { + visitor.Visit(*this); + } + + ExpressionCategory AccessMember::GetExpressionCategory() const + { + return structExpr->GetExpressionCategory(); + } + + ShaderExpressionType AccessMember::GetExpressionType() const + { + return exprType; + } + + void AccessMember::Visit(ShaderAstVisitor& visitor) + { + visitor.Visit(*this); + } + + ShaderExpressionType AssignOp::GetExpressionType() const + { + return left->GetExpressionType(); + } + + void AssignOp::Visit(ShaderAstVisitor& visitor) + { + visitor.Visit(*this); + } + + + ShaderExpressionType BinaryOp::GetExpressionType() const + { + std::optional exprType; + + switch (op) + { + case BinaryType::Add: + case BinaryType::Substract: + exprType = left->GetExpressionType(); + break; + + case BinaryType::Divide: + case BinaryType::Multiply: + { + const ShaderExpressionType& leftExprType = left->GetExpressionType(); + assert(std::holds_alternative(leftExprType)); + + const ShaderExpressionType& rightExprType = right->GetExpressionType(); + assert(std::holds_alternative(rightExprType)); + + switch (std::get(leftExprType)) + { + case BasicType::Boolean: + case BasicType::Float2: + case BasicType::Float3: + case BasicType::Float4: + 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; + + case BasicType::Sampler2D: + case BasicType::Void: + break; + } + + break; + } + + case BinaryType::Equality: + exprType = BasicType::Boolean; + break; + } + + NazaraAssert(exprType.has_value(), "Unhandled builtin"); + + return *exprType; + } + + void BinaryOp::Visit(ShaderAstVisitor& visitor) + { + visitor.Visit(*this); + } + + + void Branch::Visit(ShaderAstVisitor& visitor) + { + visitor.Visit(*this); + } + + + ShaderExpressionType Constant::GetExpressionType() const + { + 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::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) + 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); + } + + void Constant::Visit(ShaderAstVisitor& visitor) + { + visitor.Visit(*this); + } + + ShaderExpressionType Cast::GetExpressionType() const + { + return exprType; + } + + void Cast::Visit(ShaderAstVisitor& visitor) + { + visitor.Visit(*this); + } + + + ExpressionCategory SwizzleOp::GetExpressionCategory() const + { + return expression->GetExpressionCategory(); + } + + ShaderExpressionType SwizzleOp::GetExpressionType() const + { + const ShaderExpressionType& exprType = expression->GetExpressionType(); + assert(std::holds_alternative(exprType)); + + return static_cast(UnderlyingCast(GetComponentType(std::get(exprType))) + componentCount - 1); + } + + void SwizzleOp::Visit(ShaderAstVisitor& visitor) + { + visitor.Visit(*this); + } + + + ShaderExpressionType Sample2D::GetExpressionType() const + { + return BasicType::Float4; + } + + void Sample2D::Visit(ShaderAstVisitor& visitor) + { + visitor.Visit(*this); + } + + + ShaderExpressionType IntrinsicCall::GetExpressionType() const + { + switch (intrinsic) + { + case IntrinsicType::CrossProduct: + return parameters.front()->GetExpressionType(); + + case IntrinsicType::DotProduct: + return BasicType::Float1; + } + + NazaraAssert(false, "Unhandled builtin"); + return BasicType::Void; + } + + void IntrinsicCall::Visit(ShaderAstVisitor& visitor) + { + visitor.Visit(*this); + } +} diff --git a/src/Nazara/Shader/ShaderVarVisitor.cpp b/src/Nazara/Shader/ShaderVarVisitor.cpp new file mode 100644 index 000000000..108d5c69a --- /dev/null +++ b/src/Nazara/Shader/ShaderVarVisitor.cpp @@ -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 +{ + ShaderVarVisitor::~ShaderVarVisitor() = default; + + void ShaderVarVisitor::Visit(const ShaderNodes::VariablePtr& node) + { + node->Visit(*this); + } +} 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/ShaderVariables.cpp b/src/Nazara/Shader/ShaderVariables.cpp new file mode 100644 index 000000000..ebe520a0c --- /dev/null +++ b/src/Nazara/Shader/ShaderVariables.cpp @@ -0,0 +1,77 @@ +// 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::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/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/Shader/SpirvAstVisitor.cpp b/src/Nazara/Shader/SpirvAstVisitor.cpp new file mode 100644 index 000000000..6cf45cee7 --- /dev/null +++ b/src/Nazara/Shader/SpirvAstVisitor.cpp @@ -0,0 +1,435 @@ +// 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); + + assert(m_resultIds.size() == 1); + 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/SpirvConstantCache.cpp b/src/Nazara/Shader/SpirvConstantCache.cpp new file mode 100644 index 000000000..db2bdb7ee --- /dev/null +++ b/src/Nazara/Shader/SpirvConstantCache.cpp @@ -0,0 +1,909 @@ +// 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 +{ + namespace + { + template struct overloaded : Ts... { using Ts::operator()...; }; + + template overloaded(Ts...)->overloaded; + } + 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, UInt32 /*id*/, AnyHasher, Eq> ids; + 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->ids.find(c.constant); + if (it == m_internal->ids.end()) + throw std::runtime_error("constant is not registered"); + + return it->second; + } + + UInt32 SpirvConstantCache::GetId(const Type& t) + { + 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; + } + + 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->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->ids.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->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->ids.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) + { + for (auto&& [type, id] : m_internal->ids) + { + UInt32 resultId = id; + + std::visit(overloaded + { + [&](const AnyConstant& constant) { Write(constant, resultId, constants); }, + [&](const AnyType& type) { Write(type, resultId, annotations, constants, debugInfos); }, + }, type); + } + + 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::Write(const AnyConstant& constant, UInt32 resultId, SpirvSection& constants) + { + 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); + + 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/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; + } +} diff --git a/src/Nazara/Shader/SpirvExpressionLoad.cpp b/src/Nazara/Shader/SpirvExpressionLoad.cpp new file mode 100644 index 000000000..00e7ad815 --- /dev/null +++ b/src/Nazara/Shader/SpirvExpressionLoad.cpp @@ -0,0 +1,121 @@ +// 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 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) + { + 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 SpirvExpressionLoad::Visit(ShaderNodes::Identifier& node) + { + Visit(node.var); + } + + void SpirvExpressionLoad::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 SpirvExpressionLoad::Visit(ShaderNodes::LocalVariable& var) + { + m_value = Value{ m_writer.ReadLocalVariable(var.name) }; + } + + void SpirvExpressionLoad::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..964baf129 --- /dev/null +++ b/src/Nazara/Shader/SpirvPrinter.cpp @@ -0,0 +1,246 @@ +// 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; + const Settings& settings; + }; + + std::string SpirvPrinter::Print(const UInt32* codepoints, std::size_t count, const Settings& settings) + { + State state = { + codepoints, + 0, + count, + {}, + settings + }; + + 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"); + + if (m_currentState->settings.printHeader) + 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; + + UInt32 generatorId = ReadWord(); + UInt32 bound = ReadWord(); + UInt32 schema = ReadWord(); + + 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(); + + 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; + + if (m_currentState->settings.printParameters) + { + 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++; + } + } + 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"; + + 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/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 new file mode 100644 index 000000000..81f9d1d7f --- /dev/null +++ b/src/Nazara/Shader/SpirvWriter.cpp @@ -0,0 +1,661 @@ +// 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 +#include +#include +#include +#include +#include + +namespace Nz +{ + namespace + { + class PreVisitor : public ShaderAstRecursiveVisitor, 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>; + + PreVisitor(SpirvConstantCache& constantCache) : + m_constantCache(constantCache) + { + } + + using ShaderAstRecursiveVisitor::Visit; + using ShaderVarVisitor::Visit; + + void Visit(ShaderNodes::AccessMember& node) override + { + for (std::size_t index : node.memberIndices) + m_constantCache.Register(*SpirvConstantCache::BuildConstant(Int32(index))); + + ShaderAstRecursiveVisitor::Visit(node); + } + + void Visit(ShaderNodes::Constant& node) override + { + std::visit([&](auto&& arg) + { + m_constantCache.Register(*SpirvConstantCache::BuildConstant(arg)); + }, node.value); + + ShaderAstRecursiveVisitor::Visit(node); + } + + void Visit(ShaderNodes::DeclareVariable& node) override + { + Visit(node.variable); + + ShaderAstRecursiveVisitor::Visit(node); + } + + void Visit(ShaderNodes::Identifier& node) override + { + Visit(node.var); + + ShaderAstRecursiveVisitor::Visit(node); + } + + void Visit(ShaderNodes::IntrinsicCall& node) override + { + ShaderAstRecursiveVisitor::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(ShaderNodes::BuiltinVariable& var) override + { + builtinVars.insert(std::static_pointer_cast(var.shared_from_this())); + } + + void Visit(ShaderNodes::InputVariable& /*var*/) override + { + /* Handled by ShaderAst */ + } + + void Visit(ShaderNodes::LocalVariable& var) override + { + localVars.insert(std::static_pointer_cast(var.shared_from_this())); + } + + void Visit(ShaderNodes::OutputVariable& /*var*/) override + { + /* Handled by ShaderAst */ + } + + void Visit(ShaderNodes::ParameterVariable& var) override + { + paramVars.insert(std::static_pointer_cast(var.shared_from_this())); + } + + void Visit(ShaderNodes::UniformVariable& /*var*/) override + { + /* Handled by ShaderAst */ + } + + BuiltinContainer builtinVars; + ExtInstList extInsts; + LocalContainer localVars; + ParameterContainer paramVars; + + private: + SpirvConstantCache& m_constantCache; + }; + + 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::State + { + State() : + constantTypeCache(nextVarIndex) + { + } + + struct Func + { + UInt32 typeId; + UInt32 id; + std::vector paramsId; + }; + + tsl::ordered_map inputIds; + tsl::ordered_map outputIds; + tsl::ordered_map uniformIds; + 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; + SpirvSection constants; + SpirvSection debugInfo; + SpirvSection annotations; + SpirvSection instructions; + }; + + 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; + }); + + std::vector functionStatements; + + ShaderAstCloner cloner; + + PreVisitor preVisitor(state.constantTypeCache); + 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) + state.extensionInstructions[extInst] = AllocateResultId(); + + // Register all types + for (const auto& func : shader.GetFunctions()) + { + RegisterType(func.returnType); + for (const auto& param : func.parameters) + RegisterType(param.type); + } + + for (const auto& input : shader.GetInputs()) + RegisterPointerType(input.type, SpirvStorageClass::Input); + + for (const auto& output : shader.GetOutputs()) + RegisterPointerType(output.type, SpirvStorageClass::Output); + + for (const auto& uniform : shader.GetUniforms()) + 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); + + for (const auto& builtin : preVisitor.builtinVars) + RegisterType(builtin->type); + + // Register result id and debug infos for global variables/functions + for (const auto& builtin : preVisitor.builtinVars) + { + SpirvConstantCache::Variable variable; + SpirvBuiltIn builtinDecoration; + switch (builtin->entry) + { + case ShaderNodes::BuiltinEntry::VertexPosition: + variable.debugName = "builtin_VertexPosition"; + variable.storageClass = SpirvStorageClass::Output; + + builtinDecoration = SpirvBuiltIn::Position; + break; + + default: + throw std::runtime_error("unexpected builtin type"); + } + + const ShaderExpressionType& builtinExprType = builtin->type; + assert(std::holds_alternative(builtinExprType)); + + 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 = GetPointerTypeId(input.type, variable.storageClass); + inputData.typeId = GetTypeId(input.type); + inputData.varId = varId; + + state.inputIds.emplace(input.name, std::move(inputData)); + + if (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 = GetPointerTypeId(output.type, variable.storageClass); + outputData.typeId = GetTypeId(output.type); + outputData.varId = varId; + + state.outputIds.emplace(output.name, std::move(outputData)); + + if (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 = GetPointerTypeId(uniform.type, variable.storageClass); + uniformData.typeId = GetTypeId(uniform.type); + uniformData.varId = varId; + + state.uniformIds.emplace(uniform.name, std::move(uniformData)); + + if (uniform.bindingIndex) + { + state.annotations.Append(SpirvOp::OpDecorate, varId, SpvDecorationBinding, *uniform.bindingIndex); + state.annotations.Append(SpirvOp::OpDecorate, varId, SpvDecorationDescriptorSet, 0); + } + } + + for (const auto& func : shader.GetFunctions()) + { + auto& funcData = state.funcs.emplace_back(); + funcData.id = AllocateResultId(); + funcData.typeId = GetFunctionTypeId(func.returnType, func.parameters); + + state.debugInfo.Append(SpirvOp::OpName, funcData.id, func.name); + } + + 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(SpirvOp::OpFunction, GetTypeId(func.returnType), funcData.id, 0, funcData.typeId); + + state.instructions.Append(SpirvOp::OpLabel, AllocateResultId()); + + for (const auto& param : func.parameters) + { + UInt32 paramResultId = AllocateResultId(); + funcData.paramsId.push_back(paramResultId); + + state.instructions.Append(SpirvOp::OpFunctionParameter, GetTypeId(param.type), paramResultId); + } + + SpirvAstVisitor visitor(*this); + visitor.Visit(functionStatements[funcIndex]); + + if (func.returnType == ShaderNodes::BasicType::Void) + state.instructions.Append(SpirvOp::OpReturn); + + state.instructions.Append(SpirvOp::OpFunctionEnd); + } + + assert(entryPointIndex != std::numeric_limits::max()); + + m_currentState->constantTypeCache.Write(m_currentState->annotations, m_currentState->constants, m_currentState->debugInfo); + + AppendHeader(); + + SpvExecutionModel execModel; + const auto& entryFuncData = shader.GetFunction(entryPointIndex); + const auto& entryFunc = state.funcs[entryPointIndex]; + + assert(m_context.shader); + switch (m_context.shader->GetStage()) + { + case ShaderStageType::Fragment: + execModel = SpvExecutionModelFragment; + break; + + case ShaderStageType::Vertex: + execModel = SpvExecutionModelVertex; + break; + + default: + throw std::runtime_error("not yet implemented"); + } + + // OpEntryPoint Vertex %main "main" %outNormal %inNormals %outTexCoords %inTexCoord %_ %inPos + + state.header.AppendVariadic(SpirvOp::OpEntryPoint, [&](const auto& appender) + { + appender(execModel); + appender(entryFunc.id); + appender(entryFuncData.name); + + for (const auto& [name, varData] : state.builtinIds) + appender(varData.varId); + + for (const auto& [name, varData] : state.inputIds) + appender(varData.varId); + + for (const auto& [name, varData] : state.outputIds) + appender(varData.varId); + }); + + if (m_context.shader->GetStage() == ShaderStageType::Fragment) + state.header.Append(SpirvOp::OpExecutionMode, entryFunc.id, SpvExecutionModeOriginUpperLeft); + + std::vector ret; + MergeBlocks(ret, state.header); + MergeBlocks(ret, state.debugInfo); + MergeBlocks(ret, state.annotations); + MergeBlocks(ret, state.constants); + MergeBlocks(ret, state.instructions); + + return ret; + } + + void SpirvWriter::SetEnv(Environment environment) + { + m_environment = std::move(environment); + } + + UInt32 Nz::SpirvWriter::AllocateResultId() + { + return m_currentState->nextVarIndex++; + } + + void SpirvWriter::AppendHeader() + { + m_currentState->header.Append(SpvMagicNumber); //< Spir-V magic number + + UInt32 version = (m_environment.spvMajorVersion << 16) | m_environment.spvMinorVersion << 8; + 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->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(SpirvOp::OpCapability, SpvCapabilityShader); + + for (const auto& [extInst, resultId] : m_currentState->extensionInstructions) + m_currentState->header.Append(SpirvOp::OpExtInstImport, resultId, extInst); + + m_currentState->header.Append(SpirvOp::OpMemoryModel, SpvAddressingModelLogical, SpvMemoryModelGLSL450); + } + + UInt32 SpirvWriter::GetConstantId(const ShaderConstantValue& value) const + { + return m_currentState->constantTypeCache.GetId(*SpirvConstantCache::BuildConstant(value)); + } + + 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) + } + }); + } + + 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)); + } + + UInt32 SpirvWriter::GetTypeId(const ShaderExpressionType& type) const + { + return m_currentState->constantTypeCache.GetId(*SpirvConstantCache::BuildType(*m_context.shader, type)); + } + + UInt32 SpirvWriter::ReadInputVariable(const std::string& name) + { + auto it = m_currentState->inputIds.find(name); + assert(it != m_currentState->inputIds.end()); + + return ReadVariable(it.value()); + } + + std::optional SpirvWriter::ReadInputVariable(const std::string& name, OnlyCache) + { + auto it = m_currentState->inputIds.find(name); + assert(it != m_currentState->inputIds.end()); + + return ReadVariable(it.value(), OnlyCache{}); + } + + 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) + { + if (!var.valueId.has_value()) + { + UInt32 resultId = AllocateResultId(); + m_currentState->instructions.Append(SpirvOp::OpLoad, var.typeId, resultId, var.varId); + + var.valueId = resultId; + } + + 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)); + } + + 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) + { + assert(m_currentState); + return m_currentState->constantTypeCache.Register(*SpirvConstantCache::BuildType(*m_context.shader, type)); + } + + void SpirvWriter::WriteLocalVariable(std::string name, UInt32 resultId) + { + assert(m_currentState); + m_currentState->varToResult.insert_or_assign(std::move(name), resultId); + } + + void SpirvWriter::MergeBlocks(std::vector& output, const SpirvSection& from) + { + const std::vector& bytecode = from.GetBytecode(); + + std::size_t prevSize = output.size(); + output.resize(prevSize + bytecode.size()); + std::copy(bytecode.begin(), bytecode.end(), output.begin() + prevSize); + } +} diff --git a/src/Nazara/Utility/FieldOffsets.cpp b/src/Nazara/Utility/FieldOffsets.cpp new file mode 100644 index 000000000..5e9f229bb --- /dev/null +++ b/src/Nazara/Utility/FieldOffsets.cpp @@ -0,0 +1,101 @@ +// 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 + +#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; + } +} 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/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)); 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 diff --git a/src/Nazara/VulkanRenderer/VulkanShaderStage.cpp b/src/Nazara/VulkanRenderer/VulkanShaderStage.cpp index 238bb6468..9459ccfe3 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; } } diff --git a/src/ShaderNode/DataModels/BufferField.cpp b/src/ShaderNode/DataModels/BufferField.cpp new file mode 100644 index 000000000..3f3986fb5 --- /dev/null +++ b/src/ShaderNode/DataModels/BufferField.cpp @@ -0,0 +1,480 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +BufferField::BufferField(ShaderGraph& graph) : +ShaderNode(graph) +{ + UpdateFieldList(); + + m_onBufferListUpdateSlot.Connect(GetGraph().OnBufferListUpdate, [&](ShaderGraph*) { UpdateBufferIndex(); }); + m_onBufferUpdateSlot.Connect(GetGraph().OnBufferUpdate, [&](ShaderGraph*, std::size_t bufferIndex) + { + if (m_currentBufferIndex == bufferIndex) + { + UpdatePreview(); + + Q_EMIT dataUpdated(0); + } + }); + + m_onStructListUpdateSlot.Connect(GetGraph().OnStructListUpdate, [&](ShaderGraph*) + { + UpdateFieldList(); + UpdateFieldIndex(); + UpdatePreview(); + + Q_EMIT dataUpdated(0); + }); + + m_onStructUpdateSlot.Connect(GetGraph().OnStructUpdate, [&](ShaderGraph*, std::size_t) + { + UpdateFieldList(); + 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); + + std::vector memberIndices; + memberIndices.reserve(currentField.nestedFields.size() + 1); + + 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); + + 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), std::move(memberIndices), graph.ToShaderExpressionType(std::get(memberEntry.type))); +} + +unsigned int BufferField::nPorts(QtNodes::PortType portType) const +{ + switch (portType) + { + case QtNodes::PortType::In: return 0; + case QtNodes::PortType::Out: return 1; + } + + return 0; +} + +void BufferField::BuildNodeEdition(QFormLayout* layout) +{ + ShaderNode::BuildNodeEdition(layout); + + QComboBox* fieldSelection = new QComboBox; + connect(fieldSelection, qOverload(&QComboBox::currentIndexChanged), [=](int index) + { + if (index >= 0) + m_currentFieldText = m_fieldList[index]; + else + m_currentFieldText.clear(); + + UpdateFieldIndex(); + 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); + + UpdateFieldList(); + for (const std::string& field : m_fieldList) + fieldSelection->addItem(QString::fromStdString(field)); + } + 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); +} + +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)); + + return ShaderGraph::ToNodeDataType(std::get(member.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) + 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); + case PrimitiveType::Mat4x4: return std::make_shared(); + } + + assert(false); + 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(); + UpdateFieldIndex(); + + 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) + 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(); +} + +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::PopulateFieldList(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) + m_fieldList.push_back(prefix + member.name); + else if constexpr (std::is_same_v) + PopulateFieldList(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(); +} + +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 new file mode 100644 index 000000000..8bd232a7a --- /dev/null +++ b/src/ShaderNode/DataModels/BufferField.hpp @@ -0,0 +1,70 @@ +#pragma once + +#ifndef NAZARA_SHADERNODES_BUFFERFIELD_HPP +#define NAZARA_SHADERNODES_BUFFERFIELD_HPP + +#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; + + 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; + + private: + bool ComputePreview(QPixmap& pixmap) override; + 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); + + 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; + std::vector m_fieldList; +}; + +#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/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..c30f3eadc --- /dev/null +++ b/src/ShaderNode/DataModels/Cast.hpp @@ -0,0 +1,55 @@ +#pragma once + +#ifndef NAZARA_SHADERNODES_CAST_HPP +#define NAZARA_SHADERNODES_CAST_HPP + +#include +#include +#include +#include +#include +#include + +template +class CastVec : public ShaderNode +{ + public: + CastVec(ShaderGraph& graph); + ~CastVec() = default; + + void BuildNodeEdition(QFormLayout* layout) override; + + Nz::ShaderNodes::ExpressionPtr GetExpression(Nz::ShaderNodes::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; + 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: + 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; +}; + +using CastToVec2 = CastVec<2>; +using CastToVec3 = CastVec<3>; +using CastToVec4 = CastVec<4>; + +#include + +#endif diff --git a/src/ShaderNode/DataModels/Cast.inl b/src/ShaderNode/DataModels/Cast.inl new file mode 100644 index 000000000..cd96d6ccc --- /dev/null +++ b/src/ShaderNode/DataModels/Cast.inl @@ -0,0 +1,252 @@ +#include +#include +#include +#include +#include + +template +CastVec::CastVec(ShaderGraph& graph) : +ShaderNode(graph) +{ + static_assert(ToComponentCount <= s_vectorComponents.size()); + + for (std::size_t i = 0; i < ToComponentCount; ++i) + m_overflowComponents[i] = 0.f; + + m_output = std::make_shared(ToComponentCount); +} + +template +void CastVec::BuildNodeEdition(QFormLayout* layout) +{ + ShaderNode::BuildNodeEdition(layout); + + if (!m_input) + return; + + std::size_t fromComponentCount = m_input->componentCount; + + if (ToComponentCount > fromComponentCount) + { + std::size_t overflowComponentCount = ToComponentCount - fromComponentCount; + + for (std::size_t i = 0; i < overflowComponentCount; ++i) + { + 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) + { + m_overflowComponents[i] = spinbox->value(); + UpdateOutput(); + }); + + layout->addRow(QString::fromUtf8(&s_vectorComponents[fromComponentCount + i], 1), spinbox); + } + } +} + +template +Nz::ShaderNodes::ExpressionPtr CastVec::GetExpression(Nz::ShaderNodes::ExpressionPtr* expressions, std::size_t count) const +{ + assert(m_input); + assert(count == 1); + + std::size_t fromComponentCount = m_input->componentCount; + + if (ToComponentCount > fromComponentCount) + { + 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(), 1 + overflowComponentCount); + } + else if (ToComponentCount < fromComponentCount) + { + std::array swizzleComponents; + for (std::size_t i = 0; i < ToComponentCount; ++i) + swizzleComponents[i] = static_cast(static_cast(Nz::ShaderNodes::SwizzleComponent::First) + i); + + return std::apply([&](auto... components) + { + std::initializer_list componentList{ components... }; + return Nz::ShaderBuilder::Swizzle(expressions[0], componentList); + }, swizzleComponents); + } + else + return expressions[0]; //< no-op +} + +template +QString CastVec::caption() const +{ + static QString caption = "To Vector" + QString::number(ToComponentCount); + return caption; +} + +template +QString CastVec::name() const +{ + static QString name = "cast_vec" + QString::number(ToComponentCount); + return name; +} + +template +QtNodes::NodeDataType CastVec::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const +{ + assert(portIndex == 0); + + switch (portType) + { + 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 +{ + 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); + + if (!m_input) + return nullptr; + + 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(); + + UpdateOutput(); +} + +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; + + pixmap = QPixmap::fromImage(m_output->preview.GenerateImage()); + return true; +} + +template +void CastVec::UpdateOutput() +{ + if (!m_input) + { + m_output->preview = PreviewValues(1, 1); + m_output->preview(0, 0) = Nz::Vector4f::Zero(); + return; + } + + const PreviewValues& input = m_input->preview; + + std::size_t inputWidth = input.GetWidth(); + std::size_t inputHeight = input.GetHeight(); + + 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; + + for (std::size_t y = 0; y < inputHeight; ++y) + { + for (std::size_t x = 0; x < inputWidth; ++x) + { + Nz::Vector4f color = input(x, y); + + float* colorPtr = &color.x; + for (std::size_t i = 0; i < overflowComponentCount; ++i) + *colorPtr++ = m_overflowComponents[i]; + + for (std::size_t i = 0; i < voidComponents; ++i) + *colorPtr++ = (i == voidComponents - 1) ? 1.f : 0.f; + + output(x, y) = color; + } + } + + Q_EMIT dataUpdated(0); + + 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 new file mode 100644 index 000000000..23a4c766f --- /dev/null +++ b/src/ShaderNode/DataModels/FloatValue.cpp @@ -0,0 +1,107 @@ +#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(0, 0) = Nz::Vector4f(m_value, m_value, m_value, 1.f); + + return out; +} + +void FloatValue::BuildNodeEdition(QFormLayout* layout) +{ + ShaderNode::BuildNodeEdition(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) + { + m_value = spinbox->value(); + Q_EMIT dataUpdated(0); + + UpdatePreview(); + }); + + layout->addRow(tr("Value"), spinbox); +} + +Nz::ShaderNodes::ExpressionPtr FloatValue::GetExpression(Nz::ShaderNodes::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..fe77e5464 --- /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::ShaderNodes::ExpressionPtr GetExpression(Nz::ShaderNodes::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 new file mode 100644 index 000000000..e4710e6f5 --- /dev/null +++ b/src/ShaderNode/DataModels/InputValue.cpp @@ -0,0 +1,217 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +InputValue::InputValue(ShaderGraph& graph) : +ShaderNode(graph) +{ + m_onInputListUpdateSlot.Connect(GetGraph().OnInputListUpdate, [&](ShaderGraph*) { OnInputListUpdate(); }); + m_onInputUpdateSlot.Connect(GetGraph().OnInputUpdate, [&](ShaderGraph*, std::size_t inputIndex) + { + if (m_currentInputIndex == inputIndex) + { + UpdatePreview(); + Q_EMIT dataUpdated(0); + } + }); + + if (graph.GetInputCount() > 0) + { + m_currentInputIndex = 0; + UpdateInputText(); + } + + DisableCustomVariableName(); + UpdatePreview(); +} + +unsigned int InputValue::nPorts(QtNodes::PortType portType) const +{ + switch (portType) + { + case QtNodes::PortType::In: return 0; + case QtNodes::PortType::Out: return 1; + } + + return 0; +} + +bool InputValue::ComputePreview(QPixmap& pixmap) +{ + if (!m_currentInputIndex) + return false; + + const ShaderGraph& graph = GetGraph(); + const auto& inputEntry = graph.GetInput(*m_currentInputIndex); + const auto& preview = graph.GetPreviewModel(); + + pixmap = QPixmap::fromImage(preview.GetPreview(inputEntry.role, inputEntry.roleIndex).GenerateImage()); + return true; +} + +void InputValue::OnInputListUpdate() +{ + 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::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) + { + if (index >= 0) + m_currentInputIndex = static_cast(index); + else + m_currentInputIndex.reset(); + + UpdateInputText(); + UpdatePreview(); + + Q_EMIT dataUpdated(0); + }); + + layout->addRow(tr("Input"), inputSelection); +} + +Nz::ShaderNodes::ExpressionPtr InputValue::GetExpression(Nz::ShaderNodes::ExpressionPtr* /*expressions*/, std::size_t count) const +{ + assert(count == 0); + + if (!m_currentInputIndex) + throw std::runtime_error("no input"); + + const auto& inputEntry = GetGraph().GetInput(*m_currentInputIndex); + 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 +{ + assert(portType == QtNodes::PortType::Out); + assert(portIndex == 0); + + if (!m_currentInputIndex) + return VecData::Type(); + + const auto& inputEntry = GetGraph().GetInput(*m_currentInputIndex); + return ShaderGraph::ToNodeDataType(inputEntry.type); +} + +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& preview = graph.GetPreviewModel(); + + switch (inputEntry.type) + { + case PrimitiveType::Bool: + { + auto bData = std::make_shared(); + bData->preview = preview.GetPreview(inputEntry.role, inputEntry.roleIndex); + + return bData; + } + + 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 +{ + if (!m_currentInputIndex) + return QtNodes::NodeValidationState::Error; + + return QtNodes::NodeValidationState::Valid; +} + +QString InputValue::validationMessage() const +{ + if (!m_currentInputIndex) + return "No input selected"; + + 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 new file mode 100644 index 000000000..d0e1593b9 --- /dev/null +++ b/src/ShaderNode/DataModels/InputValue.hpp @@ -0,0 +1,53 @@ +#pragma once + +#ifndef NAZARA_SHADERNODES_INPUTVALUE_HPP +#define NAZARA_SHADERNODES_INPUTVALUE_HPP + +#include +#include +#include +#include +#include +#include +#include + +class InputValue : public ShaderNode +{ + public: + InputValue(ShaderGraph& graph); + ~InputValue() = 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 "Input"; } + QString name() const override { return "Input"; } + + 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 OnInputListUpdate(); + void UpdateInputText(); + + void restore(const QJsonObject& data) override; + QJsonObject save() const override; + + NazaraSlot(ShaderGraph, OnInputListUpdate, m_onInputListUpdateSlot); + NazaraSlot(ShaderGraph, OnInputUpdate, m_onInputUpdateSlot); + + std::optional m_currentInputIndex; + std::string m_currentInputText; +}; + +#include + +#endif diff --git a/src/ShaderNode/DataModels/InputValue.inl b/src/ShaderNode/DataModels/InputValue.inl new file mode 100644 index 000000000..ec5e2f581 --- /dev/null +++ b/src/ShaderNode/DataModels/InputValue.inl @@ -0,0 +1 @@ +#include 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..05cdb0479 --- /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..983545973 --- /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 new file mode 100644 index 000000000..63a481588 --- /dev/null +++ b/src/ShaderNode/DataModels/OutputValue.cpp @@ -0,0 +1,264 @@ +#include +#include +#include +#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) + { + m_currentOutputIndex = 0; + UpdateOutputText(); + } + + EnablePreview(); + SetPreviewSize({ 128, 128 }); + DisableCustomVariableName(); +} + +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) + m_currentOutputIndex = static_cast(index); + else + m_currentOutputIndex.reset(); + + UpdateOutputText(); + UpdatePreview(); + }); + + layout->addRow(tr("Output"), outputSelection); +} + +Nz::ShaderNodes::ExpressionPtr OutputValue::GetExpression(Nz::ShaderNodes::ExpressionPtr* expressions, std::size_t count) const +{ + using namespace Nz::ShaderBuilder; + using namespace Nz::ShaderNodes; + + assert(count == 1); + + if (!m_currentOutputIndex) + throw std::runtime_error("no output"); + + const auto& outputEntry = GetGraph().GetOutput(*m_currentOutputIndex); + auto output = Nz::ShaderBuilder::Identifier(Nz::ShaderBuilder::Output(outputEntry.name, ShaderGraph::ToShaderExpressionType(outputEntry.type))); + + 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 VecData::Type(); + + const auto& outputEntry = GetGraph().GetOutput(*m_currentOutputIndex); + return ShaderGraph::ToNodeDataType(outputEntry.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) +{ + if (!m_currentOutputIndex) + return; + + assert(index == 0); + m_input = std::move(value); + + UpdatePreview(); +} + +QtNodes::NodeValidationState OutputValue::validationState() const +{ + if (!m_currentOutputIndex || !m_input) + return QtNodes::NodeValidationState::Error; + + const auto& outputEntry = GetGraph().GetOutput(*m_currentOutputIndex); + 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; +} + +QString OutputValue::validationMessage() const +{ + if (!m_currentOutputIndex) + return "No output selected"; + + if (!m_input) + return "Missing input"; + + const auto& outputEntry = GetGraph().GetOutput(*m_currentOutputIndex); + 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); + + 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(); +} + +bool OutputValue::ComputePreview(QPixmap& pixmap) +{ + if (!m_input) + return false; + + 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() +{ + m_currentOutputIndex.reset(); + + std::size_t inputIndex = 0; + for (const auto& inputEntry : GetGraph().GetOutputs()) + { + if (inputEntry.name == m_currentOutputText) + { + m_currentOutputIndex = inputIndex; + break; + } + + inputIndex++; + } +} + +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["output"].toString().toStdString(); + OnOutputListUpdate(); + + ShaderNode::restore(data); +} + +QJsonObject OutputValue::save() const +{ + QJsonObject data = ShaderNode::save(); + data["output"] = QString::fromStdString(m_currentOutputText); + + return data; +} diff --git a/src/ShaderNode/DataModels/OutputValue.hpp b/src/ShaderNode/DataModels/OutputValue.hpp new file mode 100644 index 000000000..12c812c5c --- /dev/null +++ b/src/ShaderNode/DataModels/OutputValue.hpp @@ -0,0 +1,53 @@ +#pragma once + +#ifndef NAZARA_SHADERNODES_OUTPUTVALUE_HPP +#define NAZARA_SHADERNODES_OUTPUTVALUE_HPP + +#include +#include +#include + +class QFormLayout; + +class OutputValue : public ShaderNode +{ + public: + OutputValue(ShaderGraph& graph); + + void BuildNodeEdition(QFormLayout* layout) 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"; } + + 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: + bool ComputePreview(QPixmap& pixmap) override; + void OnOutputListUpdate(); + void UpdateOutputText(); + + void restore(const QJsonObject& data) override; + QJsonObject save() const override; + + NazaraSlot(ShaderGraph, OnOutputListUpdate, m_onOutputListUpdateSlot); + NazaraSlot(ShaderGraph, OnOutputUpdate, m_onOutputUpdateSlot); + + std::optional m_currentOutputIndex; + std::shared_ptr m_input; + std::string m_currentOutputText; +}; + +#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/PositionOutputValue.cpp b/src/ShaderNode/DataModels/PositionOutputValue.cpp new file mode 100644 index 000000000..c3d252f54 --- /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/DataModels/SampleTexture.cpp b/src/ShaderNode/DataModels/SampleTexture.cpp new file mode 100644 index 000000000..c784b83af --- /dev/null +++ b/src/ShaderNode/DataModels/SampleTexture.cpp @@ -0,0 +1,214 @@ +#include +#include +#include + +SampleTexture::SampleTexture(ShaderGraph& graph) : +ShaderNode(graph) +{ + m_output = std::make_shared(4); + + UpdateOutput(); +} + +unsigned int SampleTexture::nPorts(QtNodes::PortType portType) const +{ + switch (portType) + { + case QtNodes::PortType::In: return 2; + case QtNodes::PortType::Out: return 1; + } + + return 0; +} + +void SampleTexture::UpdateOutput() +{ + PreviewValues& output = m_output->preview; + + if (!m_texture || !m_uv) + { + output = PreviewValues(1, 1); + output.Fill(Nz::Vector4f::Zero()); + return; + } + + const PreviewValues& texturePreview = m_texture->preview; + + std::size_t textureWidth = texturePreview.GetWidth(); + std::size_t textureHeight = texturePreview.GetHeight(); + + const PreviewValues& uv = m_uv->preview; + + std::size_t uvWidth = uv.GetWidth(); + std::size_t uvHeight = uv.GetHeight(); + + output = PreviewValues(uvWidth, uvHeight); + + for (std::size_t y = 0; y < uvHeight; ++y) + { + for (std::size_t x = 0; x < uvWidth; ++x) + { + Nz::Vector4f uvValue = uv(x, y); + + if (textureWidth > 0 && textureHeight > 0) + output(x, y) = texturePreview.Sample(uvValue.x, uvValue.y); + else + output(x, y) = Nz::Vector4f(0.f, 0.f, 0.f, 1.f); + } + } + + Q_EMIT dataUpdated(0); + + UpdatePreview(); +} + +bool SampleTexture::ComputePreview(QPixmap& pixmap) +{ + if (!m_texture || !m_uv) + return false; + + pixmap = QPixmap::fromImage(m_output->preview.GenerateImage()); + return true; +} + +Nz::ShaderNodes::ExpressionPtr SampleTexture::GetExpression(Nz::ShaderNodes::ExpressionPtr* expressions, std::size_t count) const +{ + assert(m_texture); + assert(m_uv); + assert(count == 2); + + return Nz::ShaderBuilder::Sample2D(expressions[0], expressions[1]); +} + +auto SampleTexture::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const -> QtNodes::NodeDataType +{ + switch (portType) + { + case QtNodes::PortType::In: + { + switch (portIndex) + { + case 0: return Texture2Data::Type(); + case 1: return VecData::Type(); + } + + assert(false); + throw std::runtime_error("invalid port index"); + } + + case QtNodes::PortType::Out: + { + assert(portIndex == 0); + return VecData::Type(); + } + + default: + assert(false); + throw std::runtime_error("invalid PortType"); + } +} + +QString SampleTexture::portCaption(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const +{ + switch (portType) + { + case QtNodes::PortType::In: + { + 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: + { + 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); + + return m_output; +} + +void SampleTexture::setInData(std::shared_ptr value, int index) +{ + switch (index) + { + case 0: + { + if (value) + { + assert(dynamic_cast(value.get()) != nullptr); + + 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"); + } + + 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 new file mode 100644 index 000000000..5b1dd98fd --- /dev/null +++ b/src/ShaderNode/DataModels/SampleTexture.hpp @@ -0,0 +1,51 @@ +#pragma once + +#ifndef NAZARA_SHADERNODES_SAMPLETEXTURE_HPP +#define NAZARA_SHADERNODES_SAMPLETEXTURE_HPP + +#include +#include +#include +#include +#include +#include +#include + +class SampleTexture : public ShaderNode +{ + public: + SampleTexture(ShaderGraph& graph); + ~SampleTexture() = default; + + 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"; } + + 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; + + 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; +}; + +#include + +#endif diff --git a/src/ShaderNode/DataModels/SampleTexture.inl b/src/ShaderNode/DataModels/SampleTexture.inl new file mode 100644 index 000000000..292805b16 --- /dev/null +++ b/src/ShaderNode/DataModels/SampleTexture.inl @@ -0,0 +1,2 @@ +#include +#include diff --git a/src/ShaderNode/DataModels/ShaderNode.cpp b/src/ShaderNode/DataModels/ShaderNode.cpp new file mode 100644 index 000000000..7ed3bc84c --- /dev/null +++ b/src/ShaderNode/DataModels/ShaderNode.cpp @@ -0,0 +1,145 @@ +#include +#include +#include +#include +#include +#include + +ShaderNode::ShaderNode(ShaderGraph& graph) : +m_previewSize(64, 64), +m_pixmapLabel(nullptr), +m_graph(graph), +m_enableCustomVariableName(true), +m_isPreviewEnabled(false) +{ + m_pixmapLabel = new QLabel; + m_pixmapLabel->setStyleSheet("background-color: rgba(0,0,0,0)"); +} + +void ShaderNode::BuildNodeEdition(QFormLayout* layout) +{ + QCheckBox* checkbox = new QCheckBox; + checkbox->setCheckState((m_isPreviewEnabled) ? Qt::Checked : Qt::Unchecked); + + connect(checkbox, &QCheckBox::stateChanged, [&](int state) + { + EnablePreview(state == Qt::Checked); + }); + + 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); + + 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) +{ + 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(); + } + } +} + +QWidget* ShaderNode::embeddedWidget() +{ + return m_pixmapLabel; +} + +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; +} + +void ShaderNode::setInData(std::shared_ptr, int) +{ +} + +bool ShaderNode::ComputePreview(QPixmap& /*pixmap*/) +{ + return false; +} + +void ShaderNode::UpdatePreview() +{ + if (!m_pixmap) + { + embeddedWidgetSizeUpdated(); + 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); + + embeddedWidgetSizeUpdated(); +} diff --git a/src/ShaderNode/DataModels/ShaderNode.hpp b/src/ShaderNode/DataModels/ShaderNode.hpp new file mode 100644 index 000000000..6d3dd5cc1 --- /dev/null +++ b/src/ShaderNode/DataModels/ShaderNode.hpp @@ -0,0 +1,60 @@ +#pragma once + +#ifndef NAZARA_SHADERNODES_SHADERNODE_HPP +#define NAZARA_SHADERNODES_SHADERNODE_HPP + +#include +#include +#include +#include +#include + +class QLabel; +class QFormLayout; +class ShaderGraph; + +class ShaderNode : public QtNodes::NodeDataModel +{ + public: + ShaderNode(ShaderGraph& graph); + + virtual void BuildNodeEdition(QFormLayout* layout); + + inline void DisablePreview(); + void EnablePreview(bool enable = true); + + 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; + + inline void SetPreviewSize(const Nz::Vector2i& size); + inline void SetVariableName(std::string variableName); + + QWidget* embeddedWidget() final; + + void restore(const QJsonObject& data) override; + QJsonObject save() const override; + + void setInData(std::shared_ptr, int) override; + + protected: + inline void DisableCustomVariableName(); + inline void EnableCustomVariableName(bool enable = true); + void UpdatePreview(); + + private: + virtual bool ComputePreview(QPixmap& pixmap); + + Nz::Vector2i m_previewSize; + QLabel* m_pixmapLabel; + std::optional m_pixmap; + std::string m_variableName; + ShaderGraph& m_graph; + bool m_enableCustomVariableName; + bool m_isPreviewEnabled; +}; + +#include + +#endif diff --git a/src/ShaderNode/DataModels/ShaderNode.inl b/src/ShaderNode/DataModels/ShaderNode.inl new file mode 100644 index 000000000..558a86165 --- /dev/null +++ b/src/ShaderNode/DataModels/ShaderNode.inl @@ -0,0 +1,48 @@ +#include + +inline void ShaderNode::DisablePreview() +{ + return EnablePreview(false); +} + +inline ShaderGraph& ShaderNode::GetGraph() +{ + return m_graph; +} + +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(); + } +} + +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 new file mode 100644 index 000000000..c400d0469 --- /dev/null +++ b/src/ShaderNode/DataModels/TextureValue.cpp @@ -0,0 +1,211 @@ +#include +#include +#include +#include +#include +#include + +TextureValue::TextureValue(ShaderGraph& graph) : +ShaderNode(graph) +{ + m_onTextureListUpdateSlot.Connect(GetGraph().OnTextureListUpdate, [&](ShaderGraph*) { OnTextureListUpdate(); }); + + 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; + UpdateTexture(); + } + + DisableCustomVariableName(); + 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++; + } +} + +void TextureValue::UpdateTexture() +{ + 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) + 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; + 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) + m_currentTextureIndex = static_cast(index); + else + m_currentTextureIndex.reset(); + + UpdateTexture(); + UpdatePreview(); + + Q_EMIT dataUpdated(0); + }); + + layout->addRow(tr("Texture"), textureSelection); +} + +Nz::ShaderNodes::ExpressionPtr TextureValue::GetExpression(Nz::ShaderNodes::ExpressionPtr* /*expressions*/, std::size_t count) const +{ + if (!m_currentTextureIndex) + throw std::runtime_error("invalid texture input"); + + assert(count == 0); + + const auto& textureEntry = GetGraph().GetTexture(*m_currentTextureIndex); + + Nz::ShaderNodes::BasicType expression = [&] + { + switch (textureEntry.type) + { + case TextureType::Sampler2D: return Nz::ShaderNodes::BasicType::Sampler2D; + } + + assert(false); + throw std::runtime_error("Unhandled texture type"); + }(); + + return Nz::ShaderBuilder::Identifier(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 Texture2Data::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); + + 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; +} + +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(); +} + +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 new file mode 100644 index 000000000..d328e2f05 --- /dev/null +++ b/src/ShaderNode/DataModels/TextureValue.hpp @@ -0,0 +1,53 @@ +#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::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"; } + + 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; + + protected: + bool ComputePreview(QPixmap& pixmap) override; + void OnTextureListUpdate(); + 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; +}; + +#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/DataModels/VecBinOp.cpp b/src/ShaderNode/DataModels/VecBinOp.cpp new file mode 100644 index 000000000..f99591420 --- /dev/null +++ b/src/ShaderNode/DataModels/VecBinOp.cpp @@ -0,0 +1,75 @@ +#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 Nz::Vector4f* left, const Nz::Vector4f* right, Nz::Vector4f* output, std::size_t pixelCount) +{ + for (std::size_t i = 0; i < pixelCount; ++i) + output[i] = left[i] + right[i]; +} + +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 Nz::Vector4f* left, const Nz::Vector4f* right, Nz::Vector4f* output, std::size_t pixelCount) +{ + for (std::size_t i = 0; i < pixelCount; ++i) + output[i] = left[i] * right[i]; +} + +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 Nz::Vector4f* left, const Nz::Vector4f* right, Nz::Vector4f* output, std::size_t pixelCount) +{ + for (std::size_t i = 0; i < pixelCount; ++i) + output[i] = left[i] - right[i]; +} + +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 Nz::Vector4f* left, const Nz::Vector4f* right, Nz::Vector4f* output, std::size_t pixelCount) +{ + for (std::size_t i = 0; i < pixelCount; ++i) + output[i] = left[i] / right[i]; +} diff --git a/src/ShaderNode/DataModels/VecBinOp.hpp b/src/ShaderNode/DataModels/VecBinOp.hpp new file mode 100644 index 000000000..3c0a5aebd --- /dev/null +++ b/src/ShaderNode/DataModels/VecBinOp.hpp @@ -0,0 +1,86 @@ +#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::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: + 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(); + + std::shared_ptr m_lhs; + std::shared_ptr m_rhs; + std::shared_ptr m_output; +}; + +class VecAdd : public VecBinOp +{ + public: + using VecBinOp::VecBinOp; + + QString caption() const override; + QString name() const override; + + void ApplyOp(const Nz::Vector4f* left, const Nz::Vector4f* right, Nz::Vector4f* output, std::size_t pixelCount) override; +}; + +class VecMul : public VecBinOp +{ + public: + using VecBinOp::VecBinOp; + + QString caption() const override; + QString name() const override; + + void ApplyOp(const Nz::Vector4f* left, const Nz::Vector4f* right, Nz::Vector4f* output, std::size_t pixelCount) override; +}; + +class VecSub : public VecBinOp +{ + public: + using VecBinOp::VecBinOp; + + QString caption() const override; + QString name() const override; + + void ApplyOp(const Nz::Vector4f* left, const Nz::Vector4f* right, Nz::Vector4f* 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 Nz::Vector4f* left, const Nz::Vector4f* right, Nz::Vector4f* output, std::size_t pixelCount) override; +}; + +#include + +#endif diff --git a/src/ShaderNode/DataModels/VecBinOp.inl b/src/ShaderNode/DataModels/VecBinOp.inl new file mode 100644 index 000000000..d16347799 --- /dev/null +++ b/src/ShaderNode/DataModels/VecBinOp.inl @@ -0,0 +1,135 @@ +#include +#include + +template +VecBinOp::VecBinOp(ShaderGraph& graph) : +ShaderNode(graph) +{ + UpdateOutput(); +} + +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; + constexpr BuilderType builder; + return builder(expressions[0], expressions[1]); +} + +template +QtNodes::NodeDataType VecBinOp::dataType(QtNodes::PortType /*portType*/, QtNodes::PortIndex portIndex) const +{ + assert(portIndex == 0 || portIndex == 1); + + return VecData::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 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); + + castedValue = std::static_pointer_cast(value); + } + + if (index == 0) + m_lhs = std::move(castedValue); + else + m_rhs = std::move(castedValue); + + 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) +{ + if (!m_lhs || !m_rhs) + return false; + + pixmap = QPixmap::fromImage(m_output->preview.GenerateImage()); + return true; +} + +template +void VecBinOp::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(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/VecDot.cpp b/src/ShaderNode/DataModels/VecDot.cpp new file mode 100644 index 000000000..b083623d0 --- /dev/null +++ b/src/ShaderNode/DataModels/VecDot.cpp @@ -0,0 +1,163 @@ +#include +#include + +VecDot::VecDot(ShaderGraph& graph) : +ShaderNode(graph) +{ + m_output = std::make_shared(); + UpdateOutput(); +} + +Nz::ShaderNodes::ExpressionPtr VecDot::GetExpression(Nz::ShaderNodes::ExpressionPtr* expressions, std::size_t count) const +{ + assert(count == 2); + using namespace Nz::ShaderNodes; + return IntrinsicCall::Build(IntrinsicType::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.GenerateImage()); + return true; +} + +void VecDot::UpdateOutput() +{ + if (validationState() != QtNodes::NodeValidationState::Valid) + { + m_output->preview = PreviewValues(1, 1); + m_output->preview.Fill(Nz::Vector4f::Zero()); + return; + } + + 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) + { + float acc = 0.f; + for (std::size_t j = 0; j < m_lhs->componentCount; ++j) + acc += left[i][j] * right[i][j]; + + for (std::size_t j = 0; j < 3; ++j) + output[i][j] = acc; + output[i][3] = 1.f; //< leave alpha at maximum + } + + 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..74e6a7266 --- /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::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/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/DataModels/VecFloatMul.cpp b/src/ShaderNode/DataModels/VecFloatMul.cpp new file mode 100644 index 000000000..9dd3b02c3 --- /dev/null +++ b/src/ShaderNode/DataModels/VecFloatMul.cpp @@ -0,0 +1,178 @@ +#include +#include + +VecFloatMul::VecFloatMul(ShaderGraph& graph) : +ShaderNode(graph) +{ + UpdateOutput(); +} + +Nz::ShaderNodes::ExpressionPtr VecFloatMul::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 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.GenerateImage()); + return true; +} + +void VecFloatMul::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(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/VecFloatMul.hpp b/src/ShaderNode/DataModels/VecFloatMul.hpp new file mode 100644 index 000000000..dd1fbd1af --- /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::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/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/DataModels/VecValue.cpp b/src/ShaderNode/DataModels/VecValue.cpp new file mode 100644 index 000000000..ede5bdfac --- /dev/null +++ b/src/ShaderNode/DataModels/VecValue.cpp @@ -0,0 +1 @@ +#include diff --git a/src/ShaderNode/DataModels/VecValue.hpp b/src/ShaderNode/DataModels/VecValue.hpp new file mode 100644 index 000000000..86cd93692 --- /dev/null +++ b/src/ShaderNode/DataModels/VecValue.hpp @@ -0,0 +1,50 @@ +#pragma once + +#ifndef NAZARA_SHADERNODES_VECVALUE_HPP +#define NAZARA_SHADERNODES_VECVALUE_HPP + +#include +#include +#include +#include +#include +#include +#include + +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; + + unsigned int nPorts(QtNodes::PortType portType) const override; + + std::shared_ptr outData(QtNodes::PortIndex port) override; + + void BuildNodeEdition(QFormLayout* layout) override; + + Nz::ShaderNodes::ExpressionPtr GetExpression(Nz::ShaderNodes::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; + + VecType m_value; +}; + +using Vec2Value = VecValue<2>; +using Vec3Value = VecValue<3>; +using Vec4Value = VecValue<4>; + +#include + +#endif diff --git a/src/ShaderNode/DataModels/VecValue.inl b/src/ShaderNode/DataModels/VecValue.inl new file mode 100644 index 000000000..b07c46a9b --- /dev/null +++ b/src/ShaderNode/DataModels/VecValue.inl @@ -0,0 +1,152 @@ +#include +#include +#include +#include +#include +#include +#include + +template +VecValue::VecValue(ShaderGraph& graph) : +ShaderNode(graph) +{ + static_assert(ComponentCount <= s_vectorComponents.size()); + + std::array defaultValues; + + for (std::size_t i = 0; i < ComponentCount; ++i) + defaultValues[i] = (i == 3) ? 1.f : 0.f; + + m_value.Set(defaultValues.data()); + + UpdatePreview(); +} + +template +QString VecValue::caption() const +{ + static QString caption = "Vector" + QString::number(ComponentCount) + " constant"; + return caption; +} + +template +QString VecValue::name() const +{ + static QString name = "vec" + QString::number(ComponentCount) + "_constant"; + return name; +} + +template +QtNodes::NodeDataType VecValue::dataType(QtNodes::PortType portType, QtNodes::PortIndex portIndex) const +{ + assert(portType == QtNodes::PortType::Out); + assert(portIndex == 0); + + return VecData::Type(); +} + +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; +} + +template +std::shared_ptr VecValue::outData(QtNodes::PortIndex port) +{ + assert(port == 0); + + auto out = std::make_shared(ComponentCount); + + 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; +} + +template +void VecValue::BuildNodeEdition(QFormLayout* layout) +{ + ShaderNode::BuildNodeEdition(layout); + + for (std::size_t i = 0; i < ComponentCount; ++i) + { + 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) + { + m_value[i] = spinbox->value(); + Q_EMIT dataUpdated(0); + + UpdatePreview(); + }); + + layout->addRow(QString::fromUtf8(&s_vectorComponents[i], 1), spinbox); + } +} + +template +Nz::ShaderNodes::ExpressionPtr VecValue::GetExpression(Nz::ShaderNodes::ExpressionPtr* /*expressions*/, std::size_t count) const +{ + assert(count == 0); + + return Nz::ShaderBuilder::Constant(m_value); +} + +template +bool VecValue::ComputePreview(QPixmap& pixmap) +{ + pixmap.fill(ToColor()); + return true; +} + +template +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(m_value[i], 0.f, 1.f); + + return QColor::fromRgbF(values[0], values[1], values[2], values[3]); +} + +template +void VecValue::restore(const QJsonObject& data) +{ + QJsonArray vecValues = data["value"].toArray(); + 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); +} + +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/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); +} 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..d33d12b5d --- /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" }; + } + + PreviewValues preview; +}; + +#include + +#endif diff --git a/src/ShaderNode/DataTypes/FloatData.inl b/src/ShaderNode/DataTypes/FloatData.inl new file mode 100644 index 000000000..4f889aa90 --- /dev/null +++ b/src/ShaderNode/DataTypes/FloatData.inl @@ -0,0 +1,7 @@ +#include + +inline FloatData::FloatData() : +preview(1, 1) +{ + preview(0, 0) = Nz::Vector4f(1.f, 1.f, 1.f, 0.f); +} 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..4eb63f136 --- /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/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..28b2b73d0 --- /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(); + + PreviewValues 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..b542dff60 --- /dev/null +++ b/src/ShaderNode/DataTypes/TextureData.inl @@ -0,0 +1,7 @@ +#include + +inline TextureData::TextureData() : +preview(64, 64) +{ + preview.Fill(Nz::Vector4f(1.f, 1.f, 1.f, 0.f)); +} diff --git a/src/ShaderNode/DataTypes/VecData.cpp b/src/ShaderNode/DataTypes/VecData.cpp new file mode 100644 index 000000000..0402864e0 --- /dev/null +++ b/src/ShaderNode/DataTypes/VecData.cpp @@ -0,0 +1,18 @@ +#include +#include +#include + +Nz::ShaderNodes::BasicType VecData::GetExpressionType() const +{ + switch (componentCount) + { + case 2: return Nz::ShaderNodes::BasicType::Float2; + case 3: return Nz::ShaderNodes::BasicType::Float3; + case 4: return Nz::ShaderNodes::BasicType::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 new file mode 100644 index 000000000..d80bff106 --- /dev/null +++ b/src/ShaderNode/DataTypes/VecData.hpp @@ -0,0 +1,95 @@ +#pragma once + +#ifndef NAZARA_SHADERNODES_VECDATA_HPP +#define NAZARA_SHADERNODES_VECDATA_HPP + +#include +#include +#include + +struct VecData : public QtNodes::NodeData +{ + inline VecData(std::size_t componentCount); + + inline QtNodes::NodeDataType type() const override; + + Nz::ShaderNodes::BasicType GetExpressionType() const; + + static inline QtNodes::NodeDataType Type(); + + std::size_t componentCount; + PreviewValues preview; +}; + +template +struct VecExpressionTypeHelper; + +template<> +struct VecExpressionTypeHelper<1> +{ + static constexpr Nz::ShaderNodes::BasicType ExpressionType = Nz::ShaderNodes::BasicType::Float1; +}; + +template<> +struct VecExpressionTypeHelper<2> +{ + static constexpr Nz::ShaderNodes::BasicType ExpressionType = Nz::ShaderNodes::BasicType::Float2; +}; + +template<> +struct VecExpressionTypeHelper<3> +{ + static constexpr Nz::ShaderNodes::BasicType ExpressionType = Nz::ShaderNodes::BasicType::Float3; +}; + +template<> +struct VecExpressionTypeHelper<4> +{ + static constexpr Nz::ShaderNodes::BasicType ExpressionType = Nz::ShaderNodes::BasicType::Float4; +}; + +template constexpr Nz::ShaderNodes::BasicType VecExpressionType = VecExpressionTypeHelper::template ExpressionType; + + +struct VecTypeDummy {}; + +template +struct VecTypeHelper; + +template<> +struct VecTypeHelper<0> +{ + using Type = VecTypeDummy; +}; + +template<> +struct VecTypeHelper<1> +{ + using Type = std::array; //< To allow [0] +}; + +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/DataTypes/VecData.inl b/src/ShaderNode/DataTypes/VecData.inl new file mode 100644 index 000000000..7264ca7e9 --- /dev/null +++ b/src/ShaderNode/DataTypes/VecData.inl @@ -0,0 +1,18 @@ +#include + +inline VecData::VecData(std::size_t ComponentCount) : +componentCount(ComponentCount), +preview(64, 64) +{ + preview.Fill(Nz::Vector4f(1.f, 1.f, 1.f, 0.f)); +} + +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 new file mode 100644 index 000000000..73af36b06 --- /dev/null +++ b/src/ShaderNode/Enums.cpp @@ -0,0 +1,83 @@ +#include +#include + +std::size_t GetComponentCount(PrimitiveType type) +{ + switch (type) + { + 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; + case PrimitiveType::Mat4x4: return 16; + } + + 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) + { + 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(PrimitiveType input) +{ + switch (input) + { + 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"; + case PrimitiveType::Mat4x4: return "Mat4x4"; + } + + assert(false); + 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) + { + 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..c57969fb2 --- /dev/null +++ b/src/ShaderNode/Enums.hpp @@ -0,0 +1,77 @@ +#pragma once + +#ifndef NAZARA_SHADERNODES_ENUMS_HPP +#define NAZARA_SHADERNODES_ENUMS_HPP + +#include +#include +#include + +enum class BufferType +{ + UniformBufferObject, + + Max = UniformBufferObject +}; + +constexpr std::size_t BufferTypeCount = static_cast(BufferType::Max) + 1; + +enum class InputRole +{ + None, + Normal, + Position, + TexCoord, + + Max = TexCoord +}; + +constexpr std::size_t InputRoleCount = static_cast(InputRole::Max) + 1; + +enum class PrimitiveType +{ + Bool, + Float1, + Float2, + Float3, + Float4, + Mat4x4, + + Max = Mat4x4 +}; + +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, + + Max = Sampler2D +}; + +constexpr std::size_t TextureTypeCount = static_cast(TextureType::Max) + 1; + + +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); + +#include + +#endif diff --git a/src/ShaderNode/Enums.inl b/src/ShaderNode/Enums.inl new file mode 100644 index 000000000..f54d0801f --- /dev/null +++ b/src/ShaderNode/Enums.inl @@ -0,0 +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/Previews/PreviewModel.cpp b/src/ShaderNode/Previews/PreviewModel.cpp new file mode 100644 index 000000000..d4ab52386 --- /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..17b49fef2 --- /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 PreviewValues; + +class PreviewModel +{ + public: + PreviewModel() = default; + virtual ~PreviewModel(); + + virtual PreviewValues GetPreview(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..f4dccb3fa --- /dev/null +++ b/src/ShaderNode/Previews/PreviewModel.inl @@ -0,0 +1 @@ +#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..3efbebc39 --- /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_height; +} + +inline std::size_t PreviewValues::GetWidth() const +{ + return m_width; +} diff --git a/src/ShaderNode/Previews/QuadPreview.cpp b/src/ShaderNode/Previews/QuadPreview.cpp new file mode 100644 index 000000000..ce6155903 --- /dev/null +++ b/src/ShaderNode/Previews/QuadPreview.cpp @@ -0,0 +1,26 @@ +#include +#include + +PreviewValues QuadPreview::GetPreview(InputRole role, std::size_t roleIndex) const +{ + if (role != InputRole::TexCoord) + { + PreviewValues dummy(1, 1); + dummy(0, 0) = Nz::Vector4f::Zero(); + + return dummy; + } + + PreviewValues uv(128, 128); + + 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 < uv.GetWidth(); ++x) + uv(x, y) = Nz::Vector4f(x * invWidth, y * invHeight, 0.f, 1.f); + } + + return uv; +} diff --git a/src/ShaderNode/Previews/QuadPreview.hpp b/src/ShaderNode/Previews/QuadPreview.hpp new file mode 100644 index 000000000..947b4d637 --- /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; + + PreviewValues GetPreview(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..b3e26a0ab --- /dev/null +++ b/src/ShaderNode/Previews/QuadPreview.inl @@ -0,0 +1 @@ +#include diff --git a/src/ShaderNode/ShaderGraph.cpp b/src/ShaderNode/ShaderGraph.cpp new file mode 100644 index 000000000..a1799df3b --- /dev/null +++ b/src/ShaderNode/ShaderGraph.cpp @@ -0,0 +1,711 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace +{ + template + void RegisterShaderNode(ShaderGraph& graph, std::shared_ptr registry, QString category = QString()) + { + auto creator = [&] { return std::make_unique(graph); }; + registry->registerModel(category, std::move(creator)); + } +} + +ShaderGraph::ShaderGraph() : +m_flowScene(BuildRegistry()), +m_type(ShaderType::NotSet) +{ + 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); + }); + + // Test + 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 }, + { "inner", 2 } + } + }); + 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)")); + + 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(50, 350); + + 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(400, 200); + + 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() +{ + m_flowScene.clearScene(); +} + +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(); + inputEntry.locationIndex = locationIndex; + inputEntry.name = std::move(name); + inputEntry.role = role; + inputEntry.roleIndex = roleIndex; + inputEntry.type = type; + + OnInputListUpdate(this); + + return index; +} + +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(); + outputEntry.locationIndex = locationIndex; + outputEntry.name = std::move(name); + outputEntry.type = type; + + OnOutputListUpdate(this); + + 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(); + auto& textureEntry = m_textures.emplace_back(); + textureEntry.bindingIndex = bindingIndex; + textureEntry.name = std::move(name); + textureEntry.type = type; + + OnTextureListUpdate(this); + + return index; +} + +void ShaderGraph::Clear() +{ + m_type = ShaderType::NotSet; + + 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); +} + +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) + { + 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) + { + 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)); + 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.locationIndex = static_cast(outputDoc["locationIndex"].toInt(0)); + output.name = outputDoc["name"].toString().toStdString(); + 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) + { + 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(); + } + + 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; + sceneJson["type"] = QString(EnumToString(m_type)); + + 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) + { + QJsonObject inputDoc; + inputDoc["locationIndex"] = int(input.locationIndex); + 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["locationIndex"] = int(output.locationIndex); + outputDoc["name"] = QString::fromStdString(output.name); + outputDoc["type"] = QString(EnumToString(output.type)); + + outputArray.append(outputDoc); + } + } + 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); + + memberArray.append(std::move(memberDoc)); + } + structDoc["members"] = memberArray; + + structArray.append(structDoc); + } + } + sceneJson["structs"] = structArray; + + QJsonArray textureArray; + { + 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)); + + 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::ShaderNodes::StatementPtr ShaderGraph::ToAst() +{ + std::vector statements; + QHash usageCount; + + std::function DetectVariables; + DetectVariables = [&](QtNodes::Node* node) + { + 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)++; + }; + + m_flowScene.iterateOverNodes([&](QtNodes::Node* node) + { + if (node->nodeDataModel()->nPorts(QtNodes::PortType::Out) == 0) + DetectVariables(node); + }); + + QHash variableExpressions; + + unsigned int varCount = 0; + std::unordered_set usedVariableNames; + + std::function HandleNode; + HandleNode = [&](QtNodes::Node* node) -> Nz::ShaderNodes::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()) + 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::ShaderNodes::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++; + } + } + + auto expression = shaderNode->GetExpression(expressions.data(), expressions.size()); + + const std::string& variableName = shaderNode->GetVariableName(); + if (*it > 1 || !variableName.empty()) + { + Nz::ShaderNodes::ExpressionPtr varExpression; + if (expression->GetExpressionCategory() == Nz::ShaderNodes::ExpressionCategory::RValue) + { + 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::Local(std::move(name), expression->GetExpressionType()); + statements.emplace_back(Nz::ShaderBuilder::DeclareVariable(variable, expression)); + + varExpression = Nz::ShaderBuilder::Identifier(variable); + } + else + varExpression = expression; + + variableExpressions.insert(node->id(), varExpression); + + return varExpression; + } + else + return expression; + }; + + m_flowScene.iterateOverNodes([&](QtNodes::Node* node) + { + if (node->nodeDataModel()->nPorts(QtNodes::PortType::Out) == 0) + { + statements.emplace_back(Nz::ShaderBuilder::ExprStatement(HandleNode(node))); + } + }); + + 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()); + 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]; + inputEntry.locationIndex = locationIndex; + inputEntry.name = std::move(name); + inputEntry.role = role; + inputEntry.roleIndex = roleIndex; + inputEntry.type = type; + + OnInputUpdate(this, inputIndex); +} + +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]; + outputEntry.locationIndex = locationIndex; + outputEntry.name = std::move(name); + outputEntry.type = type; + + 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()); + 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()); + auto& textureEntry = m_textures[textureIndex]; + textureEntry.preview = std::move(preview); + textureEntry.preview.convertTo(QImage::Format_RGBA8888); + + 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) + { + 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) + { + 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; + case PrimitiveType::Mat4x4: return Nz::ShaderNodes::BasicType::Mat4x4; + } + + 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"); +} + +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(); + RegisterShaderNode(*this, registry, "Inputs"); + 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, "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"); + 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 new file mode 100644 index 000000000..1df336ce6 --- /dev/null +++ b/src/ShaderNode/ShaderGraph.hpp @@ -0,0 +1,149 @@ +#pragma once + +#ifndef NAZARA_SHADERNODES_SHADERGRAPH_HPP +#define NAZARA_SHADERNODES_SHADERGRAPH_HPP + +#include +#include +#include +#include +#include +#include +#include +#include + +class ShaderNode; + +class ShaderGraph +{ + public: + struct BufferEntry; + struct InputEntry; + struct OutputEntry; + struct StructEntry; + struct StructMemberEntry; + struct TextureEntry; + + ShaderGraph(); + ~ShaderGraph(); + + 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 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; + inline std::size_t GetTextureCount() const; + inline const std::vector& GetTextures() const; + inline ShaderType GetType() const; + + void Load(const QJsonObject& data); + 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); + 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); + void UpdateType(ShaderType type); + + 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; + PrimitiveType type; + }; + + struct OutputEntry + { + std::size_t locationIndex; + std::string name; + PrimitiveType type; + }; + + struct StructEntry + { + std::string name; + std::vector members; + }; + + struct StructMemberEntry + { + std::string name; + std::variant type; + }; + + struct TextureEntry + { + std::size_t bindingIndex; + std::string name; + TextureType type; + 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*/); + 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(); + + 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; + ShaderType m_type; +}; + +#include + +#endif diff --git a/src/ShaderNode/ShaderGraph.inl b/src/ShaderNode/ShaderGraph.inl new file mode 100644 index 000000000..afa867dcd --- /dev/null +++ b/src/ShaderNode/ShaderGraph.inl @@ -0,0 +1,97 @@ +#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()); + 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; +} + +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 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; +} + +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 std::size_t ShaderGraph::GetTextureCount() const +{ + return m_textures.size(); +} + +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/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 new file mode 100644 index 000000000..45ceed2c6 --- /dev/null +++ b/src/ShaderNode/Widgets/InputEditDialog.cpp @@ -0,0 +1,85 @@ +#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 < PrimitiveTypeCount; ++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_locationIndex = new QSpinBox; + + 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); + formLayout->addRow(tr("Input index"), m_locationIndex); + + 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_locationIndex->setValue(int(input.locationIndex)); + 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.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()); + 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..edd7577bf --- /dev/null +++ b/src/ShaderNode/Widgets/InputEditDialog.hpp @@ -0,0 +1,43 @@ +#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 locationIndex; + std::size_t roleIndex; + std::string name; + InputRole role; + PrimitiveType 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_locationIndex; + 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..db2681e5c --- /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..7898c3c27 --- /dev/null +++ b/src/ShaderNode/Widgets/InputEditor.cpp @@ -0,0 +1,98 @@ +#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, inputInfo.locationIndex); + }); + + dialog->open(); +} + +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; + 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, inputInfo.locationIndex); + }); + + 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..561a7b362 --- /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..db2681e5c --- /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 new file mode 100644 index 000000000..b88bef25f --- /dev/null +++ b/src/ShaderNode/Widgets/MainWindow.cpp @@ -0,0 +1,282 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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); + + // Input editor + 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); + + // 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")); + textureDock->setFeatures(QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetMovable); + textureDock->setWidget(textureEditor); + + addDockWidget(Qt::LeftDockWidgetArea, textureDock); + + // Node editor + 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); + + // 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) + { + m_nodeEditor->UpdateContent(node->caption(), [node](QFormLayout* layout) + { + node->BuildNodeEdition(layout); + }); + } + else + m_nodeEditor->Clear(); + }); + + + BuildMenu(); +} + +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* 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(); }); + } +} + +void MainWindow::OnCompile() +{ + try + { + auto shader = ToShader(); + + QString fileName = QFileDialog::getSaveFileName(nullptr, tr("Save shader"), QString(), tr("Shader Files (*.shader)")); + if (fileName.isEmpty()) + return; + + if (!fileName.endsWith("shader", Qt::CaseInsensitive)) + fileName += ".shader"; + + Nz::File file(fileName.toStdString(), Nz::OpenMode_WriteOnly); + file.Write(Nz::SerializeShader(shader)); + } + catch (const std::exception& e) + { + QMessageBox::critical(this, tr("Compilation failed"), QString("Compilation failed: ") + e.what()); + } +} + +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"), QString(), 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"), QString(), tr("Shader Flow Files (*.shaderflow)")); + if (fileName.isEmpty()) + return; + + if (!fileName.endsWith("shaderflow", Qt::CaseInsensitive)) + fileName += ".shaderflow"; + + QFile file(fileName); + if (file.open(QIODevice::WriteOnly)) + 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(ShaderGraph::ToShaderStageType(m_shaderGraph.GetType())); //< FIXME + for (const auto& input : m_shaderGraph.GetInputs()) + shader.AddInput(input.name, m_shaderGraph.ToShaderExpressionType(input.type), input.locationIndex); + + for (const auto& output : m_shaderGraph.GetOutputs()) + shader.AddOutput(output.name, m_shaderGraph.ToShaderExpressionType(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, m_shaderGraph.ToShaderExpressionType(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 = m_shaderGraph.ToShaderExpressionType(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); + + return shader; +} diff --git a/src/ShaderNode/Widgets/MainWindow.hpp b/src/ShaderNode/Widgets/MainWindow.hpp new file mode 100644 index 000000000..76615bb98 --- /dev/null +++ b/src/ShaderNode/Widgets/MainWindow.hpp @@ -0,0 +1,40 @@ +#pragma once + +#ifndef NAZARA_SHADERNODES_MAINWINDOW_HPP +#define NAZARA_SHADERNODES_MAINWINDOW_HPP + +#include +#include +#include + +class NodeEditor; + +namespace Nz +{ + class ShaderAst; +} + +class MainWindow : public QMainWindow +{ + public: + MainWindow(ShaderGraph& graph); + ~MainWindow() = default; + + private: + void BuildMenu(); + void OnCompile(); + void OnGenerateGLSL(); + void OnLoad(); + void OnSave(); + void OnUpdateInfo(); + Nz::ShaderAst ToShader(); + + NazaraSlot(ShaderGraph, OnSelectedNodeUpdate, m_onSelectedNodeUpdate); + + NodeEditor* m_nodeEditor; + 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..f10445799 --- /dev/null +++ b/src/ShaderNode/Widgets/MainWindow.inl @@ -0,0 +1 @@ +#include 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..1bdb36c77 --- /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: + QFormLayout* m_layout; +}; + +#include + +#endif diff --git a/src/ShaderNode/Widgets/NodeEditor.inl b/src/ShaderNode/Widgets/NodeEditor.inl new file mode 100644 index 000000000..3c26b8fe8 --- /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 QFormLayout; + setLayout(m_layout); + + QLabel* label = new QLabel(nodeName); + m_layout->addWidget(label); + + callback(m_layout); +} diff --git a/src/ShaderNode/Widgets/OutputEditDialog.cpp b/src/ShaderNode/Widgets/OutputEditDialog.cpp new file mode 100644 index 000000000..c6233e64c --- /dev/null +++ b/src/ShaderNode/Widgets/OutputEditDialog.cpp @@ -0,0 +1,73 @@ +#include +#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 < PrimitiveTypeCount; ++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); + connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); + + QVBoxLayout* verticalLayout = new QVBoxLayout; + verticalLayout->addLayout(formLayout); + verticalLayout->addWidget(buttonBox); + + setLayout(verticalLayout); +} + +OutputEditDialog::OutputEditDialog(const OutputInfo& output, QWidget* parent) : +OutputEditDialog(parent) +{ + 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()); + + 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..5b045faff --- /dev/null +++ b/src/ShaderNode/Widgets/OutputEditDialog.hpp @@ -0,0 +1,39 @@ +#pragma once + +#ifndef NAZARA_SHADERNODES_OUTPUTEDITDIALOG_HPP +#define NAZARA_SHADERNODES_OUTPUTEDITDIALOG_HPP + +#include +#include + +class QComboBox; +class QLineEdit; +class QSpinBox; + +struct OutputInfo +{ + std::size_t locationIndex; + std::string name; + PrimitiveType type; +}; + +class OutputEditDialog : public QDialog +{ + public: + OutputEditDialog(QWidget* parent = nullptr); + OutputEditDialog(const OutputInfo& output, QWidget* parent = nullptr); + ~OutputEditDialog() = default; + + OutputInfo GetOutputInfo() const; + + private: + void OnAccept(); + + QComboBox* m_typeList; + QLineEdit* m_outputName; + QSpinBox* m_locationIndex; +}; + +#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..40b8eea49 --- /dev/null +++ b/src/ShaderNode/Widgets/OutputEditor.cpp @@ -0,0 +1,94 @@ +#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 outputInfo = dialog->GetOutputInfo(); + m_shaderGraph.AddOutput(std::move(outputInfo.name), outputInfo.type, outputInfo.locationIndex); + }); + + dialog->open(); +} + +void OutputEditor::OnEditOutput(int inputIndex) +{ + const auto& output = m_shaderGraph.GetOutput(inputIndex); + + OutputInfo info; + 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); + connect(dialog, &QDialog::accepted, [this, dialog, inputIndex] + { + OutputInfo outputInfo = dialog->GetOutputInfo(); + m_shaderGraph.UpdateOutput(inputIndex, std::move(outputInfo.name), outputInfo.type, outputInfo.locationIndex); + }); + + 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 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 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 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 new file mode 100644 index 000000000..99b40316a --- /dev/null +++ b/src/ShaderNode/Widgets/TextureEditor.cpp @@ -0,0 +1,126 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +TextureEditor::TextureEditor(ShaderGraph& graph) : +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; + + 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); + 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) + 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::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(); + 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..1c006e0ab --- /dev/null +++ b/src/ShaderNode/Widgets/TextureEditor.hpp @@ -0,0 +1,44 @@ +#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 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; + 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..318a1e9a3 --- /dev/null +++ b/src/ShaderNode/Widgets/TextureEditor.inl @@ -0,0 +1 @@ +#include diff --git a/src/ShaderNode/main.cpp b/src/ShaderNode/main.cpp new file mode 100644 index 000000000..8cea2a20f --- /dev/null +++ b/src/ShaderNode/main.cpp @@ -0,0 +1,17 @@ +#include +#include +#include +#include + +int main(int argc, char* argv[]) +{ + QApplication app(argc, argv); + + ShaderGraph shaderGraph; + + MainWindow mainWindow(shaderGraph); + mainWindow.resize(1280, 720); + mainWindow.show(); + + return app.exec(); +} 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 + 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