Renderer: Add support for struct and UBO
This commit is contained in:
@@ -108,13 +108,35 @@ namespace Nz
|
||||
AppendLine();
|
||||
}
|
||||
|
||||
// Structures
|
||||
/*if (shader.GetStructCount() > 0)
|
||||
{
|
||||
AppendCommentSection("Structures");
|
||||
for (const auto& s : shader.GetStructs())
|
||||
{
|
||||
Append("struct ");
|
||||
AppendLine(s.name);
|
||||
AppendLine("{");
|
||||
for (const auto& m : s.members)
|
||||
{
|
||||
Append("\t");
|
||||
Append(m.type);
|
||||
Append(" ");
|
||||
Append(m.name);
|
||||
AppendLine(";");
|
||||
}
|
||||
AppendLine("};");
|
||||
AppendLine();
|
||||
}
|
||||
}*/
|
||||
|
||||
// Global variables (uniforms, input and outputs)
|
||||
const char* inKeyword = (glslVersion >= 130) ? "in" : "varying";
|
||||
const char* outKeyword = (glslVersion >= 130) ? "out" : "varying";
|
||||
|
||||
DeclareVariables(shader.GetUniforms(), "uniform", "Uniforms");
|
||||
DeclareVariables(shader.GetInputs(), inKeyword, "Inputs");
|
||||
DeclareVariables(shader.GetOutputs(), outKeyword, "Outputs");
|
||||
DeclareVariables(shader, shader.GetUniforms(), "uniform", "Uniforms");
|
||||
DeclareVariables(shader, shader.GetInputs(), inKeyword, "Inputs");
|
||||
DeclareVariables(shader, shader.GetOutputs(), outKeyword, "Outputs");
|
||||
|
||||
std::size_t functionCount = shader.GetFunctionCount();
|
||||
if (functionCount > 1)
|
||||
@@ -141,6 +163,14 @@ namespace Nz
|
||||
m_environment = std::move(environment);
|
||||
}
|
||||
|
||||
void GlslWriter::Append(ShaderAst::Type type)
|
||||
{
|
||||
std::visit([&](auto&& arg)
|
||||
{
|
||||
Append(arg);
|
||||
}, type);
|
||||
}
|
||||
|
||||
void GlslWriter::Append(ShaderNodes::BuiltinEntry builtin)
|
||||
{
|
||||
switch (builtin)
|
||||
@@ -182,6 +212,16 @@ namespace Nz
|
||||
}
|
||||
}
|
||||
|
||||
void GlslWriter::Append(ShaderNodes::MemoryLayout layout)
|
||||
{
|
||||
switch (layout)
|
||||
{
|
||||
case ShaderNodes::MemoryLayout::Std140:
|
||||
Append("std140");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void GlslWriter::AppendCommentSection(const std::string& section)
|
||||
{
|
||||
NazaraAssert(m_currentState, "This function should only be called while processing an AST");
|
||||
|
||||
@@ -16,27 +16,35 @@ namespace Nz
|
||||
functionEntry.statement = std::move(statement);
|
||||
}
|
||||
|
||||
void ShaderAst::AddInput(std::string name, ShaderNodes::ExpressionType type, std::optional<std::size_t> locationIndex)
|
||||
void ShaderAst::AddInput(std::string name, Type type, std::optional<std::size_t> locationIndex)
|
||||
{
|
||||
auto& inputEntry = m_inputs.emplace_back();
|
||||
inputEntry.name = std::move(name);
|
||||
inputEntry.locationIndex = std::move(locationIndex);
|
||||
inputEntry.type = type;
|
||||
inputEntry.type = std::move(type);
|
||||
}
|
||||
|
||||
void ShaderAst::AddOutput(std::string name, ShaderNodes::ExpressionType type, std::optional<std::size_t> locationIndex)
|
||||
void ShaderAst::AddOutput(std::string name, Type type, std::optional<std::size_t> locationIndex)
|
||||
{
|
||||
auto& outputEntry = m_outputs.emplace_back();
|
||||
outputEntry.name = std::move(name);
|
||||
outputEntry.locationIndex = std::move(locationIndex);
|
||||
outputEntry.type = type;
|
||||
outputEntry.type = std::move(type);
|
||||
}
|
||||
|
||||
void ShaderAst::AddUniform(std::string name, ShaderNodes::ExpressionType type, std::optional<std::size_t> bindingIndex)
|
||||
void ShaderAst::AddStruct(std::string name, std::vector<StructMember> members)
|
||||
{
|
||||
auto& structEntry = m_structs.emplace_back();
|
||||
structEntry.name = std::move(name);
|
||||
structEntry.members = std::move(members);
|
||||
}
|
||||
|
||||
void ShaderAst::AddUniform(std::string name, Type type, std::optional<std::size_t> bindingIndex, std::optional<ShaderNodes::MemoryLayout> memoryLayout)
|
||||
{
|
||||
auto& uniformEntry = m_uniforms.emplace_back();
|
||||
uniformEntry.bindingIndex = std::move(bindingIndex);
|
||||
uniformEntry.memoryLayout = std::move(memoryLayout);
|
||||
uniformEntry.name = std::move(name);
|
||||
uniformEntry.type = type;
|
||||
uniformEntry.type = std::move(type);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Renderer/ShaderSerializer.hpp>
|
||||
#include <Nazara/Renderer/ShaderAst.hpp>
|
||||
#include <Nazara/Renderer/ShaderVarVisitor.hpp>
|
||||
#include <Nazara/Renderer/ShaderVisitor.hpp>
|
||||
#include <Nazara/Renderer/Debug.hpp>
|
||||
@@ -250,12 +249,33 @@ namespace Nz
|
||||
{
|
||||
m_stream << s_magicNumber << s_currentVersion;
|
||||
|
||||
auto SerializeType = [&](const ShaderAst::Type& type)
|
||||
{
|
||||
std::visit([&](auto&& arg)
|
||||
{
|
||||
using T = std::decay_t<decltype(arg)>;
|
||||
if constexpr (std::is_same_v<T, ShaderNodes::ExpressionType>)
|
||||
{
|
||||
m_stream << UInt8(0);
|
||||
m_stream << UInt32(arg);
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, std::string>)
|
||||
{
|
||||
m_stream << UInt8(1);
|
||||
m_stream << arg;
|
||||
}
|
||||
else
|
||||
static_assert(AlwaysFalse<T>::value, "non-exhaustive visitor");
|
||||
}, type);
|
||||
};
|
||||
|
||||
auto SerializeInputOutput = [&](auto& inout)
|
||||
{
|
||||
m_stream << UInt32(inout.size());
|
||||
for (const auto& data : inout)
|
||||
{
|
||||
m_stream << data.name << UInt32(data.type);
|
||||
m_stream << data.name;
|
||||
SerializeType(data.type);
|
||||
|
||||
m_stream << data.locationIndex.has_value();
|
||||
if (data.locationIndex)
|
||||
@@ -263,17 +283,34 @@ namespace Nz
|
||||
}
|
||||
};
|
||||
|
||||
m_stream << UInt32(shader.GetStructCount());
|
||||
for (const auto& s : shader.GetStructs())
|
||||
{
|
||||
m_stream << s.name;
|
||||
m_stream << UInt32(s.members.size());
|
||||
for (const auto& member : s.members)
|
||||
{
|
||||
m_stream << member.name;
|
||||
SerializeType(member.type);
|
||||
}
|
||||
}
|
||||
|
||||
SerializeInputOutput(shader.GetInputs());
|
||||
SerializeInputOutput(shader.GetOutputs());
|
||||
|
||||
m_stream << UInt32(shader.GetUniformCount());
|
||||
for (const auto& uniform : shader.GetUniforms())
|
||||
{
|
||||
m_stream << uniform.name << UInt32(uniform.type);
|
||||
m_stream << uniform.name;
|
||||
SerializeType(uniform.type);
|
||||
|
||||
m_stream << uniform.bindingIndex.has_value();
|
||||
if (uniform.bindingIndex)
|
||||
m_stream << UInt32(uniform.bindingIndex.value());
|
||||
|
||||
m_stream << uniform.memoryLayout.has_value();
|
||||
if (uniform.memoryLayout)
|
||||
m_stream << UInt32(uniform.memoryLayout.value());
|
||||
}
|
||||
|
||||
m_stream << UInt32(shader.GetFunctionCount());
|
||||
@@ -283,7 +320,10 @@ namespace Nz
|
||||
|
||||
m_stream << UInt32(func.parameters.size());
|
||||
for (const auto& param : func.parameters)
|
||||
m_stream << param.name << UInt32(param.type);
|
||||
{
|
||||
m_stream << param.name;
|
||||
SerializeType(param.type);
|
||||
}
|
||||
|
||||
Node(func.statement);
|
||||
}
|
||||
@@ -343,6 +383,16 @@ namespace Nz
|
||||
m_stream << val;
|
||||
}
|
||||
|
||||
void ShaderSerializer::Value(UInt8& val)
|
||||
{
|
||||
m_stream << val;
|
||||
}
|
||||
|
||||
void ShaderSerializer::Value(UInt16& val)
|
||||
{
|
||||
m_stream << val;
|
||||
}
|
||||
|
||||
void ShaderSerializer::Value(UInt32& val)
|
||||
{
|
||||
m_stream << val;
|
||||
@@ -374,19 +424,38 @@ namespace Nz
|
||||
|
||||
ShaderAst shader;
|
||||
|
||||
UInt32 structCount;
|
||||
m_stream >> structCount;
|
||||
for (UInt32 i = 0; i < structCount; ++i)
|
||||
{
|
||||
std::string structName;
|
||||
std::vector<ShaderAst::StructMember> members;
|
||||
|
||||
Value(structName);
|
||||
Container(members);
|
||||
|
||||
for (auto& member : members)
|
||||
{
|
||||
Value(member.name);
|
||||
Type(member.type);
|
||||
}
|
||||
|
||||
shader.AddStruct(std::move(structName), std::move(members));
|
||||
}
|
||||
|
||||
UInt32 inputCount;
|
||||
m_stream >> inputCount;
|
||||
for (UInt32 i = 0; i < inputCount; ++i)
|
||||
{
|
||||
std::string inputName;
|
||||
ShaderNodes::ExpressionType inputType;
|
||||
ShaderAst::Type inputType;
|
||||
std::optional<std::size_t> location;
|
||||
|
||||
Value(inputName);
|
||||
Enum(inputType);
|
||||
Type(inputType);
|
||||
OptVal(location);
|
||||
|
||||
shader.AddInput(std::move(inputName), inputType, location);
|
||||
shader.AddInput(std::move(inputName), std::move(inputType), location);
|
||||
}
|
||||
|
||||
UInt32 outputCount;
|
||||
@@ -394,14 +463,14 @@ namespace Nz
|
||||
for (UInt32 i = 0; i < outputCount; ++i)
|
||||
{
|
||||
std::string outputName;
|
||||
ShaderNodes::ExpressionType outputType;
|
||||
ShaderAst::Type outputType;
|
||||
std::optional<std::size_t> location;
|
||||
|
||||
Value(outputName);
|
||||
Enum(outputType);
|
||||
Type(outputType);
|
||||
OptVal(location);
|
||||
|
||||
shader.AddOutput(std::move(outputName), outputType, location);
|
||||
shader.AddOutput(std::move(outputName), std::move(outputType), location);
|
||||
}
|
||||
|
||||
UInt32 uniformCount;
|
||||
@@ -409,14 +478,16 @@ namespace Nz
|
||||
for (UInt32 i = 0; i < uniformCount; ++i)
|
||||
{
|
||||
std::string name;
|
||||
ShaderNodes::ExpressionType type;
|
||||
ShaderAst::Type type;
|
||||
std::optional<std::size_t> binding;
|
||||
std::optional<ShaderNodes::MemoryLayout> memLayout;
|
||||
|
||||
Value(name);
|
||||
Enum(type);
|
||||
Type(type);
|
||||
OptVal(binding);
|
||||
OptEnum(memLayout);
|
||||
|
||||
shader.AddUniform(std::move(name), type, binding);
|
||||
shader.AddUniform(std::move(name), std::move(type), std::move(binding), std::move(memLayout));
|
||||
}
|
||||
|
||||
UInt32 funcCount;
|
||||
@@ -433,7 +504,7 @@ namespace Nz
|
||||
for (auto& param : parameters)
|
||||
{
|
||||
Value(param.name);
|
||||
Enum(param.type);
|
||||
Type(param.type);
|
||||
}
|
||||
|
||||
ShaderNodes::NodePtr node;
|
||||
@@ -489,6 +560,36 @@ namespace Nz
|
||||
}
|
||||
}
|
||||
|
||||
void ShaderUnserializer::Type(ShaderAst::Type& type)
|
||||
{
|
||||
UInt8 typeIndex;
|
||||
Value(typeIndex);
|
||||
|
||||
switch (typeIndex)
|
||||
{
|
||||
case 0: //< Primitive
|
||||
{
|
||||
ShaderNodes::ExpressionType exprType;
|
||||
Enum(exprType);
|
||||
|
||||
type = exprType;
|
||||
break;
|
||||
}
|
||||
|
||||
case 1: //< Struct (name)
|
||||
{
|
||||
std::string structName;
|
||||
Value(structName);
|
||||
|
||||
type = std::move(structName);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ShaderUnserializer::Value(bool& val)
|
||||
{
|
||||
m_stream >> val;
|
||||
@@ -519,6 +620,16 @@ namespace Nz
|
||||
m_stream >> val;
|
||||
}
|
||||
|
||||
void ShaderUnserializer::Value(UInt8& val)
|
||||
{
|
||||
m_stream >> val;
|
||||
}
|
||||
|
||||
void ShaderUnserializer::Value(UInt16& val)
|
||||
{
|
||||
m_stream >> val;
|
||||
}
|
||||
|
||||
void ShaderUnserializer::Value(UInt32& val)
|
||||
{
|
||||
m_stream >> val;
|
||||
|
||||
@@ -77,7 +77,7 @@ namespace Nz
|
||||
return TypeMustMatch(left->GetExpressionType(), right->GetExpressionType());
|
||||
}
|
||||
|
||||
void ShaderValidator::TypeMustMatch(ShaderNodes::ExpressionType left, ShaderNodes::ExpressionType right)
|
||||
void ShaderValidator::TypeMustMatch(const ShaderAst::Type& left, const ShaderAst::Type& right)
|
||||
{
|
||||
if (left != right)
|
||||
throw AstError{ "Left expression type must match right expression type" };
|
||||
|
||||
Reference in New Issue
Block a user