Renderer: Add shader serialization

This commit is contained in:
Lynix
2020-06-05 19:47:29 +02:00
parent de1c64253e
commit 8467c79021
15 changed files with 1131 additions and 443 deletions

View File

@@ -116,23 +116,18 @@ namespace Nz
m_glslVersion = version;
}
void GlslWriter::Write(const ShaderAst::NodePtr& node)
{
node->Visit(*this);
}
void GlslWriter::Write(const ShaderAst::Sample2D& node)
void GlslWriter::Visit(const ShaderAst::Sample2D& node)
{
Append("texture(");
Write(node.sampler);
Visit(node.sampler);
Append(", ");
Write(node.coordinates);
Visit(node.coordinates);
Append(")");
}
void GlslWriter::Write(const ShaderAst::AssignOp& node)
void GlslWriter::Visit(const ShaderAst::AssignOp& node)
{
Write(node.left);
Visit(node.left);
switch (node.op)
{
@@ -141,10 +136,10 @@ namespace Nz
break;
}
Write(node.right);
Visit(node.right);
}
void GlslWriter::Write(const ShaderAst::Branch& node)
void GlslWriter::Visit(const ShaderAst::Branch& node)
{
bool first = true;
for (const auto& statement : node.condStatements)
@@ -153,11 +148,11 @@ namespace Nz
Append("else ");
Append("if (");
Write(statement.condition);
Visit(statement.condition);
AppendLine(")");
EnterScope();
Write(statement.statement);
Visit(statement.statement);
LeaveScope();
first = false;
@@ -168,12 +163,12 @@ namespace Nz
AppendLine("else");
EnterScope();
Write(node.elseStatement);
Visit(node.elseStatement);
LeaveScope();
}
}
void GlslWriter::Write(const ShaderAst::BinaryFunc& node)
void GlslWriter::Visit(const ShaderAst::BinaryFunc& node)
{
switch (node.intrinsic)
{
@@ -187,15 +182,15 @@ namespace Nz
}
Append("(");
Write(node.left);
Visit(node.left);
Append(", ");
Write(node.right);
Visit(node.right);
Append(")");
}
void GlslWriter::Write(const ShaderAst::BinaryOp& node)
void GlslWriter::Visit(const ShaderAst::BinaryOp& node)
{
Write(node.left);
Visit(node.left);
switch (node.op)
{
@@ -216,15 +211,15 @@ namespace Nz
break;
}
Write(node.right);
Visit(node.right);
}
void GlslWriter::Write(const ShaderAst::BuiltinVariable& node)
void GlslWriter::Visit(const ShaderAst::BuiltinVariable& node)
{
Append(node.var);
}
void GlslWriter::Write(const ShaderAst::Cast& node)
void GlslWriter::Visit(const ShaderAst::Cast& node)
{
Append(node.exprType);
Append("(");
@@ -239,14 +234,14 @@ namespace Nz
const auto& exprPtr = node.expressions[i++];
NazaraAssert(exprPtr, "Invalid expression");
Write(exprPtr);
Visit(exprPtr);
requiredComponents -= ShaderAst::Node::GetComponentCount(exprPtr->GetExpressionType());
}
Append(")");
}
void GlslWriter::Write(const ShaderAst::Constant& node)
void GlslWriter::Visit(const ShaderAst::Constant& node)
{
switch (node.exprType)
{
@@ -275,7 +270,7 @@ namespace Nz
}
}
void GlslWriter::Write(const ShaderAst::DeclareVariable& node)
void GlslWriter::Visit(const ShaderAst::DeclareVariable& node)
{
Append(node.variable->GetExpressionType());
Append(" ");
@@ -285,24 +280,24 @@ namespace Nz
Append(" ");
Append("=");
Append(" ");
Write(node.expression);
Visit(node.expression);
}
AppendLine(";");
}
void GlslWriter::Write(const ShaderAst::ExpressionStatement& node)
void GlslWriter::Visit(const ShaderAst::ExpressionStatement& node)
{
Write(node.expression);
Visit(node.expression);
Append(";");
}
void GlslWriter::Write(const ShaderAst::NamedVariable& node)
void GlslWriter::Visit(const ShaderAst::NamedVariable& node)
{
Append(node.name);
}
void GlslWriter::Write(const ShaderAst::StatementBlock& node)
void GlslWriter::Visit(const ShaderAst::StatementBlock& node)
{
bool first = true;
for (const ShaderAst::StatementPtr& statement : node.statements)
@@ -310,15 +305,15 @@ namespace Nz
if (!first)
AppendLine();
Write(statement);
Visit(statement);
first = false;
}
}
void GlslWriter::Write(const ShaderAst::SwizzleOp& node)
void GlslWriter::Visit(const ShaderAst::SwizzleOp& node)
{
Write(node.expression);
Visit(node.expression);
Append(".");
for (std::size_t i = 0; i < node.componentCount; ++i)
@@ -433,7 +428,7 @@ namespace Nz
EnterScope();
{
Write(func.node);
Visit(func.node);
}
LeaveScope();
}

View File

@@ -69,7 +69,7 @@ namespace Nz
};
RegisterImpl("NazaraOpenGLRenderer" NazaraRendererDebugSuffix, [] { return 50; });
RegisterImpl("NazaraVulkanRenderer" NazaraRendererDebugSuffix, [] { return 100; });
//RegisterImpl("NazaraVulkanRenderer" NazaraRendererDebugSuffix, [] { return 100; });
std::sort(implementations.begin(), implementations.end(), [](const auto& lhs, const auto& rhs) { return lhs.score > rhs.score; });

View File

@@ -3,11 +3,15 @@
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Renderer/ShaderAst.hpp>
#include <Nazara/Core/ByteStream.hpp>
#include <Nazara/Renderer/ShaderSerializer.hpp>
#include <Nazara/Renderer/ShaderWriter.hpp>
#include <Nazara/Renderer/Debug.hpp>
namespace Nz::ShaderAst
{
Node::~Node() = default;
ExpressionCategory Expression::GetExpressionCategory() const
{
return ExpressionCategory::RValue;
@@ -18,9 +22,9 @@ namespace Nz::ShaderAst
expression->Register(visitor);
}
void ExpressionStatement::Visit(ShaderWriter& visitor)
void ExpressionStatement::Visit(ShaderVisitor& visitor)
{
visitor.Write(*this);
visitor.Visit(*this);
}
@@ -30,7 +34,7 @@ namespace Nz::ShaderAst
statement->Register(visitor);
}
void ConditionalStatement::Visit(ShaderWriter& visitor)
void ConditionalStatement::Visit(ShaderVisitor& visitor)
{
if (visitor.IsConditionEnabled(conditionName))
statement->Visit(visitor);
@@ -43,9 +47,9 @@ namespace Nz::ShaderAst
statementPtr->Register(visitor);
}
void StatementBlock::Visit(ShaderWriter& visitor)
void StatementBlock::Visit(ShaderVisitor& visitor)
{
visitor.Write(*this);
visitor.Visit(*this);
}
ExpressionCategory Variable::GetExpressionCategory() const
@@ -58,14 +62,25 @@ namespace Nz::ShaderAst
return type;
}
void BuiltinVariable::Register(ShaderWriter& /*visitor*/)
{
}
void BuiltinVariable::Visit(ShaderVisitor& visitor)
{
visitor.Visit(*this);
}
void NamedVariable::Register(ShaderWriter& visitor)
{
visitor.RegisterVariable(kind, name, type);
}
void NamedVariable::Visit(ShaderWriter& visitor)
void NamedVariable::Visit(ShaderVisitor& visitor)
{
visitor.Write(*this);
visitor.Visit(*this);
}
@@ -77,18 +92,9 @@ namespace Nz::ShaderAst
expression->Register(visitor);
}
void DeclareVariable::Visit(ShaderWriter& visitor)
void DeclareVariable::Visit(ShaderVisitor& visitor)
{
visitor.Write(*this);
}
void BuiltinVariable::Register(ShaderWriter& /*visitor*/)
{
}
void BuiltinVariable::Visit(ShaderWriter& visitor)
{
visitor.Write(*this);
visitor.Visit(*this);
}
@@ -103,9 +109,9 @@ namespace Nz::ShaderAst
right->Register(visitor);
}
void AssignOp::Visit(ShaderWriter& visitor)
void AssignOp::Visit(ShaderVisitor& visitor)
{
visitor.Write(*this);
visitor.Visit(*this);
}
@@ -138,9 +144,9 @@ namespace Nz::ShaderAst
right->Register(visitor);
}
void BinaryOp::Visit(ShaderWriter& visitor)
void BinaryOp::Visit(ShaderVisitor& visitor)
{
visitor.Write(*this);
visitor.Visit(*this);
}
@@ -156,9 +162,9 @@ namespace Nz::ShaderAst
elseStatement->Register(visitor);
}
void Branch::Visit(ShaderWriter& visitor)
void Branch::Visit(ShaderVisitor& visitor)
{
visitor.Write(*this);
visitor.Visit(*this);
}
@@ -171,9 +177,9 @@ namespace Nz::ShaderAst
{
}
void Constant::Visit(ShaderWriter& visitor)
void Constant::Visit(ShaderVisitor& visitor)
{
visitor.Write(*this);
visitor.Visit(*this);
}
ExpressionType Cast::GetExpressionType() const
@@ -195,26 +201,9 @@ namespace Nz::ShaderAst
}
}
void Cast::Visit(ShaderWriter& visitor)
void Cast::Visit(ShaderVisitor& visitor)
{
visitor.Write(*this);
}
void Cast::Validate() const
{
unsigned int componentCount = 0;
unsigned int requiredComponents = GetComponentCount(exprType);
for (const auto& exprPtr : expressions)
{
if (!exprPtr)
break;
componentCount += GetComponentCount(exprPtr->GetExpressionType());
}
//TODO: AstParseError
if (componentCount != requiredComponents)
throw std::runtime_error("Component count doesn't match required component count");
visitor.Visit(*this);
}
@@ -233,9 +222,9 @@ namespace Nz::ShaderAst
expression->Register(visitor);
}
void SwizzleOp::Visit(ShaderWriter& visitor)
void SwizzleOp::Visit(ShaderVisitor& visitor)
{
visitor.Write(*this);
visitor.Visit(*this);
}
@@ -250,9 +239,9 @@ namespace Nz::ShaderAst
coordinates->Register(visitor);
}
void Sample2D::Visit(ShaderWriter& visitor)
void Sample2D::Visit(ShaderVisitor& visitor)
{
visitor.Write(*this);
visitor.Visit(*this);
}
@@ -277,8 +266,8 @@ namespace Nz::ShaderAst
right->Register(visitor);
}
void BinaryFunc::Visit(ShaderWriter& visitor)
void BinaryFunc::Visit(ShaderVisitor& visitor)
{
visitor.Write(*this);
visitor.Visit(*this);
}
}

View File

@@ -0,0 +1,376 @@
// Copyright (C) 2020 Jérôme Leclercq
// This file is part of the "Nazara Engine - Renderer module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Renderer/ShaderSerializer.hpp>
#include <Nazara/Renderer/Debug.hpp>
namespace Nz::ShaderAst
{
namespace
{
class ShaderSerializerVisitor : public ShaderVisitor
{
public:
ShaderSerializerVisitor(ShaderSerializerBase& serializer) :
m_serializer(serializer)
{
}
void Visit(const AssignOp& node) override
{
Serialize(node);
}
void Visit(const BinaryFunc& node) override
{
Serialize(node);
}
void Visit(const BinaryOp& node) override
{
Serialize(node);
}
void Visit(const Branch& node) override
{
Serialize(node);
}
void Visit(const BuiltinVariable& node) override
{
Serialize(node);
}
void Visit(const Cast& node) override
{
Serialize(node);
}
void Visit(const Constant& node) override
{
Serialize(node);
}
void Visit(const DeclareVariable& node) override
{
Serialize(node);
}
void Visit(const ExpressionStatement& node) override
{
Serialize(node);
}
void Visit(const NamedVariable& node) override
{
Serialize(node);
}
void Visit(const Sample2D& node) override
{
Serialize(node);
}
void Visit(const StatementBlock& node) override
{
Serialize(node);
}
void Visit(const SwizzleOp& node) override
{
Serialize(node);
}
private:
template<typename T>
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<T&>(node));
}
ShaderSerializerBase& m_serializer;
};
}
void ShaderSerializerBase::Serialize(AssignOp& node)
{
Enum(node.op);
Node(node.left);
Node(node.right);
}
void ShaderSerializerBase::Serialize(BinaryFunc& node)
{
Enum(node.intrinsic);
Node(node.left);
Node(node.right);
}
void ShaderSerializerBase::Serialize(BinaryOp& node)
{
Enum(node.op);
Node(node.left);
Node(node.right);
}
void ShaderSerializerBase::Serialize(Branch& node)
{
Container(node.condStatements);
for (auto& condStatement : node.condStatements)
{
Node(condStatement.condition);
Node(condStatement.statement);
}
Node(node.elseStatement);
}
void ShaderSerializerBase::Serialize(BuiltinVariable& node)
{
Enum(node.var);
Enum(node.type);
}
void ShaderSerializerBase::Serialize(Cast& node)
{
Enum(node.exprType);
for (auto& expr : node.expressions)
Node(expr);
}
void ShaderSerializerBase::Serialize(Constant& node)
{
Enum(node.exprType);
switch (node.exprType)
{
case ExpressionType::Boolean:
Value(node.values.bool1);
break;
case ExpressionType::Float1:
Value(node.values.vec1);
break;
case ExpressionType::Float2:
Value(node.values.vec2);
break;
case ExpressionType::Float3:
Value(node.values.vec3);
break;
case ExpressionType::Float4:
Value(node.values.vec4);
break;
}
}
void ShaderSerializerBase::Serialize(DeclareVariable& node)
{
Node(node.variable);
Node(node.expression);
}
void ShaderSerializerBase::Serialize(ExpressionStatement& node)
{
Node(node.expression);
}
void ShaderSerializerBase::Serialize(NamedVariable& node)
{
Value(node.name);
Enum(node.kind);
Enum(node.type);
}
void ShaderSerializerBase::Serialize(Sample2D& node)
{
Node(node.sampler);
Node(node.coordinates);
}
void ShaderSerializerBase::Serialize(StatementBlock& node)
{
Container(node.statements);
for (auto& statement : node.statements)
Node(statement);
}
void ShaderSerializerBase::Serialize(SwizzleOp& node)
{
Value(node.componentCount);
Node(node.expression);
for (std::size_t i = 0; i < node.componentCount; ++i)
Enum(node.components[i]);
}
void ShaderSerializer::Serialize(const StatementPtr& shader)
{
assert(shader);
m_stream << static_cast<Int32>(shader->GetType());
ShaderSerializerVisitor visitor(*this);
shader->Visit(visitor);
m_stream.FlushBits();
}
bool ShaderSerializer::IsWriting() const
{
return true;
}
void ShaderSerializer::Node(NodePtr& node)
{
NodeType nodeType = (node) ? node->GetType() : NodeType::None;
m_stream << static_cast<Int32>(nodeType);
if (node)
{
ShaderSerializerVisitor visitor(*this);
node->Visit(visitor);
}
}
void ShaderSerializer::Value(bool& val)
{
m_stream << val;
}
void ShaderSerializer::Value(float& val)
{
m_stream << val;
}
void ShaderSerializer::Value(std::string& val)
{
m_stream << val;
}
void ShaderSerializer::Value(Vector2f& val)
{
m_stream << val;
}
void ShaderSerializer::Value(Vector3f& val)
{
m_stream << val;
}
void ShaderSerializer::Value(Vector4f& val)
{
m_stream << val;
}
void ShaderSerializer::Value(UInt32& val)
{
m_stream << val;
}
ByteArray Serialize(const StatementPtr& shader)
{
ByteArray byteArray;
ShaderSerializer serializer(byteArray);
serializer.Serialize(shader);
return byteArray;
}
StatementPtr Unserialize(const ByteArray& data)
{
ShaderUnserializer unserializer(data);
return unserializer.Unserialize();
}
StatementPtr ShaderUnserializer::Unserialize()
{
NodePtr statement;
Node(statement);
if (!statement || statement->GetType() != NodeType::StatementBlock)
throw std::runtime_error("Invalid shader");
return std::static_pointer_cast<Statement>(statement);
}
bool ShaderUnserializer::IsWriting() const
{
return false;
}
void ShaderUnserializer::Node(NodePtr& node)
{
Int32 nodeTypeInt;
m_stream >> nodeTypeInt;
NodeType nodeType = static_cast<NodeType>(nodeTypeInt);
#define HandleNodeType(Type) case NodeType:: Type : node = std::make_shared<Type>(); break
switch (nodeType)
{
case NodeType::None: break;
HandleNodeType(AssignOp);
HandleNodeType(BinaryFunc);
HandleNodeType(BinaryOp);
HandleNodeType(Branch);
HandleNodeType(BuiltinVariable);
HandleNodeType(Cast);
HandleNodeType(Constant);
HandleNodeType(ConditionalStatement);
HandleNodeType(DeclareVariable);
HandleNodeType(ExpressionStatement);
HandleNodeType(NamedVariable);
HandleNodeType(Sample2D);
HandleNodeType(SwizzleOp);
HandleNodeType(StatementBlock);
}
#undef HandleNodeType
if (node)
{
ShaderSerializerVisitor visitor(*this);
node->Visit(visitor);
}
}
void ShaderUnserializer::Value(bool& val)
{
m_stream >> val;
}
void ShaderUnserializer::Value(float& val)
{
m_stream >> val;
}
void ShaderUnserializer::Value(std::string& val)
{
m_stream >> val;
}
void ShaderUnserializer::Value(Vector2f& val)
{
m_stream >> val;
}
void ShaderUnserializer::Value(Vector3f& val)
{
m_stream >> val;
}
void ShaderUnserializer::Value(Vector4f& val)
{
m_stream >> val;
}
void ShaderUnserializer::Value(UInt32& val)
{
m_stream >> val;
}
}

View File

@@ -0,0 +1,29 @@
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Renderer module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Renderer/ShaderVisitor.hpp>
#include <Nazara/Renderer/Debug.hpp>
namespace Nz
{
ShaderVisitor::~ShaderVisitor() = default;
void ShaderVisitor::EnableCondition(const String& name, bool cond)
{
if (cond)
m_conditions.insert(name);
else
m_conditions.erase(name);
}
bool ShaderVisitor::IsConditionEnabled(const String& name) const
{
return m_conditions.count(name) != 0;
}
void ShaderVisitor::Visit(const ShaderAst::NodePtr& node)
{
node->Visit(*this);
}
}

View File

@@ -7,18 +7,4 @@
namespace Nz
{
ShaderWriter::~ShaderWriter() = default;
void ShaderWriter::EnableCondition(const String& name, bool cond)
{
if (cond)
m_conditions.insert(name);
else
m_conditions.erase(name);
}
bool ShaderWriter::IsConditionEnabled(const String & name) const
{
return m_conditions.count(name) != 0;
}
}