Renderer: Add support for struct and UBO

This commit is contained in:
Jérôme Leclercq
2020-07-14 21:59:49 +02:00
parent 4c0dc7813d
commit fbba281d14
12 changed files with 346 additions and 49 deletions

View File

@@ -44,15 +44,17 @@ namespace Nz
};
private:
void Append(ShaderAst::Type type);
void Append(ShaderNodes::BuiltinEntry builtin);
void Append(ShaderNodes::ExpressionType type);
void Append(ShaderNodes::MemoryLayout layout);
template<typename T> void Append(const T& param);
void AppendCommentSection(const std::string& section);
void AppendFunction(const ShaderAst::Function& func);
void AppendFunctionPrototype(const ShaderAst::Function& func);
void AppendLine(const std::string& txt = {});
template<typename T> void DeclareVariables(const std::vector<T>& variables, const std::string& keyword = {}, const std::string& section = {});
template<typename T> void DeclareVariables(const ShaderAst& shader, const std::vector<T>& variables, const std::string& keyword = {}, const std::string& section = {});
void EnterScope();
void LeaveScope();

View File

@@ -17,7 +17,7 @@ namespace Nz
}
template<typename T>
void GlslWriter::DeclareVariables(const std::vector<T>& variables, const std::string& keyword, const std::string& section)
void GlslWriter::DeclareVariables(const ShaderAst& shader, const std::vector<T>& variables, const std::string& keyword, const std::string& section)
{
if (!variables.empty())
{
@@ -34,27 +34,94 @@ namespace Nz
Append(*var.locationIndex);
Append(") ");
}
if (!keyword.empty())
{
Append(keyword);
Append(" ");
}
Append(var.type);
Append(" ");
Append(var.name);
AppendLine(";");
}
else if constexpr (std::is_same_v<T, ShaderAst::Uniform>)
{
if (var.bindingIndex)
if (var.bindingIndex || var.memoryLayout)
{
Append("layout(binding = ");
Append(*var.bindingIndex);
Append("layout(");
bool first = true;
if (var.bindingIndex)
{
if (!first)
Append(", ");
Append("binding = ");
Append(*var.bindingIndex);
first = false;
}
if (var.memoryLayout)
{
if (!first)
Append(", ");
Append(*var.memoryLayout);
first = false;
}
Append(") ");
}
}
if (!keyword.empty())
{
Append(keyword);
Append(" ");
}
if (!keyword.empty())
{
Append(keyword);
Append(" ");
}
Append(var.type);
Append(" ");
Append(var.name);
AppendLine(";");
std::visit([&](auto&& arg)
{
using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<T, ShaderNodes::ExpressionType>)
{
Append(arg);
Append(" ");
Append(var.name);
}
else if constexpr (std::is_same_v<T, std::string>)
{
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<T>::value, "non-exhaustive visitor");
}, var.type);
AppendLine(";");
AppendLine();
}
}
AppendLine();

View File

@@ -11,6 +11,8 @@
#include <Nazara/Renderer/ShaderNodes.hpp>
#include <optional>
#include <string>
#include <unordered_map>
#include <variant>
#include <vector>
namespace Nz
@@ -21,16 +23,21 @@ namespace Nz
struct Function;
struct FunctionParameter;
struct InputOutput;
struct VariableBase;
struct Struct;
struct StructMember;
struct Uniform;
struct VariableBase;
using Type = std::variant<ShaderNodes::ExpressionType, std::string>;
ShaderAst() = default;
~ShaderAst() = default;
void AddFunction(std::string name, ShaderNodes::StatementPtr statement, std::vector<FunctionParameter> parameters = {}, ShaderNodes::ExpressionType returnType = ShaderNodes::ExpressionType::Void);
void AddInput(std::string name, ShaderNodes::ExpressionType type, std::optional<std::size_t> locationIndex);
void AddOutput(std::string name, ShaderNodes::ExpressionType type, std::optional<std::size_t> locationIndex);
void AddUniform(std::string name, ShaderNodes::ExpressionType type, std::optional<std::size_t> bindingIndex);
void AddInput(std::string name, Type type, std::optional<std::size_t> locationIndex);
void AddOutput(std::string name, Type type, std::optional<std::size_t> locationIndex);
void AddStruct(std::string name, std::vector<StructMember> members);
void AddUniform(std::string name, Type type, std::optional<std::size_t> bindingIndex, std::optional<ShaderNodes::MemoryLayout> memoryLayout);
inline const Function& GetFunction(std::size_t i) const;
inline std::size_t GetFunctionCount() const;
@@ -41,6 +48,9 @@ namespace Nz
inline const InputOutput& GetOutput(std::size_t i) const;
inline std::size_t GetOutputCount() const;
inline const std::vector<InputOutput>& GetOutputs() const;
inline const Struct& GetStruct(std::size_t i) const;
inline std::size_t GetStructCount() const;
inline const std::vector<Struct>& GetStructs() const;
inline const Uniform& GetUniform(std::size_t i) const;
inline std::size_t GetUniformCount() const;
inline const std::vector<Uniform>& GetUniforms() const;
@@ -48,7 +58,7 @@ namespace Nz
struct VariableBase
{
std::string name;
ShaderNodes::ExpressionType type;
Type type;
};
struct FunctionParameter : VariableBase
@@ -71,12 +81,26 @@ namespace Nz
struct Uniform : VariableBase
{
std::optional<std::size_t> bindingIndex;
std::optional<ShaderNodes::MemoryLayout> memoryLayout;
};
struct Struct
{
std::string name;
std::vector<StructMember> members;
};
struct StructMember
{
std::string name;
Type type;
};
private:
std::vector<Function> m_functions;
std::vector<InputOutput> m_inputs;
std::vector<InputOutput> m_outputs;
std::vector<Struct> m_structs;
std::vector<Uniform> m_uniforms;
};
}

View File

@@ -55,6 +55,22 @@ namespace Nz
return m_outputs;
}
inline auto ShaderAst::GetStruct(std::size_t i) const -> const Struct&
{
assert(i < m_structs.size());
return m_structs[i];
}
inline std::size_t ShaderAst::GetStructCount() const
{
return m_structs.size();
}
inline auto ShaderAst::GetStructs() const -> const std::vector<Struct>&
{
return m_structs;
}
inline auto ShaderAst::GetUniform(std::size_t i) const -> const Uniform&
{
assert(i < m_uniforms.size());

View File

@@ -56,6 +56,11 @@ namespace Nz::ShaderNodes
DotProduct
};
enum class MemoryLayout
{
Std140
};
enum class NodeType
{
None = -1,

View File

@@ -11,13 +11,12 @@
#include <Nazara/Core/ByteArray.hpp>
#include <Nazara/Core/ByteStream.hpp>
#include <Nazara/Renderer/Config.hpp>
#include <Nazara/Renderer/ShaderAst.hpp>
#include <Nazara/Renderer/ShaderNodes.hpp>
#include <Nazara/Renderer/ShaderVariables.hpp>
namespace Nz
{
class ShaderAst;
class NAZARA_RENDERER_API ShaderSerializerBase
{
public:
@@ -44,6 +43,7 @@ namespace Nz
protected:
template<typename T> void Container(T& container);
template<typename T> void Enum(T& enumVal);
template<typename T> void OptEnum(std::optional<T>& optVal);
template<typename T> void OptVal(std::optional<T>& optVal);
virtual bool IsWriting() const = 0;
@@ -57,6 +57,8 @@ namespace Nz
virtual void Value(Vector2f& val) = 0;
virtual void Value(Vector3f& val) = 0;
virtual void Value(Vector4f& val) = 0;
virtual void Value(UInt8& val) = 0;
virtual void Value(UInt16& val) = 0;
virtual void Value(UInt32& val) = 0;
inline void Value(std::size_t& val);
@@ -82,6 +84,8 @@ namespace Nz
void Value(Vector2f& val) override;
void Value(Vector3f& val) override;
void Value(Vector4f& val) override;
void Value(UInt8& val) override;
void Value(UInt16& val) override;
void Value(UInt32& val) override;
void Variable(ShaderNodes::VariablePtr& var) override;
@@ -99,12 +103,15 @@ namespace Nz
private:
bool IsWriting() const override;
void Node(ShaderNodes::NodePtr& node) override;
void Type(ShaderAst::Type& type);
void Value(bool& val) override;
void Value(float& val) override;
void Value(std::string& val) override;
void Value(Vector2f& val) override;
void Value(Vector3f& val) override;
void Value(Vector4f& val) override;
void Value(UInt8& val) override;
void Value(UInt16& val) override;
void Value(UInt32& val) override;
void Variable(ShaderNodes::VariablePtr& var) override;

View File

@@ -36,6 +36,24 @@ namespace Nz
enumVal = static_cast<T>(value);
}
template<typename T>
void ShaderSerializerBase::OptEnum(std::optional<T>& 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<typename T>
void ShaderSerializerBase::OptVal(std::optional<T>& optVal)
{

View File

@@ -11,12 +11,11 @@
#include <Nazara/Core/ByteArray.hpp>
#include <Nazara/Core/ByteStream.hpp>
#include <Nazara/Renderer/Config.hpp>
#include <Nazara/Renderer/ShaderAst.hpp>
#include <Nazara/Renderer/ShaderVisitor.hpp>
namespace Nz
{
class ShaderAst;
class NAZARA_RENDERER_API ShaderValidator : public ShaderVisitor
{
public:
@@ -31,7 +30,7 @@ namespace Nz
const ShaderNodes::ExpressionPtr& MandatoryExpr(const ShaderNodes::ExpressionPtr& node);
const ShaderNodes::NodePtr& MandatoryNode(const ShaderNodes::NodePtr& node);
void TypeMustMatch(const ShaderNodes::ExpressionPtr& left, const ShaderNodes::ExpressionPtr& right);
void TypeMustMatch(ShaderNodes::ExpressionType left, ShaderNodes::ExpressionType right);
void TypeMustMatch(const ShaderAst::Type& left, const ShaderAst::Type& right);
using ShaderVisitor::Visit;
void Visit(const ShaderNodes::AssignOp& node) override;