Shader: Attribute can now have expressions as values and struct fields can be conditionally supported
This commit is contained in:
parent
749b40cb31
commit
f9af35b489
|
|
@ -9,6 +9,7 @@
|
||||||
|
|
||||||
#include <Nazara/Prerequisites.hpp>
|
#include <Nazara/Prerequisites.hpp>
|
||||||
#include <Nazara/Shader/Config.hpp>
|
#include <Nazara/Shader/Config.hpp>
|
||||||
|
#include <Nazara/Shader/Ast/Attribute.hpp>
|
||||||
#include <Nazara/Shader/Ast/AstExpressionVisitor.hpp>
|
#include <Nazara/Shader/Ast/AstExpressionVisitor.hpp>
|
||||||
#include <Nazara/Shader/Ast/AstStatementVisitor.hpp>
|
#include <Nazara/Shader/Ast/AstStatementVisitor.hpp>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
@ -30,6 +31,7 @@ namespace Nz::ShaderAst
|
||||||
AstCloner& operator=(AstCloner&&) = delete;
|
AstCloner& operator=(AstCloner&&) = delete;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
template<typename T> AttributeValue<T> CloneAttribute(const AttributeValue<T>& attribute);
|
||||||
inline ExpressionPtr CloneExpression(const ExpressionPtr& expr);
|
inline ExpressionPtr CloneExpression(const ExpressionPtr& expr);
|
||||||
inline StatementPtr CloneStatement(const StatementPtr& statement);
|
inline StatementPtr CloneStatement(const StatementPtr& statement);
|
||||||
|
|
||||||
|
|
@ -44,6 +46,7 @@ namespace Nz::ShaderAst
|
||||||
virtual ExpressionPtr Clone(CallMethodExpression& node);
|
virtual ExpressionPtr Clone(CallMethodExpression& node);
|
||||||
virtual ExpressionPtr Clone(CastExpression& node);
|
virtual ExpressionPtr Clone(CastExpression& node);
|
||||||
virtual ExpressionPtr Clone(ConditionalExpression& node);
|
virtual ExpressionPtr Clone(ConditionalExpression& node);
|
||||||
|
virtual ExpressionPtr Clone(ConstantIndexExpression& node);
|
||||||
virtual ExpressionPtr Clone(ConstantExpression& node);
|
virtual ExpressionPtr Clone(ConstantExpression& node);
|
||||||
virtual ExpressionPtr Clone(IdentifierExpression& node);
|
virtual ExpressionPtr Clone(IdentifierExpression& node);
|
||||||
virtual ExpressionPtr Clone(IntrinsicExpression& node);
|
virtual ExpressionPtr Clone(IntrinsicExpression& node);
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,21 @@
|
||||||
|
|
||||||
namespace Nz::ShaderAst
|
namespace Nz::ShaderAst
|
||||||
{
|
{
|
||||||
|
template<typename T>
|
||||||
|
AttributeValue<T> AstCloner::CloneAttribute(const AttributeValue<T>& attribute)
|
||||||
|
{
|
||||||
|
if (!attribute.HasValue())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
if (attribute.IsExpression())
|
||||||
|
return CloneExpression(attribute.GetExpression());
|
||||||
|
else
|
||||||
|
{
|
||||||
|
assert(attribute.IsResultingValue());
|
||||||
|
return attribute.GetResultingValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ExpressionPtr AstCloner::CloneExpression(const ExpressionPtr& expr)
|
ExpressionPtr AstCloner::CloneExpression(const ExpressionPtr& expr)
|
||||||
{
|
{
|
||||||
if (!expr)
|
if (!expr)
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,7 @@ NAZARA_SHADERAST_EXPRESSION(CallMethodExpression)
|
||||||
NAZARA_SHADERAST_EXPRESSION(CastExpression)
|
NAZARA_SHADERAST_EXPRESSION(CastExpression)
|
||||||
NAZARA_SHADERAST_EXPRESSION(ConditionalExpression)
|
NAZARA_SHADERAST_EXPRESSION(ConditionalExpression)
|
||||||
NAZARA_SHADERAST_EXPRESSION(ConstantExpression)
|
NAZARA_SHADERAST_EXPRESSION(ConstantExpression)
|
||||||
|
NAZARA_SHADERAST_EXPRESSION(ConstantIndexExpression)
|
||||||
NAZARA_SHADERAST_EXPRESSION(IdentifierExpression)
|
NAZARA_SHADERAST_EXPRESSION(IdentifierExpression)
|
||||||
NAZARA_SHADERAST_EXPRESSION(IntrinsicExpression)
|
NAZARA_SHADERAST_EXPRESSION(IntrinsicExpression)
|
||||||
NAZARA_SHADERAST_EXPRESSION(SelectOptionExpression)
|
NAZARA_SHADERAST_EXPRESSION(SelectOptionExpression)
|
||||||
|
|
|
||||||
|
|
@ -18,21 +18,32 @@ namespace Nz::ShaderAst
|
||||||
class NAZARA_SHADER_API AstOptimizer : public AstCloner
|
class NAZARA_SHADER_API AstOptimizer : public AstCloner
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
struct Options;
|
||||||
|
|
||||||
AstOptimizer() = default;
|
AstOptimizer() = default;
|
||||||
AstOptimizer(const AstOptimizer&) = delete;
|
AstOptimizer(const AstOptimizer&) = delete;
|
||||||
AstOptimizer(AstOptimizer&&) = delete;
|
AstOptimizer(AstOptimizer&&) = delete;
|
||||||
~AstOptimizer() = default;
|
~AstOptimizer() = default;
|
||||||
|
|
||||||
StatementPtr Optimise(Statement& statement);
|
inline ExpressionPtr Optimise(Expression& expression);
|
||||||
StatementPtr Optimise(Statement& statement, UInt64 enabledConditions);
|
inline ExpressionPtr Optimise(Expression& expression, const Options& options);
|
||||||
|
inline StatementPtr Optimise(Statement& statement);
|
||||||
|
inline StatementPtr Optimise(Statement& statement, const Options& options);
|
||||||
|
|
||||||
AstOptimizer& operator=(const AstOptimizer&) = delete;
|
AstOptimizer& operator=(const AstOptimizer&) = delete;
|
||||||
AstOptimizer& operator=(AstOptimizer&&) = delete;
|
AstOptimizer& operator=(AstOptimizer&&) = delete;
|
||||||
|
|
||||||
|
struct Options
|
||||||
|
{
|
||||||
|
std::function<const ConstantValue&(std::size_t constantId)> constantQueryCallback;
|
||||||
|
std::optional<UInt64> enabledOptions = 0;
|
||||||
|
};
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
ExpressionPtr Clone(BinaryExpression& node) override;
|
ExpressionPtr Clone(BinaryExpression& node) override;
|
||||||
ExpressionPtr Clone(CastExpression& node) override;
|
ExpressionPtr Clone(CastExpression& node) override;
|
||||||
ExpressionPtr Clone(ConditionalExpression& node) override;
|
ExpressionPtr Clone(ConditionalExpression& node) override;
|
||||||
|
ExpressionPtr Clone(ConstantIndexExpression& node) override;
|
||||||
ExpressionPtr Clone(UnaryExpression& node) override;
|
ExpressionPtr Clone(UnaryExpression& node) override;
|
||||||
StatementPtr Clone(BranchStatement& node) override;
|
StatementPtr Clone(BranchStatement& node) override;
|
||||||
StatementPtr Clone(ConditionalStatement& node) override;
|
StatementPtr Clone(ConditionalStatement& node) override;
|
||||||
|
|
@ -45,11 +56,13 @@ namespace Nz::ShaderAst
|
||||||
template<typename TargetType> ExpressionPtr PropagateVec4Cast(TargetType v1, TargetType v2, TargetType v3, TargetType v4);
|
template<typename TargetType> ExpressionPtr PropagateVec4Cast(TargetType v1, TargetType v2, TargetType v3, TargetType v4);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::optional<UInt64> m_enabledOptions;
|
Options m_options;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
inline ExpressionPtr Optimize(Expression& expr);
|
||||||
|
inline ExpressionPtr Optimize(Expression& expr, const AstOptimizer::Options& options);
|
||||||
inline StatementPtr Optimize(Statement& ast);
|
inline StatementPtr Optimize(Statement& ast);
|
||||||
inline StatementPtr Optimize(Statement& ast, UInt64 enabledConditions);
|
inline StatementPtr Optimize(Statement& ast, const AstOptimizer::Options& options);
|
||||||
}
|
}
|
||||||
|
|
||||||
#include <Nazara/Shader/Ast/AstOptimizer.inl>
|
#include <Nazara/Shader/Ast/AstOptimizer.inl>
|
||||||
|
|
|
||||||
|
|
@ -7,16 +7,52 @@
|
||||||
|
|
||||||
namespace Nz::ShaderAst
|
namespace Nz::ShaderAst
|
||||||
{
|
{
|
||||||
|
inline ExpressionPtr AstOptimizer::Optimise(Expression& expression)
|
||||||
|
{
|
||||||
|
m_options = {};
|
||||||
|
return CloneExpression(expression);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ExpressionPtr AstOptimizer::Optimise(Expression& expression, const Options& options)
|
||||||
|
{
|
||||||
|
m_options = options;
|
||||||
|
return CloneExpression(expression);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline StatementPtr AstOptimizer::Optimise(Statement& statement)
|
||||||
|
{
|
||||||
|
m_options = {};
|
||||||
|
return CloneStatement(statement);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline StatementPtr AstOptimizer::Optimise(Statement& statement, const Options& options)
|
||||||
|
{
|
||||||
|
m_options = options;
|
||||||
|
return CloneStatement(statement);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ExpressionPtr Optimize(Expression& ast)
|
||||||
|
{
|
||||||
|
AstOptimizer optimize;
|
||||||
|
return optimize.Optimise(ast);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ExpressionPtr Optimize(Expression& ast, const AstOptimizer::Options& options)
|
||||||
|
{
|
||||||
|
AstOptimizer optimize;
|
||||||
|
return optimize.Optimise(ast, options);
|
||||||
|
}
|
||||||
|
|
||||||
inline StatementPtr Optimize(Statement& ast)
|
inline StatementPtr Optimize(Statement& ast)
|
||||||
{
|
{
|
||||||
AstOptimizer optimize;
|
AstOptimizer optimize;
|
||||||
return optimize.Optimise(ast);
|
return optimize.Optimise(ast);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline StatementPtr Optimize(Statement& ast, UInt64 enabledConditions)
|
inline StatementPtr Optimize(Statement& ast, const AstOptimizer::Options& options)
|
||||||
{
|
{
|
||||||
AstOptimizer optimize;
|
AstOptimizer optimize;
|
||||||
return optimize.Optimise(ast, enabledConditions);
|
return optimize.Optimise(ast, options);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@ namespace Nz::ShaderAst
|
||||||
void Visit(CastExpression& node) override;
|
void Visit(CastExpression& node) override;
|
||||||
void Visit(ConditionalExpression& node) override;
|
void Visit(ConditionalExpression& node) override;
|
||||||
void Visit(ConstantExpression& node) override;
|
void Visit(ConstantExpression& node) override;
|
||||||
|
void Visit(ConstantIndexExpression& node) override;
|
||||||
void Visit(IdentifierExpression& node) override;
|
void Visit(IdentifierExpression& node) override;
|
||||||
void Visit(IntrinsicExpression& node) override;
|
void Visit(IntrinsicExpression& node) override;
|
||||||
void Visit(SelectOptionExpression& node) override;
|
void Visit(SelectOptionExpression& node) override;
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ namespace Nz::ShaderAst
|
||||||
void Serialize(CallFunctionExpression& node);
|
void Serialize(CallFunctionExpression& node);
|
||||||
void Serialize(CallMethodExpression& node);
|
void Serialize(CallMethodExpression& node);
|
||||||
void Serialize(CastExpression& node);
|
void Serialize(CastExpression& node);
|
||||||
|
void Serialize(ConstantIndexExpression& node);
|
||||||
void Serialize(ConditionalExpression& node);
|
void Serialize(ConditionalExpression& node);
|
||||||
void Serialize(ConstantExpression& node);
|
void Serialize(ConstantExpression& node);
|
||||||
void Serialize(IdentifierExpression& node);
|
void Serialize(IdentifierExpression& node);
|
||||||
|
|
@ -53,6 +54,7 @@ namespace Nz::ShaderAst
|
||||||
void Serialize(ReturnStatement& node);
|
void Serialize(ReturnStatement& node);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
template<typename T> void Attribute(AttributeValue<T>& attribute);
|
||||||
template<typename T> void Container(T& container);
|
template<typename T> void Container(T& container);
|
||||||
template<typename T> void Enum(T& enumVal);
|
template<typename T> void Enum(T& enumVal);
|
||||||
template<typename T> void OptEnum(std::optional<T>& optVal);
|
template<typename T> void OptEnum(std::optional<T>& optVal);
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,73 @@
|
||||||
|
|
||||||
namespace Nz::ShaderAst
|
namespace Nz::ShaderAst
|
||||||
{
|
{
|
||||||
|
template<typename T>
|
||||||
|
void AstSerializerBase::Attribute(AttributeValue<T>& attribute)
|
||||||
|
{
|
||||||
|
UInt32 valueType;
|
||||||
|
if (IsWriting())
|
||||||
|
{
|
||||||
|
if (!attribute.HasValue())
|
||||||
|
valueType = 0;
|
||||||
|
else if (attribute.IsExpression())
|
||||||
|
valueType = 1;
|
||||||
|
else if (attribute.IsResultingValue())
|
||||||
|
valueType = 2;
|
||||||
|
else
|
||||||
|
throw std::runtime_error("unexpected attribute");
|
||||||
|
}
|
||||||
|
|
||||||
|
Value(valueType);
|
||||||
|
|
||||||
|
switch (valueType)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
if (!IsWriting())
|
||||||
|
attribute = {};
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
if (!IsWriting())
|
||||||
|
{
|
||||||
|
ExpressionPtr expr;
|
||||||
|
Node(expr);
|
||||||
|
|
||||||
|
attribute = std::move(expr);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Node(const_cast<ExpressionPtr&>(attribute.GetExpression())); //< not used for writing
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
{
|
||||||
|
if (!IsWriting())
|
||||||
|
{
|
||||||
|
T value;
|
||||||
|
if constexpr (std::is_enum_v<T>)
|
||||||
|
Enum(value);
|
||||||
|
else
|
||||||
|
Value(value);
|
||||||
|
|
||||||
|
attribute = std::move(value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
T& value = const_cast<T&>(attribute.GetResultingValue()); //< not used for writing
|
||||||
|
if constexpr (std::is_enum_v<T>)
|
||||||
|
Enum(value);
|
||||||
|
else
|
||||||
|
Value(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void AstSerializerBase::Container(T& container)
|
void AstSerializerBase::Container(T& container)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,7 @@ namespace Nz::ShaderAst
|
||||||
void Visit(CastExpression& node) override;
|
void Visit(CastExpression& node) override;
|
||||||
void Visit(ConditionalExpression& node) override;
|
void Visit(ConditionalExpression& node) override;
|
||||||
void Visit(ConstantExpression& node) override;
|
void Visit(ConstantExpression& node) override;
|
||||||
|
void Visit(ConstantIndexExpression& node) override;
|
||||||
void Visit(IdentifierExpression& node) override;
|
void Visit(IdentifierExpression& node) override;
|
||||||
void Visit(IntrinsicExpression& node) override;
|
void Visit(IntrinsicExpression& node) override;
|
||||||
void Visit(SelectOptionExpression& node) override;
|
void Visit(SelectOptionExpression& node) override;
|
||||||
|
|
|
||||||
|
|
@ -9,17 +9,52 @@
|
||||||
|
|
||||||
#include <Nazara/Prerequisites.hpp>
|
#include <Nazara/Prerequisites.hpp>
|
||||||
#include <Nazara/Shader/Ast/Enums.hpp>
|
#include <Nazara/Shader/Ast/Enums.hpp>
|
||||||
|
#include <memory>
|
||||||
|
#include <optional>
|
||||||
#include <variant>
|
#include <variant>
|
||||||
|
|
||||||
namespace Nz::ShaderAst
|
namespace Nz::ShaderAst
|
||||||
{
|
{
|
||||||
|
struct Expression;
|
||||||
|
|
||||||
|
using ExpressionPtr = std::unique_ptr<Expression>;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
class AttributeValue
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AttributeValue() = default;
|
||||||
|
AttributeValue(T value);
|
||||||
|
AttributeValue(ExpressionPtr expr);
|
||||||
|
AttributeValue(const AttributeValue&) = default;
|
||||||
|
AttributeValue(AttributeValue&&) = default;
|
||||||
|
~AttributeValue() = default;
|
||||||
|
|
||||||
|
ExpressionPtr&& GetExpression() &&;
|
||||||
|
const ExpressionPtr& GetExpression() const &;
|
||||||
|
const T& GetResultingValue() const;
|
||||||
|
|
||||||
|
bool IsExpression() const;
|
||||||
|
bool IsResultingValue() const;
|
||||||
|
|
||||||
|
bool HasValue() const;
|
||||||
|
|
||||||
|
AttributeValue& operator=(const AttributeValue&) = default;
|
||||||
|
AttributeValue& operator=(AttributeValue&&) = default;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::variant<std::monostate, T, ExpressionPtr> m_value;
|
||||||
|
};
|
||||||
|
|
||||||
struct Attribute
|
struct Attribute
|
||||||
{
|
{
|
||||||
using Param = std::variant<std::monostate, long long, std::string>;
|
using Param = std::optional<ExpressionPtr>;
|
||||||
|
|
||||||
AttributeType type;
|
AttributeType type;
|
||||||
Param args;
|
Param args;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#include <Nazara/Shader/Ast/Attribute.inl>
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,72 @@
|
||||||
|
// 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/Ast/Attribute.hpp>
|
||||||
|
#include <cassert>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <Nazara/Shader/Debug.hpp>
|
||||||
|
|
||||||
|
namespace Nz::ShaderAst
|
||||||
|
{
|
||||||
|
template<typename T>
|
||||||
|
AttributeValue<T>::AttributeValue(T value) :
|
||||||
|
m_value(std::move(value))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
AttributeValue<T>::AttributeValue(ExpressionPtr expr)
|
||||||
|
{
|
||||||
|
assert(expr);
|
||||||
|
m_value = std::move(expr);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
ExpressionPtr&& AttributeValue<T>::GetExpression() &&
|
||||||
|
{
|
||||||
|
if (!IsExpression())
|
||||||
|
throw std::runtime_error("excepted expression");
|
||||||
|
|
||||||
|
return std::get<ExpressionPtr>(std::move(m_value));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
const ExpressionPtr& AttributeValue<T>::GetExpression() const &
|
||||||
|
{
|
||||||
|
if (!IsExpression())
|
||||||
|
throw std::runtime_error("excepted expression");
|
||||||
|
|
||||||
|
assert(std::get<ExpressionPtr>(m_value));
|
||||||
|
return std::get<ExpressionPtr>(m_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
const T& AttributeValue<T>::GetResultingValue() const
|
||||||
|
{
|
||||||
|
if (!IsResultingValue())
|
||||||
|
throw std::runtime_error("excepted resulting value");
|
||||||
|
|
||||||
|
return std::get<T>(m_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
bool AttributeValue<T>::IsExpression() const
|
||||||
|
{
|
||||||
|
return std::holds_alternative<ExpressionPtr>(m_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
bool AttributeValue<T>::IsResultingValue() const
|
||||||
|
{
|
||||||
|
return std::holds_alternative<T>(m_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
bool AttributeValue<T>::HasValue() const
|
||||||
|
{
|
||||||
|
return !std::holds_alternative<std::monostate>(m_value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <Nazara/Shader/DebugOff.hpp>
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
#define NAZARA_SHADER_CONSTANTVALUE_HPP
|
#define NAZARA_SHADER_CONSTANTVALUE_HPP
|
||||||
|
|
||||||
#include <Nazara/Prerequisites.hpp>
|
#include <Nazara/Prerequisites.hpp>
|
||||||
|
#include <Nazara/Core/TypeList.hpp>
|
||||||
#include <Nazara/Math/Vector2.hpp>
|
#include <Nazara/Math/Vector2.hpp>
|
||||||
#include <Nazara/Math/Vector3.hpp>
|
#include <Nazara/Math/Vector3.hpp>
|
||||||
#include <Nazara/Math/Vector4.hpp>
|
#include <Nazara/Math/Vector4.hpp>
|
||||||
|
|
@ -17,7 +18,7 @@
|
||||||
|
|
||||||
namespace Nz::ShaderAst
|
namespace Nz::ShaderAst
|
||||||
{
|
{
|
||||||
using ConstantValue = std::variant<
|
using ConstantTypes = TypeList<
|
||||||
bool,
|
bool,
|
||||||
float,
|
float,
|
||||||
Int32,
|
Int32,
|
||||||
|
|
@ -30,6 +31,8 @@ namespace Nz::ShaderAst
|
||||||
Vector4i32
|
Vector4i32
|
||||||
>;
|
>;
|
||||||
|
|
||||||
|
using ConstantValue = TypeListInstantiate<ConstantTypes, std::variant>;
|
||||||
|
|
||||||
NAZARA_SHADER_API ExpressionType GetExpressionType(const ConstantValue& constant);
|
NAZARA_SHADER_API ExpressionType GetExpressionType(const ConstantValue& constant);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,12 +23,12 @@ namespace Nz
|
||||||
{
|
{
|
||||||
Binding, //< Binding (external var only) - has argument index
|
Binding, //< Binding (external var only) - has argument index
|
||||||
Builtin, //< Builtin (struct member only) - has argument type
|
Builtin, //< Builtin (struct member only) - has argument type
|
||||||
|
Cond, //< Conditional compilation option - has argument expr
|
||||||
DepthWrite, //< Depth write mode (function only) - has argument type
|
DepthWrite, //< Depth write mode (function only) - has argument type
|
||||||
EarlyFragmentTests, //< Entry point (function only) - has argument on/off
|
EarlyFragmentTests, //< Entry point (function only) - has argument on/off
|
||||||
Entry, //< Entry point (function only) - has argument type
|
Entry, //< Entry point (function only) - has argument type
|
||||||
Layout, //< Struct layout (struct only) - has argument style
|
Layout, //< Struct layout (struct only) - has argument style
|
||||||
Location, //< Location (struct member only) - has argument index
|
Location, //< Location (struct member only) - has argument index
|
||||||
Option, //< Conditional compilation option - has argument expr
|
|
||||||
Set, //< Binding set (external var only) - has argument index
|
Set, //< Binding set (external var only) - has argument index
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -82,13 +82,14 @@ namespace Nz::ShaderAst
|
||||||
{
|
{
|
||||||
struct StructMember
|
struct StructMember
|
||||||
{
|
{
|
||||||
std::optional<BuiltinEntry> builtin;
|
AttributeValue<BuiltinEntry> builtin;
|
||||||
std::optional<UInt32> locationIndex;
|
AttributeValue<bool> cond;
|
||||||
|
AttributeValue<UInt32> locationIndex;
|
||||||
std::string name;
|
std::string name;
|
||||||
ExpressionType type;
|
ExpressionType type;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::optional<StructLayout> layout;
|
AttributeValue<StructLayout> layout;
|
||||||
std::string name;
|
std::string name;
|
||||||
std::vector<StructMember> members;
|
std::vector<StructMember> members;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -64,7 +64,7 @@ namespace Nz::ShaderAst
|
||||||
std::optional<ExpressionType> cachedExpressionType;
|
std::optional<ExpressionType> cachedExpressionType;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct NAZARA_SHADER_API AccessIdentifierExpression : public Expression
|
struct NAZARA_SHADER_API AccessIdentifierExpression : Expression
|
||||||
{
|
{
|
||||||
NodeType GetType() const override;
|
NodeType GetType() const override;
|
||||||
void Visit(AstExpressionVisitor& visitor) override;
|
void Visit(AstExpressionVisitor& visitor) override;
|
||||||
|
|
@ -73,7 +73,7 @@ namespace Nz::ShaderAst
|
||||||
std::vector<std::string> identifiers;
|
std::vector<std::string> identifiers;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct NAZARA_SHADER_API AccessIndexExpression : public Expression
|
struct NAZARA_SHADER_API AccessIndexExpression : Expression
|
||||||
{
|
{
|
||||||
NodeType GetType() const override;
|
NodeType GetType() const override;
|
||||||
void Visit(AstExpressionVisitor& visitor) override;
|
void Visit(AstExpressionVisitor& visitor) override;
|
||||||
|
|
@ -82,7 +82,7 @@ namespace Nz::ShaderAst
|
||||||
std::vector<ExpressionPtr> indices;
|
std::vector<ExpressionPtr> indices;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct NAZARA_SHADER_API AssignExpression : public Expression
|
struct NAZARA_SHADER_API AssignExpression : Expression
|
||||||
{
|
{
|
||||||
NodeType GetType() const override;
|
NodeType GetType() const override;
|
||||||
void Visit(AstExpressionVisitor& visitor) override;
|
void Visit(AstExpressionVisitor& visitor) override;
|
||||||
|
|
@ -92,7 +92,7 @@ namespace Nz::ShaderAst
|
||||||
ExpressionPtr right;
|
ExpressionPtr right;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct NAZARA_SHADER_API BinaryExpression : public Expression
|
struct NAZARA_SHADER_API BinaryExpression : Expression
|
||||||
{
|
{
|
||||||
NodeType GetType() const override;
|
NodeType GetType() const override;
|
||||||
void Visit(AstExpressionVisitor& visitor) override;
|
void Visit(AstExpressionVisitor& visitor) override;
|
||||||
|
|
@ -102,7 +102,7 @@ namespace Nz::ShaderAst
|
||||||
ExpressionPtr right;
|
ExpressionPtr right;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct NAZARA_SHADER_API CallFunctionExpression : public Expression
|
struct NAZARA_SHADER_API CallFunctionExpression : Expression
|
||||||
{
|
{
|
||||||
NodeType GetType() const override;
|
NodeType GetType() const override;
|
||||||
void Visit(AstExpressionVisitor& visitor) override;
|
void Visit(AstExpressionVisitor& visitor) override;
|
||||||
|
|
@ -111,7 +111,7 @@ namespace Nz::ShaderAst
|
||||||
std::vector<ExpressionPtr> parameters;
|
std::vector<ExpressionPtr> parameters;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct NAZARA_SHADER_API CallMethodExpression : public Expression
|
struct NAZARA_SHADER_API CallMethodExpression : Expression
|
||||||
{
|
{
|
||||||
NodeType GetType() const override;
|
NodeType GetType() const override;
|
||||||
void Visit(AstExpressionVisitor& visitor) override;
|
void Visit(AstExpressionVisitor& visitor) override;
|
||||||
|
|
@ -121,7 +121,7 @@ namespace Nz::ShaderAst
|
||||||
std::vector<ExpressionPtr> parameters;
|
std::vector<ExpressionPtr> parameters;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct NAZARA_SHADER_API CastExpression : public Expression
|
struct NAZARA_SHADER_API CastExpression : Expression
|
||||||
{
|
{
|
||||||
NodeType GetType() const override;
|
NodeType GetType() const override;
|
||||||
void Visit(AstExpressionVisitor& visitor) override;
|
void Visit(AstExpressionVisitor& visitor) override;
|
||||||
|
|
@ -130,17 +130,17 @@ namespace Nz::ShaderAst
|
||||||
std::array<ExpressionPtr, 4> expressions;
|
std::array<ExpressionPtr, 4> expressions;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct NAZARA_SHADER_API ConditionalExpression : public Expression
|
struct NAZARA_SHADER_API ConditionalExpression : Expression
|
||||||
{
|
{
|
||||||
NodeType GetType() const override;
|
NodeType GetType() const override;
|
||||||
void Visit(AstExpressionVisitor& visitor) override;
|
void Visit(AstExpressionVisitor& visitor) override;
|
||||||
|
|
||||||
std::size_t optionIndex;
|
ExpressionPtr condition;
|
||||||
ExpressionPtr falsePath;
|
ExpressionPtr falsePath;
|
||||||
ExpressionPtr truePath;
|
ExpressionPtr truePath;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct NAZARA_SHADER_API ConstantExpression : public Expression
|
struct NAZARA_SHADER_API ConstantExpression : Expression
|
||||||
{
|
{
|
||||||
NodeType GetType() const override;
|
NodeType GetType() const override;
|
||||||
void Visit(AstExpressionVisitor& visitor) override;
|
void Visit(AstExpressionVisitor& visitor) override;
|
||||||
|
|
@ -148,7 +148,15 @@ namespace Nz::ShaderAst
|
||||||
ShaderAst::ConstantValue value;
|
ShaderAst::ConstantValue value;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct NAZARA_SHADER_API IdentifierExpression : public Expression
|
struct NAZARA_SHADER_API ConstantIndexExpression : Expression
|
||||||
|
{
|
||||||
|
NodeType GetType() const override;
|
||||||
|
void Visit(AstExpressionVisitor& visitor) override;
|
||||||
|
|
||||||
|
std::size_t constantId;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct NAZARA_SHADER_API IdentifierExpression : Expression
|
||||||
{
|
{
|
||||||
NodeType GetType() const override;
|
NodeType GetType() const override;
|
||||||
void Visit(AstExpressionVisitor& visitor) override;
|
void Visit(AstExpressionVisitor& visitor) override;
|
||||||
|
|
@ -156,7 +164,7 @@ namespace Nz::ShaderAst
|
||||||
std::string identifier;
|
std::string identifier;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct NAZARA_SHADER_API IntrinsicExpression : public Expression
|
struct NAZARA_SHADER_API IntrinsicExpression : Expression
|
||||||
{
|
{
|
||||||
NodeType GetType() const override;
|
NodeType GetType() const override;
|
||||||
void Visit(AstExpressionVisitor& visitor) override;
|
void Visit(AstExpressionVisitor& visitor) override;
|
||||||
|
|
@ -165,7 +173,7 @@ namespace Nz::ShaderAst
|
||||||
std::vector<ExpressionPtr> parameters;
|
std::vector<ExpressionPtr> parameters;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct NAZARA_SHADER_API SelectOptionExpression : public Expression
|
struct NAZARA_SHADER_API SelectOptionExpression : Expression
|
||||||
{
|
{
|
||||||
NodeType GetType() const override;
|
NodeType GetType() const override;
|
||||||
void Visit(AstExpressionVisitor& visitor) override;
|
void Visit(AstExpressionVisitor& visitor) override;
|
||||||
|
|
@ -175,7 +183,7 @@ namespace Nz::ShaderAst
|
||||||
ExpressionPtr truePath;
|
ExpressionPtr truePath;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct NAZARA_SHADER_API SwizzleExpression : public Expression
|
struct NAZARA_SHADER_API SwizzleExpression : Expression
|
||||||
{
|
{
|
||||||
NodeType GetType() const override;
|
NodeType GetType() const override;
|
||||||
void Visit(AstExpressionVisitor& visitor) override;
|
void Visit(AstExpressionVisitor& visitor) override;
|
||||||
|
|
@ -193,7 +201,7 @@ namespace Nz::ShaderAst
|
||||||
std::size_t variableId;
|
std::size_t variableId;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct NAZARA_SHADER_API UnaryExpression : public Expression
|
struct NAZARA_SHADER_API UnaryExpression : Expression
|
||||||
{
|
{
|
||||||
NodeType GetType() const override;
|
NodeType GetType() const override;
|
||||||
void Visit(AstExpressionVisitor& visitor) override;
|
void Visit(AstExpressionVisitor& visitor) override;
|
||||||
|
|
@ -221,7 +229,7 @@ namespace Nz::ShaderAst
|
||||||
Statement& operator=(Statement&&) noexcept = default;
|
Statement& operator=(Statement&&) noexcept = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct NAZARA_SHADER_API BranchStatement : public Statement
|
struct NAZARA_SHADER_API BranchStatement : Statement
|
||||||
{
|
{
|
||||||
NodeType GetType() const override;
|
NodeType GetType() const override;
|
||||||
void Visit(AstStatementVisitor& visitor) override;
|
void Visit(AstStatementVisitor& visitor) override;
|
||||||
|
|
@ -241,7 +249,7 @@ namespace Nz::ShaderAst
|
||||||
NodeType GetType() const override;
|
NodeType GetType() const override;
|
||||||
void Visit(AstStatementVisitor& visitor) override;
|
void Visit(AstStatementVisitor& visitor) override;
|
||||||
|
|
||||||
std::size_t optionIndex;
|
ExpressionPtr condition;
|
||||||
StatementPtr statement;
|
StatementPtr statement;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -252,12 +260,13 @@ namespace Nz::ShaderAst
|
||||||
|
|
||||||
struct ExternalVar
|
struct ExternalVar
|
||||||
{
|
{
|
||||||
std::optional<UInt32> bindingIndex;
|
AttributeValue<UInt32> bindingIndex;
|
||||||
std::optional<UInt32> bindingSet;
|
AttributeValue<UInt32> bindingSet;
|
||||||
std::string name;
|
std::string name;
|
||||||
ExpressionType type;
|
ExpressionType type;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
AttributeValue<UInt32> bindingSet;
|
||||||
std::optional<std::size_t> varIndex;
|
std::optional<std::size_t> varIndex;
|
||||||
std::vector<ExternalVar> externalVars;
|
std::vector<ExternalVar> externalVars;
|
||||||
};
|
};
|
||||||
|
|
@ -273,12 +282,11 @@ namespace Nz::ShaderAst
|
||||||
ExpressionType type;
|
ExpressionType type;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::optional<DepthWriteMode> depthWrite;
|
AttributeValue<DepthWriteMode> depthWrite;
|
||||||
std::optional<bool> earlyFragmentTests;
|
AttributeValue<bool> earlyFragmentTests;
|
||||||
std::optional<ShaderStageType> entryStage;
|
AttributeValue<ShaderStageType> entryStage;
|
||||||
std::optional<std::size_t> funcIndex;
|
std::optional<std::size_t> funcIndex;
|
||||||
std::optional<std::size_t> varIndex;
|
std::optional<std::size_t> varIndex;
|
||||||
std::string optionName;
|
|
||||||
std::string name;
|
std::string name;
|
||||||
std::vector<Parameter> parameters;
|
std::vector<Parameter> parameters;
|
||||||
std::vector<StatementPtr> statements;
|
std::vector<StatementPtr> statements;
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,7 @@ namespace Nz::ShaderAst
|
||||||
struct Options
|
struct Options
|
||||||
{
|
{
|
||||||
std::unordered_set<std::string> reservedIdentifiers;
|
std::unordered_set<std::string> reservedIdentifiers;
|
||||||
|
UInt64 enabledOptions = 0;
|
||||||
bool makeVariableNameUnique = false;
|
bool makeVariableNameUnique = false;
|
||||||
bool removeOptionDeclaration = true;
|
bool removeOptionDeclaration = true;
|
||||||
};
|
};
|
||||||
|
|
@ -71,7 +72,7 @@ namespace Nz::ShaderAst
|
||||||
StatementPtr Clone(ExpressionStatement& node) override;
|
StatementPtr Clone(ExpressionStatement& node) override;
|
||||||
StatementPtr Clone(MultiStatement& node) override;
|
StatementPtr Clone(MultiStatement& node) override;
|
||||||
|
|
||||||
inline const Identifier* FindIdentifier(const std::string_view& identifierName) const;
|
const Identifier* FindIdentifier(const std::string_view& identifierName) const;
|
||||||
|
|
||||||
Expression& MandatoryExpr(ExpressionPtr& node);
|
Expression& MandatoryExpr(ExpressionPtr& node);
|
||||||
Statement& MandatoryStatement(StatementPtr& node);
|
Statement& MandatoryStatement(StatementPtr& node);
|
||||||
|
|
@ -81,14 +82,17 @@ namespace Nz::ShaderAst
|
||||||
void PushScope();
|
void PushScope();
|
||||||
void PopScope();
|
void PopScope();
|
||||||
|
|
||||||
|
template<typename T> const T& ComputeAttributeValue(AttributeValue<T>& attribute);
|
||||||
|
ConstantValue ComputeConstantValue(Expression& expr);
|
||||||
|
|
||||||
std::size_t DeclareFunction(DeclareFunctionStatement& funcDecl);
|
std::size_t DeclareFunction(DeclareFunctionStatement& funcDecl);
|
||||||
|
|
||||||
void PropagateFunctionFlags(std::size_t funcIndex, FunctionFlags flags, Bitset<>& seen);
|
void PropagateFunctionFlags(std::size_t funcIndex, FunctionFlags flags, Bitset<>& seen);
|
||||||
|
|
||||||
|
std::size_t RegisterConstant(std::string name, ConstantValue value);
|
||||||
FunctionData& RegisterFunction(std::size_t functionIndex);
|
FunctionData& RegisterFunction(std::size_t functionIndex);
|
||||||
std::size_t RegisterIntrinsic(std::string name, IntrinsicType type);
|
std::size_t RegisterIntrinsic(std::string name, IntrinsicType type);
|
||||||
std::size_t RegisterOption(std::string name, ExpressionType type);
|
std::size_t RegisterStruct(std::string name, StructDescription* description);
|
||||||
std::size_t RegisterStruct(std::string name, StructDescription description);
|
|
||||||
std::size_t RegisterVariable(std::string name, ExpressionType type);
|
std::size_t RegisterVariable(std::string name, ExpressionType type);
|
||||||
|
|
||||||
void ResolveFunctions();
|
void ResolveFunctions();
|
||||||
|
|
@ -118,9 +122,9 @@ namespace Nz::ShaderAst
|
||||||
enum class Type
|
enum class Type
|
||||||
{
|
{
|
||||||
Alias,
|
Alias,
|
||||||
|
Constant,
|
||||||
Function,
|
Function,
|
||||||
Intrinsic,
|
Intrinsic,
|
||||||
Option,
|
|
||||||
Struct,
|
Struct,
|
||||||
Variable
|
Variable
|
||||||
};
|
};
|
||||||
|
|
@ -130,14 +134,6 @@ namespace Nz::ShaderAst
|
||||||
Type type;
|
Type type;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::vector<Identifier> m_identifiersInScope;
|
|
||||||
std::vector<FunctionData> m_functions;
|
|
||||||
std::vector<IntrinsicType> m_intrinsics;
|
|
||||||
std::vector<ExpressionType> m_options;
|
|
||||||
std::vector<StructDescription> m_structs;
|
|
||||||
std::vector<ExpressionType> m_variableTypes;
|
|
||||||
std::vector<std::size_t> m_scopeSizes;
|
|
||||||
|
|
||||||
struct Context;
|
struct Context;
|
||||||
Context* m_context;
|
Context* m_context;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -12,15 +12,6 @@ namespace Nz::ShaderAst
|
||||||
return Sanitize(statement, {}, error);
|
return Sanitize(statement, {}, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline auto SanitizeVisitor::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 StatementPtr Sanitize(Statement& ast, std::string* error)
|
inline StatementPtr Sanitize(Statement& ast, std::string* error)
|
||||||
{
|
{
|
||||||
SanitizeVisitor sanitizer;
|
SanitizeVisitor sanitizer;
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ namespace Nz
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char* GetFlipYUniformName();
|
static const char* GetFlipYUniformName();
|
||||||
static ShaderAst::StatementPtr Sanitize(ShaderAst::Statement& ast, std::string* error = nullptr);
|
static ShaderAst::StatementPtr Sanitize(ShaderAst::Statement& ast, UInt64 enabledConditions, std::string* error = nullptr);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void Append(const ShaderAst::ExpressionType& type);
|
void Append(const ShaderAst::ExpressionType& type);
|
||||||
|
|
@ -76,7 +76,7 @@ namespace Nz
|
||||||
void HandleEntryPoint(ShaderAst::DeclareFunctionStatement& node);
|
void HandleEntryPoint(ShaderAst::DeclareFunctionStatement& node);
|
||||||
void HandleInOut();
|
void HandleInOut();
|
||||||
|
|
||||||
void RegisterStruct(std::size_t structIndex, ShaderAst::StructDescription desc);
|
void RegisterStruct(std::size_t structIndex, ShaderAst::StructDescription* desc);
|
||||||
void RegisterVariable(std::size_t varIndex, std::string varName);
|
void RegisterVariable(std::size_t varIndex, std::string varName);
|
||||||
|
|
||||||
void Visit(ShaderAst::ExpressionPtr& expr, bool encloseIfRequired = false);
|
void Visit(ShaderAst::ExpressionPtr& expr, bool encloseIfRequired = false);
|
||||||
|
|
@ -86,7 +86,6 @@ namespace Nz
|
||||||
void Visit(ShaderAst::BinaryExpression& node) override;
|
void Visit(ShaderAst::BinaryExpression& node) override;
|
||||||
void Visit(ShaderAst::CallFunctionExpression& node) override;
|
void Visit(ShaderAst::CallFunctionExpression& node) override;
|
||||||
void Visit(ShaderAst::CastExpression& node) override;
|
void Visit(ShaderAst::CastExpression& node) override;
|
||||||
void Visit(ShaderAst::ConditionalExpression& node) override;
|
|
||||||
void Visit(ShaderAst::ConstantExpression& node) override;
|
void Visit(ShaderAst::ConstantExpression& node) override;
|
||||||
void Visit(ShaderAst::IntrinsicExpression& node) override;
|
void Visit(ShaderAst::IntrinsicExpression& node) override;
|
||||||
void Visit(ShaderAst::SwizzleExpression& node) override;
|
void Visit(ShaderAst::SwizzleExpression& node) override;
|
||||||
|
|
@ -94,7 +93,6 @@ namespace Nz
|
||||||
void Visit(ShaderAst::UnaryExpression& node) override;
|
void Visit(ShaderAst::UnaryExpression& node) override;
|
||||||
|
|
||||||
void Visit(ShaderAst::BranchStatement& node) override;
|
void Visit(ShaderAst::BranchStatement& node) override;
|
||||||
void Visit(ShaderAst::ConditionalStatement& 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;
|
||||||
|
|
|
||||||
|
|
@ -78,8 +78,8 @@ namespace Nz
|
||||||
void EnterScope();
|
void EnterScope();
|
||||||
void LeaveScope(bool skipLine = true);
|
void LeaveScope(bool skipLine = true);
|
||||||
|
|
||||||
void RegisterOption(std::size_t optionIndex, std::string optionName);
|
void RegisterConstant(std::size_t constantIndex, std::string constantName);
|
||||||
void RegisterStruct(std::size_t structIndex, ShaderAst::StructDescription desc);
|
void RegisterStruct(std::size_t structIndex, ShaderAst::StructDescription* desc);
|
||||||
void RegisterVariable(std::size_t varIndex, std::string varName);
|
void RegisterVariable(std::size_t varIndex, std::string varName);
|
||||||
|
|
||||||
void Visit(ShaderAst::ExpressionPtr& expr, bool encloseIfRequired = false);
|
void Visit(ShaderAst::ExpressionPtr& expr, bool encloseIfRequired = false);
|
||||||
|
|
@ -90,6 +90,7 @@ namespace Nz
|
||||||
void Visit(ShaderAst::CastExpression& node) override;
|
void Visit(ShaderAst::CastExpression& node) override;
|
||||||
void Visit(ShaderAst::ConditionalExpression& node) override;
|
void Visit(ShaderAst::ConditionalExpression& node) override;
|
||||||
void Visit(ShaderAst::ConstantExpression& node) override;
|
void Visit(ShaderAst::ConstantExpression& node) override;
|
||||||
|
void Visit(ShaderAst::ConstantIndexExpression& node) override;
|
||||||
void Visit(ShaderAst::IntrinsicExpression& node) override;
|
void Visit(ShaderAst::IntrinsicExpression& node) override;
|
||||||
void Visit(ShaderAst::SwizzleExpression& node) override;
|
void Visit(ShaderAst::SwizzleExpression& node) override;
|
||||||
void Visit(ShaderAst::VariableExpression& node) override;
|
void Visit(ShaderAst::VariableExpression& node) override;
|
||||||
|
|
|
||||||
|
|
@ -57,12 +57,12 @@ namespace Nz::ShaderBuilder
|
||||||
|
|
||||||
struct ConditionalExpression
|
struct ConditionalExpression
|
||||||
{
|
{
|
||||||
inline std::unique_ptr<ShaderAst::ConditionalExpression> operator()(std::size_t optionIndex, ShaderAst::ExpressionPtr truePath, ShaderAst::ExpressionPtr falsePath) const;
|
inline std::unique_ptr<ShaderAst::ConditionalExpression> operator()(ShaderAst::ExpressionPtr condition, ShaderAst::ExpressionPtr truePath, ShaderAst::ExpressionPtr falsePath) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ConditionalStatement
|
struct ConditionalStatement
|
||||||
{
|
{
|
||||||
inline std::unique_ptr<ShaderAst::ConditionalStatement> operator()(std::size_t optionIndex, ShaderAst::StatementPtr statement) const;
|
inline std::unique_ptr<ShaderAst::ConditionalStatement> operator()(ShaderAst::ExpressionPtr condition, ShaderAst::StatementPtr statement) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Constant
|
struct Constant
|
||||||
|
|
|
||||||
|
|
@ -109,20 +109,20 @@ namespace Nz::ShaderBuilder
|
||||||
return castNode;
|
return castNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::unique_ptr<ShaderAst::ConditionalExpression> Impl::ConditionalExpression::operator()(std::size_t optionIndex, ShaderAst::ExpressionPtr truePath, ShaderAst::ExpressionPtr falsePath) const
|
inline std::unique_ptr<ShaderAst::ConditionalExpression> Impl::ConditionalExpression::operator()(ShaderAst::ExpressionPtr condition, ShaderAst::ExpressionPtr truePath, ShaderAst::ExpressionPtr falsePath) const
|
||||||
{
|
{
|
||||||
auto condExprNode = std::make_unique<ShaderAst::ConditionalExpression>();
|
auto condExprNode = std::make_unique<ShaderAst::ConditionalExpression>();
|
||||||
condExprNode->optionIndex = optionIndex;
|
condExprNode->condition = std::move(condition);
|
||||||
condExprNode->falsePath = std::move(falsePath);
|
condExprNode->falsePath = std::move(falsePath);
|
||||||
condExprNode->truePath = std::move(truePath);
|
condExprNode->truePath = std::move(truePath);
|
||||||
|
|
||||||
return condExprNode;
|
return condExprNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::unique_ptr<ShaderAst::ConditionalStatement> Impl::ConditionalStatement::operator()(std::size_t optionIndex, ShaderAst::StatementPtr statement) const
|
inline std::unique_ptr<ShaderAst::ConditionalStatement> Impl::ConditionalStatement::operator()(ShaderAst::ExpressionPtr condition, ShaderAst::StatementPtr statement) const
|
||||||
{
|
{
|
||||||
auto condStatementNode = std::make_unique<ShaderAst::ConditionalStatement>();
|
auto condStatementNode = std::make_unique<ShaderAst::ConditionalStatement>();
|
||||||
condStatementNode->optionIndex = optionIndex;
|
condStatementNode->condition = std::move(condition);
|
||||||
condStatementNode->statement = std::move(statement);
|
condStatementNode->statement = std::move(statement);
|
||||||
|
|
||||||
return condStatementNode;
|
return condStatementNode;
|
||||||
|
|
@ -159,7 +159,9 @@ namespace Nz::ShaderBuilder
|
||||||
inline std::unique_ptr<ShaderAst::DeclareFunctionStatement> Impl::DeclareFunction::operator()(std::optional<ShaderStageType> entryStage, std::string name, std::vector<ShaderAst::DeclareFunctionStatement::Parameter> parameters, std::vector<ShaderAst::StatementPtr> statements, ShaderAst::ExpressionType returnType) const
|
inline std::unique_ptr<ShaderAst::DeclareFunctionStatement> Impl::DeclareFunction::operator()(std::optional<ShaderStageType> entryStage, std::string name, std::vector<ShaderAst::DeclareFunctionStatement::Parameter> parameters, std::vector<ShaderAst::StatementPtr> statements, ShaderAst::ExpressionType returnType) const
|
||||||
{
|
{
|
||||||
auto declareFunctionNode = std::make_unique<ShaderAst::DeclareFunctionStatement>();
|
auto declareFunctionNode = std::make_unique<ShaderAst::DeclareFunctionStatement>();
|
||||||
declareFunctionNode->entryStage = entryStage;
|
if (entryStage)
|
||||||
|
declareFunctionNode->entryStage = *entryStage;
|
||||||
|
|
||||||
declareFunctionNode->name = std::move(name);
|
declareFunctionNode->name = std::move(name);
|
||||||
declareFunctionNode->parameters = std::move(parameters);
|
declareFunctionNode->parameters = std::move(parameters);
|
||||||
declareFunctionNode->returnType = std::move(returnType);
|
declareFunctionNode->returnType = std::move(returnType);
|
||||||
|
|
|
||||||
|
|
@ -47,8 +47,6 @@ namespace Nz
|
||||||
void Visit(ShaderAst::BranchStatement& node) override;
|
void Visit(ShaderAst::BranchStatement& node) override;
|
||||||
void Visit(ShaderAst::CallFunctionExpression& node) override;
|
void Visit(ShaderAst::CallFunctionExpression& node) override;
|
||||||
void Visit(ShaderAst::CastExpression& node) override;
|
void Visit(ShaderAst::CastExpression& node) override;
|
||||||
void Visit(ShaderAst::ConditionalExpression& node) override;
|
|
||||||
void Visit(ShaderAst::ConditionalStatement& node) override;
|
|
||||||
void Visit(ShaderAst::ConstantExpression& node) override;
|
void Visit(ShaderAst::ConstantExpression& 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;
|
||||||
|
|
@ -142,7 +140,7 @@ namespace Nz
|
||||||
UInt32 PopResultId();
|
UInt32 PopResultId();
|
||||||
|
|
||||||
inline void RegisterExternalVariable(std::size_t varIndex, const ShaderAst::ExpressionType& type);
|
inline void RegisterExternalVariable(std::size_t varIndex, const ShaderAst::ExpressionType& type);
|
||||||
inline void RegisterStruct(std::size_t structIndex, ShaderAst::StructDescription structDesc);
|
inline void RegisterStruct(std::size_t structIndex, ShaderAst::StructDescription* structDesc);
|
||||||
inline void RegisterVariable(std::size_t varIndex, UInt32 typeId, UInt32 pointerId, SpirvStorageClass storageClass);
|
inline void RegisterVariable(std::size_t varIndex, UInt32 typeId, UInt32 pointerId, SpirvStorageClass storageClass);
|
||||||
|
|
||||||
std::size_t m_extVarIndex;
|
std::size_t m_extVarIndex;
|
||||||
|
|
@ -150,7 +148,7 @@ namespace Nz
|
||||||
std::size_t m_funcIndex;
|
std::size_t m_funcIndex;
|
||||||
std::vector<std::size_t> m_scopeSizes;
|
std::vector<std::size_t> m_scopeSizes;
|
||||||
std::vector<FuncData>& m_funcData;
|
std::vector<FuncData>& m_funcData;
|
||||||
std::vector<ShaderAst::StructDescription> m_structs;
|
std::vector<ShaderAst::StructDescription*> m_structs;
|
||||||
std::vector<std::optional<Variable>> m_variables;
|
std::vector<std::optional<Variable>> m_variables;
|
||||||
std::vector<SpirvBlock> m_functionBlocks;
|
std::vector<SpirvBlock> m_functionBlocks;
|
||||||
std::vector<UInt32> m_resultIds;
|
std::vector<UInt32> m_resultIds;
|
||||||
|
|
|
||||||
|
|
@ -25,12 +25,12 @@ namespace Nz
|
||||||
RegisterVariable(varIndex, m_writer.GetTypeId(type), pointerId, storageClass);
|
RegisterVariable(varIndex, m_writer.GetTypeId(type), pointerId, storageClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void SpirvAstVisitor::RegisterStruct(std::size_t structIndex, ShaderAst::StructDescription structDesc)
|
inline void SpirvAstVisitor::RegisterStruct(std::size_t structIndex, ShaderAst::StructDescription* structDesc)
|
||||||
{
|
{
|
||||||
if (structIndex >= m_structs.size())
|
if (structIndex >= m_structs.size())
|
||||||
m_structs.resize(structIndex + 1);
|
m_structs.resize(structIndex + 1);
|
||||||
|
|
||||||
m_structs[structIndex] = std::move(structDesc);
|
m_structs[structIndex] = structDesc;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void SpirvAstVisitor::RegisterVariable(std::size_t varIndex, UInt32 typeId, UInt32 pointerId, SpirvStorageClass storageClass)
|
inline void SpirvAstVisitor::RegisterVariable(std::size_t varIndex, UInt32 typeId, UInt32 pointerId, SpirvStorageClass storageClass)
|
||||||
|
|
|
||||||
|
|
@ -16,10 +16,8 @@ namespace Nz
|
||||||
UberShader::UberShader(ShaderStageType shaderStage, const ShaderAst::StatementPtr& shaderAst) :
|
UberShader::UberShader(ShaderStageType shaderStage, const ShaderAst::StatementPtr& shaderAst) :
|
||||||
m_shaderStage(shaderStage)
|
m_shaderStage(shaderStage)
|
||||||
{
|
{
|
||||||
ShaderAst::SanitizeVisitor::Options options;
|
//TODO: Try to partially sanitize shader?
|
||||||
options.removeOptionDeclaration = false;
|
m_shaderAst = ShaderAst::Clone(*shaderAst);
|
||||||
|
|
||||||
m_shaderAst = ShaderAst::Sanitize(*shaderAst, options);
|
|
||||||
|
|
||||||
std::size_t optionCount = 0;
|
std::size_t optionCount = 0;
|
||||||
|
|
||||||
|
|
@ -59,7 +57,6 @@ namespace Nz
|
||||||
{
|
{
|
||||||
ShaderWriter::States states;
|
ShaderWriter::States states;
|
||||||
states.enabledOptions = combination;
|
states.enabledOptions = combination;
|
||||||
states.sanitized = true;
|
|
||||||
|
|
||||||
std::shared_ptr<ShaderModule> stage = Graphics::Instance()->GetRenderDevice()->InstantiateShaderModule(m_shaderStage, *m_shaderAst, std::move(states));
|
std::shared_ptr<ShaderModule> stage = Graphics::Instance()->GetRenderDevice()->InstantiateShaderModule(m_shaderStage, *m_shaderAst, std::move(states));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -140,7 +140,7 @@ namespace Nz
|
||||||
{
|
{
|
||||||
m_states = states;
|
m_states = states;
|
||||||
m_states.sanitized = true; //< Shader is always sanitized (because of keywords)
|
m_states.sanitized = true; //< Shader is always sanitized (because of keywords)
|
||||||
std::shared_ptr<ShaderAst::Statement> sanitized = GlslWriter::Sanitize(shaderAst);
|
std::shared_ptr<ShaderAst::Statement> sanitized = GlslWriter::Sanitize(shaderAst, states.enabledOptions);
|
||||||
|
|
||||||
for (std::size_t i = 0; i < ShaderStageTypeCount; ++i)
|
for (std::size_t i = 0; i < ShaderStageTypeCount; ++i)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@ namespace Nz::ShaderAst
|
||||||
StatementPtr AstCloner::Clone(ConditionalStatement& node)
|
StatementPtr AstCloner::Clone(ConditionalStatement& node)
|
||||||
{
|
{
|
||||||
auto clone = std::make_unique<ConditionalStatement>();
|
auto clone = std::make_unique<ConditionalStatement>();
|
||||||
clone->optionIndex = node.optionIndex;
|
clone->condition = CloneExpression(node.condition);
|
||||||
clone->statement = CloneStatement(node.statement);
|
clone->statement = CloneStatement(node.statement);
|
||||||
|
|
||||||
return clone;
|
return clone;
|
||||||
|
|
@ -65,21 +65,31 @@ namespace Nz::ShaderAst
|
||||||
StatementPtr AstCloner::Clone(DeclareExternalStatement& node)
|
StatementPtr AstCloner::Clone(DeclareExternalStatement& node)
|
||||||
{
|
{
|
||||||
auto clone = std::make_unique<DeclareExternalStatement>();
|
auto clone = std::make_unique<DeclareExternalStatement>();
|
||||||
clone->externalVars = node.externalVars;
|
|
||||||
clone->varIndex = node.varIndex;
|
clone->varIndex = node.varIndex;
|
||||||
|
|
||||||
|
clone->bindingSet = CloneAttribute(node.bindingSet);
|
||||||
|
|
||||||
|
clone->externalVars.reserve(node.externalVars.size());
|
||||||
|
for (const auto& var : node.externalVars)
|
||||||
|
{
|
||||||
|
auto& cloneVar = clone->externalVars.emplace_back();
|
||||||
|
cloneVar.name = var.name;
|
||||||
|
cloneVar.type = var.type;
|
||||||
|
cloneVar.bindingIndex = CloneAttribute(var.bindingIndex);
|
||||||
|
cloneVar.bindingSet = CloneAttribute(var.bindingSet);
|
||||||
|
}
|
||||||
|
|
||||||
return clone;
|
return clone;
|
||||||
}
|
}
|
||||||
|
|
||||||
StatementPtr AstCloner::Clone(DeclareFunctionStatement& node)
|
StatementPtr AstCloner::Clone(DeclareFunctionStatement& node)
|
||||||
{
|
{
|
||||||
auto clone = std::make_unique<DeclareFunctionStatement>();
|
auto clone = std::make_unique<DeclareFunctionStatement>();
|
||||||
clone->depthWrite = node.depthWrite;
|
clone->depthWrite = CloneAttribute(node.depthWrite);
|
||||||
clone->earlyFragmentTests = node.earlyFragmentTests;
|
clone->earlyFragmentTests = CloneAttribute(node.earlyFragmentTests);
|
||||||
clone->entryStage = node.entryStage;
|
clone->entryStage = CloneAttribute(node.entryStage);
|
||||||
clone->funcIndex = node.funcIndex;
|
clone->funcIndex = node.funcIndex;
|
||||||
clone->name = node.name;
|
clone->name = node.name;
|
||||||
clone->optionName = node.optionName;
|
|
||||||
clone->parameters = node.parameters;
|
clone->parameters = node.parameters;
|
||||||
clone->returnType = node.returnType;
|
clone->returnType = node.returnType;
|
||||||
clone->varIndex = node.varIndex;
|
clone->varIndex = node.varIndex;
|
||||||
|
|
@ -106,7 +116,20 @@ namespace Nz::ShaderAst
|
||||||
{
|
{
|
||||||
auto clone = std::make_unique<DeclareStructStatement>();
|
auto clone = std::make_unique<DeclareStructStatement>();
|
||||||
clone->structIndex = node.structIndex;
|
clone->structIndex = node.structIndex;
|
||||||
clone->description = node.description;
|
|
||||||
|
clone->description.layout = CloneAttribute(node.description.layout);
|
||||||
|
clone->description.name = node.description.name;
|
||||||
|
|
||||||
|
clone->description.members.reserve(node.description.members.size());
|
||||||
|
for (const auto& member : node.description.members)
|
||||||
|
{
|
||||||
|
auto& cloneMember = clone->description.members.emplace_back();
|
||||||
|
cloneMember.name = member.name;
|
||||||
|
cloneMember.type = member.type;
|
||||||
|
cloneMember.builtin = CloneAttribute(member.builtin);
|
||||||
|
cloneMember.cond = CloneAttribute(member.cond);
|
||||||
|
cloneMember.locationIndex = CloneAttribute(member.locationIndex);
|
||||||
|
}
|
||||||
|
|
||||||
return clone;
|
return clone;
|
||||||
}
|
}
|
||||||
|
|
@ -259,7 +282,7 @@ namespace Nz::ShaderAst
|
||||||
ExpressionPtr AstCloner::Clone(ConditionalExpression& node)
|
ExpressionPtr AstCloner::Clone(ConditionalExpression& node)
|
||||||
{
|
{
|
||||||
auto clone = std::make_unique<ConditionalExpression>();
|
auto clone = std::make_unique<ConditionalExpression>();
|
||||||
clone->optionIndex = node.optionIndex;
|
clone->condition = CloneExpression(node.condition);
|
||||||
clone->falsePath = CloneExpression(node.falsePath);
|
clone->falsePath = CloneExpression(node.falsePath);
|
||||||
clone->truePath = CloneExpression(node.truePath);
|
clone->truePath = CloneExpression(node.truePath);
|
||||||
|
|
||||||
|
|
@ -268,6 +291,16 @@ namespace Nz::ShaderAst
|
||||||
return clone;
|
return clone;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ExpressionPtr AstCloner::Clone(ConstantIndexExpression& node)
|
||||||
|
{
|
||||||
|
auto clone = std::make_unique<ConstantIndexExpression>();
|
||||||
|
clone->constantId = node.constantId;
|
||||||
|
|
||||||
|
clone->cachedExpressionType = node.cachedExpressionType;
|
||||||
|
|
||||||
|
return clone;
|
||||||
|
}
|
||||||
|
|
||||||
ExpressionPtr AstCloner::Clone(ConstantExpression& node)
|
ExpressionPtr AstCloner::Clone(ConstantExpression& node)
|
||||||
{
|
{
|
||||||
auto clone = std::make_unique<ConstantExpression>();
|
auto clone = std::make_unique<ConstantExpression>();
|
||||||
|
|
|
||||||
|
|
@ -531,19 +531,6 @@ namespace Nz::ShaderAst
|
||||||
#undef EnableOptimisation
|
#undef EnableOptimisation
|
||||||
}
|
}
|
||||||
|
|
||||||
StatementPtr AstOptimizer::Optimise(Statement& statement)
|
|
||||||
{
|
|
||||||
m_enabledOptions.reset();
|
|
||||||
return CloneStatement(statement);
|
|
||||||
}
|
|
||||||
|
|
||||||
StatementPtr AstOptimizer::Optimise(Statement& statement, UInt64 enabledConditions)
|
|
||||||
{
|
|
||||||
m_enabledOptions = enabledConditions;
|
|
||||||
|
|
||||||
return CloneStatement(statement);
|
|
||||||
}
|
|
||||||
|
|
||||||
ExpressionPtr AstOptimizer::Clone(BinaryExpression& node)
|
ExpressionPtr AstOptimizer::Clone(BinaryExpression& node)
|
||||||
{
|
{
|
||||||
auto lhs = CloneExpression(node.left);
|
auto lhs = CloneExpression(node.left);
|
||||||
|
|
@ -785,15 +772,36 @@ namespace Nz::ShaderAst
|
||||||
|
|
||||||
ExpressionPtr AstOptimizer::Clone(ConditionalExpression& node)
|
ExpressionPtr AstOptimizer::Clone(ConditionalExpression& node)
|
||||||
{
|
{
|
||||||
if (!m_enabledOptions)
|
if (!m_options.enabledOptions)
|
||||||
return AstCloner::Clone(node);
|
return AstCloner::Clone(node);
|
||||||
|
|
||||||
if (TestBit<UInt64>(*m_enabledOptions, node.optionIndex))
|
auto cond = CloneExpression(node.condition);
|
||||||
|
if (cond->GetType() != NodeType::ConstantExpression)
|
||||||
|
throw std::runtime_error("conditional expression condition must be a constant expression");
|
||||||
|
|
||||||
|
auto& constant = static_cast<ConstantExpression&>(*cond);
|
||||||
|
|
||||||
|
assert(constant.cachedExpressionType);
|
||||||
|
const ExpressionType& constantType = constant.cachedExpressionType.value();
|
||||||
|
|
||||||
|
if (!IsPrimitiveType(constantType) || std::get<PrimitiveType>(constantType) != PrimitiveType::Boolean)
|
||||||
|
throw std::runtime_error("conditional expression condition must resolve to a boolean");
|
||||||
|
|
||||||
|
bool cValue = std::get<bool>(constant.value);
|
||||||
|
if (cValue)
|
||||||
return AstCloner::Clone(*node.truePath);
|
return AstCloner::Clone(*node.truePath);
|
||||||
else
|
else
|
||||||
return AstCloner::Clone(*node.falsePath);
|
return AstCloner::Clone(*node.falsePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ExpressionPtr AstOptimizer::Clone(ConstantIndexExpression& node)
|
||||||
|
{
|
||||||
|
if (!m_options.constantQueryCallback)
|
||||||
|
return AstCloner::Clone(node);
|
||||||
|
|
||||||
|
return ShaderBuilder::Constant(m_options.constantQueryCallback(node.constantId));
|
||||||
|
}
|
||||||
|
|
||||||
ExpressionPtr AstOptimizer::Clone(UnaryExpression& node)
|
ExpressionPtr AstOptimizer::Clone(UnaryExpression& node)
|
||||||
{
|
{
|
||||||
auto expr = CloneExpression(node.expression);
|
auto expr = CloneExpression(node.expression);
|
||||||
|
|
@ -830,10 +838,23 @@ namespace Nz::ShaderAst
|
||||||
|
|
||||||
StatementPtr AstOptimizer::Clone(ConditionalStatement& node)
|
StatementPtr AstOptimizer::Clone(ConditionalStatement& node)
|
||||||
{
|
{
|
||||||
if (!m_enabledOptions)
|
if (!m_options.enabledOptions)
|
||||||
return AstCloner::Clone(node);
|
return AstCloner::Clone(node);
|
||||||
|
|
||||||
if (TestBit<UInt64>(*m_enabledOptions, node.optionIndex))
|
auto cond = CloneExpression(node.condition);
|
||||||
|
if (cond->GetType() != NodeType::ConstantExpression)
|
||||||
|
throw std::runtime_error("conditional expression condition must be a constant expression");
|
||||||
|
|
||||||
|
auto& constant = static_cast<ConstantExpression&>(*cond);
|
||||||
|
|
||||||
|
assert(constant.cachedExpressionType);
|
||||||
|
const ExpressionType& constantType = constant.cachedExpressionType.value();
|
||||||
|
|
||||||
|
if (!IsPrimitiveType(constantType) || std::get<PrimitiveType>(constantType) != PrimitiveType::Boolean)
|
||||||
|
throw std::runtime_error("conditional expression condition must resolve to a boolean");
|
||||||
|
|
||||||
|
bool cValue = std::get<bool>(constant.value);
|
||||||
|
if (cValue)
|
||||||
return AstCloner::Clone(node);
|
return AstCloner::Clone(node);
|
||||||
else
|
else
|
||||||
return ShaderBuilder::NoOp();
|
return ShaderBuilder::NoOp();
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
#include <Nazara/Shader/Ast/AstRecursiveVisitor.hpp>
|
#include <Nazara/Shader/Ast/AstRecursiveVisitor.hpp>
|
||||||
#include <Nazara/Shader/Debug.hpp>
|
#include <Nazara/Shader/Debug.hpp>
|
||||||
|
#include "..\..\..\..\include\Nazara\Shader\Ast\AstRecursiveVisitor.hpp"
|
||||||
|
|
||||||
namespace Nz::ShaderAst
|
namespace Nz::ShaderAst
|
||||||
{
|
{
|
||||||
|
|
@ -67,6 +68,11 @@ namespace Nz::ShaderAst
|
||||||
/* Nothing to do */
|
/* Nothing to do */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AstRecursiveVisitor::Visit(ConstantIndexExpression& /*node*/)
|
||||||
|
{
|
||||||
|
/* Nothing to do */
|
||||||
|
}
|
||||||
|
|
||||||
void AstRecursiveVisitor::Visit(IdentifierExpression& /*node*/)
|
void AstRecursiveVisitor::Visit(IdentifierExpression& /*node*/)
|
||||||
{
|
{
|
||||||
/* Nothing to do */
|
/* Nothing to do */
|
||||||
|
|
|
||||||
|
|
@ -111,9 +111,14 @@ namespace Nz::ShaderAst
|
||||||
Node(expr);
|
Node(expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AstSerializerBase::Serialize(ConstantIndexExpression& node)
|
||||||
|
{
|
||||||
|
SizeT(node.constantId);
|
||||||
|
}
|
||||||
|
|
||||||
void AstSerializerBase::Serialize(ConditionalExpression& node)
|
void AstSerializerBase::Serialize(ConditionalExpression& node)
|
||||||
{
|
{
|
||||||
SizeT(node.optionIndex);
|
Node(node.condition);
|
||||||
Node(node.truePath);
|
Node(node.truePath);
|
||||||
Node(node.falsePath);
|
Node(node.falsePath);
|
||||||
}
|
}
|
||||||
|
|
@ -207,7 +212,7 @@ namespace Nz::ShaderAst
|
||||||
|
|
||||||
void AstSerializerBase::Serialize(ConditionalStatement& node)
|
void AstSerializerBase::Serialize(ConditionalStatement& node)
|
||||||
{
|
{
|
||||||
SizeT(node.optionIndex);
|
Node(node.condition);
|
||||||
Node(node.statement);
|
Node(node.statement);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -215,13 +220,15 @@ namespace Nz::ShaderAst
|
||||||
{
|
{
|
||||||
OptVal(node.varIndex);
|
OptVal(node.varIndex);
|
||||||
|
|
||||||
|
Attribute(node.bindingSet);
|
||||||
|
|
||||||
Container(node.externalVars);
|
Container(node.externalVars);
|
||||||
for (auto& extVar : node.externalVars)
|
for (auto& extVar : node.externalVars)
|
||||||
{
|
{
|
||||||
Value(extVar.name);
|
Value(extVar.name);
|
||||||
Type(extVar.type);
|
Type(extVar.type);
|
||||||
OptVal(extVar.bindingIndex);
|
Attribute(extVar.bindingIndex);
|
||||||
OptVal(extVar.bindingSet);
|
Attribute(extVar.bindingSet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -229,11 +236,10 @@ namespace Nz::ShaderAst
|
||||||
{
|
{
|
||||||
Value(node.name);
|
Value(node.name);
|
||||||
Type(node.returnType);
|
Type(node.returnType);
|
||||||
OptEnum(node.depthWrite);
|
Attribute(node.depthWrite);
|
||||||
OptVal(node.earlyFragmentTests);
|
Attribute(node.earlyFragmentTests);
|
||||||
OptEnum(node.entryStage);
|
Attribute(node.entryStage);
|
||||||
OptVal(node.funcIndex);
|
OptVal(node.funcIndex);
|
||||||
Value(node.optionName);
|
|
||||||
OptVal(node.varIndex);
|
OptVal(node.varIndex);
|
||||||
|
|
||||||
Container(node.parameters);
|
Container(node.parameters);
|
||||||
|
|
@ -261,15 +267,16 @@ namespace Nz::ShaderAst
|
||||||
OptVal(node.structIndex);
|
OptVal(node.structIndex);
|
||||||
|
|
||||||
Value(node.description.name);
|
Value(node.description.name);
|
||||||
OptEnum(node.description.layout);
|
Attribute(node.description.layout);
|
||||||
|
|
||||||
Container(node.description.members);
|
Container(node.description.members);
|
||||||
for (auto& member : node.description.members)
|
for (auto& member : node.description.members)
|
||||||
{
|
{
|
||||||
Value(member.name);
|
Value(member.name);
|
||||||
Type(member.type);
|
Type(member.type);
|
||||||
OptEnum(member.builtin);
|
Attribute(member.builtin);
|
||||||
OptVal(member.locationIndex);
|
Attribute(member.cond);
|
||||||
|
Attribute(member.locationIndex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -535,6 +542,7 @@ namespace Nz::ShaderAst
|
||||||
|
|
||||||
#define NAZARA_SHADERAST_STATEMENT(Node) case NodeType:: Node : node = std::make_unique<Node>(); break;
|
#define NAZARA_SHADERAST_STATEMENT(Node) case NodeType:: Node : node = std::make_unique<Node>(); break;
|
||||||
#include <Nazara/Shader/Ast/AstNodeList.hpp>
|
#include <Nazara/Shader/Ast/AstNodeList.hpp>
|
||||||
|
#include "..\..\..\..\include\Nazara\Shader\Ast\AstSerializer.hpp"
|
||||||
|
|
||||||
default: throw std::runtime_error("unexpected node type");
|
default: throw std::runtime_error("unexpected node type");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -67,6 +67,11 @@ namespace Nz::ShaderAst
|
||||||
m_expressionCategory = ExpressionCategory::RValue;
|
m_expressionCategory = ExpressionCategory::RValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ShaderAstValueCategory::Visit(ConstantIndexExpression& /*node*/)
|
||||||
|
{
|
||||||
|
m_expressionCategory = ExpressionCategory::LValue;
|
||||||
|
}
|
||||||
|
|
||||||
void ShaderAstValueCategory::Visit(IdentifierExpression& /*node*/)
|
void ShaderAstValueCategory::Visit(IdentifierExpression& /*node*/)
|
||||||
{
|
{
|
||||||
m_expressionCategory = ExpressionCategory::LValue;
|
m_expressionCategory = ExpressionCategory::LValue;
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@
|
||||||
#include <Nazara/Core/StackArray.hpp>
|
#include <Nazara/Core/StackArray.hpp>
|
||||||
#include <Nazara/Shader/ShaderBuilder.hpp>
|
#include <Nazara/Shader/ShaderBuilder.hpp>
|
||||||
#include <Nazara/Shader/Ast/AstRecursiveVisitor.hpp>
|
#include <Nazara/Shader/Ast/AstRecursiveVisitor.hpp>
|
||||||
|
#include <Nazara/Shader/Ast/AstOptimizer.hpp>
|
||||||
#include <Nazara/Shader/Ast/AstUtils.hpp>
|
#include <Nazara/Shader/Ast/AstUtils.hpp>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
|
|
@ -30,7 +31,7 @@ namespace Nz::ShaderAst
|
||||||
|
|
||||||
struct SanitizeVisitor::Context
|
struct SanitizeVisitor::Context
|
||||||
{
|
{
|
||||||
struct FunctionData
|
struct CurrentFunctionData
|
||||||
{
|
{
|
||||||
std::optional<ShaderStageType> stageType;
|
std::optional<ShaderStageType> stageType;
|
||||||
Bitset<> calledFunctions;
|
Bitset<> calledFunctions;
|
||||||
|
|
@ -38,11 +39,19 @@ namespace Nz::ShaderAst
|
||||||
FunctionFlags flags;
|
FunctionFlags flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
std::size_t nextOptionIndex = 0;
|
||||||
Options options;
|
Options options;
|
||||||
std::array<DeclareFunctionStatement*, ShaderStageTypeCount> entryFunctions = {};
|
std::array<DeclareFunctionStatement*, ShaderStageTypeCount> entryFunctions = {};
|
||||||
std::unordered_set<std::string> declaredExternalVar;
|
std::unordered_set<std::string> declaredExternalVar;
|
||||||
std::unordered_set<UInt64> usedBindingIndexes;
|
std::unordered_set<UInt64> usedBindingIndexes;
|
||||||
FunctionData* currentFunction = nullptr;
|
std::vector<Identifier> identifiersInScope;
|
||||||
|
std::vector<ConstantValue> constantValues;
|
||||||
|
std::vector<FunctionData> functions;
|
||||||
|
std::vector<IntrinsicType> intrinsics;
|
||||||
|
std::vector<StructDescription*> structs;
|
||||||
|
std::vector<ExpressionType> variableTypes;
|
||||||
|
std::vector<std::size_t> scopeSizes;
|
||||||
|
CurrentFunctionData* currentFunction = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
StatementPtr SanitizeVisitor::Sanitize(Statement& statement, const Options& options, std::string* error)
|
StatementPtr SanitizeVisitor::Sanitize(Statement& statement, const Options& options, std::string* error)
|
||||||
|
|
@ -123,14 +132,23 @@ namespace Nz::ShaderAst
|
||||||
accessIndexPtr = static_cast<AccessIndexExpression*>(indexedExpr.get());
|
accessIndexPtr = static_cast<AccessIndexExpression*>(indexedExpr.get());
|
||||||
|
|
||||||
std::size_t structIndex = ResolveStruct(exprType);
|
std::size_t structIndex = ResolveStruct(exprType);
|
||||||
assert(structIndex < m_structs.size());
|
assert(structIndex < m_context->structs.size());
|
||||||
const StructDescription& s = m_structs[structIndex];
|
const StructDescription* s = m_context->structs[structIndex];
|
||||||
|
|
||||||
auto it = std::find_if(s.members.begin(), s.members.end(), [&](const auto& field) { return field.name == identifier; });
|
auto it = std::find_if(s->members.begin(), s->members.end(), [&](const auto& field)
|
||||||
if (it == s.members.end())
|
{
|
||||||
|
if (field.name != identifier)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (field.cond.HasValue() && !field.cond.GetResultingValue())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
if (it == s->members.end())
|
||||||
throw AstError{ "unknown field " + identifier };
|
throw AstError{ "unknown field " + identifier };
|
||||||
|
|
||||||
accessIndexPtr->indices.push_back(ShaderBuilder::Constant(Int32(std::distance(s.members.begin(), it))));
|
accessIndexPtr->indices.push_back(ShaderBuilder::Constant(Int32(std::distance(s->members.begin(), it))));
|
||||||
accessIndexPtr->cachedExpressionType = ResolveType(it->type);
|
accessIndexPtr->cachedExpressionType = ResolveType(it->type);
|
||||||
}
|
}
|
||||||
else if (IsVectorType(exprType))
|
else if (IsVectorType(exprType))
|
||||||
|
|
@ -419,7 +437,7 @@ namespace Nz::ShaderAst
|
||||||
for (const auto& param : node.parameters)
|
for (const auto& param : node.parameters)
|
||||||
parameters.push_back(CloneExpression(param));
|
parameters.push_back(CloneExpression(param));
|
||||||
|
|
||||||
auto intrinsic = ShaderBuilder::Intrinsic(m_intrinsics[identifier->index], std::move(parameters));
|
auto intrinsic = ShaderBuilder::Intrinsic(m_context->intrinsics[identifier->index], std::move(parameters));
|
||||||
Validate(*intrinsic);
|
Validate(*intrinsic);
|
||||||
|
|
||||||
return intrinsic;
|
return intrinsic;
|
||||||
|
|
@ -437,11 +455,11 @@ namespace Nz::ShaderAst
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Identifier not found, maybe the function is declared later
|
// Identifier not found, maybe the function is declared later
|
||||||
auto it = std::find_if(m_functions.begin(), m_functions.end(), [&](const auto& funcData) { return funcData.node->name == functionName; });
|
auto it = std::find_if(m_context->functions.begin(), m_context->functions.end(), [&](const auto& funcData) { return funcData.node->name == functionName; });
|
||||||
if (it == m_functions.end())
|
if (it == m_context->functions.end())
|
||||||
throw AstError{ "function " + functionName + " does not exist" };
|
throw AstError{ "function " + functionName + " does not exist" };
|
||||||
|
|
||||||
targetFuncIndex = std::distance(m_functions.begin(), it);
|
targetFuncIndex = std::distance(m_context->functions.begin(), it);
|
||||||
|
|
||||||
clone->targetFunction = targetFuncIndex;
|
clone->targetFunction = targetFuncIndex;
|
||||||
}
|
}
|
||||||
|
|
@ -451,7 +469,7 @@ namespace Nz::ShaderAst
|
||||||
|
|
||||||
m_context->currentFunction->calledFunctions.UnboundedSet(targetFuncIndex);
|
m_context->currentFunction->calledFunctions.UnboundedSet(targetFuncIndex);
|
||||||
|
|
||||||
Validate(*clone, m_functions[targetFuncIndex].node);
|
Validate(*clone, m_context->functions[targetFuncIndex].node);
|
||||||
|
|
||||||
return clone;
|
return clone;
|
||||||
}
|
}
|
||||||
|
|
@ -507,18 +525,18 @@ namespace Nz::ShaderAst
|
||||||
|
|
||||||
ExpressionPtr SanitizeVisitor::Clone(ConditionalExpression& node)
|
ExpressionPtr SanitizeVisitor::Clone(ConditionalExpression& node)
|
||||||
{
|
{
|
||||||
|
MandatoryExpr(node.condition);
|
||||||
MandatoryExpr(node.truePath);
|
MandatoryExpr(node.truePath);
|
||||||
MandatoryExpr(node.falsePath);
|
MandatoryExpr(node.falsePath);
|
||||||
|
|
||||||
auto clone = static_unique_pointer_cast<ConditionalExpression>(AstCloner::Clone(node));
|
ConstantValue conditionValue = ComputeConstantValue(*AstCloner::Clone(*node.condition));
|
||||||
|
if (GetExpressionType(conditionValue) != ExpressionType{ PrimitiveType::Boolean })
|
||||||
|
throw AstError{ "expected a boolean value" };
|
||||||
|
|
||||||
const ExpressionType& leftExprType = GetExpressionType(*clone->truePath);
|
if (std::get<bool>(conditionValue))
|
||||||
if (leftExprType != GetExpressionType(*clone->falsePath))
|
return AstCloner::Clone(*node.truePath);
|
||||||
throw AstError{ "true path type must match false path type" };
|
else
|
||||||
|
return AstCloner::Clone(*node.falsePath);
|
||||||
clone->cachedExpressionType = leftExprType;
|
|
||||||
|
|
||||||
return clone;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ExpressionPtr SanitizeVisitor::Clone(ConstantExpression& node)
|
ExpressionPtr SanitizeVisitor::Clone(ConstantExpression& node)
|
||||||
|
|
@ -537,15 +555,31 @@ namespace Nz::ShaderAst
|
||||||
if (!identifier)
|
if (!identifier)
|
||||||
throw AstError{ "unknown identifier " + node.identifier };
|
throw AstError{ "unknown identifier " + node.identifier };
|
||||||
|
|
||||||
if (identifier->type != Identifier::Type::Variable)
|
switch (identifier->type)
|
||||||
throw AstError{ "expected variable identifier" };
|
{
|
||||||
|
case Identifier::Type::Constant:
|
||||||
|
{
|
||||||
|
// Replace IdentifierExpression by ConstantIndexExpression
|
||||||
|
auto constantExpr = std::make_unique<ConstantIndexExpression>();
|
||||||
|
constantExpr->cachedExpressionType = GetExpressionType(m_context->constantValues[identifier->index]);
|
||||||
|
constantExpr->constantId = identifier->index;
|
||||||
|
|
||||||
// Replace IdentifierExpression by VariableExpression
|
return constantExpr;
|
||||||
auto varExpr = std::make_unique<VariableExpression>();
|
}
|
||||||
varExpr->cachedExpressionType = m_variableTypes[identifier->index];
|
|
||||||
varExpr->variableId = identifier->index;
|
|
||||||
|
|
||||||
return varExpr;
|
case Identifier::Type::Variable:
|
||||||
|
{
|
||||||
|
// Replace IdentifierExpression by VariableExpression
|
||||||
|
auto varExpr = std::make_unique<VariableExpression>();
|
||||||
|
varExpr->cachedExpressionType = m_context->variableTypes[identifier->index];
|
||||||
|
varExpr->variableId = identifier->index;
|
||||||
|
|
||||||
|
return varExpr;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw AstError{ "expected constant or variable identifier" };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ExpressionPtr SanitizeVisitor::Clone(IntrinsicExpression& node)
|
ExpressionPtr SanitizeVisitor::Clone(IntrinsicExpression& node)
|
||||||
|
|
@ -561,26 +595,20 @@ namespace Nz::ShaderAst
|
||||||
MandatoryExpr(node.truePath);
|
MandatoryExpr(node.truePath);
|
||||||
MandatoryExpr(node.falsePath);
|
MandatoryExpr(node.falsePath);
|
||||||
|
|
||||||
auto condExpr = std::make_unique<ConditionalExpression>();
|
|
||||||
condExpr->truePath = CloneExpression(node.truePath);
|
|
||||||
condExpr->falsePath = CloneExpression(node.falsePath);
|
|
||||||
|
|
||||||
const Identifier* identifier = FindIdentifier(node.optionName);
|
const Identifier* identifier = FindIdentifier(node.optionName);
|
||||||
if (!identifier)
|
if (!identifier)
|
||||||
throw AstError{ "unknown option " + node.optionName };
|
throw AstError{ "unknown constant " + node.optionName };
|
||||||
|
|
||||||
if (identifier->type != Identifier::Type::Option)
|
if (identifier->type != Identifier::Type::Constant)
|
||||||
throw AstError{ "expected option identifier" };
|
throw AstError{ "expected constant identifier" };
|
||||||
|
|
||||||
condExpr->optionIndex = identifier->index;
|
if (GetExpressionType(m_context->constantValues[identifier->index]) != ExpressionType{ PrimitiveType::Boolean })
|
||||||
|
throw AstError{ "constant is not a boolean" };
|
||||||
|
|
||||||
const ExpressionType& leftExprType = GetExpressionType(*condExpr->truePath);
|
if (std::get<bool>(m_context->constantValues[identifier->index]))
|
||||||
if (leftExprType != GetExpressionType(*condExpr->falsePath))
|
return CloneExpression(node.truePath);
|
||||||
throw AstError{ "true path type must match false path type" };
|
else
|
||||||
|
return CloneExpression(node.falsePath);
|
||||||
condExpr->cachedExpressionType = leftExprType;
|
|
||||||
|
|
||||||
return condExpr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ExpressionPtr SanitizeVisitor::Clone(SwizzleExpression& node)
|
ExpressionPtr SanitizeVisitor::Clone(SwizzleExpression& node)
|
||||||
|
|
@ -687,43 +715,54 @@ namespace Nz::ShaderAst
|
||||||
|
|
||||||
StatementPtr SanitizeVisitor::Clone(ConditionalStatement& node)
|
StatementPtr SanitizeVisitor::Clone(ConditionalStatement& node)
|
||||||
{
|
{
|
||||||
|
MandatoryExpr(node.condition);
|
||||||
MandatoryStatement(node.statement);
|
MandatoryStatement(node.statement);
|
||||||
|
|
||||||
PushScope();
|
ConstantValue conditionValue = ComputeConstantValue(*AstCloner::Clone(*node.condition));
|
||||||
|
if (GetExpressionType(conditionValue) != ExpressionType{ PrimitiveType::Boolean })
|
||||||
|
throw AstError{ "expected a boolean value" };
|
||||||
|
|
||||||
auto clone = static_unique_pointer_cast<ConditionalStatement>(AstCloner::Clone(node));
|
if (std::get<bool>(conditionValue))
|
||||||
|
return AstCloner::Clone(*node.statement);
|
||||||
PopScope();
|
else
|
||||||
|
return ShaderBuilder::NoOp();
|
||||||
return clone;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
StatementPtr SanitizeVisitor::Clone(DeclareExternalStatement& node)
|
StatementPtr SanitizeVisitor::Clone(DeclareExternalStatement& node)
|
||||||
{
|
{
|
||||||
assert(m_context);
|
assert(m_context);
|
||||||
|
|
||||||
for (const auto& extVar : node.externalVars)
|
auto clone = static_unique_pointer_cast<DeclareExternalStatement>(AstCloner::Clone(node));
|
||||||
|
|
||||||
|
UInt32 defaultBlockSet = 0;
|
||||||
|
if (clone->bindingSet.HasValue())
|
||||||
|
defaultBlockSet = ComputeAttributeValue(clone->bindingSet);
|
||||||
|
|
||||||
|
for (auto& extVar : clone->externalVars)
|
||||||
{
|
{
|
||||||
if (!extVar.bindingIndex)
|
if (!extVar.bindingIndex.HasValue())
|
||||||
throw AstError{ "external variable " + extVar.name + " requires a binding index" };
|
throw AstError{ "external variable " + extVar.name + " requires a binding index" };
|
||||||
|
|
||||||
UInt64 bindingIndex = *extVar.bindingIndex;
|
if (extVar.bindingSet.HasValue())
|
||||||
UInt64 bindingSet = extVar.bindingSet.value_or(0);
|
ComputeAttributeValue(extVar.bindingSet);
|
||||||
|
else
|
||||||
|
extVar.bindingSet = defaultBlockSet;
|
||||||
|
|
||||||
|
UInt64 bindingSet = extVar.bindingSet.GetResultingValue();
|
||||||
|
|
||||||
|
UInt64 bindingIndex = ComputeAttributeValue(extVar.bindingIndex);
|
||||||
|
|
||||||
UInt64 bindingKey = bindingSet << 32 | bindingIndex;
|
UInt64 bindingKey = bindingSet << 32 | bindingIndex;
|
||||||
if (m_context->usedBindingIndexes.find(bindingKey) != m_context->usedBindingIndexes.end())
|
if (m_context->usedBindingIndexes.find(bindingKey) != m_context->usedBindingIndexes.end())
|
||||||
throw AstError{ "Binding (set=" + std::to_string(bindingSet) + ", binding=" + std::to_string(bindingIndex) + ") is already in use" };
|
throw AstError{ "binding (set=" + std::to_string(bindingSet) + ", binding=" + std::to_string(bindingIndex) + ") is already in use" };
|
||||||
|
|
||||||
m_context->usedBindingIndexes.insert(bindingKey);
|
m_context->usedBindingIndexes.insert(bindingKey);
|
||||||
|
|
||||||
if (m_context->declaredExternalVar.find(extVar.name) != m_context->declaredExternalVar.end())
|
if (m_context->declaredExternalVar.find(extVar.name) != m_context->declaredExternalVar.end())
|
||||||
throw AstError{ "External variable " + extVar.name + " is already declared" };
|
throw AstError{ "external variable " + extVar.name + " is already declared" };
|
||||||
|
|
||||||
m_context->declaredExternalVar.insert(extVar.name);
|
m_context->declaredExternalVar.insert(extVar.name);
|
||||||
}
|
|
||||||
|
|
||||||
auto clone = static_unique_pointer_cast<DeclareExternalStatement>(AstCloner::Clone(node));
|
|
||||||
for (auto& extVar : clone->externalVars)
|
|
||||||
{
|
|
||||||
extVar.type = ResolveType(extVar.type);
|
extVar.type = ResolveType(extVar.type);
|
||||||
|
|
||||||
ExpressionType varType;
|
ExpressionType varType;
|
||||||
|
|
@ -746,9 +785,23 @@ namespace Nz::ShaderAst
|
||||||
|
|
||||||
StatementPtr SanitizeVisitor::Clone(DeclareFunctionStatement& node)
|
StatementPtr SanitizeVisitor::Clone(DeclareFunctionStatement& node)
|
||||||
{
|
{
|
||||||
if (node.entryStage)
|
auto clone = std::make_unique<DeclareFunctionStatement>();
|
||||||
|
clone->name = node.name;
|
||||||
|
clone->parameters = node.parameters;
|
||||||
|
clone->returnType = ResolveType(node.returnType);
|
||||||
|
|
||||||
|
if (node.depthWrite.HasValue())
|
||||||
|
clone->depthWrite = ComputeAttributeValue(node.depthWrite);
|
||||||
|
|
||||||
|
if (node.earlyFragmentTests.HasValue())
|
||||||
|
clone->earlyFragmentTests = ComputeAttributeValue(node.earlyFragmentTests);
|
||||||
|
|
||||||
|
if (node.entryStage.HasValue())
|
||||||
|
clone->entryStage = ComputeAttributeValue(node.entryStage);
|
||||||
|
|
||||||
|
if (clone->entryStage.HasValue())
|
||||||
{
|
{
|
||||||
ShaderStageType stageType = *node.entryStage;
|
ShaderStageType stageType = clone->entryStage.GetResultingValue();
|
||||||
|
|
||||||
if (m_context->entryFunctions[UnderlyingCast(stageType)])
|
if (m_context->entryFunctions[UnderlyingCast(stageType)])
|
||||||
throw AstError{ "the same entry type has been defined multiple times" };
|
throw AstError{ "the same entry type has been defined multiple times" };
|
||||||
|
|
@ -760,26 +813,17 @@ namespace Nz::ShaderAst
|
||||||
|
|
||||||
if (stageType != ShaderStageType::Fragment)
|
if (stageType != ShaderStageType::Fragment)
|
||||||
{
|
{
|
||||||
if (node.depthWrite.has_value())
|
if (node.depthWrite.HasValue())
|
||||||
throw AstError{ "only fragment entry-points can have the depth_write attribute" };
|
throw AstError{ "only fragment entry-points can have the depth_write attribute" };
|
||||||
|
|
||||||
if (node.earlyFragmentTests.has_value())
|
if (node.earlyFragmentTests.HasValue())
|
||||||
throw AstError{ "only functions with entry(frag) attribute can have the early_fragments_tests attribute" };
|
throw AstError{ "only functions with entry(frag) attribute can have the early_fragments_tests attribute" };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto clone = std::make_unique<DeclareFunctionStatement>();
|
Context::CurrentFunctionData tempFuncData;
|
||||||
clone->depthWrite = node.depthWrite;
|
if (node.entryStage.HasValue())
|
||||||
clone->earlyFragmentTests = node.earlyFragmentTests;
|
tempFuncData.stageType = node.entryStage.GetResultingValue();
|
||||||
clone->entryStage = node.entryStage;
|
|
||||||
clone->name = node.name;
|
|
||||||
clone->optionName = node.optionName;
|
|
||||||
clone->parameters = node.parameters;
|
|
||||||
clone->returnType = ResolveType(node.returnType);
|
|
||||||
|
|
||||||
|
|
||||||
Context::FunctionData tempFuncData;
|
|
||||||
tempFuncData.stageType = node.entryStage;
|
|
||||||
|
|
||||||
m_context->currentFunction = &tempFuncData;
|
m_context->currentFunction = &tempFuncData;
|
||||||
|
|
||||||
|
|
@ -803,31 +847,17 @@ namespace Nz::ShaderAst
|
||||||
|
|
||||||
m_context->currentFunction = nullptr;
|
m_context->currentFunction = nullptr;
|
||||||
|
|
||||||
if (clone->earlyFragmentTests.has_value() && *clone->earlyFragmentTests)
|
if (clone->earlyFragmentTests.HasValue() && clone->earlyFragmentTests.GetResultingValue())
|
||||||
{
|
{
|
||||||
//TODO: warning and disable early fragment tests
|
//TODO: warning and disable early fragment tests
|
||||||
throw AstError{ "discard is not compatible with early fragment tests" };
|
throw AstError{ "discard is not compatible with early fragment tests" };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!clone->optionName.empty())
|
auto it = std::find_if(m_context->functions.begin(), m_context->functions.end(), [&](const auto& funcData) { return funcData.node == &node; });
|
||||||
{
|
assert(it != m_context->functions.end());
|
||||||
const Identifier* identifier = FindIdentifier(node.optionName);
|
|
||||||
if (!identifier)
|
|
||||||
throw AstError{ "unknown option " + node.optionName };
|
|
||||||
|
|
||||||
if (identifier->type != Identifier::Type::Option)
|
|
||||||
throw AstError{ "expected option identifier" };
|
|
||||||
|
|
||||||
std::size_t optionIndex = identifier->index;
|
|
||||||
|
|
||||||
return ShaderBuilder::ConditionalStatement(optionIndex, std::move(clone));
|
|
||||||
}
|
|
||||||
|
|
||||||
auto it = std::find_if(m_functions.begin(), m_functions.end(), [&](const auto& funcData) { return funcData.node == &node; });
|
|
||||||
assert(it != m_functions.end());
|
|
||||||
assert(!it->defined);
|
assert(!it->defined);
|
||||||
|
|
||||||
std::size_t funcIndex = std::distance(m_functions.begin(), it);
|
std::size_t funcIndex = std::distance(m_context->functions.begin(), it);
|
||||||
|
|
||||||
clone->funcIndex = funcIndex;
|
clone->funcIndex = funcIndex;
|
||||||
|
|
||||||
|
|
@ -836,8 +866,8 @@ namespace Nz::ShaderAst
|
||||||
|
|
||||||
for (std::size_t i = tempFuncData.calledFunctions.FindFirst(); i != tempFuncData.calledFunctions.npos; i = tempFuncData.calledFunctions.FindNext(i))
|
for (std::size_t i = tempFuncData.calledFunctions.FindFirst(); i != tempFuncData.calledFunctions.npos; i = tempFuncData.calledFunctions.FindNext(i))
|
||||||
{
|
{
|
||||||
assert(i < m_functions.size());
|
assert(i < m_context->functions.size());
|
||||||
auto& targetFunc = m_functions[i];
|
auto& targetFunc = m_context->functions[i];
|
||||||
targetFunc.calledByFunctions.UnboundedSet(funcIndex);
|
targetFunc.calledByFunctions.UnboundedSet(funcIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -854,7 +884,9 @@ namespace Nz::ShaderAst
|
||||||
if (clone->initialValue && clone->optType != GetExpressionType(*clone->initialValue))
|
if (clone->initialValue && clone->optType != GetExpressionType(*clone->initialValue))
|
||||||
throw AstError{ "option " + clone->optName + " initial expression must be of the same type than the option" };
|
throw AstError{ "option " + clone->optName + " initial expression must be of the same type than the option" };
|
||||||
|
|
||||||
clone->optIndex = RegisterOption(clone->optName, clone->optType);
|
std::size_t optionIndex = m_context->nextOptionIndex++;
|
||||||
|
|
||||||
|
clone->optIndex = RegisterConstant(clone->optName, TestBit(m_context->options.enabledOptions, optionIndex));
|
||||||
|
|
||||||
if (m_context->options.removeOptionDeclaration)
|
if (m_context->options.removeOptionDeclaration)
|
||||||
return ShaderBuilder::NoOp();
|
return ShaderBuilder::NoOp();
|
||||||
|
|
@ -864,22 +896,33 @@ namespace Nz::ShaderAst
|
||||||
|
|
||||||
StatementPtr SanitizeVisitor::Clone(DeclareStructStatement& node)
|
StatementPtr SanitizeVisitor::Clone(DeclareStructStatement& node)
|
||||||
{
|
{
|
||||||
std::unordered_set<std::string> declaredMembers;
|
auto clone = static_unique_pointer_cast<DeclareStructStatement>(AstCloner::Clone(node));
|
||||||
|
|
||||||
for (auto& member : node.description.members)
|
std::unordered_set<std::string> declaredMembers;
|
||||||
|
for (auto& member : clone->description.members)
|
||||||
{
|
{
|
||||||
|
if (member.cond.HasValue())
|
||||||
|
{
|
||||||
|
member.cond = ComputeAttributeValue(member.cond);
|
||||||
|
if (!member.cond.GetResultingValue())
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (member.builtin.HasValue())
|
||||||
|
member.builtin = ComputeAttributeValue(member.builtin);
|
||||||
|
|
||||||
|
if (member.locationIndex.HasValue())
|
||||||
|
member.locationIndex = ComputeAttributeValue(member.locationIndex);
|
||||||
|
|
||||||
if (declaredMembers.find(member.name) != declaredMembers.end())
|
if (declaredMembers.find(member.name) != declaredMembers.end())
|
||||||
throw AstError{ "struct member " + member.name + " found multiple time" };
|
throw AstError{ "struct member " + member.name + " found multiple time" };
|
||||||
|
|
||||||
declaredMembers.insert(member.name);
|
declaredMembers.insert(member.name);
|
||||||
|
|
||||||
|
member.type = ResolveType(member.type);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto clone = static_unique_pointer_cast<DeclareStructStatement>(AstCloner::Clone(node));
|
clone->structIndex = RegisterStruct(clone->description.name, &clone->description);
|
||||||
|
|
||||||
for (auto& member : clone->description.members)
|
|
||||||
member.type = ResolveType(member.type);
|
|
||||||
|
|
||||||
clone->structIndex = RegisterStruct(clone->description.name, clone->description);
|
|
||||||
|
|
||||||
SanitizeIdentifier(clone->description.name);
|
SanitizeIdentifier(clone->description.name);
|
||||||
|
|
||||||
|
|
@ -951,6 +994,15 @@ namespace Nz::ShaderAst
|
||||||
return clone;
|
return clone;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto SanitizeVisitor::FindIdentifier(const std::string_view& identifierName) const -> const Identifier*
|
||||||
|
{
|
||||||
|
auto it = std::find_if(m_context->identifiersInScope.rbegin(), m_context->identifiersInScope.rend(), [&](const Identifier& identifier) { return identifier.name == identifierName; });
|
||||||
|
if (it == m_context->identifiersInScope.rend())
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
return &*it;
|
||||||
|
}
|
||||||
|
|
||||||
Expression& SanitizeVisitor::MandatoryExpr(ExpressionPtr& node)
|
Expression& SanitizeVisitor::MandatoryExpr(ExpressionPtr& node)
|
||||||
{
|
{
|
||||||
if (!node)
|
if (!node)
|
||||||
|
|
@ -969,20 +1021,69 @@ namespace Nz::ShaderAst
|
||||||
|
|
||||||
void SanitizeVisitor::PushScope()
|
void SanitizeVisitor::PushScope()
|
||||||
{
|
{
|
||||||
m_scopeSizes.push_back(m_identifiersInScope.size());
|
m_context->scopeSizes.push_back(m_context->identifiersInScope.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
void SanitizeVisitor::PopScope()
|
void SanitizeVisitor::PopScope()
|
||||||
{
|
{
|
||||||
assert(!m_scopeSizes.empty());
|
assert(!m_context->scopeSizes.empty());
|
||||||
m_identifiersInScope.resize(m_scopeSizes.back());
|
m_context->identifiersInScope.resize(m_context->scopeSizes.back());
|
||||||
m_scopeSizes.pop_back();
|
m_context->scopeSizes.pop_back();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
const T& SanitizeVisitor::ComputeAttributeValue(AttributeValue<T>& attribute)
|
||||||
|
{
|
||||||
|
if (!attribute.HasValue())
|
||||||
|
throw AstError{"attribute expected a value"};
|
||||||
|
|
||||||
|
if (attribute.IsExpression())
|
||||||
|
{
|
||||||
|
ConstantValue value = ComputeConstantValue(*attribute.GetExpression());
|
||||||
|
if constexpr (TypeListFind<ConstantTypes, T>)
|
||||||
|
{
|
||||||
|
if (!std::holds_alternative<T>(value))
|
||||||
|
{
|
||||||
|
// HAAAAAX
|
||||||
|
if (std::holds_alternative<Int32>(value) && std::is_same_v<T, UInt32>)
|
||||||
|
attribute = static_cast<UInt32>(std::get<Int32>(value));
|
||||||
|
else
|
||||||
|
throw AstError{ "unexpected attribute type" };
|
||||||
|
}
|
||||||
|
else
|
||||||
|
attribute = std::get<T>(value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
throw AstError{ "unexpected expression for this type" };
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(attribute.IsResultingValue());
|
||||||
|
return attribute.GetResultingValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
ConstantValue SanitizeVisitor::ComputeConstantValue(Expression& expr)
|
||||||
|
{
|
||||||
|
AstOptimizer::Options optimizerOptions;
|
||||||
|
optimizerOptions.constantQueryCallback = [this](std::size_t constantId)
|
||||||
|
{
|
||||||
|
assert(constantId < m_context->constantValues.size());
|
||||||
|
return m_context->constantValues[constantId];
|
||||||
|
};
|
||||||
|
|
||||||
|
optimizerOptions.enabledOptions = m_context->options.enabledOptions;
|
||||||
|
|
||||||
|
// Run optimizer on constant value to hopefully retrieve a single constant value
|
||||||
|
ExpressionPtr optimizedExpr = Optimize(expr, optimizerOptions);
|
||||||
|
if (optimizedExpr->GetType() != NodeType::ConstantExpression)
|
||||||
|
throw AstError{"expected a constant expression"};
|
||||||
|
|
||||||
|
return static_cast<ConstantExpression&>(*optimizedExpr).value;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t SanitizeVisitor::DeclareFunction(DeclareFunctionStatement& funcDecl)
|
std::size_t SanitizeVisitor::DeclareFunction(DeclareFunctionStatement& funcDecl)
|
||||||
{
|
{
|
||||||
std::size_t functionIndex = m_functions.size();
|
std::size_t functionIndex = m_context->functions.size();
|
||||||
auto& funcData = m_functions.emplace_back();
|
auto& funcData = m_context->functions.emplace_back();
|
||||||
funcData.node = &funcDecl;
|
funcData.node = &funcDecl;
|
||||||
|
|
||||||
return functionIndex;
|
return functionIndex;
|
||||||
|
|
@ -990,8 +1091,8 @@ namespace Nz::ShaderAst
|
||||||
|
|
||||||
void SanitizeVisitor::PropagateFunctionFlags(std::size_t funcIndex, FunctionFlags flags, Bitset<>& seen)
|
void SanitizeVisitor::PropagateFunctionFlags(std::size_t funcIndex, FunctionFlags flags, Bitset<>& seen)
|
||||||
{
|
{
|
||||||
assert(funcIndex < m_functions.size());
|
assert(funcIndex < m_context->functions.size());
|
||||||
auto& funcData = m_functions[funcIndex];
|
auto& funcData = m_context->functions[funcIndex];
|
||||||
assert(funcData.defined);
|
assert(funcData.defined);
|
||||||
|
|
||||||
funcData.flags |= flags;
|
funcData.flags |= flags;
|
||||||
|
|
@ -1000,10 +1101,27 @@ namespace Nz::ShaderAst
|
||||||
PropagateFunctionFlags(i, funcData.flags, seen);
|
PropagateFunctionFlags(i, funcData.flags, seen);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::size_t SanitizeVisitor::RegisterConstant(std::string name, ConstantValue value)
|
||||||
|
{
|
||||||
|
if (FindIdentifier(name))
|
||||||
|
throw AstError{ name + " is already used" };
|
||||||
|
|
||||||
|
std::size_t constantIndex = m_context->constantValues.size();
|
||||||
|
m_context->constantValues.emplace_back(std::move(value));
|
||||||
|
|
||||||
|
m_context->identifiersInScope.push_back({
|
||||||
|
std::move(name),
|
||||||
|
constantIndex,
|
||||||
|
Identifier::Type::Constant
|
||||||
|
});
|
||||||
|
|
||||||
|
return constantIndex;
|
||||||
|
}
|
||||||
|
|
||||||
auto SanitizeVisitor::RegisterFunction(std::size_t functionIndex) -> FunctionData&
|
auto SanitizeVisitor::RegisterFunction(std::size_t functionIndex) -> FunctionData&
|
||||||
{
|
{
|
||||||
assert(m_functions.size() >= functionIndex);
|
assert(m_context->functions.size() >= functionIndex);
|
||||||
auto& funcData = m_functions[functionIndex];
|
auto& funcData = m_context->functions[functionIndex];
|
||||||
assert(!funcData.defined);
|
assert(!funcData.defined);
|
||||||
funcData.defined = true;
|
funcData.defined = true;
|
||||||
|
|
||||||
|
|
@ -1012,10 +1130,10 @@ namespace Nz::ShaderAst
|
||||||
bool duplicate = true;
|
bool duplicate = true;
|
||||||
|
|
||||||
// Functions cannot be declared twice, except for entry ones if their stages are different
|
// Functions cannot be declared twice, except for entry ones if their stages are different
|
||||||
if (funcData.node->entryStage && identifier->type == Identifier::Type::Function)
|
if (funcData.node->entryStage.HasValue() && identifier->type == Identifier::Type::Function)
|
||||||
{
|
{
|
||||||
auto& otherFunction = m_functions[identifier->index];
|
auto& otherFunction = m_context->functions[identifier->index];
|
||||||
if (funcData.node->entryStage != otherFunction.node->entryStage)
|
if (funcData.node->entryStage.GetResultingValue() != otherFunction.node->entryStage.GetResultingValue())
|
||||||
duplicate = false;
|
duplicate = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1023,7 +1141,7 @@ namespace Nz::ShaderAst
|
||||||
throw AstError{ funcData.node->name + " is already used" };
|
throw AstError{ funcData.node->name + " is already used" };
|
||||||
}
|
}
|
||||||
|
|
||||||
m_identifiersInScope.push_back({
|
m_context->identifiersInScope.push_back({
|
||||||
funcData.node->name,
|
funcData.node->name,
|
||||||
functionIndex,
|
functionIndex,
|
||||||
Identifier::Type::Function
|
Identifier::Type::Function
|
||||||
|
|
@ -1037,10 +1155,10 @@ namespace Nz::ShaderAst
|
||||||
if (FindIdentifier(name))
|
if (FindIdentifier(name))
|
||||||
throw AstError{ name + " is already used" };
|
throw AstError{ name + " is already used" };
|
||||||
|
|
||||||
std::size_t intrinsicIndex = m_intrinsics.size();
|
std::size_t intrinsicIndex = m_context->intrinsics.size();
|
||||||
m_intrinsics.push_back(type);
|
m_context->intrinsics.push_back(type);
|
||||||
|
|
||||||
m_identifiersInScope.push_back({
|
m_context->identifiersInScope.push_back({
|
||||||
std::move(name),
|
std::move(name),
|
||||||
intrinsicIndex,
|
intrinsicIndex,
|
||||||
Identifier::Type::Intrinsic
|
Identifier::Type::Intrinsic
|
||||||
|
|
@ -1049,32 +1167,15 @@ namespace Nz::ShaderAst
|
||||||
return intrinsicIndex;
|
return intrinsicIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t SanitizeVisitor::RegisterOption(std::string name, ExpressionType type)
|
std::size_t SanitizeVisitor::RegisterStruct(std::string name, StructDescription* description)
|
||||||
{
|
{
|
||||||
if (FindIdentifier(name))
|
if (FindIdentifier(name))
|
||||||
throw AstError{ name + " is already used" };
|
throw AstError{ name + " is already used" };
|
||||||
|
|
||||||
std::size_t optionIndex = m_options.size();
|
std::size_t structIndex = m_context->structs.size();
|
||||||
m_options.emplace_back(std::move(type));
|
m_context->structs.emplace_back(description);
|
||||||
|
|
||||||
m_identifiersInScope.push_back({
|
m_context->identifiersInScope.push_back({
|
||||||
std::move(name),
|
|
||||||
optionIndex,
|
|
||||||
Identifier::Type::Option
|
|
||||||
});
|
|
||||||
|
|
||||||
return optionIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::size_t SanitizeVisitor::RegisterStruct(std::string name, StructDescription description)
|
|
||||||
{
|
|
||||||
if (FindIdentifier(name))
|
|
||||||
throw AstError{ name + " is already used" };
|
|
||||||
|
|
||||||
std::size_t structIndex = m_structs.size();
|
|
||||||
m_structs.emplace_back(std::move(description));
|
|
||||||
|
|
||||||
m_identifiersInScope.push_back({
|
|
||||||
std::move(name),
|
std::move(name),
|
||||||
structIndex,
|
structIndex,
|
||||||
Identifier::Type::Struct
|
Identifier::Type::Struct
|
||||||
|
|
@ -1089,10 +1190,10 @@ namespace Nz::ShaderAst
|
||||||
if (auto* identifier = FindIdentifier(name); identifier && identifier->type != Identifier::Type::Variable)
|
if (auto* identifier = FindIdentifier(name); identifier && identifier->type != Identifier::Type::Variable)
|
||||||
throw AstError{ name + " is already used" };
|
throw AstError{ name + " is already used" };
|
||||||
|
|
||||||
std::size_t varIndex = m_variableTypes.size();
|
std::size_t varIndex = m_context->variableTypes.size();
|
||||||
m_variableTypes.emplace_back(std::move(type));
|
m_context->variableTypes.emplace_back(std::move(type));
|
||||||
|
|
||||||
m_identifiersInScope.push_back({
|
m_context->identifiersInScope.push_back({
|
||||||
std::move(name),
|
std::move(name),
|
||||||
varIndex,
|
varIndex,
|
||||||
Identifier::Type::Variable
|
Identifier::Type::Variable
|
||||||
|
|
@ -1106,17 +1207,17 @@ namespace Nz::ShaderAst
|
||||||
// Once every function is known, we can propagate flags
|
// Once every function is known, we can propagate flags
|
||||||
|
|
||||||
Bitset<> seen;
|
Bitset<> seen;
|
||||||
for (std::size_t funcIndex = 0; funcIndex < m_functions.size(); ++funcIndex)
|
for (std::size_t funcIndex = 0; funcIndex < m_context->functions.size(); ++funcIndex)
|
||||||
{
|
{
|
||||||
auto& funcData = m_functions[funcIndex];
|
auto& funcData = m_context->functions[funcIndex];
|
||||||
|
|
||||||
PropagateFunctionFlags(funcIndex, funcData.flags, seen);
|
PropagateFunctionFlags(funcIndex, funcData.flags, seen);
|
||||||
seen.Clear();
|
seen.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const FunctionData& funcData : m_functions)
|
for (const FunctionData& funcData : m_context->functions)
|
||||||
{
|
{
|
||||||
if (funcData.flags.Test(ShaderAst::FunctionFlag::DoesDiscard) && funcData.node->entryStage && *funcData.node->entryStage != ShaderStageType::Fragment)
|
if (funcData.flags.Test(ShaderAst::FunctionFlag::DoesDiscard) && funcData.node->entryStage.HasValue() && funcData.node->entryStage.GetResultingValue() != ShaderStageType::Fragment)
|
||||||
throw AstError{ "discard can only be used in the fragment stage" };
|
throw AstError{ "discard can only be used in the fragment stage" };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1246,18 +1347,18 @@ namespace Nz::ShaderAst
|
||||||
auto& indexExpr = node.indices[i];
|
auto& indexExpr = node.indices[i];
|
||||||
|
|
||||||
const ShaderAst::ExpressionType& indexType = GetExpressionType(*indexExpr);
|
const ShaderAst::ExpressionType& indexType = GetExpressionType(*indexExpr);
|
||||||
if (indexExpr->GetType() != NodeType::ConstantExpression)
|
if (indexExpr->GetType() != NodeType::ConstantExpression || indexType != ExpressionType{ PrimitiveType::Int32 })
|
||||||
throw AstError{ "struct can only be accessed with constant indices" };
|
throw AstError{ "struct can only be accessed with constant i32 indices" };
|
||||||
|
|
||||||
ConstantExpression& constantExpr = static_cast<ConstantExpression&>(*indexExpr);
|
ConstantExpression& constantExpr = static_cast<ConstantExpression&>(*indexExpr);
|
||||||
|
|
||||||
Int32 index = std::get<Int32>(constantExpr.value);
|
Int32 index = std::get<Int32>(constantExpr.value);
|
||||||
|
|
||||||
std::size_t structIndex = ResolveStruct(exprType);
|
std::size_t structIndex = ResolveStruct(exprType);
|
||||||
assert(structIndex < m_structs.size());
|
assert(structIndex < m_context->structs.size());
|
||||||
const StructDescription& s = m_structs[structIndex];
|
const StructDescription* s = m_context->structs[structIndex];
|
||||||
|
|
||||||
exprType = ResolveType(s.members[index].type);
|
exprType = ResolveType(s->members[index].type);
|
||||||
}
|
}
|
||||||
else if (IsMatrixType(exprType))
|
else if (IsMatrixType(exprType))
|
||||||
{
|
{
|
||||||
|
|
@ -1283,7 +1384,7 @@ namespace Nz::ShaderAst
|
||||||
|
|
||||||
void SanitizeVisitor::Validate(CallFunctionExpression& node, const DeclareFunctionStatement* referenceDeclaration)
|
void SanitizeVisitor::Validate(CallFunctionExpression& node, const DeclareFunctionStatement* referenceDeclaration)
|
||||||
{
|
{
|
||||||
if (referenceDeclaration->entryStage)
|
if (referenceDeclaration->entryStage.HasValue())
|
||||||
throw AstError{ referenceDeclaration->name + " is an entry function which cannot be called by the program" };
|
throw AstError{ referenceDeclaration->name + " is an entry function which cannot be called by the program" };
|
||||||
|
|
||||||
for (std::size_t i = 0; i < node.parameters.size(); ++i)
|
for (std::size_t i = 0; i < node.parameters.size(); ++i)
|
||||||
|
|
|
||||||
|
|
@ -46,20 +46,27 @@ namespace Nz
|
||||||
currentFunction->calledFunctions.UnboundedSet(std::get<std::size_t>(node.targetFunction));
|
currentFunction->calledFunctions.UnboundedSet(std::get<std::size_t>(node.targetFunction));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Visit(ShaderAst::ConditionalExpression& node) override
|
||||||
|
{
|
||||||
|
throw std::runtime_error("unexpected conditional expression, is shader sanitized?");
|
||||||
|
}
|
||||||
|
|
||||||
void Visit(ShaderAst::ConditionalStatement& node) override
|
void Visit(ShaderAst::ConditionalStatement& node) override
|
||||||
{
|
{
|
||||||
if (TestBit<UInt64>(enabledOptions, node.optionIndex))
|
throw std::runtime_error("unexpected conditional statement, is shader sanitized?");
|
||||||
node.statement->Visit(*this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Visit(ShaderAst::DeclareFunctionStatement& node) override
|
void Visit(ShaderAst::DeclareFunctionStatement& node) override
|
||||||
{
|
{
|
||||||
// Dismiss function if it's an entry point of another type than the one selected
|
// Dismiss function if it's an entry point of another type than the one selected
|
||||||
if (node.entryStage)
|
if (node.entryStage.HasValue())
|
||||||
{
|
{
|
||||||
if (selectedStage)
|
if (selectedStage)
|
||||||
{
|
{
|
||||||
ShaderStageType stage = *node.entryStage;
|
if (!node.entryStage.IsResultingValue())
|
||||||
|
throw std::runtime_error("unexpected unresolved value for entry attribute, is shader sanitized?");
|
||||||
|
|
||||||
|
ShaderStageType stage = node.entryStage.GetResultingValue();
|
||||||
if (stage != *selectedStage)
|
if (stage != *selectedStage)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
@ -132,7 +139,7 @@ namespace Nz
|
||||||
|
|
||||||
std::optional<ShaderStageType> stage;
|
std::optional<ShaderStageType> stage;
|
||||||
std::stringstream stream;
|
std::stringstream stream;
|
||||||
std::unordered_map<std::size_t, ShaderAst::StructDescription> structs;
|
std::unordered_map<std::size_t, ShaderAst::StructDescription*> structs;
|
||||||
std::unordered_map<std::size_t, std::string> variableNames;
|
std::unordered_map<std::size_t, std::string> variableNames;
|
||||||
std::vector<InOutField> inputFields;
|
std::vector<InOutField> inputFields;
|
||||||
std::vector<InOutField> outputFields;
|
std::vector<InOutField> outputFields;
|
||||||
|
|
@ -161,7 +168,7 @@ namespace Nz
|
||||||
ShaderAst::Statement* targetAst;
|
ShaderAst::Statement* targetAst;
|
||||||
if (!states.sanitized)
|
if (!states.sanitized)
|
||||||
{
|
{
|
||||||
sanitizedAst = Sanitize(shader);
|
sanitizedAst = Sanitize(shader, states.enabledOptions);
|
||||||
targetAst = sanitizedAst.get();
|
targetAst = sanitizedAst.get();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -196,10 +203,11 @@ namespace Nz
|
||||||
return s_flipYUniformName;
|
return s_flipYUniformName;
|
||||||
}
|
}
|
||||||
|
|
||||||
ShaderAst::StatementPtr GlslWriter::Sanitize(ShaderAst::Statement& ast, std::string* error)
|
ShaderAst::StatementPtr GlslWriter::Sanitize(ShaderAst::Statement& ast, UInt64 enabledConditions, std::string* error)
|
||||||
{
|
{
|
||||||
// Always sanitize for reserved identifiers
|
// Always sanitize for reserved identifiers
|
||||||
ShaderAst::SanitizeVisitor::Options options;
|
ShaderAst::SanitizeVisitor::Options options;
|
||||||
|
options.enabledOptions = enabledConditions;
|
||||||
options.makeVariableNameUnique = true;
|
options.makeVariableNameUnique = 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
|
||||||
|
|
@ -296,8 +304,8 @@ namespace Nz
|
||||||
|
|
||||||
void GlslWriter::Append(const ShaderAst::StructType& structType)
|
void GlslWriter::Append(const ShaderAst::StructType& structType)
|
||||||
{
|
{
|
||||||
const auto& structDesc = Retrieve(m_currentState->structs, structType.structIndex);
|
ShaderAst::StructDescription* structDesc = Retrieve(m_currentState->structs, structType.structIndex);
|
||||||
Append(structDesc.name);
|
Append(structDesc->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GlslWriter::Append(const ShaderAst::UniformType& /*uniformType*/)
|
void GlslWriter::Append(const ShaderAst::UniformType& /*uniformType*/)
|
||||||
|
|
@ -377,13 +385,13 @@ namespace Nz
|
||||||
|
|
||||||
void GlslWriter::AppendField(std::size_t structIndex, const ShaderAst::ExpressionPtr* memberIndices, std::size_t remainingMembers)
|
void GlslWriter::AppendField(std::size_t structIndex, const ShaderAst::ExpressionPtr* memberIndices, std::size_t remainingMembers)
|
||||||
{
|
{
|
||||||
const auto& structDesc = Retrieve(m_currentState->structs, structIndex);
|
ShaderAst::StructDescription* structDesc = Retrieve(m_currentState->structs, structIndex);
|
||||||
|
|
||||||
assert((*memberIndices)->GetType() == ShaderAst::NodeType::ConstantExpression);
|
assert((*memberIndices)->GetType() == ShaderAst::NodeType::ConstantExpression);
|
||||||
auto& constantValue = static_cast<ShaderAst::ConstantExpression&>(**memberIndices);
|
auto& constantValue = static_cast<ShaderAst::ConstantExpression&>(**memberIndices);
|
||||||
Int32 index = std::get<Int32>(constantValue.value);
|
Int32 index = std::get<Int32>(constantValue.value);
|
||||||
|
|
||||||
const auto& member = structDesc.members[index];
|
const auto& member = structDesc->members[index];
|
||||||
|
|
||||||
Append(".");
|
Append(".");
|
||||||
Append(member.name);
|
Append(member.name);
|
||||||
|
|
@ -529,7 +537,7 @@ namespace Nz
|
||||||
|
|
||||||
void GlslWriter::HandleEntryPoint(ShaderAst::DeclareFunctionStatement& node)
|
void GlslWriter::HandleEntryPoint(ShaderAst::DeclareFunctionStatement& node)
|
||||||
{
|
{
|
||||||
if (node.entryStage == ShaderStageType::Fragment && node.earlyFragmentTests && *node.earlyFragmentTests)
|
if (node.entryStage.GetResultingValue() == ShaderStageType::Fragment && node.earlyFragmentTests.HasValue() && node.earlyFragmentTests.GetResultingValue())
|
||||||
{
|
{
|
||||||
if ((m_environment.glES && m_environment.glMajorVersion >= 3 && m_environment.glMinorVersion >= 1) || (!m_environment.glES && m_environment.glMajorVersion >= 4 && m_environment.glMinorVersion >= 2) || (m_environment.extCallback && m_environment.extCallback("GL_ARB_shader_image_load_store")))
|
if ((m_environment.glES && m_environment.glMajorVersion >= 3 && m_environment.glMinorVersion >= 1) || (!m_environment.glES && m_environment.glMajorVersion >= 4 && m_environment.glMinorVersion >= 2) || (m_environment.extCallback && m_environment.extCallback("GL_ARB_shader_image_load_store")))
|
||||||
{
|
{
|
||||||
|
|
@ -553,9 +561,9 @@ namespace Nz
|
||||||
|
|
||||||
assert(IsStructType(parameter.type));
|
assert(IsStructType(parameter.type));
|
||||||
std::size_t structIndex = std::get<ShaderAst::StructType>(parameter.type).structIndex;
|
std::size_t structIndex = std::get<ShaderAst::StructType>(parameter.type).structIndex;
|
||||||
const ShaderAst::StructDescription& structDesc = Retrieve(m_currentState->structs, structIndex);
|
const ShaderAst::StructDescription* structDesc = Retrieve(m_currentState->structs, structIndex);
|
||||||
|
|
||||||
AppendLine(structDesc.name, " ", varName, ";");
|
AppendLine(structDesc->name, " ", varName, ";");
|
||||||
for (const auto& [memberName, targetName] : m_currentState->inputFields)
|
for (const auto& [memberName, targetName] : m_currentState->inputFields)
|
||||||
AppendLine(varName, ".", memberName, " = ", targetName, ";");
|
AppendLine(varName, ".", memberName, " = ", targetName, ";");
|
||||||
|
|
||||||
|
|
@ -578,9 +586,9 @@ namespace Nz
|
||||||
{
|
{
|
||||||
for (const auto& member : structDesc.members)
|
for (const auto& member : structDesc.members)
|
||||||
{
|
{
|
||||||
if (member.builtin)
|
if (member.builtin.HasValue())
|
||||||
{
|
{
|
||||||
auto it = s_builtinMapping.find(member.builtin.value());
|
auto it = s_builtinMapping.find(member.builtin.GetResultingValue());
|
||||||
assert(it != s_builtinMapping.end());
|
assert(it != s_builtinMapping.end());
|
||||||
|
|
||||||
const Builtin& builtin = it->second;
|
const Builtin& builtin = it->second;
|
||||||
|
|
@ -592,10 +600,10 @@ namespace Nz
|
||||||
builtin.identifier
|
builtin.identifier
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else if (member.locationIndex)
|
else if (member.locationIndex.HasValue())
|
||||||
{
|
{
|
||||||
Append("layout(location = ");
|
Append("layout(location = ");
|
||||||
Append(*member.locationIndex);
|
Append(member.locationIndex.GetResultingValue());
|
||||||
Append(") ");
|
Append(") ");
|
||||||
Append(keyword);
|
Append(keyword);
|
||||||
Append(" ");
|
Append(" ");
|
||||||
|
|
@ -625,7 +633,7 @@ namespace Nz
|
||||||
assert(std::holds_alternative<ShaderAst::StructType>(parameter.type));
|
assert(std::holds_alternative<ShaderAst::StructType>(parameter.type));
|
||||||
|
|
||||||
std::size_t inputStructIndex = std::get<ShaderAst::StructType>(parameter.type).structIndex;
|
std::size_t inputStructIndex = std::get<ShaderAst::StructType>(parameter.type).structIndex;
|
||||||
inputStruct = &Retrieve(m_currentState->structs, inputStructIndex);
|
inputStruct = Retrieve(m_currentState->structs, inputStructIndex);
|
||||||
|
|
||||||
AppendCommentSection("Inputs");
|
AppendCommentSection("Inputs");
|
||||||
AppendInOut(*inputStruct, m_currentState->inputFields, "in", s_inputPrefix);
|
AppendInOut(*inputStruct, m_currentState->inputFields, "in", s_inputPrefix);
|
||||||
|
|
@ -642,17 +650,17 @@ namespace Nz
|
||||||
assert(std::holds_alternative<ShaderAst::StructType>(node.returnType));
|
assert(std::holds_alternative<ShaderAst::StructType>(node.returnType));
|
||||||
std::size_t outputStructIndex = std::get<ShaderAst::StructType>(node.returnType).structIndex;
|
std::size_t outputStructIndex = std::get<ShaderAst::StructType>(node.returnType).structIndex;
|
||||||
|
|
||||||
const ShaderAst::StructDescription& outputStruct = Retrieve(m_currentState->structs, outputStructIndex);
|
const ShaderAst::StructDescription* outputStruct = Retrieve(m_currentState->structs, outputStructIndex);
|
||||||
|
|
||||||
AppendCommentSection("Outputs");
|
AppendCommentSection("Outputs");
|
||||||
AppendInOut(outputStruct, m_currentState->outputFields, "out", s_outputPrefix);
|
AppendInOut(*outputStruct, m_currentState->outputFields, "out", s_outputPrefix);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GlslWriter::RegisterStruct(std::size_t structIndex, ShaderAst::StructDescription desc)
|
void GlslWriter::RegisterStruct(std::size_t structIndex, ShaderAst::StructDescription* desc)
|
||||||
{
|
{
|
||||||
assert(m_currentState->structs.find(structIndex) == m_currentState->structs.end());
|
assert(m_currentState->structs.find(structIndex) == m_currentState->structs.end());
|
||||||
m_currentState->structs.emplace(structIndex, std::move(desc));
|
m_currentState->structs.emplace(structIndex, desc);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GlslWriter::RegisterVariable(std::size_t varIndex, std::string varName)
|
void GlslWriter::RegisterVariable(std::size_t varIndex, std::string varName)
|
||||||
|
|
@ -797,20 +805,6 @@ namespace Nz
|
||||||
Append(")");
|
Append(")");
|
||||||
}
|
}
|
||||||
|
|
||||||
void GlslWriter::Visit(ShaderAst::ConditionalExpression& node)
|
|
||||||
{
|
|
||||||
if (TestBit<Nz::UInt64>(m_currentState->enabledOptions, node.optionIndex))
|
|
||||||
Visit(node.truePath);
|
|
||||||
else
|
|
||||||
Visit(node.falsePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
void GlslWriter::Visit(ShaderAst::ConditionalStatement& node)
|
|
||||||
{
|
|
||||||
if (TestBit<Nz::UInt64>(m_currentState->enabledOptions, node.optionIndex))
|
|
||||||
node.statement->Visit(*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void GlslWriter::Visit(ShaderAst::ConstantExpression& node)
|
void GlslWriter::Visit(ShaderAst::ConstantExpression& node)
|
||||||
{
|
{
|
||||||
std::visit([&](auto&& arg)
|
std::visit([&](auto&& arg)
|
||||||
|
|
@ -849,8 +843,9 @@ namespace Nz
|
||||||
assert(std::holds_alternative<ShaderAst::StructType>(uniform.containedType));
|
assert(std::holds_alternative<ShaderAst::StructType>(uniform.containedType));
|
||||||
|
|
||||||
std::size_t structIndex = std::get<ShaderAst::StructType>(uniform.containedType).structIndex;
|
std::size_t structIndex = std::get<ShaderAst::StructType>(uniform.containedType).structIndex;
|
||||||
auto& structInfo = Retrieve(m_currentState->structs, structIndex);
|
ShaderAst::StructDescription* structInfo = Retrieve(m_currentState->structs, structIndex);
|
||||||
isStd140 = structInfo.layout == StructLayout::Std140;
|
if (structInfo->layout.HasValue())
|
||||||
|
isStd140 = structInfo->layout.GetResultingValue() == StructLayout::Std140;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!m_currentState->bindingMapping.empty() || isStd140)
|
if (!m_currentState->bindingMapping.empty() || isStd140)
|
||||||
|
|
@ -858,10 +853,14 @@ namespace Nz
|
||||||
|
|
||||||
if (!m_currentState->bindingMapping.empty())
|
if (!m_currentState->bindingMapping.empty())
|
||||||
{
|
{
|
||||||
assert(externalVar.bindingIndex);
|
assert(externalVar.bindingIndex.HasValue());
|
||||||
|
|
||||||
UInt64 bindingIndex = *externalVar.bindingIndex;
|
UInt64 bindingIndex = externalVar.bindingIndex.GetResultingValue();
|
||||||
UInt64 bindingSet = externalVar.bindingSet.value_or(0);
|
UInt64 bindingSet;
|
||||||
|
if (externalVar.bindingSet.HasValue())
|
||||||
|
bindingSet = externalVar.bindingSet.GetResultingValue();
|
||||||
|
else
|
||||||
|
bindingSet = 0;
|
||||||
|
|
||||||
auto bindingIt = m_currentState->bindingMapping.find(bindingSet << 32 | bindingIndex);
|
auto bindingIt = m_currentState->bindingMapping.find(bindingSet << 32 | bindingIndex);
|
||||||
if (bindingIt == m_currentState->bindingMapping.end())
|
if (bindingIt == m_currentState->bindingMapping.end())
|
||||||
|
|
@ -894,7 +893,7 @@ namespace Nz
|
||||||
auto& structDesc = Retrieve(m_currentState->structs, structIndex);
|
auto& structDesc = Retrieve(m_currentState->structs, structIndex);
|
||||||
|
|
||||||
bool first = true;
|
bool first = true;
|
||||||
for (const auto& member : structDesc.members)
|
for (const auto& member : structDesc->members)
|
||||||
{
|
{
|
||||||
if (!first)
|
if (!first)
|
||||||
AppendLine();
|
AppendLine();
|
||||||
|
|
@ -927,7 +926,7 @@ namespace Nz
|
||||||
{
|
{
|
||||||
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");
|
||||||
|
|
||||||
if (node.entryStage && m_currentState->previsitor.entryPoint != &node)
|
if (node.entryStage.HasValue() && m_currentState->previsitor.entryPoint != &node)
|
||||||
return; //< Ignore other entry points
|
return; //< Ignore other entry points
|
||||||
|
|
||||||
assert(node.funcIndex);
|
assert(node.funcIndex);
|
||||||
|
|
@ -951,7 +950,7 @@ namespace Nz
|
||||||
if (hasPredeclaration)
|
if (hasPredeclaration)
|
||||||
AppendLine();
|
AppendLine();
|
||||||
|
|
||||||
if (node.entryStage)
|
if (node.entryStage.HasValue())
|
||||||
return HandleEntryPoint(node);
|
return HandleEntryPoint(node);
|
||||||
|
|
||||||
std::optional<std::size_t> varIndexOpt = node.varIndex;
|
std::optional<std::size_t> varIndexOpt = node.varIndex;
|
||||||
|
|
@ -981,7 +980,7 @@ namespace Nz
|
||||||
void GlslWriter::Visit(ShaderAst::DeclareStructStatement& node)
|
void GlslWriter::Visit(ShaderAst::DeclareStructStatement& node)
|
||||||
{
|
{
|
||||||
assert(node.structIndex);
|
assert(node.structIndex);
|
||||||
RegisterStruct(*node.structIndex, node.description);
|
RegisterStruct(*node.structIndex, &node.description);
|
||||||
|
|
||||||
Append("struct ");
|
Append("struct ");
|
||||||
AppendLine(node.description.name);
|
AppendLine(node.description.name);
|
||||||
|
|
@ -1096,7 +1095,7 @@ namespace Nz
|
||||||
const ShaderAst::ExpressionType& returnType = GetExpressionType(*node.returnExpr);
|
const ShaderAst::ExpressionType& returnType = GetExpressionType(*node.returnExpr);
|
||||||
assert(IsStructType(returnType));
|
assert(IsStructType(returnType));
|
||||||
std::size_t structIndex = std::get<ShaderAst::StructType>(returnType).structIndex;
|
std::size_t structIndex = std::get<ShaderAst::StructType>(returnType).structIndex;
|
||||||
const ShaderAst::StructDescription& structDesc = Retrieve(m_currentState->structs, structIndex);
|
const ShaderAst::StructDescription* structDesc = Retrieve(m_currentState->structs, structIndex);
|
||||||
|
|
||||||
std::string outputStructVarName;
|
std::string outputStructVarName;
|
||||||
if (node.returnExpr->GetType() == ShaderAst::NodeType::VariableExpression)
|
if (node.returnExpr->GetType() == ShaderAst::NodeType::VariableExpression)
|
||||||
|
|
@ -1104,7 +1103,7 @@ namespace Nz
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
AppendLine();
|
AppendLine();
|
||||||
Append(structDesc.name, " ", s_outputVarName, " = ");
|
Append(structDesc->name, " ", s_outputVarName, " = ");
|
||||||
node.returnExpr->Visit(*this);
|
node.returnExpr->Visit(*this);
|
||||||
AppendLine(";");
|
AppendLine(";");
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,66 +29,66 @@ namespace Nz
|
||||||
|
|
||||||
struct LangWriter::BindingAttribute
|
struct LangWriter::BindingAttribute
|
||||||
{
|
{
|
||||||
std::optional<UInt32> bindingIndex;
|
const ShaderAst::AttributeValue<UInt32>& bindingIndex;
|
||||||
|
|
||||||
inline bool HasValue() const { return bindingIndex.has_value(); }
|
inline bool HasValue() const { return bindingIndex.HasValue(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct LangWriter::BuiltinAttribute
|
struct LangWriter::BuiltinAttribute
|
||||||
{
|
{
|
||||||
std::optional<ShaderAst::BuiltinEntry> builtin;
|
const ShaderAst::AttributeValue<ShaderAst::BuiltinEntry>& builtin;
|
||||||
|
|
||||||
inline bool HasValue() const { return builtin.has_value(); }
|
inline bool HasValue() const { return builtin.HasValue(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct LangWriter::DepthWriteAttribute
|
struct LangWriter::DepthWriteAttribute
|
||||||
{
|
{
|
||||||
std::optional<ShaderAst::DepthWriteMode> writeMode;
|
const ShaderAst::AttributeValue<ShaderAst::DepthWriteMode>& writeMode;
|
||||||
|
|
||||||
inline bool HasValue() const { return writeMode.has_value(); }
|
inline bool HasValue() const { return writeMode.HasValue(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct LangWriter::EarlyFragmentTestsAttribute
|
struct LangWriter::EarlyFragmentTestsAttribute
|
||||||
{
|
{
|
||||||
std::optional<bool> earlyFragmentTests;
|
const ShaderAst::AttributeValue<bool>& earlyFragmentTests;
|
||||||
|
|
||||||
inline bool HasValue() const { return earlyFragmentTests.has_value(); }
|
inline bool HasValue() const { return earlyFragmentTests.HasValue(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct LangWriter::EntryAttribute
|
struct LangWriter::EntryAttribute
|
||||||
{
|
{
|
||||||
std::optional<ShaderStageType> stageType;
|
const ShaderAst::AttributeValue<ShaderStageType>& stageType;
|
||||||
|
|
||||||
inline bool HasValue() const { return stageType.has_value(); }
|
inline bool HasValue() const { return stageType.HasValue(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct LangWriter::LayoutAttribute
|
struct LangWriter::LayoutAttribute
|
||||||
{
|
{
|
||||||
std::optional<StructLayout> layout;
|
const ShaderAst::AttributeValue<StructLayout>& layout;
|
||||||
|
|
||||||
inline bool HasValue() const { return layout.has_value(); }
|
inline bool HasValue() const { return layout.HasValue(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct LangWriter::LocationAttribute
|
struct LangWriter::LocationAttribute
|
||||||
{
|
{
|
||||||
std::optional<UInt32> locationIndex;
|
const ShaderAst::AttributeValue<UInt32>& locationIndex;
|
||||||
|
|
||||||
inline bool HasValue() const { return locationIndex.has_value(); }
|
inline bool HasValue() const { return locationIndex.HasValue(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct LangWriter::SetAttribute
|
struct LangWriter::SetAttribute
|
||||||
{
|
{
|
||||||
std::optional<UInt32> setIndex;
|
const ShaderAst::AttributeValue<UInt32>& setIndex;
|
||||||
|
|
||||||
inline bool HasValue() const { return setIndex.has_value(); }
|
inline bool HasValue() const { return setIndex.HasValue(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct LangWriter::State
|
struct LangWriter::State
|
||||||
{
|
{
|
||||||
const States* states = nullptr;
|
const States* states = nullptr;
|
||||||
std::stringstream stream;
|
std::stringstream stream;
|
||||||
std::unordered_map<std::size_t, std::string> optionNames;
|
std::unordered_map<std::size_t, std::string> constantNames;
|
||||||
std::unordered_map<std::size_t, ShaderAst::StructDescription> structs;
|
std::unordered_map<std::size_t, ShaderAst::StructDescription*> structs;
|
||||||
std::unordered_map<std::size_t, std::string> variableNames;
|
std::unordered_map<std::size_t, std::string> variableNames;
|
||||||
bool isInEntryPoint = false;
|
bool isInEntryPoint = false;
|
||||||
unsigned int indentLevel = 0;
|
unsigned int indentLevel = 0;
|
||||||
|
|
@ -181,8 +181,8 @@ namespace Nz
|
||||||
|
|
||||||
void LangWriter::Append(const ShaderAst::StructType& structType)
|
void LangWriter::Append(const ShaderAst::StructType& structType)
|
||||||
{
|
{
|
||||||
const auto& structDesc = Retrieve(m_currentState->structs, structType.structIndex);
|
ShaderAst::StructDescription* structDesc = Retrieve(m_currentState->structs, structType.structIndex);
|
||||||
Append(structDesc.name);
|
Append(structDesc->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LangWriter::Append(const ShaderAst::UniformType& uniformType)
|
void LangWriter::Append(const ShaderAst::UniformType& uniformType)
|
||||||
|
|
@ -265,7 +265,10 @@ namespace Nz
|
||||||
if (!binding.HasValue())
|
if (!binding.HasValue())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Append("binding(", *binding.bindingIndex, ")");
|
if (binding.bindingIndex.IsResultingValue())
|
||||||
|
Append("binding(", binding.bindingIndex.GetResultingValue(), ")");
|
||||||
|
else
|
||||||
|
binding.bindingIndex.GetExpression()->Visit(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LangWriter::AppendAttribute(BuiltinAttribute builtin)
|
void LangWriter::AppendAttribute(BuiltinAttribute builtin)
|
||||||
|
|
@ -273,20 +276,25 @@ namespace Nz
|
||||||
if (!builtin.HasValue())
|
if (!builtin.HasValue())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
switch (*builtin.builtin)
|
if (builtin.builtin.IsResultingValue())
|
||||||
{
|
{
|
||||||
case ShaderAst::BuiltinEntry::FragCoord:
|
switch (builtin.builtin.GetResultingValue())
|
||||||
Append("builtin(fragcoord)");
|
{
|
||||||
break;
|
case ShaderAst::BuiltinEntry::FragCoord:
|
||||||
|
Append("builtin(fragcoord)");
|
||||||
|
break;
|
||||||
|
|
||||||
case ShaderAst::BuiltinEntry::FragDepth:
|
case ShaderAst::BuiltinEntry::FragDepth:
|
||||||
Append("builtin(fragdepth)");
|
Append("builtin(fragdepth)");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ShaderAst::BuiltinEntry::VertexPosition:
|
case ShaderAst::BuiltinEntry::VertexPosition:
|
||||||
Append("builtin(position)");
|
Append("builtin(position)");
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
builtin.builtin.GetExpression()->Visit(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LangWriter::AppendAttribute(DepthWriteAttribute depthWrite)
|
void LangWriter::AppendAttribute(DepthWriteAttribute depthWrite)
|
||||||
|
|
@ -294,24 +302,29 @@ namespace Nz
|
||||||
if (!depthWrite.HasValue())
|
if (!depthWrite.HasValue())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
switch (*depthWrite.writeMode)
|
if (depthWrite.writeMode.IsResultingValue())
|
||||||
{
|
{
|
||||||
case ShaderAst::DepthWriteMode::Greater:
|
switch (depthWrite.writeMode.GetResultingValue())
|
||||||
Append("depth_write(greater)");
|
{
|
||||||
break;
|
case ShaderAst::DepthWriteMode::Greater:
|
||||||
|
Append("depth_write(greater)");
|
||||||
|
break;
|
||||||
|
|
||||||
case ShaderAst::DepthWriteMode::Less:
|
case ShaderAst::DepthWriteMode::Less:
|
||||||
Append("depth_write(less)");
|
Append("depth_write(less)");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ShaderAst::DepthWriteMode::Replace:
|
case ShaderAst::DepthWriteMode::Replace:
|
||||||
Append("depth_write(replace)");
|
Append("depth_write(replace)");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ShaderAst::DepthWriteMode::Unchanged:
|
case ShaderAst::DepthWriteMode::Unchanged:
|
||||||
Append("depth_write(unchanged)");
|
Append("depth_write(unchanged)");
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
depthWrite.writeMode.GetExpression()->Visit(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LangWriter::AppendAttribute(EarlyFragmentTestsAttribute earlyFragmentTests)
|
void LangWriter::AppendAttribute(EarlyFragmentTestsAttribute earlyFragmentTests)
|
||||||
|
|
@ -319,10 +332,15 @@ namespace Nz
|
||||||
if (!earlyFragmentTests.HasValue())
|
if (!earlyFragmentTests.HasValue())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (*earlyFragmentTests.earlyFragmentTests)
|
if (earlyFragmentTests.earlyFragmentTests.IsResultingValue())
|
||||||
Append("early_fragment_tests(on)");
|
{
|
||||||
|
if (earlyFragmentTests.earlyFragmentTests.GetResultingValue())
|
||||||
|
Append("early_fragment_tests(true)");
|
||||||
|
else
|
||||||
|
Append("early_fragment_tests(false)");
|
||||||
|
}
|
||||||
else
|
else
|
||||||
Append("early_fragment_tests(off)");
|
earlyFragmentTests.earlyFragmentTests.GetExpression()->Visit(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LangWriter::AppendAttribute(EntryAttribute entry)
|
void LangWriter::AppendAttribute(EntryAttribute entry)
|
||||||
|
|
@ -330,16 +348,21 @@ namespace Nz
|
||||||
if (!entry.HasValue())
|
if (!entry.HasValue())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
switch (*entry.stageType)
|
if (entry.stageType.IsResultingValue())
|
||||||
{
|
{
|
||||||
case ShaderStageType::Fragment:
|
switch (entry.stageType.GetResultingValue())
|
||||||
Append("entry(frag)");
|
{
|
||||||
break;
|
case ShaderStageType::Fragment:
|
||||||
|
Append("entry(frag)");
|
||||||
|
break;
|
||||||
|
|
||||||
case ShaderStageType::Vertex:
|
case ShaderStageType::Vertex:
|
||||||
Append("entry(vert)");
|
Append("entry(vert)");
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
entry.stageType.GetExpression()->Visit(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LangWriter::AppendAttribute(LayoutAttribute entry)
|
void LangWriter::AppendAttribute(LayoutAttribute entry)
|
||||||
|
|
@ -347,12 +370,17 @@ namespace Nz
|
||||||
if (!entry.HasValue())
|
if (!entry.HasValue())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
switch (*entry.layout)
|
if (entry.layout.IsResultingValue())
|
||||||
{
|
{
|
||||||
case StructLayout::Std140:
|
switch (entry.layout.GetResultingValue())
|
||||||
Append("layout(std140)");
|
{
|
||||||
break;
|
case StructLayout::Std140:
|
||||||
|
Append("layout(std140)");
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
entry.layout.GetExpression()->Visit(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LangWriter::AppendAttribute(LocationAttribute location)
|
void LangWriter::AppendAttribute(LocationAttribute location)
|
||||||
|
|
@ -360,7 +388,10 @@ namespace Nz
|
||||||
if (!location.HasValue())
|
if (!location.HasValue())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Append("location(", *location.locationIndex, ")");
|
if (location.locationIndex.IsResultingValue())
|
||||||
|
Append("location(", location.locationIndex.GetResultingValue(), ")");
|
||||||
|
else
|
||||||
|
location.locationIndex.GetExpression()->Visit(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LangWriter::AppendAttribute(SetAttribute set)
|
void LangWriter::AppendAttribute(SetAttribute set)
|
||||||
|
|
@ -368,7 +399,10 @@ namespace Nz
|
||||||
if (!set.HasValue())
|
if (!set.HasValue())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Append("set(", *set.setIndex, ")");
|
if (set.setIndex.IsResultingValue())
|
||||||
|
Append("set(", set.setIndex.GetResultingValue(), ")");
|
||||||
|
else
|
||||||
|
set.setIndex.GetExpression()->Visit(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LangWriter::AppendCommentSection(const std::string& section)
|
void LangWriter::AppendCommentSection(const std::string& section)
|
||||||
|
|
@ -382,13 +416,13 @@ namespace Nz
|
||||||
|
|
||||||
void LangWriter::AppendField(std::size_t structIndex, const ShaderAst::ExpressionPtr* memberIndices, std::size_t remainingMembers)
|
void LangWriter::AppendField(std::size_t structIndex, const ShaderAst::ExpressionPtr* memberIndices, std::size_t remainingMembers)
|
||||||
{
|
{
|
||||||
const auto& structDesc = Retrieve(m_currentState->structs, structIndex);
|
ShaderAst::StructDescription* structDesc = Retrieve(m_currentState->structs, structIndex);
|
||||||
|
|
||||||
assert((*memberIndices)->GetType() == ShaderAst::NodeType::ConstantExpression);
|
assert((*memberIndices)->GetType() == ShaderAst::NodeType::ConstantExpression);
|
||||||
auto& constantValue = static_cast<ShaderAst::ConstantExpression&>(**memberIndices);
|
auto& constantValue = static_cast<ShaderAst::ConstantExpression&>(**memberIndices);
|
||||||
Int32 index = std::get<Int32>(constantValue.value);
|
Int32 index = std::get<Int32>(constantValue.value);
|
||||||
|
|
||||||
const auto& member = structDesc.members[index];
|
const auto& member = structDesc->members[index];
|
||||||
|
|
||||||
Append(".");
|
Append(".");
|
||||||
Append(member.name);
|
Append(member.name);
|
||||||
|
|
@ -449,16 +483,16 @@ namespace Nz
|
||||||
Append("}");
|
Append("}");
|
||||||
}
|
}
|
||||||
|
|
||||||
void LangWriter::RegisterOption(std::size_t optionIndex, std::string optionName)
|
void LangWriter::RegisterConstant(std::size_t constantIndex, std::string constantName)
|
||||||
{
|
{
|
||||||
assert(m_currentState->optionNames.find(optionIndex) == m_currentState->optionNames.end());
|
assert(m_currentState->constantNames.find(constantIndex) == m_currentState->constantNames.end());
|
||||||
m_currentState->optionNames.emplace(optionIndex, std::move(optionName));
|
m_currentState->constantNames.emplace(constantIndex, std::move(constantName));
|
||||||
}
|
}
|
||||||
|
|
||||||
void LangWriter::RegisterStruct(std::size_t structIndex, ShaderAst::StructDescription desc)
|
void LangWriter::RegisterStruct(std::size_t structIndex, ShaderAst::StructDescription* desc)
|
||||||
{
|
{
|
||||||
assert(m_currentState->structs.find(structIndex) == m_currentState->structs.end());
|
assert(m_currentState->structs.find(structIndex) == m_currentState->structs.end());
|
||||||
m_currentState->structs.emplace(structIndex, std::move(desc));
|
m_currentState->structs.emplace(structIndex, desc);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LangWriter::RegisterVariable(std::size_t varIndex, std::string varName)
|
void LangWriter::RegisterVariable(std::size_t varIndex, std::string varName)
|
||||||
|
|
@ -589,16 +623,14 @@ namespace Nz
|
||||||
|
|
||||||
void LangWriter::Visit(ShaderAst::ConditionalExpression& node)
|
void LangWriter::Visit(ShaderAst::ConditionalExpression& node)
|
||||||
{
|
{
|
||||||
Append("select_opt(", Retrieve(m_currentState->optionNames, node.optionIndex), ", ");
|
throw std::runtime_error("fixme");
|
||||||
node.truePath->Visit(*this);
|
|
||||||
Append(", ");
|
|
||||||
node.falsePath->Visit(*this);
|
|
||||||
Append(")");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LangWriter::Visit(ShaderAst::ConditionalStatement& node)
|
void LangWriter::Visit(ShaderAst::ConditionalStatement& node)
|
||||||
{
|
{
|
||||||
Append("[opt(", Retrieve(m_currentState->optionNames, node.optionIndex), ")]");
|
Append("[cond(");
|
||||||
|
node.condition->Visit(*this);
|
||||||
|
AppendLine(")]");
|
||||||
node.statement->Visit(*this);
|
node.statement->Visit(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -629,6 +661,11 @@ namespace Nz
|
||||||
}, node.value);
|
}, node.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LangWriter::Visit(ShaderAst::ConstantIndexExpression& node)
|
||||||
|
{
|
||||||
|
Append(Retrieve(m_currentState->constantNames, node.constantId));
|
||||||
|
}
|
||||||
|
|
||||||
void LangWriter::Visit(ShaderAst::DeclareExternalStatement& node)
|
void LangWriter::Visit(ShaderAst::DeclareExternalStatement& node)
|
||||||
{
|
{
|
||||||
assert(node.varIndex);
|
assert(node.varIndex);
|
||||||
|
|
@ -690,7 +727,7 @@ namespace Nz
|
||||||
void LangWriter::Visit(ShaderAst::DeclareOptionStatement& node)
|
void LangWriter::Visit(ShaderAst::DeclareOptionStatement& node)
|
||||||
{
|
{
|
||||||
assert(node.optIndex);
|
assert(node.optIndex);
|
||||||
RegisterOption(*node.optIndex, node.optName);
|
RegisterConstant(*node.optIndex, node.optName);
|
||||||
|
|
||||||
Append("option ", node.optName, ": ", node.optType);
|
Append("option ", node.optName, ": ", node.optType);
|
||||||
if (node.initialValue)
|
if (node.initialValue)
|
||||||
|
|
@ -705,7 +742,7 @@ namespace Nz
|
||||||
void LangWriter::Visit(ShaderAst::DeclareStructStatement& node)
|
void LangWriter::Visit(ShaderAst::DeclareStructStatement& node)
|
||||||
{
|
{
|
||||||
assert(node.structIndex);
|
assert(node.structIndex);
|
||||||
RegisterStruct(*node.structIndex, node.description);
|
RegisterStruct(*node.structIndex, &node.description);
|
||||||
|
|
||||||
AppendAttributes(true, LayoutAttribute{ node.description.layout });
|
AppendAttributes(true, LayoutAttribute{ node.description.layout });
|
||||||
Append("struct ");
|
Append("struct ");
|
||||||
|
|
|
||||||
|
|
@ -29,12 +29,12 @@ namespace Nz::ShaderLang
|
||||||
std::unordered_map<std::string, ShaderAst::AttributeType> s_identifierToAttributeType = {
|
std::unordered_map<std::string, ShaderAst::AttributeType> s_identifierToAttributeType = {
|
||||||
{ "binding", ShaderAst::AttributeType::Binding },
|
{ "binding", ShaderAst::AttributeType::Binding },
|
||||||
{ "builtin", ShaderAst::AttributeType::Builtin },
|
{ "builtin", ShaderAst::AttributeType::Builtin },
|
||||||
|
{ "cond", ShaderAst::AttributeType::Cond },
|
||||||
{ "depth_write", ShaderAst::AttributeType::DepthWrite },
|
{ "depth_write", ShaderAst::AttributeType::DepthWrite },
|
||||||
{ "early_fragment_tests", ShaderAst::AttributeType::EarlyFragmentTests },
|
{ "early_fragment_tests", ShaderAst::AttributeType::EarlyFragmentTests },
|
||||||
{ "entry", ShaderAst::AttributeType::Entry },
|
{ "entry", ShaderAst::AttributeType::Entry },
|
||||||
{ "layout", ShaderAst::AttributeType::Layout },
|
{ "layout", ShaderAst::AttributeType::Layout },
|
||||||
{ "location", ShaderAst::AttributeType::Location },
|
{ "location", ShaderAst::AttributeType::Location },
|
||||||
{ "opt", ShaderAst::AttributeType::Option },
|
|
||||||
{ "set", ShaderAst::AttributeType::Set },
|
{ "set", ShaderAst::AttributeType::Set },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -61,6 +61,41 @@ namespace Nz::ShaderLang
|
||||||
|
|
||||||
return static_cast<T>(val);
|
return static_cast<T>(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void HandleUniqueAttribute(const std::string_view& attributeName, ShaderAst::AttributeValue<T>& targetAttribute, ShaderAst::Attribute::Param&& param, bool requireValue = true)
|
||||||
|
{
|
||||||
|
if (targetAttribute.HasValue())
|
||||||
|
throw AttributeError{ "attribute " + std::string(attributeName) + " must be present once" };
|
||||||
|
|
||||||
|
if (!param && requireValue)
|
||||||
|
throw AttributeError{ "attribute " + std::string(attributeName) + " requires a parameter" };
|
||||||
|
|
||||||
|
targetAttribute = std::move(*param);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void HandleUniqueStringAttribute(const std::string_view& attributeName, const std::unordered_map<std::string, T>& map, ShaderAst::AttributeValue<T>& targetAttribute, ShaderAst::Attribute::Param&& param)
|
||||||
|
{
|
||||||
|
if (targetAttribute.HasValue())
|
||||||
|
throw AttributeError{ "attribute " + std::string(attributeName) + " must be present once" };
|
||||||
|
|
||||||
|
//FIXME: This should be handled with global values at sanitization stage
|
||||||
|
if (!param)
|
||||||
|
throw AttributeError{ "attribute " + std::string(attributeName) + " requires a value" };
|
||||||
|
|
||||||
|
const ShaderAst::ExpressionPtr& expr = *param;
|
||||||
|
if (expr->GetType() != ShaderAst::NodeType::IdentifierExpression)
|
||||||
|
throw AttributeError{ "attribute " + std::string(attributeName) + " can only be an identifier for now" };
|
||||||
|
|
||||||
|
const std::string& exprStr = static_cast<ShaderAst::IdentifierExpression&>(*expr).identifier;
|
||||||
|
|
||||||
|
auto it = map.find(exprStr);
|
||||||
|
if (it == map.end())
|
||||||
|
throw AttributeError{ ("invalid parameter " + exprStr + " for " + std::string(attributeName) + " attribute").c_str() };
|
||||||
|
|
||||||
|
targetAttribute = it->second;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ShaderAst::StatementPtr Parser::Parse(const std::vector<Token>& tokens)
|
ShaderAst::StatementPtr Parser::Parse(const std::vector<Token>& tokens)
|
||||||
|
|
@ -347,17 +382,7 @@ namespace Nz::ShaderLang
|
||||||
{
|
{
|
||||||
Consume();
|
Consume();
|
||||||
|
|
||||||
const Token& n = Peek();
|
arg = ParseExpression();
|
||||||
if (n.type == TokenType::Identifier)
|
|
||||||
{
|
|
||||||
arg = std::get<std::string>(n.data);
|
|
||||||
Consume();
|
|
||||||
}
|
|
||||||
else if (n.type == TokenType::IntegerValue)
|
|
||||||
{
|
|
||||||
arg = std::get<long long>(n.data);
|
|
||||||
Consume();
|
|
||||||
}
|
|
||||||
|
|
||||||
Expect(Advance(), TokenType::ClosingParenthesis);
|
Expect(Advance(), TokenType::ClosingParenthesis);
|
||||||
}
|
}
|
||||||
|
|
@ -418,37 +443,24 @@ namespace Nz::ShaderLang
|
||||||
|
|
||||||
ShaderAst::StatementPtr Parser::ParseExternalBlock(std::vector<ShaderAst::Attribute> attributes)
|
ShaderAst::StatementPtr Parser::ParseExternalBlock(std::vector<ShaderAst::Attribute> attributes)
|
||||||
{
|
{
|
||||||
std::optional<UInt32> blockSetIndex;
|
Expect(Advance(), TokenType::External);
|
||||||
for (const auto& [attributeType, arg] : attributes)
|
Expect(Advance(), TokenType::OpenCurlyBracket);
|
||||||
|
|
||||||
|
std::unique_ptr<ShaderAst::DeclareExternalStatement> externalStatement = std::make_unique<ShaderAst::DeclareExternalStatement>();
|
||||||
|
|
||||||
|
for (auto&& [attributeType, arg] : attributes)
|
||||||
{
|
{
|
||||||
switch (attributeType)
|
switch (attributeType)
|
||||||
{
|
{
|
||||||
case ShaderAst::AttributeType::Set:
|
case ShaderAst::AttributeType::Set:
|
||||||
{
|
HandleUniqueAttribute("set", externalStatement->bindingSet, std::move(arg));
|
||||||
if (blockSetIndex)
|
|
||||||
throw AttributeError{ "attribute set must be present once" };
|
|
||||||
|
|
||||||
if (!std::holds_alternative<long long>(arg))
|
|
||||||
throw AttributeError{ "attribute set requires a string parameter" };
|
|
||||||
|
|
||||||
std::optional<UInt32> bindingIndex = BoundCast<UInt32>(std::get<long long>(arg));
|
|
||||||
if (!bindingIndex)
|
|
||||||
throw AttributeError{ "invalid set index" };
|
|
||||||
|
|
||||||
blockSetIndex = bindingIndex.value();
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw AttributeError{ "unhandled attribute for external block" };
|
throw AttributeError{ "unhandled attribute for external block" };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Expect(Advance(), TokenType::External);
|
|
||||||
Expect(Advance(), TokenType::OpenCurlyBracket);
|
|
||||||
|
|
||||||
std::unique_ptr<ShaderAst::DeclareExternalStatement> externalStatement = std::make_unique<ShaderAst::DeclareExternalStatement>();
|
|
||||||
|
|
||||||
bool first = true;
|
bool first = true;
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
|
|
@ -474,41 +486,17 @@ namespace Nz::ShaderLang
|
||||||
|
|
||||||
if (token.type == TokenType::OpenSquareBracket)
|
if (token.type == TokenType::OpenSquareBracket)
|
||||||
{
|
{
|
||||||
for (const auto& [attributeType, arg] : ParseAttributes())
|
for (auto&& [attributeType, arg] : ParseAttributes())
|
||||||
{
|
{
|
||||||
switch (attributeType)
|
switch (attributeType)
|
||||||
{
|
{
|
||||||
case ShaderAst::AttributeType::Binding:
|
case ShaderAst::AttributeType::Binding:
|
||||||
{
|
HandleUniqueAttribute("binding", extVar.bindingIndex, std::move(arg));
|
||||||
if (extVar.bindingIndex)
|
|
||||||
throw AttributeError{ "attribute binding must be present once" };
|
|
||||||
|
|
||||||
if (!std::holds_alternative<long long>(arg))
|
|
||||||
throw AttributeError{ "attribute binding requires a string parameter" };
|
|
||||||
|
|
||||||
std::optional<UInt32> bindingIndex = BoundCast<UInt32>(std::get<long long>(arg));
|
|
||||||
if (!bindingIndex)
|
|
||||||
throw AttributeError{ "invalid binding index" };
|
|
||||||
|
|
||||||
extVar.bindingIndex = bindingIndex.value();
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
case ShaderAst::AttributeType::Set:
|
case ShaderAst::AttributeType::Set:
|
||||||
{
|
HandleUniqueAttribute("set", extVar.bindingSet, std::move(arg));
|
||||||
if (extVar.bindingSet)
|
|
||||||
throw AttributeError{ "attribute set must be present once" };
|
|
||||||
|
|
||||||
if (!std::holds_alternative<long long>(arg))
|
|
||||||
throw AttributeError{ "attribute set requires a string parameter" };
|
|
||||||
|
|
||||||
std::optional<UInt32> bindingIndex = BoundCast<UInt32>(std::get<long long>(arg));
|
|
||||||
if (!bindingIndex)
|
|
||||||
throw AttributeError{ "invalid set index" };
|
|
||||||
|
|
||||||
extVar.bindingSet = bindingIndex.value();
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw AttributeError{ "unhandled attribute for external variable" };
|
throw AttributeError{ "unhandled attribute for external variable" };
|
||||||
|
|
@ -520,9 +508,6 @@ namespace Nz::ShaderLang
|
||||||
Expect(Advance(), TokenType::Colon);
|
Expect(Advance(), TokenType::Colon);
|
||||||
extVar.type = ParseType();
|
extVar.type = ParseType();
|
||||||
|
|
||||||
if (!extVar.bindingSet && blockSetIndex)
|
|
||||||
extVar.bindingSet = *blockSetIndex;
|
|
||||||
|
|
||||||
RegisterVariable(extVar.name);
|
RegisterVariable(extVar.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -583,90 +568,37 @@ namespace Nz::ShaderLang
|
||||||
|
|
||||||
auto func = ShaderBuilder::DeclareFunction(std::move(functionName), std::move(parameters), std::move(functionBody), std::move(returnType));
|
auto func = ShaderBuilder::DeclareFunction(std::move(functionName), std::move(parameters), std::move(functionBody), std::move(returnType));
|
||||||
|
|
||||||
for (const auto& [attributeType, arg] : attributes)
|
ShaderAst::AttributeValue<bool> condition;
|
||||||
|
|
||||||
|
for (auto&& [attributeType, arg] : attributes)
|
||||||
{
|
{
|
||||||
switch (attributeType)
|
switch (attributeType)
|
||||||
{
|
{
|
||||||
case ShaderAst::AttributeType::DepthWrite:
|
case ShaderAst::AttributeType::Cond:
|
||||||
{
|
HandleUniqueAttribute("cond", condition, std::move(arg));
|
||||||
if (func->depthWrite)
|
|
||||||
throw AttributeError{ "attribute depth_write can only be present once" };
|
|
||||||
|
|
||||||
if (!std::holds_alternative<std::string>(arg))
|
|
||||||
throw AttributeError{ "attribute entry requires a string parameter" };
|
|
||||||
|
|
||||||
const std::string& argStr = std::get<std::string>(arg);
|
|
||||||
|
|
||||||
auto it = s_depthWriteModes.find(argStr);
|
|
||||||
if (it == s_depthWriteModes.end())
|
|
||||||
throw AttributeError{ ("invalid parameter " + argStr + " for depth_write attribute").c_str() };
|
|
||||||
|
|
||||||
func->depthWrite = it->second;
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
case ShaderAst::AttributeType::EarlyFragmentTests:
|
|
||||||
{
|
|
||||||
if (func->earlyFragmentTests)
|
|
||||||
throw AttributeError{ "attribute early_fragment_tests can only be present once" };
|
|
||||||
|
|
||||||
if (std::holds_alternative<std::string>(arg))
|
|
||||||
{
|
|
||||||
const std::string& argStr = std::get<std::string>(arg);
|
|
||||||
if (argStr == "true" || argStr == "on")
|
|
||||||
func->earlyFragmentTests = true;
|
|
||||||
else if (argStr == "false" || argStr == "off")
|
|
||||||
func->earlyFragmentTests = false;
|
|
||||||
else
|
|
||||||
throw AttributeError{ "expected boolean value (got " + argStr + ")" };
|
|
||||||
}
|
|
||||||
else if (std::holds_alternative<std::monostate>(arg))
|
|
||||||
{
|
|
||||||
// No parameter, default to true
|
|
||||||
func->earlyFragmentTests = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
throw AttributeError{ "unexpected value for early_fragment_tests" };
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case ShaderAst::AttributeType::Entry:
|
case ShaderAst::AttributeType::Entry:
|
||||||
{
|
HandleUniqueStringAttribute("entry", s_entryPoints, func->entryStage, std::move(arg));
|
||||||
if (func->entryStage)
|
|
||||||
throw AttributeError{ "attribute entry can only be present once" };
|
|
||||||
|
|
||||||
if (!std::holds_alternative<std::string>(arg))
|
|
||||||
throw AttributeError{ "attribute entry requires a string parameter" };
|
|
||||||
|
|
||||||
const std::string& argStr = std::get<std::string>(arg);
|
|
||||||
|
|
||||||
auto it = s_entryPoints.find(argStr);
|
|
||||||
if (it == s_entryPoints.end())
|
|
||||||
throw AttributeError{ ("invalid parameter " + argStr + " for entry attribute").c_str() };
|
|
||||||
|
|
||||||
func->entryStage = it->second;
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
case ShaderAst::AttributeType::Option:
|
case ShaderAst::AttributeType::DepthWrite:
|
||||||
{
|
HandleUniqueStringAttribute("depth_write", s_depthWriteModes, func->depthWrite, std::move(arg));
|
||||||
if (!func->optionName.empty())
|
break;
|
||||||
throw AttributeError{ "attribute opt must be present once" };
|
|
||||||
|
case ShaderAst::AttributeType::EarlyFragmentTests:
|
||||||
if (!std::holds_alternative<std::string>(arg))
|
HandleUniqueAttribute("early_fragment_tests", func->earlyFragmentTests, std::move(arg), false);
|
||||||
throw AttributeError{ "attribute opt requires a string parameter" };
|
|
||||||
|
|
||||||
func->optionName = std::get<std::string>(arg);
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw AttributeError{ "unhandled attribute for function" };
|
throw AttributeError{ "unhandled attribute for function" };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return func;
|
if (condition.HasValue())
|
||||||
|
return ShaderBuilder::ConditionalStatement(std::move(condition).GetExpression(), std::move(func));
|
||||||
|
else
|
||||||
|
return func;
|
||||||
}
|
}
|
||||||
|
|
||||||
ShaderAst::DeclareFunctionStatement::Parameter Parser::ParseFunctionParameter()
|
ShaderAst::DeclareFunctionStatement::Parameter Parser::ParseFunctionParameter()
|
||||||
|
|
@ -710,22 +642,13 @@ namespace Nz::ShaderLang
|
||||||
ShaderAst::StructDescription description;
|
ShaderAst::StructDescription description;
|
||||||
description.name = ParseIdentifierAsName();
|
description.name = ParseIdentifierAsName();
|
||||||
|
|
||||||
for (const auto& [attributeType, attributeParam] : attributes)
|
for (auto&& [attributeType, attributeParam] : attributes)
|
||||||
{
|
{
|
||||||
switch (attributeType)
|
switch (attributeType)
|
||||||
{
|
{
|
||||||
case ShaderAst::AttributeType::Layout:
|
case ShaderAst::AttributeType::Layout:
|
||||||
{
|
HandleUniqueStringAttribute("layout", s_layoutMapping, description.layout, std::move(attributeParam));
|
||||||
if (description.layout)
|
|
||||||
throw AttributeError{ "attribute layout must be present once" };
|
|
||||||
|
|
||||||
auto it = s_layoutMapping.find(std::get<std::string>(attributeParam));
|
|
||||||
if (it == s_layoutMapping.end())
|
|
||||||
throw AttributeError{ "unknown layout" };
|
|
||||||
|
|
||||||
description.layout = it->second;
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw AttributeError{ "unexpected attribute" };
|
throw AttributeError{ "unexpected attribute" };
|
||||||
|
|
@ -760,42 +683,28 @@ namespace Nz::ShaderLang
|
||||||
|
|
||||||
if (token.type == TokenType::OpenSquareBracket)
|
if (token.type == TokenType::OpenSquareBracket)
|
||||||
{
|
{
|
||||||
for (const auto& [attributeType, attributeParam] : ParseAttributes())
|
for (auto&& [attributeType, arg] : ParseAttributes())
|
||||||
{
|
{
|
||||||
switch (attributeType)
|
switch (attributeType)
|
||||||
{
|
{
|
||||||
case ShaderAst::AttributeType::Builtin:
|
case ShaderAst::AttributeType::Builtin:
|
||||||
{
|
HandleUniqueStringAttribute("builtin", s_builtinMapping, structField.builtin, std::move(arg));
|
||||||
if (structField.builtin)
|
break;
|
||||||
throw AttributeError{ "attribute builtin must be present once" };
|
|
||||||
|
case ShaderAst::AttributeType::Cond:
|
||||||
auto it = s_builtinMapping.find(std::get<std::string>(attributeParam));
|
HandleUniqueAttribute("cond", structField.cond, std::move(arg));
|
||||||
|
|
||||||
if (it == s_builtinMapping.end())
|
|
||||||
throw AttributeError{ "unknown builtin" };
|
|
||||||
|
|
||||||
structField.builtin = it->second;
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
case ShaderAst::AttributeType::Location:
|
case ShaderAst::AttributeType::Location:
|
||||||
{
|
HandleUniqueAttribute("location", structField.locationIndex, std::move(arg));
|
||||||
if (structField.locationIndex)
|
|
||||||
throw AttributeError{ "attribute location must be present once" };
|
|
||||||
|
|
||||||
structField.locationIndex = BoundCast<UInt32>(std::get<long long>(attributeParam));
|
|
||||||
if (!structField.locationIndex)
|
|
||||||
throw AttributeError{ "invalid location index" };
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw AttributeError{ "unexpected attribute" };
|
throw AttributeError{ "unexpected attribute" };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (structField.builtin && structField.locationIndex)
|
if (structField.builtin.HasValue() && structField.locationIndex.HasValue())
|
||||||
throw AttributeError{ "A struct field cannot have both builtin and location attributes" };
|
throw AttributeError{ "A struct field cannot have both builtin and location attributes" };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -570,20 +570,6 @@ namespace Nz
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpirvAstVisitor::Visit(ShaderAst::ConditionalExpression& node)
|
|
||||||
{
|
|
||||||
if (m_writer.IsOptionEnabled(node.optionIndex))
|
|
||||||
node.truePath->Visit(*this);
|
|
||||||
else
|
|
||||||
node.falsePath->Visit(*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SpirvAstVisitor::Visit(ShaderAst::ConditionalStatement& node)
|
|
||||||
{
|
|
||||||
if (m_writer.IsOptionEnabled(node.optionIndex))
|
|
||||||
node.statement->Visit(*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SpirvAstVisitor::Visit(ShaderAst::ConstantExpression& node)
|
void SpirvAstVisitor::Visit(ShaderAst::ConstantExpression& node)
|
||||||
{
|
{
|
||||||
std::visit([&] (const auto& value)
|
std::visit([&] (const auto& value)
|
||||||
|
|
@ -678,7 +664,7 @@ namespace Nz
|
||||||
void SpirvAstVisitor::Visit(ShaderAst::DeclareStructStatement& node)
|
void SpirvAstVisitor::Visit(ShaderAst::DeclareStructStatement& node)
|
||||||
{
|
{
|
||||||
assert(node.structIndex);
|
assert(node.structIndex);
|
||||||
RegisterStruct(*node.structIndex, node.description);
|
RegisterStruct(*node.structIndex, &node.description);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpirvAstVisitor::Visit(ShaderAst::DeclareVariableStatement& node)
|
void SpirvAstVisitor::Visit(ShaderAst::DeclareVariableStatement& node)
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,7 @@ namespace Nz
|
||||||
using ExtVarContainer = std::unordered_map<std::size_t /*varIndex*/, UniformVar>;
|
using ExtVarContainer = std::unordered_map<std::size_t /*varIndex*/, UniformVar>;
|
||||||
using LocalContainer = std::unordered_set<ShaderAst::ExpressionType>;
|
using LocalContainer = std::unordered_set<ShaderAst::ExpressionType>;
|
||||||
using FunctionContainer = std::vector<std::reference_wrapper<ShaderAst::DeclareFunctionStatement>>;
|
using FunctionContainer = std::vector<std::reference_wrapper<ShaderAst::DeclareFunctionStatement>>;
|
||||||
using StructContainer = std::vector<ShaderAst::StructDescription>;
|
using StructContainer = std::vector<ShaderAst::StructDescription*>;
|
||||||
|
|
||||||
PreVisitor(const SpirvWriter::States& conditions, SpirvConstantCache& constantCache, std::vector<SpirvAstVisitor::FuncData>& funcs) :
|
PreVisitor(const SpirvWriter::States& conditions, SpirvConstantCache& constantCache, std::vector<SpirvAstVisitor::FuncData>& funcs) :
|
||||||
m_states(conditions),
|
m_states(conditions),
|
||||||
|
|
@ -68,7 +68,7 @@ namespace Nz
|
||||||
m_constantCache.SetStructCallback([this](std::size_t structIndex) -> const ShaderAst::StructDescription&
|
m_constantCache.SetStructCallback([this](std::size_t structIndex) -> const ShaderAst::StructDescription&
|
||||||
{
|
{
|
||||||
assert(structIndex < declaredStructs.size());
|
assert(structIndex < declaredStructs.size());
|
||||||
return declaredStructs[structIndex];
|
return *declaredStructs[structIndex];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -88,18 +88,12 @@ namespace Nz
|
||||||
|
|
||||||
void Visit(ShaderAst::ConditionalExpression& node) override
|
void Visit(ShaderAst::ConditionalExpression& node) override
|
||||||
{
|
{
|
||||||
if (TestBit<Nz::UInt64>(m_states.enabledOptions, node.optionIndex))
|
throw std::runtime_error("unexpected conditional expression, did you forget to sanitize the shader?");
|
||||||
node.truePath->Visit(*this);
|
|
||||||
else
|
|
||||||
node.falsePath->Visit(*this);
|
|
||||||
|
|
||||||
m_constantCache.Register(*m_constantCache.BuildType(node.cachedExpressionType.value()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Visit(ShaderAst::ConditionalStatement& node) override
|
void Visit(ShaderAst::ConditionalStatement& node) override
|
||||||
{
|
{
|
||||||
if (TestBit<Nz::UInt64>(m_states.enabledOptions, node.optionIndex))
|
throw std::runtime_error("unexpected conditional expression, did you forget to sanitize the shader?");
|
||||||
node.statement->Visit(*this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Visit(ShaderAst::ConstantExpression& node) override
|
void Visit(ShaderAst::ConstantExpression& node) override
|
||||||
|
|
@ -123,12 +117,12 @@ namespace Nz
|
||||||
variable.storageClass = (ShaderAst::IsSamplerType(extVar.type)) ? SpirvStorageClass::UniformConstant : SpirvStorageClass::Uniform;
|
variable.storageClass = (ShaderAst::IsSamplerType(extVar.type)) ? SpirvStorageClass::UniformConstant : SpirvStorageClass::Uniform;
|
||||||
variable.type = m_constantCache.BuildPointerType(extVar.type, variable.storageClass);
|
variable.type = m_constantCache.BuildPointerType(extVar.type, variable.storageClass);
|
||||||
|
|
||||||
assert(extVar.bindingIndex);
|
assert(extVar.bindingIndex.IsResultingValue());
|
||||||
|
|
||||||
UniformVar& uniformVar = extVars[varIndex++];
|
UniformVar& uniformVar = extVars[varIndex++];
|
||||||
uniformVar.pointerId = m_constantCache.Register(variable);
|
uniformVar.pointerId = m_constantCache.Register(variable);
|
||||||
uniformVar.bindingIndex = *extVar.bindingIndex;
|
uniformVar.bindingIndex = extVar.bindingIndex.GetResultingValue();
|
||||||
uniformVar.descriptorSet = extVar.bindingSet.value_or(0);
|
uniformVar.descriptorSet = (extVar.bindingSet.HasValue()) ? extVar.bindingSet.GetResultingValue() : 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -151,7 +145,9 @@ namespace Nz
|
||||||
|
|
||||||
void Visit(ShaderAst::DeclareFunctionStatement& node) override
|
void Visit(ShaderAst::DeclareFunctionStatement& node) override
|
||||||
{
|
{
|
||||||
std::optional<ShaderStageType> entryPointType = node.entryStage;
|
std::optional<ShaderStageType> entryPointType;
|
||||||
|
if (node.entryStage.HasValue())
|
||||||
|
entryPointType = node.entryStage.GetResultingValue();
|
||||||
|
|
||||||
assert(node.funcIndex);
|
assert(node.funcIndex);
|
||||||
std::size_t funcIndex = *node.funcIndex;
|
std::size_t funcIndex = *node.funcIndex;
|
||||||
|
|
@ -188,14 +184,14 @@ namespace Nz
|
||||||
if (*entryPointType == ShaderStageType::Fragment)
|
if (*entryPointType == ShaderStageType::Fragment)
|
||||||
{
|
{
|
||||||
executionModes.push_back(SpirvExecutionMode::OriginUpperLeft);
|
executionModes.push_back(SpirvExecutionMode::OriginUpperLeft);
|
||||||
if (node.earlyFragmentTests && *node.earlyFragmentTests)
|
if (node.earlyFragmentTests.HasValue() && node.earlyFragmentTests.GetResultingValue())
|
||||||
executionModes.push_back(SpirvExecutionMode::EarlyFragmentTests);
|
executionModes.push_back(SpirvExecutionMode::EarlyFragmentTests);
|
||||||
|
|
||||||
if (node.depthWrite)
|
if (node.depthWrite.HasValue())
|
||||||
{
|
{
|
||||||
executionModes.push_back(SpirvExecutionMode::DepthReplacing);
|
executionModes.push_back(SpirvExecutionMode::DepthReplacing);
|
||||||
|
|
||||||
switch (*node.depthWrite)
|
switch (node.depthWrite.GetResultingValue())
|
||||||
{
|
{
|
||||||
case ShaderAst::DepthWriteMode::Replace: break;
|
case ShaderAst::DepthWriteMode::Replace: break;
|
||||||
case ShaderAst::DepthWriteMode::Greater: executionModes.push_back(SpirvExecutionMode::DepthGreater); break;
|
case ShaderAst::DepthWriteMode::Greater: executionModes.push_back(SpirvExecutionMode::DepthGreater); break;
|
||||||
|
|
@ -217,10 +213,10 @@ namespace Nz
|
||||||
assert(std::holds_alternative<ShaderAst::StructType>(parameter.type));
|
assert(std::holds_alternative<ShaderAst::StructType>(parameter.type));
|
||||||
|
|
||||||
std::size_t structIndex = std::get<ShaderAst::StructType>(parameter.type).structIndex;
|
std::size_t structIndex = std::get<ShaderAst::StructType>(parameter.type).structIndex;
|
||||||
const ShaderAst::StructDescription& structDesc = declaredStructs[structIndex];
|
const ShaderAst::StructDescription* structDesc = declaredStructs[structIndex];
|
||||||
|
|
||||||
std::size_t memberIndex = 0;
|
std::size_t memberIndex = 0;
|
||||||
for (const auto& member : structDesc.members)
|
for (const auto& member : structDesc->members)
|
||||||
{
|
{
|
||||||
if (UInt32 varId = HandleEntryInOutType(*entryPointType, funcIndex, member, SpirvStorageClass::Input); varId != 0)
|
if (UInt32 varId = HandleEntryInOutType(*entryPointType, funcIndex, member, SpirvStorageClass::Input); varId != 0)
|
||||||
{
|
{
|
||||||
|
|
@ -247,10 +243,10 @@ namespace Nz
|
||||||
assert(std::holds_alternative<ShaderAst::StructType>(node.returnType));
|
assert(std::holds_alternative<ShaderAst::StructType>(node.returnType));
|
||||||
|
|
||||||
std::size_t structIndex = std::get<ShaderAst::StructType>(node.returnType).structIndex;
|
std::size_t structIndex = std::get<ShaderAst::StructType>(node.returnType).structIndex;
|
||||||
const ShaderAst::StructDescription& structDesc = declaredStructs[structIndex];
|
const ShaderAst::StructDescription* structDesc = declaredStructs[structIndex];
|
||||||
|
|
||||||
std::size_t memberIndex = 0;
|
std::size_t memberIndex = 0;
|
||||||
for (const auto& member : structDesc.members)
|
for (const auto& member : structDesc->members)
|
||||||
{
|
{
|
||||||
if (UInt32 varId = HandleEntryInOutType(*entryPointType, funcIndex, member, SpirvStorageClass::Output); varId != 0)
|
if (UInt32 varId = HandleEntryInOutType(*entryPointType, funcIndex, member, SpirvStorageClass::Output); varId != 0)
|
||||||
{
|
{
|
||||||
|
|
@ -291,7 +287,7 @@ namespace Nz
|
||||||
if (structIndex >= declaredStructs.size())
|
if (structIndex >= declaredStructs.size())
|
||||||
declaredStructs.resize(structIndex + 1);
|
declaredStructs.resize(structIndex + 1);
|
||||||
|
|
||||||
declaredStructs[structIndex] = node.description;
|
declaredStructs[structIndex] = &node.description;
|
||||||
|
|
||||||
m_constantCache.Register(*m_constantCache.BuildType(node.description));
|
m_constantCache.Register(*m_constantCache.BuildType(node.description));
|
||||||
}
|
}
|
||||||
|
|
@ -357,9 +353,9 @@ namespace Nz
|
||||||
|
|
||||||
UInt32 HandleEntryInOutType(ShaderStageType entryPointType, std::size_t funcIndex, const ShaderAst::StructDescription::StructMember& member, SpirvStorageClass storageClass)
|
UInt32 HandleEntryInOutType(ShaderStageType entryPointType, std::size_t funcIndex, const ShaderAst::StructDescription::StructMember& member, SpirvStorageClass storageClass)
|
||||||
{
|
{
|
||||||
if (member.builtin)
|
if (member.builtin.HasValue())
|
||||||
{
|
{
|
||||||
auto it = s_builtinMapping.find(*member.builtin);
|
auto it = s_builtinMapping.find(member.builtin.GetResultingValue());
|
||||||
assert(it != s_builtinMapping.end());
|
assert(it != s_builtinMapping.end());
|
||||||
|
|
||||||
Builtin& builtin = it->second;
|
Builtin& builtin = it->second;
|
||||||
|
|
@ -379,7 +375,7 @@ namespace Nz
|
||||||
|
|
||||||
return varId;
|
return varId;
|
||||||
}
|
}
|
||||||
else if (member.locationIndex)
|
else if (member.locationIndex.HasValue())
|
||||||
{
|
{
|
||||||
SpirvConstantCache::Variable variable;
|
SpirvConstantCache::Variable variable;
|
||||||
variable.debugName = member.name;
|
variable.debugName = member.name;
|
||||||
|
|
@ -388,7 +384,7 @@ namespace Nz
|
||||||
variable.type = m_constantCache.BuildPointerType(member.type, storageClass);
|
variable.type = m_constantCache.BuildPointerType(member.type, storageClass);
|
||||||
|
|
||||||
UInt32 varId = m_constantCache.Register(variable);
|
UInt32 varId = m_constantCache.Register(variable);
|
||||||
locationDecorations[varId] = *member.locationIndex;
|
locationDecorations[varId] = member.locationIndex.GetResultingValue();
|
||||||
|
|
||||||
return varId;
|
return varId;
|
||||||
}
|
}
|
||||||
|
|
@ -453,7 +449,10 @@ namespace Nz
|
||||||
ShaderAst::StatementPtr sanitizedAst;
|
ShaderAst::StatementPtr sanitizedAst;
|
||||||
if (!states.sanitized)
|
if (!states.sanitized)
|
||||||
{
|
{
|
||||||
sanitizedAst = ShaderAst::Sanitize(shader);
|
ShaderAst::SanitizeVisitor::Options options;
|
||||||
|
options.enabledOptions = states.enabledOptions;
|
||||||
|
|
||||||
|
sanitizedAst = ShaderAst::Sanitize(shader, options);
|
||||||
targetAst = sanitizedAst.get();
|
targetAst = sanitizedAst.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue