WIP SpirvWriter
This commit is contained in:
parent
59add283cf
commit
251810ca99
|
|
@ -1,5 +1,6 @@
|
|||
#include <Nazara/Utility.hpp>
|
||||
#include <Nazara/Renderer.hpp>
|
||||
#include <Nazara/Renderer/SpirvWriter.hpp>
|
||||
#include <array>
|
||||
#include <iostream>
|
||||
|
||||
|
|
@ -7,6 +8,38 @@
|
|||
|
||||
int main()
|
||||
{
|
||||
{
|
||||
Nz::File file("frag.shader");
|
||||
if (!file.Open(Nz::OpenMode_ReadOnly))
|
||||
return __LINE__;
|
||||
|
||||
std::size_t length = static_cast<std::size_t>(file.GetSize());
|
||||
|
||||
std::vector<Nz::UInt8> source(length);
|
||||
if (file.Read(&source[0], length) != length)
|
||||
{
|
||||
NazaraError("Failed to read program file");
|
||||
return {};
|
||||
}
|
||||
|
||||
|
||||
|
||||
Nz::SpirvWriter writer;
|
||||
|
||||
Nz::ByteStream byteStream(source.data(), source.size());
|
||||
auto shader = Nz::UnserializeShader(byteStream);
|
||||
|
||||
std::vector<Nz::UInt32> result = writer.Generate(shader);
|
||||
|
||||
Nz::File target("test.spirv");
|
||||
if (!target.Open(Nz::OpenMode_WriteOnly | Nz::OpenMode_Truncate))
|
||||
return __LINE__;
|
||||
|
||||
target.Write(result.data(), result.size() * sizeof(Nz::UInt32));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Nz::Initializer<Nz::Renderer> loader;
|
||||
if (!loader)
|
||||
{
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
|
|
@ -81,6 +81,15 @@ namespace Nz::ShaderNodes
|
|||
StatementBlock
|
||||
};
|
||||
|
||||
enum class SsaInstruction
|
||||
{
|
||||
OpAdd,
|
||||
OpDiv,
|
||||
OpMul,
|
||||
OpSub,
|
||||
OpSample
|
||||
};
|
||||
|
||||
enum class SwizzleComponent
|
||||
{
|
||||
First,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,100 @@
|
|||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Renderer module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NAZARA_SPIRVWRITER_HPP
|
||||
#define NAZARA_SPIRVWRITER_HPP
|
||||
|
||||
#include <Nazara/Prerequisites.hpp>
|
||||
#include <Nazara/Renderer/Config.hpp>
|
||||
#include <Nazara/Renderer/ShaderAst.hpp>
|
||||
#include <Nazara/Renderer/ShaderVarVisitor.hpp>
|
||||
#include <Nazara/Renderer/ShaderVisitor.hpp>
|
||||
#include <Nazara/Renderer/ShaderWriter.hpp>
|
||||
#include <set>
|
||||
#include <string_view>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
class NAZARA_RENDERER_API SpirvWriter : public ShaderVarVisitor, public ShaderVisitor
|
||||
{
|
||||
public:
|
||||
struct Environment;
|
||||
|
||||
SpirvWriter();
|
||||
SpirvWriter(const SpirvWriter&) = delete;
|
||||
SpirvWriter(SpirvWriter&&) = delete;
|
||||
~SpirvWriter() = default;
|
||||
|
||||
std::vector<UInt32> Generate(const ShaderAst& shader);
|
||||
|
||||
void SetEnv(Environment environment);
|
||||
|
||||
struct Environment
|
||||
{
|
||||
};
|
||||
|
||||
private:
|
||||
struct Opcode;
|
||||
|
||||
inline void Append(const char* str);
|
||||
void Append(const std::string_view& str);
|
||||
void Append(const Opcode& opcode, unsigned int wordCount);
|
||||
void Append(UInt32 codepoint);
|
||||
void Append(std::initializer_list<UInt32> codepoints);
|
||||
template<typename... Args> void Append(Opcode opcode, const Args&... args);
|
||||
template<typename T> void Append(T value);
|
||||
|
||||
void AppendHeader();
|
||||
|
||||
inline unsigned int CountWord(const char* str);
|
||||
unsigned int CountWord(const std::string_view& str);
|
||||
template<typename T> unsigned int CountWord(const T& value);
|
||||
template<typename T1, typename T2, typename... Args> unsigned int CountWord(const T1& value, const T2& value2, const Args&... rest);
|
||||
|
||||
using ShaderVarVisitor::Visit;
|
||||
using ShaderVisitor::Visit;
|
||||
void Visit(const ShaderNodes::ExpressionPtr& expr, bool encloseIfRequired = false);
|
||||
void Visit(const ShaderNodes::AccessMember& node) override;
|
||||
void Visit(const ShaderNodes::AssignOp& node) override;
|
||||
void Visit(const ShaderNodes::Branch& node) override;
|
||||
void Visit(const ShaderNodes::BinaryOp& node) override;
|
||||
void Visit(const ShaderNodes::BuiltinVariable& var) override;
|
||||
void Visit(const ShaderNodes::Cast& node) override;
|
||||
void Visit(const ShaderNodes::Constant& node) override;
|
||||
void Visit(const ShaderNodes::DeclareVariable& node) override;
|
||||
void Visit(const ShaderNodes::ExpressionStatement& node) override;
|
||||
void Visit(const ShaderNodes::Identifier& node) override;
|
||||
void Visit(const ShaderNodes::InputVariable& var) override;
|
||||
void Visit(const ShaderNodes::IntrinsicCall& node) override;
|
||||
void Visit(const ShaderNodes::LocalVariable& var) override;
|
||||
void Visit(const ShaderNodes::ParameterVariable& var) override;
|
||||
void Visit(const ShaderNodes::OutputVariable& var) override;
|
||||
void Visit(const ShaderNodes::Sample2D& node) override;
|
||||
void Visit(const ShaderNodes::StatementBlock& node) override;
|
||||
void Visit(const ShaderNodes::SwizzleOp& node) override;
|
||||
void Visit(const ShaderNodes::UniformVariable& var) override;
|
||||
|
||||
struct Context
|
||||
{
|
||||
const ShaderAst* shader = nullptr;
|
||||
const ShaderAst::Function* currentFunction = nullptr;
|
||||
};
|
||||
|
||||
struct State
|
||||
{
|
||||
std::vector<UInt32> output;
|
||||
};
|
||||
|
||||
Context m_context;
|
||||
Environment m_environment;
|
||||
State* m_currentState;
|
||||
};
|
||||
}
|
||||
|
||||
#include <Nazara/Renderer/SpirvWriter.inl>
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Renderer module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Renderer/SpirvWriter.hpp>
|
||||
#include <cassert>
|
||||
#include <type_traits>
|
||||
#include <Nazara/Renderer/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
inline void SpirvWriter::Append(const char* str)
|
||||
{
|
||||
return Append(std::string_view(str));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void SpirvWriter::Append(T value)
|
||||
{
|
||||
assert(m_currentState);
|
||||
m_currentState->output.push_back(static_cast<UInt32>(value));
|
||||
}
|
||||
|
||||
template<typename ...Args>
|
||||
inline void SpirvWriter::Append(Opcode opcode, const Args&... args)
|
||||
{
|
||||
unsigned int wordCount = 1 + (CountWord(args) + ... + 0);
|
||||
Append(opcode, wordCount);
|
||||
if constexpr (sizeof...(args) > 0)
|
||||
(Append(args), ...);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline unsigned int SpirvWriter::CountWord(const T& value)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
template<typename T1, typename T2, typename ...Args>
|
||||
unsigned int SpirvWriter::CountWord(const T1& value, const T2& value2, const Args&... rest)
|
||||
{
|
||||
return CountWord(value) + CountWord(value2) + (CountWord(rest) + ...);
|
||||
}
|
||||
|
||||
inline unsigned int SpirvWriter::CountWord(const char* str)
|
||||
{
|
||||
return CountWord(std::string_view(str));
|
||||
}
|
||||
|
||||
inline unsigned int SpirvWriter::CountWord(const std::string_view& str)
|
||||
{
|
||||
return (str.size() + 1 + 4 - 1) / 4; //< + 1 for null character
|
||||
}
|
||||
}
|
||||
|
||||
#include <Nazara/Renderer/DebugOff.hpp>
|
||||
|
|
@ -0,0 +1,178 @@
|
|||
// Copyright (C) 2015 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Renderer module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Renderer/SpirvWriter.hpp>
|
||||
#include <Nazara/Core/CallOnExit.hpp>
|
||||
#include <Nazara/Renderer/ShaderValidator.hpp>
|
||||
#include <SpirV/spirv.h>
|
||||
#include <SpirV/GLSL.std.450.h>
|
||||
#include <cassert>
|
||||
#include <stdexcept>
|
||||
#include <Nazara/Renderer/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
struct SpirvWriter::Opcode
|
||||
{
|
||||
SpvOp op;
|
||||
};
|
||||
|
||||
SpirvWriter::SpirvWriter() :
|
||||
m_currentState(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
std::vector<UInt32> SpirvWriter::Generate(const ShaderAst& shader)
|
||||
{
|
||||
std::string error;
|
||||
if (!ValidateShader(shader, &error))
|
||||
throw std::runtime_error("Invalid shader AST: " + error);
|
||||
|
||||
m_context.shader = &shader;
|
||||
|
||||
State state;
|
||||
m_currentState = &state;
|
||||
CallOnExit onExit([this]()
|
||||
{
|
||||
m_currentState = nullptr;
|
||||
});
|
||||
|
||||
AppendHeader();
|
||||
|
||||
// OpImageSampleImplicitLod %23 %31 %35
|
||||
|
||||
//Append("BONJOUR PRAETONUS");
|
||||
|
||||
std::vector<UInt32> ret = std::move(state.output);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void SpirvWriter::SetEnv(Environment environment)
|
||||
{
|
||||
m_environment = std::move(environment);
|
||||
}
|
||||
|
||||
void SpirvWriter::Append(const std::string_view& str)
|
||||
{
|
||||
std::size_t size4 = CountWord(str);
|
||||
for (std::size_t i = 0; i < size4; ++i)
|
||||
{
|
||||
auto GetChar = [&](std::size_t pos) -> UInt32
|
||||
{
|
||||
if (pos < str.size())
|
||||
return static_cast<UInt32>(str[pos]);
|
||||
else
|
||||
return 0;
|
||||
};
|
||||
|
||||
UInt32 codepoint = 0;
|
||||
for (std::size_t j = 0; j < 4; ++j)
|
||||
codepoint |= GetChar(i * 4 + j) << (j * 8);
|
||||
|
||||
Append(codepoint);
|
||||
}
|
||||
}
|
||||
|
||||
void SpirvWriter::Append(const Opcode& opcode, unsigned int wordCount)
|
||||
{
|
||||
Append(UInt32(opcode.op) | UInt32(wordCount) << 16);
|
||||
}
|
||||
|
||||
void SpirvWriter::Append(UInt32 codepoint)
|
||||
{
|
||||
assert(m_currentState);
|
||||
m_currentState->output.push_back(codepoint);
|
||||
}
|
||||
|
||||
void SpirvWriter::Append(std::initializer_list<UInt32> codepoints)
|
||||
{
|
||||
for (UInt32 cp : codepoints)
|
||||
Append(cp);
|
||||
}
|
||||
|
||||
void SpirvWriter::AppendHeader()
|
||||
{
|
||||
Append(SpvMagicNumber); //< Spir-V magic number
|
||||
Append(0x00010000); //< Spir-V version number (1.0 for compatibility)
|
||||
Append(0); //< Generator magic number (TODO: Register generator to Khronos)
|
||||
Append(1); //< Bound (ID count)
|
||||
Append(0); //< Instruction schema (required to be 0 for now)
|
||||
Append(Opcode{ SpvOpCapability }, SpvCapabilityShader);
|
||||
Append(Opcode{ SpvOpExtInstImport }, 1, "GLSL.std.450");
|
||||
Append(Opcode{ SpvOpMemoryModel }, SpvAddressingModelLogical, SpvMemoryModelGLSL450);
|
||||
|
||||
assert(m_context.shader);
|
||||
switch (m_context.shader->GetStage())
|
||||
{
|
||||
case ShaderStageType::Fragment:
|
||||
break;
|
||||
case ShaderStageType::Vertex:
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void SpirvWriter::Visit(const ShaderNodes::ExpressionPtr& expr, bool encloseIfRequired)
|
||||
{
|
||||
}
|
||||
void SpirvWriter::Visit(const ShaderNodes::AccessMember& node)
|
||||
{
|
||||
}
|
||||
void SpirvWriter::Visit(const ShaderNodes::AssignOp& node)
|
||||
{
|
||||
}
|
||||
void SpirvWriter::Visit(const ShaderNodes::Branch& node)
|
||||
{
|
||||
}
|
||||
void SpirvWriter::Visit(const ShaderNodes::BinaryOp& node)
|
||||
{
|
||||
}
|
||||
void SpirvWriter::Visit(const ShaderNodes::BuiltinVariable& var)
|
||||
{
|
||||
}
|
||||
void SpirvWriter::Visit(const ShaderNodes::Cast& node)
|
||||
{
|
||||
}
|
||||
void SpirvWriter::Visit(const ShaderNodes::Constant& node)
|
||||
{
|
||||
}
|
||||
void SpirvWriter::Visit(const ShaderNodes::DeclareVariable& node)
|
||||
{
|
||||
}
|
||||
void SpirvWriter::Visit(const ShaderNodes::ExpressionStatement& node)
|
||||
{
|
||||
}
|
||||
void SpirvWriter::Visit(const ShaderNodes::Identifier& node)
|
||||
{
|
||||
}
|
||||
void SpirvWriter::Visit(const ShaderNodes::InputVariable& var)
|
||||
{
|
||||
}
|
||||
void SpirvWriter::Visit(const ShaderNodes::IntrinsicCall& node)
|
||||
{
|
||||
}
|
||||
void SpirvWriter::Visit(const ShaderNodes::LocalVariable& var)
|
||||
{
|
||||
}
|
||||
void SpirvWriter::Visit(const ShaderNodes::ParameterVariable& var)
|
||||
{
|
||||
}
|
||||
void SpirvWriter::Visit(const ShaderNodes::OutputVariable& var)
|
||||
{
|
||||
}
|
||||
void SpirvWriter::Visit(const ShaderNodes::Sample2D& node)
|
||||
{
|
||||
}
|
||||
void SpirvWriter::Visit(const ShaderNodes::StatementBlock& node)
|
||||
{
|
||||
}
|
||||
void SpirvWriter::Visit(const ShaderNodes::SwizzleOp& node)
|
||||
{
|
||||
}
|
||||
void SpirvWriter::Visit(const ShaderNodes::UniformVariable& var)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue