Shader: Add support for for-each statements and improve arrays
This commit is contained in:
parent
aac6e38da2
commit
4fe44339c5
|
|
@ -64,6 +64,7 @@ namespace Nz::ShaderAst
|
||||||
virtual StatementPtr Clone(DeclareVariableStatement& node);
|
virtual StatementPtr Clone(DeclareVariableStatement& node);
|
||||||
virtual StatementPtr Clone(DiscardStatement& node);
|
virtual StatementPtr Clone(DiscardStatement& node);
|
||||||
virtual StatementPtr Clone(ExpressionStatement& node);
|
virtual StatementPtr Clone(ExpressionStatement& node);
|
||||||
|
virtual StatementPtr Clone(ForEachStatement& node);
|
||||||
virtual StatementPtr Clone(MultiStatement& node);
|
virtual StatementPtr Clone(MultiStatement& node);
|
||||||
virtual StatementPtr Clone(NoOpStatement& node);
|
virtual StatementPtr Clone(NoOpStatement& node);
|
||||||
virtual StatementPtr Clone(ReturnStatement& node);
|
virtual StatementPtr Clone(ReturnStatement& node);
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,7 @@ namespace Nz::ShaderAst
|
||||||
inline bool Compare(const DeclareVariableStatement& lhs, const DeclareVariableStatement& rhs);
|
inline bool Compare(const DeclareVariableStatement& lhs, const DeclareVariableStatement& rhs);
|
||||||
inline bool Compare(const DiscardStatement& lhs, const DiscardStatement& rhs);
|
inline bool Compare(const DiscardStatement& lhs, const DiscardStatement& rhs);
|
||||||
inline bool Compare(const ExpressionStatement& lhs, const ExpressionStatement& rhs);
|
inline bool Compare(const ExpressionStatement& lhs, const ExpressionStatement& rhs);
|
||||||
|
inline bool Compare(const ForEachStatement& lhs, const ForEachStatement& rhs);
|
||||||
inline bool Compare(const MultiStatement& lhs, const MultiStatement& rhs);
|
inline bool Compare(const MultiStatement& lhs, const MultiStatement& rhs);
|
||||||
inline bool Compare(const NoOpStatement& lhs, const NoOpStatement& rhs);
|
inline bool Compare(const NoOpStatement& lhs, const NoOpStatement& rhs);
|
||||||
inline bool Compare(const ReturnStatement& lhs, const ReturnStatement& rhs);
|
inline bool Compare(const ReturnStatement& lhs, const ReturnStatement& rhs);
|
||||||
|
|
|
||||||
|
|
@ -458,6 +458,23 @@ namespace Nz::ShaderAst
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Compare(const ForEachStatement& lhs, const ForEachStatement& rhs)
|
||||||
|
{
|
||||||
|
if (!Compare(lhs.isConst, rhs.isConst))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!Compare(lhs.varName, rhs.varName))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!Compare(lhs.expression, rhs.expression))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!Compare(lhs.statement, rhs.statement))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
inline bool Compare(const MultiStatement& lhs, const MultiStatement& rhs)
|
inline bool Compare(const MultiStatement& lhs, const MultiStatement& rhs)
|
||||||
{
|
{
|
||||||
if (!Compare(lhs.statements, rhs.statements))
|
if (!Compare(lhs.statements, rhs.statements))
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,7 @@ NAZARA_SHADERAST_STATEMENT(DeclareOptionStatement)
|
||||||
NAZARA_SHADERAST_STATEMENT(DeclareStructStatement)
|
NAZARA_SHADERAST_STATEMENT(DeclareStructStatement)
|
||||||
NAZARA_SHADERAST_STATEMENT(DeclareVariableStatement)
|
NAZARA_SHADERAST_STATEMENT(DeclareVariableStatement)
|
||||||
NAZARA_SHADERAST_STATEMENT(DiscardStatement)
|
NAZARA_SHADERAST_STATEMENT(DiscardStatement)
|
||||||
|
NAZARA_SHADERAST_STATEMENT(ForEachStatement)
|
||||||
NAZARA_SHADERAST_STATEMENT(ExpressionStatement)
|
NAZARA_SHADERAST_STATEMENT(ExpressionStatement)
|
||||||
NAZARA_SHADERAST_STATEMENT(MultiStatement)
|
NAZARA_SHADERAST_STATEMENT(MultiStatement)
|
||||||
NAZARA_SHADERAST_STATEMENT(NoOpStatement)
|
NAZARA_SHADERAST_STATEMENT(NoOpStatement)
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,7 @@ namespace Nz::ShaderAst
|
||||||
void Visit(DeclareVariableStatement& node) override;
|
void Visit(DeclareVariableStatement& node) override;
|
||||||
void Visit(DiscardStatement& node) override;
|
void Visit(DiscardStatement& node) override;
|
||||||
void Visit(ExpressionStatement& node) override;
|
void Visit(ExpressionStatement& node) override;
|
||||||
|
void Visit(ForEachStatement& node) override;
|
||||||
void Visit(MultiStatement& node) override;
|
void Visit(MultiStatement& node) override;
|
||||||
void Visit(NoOpStatement& node) override;
|
void Visit(NoOpStatement& node) override;
|
||||||
void Visit(ReturnStatement& node) override;
|
void Visit(ReturnStatement& node) override;
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,7 @@ namespace Nz::ShaderAst
|
||||||
void Serialize(DeclareVariableStatement& node);
|
void Serialize(DeclareVariableStatement& node);
|
||||||
void Serialize(DiscardStatement& node);
|
void Serialize(DiscardStatement& node);
|
||||||
void Serialize(ExpressionStatement& node);
|
void Serialize(ExpressionStatement& node);
|
||||||
|
void Serialize(ForEachStatement& node);
|
||||||
void Serialize(MultiStatement& node);
|
void Serialize(MultiStatement& node);
|
||||||
void Serialize(NoOpStatement& node);
|
void Serialize(NoOpStatement& node);
|
||||||
void Serialize(ReturnStatement& node);
|
void Serialize(ReturnStatement& node);
|
||||||
|
|
|
||||||
|
|
@ -340,6 +340,18 @@ namespace Nz::ShaderAst
|
||||||
ExpressionPtr expression;
|
ExpressionPtr expression;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct NAZARA_SHADER_API ForEachStatement : Statement
|
||||||
|
{
|
||||||
|
NodeType GetType() const override;
|
||||||
|
void Visit(AstStatementVisitor& visitor) override;
|
||||||
|
|
||||||
|
std::optional<std::size_t> varIndex;
|
||||||
|
std::string varName;
|
||||||
|
ExpressionPtr expression;
|
||||||
|
StatementPtr statement;
|
||||||
|
bool isConst = false;
|
||||||
|
};
|
||||||
|
|
||||||
struct NAZARA_SHADER_API MultiStatement : Statement
|
struct NAZARA_SHADER_API MultiStatement : Statement
|
||||||
{
|
{
|
||||||
NodeType GetType() const override;
|
NodeType GetType() const override;
|
||||||
|
|
@ -371,7 +383,12 @@ namespace Nz::ShaderAst
|
||||||
StatementPtr body;
|
StatementPtr body;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define NAZARA_SHADERAST_NODE(X) using X##Ptr = std::unique_ptr<X>;
|
||||||
|
|
||||||
|
#include <Nazara/Shader/Ast/AstNodeList.hpp>
|
||||||
|
|
||||||
inline const ShaderAst::ExpressionType& GetExpressionType(ShaderAst::Expression& expr);
|
inline const ShaderAst::ExpressionType& GetExpressionType(ShaderAst::Expression& expr);
|
||||||
|
inline ShaderAst::ExpressionType& GetExpressionTypeMut(ShaderAst::Expression& expr);
|
||||||
inline bool IsExpression(NodeType nodeType);
|
inline bool IsExpression(NodeType nodeType);
|
||||||
inline bool IsStatement(NodeType nodeType);
|
inline bool IsStatement(NodeType nodeType);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,12 @@ namespace Nz::ShaderAst
|
||||||
return expr.cachedExpressionType.value();
|
return expr.cachedExpressionType.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ShaderAst::ExpressionType& GetExpressionTypeMut(ShaderAst::Expression& expr)
|
||||||
|
{
|
||||||
|
assert(expr.cachedExpressionType);
|
||||||
|
return expr.cachedExpressionType.value();
|
||||||
|
}
|
||||||
|
|
||||||
inline bool IsExpression(NodeType nodeType)
|
inline bool IsExpression(NodeType nodeType)
|
||||||
{
|
{
|
||||||
switch (nodeType)
|
switch (nodeType)
|
||||||
|
|
|
||||||
|
|
@ -40,8 +40,9 @@ namespace Nz::ShaderAst
|
||||||
std::unordered_set<std::string> reservedIdentifiers;
|
std::unordered_set<std::string> reservedIdentifiers;
|
||||||
std::unordered_map<std::size_t, ConstantValue> optionValues;
|
std::unordered_map<std::size_t, ConstantValue> optionValues;
|
||||||
bool makeVariableNameUnique = false;
|
bool makeVariableNameUnique = false;
|
||||||
|
bool reduceLoopsToWhile = false;
|
||||||
bool removeCompoundAssignments = false;
|
bool removeCompoundAssignments = false;
|
||||||
bool removeOptionDeclaration = true;
|
bool removeOptionDeclaration = false;
|
||||||
bool removeScalarSwizzling = false;
|
bool removeScalarSwizzling = false;
|
||||||
bool splitMultipleBranches = false;
|
bool splitMultipleBranches = false;
|
||||||
};
|
};
|
||||||
|
|
@ -77,6 +78,7 @@ namespace Nz::ShaderAst
|
||||||
StatementPtr Clone(DeclareVariableStatement& node) override;
|
StatementPtr Clone(DeclareVariableStatement& node) override;
|
||||||
StatementPtr Clone(DiscardStatement& node) override;
|
StatementPtr Clone(DiscardStatement& node) override;
|
||||||
StatementPtr Clone(ExpressionStatement& node) override;
|
StatementPtr Clone(ExpressionStatement& node) override;
|
||||||
|
StatementPtr Clone(ForEachStatement& node) override;
|
||||||
StatementPtr Clone(MultiStatement& node) override;
|
StatementPtr Clone(MultiStatement& node) override;
|
||||||
StatementPtr Clone(WhileStatement& node) override;
|
StatementPtr Clone(WhileStatement& node) override;
|
||||||
|
|
||||||
|
|
@ -117,6 +119,8 @@ namespace Nz::ShaderAst
|
||||||
void SanitizeIdentifier(std::string& identifier);
|
void SanitizeIdentifier(std::string& identifier);
|
||||||
|
|
||||||
void Validate(AccessIndexExpression& node);
|
void Validate(AccessIndexExpression& node);
|
||||||
|
void Validate(AssignExpression& node);
|
||||||
|
void Validate(BinaryExpression& node);
|
||||||
void Validate(CallFunctionExpression& node, const DeclareFunctionStatement* referenceDeclaration);
|
void Validate(CallFunctionExpression& node, const DeclareFunctionStatement* referenceDeclaration);
|
||||||
void Validate(CastExpression& node);
|
void Validate(CastExpression& node);
|
||||||
void Validate(DeclareVariableStatement& node);
|
void Validate(DeclareVariableStatement& node);
|
||||||
|
|
|
||||||
|
|
@ -71,6 +71,7 @@ namespace Nz
|
||||||
void AppendLine(const std::string& txt = {});
|
void AppendLine(const std::string& txt = {});
|
||||||
template<typename... Args> void AppendLine(Args&&... params);
|
template<typename... Args> void AppendLine(Args&&... params);
|
||||||
void AppendStatementList(std::vector<ShaderAst::StatementPtr>& statements);
|
void AppendStatementList(std::vector<ShaderAst::StatementPtr>& statements);
|
||||||
|
void AppendVariableDeclaration(const ShaderAst::ExpressionType& varType, const std::string& varName);
|
||||||
|
|
||||||
void EnterScope();
|
void EnterScope();
|
||||||
void LeaveScope(bool skipLine = true);
|
void LeaveScope(bool skipLine = true);
|
||||||
|
|
|
||||||
|
|
@ -99,6 +99,7 @@ namespace Nz
|
||||||
|
|
||||||
void Visit(ShaderAst::BranchStatement& node) override;
|
void Visit(ShaderAst::BranchStatement& node) override;
|
||||||
void Visit(ShaderAst::ConditionalStatement& node) override;
|
void Visit(ShaderAst::ConditionalStatement& node) override;
|
||||||
|
void Visit(ShaderAst::DeclareConstStatement& node) override;
|
||||||
void Visit(ShaderAst::DeclareExternalStatement& node) override;
|
void Visit(ShaderAst::DeclareExternalStatement& node) override;
|
||||||
void Visit(ShaderAst::DeclareFunctionStatement& node) override;
|
void Visit(ShaderAst::DeclareFunctionStatement& node) override;
|
||||||
void Visit(ShaderAst::DeclareOptionStatement& node) override;
|
void Visit(ShaderAst::DeclareOptionStatement& node) override;
|
||||||
|
|
@ -106,6 +107,7 @@ namespace Nz
|
||||||
void Visit(ShaderAst::DeclareVariableStatement& node) override;
|
void Visit(ShaderAst::DeclareVariableStatement& node) override;
|
||||||
void Visit(ShaderAst::DiscardStatement& node) override;
|
void Visit(ShaderAst::DiscardStatement& node) override;
|
||||||
void Visit(ShaderAst::ExpressionStatement& node) override;
|
void Visit(ShaderAst::ExpressionStatement& node) override;
|
||||||
|
void Visit(ShaderAst::ForEachStatement& node) override;
|
||||||
void Visit(ShaderAst::MultiStatement& node) override;
|
void Visit(ShaderAst::MultiStatement& node) override;
|
||||||
void Visit(ShaderAst::NoOpStatement& node) override;
|
void Visit(ShaderAst::NoOpStatement& node) override;
|
||||||
void Visit(ShaderAst::ReturnStatement& node) override;
|
void Visit(ShaderAst::ReturnStatement& node) override;
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,9 @@ namespace Nz::ShaderBuilder
|
||||||
{
|
{
|
||||||
struct AccessIndex
|
struct AccessIndex
|
||||||
{
|
{
|
||||||
|
inline std::unique_ptr<ShaderAst::AccessIndexExpression> operator()(ShaderAst::ExpressionPtr expr, Int32 index) const;
|
||||||
inline std::unique_ptr<ShaderAst::AccessIndexExpression> operator()(ShaderAst::ExpressionPtr expr, const std::vector<Int32>& indexConstants) const;
|
inline std::unique_ptr<ShaderAst::AccessIndexExpression> operator()(ShaderAst::ExpressionPtr expr, const std::vector<Int32>& indexConstants) const;
|
||||||
|
inline std::unique_ptr<ShaderAst::AccessIndexExpression> operator()(ShaderAst::ExpressionPtr expr, ShaderAst::ExpressionPtr indexExpression) const;
|
||||||
inline std::unique_ptr<ShaderAst::AccessIndexExpression> operator()(ShaderAst::ExpressionPtr expr, std::vector<ShaderAst::ExpressionPtr> indexExpressions) const;
|
inline std::unique_ptr<ShaderAst::AccessIndexExpression> operator()(ShaderAst::ExpressionPtr expr, std::vector<ShaderAst::ExpressionPtr> indexExpressions) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -106,6 +108,12 @@ namespace Nz::ShaderBuilder
|
||||||
inline std::unique_ptr<ShaderAst::ExpressionStatement> operator()(ShaderAst::ExpressionPtr expression) const;
|
inline std::unique_ptr<ShaderAst::ExpressionStatement> operator()(ShaderAst::ExpressionPtr expression) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<bool Const>
|
||||||
|
struct ForEach
|
||||||
|
{
|
||||||
|
inline std::unique_ptr<ShaderAst::ForEachStatement> operator()(std::string varName, ShaderAst::ExpressionPtr expression, ShaderAst::StatementPtr statement) const;
|
||||||
|
};
|
||||||
|
|
||||||
struct Identifier
|
struct Identifier
|
||||||
{
|
{
|
||||||
inline std::unique_ptr<ShaderAst::IdentifierExpression> operator()(std::string name) const;
|
inline std::unique_ptr<ShaderAst::IdentifierExpression> operator()(std::string name) const;
|
||||||
|
|
@ -143,11 +151,16 @@ namespace Nz::ShaderBuilder
|
||||||
inline std::unique_ptr<ShaderAst::UnaryExpression> operator()(ShaderAst::UnaryType op, ShaderAst::ExpressionPtr expression) const;
|
inline std::unique_ptr<ShaderAst::UnaryExpression> operator()(ShaderAst::UnaryType op, ShaderAst::ExpressionPtr expression) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Variable
|
||||||
|
{
|
||||||
|
inline std::unique_ptr<ShaderAst::VariableExpression> operator()(std::size_t variableId, ShaderAst::ExpressionType expressionType) const;
|
||||||
|
};
|
||||||
|
|
||||||
struct While
|
struct While
|
||||||
{
|
{
|
||||||
inline std::unique_ptr<ShaderAst::WhileStatement> operator()(ShaderAst::ExpressionPtr condition, ShaderAst::StatementPtr body) const;
|
inline std::unique_ptr<ShaderAst::WhileStatement> operator()(ShaderAst::ExpressionPtr condition, ShaderAst::StatementPtr body) const;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr Impl::AccessIndex AccessIndex;
|
constexpr Impl::AccessIndex AccessIndex;
|
||||||
constexpr Impl::AccessMember AccessMember;
|
constexpr Impl::AccessMember AccessMember;
|
||||||
|
|
@ -160,6 +173,7 @@ namespace Nz::ShaderBuilder
|
||||||
constexpr Impl::ConditionalStatement ConditionalStatement;
|
constexpr Impl::ConditionalStatement ConditionalStatement;
|
||||||
constexpr Impl::Constant Constant;
|
constexpr Impl::Constant Constant;
|
||||||
constexpr Impl::Branch<true> ConstBranch;
|
constexpr Impl::Branch<true> ConstBranch;
|
||||||
|
constexpr Impl::ForEach<false> ConstForEach;
|
||||||
constexpr Impl::DeclareConst DeclareConst;
|
constexpr Impl::DeclareConst DeclareConst;
|
||||||
constexpr Impl::DeclareFunction DeclareFunction;
|
constexpr Impl::DeclareFunction DeclareFunction;
|
||||||
constexpr Impl::DeclareOption DeclareOption;
|
constexpr Impl::DeclareOption DeclareOption;
|
||||||
|
|
@ -167,6 +181,7 @@ namespace Nz::ShaderBuilder
|
||||||
constexpr Impl::DeclareVariable DeclareVariable;
|
constexpr Impl::DeclareVariable DeclareVariable;
|
||||||
constexpr Impl::ExpressionStatement ExpressionStatement;
|
constexpr Impl::ExpressionStatement ExpressionStatement;
|
||||||
constexpr Impl::NoParam<ShaderAst::DiscardStatement> Discard;
|
constexpr Impl::NoParam<ShaderAst::DiscardStatement> Discard;
|
||||||
|
constexpr Impl::ForEach<false> ForEach;
|
||||||
constexpr Impl::Identifier Identifier;
|
constexpr Impl::Identifier Identifier;
|
||||||
constexpr Impl::Intrinsic Intrinsic;
|
constexpr Impl::Intrinsic Intrinsic;
|
||||||
constexpr Impl::Multi MultiStatement;
|
constexpr Impl::Multi MultiStatement;
|
||||||
|
|
@ -174,6 +189,7 @@ namespace Nz::ShaderBuilder
|
||||||
constexpr Impl::Return Return;
|
constexpr Impl::Return Return;
|
||||||
constexpr Impl::Swizzle Swizzle;
|
constexpr Impl::Swizzle Swizzle;
|
||||||
constexpr Impl::Unary Unary;
|
constexpr Impl::Unary Unary;
|
||||||
|
constexpr Impl::Variable Variable;
|
||||||
constexpr Impl::While While;
|
constexpr Impl::While While;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,15 @@ namespace Nz::ShaderBuilder
|
||||||
return accessMemberNode;
|
return accessMemberNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline std::unique_ptr<ShaderAst::AccessIndexExpression> Impl::AccessIndex::operator()(ShaderAst::ExpressionPtr expr, Int32 index) const
|
||||||
|
{
|
||||||
|
auto accessMemberNode = std::make_unique<ShaderAst::AccessIndexExpression>();
|
||||||
|
accessMemberNode->expr = std::move(expr);
|
||||||
|
accessMemberNode->indices.push_back(ShaderBuilder::Constant(index));
|
||||||
|
|
||||||
|
return accessMemberNode;
|
||||||
|
}
|
||||||
|
|
||||||
inline std::unique_ptr<ShaderAst::AccessIndexExpression> Impl::AccessIndex::operator()(ShaderAst::ExpressionPtr expr, const std::vector<Int32>& indexConstants) const
|
inline std::unique_ptr<ShaderAst::AccessIndexExpression> Impl::AccessIndex::operator()(ShaderAst::ExpressionPtr expr, const std::vector<Int32>& indexConstants) const
|
||||||
{
|
{
|
||||||
auto accessMemberNode = std::make_unique<ShaderAst::AccessIndexExpression>();
|
auto accessMemberNode = std::make_unique<ShaderAst::AccessIndexExpression>();
|
||||||
|
|
@ -28,6 +37,15 @@ namespace Nz::ShaderBuilder
|
||||||
return accessMemberNode;
|
return accessMemberNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline std::unique_ptr<ShaderAst::AccessIndexExpression> Impl::AccessIndex::operator()(ShaderAst::ExpressionPtr expr, ShaderAst::ExpressionPtr indexExpression) const
|
||||||
|
{
|
||||||
|
auto accessMemberNode = std::make_unique<ShaderAst::AccessIndexExpression>();
|
||||||
|
accessMemberNode->expr = std::move(expr);
|
||||||
|
accessMemberNode->indices.push_back(std::move(indexExpression));
|
||||||
|
|
||||||
|
return accessMemberNode;
|
||||||
|
}
|
||||||
|
|
||||||
inline std::unique_ptr<ShaderAst::AccessIndexExpression> Impl::AccessIndex::operator()(ShaderAst::ExpressionPtr expr, std::vector<ShaderAst::ExpressionPtr> indexExpressions) const
|
inline std::unique_ptr<ShaderAst::AccessIndexExpression> Impl::AccessIndex::operator()(ShaderAst::ExpressionPtr expr, std::vector<ShaderAst::ExpressionPtr> indexExpressions) const
|
||||||
{
|
{
|
||||||
auto accessMemberNode = std::make_unique<ShaderAst::AccessIndexExpression>();
|
auto accessMemberNode = std::make_unique<ShaderAst::AccessIndexExpression>();
|
||||||
|
|
@ -136,6 +154,7 @@ namespace Nz::ShaderBuilder
|
||||||
{
|
{
|
||||||
auto constantNode = std::make_unique<ShaderAst::ConstantValueExpression>();
|
auto constantNode = std::make_unique<ShaderAst::ConstantValueExpression>();
|
||||||
constantNode->value = std::move(value);
|
constantNode->value = std::move(value);
|
||||||
|
constantNode->cachedExpressionType = ShaderAst::GetExpressionType(constantNode->value);
|
||||||
|
|
||||||
return constantNode;
|
return constantNode;
|
||||||
}
|
}
|
||||||
|
|
@ -250,6 +269,18 @@ namespace Nz::ShaderBuilder
|
||||||
return expressionStatementNode;
|
return expressionStatementNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<bool Const>
|
||||||
|
std::unique_ptr<ShaderAst::ForEachStatement> Impl::ForEach<Const>::operator()(std::string varName, ShaderAst::ExpressionPtr expression, ShaderAst::StatementPtr statement) const
|
||||||
|
{
|
||||||
|
auto forEachNode = std::make_unique<ShaderAst::ForEachStatement>();
|
||||||
|
forEachNode->isConst = Const;
|
||||||
|
forEachNode->expression = std::move(expression);
|
||||||
|
forEachNode->statement = std::move(statement);
|
||||||
|
forEachNode->varName = std::move(varName);
|
||||||
|
|
||||||
|
return forEachNode;
|
||||||
|
}
|
||||||
|
|
||||||
inline std::unique_ptr<ShaderAst::IdentifierExpression> Impl::Identifier::operator()(std::string name) const
|
inline std::unique_ptr<ShaderAst::IdentifierExpression> Impl::Identifier::operator()(std::string name) const
|
||||||
{
|
{
|
||||||
auto identifierNode = std::make_unique<ShaderAst::IdentifierExpression>();
|
auto identifierNode = std::make_unique<ShaderAst::IdentifierExpression>();
|
||||||
|
|
@ -327,6 +358,15 @@ namespace Nz::ShaderBuilder
|
||||||
return unaryNode;
|
return unaryNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline std::unique_ptr<ShaderAst::VariableExpression> Impl::Variable::operator()(std::size_t variableId, ShaderAst::ExpressionType expressionType) const
|
||||||
|
{
|
||||||
|
auto varNode = std::make_unique<ShaderAst::VariableExpression>();
|
||||||
|
varNode->variableId = variableId;
|
||||||
|
varNode->cachedExpressionType = std::move(expressionType);
|
||||||
|
|
||||||
|
return varNode;
|
||||||
|
}
|
||||||
|
|
||||||
inline std::unique_ptr<ShaderAst::WhileStatement> Impl::While::operator()(ShaderAst::ExpressionPtr condition, ShaderAst::StatementPtr body) const
|
inline std::unique_ptr<ShaderAst::WhileStatement> Impl::While::operator()(ShaderAst::ExpressionPtr condition, ShaderAst::StatementPtr body) const
|
||||||
{
|
{
|
||||||
auto whileNode = std::make_unique<ShaderAst::WhileStatement>();
|
auto whileNode = std::make_unique<ShaderAst::WhileStatement>();
|
||||||
|
|
|
||||||
|
|
@ -88,6 +88,7 @@ namespace Nz::ShaderLang
|
||||||
ShaderAst::StatementPtr ParseConstStatement();
|
ShaderAst::StatementPtr ParseConstStatement();
|
||||||
ShaderAst::StatementPtr ParseDiscardStatement();
|
ShaderAst::StatementPtr ParseDiscardStatement();
|
||||||
ShaderAst::StatementPtr ParseExternalBlock(std::vector<ShaderAst::Attribute> attributes = {});
|
ShaderAst::StatementPtr ParseExternalBlock(std::vector<ShaderAst::Attribute> attributes = {});
|
||||||
|
ShaderAst::StatementPtr ParseForDeclaration();
|
||||||
std::vector<ShaderAst::StatementPtr> ParseFunctionBody();
|
std::vector<ShaderAst::StatementPtr> ParseFunctionBody();
|
||||||
ShaderAst::StatementPtr ParseFunctionDeclaration(std::vector<ShaderAst::Attribute> attributes = {});
|
ShaderAst::StatementPtr ParseFunctionDeclaration(std::vector<ShaderAst::Attribute> attributes = {});
|
||||||
ShaderAst::DeclareFunctionStatement::Parameter ParseFunctionParameter();
|
ShaderAst::DeclareFunctionStatement::Parameter ParseFunctionParameter();
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@ NAZARA_SHADERLANG_TOKEN(Else)
|
||||||
NAZARA_SHADERLANG_TOKEN(EndOfStream)
|
NAZARA_SHADERLANG_TOKEN(EndOfStream)
|
||||||
NAZARA_SHADERLANG_TOKEN(External)
|
NAZARA_SHADERLANG_TOKEN(External)
|
||||||
NAZARA_SHADERLANG_TOKEN(FloatingPointValue)
|
NAZARA_SHADERLANG_TOKEN(FloatingPointValue)
|
||||||
|
NAZARA_SHADERLANG_TOKEN(For)
|
||||||
NAZARA_SHADERLANG_TOKEN(FunctionDeclaration)
|
NAZARA_SHADERLANG_TOKEN(FunctionDeclaration)
|
||||||
NAZARA_SHADERLANG_TOKEN(FunctionReturn)
|
NAZARA_SHADERLANG_TOKEN(FunctionReturn)
|
||||||
NAZARA_SHADERLANG_TOKEN(GreaterThan)
|
NAZARA_SHADERLANG_TOKEN(GreaterThan)
|
||||||
|
|
@ -38,6 +39,7 @@ NAZARA_SHADERLANG_TOKEN(GreaterThanEqual)
|
||||||
NAZARA_SHADERLANG_TOKEN(IntegerValue)
|
NAZARA_SHADERLANG_TOKEN(IntegerValue)
|
||||||
NAZARA_SHADERLANG_TOKEN(Identifier)
|
NAZARA_SHADERLANG_TOKEN(Identifier)
|
||||||
NAZARA_SHADERLANG_TOKEN(If)
|
NAZARA_SHADERLANG_TOKEN(If)
|
||||||
|
NAZARA_SHADERLANG_TOKEN(In)
|
||||||
NAZARA_SHADERLANG_TOKEN(LessThan)
|
NAZARA_SHADERLANG_TOKEN(LessThan)
|
||||||
NAZARA_SHADERLANG_TOKEN(LessThanEqual)
|
NAZARA_SHADERLANG_TOKEN(LessThanEqual)
|
||||||
NAZARA_SHADERLANG_TOKEN(Let)
|
NAZARA_SHADERLANG_TOKEN(Let)
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,8 @@ namespace Nz
|
||||||
struct Array
|
struct Array
|
||||||
{
|
{
|
||||||
TypePtr elementType;
|
TypePtr elementType;
|
||||||
UInt32 length;
|
ConstantPtr length;
|
||||||
|
std::optional<UInt32> stride;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Bool {};
|
struct Bool {};
|
||||||
|
|
@ -129,7 +130,7 @@ namespace Nz
|
||||||
|
|
||||||
struct ConstantScalar
|
struct ConstantScalar
|
||||||
{
|
{
|
||||||
std::variant<float, double, Nz::Int32, Nz::Int64, Nz::UInt32, Nz::UInt64> value;
|
std::variant<float, double, Int32, Int64, UInt32, UInt64> value;
|
||||||
};
|
};
|
||||||
|
|
||||||
using AnyConstant = std::variant<ConstantBool, ConstantComposite, ConstantScalar>;
|
using AnyConstant = std::variant<ConstantBool, ConstantComposite, ConstantScalar>;
|
||||||
|
|
@ -174,6 +175,7 @@ namespace Nz
|
||||||
TypePtr BuildPointerType(const ShaderAst::PrimitiveType& type, SpirvStorageClass storageClass) const;
|
TypePtr BuildPointerType(const ShaderAst::PrimitiveType& type, SpirvStorageClass storageClass) const;
|
||||||
TypePtr BuildPointerType(const ShaderAst::ExpressionType& type, SpirvStorageClass storageClass) const;
|
TypePtr BuildPointerType(const ShaderAst::ExpressionType& type, SpirvStorageClass storageClass) const;
|
||||||
TypePtr BuildPointerType(const TypePtr& type, SpirvStorageClass storageClass) const;
|
TypePtr BuildPointerType(const TypePtr& type, SpirvStorageClass storageClass) const;
|
||||||
|
TypePtr BuildType(const ShaderAst::ArrayType& type) const;
|
||||||
TypePtr BuildType(const ShaderAst::ExpressionType& type) const;
|
TypePtr BuildType(const ShaderAst::ExpressionType& type) const;
|
||||||
TypePtr BuildType(const ShaderAst::IdentifierType& type) const;
|
TypePtr BuildType(const ShaderAst::IdentifierType& type) const;
|
||||||
TypePtr BuildType(const ShaderAst::MatrixType& type) const;
|
TypePtr BuildType(const ShaderAst::MatrixType& type) const;
|
||||||
|
|
|
||||||
|
|
@ -170,6 +170,16 @@ namespace Nz::ShaderAst
|
||||||
return clone;
|
return clone;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StatementPtr AstCloner::Clone(ForEachStatement& node)
|
||||||
|
{
|
||||||
|
auto clone = std::make_unique<ForEachStatement>();
|
||||||
|
clone->isConst = node.isConst;
|
||||||
|
clone->expression = CloneExpression(node.expression);
|
||||||
|
clone->statement = CloneStatement(node.statement);
|
||||||
|
|
||||||
|
return clone;
|
||||||
|
}
|
||||||
|
|
||||||
StatementPtr AstCloner::Clone(MultiStatement& node)
|
StatementPtr AstCloner::Clone(MultiStatement& node)
|
||||||
{
|
{
|
||||||
auto clone = std::make_unique<MultiStatement>();
|
auto clone = std::make_unique<MultiStatement>();
|
||||||
|
|
|
||||||
|
|
@ -85,7 +85,8 @@ namespace Nz::ShaderAst
|
||||||
|
|
||||||
void AstRecursiveVisitor::Visit(SwizzleExpression& node)
|
void AstRecursiveVisitor::Visit(SwizzleExpression& node)
|
||||||
{
|
{
|
||||||
node.expression->Visit(*this);
|
if (node.expression)
|
||||||
|
node.expression->Visit(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AstRecursiveVisitor::Visit(VariableExpression& /*node*/)
|
void AstRecursiveVisitor::Visit(VariableExpression& /*node*/)
|
||||||
|
|
@ -95,7 +96,8 @@ namespace Nz::ShaderAst
|
||||||
|
|
||||||
void AstRecursiveVisitor::Visit(UnaryExpression& node)
|
void AstRecursiveVisitor::Visit(UnaryExpression& node)
|
||||||
{
|
{
|
||||||
node.expression->Visit(*this);
|
if (node.expression)
|
||||||
|
node.expression->Visit(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AstRecursiveVisitor::Visit(BranchStatement& node)
|
void AstRecursiveVisitor::Visit(BranchStatement& node)
|
||||||
|
|
@ -159,6 +161,15 @@ namespace Nz::ShaderAst
|
||||||
node.expression->Visit(*this);
|
node.expression->Visit(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AstRecursiveVisitor::Visit(ForEachStatement& node)
|
||||||
|
{
|
||||||
|
if (node.expression)
|
||||||
|
node.expression->Visit(*this);
|
||||||
|
|
||||||
|
if (node.statement)
|
||||||
|
node.statement->Visit(*this);
|
||||||
|
}
|
||||||
|
|
||||||
void AstRecursiveVisitor::Visit(MultiStatement& node)
|
void AstRecursiveVisitor::Visit(MultiStatement& node)
|
||||||
{
|
{
|
||||||
for (auto& statement : node.statements)
|
for (auto& statement : node.statements)
|
||||||
|
|
|
||||||
|
|
@ -301,6 +301,14 @@ namespace Nz::ShaderAst
|
||||||
Node(node.expression);
|
Node(node.expression);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AstSerializerBase::Serialize(ForEachStatement& node)
|
||||||
|
{
|
||||||
|
Value(node.isConst);
|
||||||
|
Value(node.varName);
|
||||||
|
Node(node.expression);
|
||||||
|
Node(node.statement);
|
||||||
|
}
|
||||||
|
|
||||||
void AstSerializerBase::Serialize(MultiStatement& node)
|
void AstSerializerBase::Serialize(MultiStatement& node)
|
||||||
{
|
{
|
||||||
Container(node.statements);
|
Container(node.statements);
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ namespace Nz::ShaderAst
|
||||||
{
|
{
|
||||||
assert(array.containedType);
|
assert(array.containedType);
|
||||||
containedType = std::make_unique<ContainedType>(*array.containedType);
|
containedType = std::make_unique<ContainedType>(*array.containedType);
|
||||||
length = Clone(length);
|
length = Clone(array.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
ArrayType& ArrayType::operator=(const ArrayType& array)
|
ArrayType& ArrayType::operator=(const ArrayType& array)
|
||||||
|
|
@ -21,7 +21,7 @@ namespace Nz::ShaderAst
|
||||||
assert(array.containedType);
|
assert(array.containedType);
|
||||||
|
|
||||||
containedType = std::make_unique<ContainedType>(*array.containedType);
|
containedType = std::make_unique<ContainedType>(*array.containedType);
|
||||||
length = Clone(length);
|
length = Clone(array.length);
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -278,39 +278,7 @@ namespace Nz::ShaderAst
|
||||||
MandatoryExpr(node.right);
|
MandatoryExpr(node.right);
|
||||||
|
|
||||||
auto clone = static_unique_pointer_cast<AssignExpression>(AstCloner::Clone(node));
|
auto clone = static_unique_pointer_cast<AssignExpression>(AstCloner::Clone(node));
|
||||||
|
Validate(*clone);
|
||||||
if (GetExpressionCategory(*clone->left) != ExpressionCategory::LValue)
|
|
||||||
throw AstError{ "Assignation is only possible with a l-value" };
|
|
||||||
|
|
||||||
std::optional<BinaryType> binaryType;
|
|
||||||
switch (clone->op)
|
|
||||||
{
|
|
||||||
case AssignType::Simple:
|
|
||||||
TypeMustMatch(clone->left, clone->right);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case AssignType::CompoundAdd: binaryType = BinaryType::Add; break;
|
|
||||||
case AssignType::CompoundDivide: binaryType = BinaryType::Divide; break;
|
|
||||||
case AssignType::CompoundMultiply: binaryType = BinaryType::Multiply; break;
|
|
||||||
case AssignType::CompoundLogicalAnd: binaryType = BinaryType::LogicalAnd; break;
|
|
||||||
case AssignType::CompoundLogicalOr: binaryType = BinaryType::LogicalOr; break;
|
|
||||||
case AssignType::CompoundSubtract: binaryType = BinaryType::Subtract; break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (binaryType)
|
|
||||||
{
|
|
||||||
ExpressionType expressionType = ValidateBinaryOp(*binaryType, clone->left, clone->right);
|
|
||||||
TypeMustMatch(GetExpressionType(*clone->left), expressionType);
|
|
||||||
|
|
||||||
if (m_context->options.removeCompoundAssignments)
|
|
||||||
{
|
|
||||||
clone->op = AssignType::Simple;
|
|
||||||
clone->right = ShaderBuilder::Binary(*binaryType, AstCloner::Clone(*clone->left), std::move(clone->right));
|
|
||||||
clone->right->cachedExpressionType = std::move(expressionType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
clone->cachedExpressionType = GetExpressionType(*clone->left);
|
|
||||||
|
|
||||||
return clone;
|
return clone;
|
||||||
}
|
}
|
||||||
|
|
@ -318,7 +286,7 @@ namespace Nz::ShaderAst
|
||||||
ExpressionPtr SanitizeVisitor::Clone(BinaryExpression& node)
|
ExpressionPtr SanitizeVisitor::Clone(BinaryExpression& node)
|
||||||
{
|
{
|
||||||
auto clone = static_unique_pointer_cast<BinaryExpression>(AstCloner::Clone(node));
|
auto clone = static_unique_pointer_cast<BinaryExpression>(AstCloner::Clone(node));
|
||||||
clone->cachedExpressionType = ValidateBinaryOp(clone->op, clone->left, clone->right);
|
Validate(*clone);
|
||||||
|
|
||||||
return clone;
|
return clone;
|
||||||
}
|
}
|
||||||
|
|
@ -861,6 +829,119 @@ namespace Nz::ShaderAst
|
||||||
return AstCloner::Clone(node);
|
return AstCloner::Clone(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StatementPtr SanitizeVisitor::Clone(ForEachStatement& node)
|
||||||
|
{
|
||||||
|
auto expr = CloneExpression(node.expression);
|
||||||
|
|
||||||
|
const ExpressionType& exprType = GetExpressionType(*expr);
|
||||||
|
ExpressionType innerType;
|
||||||
|
if (IsArrayType(exprType))
|
||||||
|
{
|
||||||
|
const ArrayType& arrayType = std::get<ArrayType>(exprType);
|
||||||
|
innerType = arrayType.containedType->type;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
throw AstError{ "for-each is only supported on arrays and range expressions" };
|
||||||
|
|
||||||
|
if (node.isConst)
|
||||||
|
{
|
||||||
|
// Repeat code
|
||||||
|
auto multi = std::make_unique<MultiStatement>();
|
||||||
|
if (IsArrayType(exprType))
|
||||||
|
{
|
||||||
|
const ArrayType& arrayType = std::get<ArrayType>(exprType);
|
||||||
|
UInt32 length = arrayType.length.GetResultingValue();
|
||||||
|
|
||||||
|
for (UInt32 i = 0; i < length; ++i)
|
||||||
|
{
|
||||||
|
auto accessIndex = ShaderBuilder::AccessIndex(CloneExpression(expr), ShaderBuilder::Constant(i));
|
||||||
|
Validate(*accessIndex);
|
||||||
|
|
||||||
|
auto elementVariable = ShaderBuilder::DeclareVariable(node.varName, std::move(accessIndex));
|
||||||
|
Validate(*elementVariable);
|
||||||
|
|
||||||
|
multi->statements.emplace_back(std::move(elementVariable));
|
||||||
|
multi->statements.emplace_back(CloneStatement(node.statement));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return multi;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_context->options.reduceLoopsToWhile)
|
||||||
|
{
|
||||||
|
PushScope();
|
||||||
|
|
||||||
|
auto multi = std::make_unique<MultiStatement>();
|
||||||
|
|
||||||
|
if (IsArrayType(exprType))
|
||||||
|
{
|
||||||
|
const ArrayType& arrayType = std::get<ArrayType>(exprType);
|
||||||
|
UInt32 length = arrayType.length.GetResultingValue();
|
||||||
|
|
||||||
|
multi->statements.reserve(2);
|
||||||
|
|
||||||
|
// Counter variable
|
||||||
|
auto counterVariable = ShaderBuilder::DeclareVariable("i", ShaderBuilder::Constant(0u));
|
||||||
|
Validate(*counterVariable);
|
||||||
|
|
||||||
|
std::size_t counterVarIndex = counterVariable->varIndex.value();
|
||||||
|
|
||||||
|
multi->statements.emplace_back(std::move(counterVariable));
|
||||||
|
|
||||||
|
auto whileStatement = std::make_unique<WhileStatement>();
|
||||||
|
|
||||||
|
// While condition
|
||||||
|
auto condition = ShaderBuilder::Binary(BinaryType::CompLt, ShaderBuilder::Variable(counterVarIndex, PrimitiveType::UInt32), ShaderBuilder::Constant(length));
|
||||||
|
Validate(*condition);
|
||||||
|
whileStatement->condition = std::move(condition);
|
||||||
|
|
||||||
|
// While body
|
||||||
|
auto body = std::make_unique<MultiStatement>();
|
||||||
|
body->statements.reserve(3);
|
||||||
|
|
||||||
|
auto accessIndex = ShaderBuilder::AccessIndex(std::move(expr), ShaderBuilder::Variable(counterVarIndex, PrimitiveType::UInt32));
|
||||||
|
Validate(*accessIndex);
|
||||||
|
|
||||||
|
auto elementVariable = ShaderBuilder::DeclareVariable(node.varName, std::move(accessIndex));
|
||||||
|
Validate(*elementVariable);
|
||||||
|
body->statements.emplace_back(std::move(elementVariable));
|
||||||
|
|
||||||
|
body->statements.emplace_back(CloneStatement(node.statement));
|
||||||
|
|
||||||
|
auto incrCounter = ShaderBuilder::Assign(AssignType::CompoundAdd, ShaderBuilder::Variable(counterVarIndex, PrimitiveType::UInt32), ShaderBuilder::Constant(1u));
|
||||||
|
Validate(*incrCounter);
|
||||||
|
|
||||||
|
body->statements.emplace_back(ShaderBuilder::ExpressionStatement(std::move(incrCounter)));
|
||||||
|
|
||||||
|
whileStatement->body = std::move(body);
|
||||||
|
|
||||||
|
multi->statements.emplace_back(std::move(whileStatement));
|
||||||
|
}
|
||||||
|
|
||||||
|
PopScope();
|
||||||
|
|
||||||
|
return multi;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto clone = std::make_unique<ForEachStatement>();
|
||||||
|
clone->expression = std::move(expr);
|
||||||
|
clone->varName = node.varName;
|
||||||
|
|
||||||
|
PushScope();
|
||||||
|
{
|
||||||
|
clone->varIndex = RegisterVariable(node.varName, innerType);
|
||||||
|
clone->statement = CloneStatement(node.statement);
|
||||||
|
}
|
||||||
|
PopScope();
|
||||||
|
|
||||||
|
SanitizeIdentifier(node.varName);
|
||||||
|
|
||||||
|
return clone;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
StatementPtr SanitizeVisitor::Clone(MultiStatement& node)
|
StatementPtr SanitizeVisitor::Clone(MultiStatement& node)
|
||||||
{
|
{
|
||||||
PushScope();
|
PushScope();
|
||||||
|
|
@ -1206,7 +1287,6 @@ namespace Nz::ShaderAst
|
||||||
using T = std::decay_t<decltype(arg)>;
|
using T = std::decay_t<decltype(arg)>;
|
||||||
|
|
||||||
if constexpr (std::is_same_v<T, NoType> ||
|
if constexpr (std::is_same_v<T, NoType> ||
|
||||||
std::is_same_v<T, ArrayType> ||
|
|
||||||
std::is_same_v<T, PrimitiveType> ||
|
std::is_same_v<T, PrimitiveType> ||
|
||||||
std::is_same_v<T, MatrixType> ||
|
std::is_same_v<T, MatrixType> ||
|
||||||
std::is_same_v<T, SamplerType> ||
|
std::is_same_v<T, SamplerType> ||
|
||||||
|
|
@ -1215,6 +1295,22 @@ namespace Nz::ShaderAst
|
||||||
{
|
{
|
||||||
return exprType;
|
return exprType;
|
||||||
}
|
}
|
||||||
|
else if constexpr (std::is_same_v<T, ArrayType>)
|
||||||
|
{
|
||||||
|
ArrayType resolvedArrayType;
|
||||||
|
if (arg.length.IsExpression())
|
||||||
|
{
|
||||||
|
resolvedArrayType.length = CloneExpression(arg.length.GetExpression());
|
||||||
|
ComputeAttributeValue(resolvedArrayType.length);
|
||||||
|
}
|
||||||
|
else if (arg.length.IsResultingValue())
|
||||||
|
resolvedArrayType.length = arg.length.GetResultingValue();
|
||||||
|
|
||||||
|
resolvedArrayType.containedType = std::make_unique<ContainedType>();
|
||||||
|
resolvedArrayType.containedType->type = ResolveType(arg.containedType->type);
|
||||||
|
|
||||||
|
return resolvedArrayType;
|
||||||
|
}
|
||||||
else if constexpr (std::is_same_v<T, IdentifierType>)
|
else if constexpr (std::is_same_v<T, IdentifierType>)
|
||||||
{
|
{
|
||||||
const Identifier* identifier = FindIdentifier(arg.name);
|
const Identifier* identifier = FindIdentifier(arg.name);
|
||||||
|
|
@ -1262,8 +1358,12 @@ namespace Nz::ShaderAst
|
||||||
for (auto& index : node.indices)
|
for (auto& index : node.indices)
|
||||||
{
|
{
|
||||||
const ShaderAst::ExpressionType& indexType = GetExpressionType(*index);
|
const ShaderAst::ExpressionType& indexType = GetExpressionType(*index);
|
||||||
if (!IsPrimitiveType(indexType) || std::get<PrimitiveType>(indexType) != PrimitiveType::Int32)
|
if (!IsPrimitiveType(indexType))
|
||||||
throw AstError{ "AccessIndex expects Int32 indices" };
|
throw AstError{ "AccessIndex expects integer indices" };
|
||||||
|
|
||||||
|
PrimitiveType primitiveIndexType = std::get<PrimitiveType>(indexType);
|
||||||
|
if (primitiveIndexType != PrimitiveType::Int32 && primitiveIndexType != PrimitiveType::UInt32)
|
||||||
|
throw AstError{ "AccessIndex expects integer indices" };
|
||||||
}
|
}
|
||||||
|
|
||||||
ExpressionType exprType = GetExpressionType(*node.expr);
|
ExpressionType exprType = GetExpressionType(*node.expr);
|
||||||
|
|
@ -1272,8 +1372,8 @@ namespace Nz::ShaderAst
|
||||||
if (IsArrayType(exprType))
|
if (IsArrayType(exprType))
|
||||||
{
|
{
|
||||||
const ArrayType& arrayType = std::get<ArrayType>(exprType);
|
const ArrayType& arrayType = std::get<ArrayType>(exprType);
|
||||||
|
ExpressionType containedType = arrayType.containedType->type; //< Don't overwrite exprType directly since it contains arrayType
|
||||||
exprType = arrayType.containedType->type;
|
exprType = std::move(containedType);
|
||||||
}
|
}
|
||||||
else if (IsStructType(exprType))
|
else if (IsStructType(exprType))
|
||||||
{
|
{
|
||||||
|
|
@ -1294,7 +1394,7 @@ namespace Nz::ShaderAst
|
||||||
else if (IsMatrixType(exprType))
|
else if (IsMatrixType(exprType))
|
||||||
{
|
{
|
||||||
// Matrix index (ex: mat[2])
|
// Matrix index (ex: mat[2])
|
||||||
const MatrixType& matrixType = std::get<MatrixType>(exprType);
|
MatrixType matrixType = std::get<MatrixType>(exprType);
|
||||||
|
|
||||||
//TODO: Handle row-major matrices
|
//TODO: Handle row-major matrices
|
||||||
exprType = VectorType{ matrixType.rowCount, matrixType.type };
|
exprType = VectorType{ matrixType.rowCount, matrixType.type };
|
||||||
|
|
@ -1302,7 +1402,7 @@ namespace Nz::ShaderAst
|
||||||
else if (IsVectorType(exprType))
|
else if (IsVectorType(exprType))
|
||||||
{
|
{
|
||||||
// Swizzle expression with one component (ex: vec[2])
|
// Swizzle expression with one component (ex: vec[2])
|
||||||
const VectorType& swizzledVec = std::get<VectorType>(exprType);
|
VectorType swizzledVec = std::get<VectorType>(exprType);
|
||||||
|
|
||||||
exprType = swizzledVec.type;
|
exprType = swizzledVec.type;
|
||||||
}
|
}
|
||||||
|
|
@ -1313,6 +1413,47 @@ namespace Nz::ShaderAst
|
||||||
node.cachedExpressionType = std::move(exprType);
|
node.cachedExpressionType = std::move(exprType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SanitizeVisitor::Validate(AssignExpression& node)
|
||||||
|
{
|
||||||
|
if (GetExpressionCategory(*node.left) != ExpressionCategory::LValue)
|
||||||
|
throw AstError{ "Assignation is only possible with a l-value" };
|
||||||
|
|
||||||
|
std::optional<BinaryType> binaryType;
|
||||||
|
switch (node.op)
|
||||||
|
{
|
||||||
|
case AssignType::Simple:
|
||||||
|
TypeMustMatch(node.left, node.right);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AssignType::CompoundAdd: binaryType = BinaryType::Add; break;
|
||||||
|
case AssignType::CompoundDivide: binaryType = BinaryType::Divide; break;
|
||||||
|
case AssignType::CompoundMultiply: binaryType = BinaryType::Multiply; break;
|
||||||
|
case AssignType::CompoundLogicalAnd: binaryType = BinaryType::LogicalAnd; break;
|
||||||
|
case AssignType::CompoundLogicalOr: binaryType = BinaryType::LogicalOr; break;
|
||||||
|
case AssignType::CompoundSubtract: binaryType = BinaryType::Subtract; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (binaryType)
|
||||||
|
{
|
||||||
|
ExpressionType expressionType = ValidateBinaryOp(*binaryType, node.left, node.right);
|
||||||
|
TypeMustMatch(GetExpressionType(*node.left), expressionType);
|
||||||
|
|
||||||
|
if (m_context->options.removeCompoundAssignments)
|
||||||
|
{
|
||||||
|
node.op = AssignType::Simple;
|
||||||
|
node.right = ShaderBuilder::Binary(*binaryType, AstCloner::Clone(*node.left), std::move(node.right));
|
||||||
|
node.right->cachedExpressionType = std::move(expressionType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
node.cachedExpressionType = GetExpressionType(*node.left);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SanitizeVisitor::Validate(BinaryExpression& node)
|
||||||
|
{
|
||||||
|
node.cachedExpressionType = ValidateBinaryOp(node.op, node.left, node.right);
|
||||||
|
}
|
||||||
|
|
||||||
void SanitizeVisitor::Validate(CallFunctionExpression& node, const DeclareFunctionStatement* referenceDeclaration)
|
void SanitizeVisitor::Validate(CallFunctionExpression& node, const DeclareFunctionStatement* referenceDeclaration)
|
||||||
{
|
{
|
||||||
if (referenceDeclaration->entryStage.HasValue())
|
if (referenceDeclaration->entryStage.HasValue())
|
||||||
|
|
|
||||||
|
|
@ -207,28 +207,23 @@ namespace Nz
|
||||||
ShaderAst::SanitizeVisitor::Options options;
|
ShaderAst::SanitizeVisitor::Options options;
|
||||||
options.optionValues = std::move(optionValues);
|
options.optionValues = std::move(optionValues);
|
||||||
options.makeVariableNameUnique = true;
|
options.makeVariableNameUnique = true;
|
||||||
|
options.reduceLoopsToWhile = true;
|
||||||
options.removeCompoundAssignments = false;
|
options.removeCompoundAssignments = false;
|
||||||
|
options.removeOptionDeclaration = true;
|
||||||
options.removeScalarSwizzling = true;
|
options.removeScalarSwizzling = true;
|
||||||
options.reservedIdentifiers = {
|
options.reservedIdentifiers = {
|
||||||
// All reserved GLSL keywords as of GLSL ES 3.2
|
// All reserved GLSL keywords as of GLSL ES 3.2
|
||||||
"active", "asm", "atomic_uint", "attribute", "bool", "break", "buffer", "bvec2", "bvec3", "bvec4", "case", "cast", "centroid", "class", "coherent", "common", "const", "continue", "default", "discard", "dmat2", "dmat2x2", "dmat2x3", "dmat2x4", "dmat3", "dmat3x2", "dmat3x3", "dmat3x4", "dmat4", "dmat4x2", "dmat4x3", "dmat4x4", "do", "double", "dvec2", "dvec3", "dvec4", "else", "enum", "extern", "external", "false", "filter", "fixed", "flat", "float", "for", "fvec2", "fvec3", "fvec4", "goto", "half", "highp", "hvec2", "hvec3", "hvec4", "if", "iimage1D", "iimage1DArray", "iimage2D", "iimage2DArray", "iimage2DMS", "iimage2DMSArray", "iimage2DRect", "iimage3D", "iimageBuffer", "iimageCube", "iimageCubeArray", "image1D", "image1DArray", "image2D", "image2DArray", "image2DMS", "image2DMSArray", "image2DRect", "image3D", "imageBuffer", "imageCube", "imageCubeArray", "in", "inline", "inout", "input", "int", "interface", "invariant", "isampler1D", "isampler1DArray", "isampler2D", "isampler2DArray", "isampler2DMS", "isampler2DMSArray", "isampler2DRect", "isampler3D", "isamplerBuffer", "isamplerCube", "isamplerCubeArray", "isubpassInput", "isubpassInputMS", "itexture2D", "itexture2DArray", "itexture2DMS", "itexture2DMSArray", "itexture3D", "itextureBuffer", "itextureCube", "itextureCubeArray", "ivec2", "ivec3", "ivec4", "layout", "long", "lowp", "mat2", "mat2x2", "mat2x3", "mat2x4", "mat3", "mat3x2", "mat3x3", "mat3x4", "mat4", "mat4x2", "mat4x3", "mat4x4", "mediump", "namespace", "noinline", "noperspective", "out", "output", "partition", "patch", "precise", "precision", "public", "readonly", "resource", "restrict", "return", "sample", "sampler", "sampler1D", "sampler1DArray", "sampler1DArrayShadow", "sampler1DShadow", "sampler2D", "sampler2DArray", "sampler2DArrayShadow", "sampler2DMS", "sampler2DMSArray", "sampler2DRect", "sampler2DRectShadow", "sampler2DShadow", "sampler3D", "sampler3DRect", "samplerBuffer", "samplerCube", "samplerCubeArray", "samplerCubeArrayShadow", "samplerCubeShadow", "samplerShadow", "shared", "short", "sizeof", "smooth", "static", "struct", "subpassInput", "subpassInputMS", "subroutine", "superp", "switch", "template", "texture2D", "texture2DArray", "texture2DMS", "texture2DMSArray", "texture3D", "textureBuffer", "textureCube", "textureCubeArray", "this", "true", "typedef", "uimage1D", "uimage1DArray", "uimage2D", "uimage2DArray", "uimage2DMS", "uimage2DMSArray", "uimage2DRect", "uimage3D", "uimageBuffer", "uimageCube", "uimageCubeArray", "uint", "uniform", "union", "unsigned", "usampler1D", "usampler1DArray", "usampler2D", "usampler2DArray", "usampler2DMS", "usampler2DMSArray", "usampler2DRect", "usampler3D", "usamplerBuffer", "usamplerCube", "usamplerCubeArray", "using", "usubpassInput", "usubpassInputMS", "utexture2D", "utexture2DArray", "utexture2DMS", "utexture2DMSArray", "utexture3D", "utextureBuffer", "utextureCube", "utextureCubeArray", "uvec2", "uvec3", "uvec4", "varying", "vec2", "vec3", "vec4", "void", "volatile", "while", "writeonly"
|
"active", "asm", "atomic_uint", "attribute", "bool", "break", "buffer", "bvec2", "bvec3", "bvec4", "case", "cast", "centroid", "class", "coherent", "common", "const", "continue", "default", "discard", "dmat2", "dmat2x2", "dmat2x3", "dmat2x4", "dmat3", "dmat3x2", "dmat3x3", "dmat3x4", "dmat4", "dmat4x2", "dmat4x3", "dmat4x4", "do", "double", "dvec2", "dvec3", "dvec4", "else", "enum", "extern", "external", "false", "filter", "fixed", "flat", "float", "for", "fvec2", "fvec3", "fvec4", "goto", "half", "highp", "hvec2", "hvec3", "hvec4", "if", "iimage1D", "iimage1DArray", "iimage2D", "iimage2DArray", "iimage2DMS", "iimage2DMSArray", "iimage2DRect", "iimage3D", "iimageBuffer", "iimageCube", "iimageCubeArray", "image1D", "image1DArray", "image2D", "image2DArray", "image2DMS", "image2DMSArray", "image2DRect", "image3D", "imageBuffer", "imageCube", "imageCubeArray", "in", "inline", "inout", "input", "int", "interface", "invariant", "isampler1D", "isampler1DArray", "isampler2D", "isampler2DArray", "isampler2DMS", "isampler2DMSArray", "isampler2DRect", "isampler3D", "isamplerBuffer", "isamplerCube", "isamplerCubeArray", "isubpassInput", "isubpassInputMS", "itexture2D", "itexture2DArray", "itexture2DMS", "itexture2DMSArray", "itexture3D", "itextureBuffer", "itextureCube", "itextureCubeArray", "ivec2", "ivec3", "ivec4", "layout", "long", "lowp", "mat2", "mat2x2", "mat2x3", "mat2x4", "mat3", "mat3x2", "mat3x3", "mat3x4", "mat4", "mat4x2", "mat4x3", "mat4x4", "mediump", "namespace", "noinline", "noperspective", "out", "output", "partition", "patch", "precise", "precision", "public", "readonly", "resource", "restrict", "return", "sample", "sampler", "sampler1D", "sampler1DArray", "sampler1DArrayShadow", "sampler1DShadow", "sampler2D", "sampler2DArray", "sampler2DArrayShadow", "sampler2DMS", "sampler2DMSArray", "sampler2DRect", "sampler2DRectShadow", "sampler2DShadow", "sampler3D", "sampler3DRect", "samplerBuffer", "samplerCube", "samplerCubeArray", "samplerCubeArrayShadow", "samplerCubeShadow", "samplerShadow", "shared", "short", "sizeof", "smooth", "static", "struct", "subpassInput", "subpassInputMS", "subroutine", "superp", "switch", "template", "texture2D", "texture2DArray", "texture2DMS", "texture2DMSArray", "texture3D", "textureBuffer", "textureCube", "textureCubeArray", "this", "true", "typedef", "uimage1D", "uimage1DArray", "uimage2D", "uimage2DArray", "uimage2DMS", "uimage2DMSArray", "uimage2DRect", "uimage3D", "uimageBuffer", "uimageCube", "uimageCubeArray", "uint", "uniform", "union", "unsigned", "usampler1D", "usampler1DArray", "usampler2D", "usampler2DArray", "usampler2DMS", "usampler2DMSArray", "usampler2DRect", "usampler3D", "usamplerBuffer", "usamplerCube", "usamplerCubeArray", "using", "usubpassInput", "usubpassInputMS", "utexture2D", "utexture2DArray", "utexture2DMS", "utexture2DMSArray", "utexture3D", "utextureBuffer", "utextureCube", "utextureCubeArray", "uvec2", "uvec3", "uvec4", "varying", "vec2", "vec3", "vec4", "void", "volatile", "while", "writeonly"
|
||||||
// GLSL functions
|
// GLSL functions
|
||||||
"cross", "dot", "length", "max", "min", "pow", "texture"
|
"cross", "dot", "exp", "length", "max", "min", "pow", "texture"
|
||||||
};
|
};
|
||||||
|
|
||||||
return ShaderAst::Sanitize(ast, options, error);
|
return ShaderAst::Sanitize(ast, options, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GlslWriter::Append(const ShaderAst::ArrayType& type)
|
void GlslWriter::Append(const ShaderAst::ArrayType& /*type*/)
|
||||||
{
|
{
|
||||||
Append(type.containedType->type, "[");
|
throw std::runtime_error("unexpected ArrayType");
|
||||||
|
|
||||||
if (type.length.IsResultingValue())
|
|
||||||
Append(type.length.GetResultingValue());
|
|
||||||
else
|
|
||||||
type.length.GetExpression()->Visit(*this);
|
|
||||||
|
|
||||||
Append("]");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GlslWriter::Append(const ShaderAst::ExpressionType& type)
|
void GlslWriter::Append(const ShaderAst::ExpressionType& type)
|
||||||
|
|
@ -390,7 +385,7 @@ namespace Nz
|
||||||
|
|
||||||
first = false;
|
first = false;
|
||||||
|
|
||||||
Append(parameter.type, " ", parameter.name);
|
AppendVariableDeclaration(parameter.type, parameter.name);
|
||||||
}
|
}
|
||||||
AppendLine((forward) ? ");" : ")");
|
AppendLine((forward) ? ");" : ")");
|
||||||
}
|
}
|
||||||
|
|
@ -538,6 +533,40 @@ namespace Nz
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GlslWriter::AppendVariableDeclaration(const ShaderAst::ExpressionType& varType, const std::string& varName)
|
||||||
|
{
|
||||||
|
if (ShaderAst::IsArrayType(varType))
|
||||||
|
{
|
||||||
|
std::vector<const ShaderAst::AttributeValue<UInt32>*> lengths;
|
||||||
|
|
||||||
|
const ShaderAst::ExpressionType* exprType = &varType;
|
||||||
|
while (ShaderAst::IsArrayType(*exprType))
|
||||||
|
{
|
||||||
|
const auto& arrayType = std::get<ShaderAst::ArrayType>(*exprType);
|
||||||
|
lengths.push_back(&arrayType.length);
|
||||||
|
|
||||||
|
exprType = &arrayType.containedType->type;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(!ShaderAst::IsArrayType(*exprType));
|
||||||
|
Append(*exprType, " ", varName);
|
||||||
|
|
||||||
|
for (const auto* lengthAttribute : lengths)
|
||||||
|
{
|
||||||
|
Append("[");
|
||||||
|
|
||||||
|
if (lengthAttribute->IsResultingValue())
|
||||||
|
Append(lengthAttribute->GetResultingValue());
|
||||||
|
else
|
||||||
|
lengthAttribute->GetExpression()->Visit(*this);
|
||||||
|
|
||||||
|
Append("]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Append(varType, " ", varName);
|
||||||
|
}
|
||||||
|
|
||||||
void GlslWriter::EnterScope()
|
void GlslWriter::EnterScope()
|
||||||
{
|
{
|
||||||
NazaraAssert(m_currentState, "This function should only be called while processing an AST");
|
NazaraAssert(m_currentState, "This function should only be called while processing an AST");
|
||||||
|
|
@ -632,13 +661,8 @@ namespace Nz
|
||||||
{
|
{
|
||||||
Append("layout(location = ");
|
Append("layout(location = ");
|
||||||
Append(member.locationIndex.GetResultingValue());
|
Append(member.locationIndex.GetResultingValue());
|
||||||
Append(") ");
|
Append(") ", keyword, " ");
|
||||||
Append(keyword);
|
AppendVariableDeclaration(member.type, targetPrefix + member.name);
|
||||||
Append(" ");
|
|
||||||
Append(member.type);
|
|
||||||
Append(" ");
|
|
||||||
Append(targetPrefix);
|
|
||||||
Append(member.name);
|
|
||||||
AppendLine(";");
|
AppendLine(";");
|
||||||
|
|
||||||
fields.push_back({
|
fields.push_back({
|
||||||
|
|
@ -824,8 +848,10 @@ namespace Nz
|
||||||
throw std::runtime_error("invalid type (value expected)");
|
throw std::runtime_error("invalid type (value expected)");
|
||||||
else if constexpr (std::is_same_v<T, bool>)
|
else if constexpr (std::is_same_v<T, bool>)
|
||||||
Append((arg) ? "true" : "false");
|
Append((arg) ? "true" : "false");
|
||||||
else if constexpr (std::is_same_v<T, float> || std::is_same_v<T, Int32> || std::is_same_v<T, UInt32>)
|
else if constexpr (std::is_same_v<T, float> || std::is_same_v<T, Int32>)
|
||||||
Append(std::to_string(arg));
|
Append(std::to_string(arg));
|
||||||
|
else if constexpr (std::is_same_v<T, UInt32>)
|
||||||
|
Append(std::to_string(arg), "u");
|
||||||
else if constexpr (std::is_same_v<T, Vector2f> || std::is_same_v<T, Vector2i32>)
|
else if constexpr (std::is_same_v<T, Vector2f> || std::is_same_v<T, Vector2i32>)
|
||||||
Append("vec2(" + std::to_string(arg.x) + ", " + std::to_string(arg.y) + ")");
|
Append("vec2(" + std::to_string(arg.x) + ", " + std::to_string(arg.y) + ")");
|
||||||
else if constexpr (std::is_same_v<T, Vector3f> || std::is_same_v<T, Vector3i32>)
|
else if constexpr (std::is_same_v<T, Vector3f> || std::is_same_v<T, Vector3i32>)
|
||||||
|
|
@ -1033,19 +1059,18 @@ namespace Nz
|
||||||
|
|
||||||
first = false;
|
first = false;
|
||||||
|
|
||||||
Append(member.type);
|
AppendVariableDeclaration(member.type, member.name);
|
||||||
Append(" ");
|
|
||||||
Append(member.name);
|
|
||||||
Append(";");
|
Append(";");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LeaveScope(false);
|
LeaveScope(false);
|
||||||
|
|
||||||
|
Append(" ");
|
||||||
|
Append(externalVar.name);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
Append(externalVar.type);
|
AppendVariableDeclaration(externalVar.type, externalVar.name);
|
||||||
|
|
||||||
Append(" ");
|
|
||||||
Append(externalVar.name);
|
|
||||||
AppendLine(";");
|
AppendLine(";");
|
||||||
|
|
||||||
if (IsUniformType(externalVar.type))
|
if (IsUniformType(externalVar.type))
|
||||||
|
|
@ -1127,9 +1152,7 @@ namespace Nz
|
||||||
|
|
||||||
first = false;
|
first = false;
|
||||||
|
|
||||||
Append(member.type);
|
AppendVariableDeclaration(member.type, member.name);
|
||||||
Append(" ");
|
|
||||||
Append(member.name);
|
|
||||||
Append(";");
|
Append(";");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1142,7 +1165,7 @@ namespace Nz
|
||||||
assert(node.varIndex);
|
assert(node.varIndex);
|
||||||
RegisterVariable(*node.varIndex, node.varName);
|
RegisterVariable(*node.varIndex, node.varName);
|
||||||
|
|
||||||
Append(node.varType, " ", node.varName);
|
AppendVariableDeclaration(node.varType, node.varName);
|
||||||
if (node.initialExpression)
|
if (node.initialExpression)
|
||||||
{
|
{
|
||||||
Append(" = ");
|
Append(" = ");
|
||||||
|
|
|
||||||
|
|
@ -170,7 +170,7 @@ namespace Nz
|
||||||
case ShaderAst::PrimitiveType::Boolean: return Append("bool");
|
case ShaderAst::PrimitiveType::Boolean: return Append("bool");
|
||||||
case ShaderAst::PrimitiveType::Float32: return Append("f32");
|
case ShaderAst::PrimitiveType::Float32: return Append("f32");
|
||||||
case ShaderAst::PrimitiveType::Int32: return Append("i32");
|
case ShaderAst::PrimitiveType::Int32: return Append("i32");
|
||||||
case ShaderAst::PrimitiveType::UInt32: return Append("ui32");
|
case ShaderAst::PrimitiveType::UInt32: return Append("u32");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -185,7 +185,7 @@ namespace Nz
|
||||||
case ImageType::E2D: Append("2D"); break;
|
case ImageType::E2D: Append("2D"); break;
|
||||||
case ImageType::E2D_Array: Append("2DArray"); break;
|
case ImageType::E2D_Array: Append("2DArray"); break;
|
||||||
case ImageType::E3D: Append("3D"); break;
|
case ImageType::E3D: Append("3D"); break;
|
||||||
case ImageType::Cubemap: Append("Cube"); break;
|
case ImageType::Cubemap: Append("Cube"); break;
|
||||||
}
|
}
|
||||||
|
|
||||||
Append("<", samplerType.sampledType, ">");
|
Append("<", samplerType.sampledType, ">");
|
||||||
|
|
@ -653,6 +653,21 @@ namespace Nz
|
||||||
node.statement->Visit(*this);
|
node.statement->Visit(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LangWriter::Visit(ShaderAst::DeclareConstStatement& node)
|
||||||
|
{
|
||||||
|
assert(node.constIndex);
|
||||||
|
RegisterConstant(*node.constIndex, node.name);
|
||||||
|
|
||||||
|
Append("const ", node.name, ": ", node.type);
|
||||||
|
if (node.expression)
|
||||||
|
{
|
||||||
|
Append(" = ");
|
||||||
|
node.expression->Visit(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
Append(";");
|
||||||
|
}
|
||||||
|
|
||||||
void LangWriter::Visit(ShaderAst::ConstantValueExpression& node)
|
void LangWriter::Visit(ShaderAst::ConstantValueExpression& node)
|
||||||
{
|
{
|
||||||
std::visit([&](auto&& arg)
|
std::visit([&](auto&& arg)
|
||||||
|
|
@ -811,6 +826,20 @@ namespace Nz
|
||||||
Append(";");
|
Append(";");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LangWriter::Visit(ShaderAst::ForEachStatement& node)
|
||||||
|
{
|
||||||
|
assert(node.varIndex);
|
||||||
|
RegisterVariable(*node.varIndex, node.varName);
|
||||||
|
|
||||||
|
Append("for ", node.varName, " in ");
|
||||||
|
node.expression->Visit(*this);
|
||||||
|
AppendLine();
|
||||||
|
|
||||||
|
EnterScope();
|
||||||
|
node.statement->Visit(*this);
|
||||||
|
LeaveScope();
|
||||||
|
}
|
||||||
|
|
||||||
void LangWriter::Visit(ShaderAst::IntrinsicExpression& node)
|
void LangWriter::Visit(ShaderAst::IntrinsicExpression& node)
|
||||||
{
|
{
|
||||||
bool method = false;
|
bool method = false;
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,9 @@ namespace Nz::ShaderLang
|
||||||
{ "external", TokenType::External },
|
{ "external", TokenType::External },
|
||||||
{ "false", TokenType::BoolFalse },
|
{ "false", TokenType::BoolFalse },
|
||||||
{ "fn", TokenType::FunctionDeclaration },
|
{ "fn", TokenType::FunctionDeclaration },
|
||||||
|
{ "for", TokenType::For },
|
||||||
{ "if", TokenType::If },
|
{ "if", TokenType::If },
|
||||||
|
{ "in", TokenType::In },
|
||||||
{ "let", TokenType::Let },
|
{ "let", TokenType::Let },
|
||||||
{ "option", TokenType::Option },
|
{ "option", TokenType::Option },
|
||||||
{ "return", TokenType::Return },
|
{ "return", TokenType::Return },
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||||
|
|
||||||
#include <Nazara/Shader/ShaderLangParser.hpp>
|
#include <Nazara/Shader/ShaderLangParser.hpp>
|
||||||
|
#include <Nazara/Core/Algorithm.hpp>
|
||||||
#include <Nazara/Core/File.hpp>
|
#include <Nazara/Core/File.hpp>
|
||||||
#include <Nazara/Shader/ShaderBuilder.hpp>
|
#include <Nazara/Shader/ShaderBuilder.hpp>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
@ -472,6 +473,14 @@ namespace Nz::ShaderLang
|
||||||
|
|
||||||
switch (Peek().type)
|
switch (Peek().type)
|
||||||
{
|
{
|
||||||
|
case TokenType::For:
|
||||||
|
{
|
||||||
|
auto forEach = ParseForDeclaration();
|
||||||
|
SafeCast<ShaderAst::ForEachStatement&>(*forEach).isConst = true;
|
||||||
|
|
||||||
|
return forEach;
|
||||||
|
}
|
||||||
|
|
||||||
case TokenType::Identifier:
|
case TokenType::Identifier:
|
||||||
{
|
{
|
||||||
std::string constName;
|
std::string constName;
|
||||||
|
|
@ -487,7 +496,7 @@ namespace Nz::ShaderLang
|
||||||
case TokenType::If:
|
case TokenType::If:
|
||||||
{
|
{
|
||||||
auto branch = ParseBranchStatement();
|
auto branch = ParseBranchStatement();
|
||||||
static_cast<ShaderAst::BranchStatement&>(*branch).isConst = true;
|
SafeCast<ShaderAst::BranchStatement&>(*branch).isConst = true;
|
||||||
|
|
||||||
return branch;
|
return branch;
|
||||||
}
|
}
|
||||||
|
|
@ -589,6 +598,21 @@ namespace Nz::ShaderLang
|
||||||
return externalStatement;
|
return externalStatement;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ShaderAst::StatementPtr Parser::ParseForDeclaration()
|
||||||
|
{
|
||||||
|
Expect(Advance(), TokenType::For);
|
||||||
|
|
||||||
|
std::string varName = ParseIdentifierAsName();
|
||||||
|
|
||||||
|
Expect(Advance(), TokenType::In);
|
||||||
|
|
||||||
|
ShaderAst::ExpressionPtr expr = ParseExpression();
|
||||||
|
|
||||||
|
ShaderAst::StatementPtr statement = ParseStatement();
|
||||||
|
|
||||||
|
return ShaderBuilder::ForEach(std::move(varName), std::move(expr), std::move(statement));
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<ShaderAst::StatementPtr> Parser::ParseFunctionBody()
|
std::vector<ShaderAst::StatementPtr> Parser::ParseFunctionBody()
|
||||||
{
|
{
|
||||||
return ParseStatementList();
|
return ParseStatementList();
|
||||||
|
|
@ -734,6 +758,10 @@ namespace Nz::ShaderLang
|
||||||
statement = ParseDiscardStatement();
|
statement = ParseDiscardStatement();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case TokenType::For:
|
||||||
|
statement = ParseForDeclaration();
|
||||||
|
break;
|
||||||
|
|
||||||
case TokenType::Let:
|
case TokenType::Let:
|
||||||
statement = ParseVariableDeclaration();
|
statement = ParseVariableDeclaration();
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ namespace Nz
|
||||||
|
|
||||||
bool Compare(const Array& lhs, const Array& rhs) const
|
bool Compare(const Array& lhs, const Array& rhs) const
|
||||||
{
|
{
|
||||||
return lhs.length == rhs.length && Compare(lhs.elementType, rhs.elementType);
|
return Compare(lhs.length, rhs.length) && Compare(lhs.elementType, rhs.elementType) && lhs.stride == rhs.stride;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Compare(const Bool& /*lhs*/, const Bool& /*rhs*/) const
|
bool Compare(const Bool& /*lhs*/, const Bool& /*rhs*/) const
|
||||||
|
|
@ -237,6 +237,8 @@ namespace Nz
|
||||||
{
|
{
|
||||||
assert(array.elementType);
|
assert(array.elementType);
|
||||||
cache.Register(*array.elementType);
|
cache.Register(*array.elementType);
|
||||||
|
assert(array.length);
|
||||||
|
cache.Register(*array.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Register(const Bool&) {}
|
void Register(const Bool&) {}
|
||||||
|
|
@ -416,6 +418,7 @@ namespace Nz
|
||||||
tsl::ordered_map<Structure, FieldOffsets /*fieldOffsets*/, AnyHasher, Eq> structureSizes;
|
tsl::ordered_map<Structure, FieldOffsets /*fieldOffsets*/, AnyHasher, Eq> structureSizes;
|
||||||
StructCallback structCallback;
|
StructCallback structCallback;
|
||||||
UInt32& nextResultId;
|
UInt32& nextResultId;
|
||||||
|
bool isInBlockStruct = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
SpirvConstantCache::SpirvConstantCache(UInt32& resultId)
|
SpirvConstantCache::SpirvConstantCache(UInt32& resultId)
|
||||||
|
|
@ -493,26 +496,59 @@ namespace Nz
|
||||||
|
|
||||||
auto SpirvConstantCache::BuildPointerType(const ShaderAst::ExpressionType& type, SpirvStorageClass storageClass) const -> TypePtr
|
auto SpirvConstantCache::BuildPointerType(const ShaderAst::ExpressionType& type, SpirvStorageClass storageClass) const -> TypePtr
|
||||||
{
|
{
|
||||||
return std::make_shared<Type>(Pointer{
|
bool wasInblockStruct = m_internal->isInBlockStruct;
|
||||||
|
if (storageClass == SpirvStorageClass::Uniform)
|
||||||
|
m_internal->isInBlockStruct = true;
|
||||||
|
|
||||||
|
auto typePtr = std::make_shared<Type>(Pointer{
|
||||||
BuildType(type),
|
BuildType(type),
|
||||||
storageClass
|
storageClass
|
||||||
});
|
});
|
||||||
|
|
||||||
|
m_internal->isInBlockStruct = wasInblockStruct;
|
||||||
|
|
||||||
|
return typePtr;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto SpirvConstantCache::BuildPointerType(const TypePtr& type, SpirvStorageClass storageClass) const -> TypePtr
|
auto SpirvConstantCache::BuildPointerType(const TypePtr& type, SpirvStorageClass storageClass) const -> TypePtr
|
||||||
{
|
{
|
||||||
return std::make_shared<Type>(Pointer{
|
bool wasInblockStruct = m_internal->isInBlockStruct;
|
||||||
|
if (storageClass == SpirvStorageClass::Uniform)
|
||||||
|
m_internal->isInBlockStruct = true;
|
||||||
|
|
||||||
|
auto typePtr = std::make_shared<Type>(Pointer{
|
||||||
type,
|
type,
|
||||||
storageClass
|
storageClass
|
||||||
|
});
|
||||||
|
|
||||||
|
m_internal->isInBlockStruct = wasInblockStruct;
|
||||||
|
|
||||||
|
return typePtr;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto SpirvConstantCache::BuildType(const ShaderAst::ArrayType& type) const -> TypePtr
|
||||||
|
{
|
||||||
|
return std::make_shared<Type>(Array{
|
||||||
|
BuildType(type.containedType->type),
|
||||||
|
BuildConstant(type.length.GetResultingValue()),
|
||||||
|
(m_internal->isInBlockStruct) ? std::make_optional<UInt32>(16) : std::nullopt
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
auto SpirvConstantCache::BuildPointerType(const ShaderAst::PrimitiveType& type, SpirvStorageClass storageClass) const -> TypePtr
|
auto SpirvConstantCache::BuildPointerType(const ShaderAst::PrimitiveType& type, SpirvStorageClass storageClass) const -> TypePtr
|
||||||
{
|
{
|
||||||
return std::make_shared<Type>(Pointer{
|
bool wasInblockStruct = m_internal->isInBlockStruct;
|
||||||
|
if (storageClass == SpirvStorageClass::Uniform)
|
||||||
|
m_internal->isInBlockStruct = true;
|
||||||
|
|
||||||
|
auto typePtr = std::make_shared<Type>(Pointer{
|
||||||
BuildType(type),
|
BuildType(type),
|
||||||
storageClass
|
storageClass
|
||||||
});
|
});
|
||||||
|
|
||||||
|
m_internal->isInBlockStruct = wasInblockStruct;
|
||||||
|
|
||||||
|
return typePtr;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto SpirvConstantCache::BuildType(const ShaderAst::ExpressionType& type) const -> TypePtr
|
auto SpirvConstantCache::BuildType(const ShaderAst::ExpressionType& type) const -> TypePtr
|
||||||
|
|
@ -614,6 +650,10 @@ namespace Nz
|
||||||
sType.name = structDesc.name;
|
sType.name = structDesc.name;
|
||||||
sType.decorations = std::move(decorations);
|
sType.decorations = std::move(decorations);
|
||||||
|
|
||||||
|
bool wasInBlock = m_internal->isInBlockStruct;
|
||||||
|
if (!wasInBlock)
|
||||||
|
m_internal->isInBlockStruct = std::find(sType.decorations.begin(), sType.decorations.end(), SpirvDecoration::Block) != sType.decorations.end();
|
||||||
|
|
||||||
for (const auto& member : structDesc.members)
|
for (const auto& member : structDesc.members)
|
||||||
{
|
{
|
||||||
if (member.cond.HasValue() && !member.cond.GetResultingValue())
|
if (member.cond.HasValue() && !member.cond.GetResultingValue())
|
||||||
|
|
@ -624,6 +664,8 @@ namespace Nz
|
||||||
sMembers.type = BuildType(member.type);
|
sMembers.type = BuildType(member.type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_internal->isInBlockStruct = wasInBlock;
|
||||||
|
|
||||||
return std::make_shared<Type>(std::move(sType));
|
return std::make_shared<Type>(std::move(sType));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -814,7 +856,11 @@ namespace Nz
|
||||||
using T = std::decay_t<decltype(arg)>;
|
using T = std::decay_t<decltype(arg)>;
|
||||||
|
|
||||||
if constexpr (std::is_same_v<T, Array>)
|
if constexpr (std::is_same_v<T, Array>)
|
||||||
constants.Append(SpirvOp::OpTypeArray, resultId, GetId(*arg.elementType), arg.length);
|
{
|
||||||
|
constants.Append(SpirvOp::OpTypeArray, resultId, GetId(*arg.elementType), GetId(*arg.length));
|
||||||
|
if (arg.stride)
|
||||||
|
annotations.Append(SpirvOp::OpDecorate, resultId, SpirvDecoration::ArrayStride, *arg.stride);
|
||||||
|
}
|
||||||
else if constexpr (std::is_same_v<T, Bool>)
|
else if constexpr (std::is_same_v<T, Bool>)
|
||||||
constants.Append(SpirvOp::OpTypeBool, resultId);
|
constants.Append(SpirvOp::OpTypeBool, resultId);
|
||||||
else if constexpr (std::is_same_v<T, Float>)
|
else if constexpr (std::is_same_v<T, Float>)
|
||||||
|
|
@ -908,8 +954,23 @@ namespace Nz
|
||||||
|
|
||||||
if constexpr (std::is_same_v<T, Array>)
|
if constexpr (std::is_same_v<T, Array>)
|
||||||
{
|
{
|
||||||
// TODO
|
assert(std::holds_alternative<ConstantScalar>(arg.length->constant));
|
||||||
throw std::runtime_error("todo");
|
const auto& scalar = std::get<ConstantScalar>(arg.length->constant);
|
||||||
|
assert(std::holds_alternative<UInt32>(scalar.value));
|
||||||
|
std::size_t length = std::get<UInt32>(scalar.value);
|
||||||
|
|
||||||
|
if (!std::holds_alternative<Float>(arg.elementType->type))
|
||||||
|
throw std::runtime_error("todo");
|
||||||
|
|
||||||
|
// FIXME: Virer cette implémentation du ghetto
|
||||||
|
|
||||||
|
const Float& fData = std::get<Float>(arg.elementType->type);
|
||||||
|
switch (fData.width)
|
||||||
|
{
|
||||||
|
case 32: return structOffsets.AddFieldArray(StructFieldType::Float1, length);
|
||||||
|
case 64: return structOffsets.AddFieldArray(StructFieldType::Double1, length);
|
||||||
|
default: throw std::runtime_error("unexpected float width " + std::to_string(fData.width));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if constexpr (std::is_same_v<T, Bool>)
|
else if constexpr (std::is_same_v<T, Bool>)
|
||||||
return structOffsets.AddField(StructFieldType::Bool1);
|
return structOffsets.AddField(StructFieldType::Bool1);
|
||||||
|
|
|
||||||
|
|
@ -487,7 +487,9 @@ namespace Nz
|
||||||
{
|
{
|
||||||
ShaderAst::SanitizeVisitor::Options options;
|
ShaderAst::SanitizeVisitor::Options options;
|
||||||
options.optionValues = states.optionValues;
|
options.optionValues = states.optionValues;
|
||||||
|
options.reduceLoopsToWhile = true;
|
||||||
options.removeCompoundAssignments = true;
|
options.removeCompoundAssignments = true;
|
||||||
|
options.removeOptionDeclaration = true;
|
||||||
options.splitMultipleBranches = true;
|
options.splitMultipleBranches = true;
|
||||||
|
|
||||||
sanitizedAst = ShaderAst::Sanitize(shader, options);
|
sanitizedAst = ShaderAst::Sanitize(shader, options);
|
||||||
|
|
|
||||||
|
|
@ -109,4 +109,55 @@ fn main()
|
||||||
)");
|
)");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WHEN("using const for-each")
|
||||||
|
{
|
||||||
|
std::string_view sourceCode = R"(
|
||||||
|
const LightCount = 3;
|
||||||
|
|
||||||
|
[layout(std140)]
|
||||||
|
struct Light
|
||||||
|
{
|
||||||
|
color: vec4<f32>
|
||||||
|
}
|
||||||
|
|
||||||
|
[layout(std140)]
|
||||||
|
struct LightData
|
||||||
|
{
|
||||||
|
lights: [Light; LightCount]
|
||||||
|
}
|
||||||
|
|
||||||
|
external
|
||||||
|
{
|
||||||
|
[set(0), binding(0)] data: uniform<LightData>
|
||||||
|
}
|
||||||
|
|
||||||
|
[entry(frag)]
|
||||||
|
fn main()
|
||||||
|
{
|
||||||
|
let color = (0.0).xxxx;
|
||||||
|
const for light in data.lights
|
||||||
|
{
|
||||||
|
color += light.color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
|
||||||
|
Nz::ShaderAst::StatementPtr shader;
|
||||||
|
REQUIRE_NOTHROW(shader = Nz::ShaderLang::Parse(sourceCode));
|
||||||
|
|
||||||
|
ExpectOutput(*shader, {}, R"(
|
||||||
|
[entry(frag)]
|
||||||
|
fn main()
|
||||||
|
{
|
||||||
|
let color: vec4<f32> = (0.000000).xxxx;
|
||||||
|
let light: Light = data.lights[0];
|
||||||
|
color += light.color;
|
||||||
|
let light: Light = data.lights[1];
|
||||||
|
color += light.color;
|
||||||
|
let light: Light = data.lights[2];
|
||||||
|
color += light.color;
|
||||||
|
}
|
||||||
|
)");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,9 @@
|
||||||
|
|
||||||
TEST_CASE("loops", "[Shader]")
|
TEST_CASE("loops", "[Shader]")
|
||||||
{
|
{
|
||||||
std::string_view nzslSource = R"(
|
WHEN("using a while")
|
||||||
|
{
|
||||||
|
std::string_view nzslSource = R"(
|
||||||
struct inputStruct
|
struct inputStruct
|
||||||
{
|
{
|
||||||
value: f32
|
value: f32
|
||||||
|
|
@ -32,9 +34,9 @@ fn main()
|
||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
|
|
||||||
Nz::ShaderAst::StatementPtr shader = Nz::ShaderLang::Parse(nzslSource);
|
Nz::ShaderAst::StatementPtr shader = Nz::ShaderLang::Parse(nzslSource);
|
||||||
|
|
||||||
ExpectGLSL(*shader, R"(
|
ExpectGLSL(*shader, R"(
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
float value = 0.000000;
|
float value = 0.000000;
|
||||||
|
|
@ -48,7 +50,7 @@ void main()
|
||||||
}
|
}
|
||||||
)");
|
)");
|
||||||
|
|
||||||
ExpectNZSL(*shader, R"(
|
ExpectNZSL(*shader, R"(
|
||||||
[entry(frag)]
|
[entry(frag)]
|
||||||
fn main()
|
fn main()
|
||||||
{
|
{
|
||||||
|
|
@ -63,7 +65,7 @@ fn main()
|
||||||
}
|
}
|
||||||
)");
|
)");
|
||||||
|
|
||||||
ExpectSpirV(*shader, R"(
|
ExpectSpirV(*shader, R"(
|
||||||
OpFunction
|
OpFunction
|
||||||
OpLabel
|
OpLabel
|
||||||
OpVariable
|
OpVariable
|
||||||
|
|
@ -87,4 +89,93 @@ OpBranch
|
||||||
OpLabel
|
OpLabel
|
||||||
OpReturn
|
OpReturn
|
||||||
OpFunctionEnd)");
|
OpFunctionEnd)");
|
||||||
|
}
|
||||||
|
|
||||||
|
WHEN("using a for-each")
|
||||||
|
{
|
||||||
|
std::string_view nzslSource = R"(
|
||||||
|
struct inputStruct
|
||||||
|
{
|
||||||
|
value: [f32; 10]
|
||||||
|
}
|
||||||
|
|
||||||
|
external
|
||||||
|
{
|
||||||
|
[set(0), binding(0)] data: uniform<inputStruct>
|
||||||
|
}
|
||||||
|
|
||||||
|
[entry(frag)]
|
||||||
|
fn main()
|
||||||
|
{
|
||||||
|
let x = 0.0;
|
||||||
|
for v in data.value
|
||||||
|
{
|
||||||
|
x += v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
|
||||||
|
Nz::ShaderAst::StatementPtr shader = Nz::ShaderLang::Parse(nzslSource);
|
||||||
|
|
||||||
|
|
||||||
|
ExpectGLSL(*shader, R"(
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
float x = 0.000000;
|
||||||
|
uint i = 0u;
|
||||||
|
while (i < (10u))
|
||||||
|
{
|
||||||
|
float v = data.value[i];
|
||||||
|
x += v;
|
||||||
|
i += 1u;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
)");
|
||||||
|
|
||||||
|
ExpectNZSL(*shader, R"(
|
||||||
|
[entry(frag)]
|
||||||
|
fn main()
|
||||||
|
{
|
||||||
|
let x: f32 = 0.000000;
|
||||||
|
for v in data.value
|
||||||
|
{
|
||||||
|
x += v;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
)");
|
||||||
|
|
||||||
|
ExpectSpirV(*shader, R"(
|
||||||
|
OpFunction
|
||||||
|
OpLabel
|
||||||
|
OpVariable
|
||||||
|
OpVariable
|
||||||
|
OpVariable
|
||||||
|
OpStore
|
||||||
|
OpStore
|
||||||
|
OpBranch
|
||||||
|
OpLabel
|
||||||
|
OpLoad
|
||||||
|
OpULessThan
|
||||||
|
OpLoopMerge
|
||||||
|
OpBranchConditional
|
||||||
|
OpLabel
|
||||||
|
OpAccessChain
|
||||||
|
OpLoad
|
||||||
|
OpAccessChain
|
||||||
|
OpLoad
|
||||||
|
OpStore
|
||||||
|
OpLoad
|
||||||
|
OpLoad
|
||||||
|
OpFAdd
|
||||||
|
OpStore
|
||||||
|
OpLoad
|
||||||
|
OpIAdd
|
||||||
|
OpStore
|
||||||
|
OpBranch
|
||||||
|
OpLabel
|
||||||
|
OpReturn
|
||||||
|
OpFunctionEnd)");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -74,6 +74,55 @@ fn main()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
)");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
WHEN("reducing for-each to while")
|
||||||
|
{
|
||||||
|
std::string_view nzslSource = R"(
|
||||||
|
struct inputStruct
|
||||||
|
{
|
||||||
|
value: [f32; 10]
|
||||||
|
}
|
||||||
|
|
||||||
|
external
|
||||||
|
{
|
||||||
|
[set(0), binding(0)] data: uniform<inputStruct>
|
||||||
|
}
|
||||||
|
|
||||||
|
[entry(frag)]
|
||||||
|
fn main()
|
||||||
|
{
|
||||||
|
let x = 0.0;
|
||||||
|
for v in data.value
|
||||||
|
{
|
||||||
|
x += v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
|
||||||
|
Nz::ShaderAst::StatementPtr shader = Nz::ShaderLang::Parse(nzslSource);
|
||||||
|
|
||||||
|
Nz::ShaderAst::SanitizeVisitor::Options options;
|
||||||
|
options.reduceLoopsToWhile = true;
|
||||||
|
|
||||||
|
REQUIRE_NOTHROW(shader = Nz::ShaderAst::Sanitize(*shader, options));
|
||||||
|
|
||||||
|
ExpectNZSL(*shader, R"(
|
||||||
|
[entry(frag)]
|
||||||
|
fn main()
|
||||||
|
{
|
||||||
|
let x: f32 = 0.000000;
|
||||||
|
let i: u32 = 0;
|
||||||
|
while (i < (10))
|
||||||
|
{
|
||||||
|
let v: f32 = data.value[i];
|
||||||
|
x += v;
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
)");
|
)");
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue