Shader: Rework scope handling

This commit is contained in:
Jérôme Leclercq
2021-04-04 20:31:09 +02:00
parent feffcfa6e5
commit f93a5bbdc1
23 changed files with 661 additions and 755 deletions

View File

@@ -32,12 +32,9 @@
#include <Nazara/Shader/Config.hpp>
#include <Nazara/Shader/GlslWriter.hpp>
#include <Nazara/Shader/Shader.hpp>
#include <Nazara/Shader/ShaderAstCache.hpp>
#include <Nazara/Shader/ShaderAstCloner.hpp>
#include <Nazara/Shader/ShaderAstExpressionType.hpp>
#include <Nazara/Shader/ShaderAstExpressionVisitor.hpp>
#include <Nazara/Shader/ShaderAstExpressionVisitorExcept.hpp>
#include <Nazara/Shader/ShaderAstNodes.hpp>
#include <Nazara/Shader/ShaderAstOptimizer.hpp>
#include <Nazara/Shader/ShaderAstRecursiveVisitor.hpp>
#include <Nazara/Shader/ShaderAstSerializer.hpp>

View File

@@ -9,7 +9,7 @@
#include <Nazara/Prerequisites.hpp>
#include <Nazara/Shader/Config.hpp>
#include <Nazara/Shader/ShaderAstRecursiveVisitor.hpp>
#include <Nazara/Shader/ShaderAstScopedVisitor.hpp>
#include <Nazara/Shader/ShaderWriter.hpp>
#include <set>
#include <sstream>
@@ -17,7 +17,7 @@
namespace Nz
{
class NAZARA_SHADER_API GlslWriter : public ShaderWriter, public ShaderAst::AstRecursiveVisitor
class NAZARA_SHADER_API GlslWriter : public ShaderWriter, public ShaderAst::AstScopedVisitor
{
public:
struct Environment;
@@ -57,8 +57,8 @@ namespace Nz
template<typename T> void Append(const T& param);
template<typename T1, typename T2, typename... Args> void Append(const T1& firstParam, const T2& secondParam, Args&&... params);
void AppendCommentSection(const std::string& section);
void AppendEntryPoint(ShaderStageType shaderStage);
void AppendField(std::size_t scopeId, const std::string& structName, const std::string* memberIdentifier, std::size_t remainingMembers);
void AppendEntryPoint(ShaderStageType shaderStage, ShaderAst::StatementPtr& shader);
void AppendField(const std::string& structName, const std::string* memberIdentifier, std::size_t remainingMembers);
void AppendLine(const std::string& txt = {});
template<typename... Args> void AppendLine(Args&&... params);

View File

@@ -1,56 +0,0 @@
// 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_SHADERASTCACHE_HPP
#define NAZARA_SHADERASTCACHE_HPP
#include <Nazara/Prerequisites.hpp>
#include <Nazara/Shader/Config.hpp>
#include <Nazara/Shader/ShaderAstExpressionType.hpp>
#include <Nazara/Utility/Enums.hpp>
namespace Nz::ShaderAst
{
struct AstCache
{
struct Identifier;
struct Alias
{
std::variant<ExpressionType> value;
};
struct Variable
{
ExpressionType type;
};
struct Identifier
{
std::string name;
std::variant<Alias, Variable, StructDescription> value;
};
struct Scope
{
std::optional<std::size_t> parentScopeIndex;
std::vector<Identifier> identifiers;
};
inline void Clear();
inline const Identifier* FindIdentifier(std::size_t startingScopeId, const std::string& identifierName) const;
inline std::size_t GetScopeId(const Node* node) const;
std::array<DeclareFunctionStatement*, ShaderStageTypeCount> entryFunctions = {};
std::unordered_map<const Expression*, ExpressionType> nodeExpressionType;
std::unordered_map<const Node*, std::size_t> scopeIdByNode;
std::vector<Scope> scopes;
};
}
#include <Nazara/Shader/ShaderAstCache.inl>
#endif

View File

@@ -1,45 +0,0 @@
// 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 <Nazara/Shader/ShaderAstCache.hpp>
#include <Nazara/Shader/Debug.hpp>
namespace Nz::ShaderAst
{
inline void AstCache::Clear()
{
entryFunctions.fill(nullptr);
nodeExpressionType.clear();
scopeIdByNode.clear();
scopes.clear();
}
inline auto AstCache::FindIdentifier(std::size_t startingScopeId, const std::string& identifierName) const -> const Identifier*
{
assert(startingScopeId < scopes.size());
std::optional<std::size_t> scopeId = startingScopeId;
do
{
const auto& scope = scopes[*scopeId];
auto it = std::find_if(scope.identifiers.rbegin(), scope.identifiers.rend(), [&](const auto& identifier) { return identifier.name == identifierName; });
if (it != scope.identifiers.rend())
return &*it;
scopeId = scope.parentScopeIndex;
} while (scopeId);
return nullptr;
}
inline std::size_t AstCache::GetScopeId(const Node* node) const
{
auto it = scopeIdByNode.find(node);
assert(it != scopeIdByNode.end());
return it->second;
}
}
#include <Nazara/Shader/DebugOff.hpp>

View File

@@ -33,7 +33,7 @@ namespace Nz::ShaderAst
ExpressionPtr CloneExpression(ExpressionPtr& expr);
StatementPtr CloneStatement(StatementPtr& statement);
virtual std::unique_ptr<DeclareFunctionStatement> Clone(DeclareFunctionStatement& node);
virtual StatementPtr Clone(DeclareFunctionStatement& node);
using AstExpressionVisitor::Visit;
using AstStatementVisitor::Visit;

View File

@@ -1,58 +0,0 @@
// 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_SHADERASTEXPRESSIONTYPE_HPP
#define NAZARA_SHADERASTEXPRESSIONTYPE_HPP
#include <Nazara/Prerequisites.hpp>
#include <Nazara/Shader/Config.hpp>
#include <Nazara/Shader/ShaderAstExpressionVisitor.hpp>
#include <Nazara/Shader/Ast/ExpressionType.hpp>
#include <vector>
namespace Nz::ShaderAst
{
struct AstCache;
class NAZARA_SHADER_API ExpressionTypeVisitor : public AstExpressionVisitor
{
public:
ExpressionTypeVisitor() = default;
ExpressionTypeVisitor(const ExpressionTypeVisitor&) = delete;
ExpressionTypeVisitor(ExpressionTypeVisitor&&) = delete;
~ExpressionTypeVisitor() = default;
ExpressionType GetExpressionType(Expression& expression, AstCache* cache);
ExpressionTypeVisitor& operator=(const ExpressionTypeVisitor&) = delete;
ExpressionTypeVisitor& operator=(ExpressionTypeVisitor&&) = delete;
private:
ExpressionType GetExpressionTypeInternal(Expression& expression);
ExpressionType ResolveAlias(Expression& expression, ExpressionType expressionType);
void Visit(Expression& expression);
void Visit(AccessMemberExpression& node) override;
void Visit(AssignExpression& node) override;
void Visit(BinaryExpression& node) override;
void Visit(CastExpression& node) override;
void Visit(ConditionalExpression& node) override;
void Visit(ConstantExpression& node) override;
void Visit(IdentifierExpression& node) override;
void Visit(IntrinsicExpression& node) override;
void Visit(SwizzleExpression& node) override;
AstCache* m_cache;
std::optional<ExpressionType> m_lastExpressionType;
};
inline ExpressionType GetExpressionType(Expression& expression, AstCache* cache = nullptr);
}
#include <Nazara/Shader/ShaderAstExpressionType.inl>
#endif

View File

@@ -1,17 +0,0 @@
// 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 <Nazara/Shader/ShaderAstExpressionType.hpp>
#include <Nazara/Shader/Debug.hpp>
namespace Nz::ShaderAst
{
inline ExpressionType GetExpressionType(Expression& expression, AstCache* cache)
{
ExpressionTypeVisitor visitor;
return visitor.GetExpressionType(expression, cache);
}
}
#include <Nazara/Shader/DebugOff.hpp>

View File

@@ -0,0 +1,68 @@
// 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_SCOPED_VISITOR_HPP
#define NAZARA_SHADER_SCOPED_VISITOR_HPP
#include <Nazara/Prerequisites.hpp>
#include <Nazara/Shader/Config.hpp>
#include <Nazara/Shader/ShaderAstRecursiveVisitor.hpp>
namespace Nz::ShaderAst
{
class NAZARA_SHADER_API AstScopedVisitor : public AstRecursiveVisitor
{
public:
struct Identifier;
AstScopedVisitor() = default;
~AstScopedVisitor() = default;
inline const Identifier* FindIdentifier(const std::string_view& identifierName) const;
void ScopedVisit(StatementPtr& nodePtr);
using AstRecursiveVisitor::Visit;
void Visit(BranchStatement& node) override;
void Visit(ConditionalStatement& node) override;
void Visit(DeclareExternalStatement& node) override;
void Visit(DeclareFunctionStatement& node) override;
void Visit(DeclareStructStatement& node) override;
void Visit(DeclareVariableStatement& node) override;
void Visit(MultiStatement& node) override;
struct Alias
{
std::variant<ExpressionType> value;
};
struct Variable
{
ExpressionType type;
};
struct Identifier
{
std::string name;
std::variant<Alias, Variable, StructDescription> value;
};
protected:
void PushScope();
void PopScope();
inline void RegisterStruct(StructDescription structDesc);
inline void RegisterVariable(std::string name, ExpressionType type);
private:
std::vector<Identifier> m_identifiersInScope;
std::vector<std::size_t> m_scopeSizes;
};
}
#include <Nazara/Shader/ShaderAstScopedVisitor.inl>
#endif

View File

@@ -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 <Nazara/Shader/ShaderAstScopedVisitor.hpp>
#include <Nazara/Shader/Debug.hpp>
namespace Nz::ShaderAst
{
inline auto AstScopedVisitor::FindIdentifier(const std::string_view& identifierName) const -> const Identifier*
{
auto it = std::find_if(m_identifiersInScope.rbegin(), m_identifiersInScope.rend(), [&](const Identifier& identifier) { return identifier.name == identifierName; });
if (it == m_identifiersInScope.rend())
return nullptr;
return &*it;
}
inline void AstScopedVisitor::RegisterStruct(StructDescription structDesc)
{
std::string name = structDesc.name;
m_identifiersInScope.push_back({
std::move(name),
std::move(structDesc)
});
}
inline void AstScopedVisitor::RegisterVariable(std::string name, ExpressionType type)
{
m_identifiersInScope.push_back({
std::move(name),
Variable { std::move(type) }
});
}
}
#include <Nazara/Shader/DebugOff.hpp>

View File

@@ -9,13 +9,12 @@
#include <Nazara/Prerequisites.hpp>
#include <Nazara/Shader/Config.hpp>
#include <Nazara/Shader/ShaderAstCache.hpp>
#include <Nazara/Shader/ShaderAstRecursiveVisitor.hpp>
#include <Nazara/Shader/ShaderAstScopedVisitor.hpp>
#include <Nazara/Utility/Enums.hpp>
namespace Nz::ShaderAst
{
class NAZARA_SHADER_API AstValidator : public AstRecursiveVisitor
class NAZARA_SHADER_API AstValidator final : public AstScopedVisitor
{
public:
inline AstValidator();
@@ -23,28 +22,24 @@ namespace Nz::ShaderAst
AstValidator(AstValidator&&) = delete;
~AstValidator() = default;
bool Validate(StatementPtr& node, std::string* error = nullptr, AstCache* cache = nullptr);
bool Validate(StatementPtr& node, std::string* error = nullptr);
private:
const ExpressionType& GetExpressionType(Expression& expression);
Expression& MandatoryExpr(ExpressionPtr& node);
Statement& MandatoryStatement(StatementPtr& node);
void TypeMustMatch(ExpressionPtr& left, ExpressionPtr& right);
void TypeMustMatch(const ExpressionType& left, const ExpressionType& right);
ExpressionType CheckField(const std::string& structName, const std::string* memberIdentifier, std::size_t remainingMembers);
AstCache::Scope& EnterScope();
void ExitScope();
void RegisterExpressionType(Expression& node, ExpressionType expressionType);
void RegisterScope(Node& node);
const ExpressionType& ResolveAlias(const ExpressionType& expressionType);
void Visit(AccessMemberExpression& node) override;
void Visit(AssignExpression& node) override;
void Visit(BinaryExpression& node) override;
void Visit(CastExpression& node) override;
void Visit(ConditionalExpression& node) override;
void Visit(ConstantExpression& node) override;
void Visit(ConditionalExpression& node) override;
void Visit(IdentifierExpression& node) override;
void Visit(IntrinsicExpression& node) override;
void Visit(SwizzleExpression& node) override;
@@ -54,17 +49,15 @@ namespace Nz::ShaderAst
void Visit(DeclareExternalStatement& node) override;
void Visit(DeclareFunctionStatement& node) override;
void Visit(DeclareStructStatement& node) override;
void Visit(DeclareVariableStatement& node) override;
void Visit(ExpressionStatement& node) override;
void Visit(MultiStatement& node) override;
void Visit(ReturnStatement& node) override;
struct Context;
Context* m_context;
};
NAZARA_SHADER_API bool ValidateAst(StatementPtr& node, std::string* error = nullptr, AstCache* cache = nullptr);
NAZARA_SHADER_API bool ValidateAst(StatementPtr& node, std::string* error = nullptr);
}
#include <Nazara/Shader/ShaderAstValidator.inl>

View File

@@ -56,6 +56,8 @@ namespace Nz::ShaderAst
Expression& operator=(const Expression&) = delete;
Expression& operator=(Expression&&) noexcept = default;
std::optional<ExpressionType> cachedExpressionType;
};
struct NAZARA_SHADER_API AccessMemberExpression : public Expression

View File

@@ -21,7 +21,7 @@ namespace Nz
class NAZARA_SHADER_API SpirvAstVisitor : public ShaderAst::ExpressionVisitorExcept, public ShaderAst::StatementVisitorExcept
{
public:
inline SpirvAstVisitor(SpirvWriter& writer, std::vector<SpirvBlock>& blocks, ShaderAst::AstCache* cache);
inline SpirvAstVisitor(SpirvWriter& writer, std::vector<SpirvBlock>& blocks);
SpirvAstVisitor(const SpirvAstVisitor&) = delete;
SpirvAstVisitor(SpirvAstVisitor&&) = delete;
~SpirvAstVisitor() = default;
@@ -53,10 +53,10 @@ namespace Nz
SpirvAstVisitor& operator=(SpirvAstVisitor&&) = delete;
private:
inline const ShaderAst::ExpressionType& GetExpressionType(ShaderAst::Expression& expr) const;
void PushResultId(UInt32 value);
UInt32 PopResultId();
ShaderAst::AstCache* m_cache;
std::vector<SpirvBlock>& m_blocks;
std::vector<UInt32> m_resultIds;
SpirvBlock* m_currentBlock;

View File

@@ -7,13 +7,18 @@
namespace Nz
{
inline SpirvAstVisitor::SpirvAstVisitor(SpirvWriter& writer, std::vector<SpirvBlock>& blocks, ShaderAst::AstCache* cache) :
m_cache(cache),
inline SpirvAstVisitor::SpirvAstVisitor(SpirvWriter& writer, std::vector<SpirvBlock>& blocks) :
m_blocks(blocks),
m_writer(writer)
{
m_currentBlock = &m_blocks.back();
}
inline const ShaderAst::ExpressionType& SpirvAstVisitor::GetExpressionType(ShaderAst::Expression& expr) const
{
assert(expr.cachedExpressionType);
return expr.cachedExpressionType.value();
}
}
#include <Nazara/Shader/DebugOff.hpp>

View File

@@ -31,11 +31,14 @@ namespace Nz
~SpirvConstantCache();
struct Constant;
struct Identifier;
struct Type;
using ConstantPtr = std::shared_ptr<Constant>;
using TypePtr = std::shared_ptr<Type>;
using IdentifierCallback = std::function<TypePtr(const std::string& identifier)>;
struct Bool {};
struct Float
@@ -63,6 +66,11 @@ namespace Nz
UInt32 columnCount;
};
struct Identifier
{
std::string name;
};
struct Image
{
std::optional<SpirvAccessQualifier> qualifier;
@@ -104,7 +112,7 @@ namespace Nz
std::vector<Member> members;
};
using AnyType = std::variant<Bool, Float, Function, Image, Integer, Matrix, Pointer, SampledImage, Structure, Vector, Void>;
using AnyType = std::variant<Bool, Float, Function, Identifier, Image, Integer, Matrix, Pointer, SampledImage, Structure, Vector, Void>;
struct ConstantBool
{
@@ -166,6 +174,8 @@ namespace Nz
UInt32 Register(Type t);
UInt32 Register(Variable v);
void SetIdentifierCallback(IdentifierCallback callback);
void Write(SpirvSection& annotations, SpirvSection& constants, SpirvSection& debugInfos);
SpirvConstantCache& operator=(const SpirvConstantCache& cache) = delete;
@@ -181,6 +191,7 @@ namespace Nz
static TypePtr BuildType(const ShaderAst::NoType& type);
static TypePtr BuildType(const ShaderAst::PrimitiveType& type);
static TypePtr BuildType(const ShaderAst::SamplerType& type);
static TypePtr BuildType(const ShaderAst::StructDescription& structDesc);
static TypePtr BuildType(const ShaderAst::VectorType& type);
private:
@@ -193,6 +204,7 @@ namespace Nz
void WriteStruct(const Structure& structData, UInt32 resultId, SpirvSection& annotations, SpirvSection& constants, SpirvSection& debugInfos);
IdentifierCallback m_identifierCallback;
std::unique_ptr<Internal> m_internal;
};
}