Shader: Add EliminateUnusedPassVisitor and use it when optimizing
This commit is contained in:
parent
ebd1318512
commit
3f7815175b
|
|
@ -0,0 +1,50 @@
|
||||||
|
// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
|
||||||
|
// This file is part of the "Nazara Engine - Shader module"
|
||||||
|
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef NAZARA_SHADER_AST_ELIMINATEUNUSEDPASSVISITOR_HPP
|
||||||
|
#define NAZARA_SHADER_AST_ELIMINATEUNUSEDPASSVISITOR_HPP
|
||||||
|
|
||||||
|
#include <Nazara/Prerequisites.hpp>
|
||||||
|
#include <Nazara/Core/Bitset.hpp>
|
||||||
|
#include <Nazara/Shader/Config.hpp>
|
||||||
|
#include <Nazara/Shader/Ast/AstCloner.hpp>
|
||||||
|
|
||||||
|
namespace Nz::ShaderAst
|
||||||
|
{
|
||||||
|
class NAZARA_SHADER_API EliminateUnusedPassVisitor : AstCloner
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
EliminateUnusedPassVisitor() = default;
|
||||||
|
EliminateUnusedPassVisitor(const EliminateUnusedPassVisitor&) = delete;
|
||||||
|
EliminateUnusedPassVisitor(EliminateUnusedPassVisitor&&) = delete;
|
||||||
|
~EliminateUnusedPassVisitor() = default;
|
||||||
|
|
||||||
|
StatementPtr Process(Statement& statement);
|
||||||
|
|
||||||
|
EliminateUnusedPassVisitor& operator=(const EliminateUnusedPassVisitor&) = delete;
|
||||||
|
EliminateUnusedPassVisitor& operator=(EliminateUnusedPassVisitor&&) = delete;
|
||||||
|
|
||||||
|
private:
|
||||||
|
using AstCloner::Clone;
|
||||||
|
StatementPtr Clone(DeclareExternalStatement& node) override;
|
||||||
|
StatementPtr Clone(DeclareFunctionStatement& node) override;
|
||||||
|
StatementPtr Clone(DeclareStructStatement& node) override;
|
||||||
|
StatementPtr Clone(DeclareVariableStatement& node) override;
|
||||||
|
|
||||||
|
bool IsFunctionUsed(std::size_t varIndex) const;
|
||||||
|
bool IsStructUsed(std::size_t varIndex) const;
|
||||||
|
bool IsVariableUsed(std::size_t varIndex) const;
|
||||||
|
|
||||||
|
struct Context;
|
||||||
|
Context* m_context;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline StatementPtr EliminateUnusedPass(Statement& ast);
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <Nazara/Shader/Ast/EliminateUnusedPassVisitor.inl>
|
||||||
|
|
||||||
|
#endif // NAZARA_SHADER_AST_ELIMINATEUNUSEDPASSVISITOR_HPP
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
|
||||||
|
// This file is part of the "Nazara Engine - Shader module"
|
||||||
|
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||||
|
|
||||||
|
#include <Nazara/Shader/Ast/EliminateUnusedPassVisitor.hpp>
|
||||||
|
#include <Nazara/Shader/Debug.hpp>
|
||||||
|
|
||||||
|
namespace Nz::ShaderAst
|
||||||
|
{
|
||||||
|
inline StatementPtr EliminateUnusedPass(Statement& ast)
|
||||||
|
{
|
||||||
|
EliminateUnusedPassVisitor visitor;
|
||||||
|
return visitor.Process(ast);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <Nazara/Shader/DebugOff.hpp>
|
||||||
|
|
@ -265,11 +265,11 @@ namespace Nz::ShaderAst
|
||||||
ExpressionValue<UInt32> bindingIndex;
|
ExpressionValue<UInt32> bindingIndex;
|
||||||
ExpressionValue<UInt32> bindingSet;
|
ExpressionValue<UInt32> bindingSet;
|
||||||
ExpressionValue<ExpressionType> type;
|
ExpressionValue<ExpressionType> type;
|
||||||
|
std::optional<std::size_t> varIndex;
|
||||||
std::string name;
|
std::string name;
|
||||||
};
|
};
|
||||||
|
|
||||||
ExpressionValue<UInt32> bindingSet;
|
ExpressionValue<UInt32> bindingSet;
|
||||||
std::optional<std::size_t> varIndex;
|
|
||||||
std::vector<ExternalVar> externalVars;
|
std::vector<ExternalVar> externalVars;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -91,8 +91,6 @@ 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->varIndex = node.varIndex;
|
|
||||||
|
|
||||||
clone->bindingSet = Clone(node.bindingSet);
|
clone->bindingSet = Clone(node.bindingSet);
|
||||||
|
|
||||||
clone->externalVars.reserve(node.externalVars.size());
|
clone->externalVars.reserve(node.externalVars.size());
|
||||||
|
|
@ -100,6 +98,7 @@ namespace Nz::ShaderAst
|
||||||
{
|
{
|
||||||
auto& cloneVar = clone->externalVars.emplace_back();
|
auto& cloneVar = clone->externalVars.emplace_back();
|
||||||
cloneVar.name = var.name;
|
cloneVar.name = var.name;
|
||||||
|
cloneVar.varIndex = var.varIndex;
|
||||||
cloneVar.type = Clone(var.type);
|
cloneVar.type = Clone(var.type);
|
||||||
cloneVar.bindingIndex = Clone(var.bindingIndex);
|
cloneVar.bindingIndex = Clone(var.bindingIndex);
|
||||||
cloneVar.bindingSet = Clone(var.bindingSet);
|
cloneVar.bindingSet = Clone(var.bindingSet);
|
||||||
|
|
|
||||||
|
|
@ -193,14 +193,13 @@ namespace Nz::ShaderAst
|
||||||
|
|
||||||
void AstSerializerBase::Serialize(DeclareExternalStatement& node)
|
void AstSerializerBase::Serialize(DeclareExternalStatement& node)
|
||||||
{
|
{
|
||||||
OptVal(node.varIndex);
|
|
||||||
|
|
||||||
ExprValue(node.bindingSet);
|
ExprValue(node.bindingSet);
|
||||||
|
|
||||||
Container(node.externalVars);
|
Container(node.externalVars);
|
||||||
for (auto& extVar : node.externalVars)
|
for (auto& extVar : node.externalVars)
|
||||||
{
|
{
|
||||||
Value(extVar.name);
|
Value(extVar.name);
|
||||||
|
OptVal(extVar.varIndex);
|
||||||
ExprValue(extVar.type);
|
ExprValue(extVar.type);
|
||||||
ExprValue(extVar.bindingIndex);
|
ExprValue(extVar.bindingIndex);
|
||||||
ExprValue(extVar.bindingSet);
|
ExprValue(extVar.bindingSet);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,308 @@
|
||||||
|
// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
|
||||||
|
// This file is part of the "Nazara Engine - Shader module"
|
||||||
|
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||||
|
|
||||||
|
#include <Nazara/Shader/Ast/EliminateUnusedPassVisitor.hpp>
|
||||||
|
#include <Nazara/Core/CallOnExit.hpp>
|
||||||
|
#include <Nazara/Shader/ShaderBuilder.hpp>
|
||||||
|
#include <Nazara/Shader/Ast/AstRecursiveVisitor.hpp>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <Nazara/Shader/Debug.hpp>
|
||||||
|
|
||||||
|
namespace Nz::ShaderAst
|
||||||
|
{
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
template<typename T> T& Retrieve(std::unordered_map<std::size_t, T>& map, std::size_t id)
|
||||||
|
{
|
||||||
|
auto it = map.find(id);
|
||||||
|
assert(it != map.end());
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T> const T& Retrieve(const std::unordered_map<std::size_t, T>& map, std::size_t id)
|
||||||
|
{
|
||||||
|
auto it = map.find(id);
|
||||||
|
assert(it != map.end());
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct UsageChecker : AstRecursiveVisitor
|
||||||
|
{
|
||||||
|
struct UsageSet;
|
||||||
|
|
||||||
|
void Resolve()
|
||||||
|
{
|
||||||
|
Resolve(globalUsage);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Resolve(const UsageSet& usageSet)
|
||||||
|
{
|
||||||
|
resolvedUsage.usedFunctions |= usageSet.usedFunctions;
|
||||||
|
resolvedUsage.usedStructs |= usageSet.usedStructs;
|
||||||
|
resolvedUsage.usedVariables |= usageSet.usedVariables;
|
||||||
|
|
||||||
|
for (std::size_t funcIndex = usageSet.usedFunctions.FindFirst(); funcIndex != usageSet.usedFunctions.npos; funcIndex = usageSet.usedFunctions.FindNext(funcIndex))
|
||||||
|
Resolve(Retrieve(functionUsages, funcIndex));
|
||||||
|
|
||||||
|
for (std::size_t structIndex = usageSet.usedStructs.FindFirst(); structIndex != usageSet.usedStructs.npos; structIndex = usageSet.usedStructs.FindNext(structIndex))
|
||||||
|
Resolve(Retrieve(structUsages, structIndex));
|
||||||
|
|
||||||
|
for (std::size_t varIndex = usageSet.usedVariables.FindFirst(); varIndex != usageSet.usedVariables.npos; varIndex = usageSet.usedVariables.FindNext(varIndex))
|
||||||
|
Resolve(Retrieve(variableUsages, varIndex));
|
||||||
|
}
|
||||||
|
|
||||||
|
using AstRecursiveVisitor::Visit;
|
||||||
|
|
||||||
|
void Visit(CallFunctionExpression& node) override
|
||||||
|
{
|
||||||
|
const auto& targetFuncType = GetExpressionType(node);
|
||||||
|
assert(std::holds_alternative<FunctionType>(targetFuncType));
|
||||||
|
|
||||||
|
const auto& funcType = std::get<FunctionType>(targetFuncType);
|
||||||
|
|
||||||
|
assert(currentFunctionIndex);
|
||||||
|
UsageSet& usageSet = Retrieve(functionUsages, *currentFunctionIndex);
|
||||||
|
usageSet.usedFunctions.UnboundedSet(funcType.funcIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Visit(DeclareExternalStatement& node) override
|
||||||
|
{
|
||||||
|
for (const auto& externalVar : node.externalVars)
|
||||||
|
{
|
||||||
|
assert(externalVar.varIndex);
|
||||||
|
std::size_t varIndex = *externalVar.varIndex;
|
||||||
|
|
||||||
|
assert(variableUsages.find(varIndex) == variableUsages.end());
|
||||||
|
UsageSet& usageSet = variableUsages[varIndex];
|
||||||
|
|
||||||
|
const auto& exprType = externalVar.type.GetResultingValue();
|
||||||
|
|
||||||
|
if (IsUniformType(exprType))
|
||||||
|
{
|
||||||
|
const UniformType& uniformType = std::get<UniformType>(exprType);
|
||||||
|
usageSet.usedStructs.UnboundedSet(uniformType.containedType.structIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
++varIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
AstRecursiveVisitor::Visit(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Visit(DeclareFunctionStatement& node) override
|
||||||
|
{
|
||||||
|
assert(node.funcIndex);
|
||||||
|
assert(functionUsages.find(*node.funcIndex) == functionUsages.end());
|
||||||
|
UsageSet& usageSet = functionUsages[*node.funcIndex];
|
||||||
|
|
||||||
|
// Register struct used in parameters or return type
|
||||||
|
if (!node.parameters.empty())
|
||||||
|
{
|
||||||
|
assert(node.varIndex);
|
||||||
|
std::size_t parameterVarIndex = *node.varIndex;
|
||||||
|
for (auto& parameter : node.parameters)
|
||||||
|
{
|
||||||
|
// Since parameters must always be defined, their type isn't a dependency of parameter variables
|
||||||
|
assert(variableUsages.find(parameterVarIndex) == variableUsages.end());
|
||||||
|
variableUsages.emplace(parameterVarIndex, UsageSet{});
|
||||||
|
|
||||||
|
const auto& exprType = parameter.type.GetResultingValue();
|
||||||
|
if (IsStructType(exprType))
|
||||||
|
{
|
||||||
|
std::size_t structIndex = std::get<ShaderAst::StructType>(exprType).structIndex;
|
||||||
|
usageSet.usedStructs.UnboundedSet(structIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
++parameterVarIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node.returnType.HasValue())
|
||||||
|
{
|
||||||
|
const auto& returnExprType = node.returnType.GetResultingValue();
|
||||||
|
if (IsStructType(returnExprType))
|
||||||
|
{
|
||||||
|
std::size_t structIndex = std::get<ShaderAst::StructType>(returnExprType).structIndex;
|
||||||
|
usageSet.usedStructs.UnboundedSet(structIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node.entryStage.HasValue())
|
||||||
|
globalUsage.usedFunctions.UnboundedSet(*node.funcIndex);
|
||||||
|
|
||||||
|
currentFunctionIndex = node.funcIndex;
|
||||||
|
AstRecursiveVisitor::Visit(node);
|
||||||
|
currentFunctionIndex = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
void Visit(DeclareStructStatement& node) override
|
||||||
|
{
|
||||||
|
assert(node.structIndex);
|
||||||
|
assert(structUsages.find(*node.structIndex) == structUsages.end());
|
||||||
|
UsageSet& usageSet = structUsages[*node.structIndex];
|
||||||
|
|
||||||
|
for (const auto& structMember : node.description.members)
|
||||||
|
{
|
||||||
|
const auto& memberExprType = structMember.type.GetResultingValue();
|
||||||
|
if (IsStructType(memberExprType))
|
||||||
|
{
|
||||||
|
std::size_t structIndex = std::get<ShaderAst::StructType>(memberExprType).structIndex;
|
||||||
|
usageSet.usedStructs.UnboundedSet(structIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AstRecursiveVisitor::Visit(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Visit(DeclareVariableStatement& node) override
|
||||||
|
{
|
||||||
|
assert(node.varIndex);
|
||||||
|
assert(variableUsages.find(*node.varIndex) == variableUsages.end());
|
||||||
|
UsageSet& usageSet = variableUsages[*node.varIndex];
|
||||||
|
|
||||||
|
const auto& varType = node.varType.GetResultingValue();
|
||||||
|
if (IsStructType(varType))
|
||||||
|
{
|
||||||
|
const auto& structType = std::get<StructType>(varType);
|
||||||
|
usageSet.usedStructs.UnboundedSet(structType.structIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
currentVariableDeclIndex = node.varIndex;
|
||||||
|
AstRecursiveVisitor::Visit(node);
|
||||||
|
currentVariableDeclIndex = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
void Visit(VariableExpression& node) override
|
||||||
|
{
|
||||||
|
assert(currentFunctionIndex);
|
||||||
|
if (currentVariableDeclIndex)
|
||||||
|
{
|
||||||
|
UsageSet& usageSet = Retrieve(variableUsages, *currentVariableDeclIndex);
|
||||||
|
usageSet.usedVariables.UnboundedSet(node.variableId);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
UsageSet& usageSet = Retrieve(functionUsages, *currentFunctionIndex);
|
||||||
|
usageSet.usedVariables.UnboundedSet(node.variableId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct UsageSet
|
||||||
|
{
|
||||||
|
Bitset<> usedFunctions;
|
||||||
|
Bitset<> usedStructs;
|
||||||
|
Bitset<> usedVariables;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::optional<std::size_t> currentFunctionIndex;
|
||||||
|
std::optional<std::size_t> currentVariableDeclIndex;
|
||||||
|
std::unordered_map<std::size_t, UsageSet> functionUsages;
|
||||||
|
std::unordered_map<std::size_t, UsageSet> structUsages;
|
||||||
|
std::unordered_map<std::size_t, UsageSet> variableUsages;
|
||||||
|
UsageSet globalUsage;
|
||||||
|
UsageSet resolvedUsage;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
struct EliminateUnusedPassVisitor::Context
|
||||||
|
{
|
||||||
|
UsageChecker usageChecker;
|
||||||
|
};
|
||||||
|
|
||||||
|
StatementPtr EliminateUnusedPassVisitor::Process(Statement& statement)
|
||||||
|
{
|
||||||
|
Context context;
|
||||||
|
statement.Visit(context.usageChecker);
|
||||||
|
context.usageChecker.Resolve();
|
||||||
|
|
||||||
|
m_context = &context;
|
||||||
|
CallOnExit onExit([this]()
|
||||||
|
{
|
||||||
|
m_context = nullptr;
|
||||||
|
});
|
||||||
|
|
||||||
|
return Clone(statement);
|
||||||
|
}
|
||||||
|
|
||||||
|
StatementPtr EliminateUnusedPassVisitor::Clone(DeclareExternalStatement& node)
|
||||||
|
{
|
||||||
|
bool isUsed = false;
|
||||||
|
for (const auto& externalVar : node.externalVars)
|
||||||
|
{
|
||||||
|
assert(externalVar.varIndex);
|
||||||
|
std::size_t varIndex = *externalVar.varIndex;
|
||||||
|
|
||||||
|
if (IsVariableUsed(varIndex))
|
||||||
|
{
|
||||||
|
isUsed = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isUsed)
|
||||||
|
return ShaderBuilder::NoOp();
|
||||||
|
|
||||||
|
auto clonedNode = AstCloner::Clone(node);
|
||||||
|
|
||||||
|
auto& externalStatement = static_cast<DeclareExternalStatement&>(*clonedNode);
|
||||||
|
for (auto it = externalStatement.externalVars.begin(); it != externalStatement.externalVars.end(); )
|
||||||
|
{
|
||||||
|
const auto& externalVar = *it;
|
||||||
|
assert(externalVar.varIndex);
|
||||||
|
std::size_t varIndex = *externalVar.varIndex;
|
||||||
|
|
||||||
|
if (!IsVariableUsed(varIndex))
|
||||||
|
it = externalStatement.externalVars.erase(it);
|
||||||
|
else
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
|
||||||
|
return clonedNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
StatementPtr EliminateUnusedPassVisitor::Clone(DeclareFunctionStatement& node)
|
||||||
|
{
|
||||||
|
assert(node.funcIndex);
|
||||||
|
if (!IsFunctionUsed(*node.funcIndex))
|
||||||
|
return ShaderBuilder::NoOp();
|
||||||
|
|
||||||
|
return AstCloner::Clone(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
StatementPtr EliminateUnusedPassVisitor::Clone(DeclareStructStatement& node)
|
||||||
|
{
|
||||||
|
assert(node.structIndex);
|
||||||
|
if (!IsStructUsed(*node.structIndex))
|
||||||
|
return ShaderBuilder::NoOp();
|
||||||
|
|
||||||
|
return AstCloner::Clone(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
StatementPtr EliminateUnusedPassVisitor::Clone(DeclareVariableStatement& node)
|
||||||
|
{
|
||||||
|
assert(node.varIndex);
|
||||||
|
if (!IsVariableUsed(*node.varIndex))
|
||||||
|
return ShaderBuilder::NoOp();
|
||||||
|
|
||||||
|
return AstCloner::Clone(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EliminateUnusedPassVisitor::IsFunctionUsed(std::size_t varIndex) const
|
||||||
|
{
|
||||||
|
assert(m_context);
|
||||||
|
return m_context->usageChecker.resolvedUsage.usedFunctions.UnboundedTest(varIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EliminateUnusedPassVisitor::IsStructUsed(std::size_t varIndex) const
|
||||||
|
{
|
||||||
|
assert(m_context);
|
||||||
|
return m_context->usageChecker.resolvedUsage.usedStructs.UnboundedTest(varIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EliminateUnusedPassVisitor::IsVariableUsed(std::size_t varIndex) const
|
||||||
|
{
|
||||||
|
assert(m_context);
|
||||||
|
return m_context->usageChecker.resolvedUsage.usedVariables.UnboundedTest(varIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -786,10 +786,7 @@ namespace Nz::ShaderAst
|
||||||
throw AstError{ "external variable " + extVar.name + " is of wrong type: only uniform and sampler are allowed in external blocks" };
|
throw AstError{ "external variable " + extVar.name + " is of wrong type: only uniform and sampler are allowed in external blocks" };
|
||||||
|
|
||||||
extVar.type = std::move(resolvedType);
|
extVar.type = std::move(resolvedType);
|
||||||
|
extVar.varIndex = RegisterVariable(extVar.name, std::move(varType));
|
||||||
std::size_t varIndex = RegisterVariable(extVar.name, std::move(varType));
|
|
||||||
if (!clone->varIndex)
|
|
||||||
clone->varIndex = varIndex; //< First external variable index is node variable index
|
|
||||||
|
|
||||||
SanitizeIdentifier(extVar.name);
|
SanitizeIdentifier(extVar.name);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@
|
||||||
#include <Nazara/Shader/Ast/AstOptimizer.hpp>
|
#include <Nazara/Shader/Ast/AstOptimizer.hpp>
|
||||||
#include <Nazara/Shader/Ast/AstRecursiveVisitor.hpp>
|
#include <Nazara/Shader/Ast/AstRecursiveVisitor.hpp>
|
||||||
#include <Nazara/Shader/Ast/AstUtils.hpp>
|
#include <Nazara/Shader/Ast/AstUtils.hpp>
|
||||||
|
#include <Nazara/Shader/Ast/EliminateUnusedPassVisitor.hpp>
|
||||||
#include <Nazara/Shader/Ast/SanitizeVisitor.hpp>
|
#include <Nazara/Shader/Ast/SanitizeVisitor.hpp>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <set>
|
#include <set>
|
||||||
|
|
@ -177,7 +178,11 @@ namespace Nz
|
||||||
ShaderAst::StatementPtr optimizedAst;
|
ShaderAst::StatementPtr optimizedAst;
|
||||||
if (states.optimize)
|
if (states.optimize)
|
||||||
{
|
{
|
||||||
optimizedAst = ShaderAst::Optimize(*targetAst);
|
ShaderAst::StatementPtr tempAst;
|
||||||
|
|
||||||
|
tempAst = ShaderAst::Optimize(*targetAst);
|
||||||
|
optimizedAst = ShaderAst::EliminateUnusedPass(*tempAst);
|
||||||
|
|
||||||
targetAst = optimizedAst.get();
|
targetAst = optimizedAst.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -992,9 +997,6 @@ namespace Nz
|
||||||
|
|
||||||
void GlslWriter::Visit(ShaderAst::DeclareExternalStatement& node)
|
void GlslWriter::Visit(ShaderAst::DeclareExternalStatement& node)
|
||||||
{
|
{
|
||||||
assert(node.varIndex);
|
|
||||||
std::size_t varIndex = *node.varIndex;
|
|
||||||
|
|
||||||
for (const auto& externalVar : node.externalVars)
|
for (const auto& externalVar : node.externalVars)
|
||||||
{
|
{
|
||||||
bool isStd140 = false;
|
bool isStd140 = false;
|
||||||
|
|
@ -1075,7 +1077,8 @@ namespace Nz
|
||||||
if (IsUniformType(externalVar.type.GetResultingValue()))
|
if (IsUniformType(externalVar.type.GetResultingValue()))
|
||||||
AppendLine();
|
AppendLine();
|
||||||
|
|
||||||
RegisterVariable(varIndex++, externalVar.name);
|
assert(externalVar.varIndex);
|
||||||
|
RegisterVariable(*externalVar.varIndex, externalVar.name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -787,9 +787,6 @@ namespace Nz
|
||||||
|
|
||||||
void LangWriter::Visit(ShaderAst::DeclareExternalStatement& node)
|
void LangWriter::Visit(ShaderAst::DeclareExternalStatement& node)
|
||||||
{
|
{
|
||||||
assert(node.varIndex);
|
|
||||||
std::size_t varIndex = *node.varIndex;
|
|
||||||
|
|
||||||
AppendLine("external");
|
AppendLine("external");
|
||||||
EnterScope();
|
EnterScope();
|
||||||
|
|
||||||
|
|
@ -804,7 +801,8 @@ namespace Nz
|
||||||
AppendAttributes(false, SetAttribute{ externalVar.bindingSet }, BindingAttribute{ externalVar.bindingIndex });
|
AppendAttributes(false, SetAttribute{ externalVar.bindingSet }, BindingAttribute{ externalVar.bindingIndex });
|
||||||
Append(externalVar.name, ": ", externalVar.type);
|
Append(externalVar.name, ": ", externalVar.type);
|
||||||
|
|
||||||
RegisterVariable(varIndex++, externalVar.name);
|
assert(externalVar.varIndex);
|
||||||
|
RegisterVariable(*externalVar.varIndex, externalVar.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
LeaveScope();
|
LeaveScope();
|
||||||
|
|
|
||||||
|
|
@ -579,11 +579,11 @@ namespace Nz
|
||||||
|
|
||||||
void SpirvAstVisitor::Visit(ShaderAst::DeclareExternalStatement& node)
|
void SpirvAstVisitor::Visit(ShaderAst::DeclareExternalStatement& node)
|
||||||
{
|
{
|
||||||
assert(node.varIndex);
|
|
||||||
|
|
||||||
std::size_t varIndex = *node.varIndex;
|
|
||||||
for (auto&& extVar : node.externalVars)
|
for (auto&& extVar : node.externalVars)
|
||||||
RegisterExternalVariable(varIndex++, extVar.type.GetResultingValue());
|
{
|
||||||
|
assert(extVar.varIndex);
|
||||||
|
RegisterExternalVariable(*extVar.varIndex, extVar.type.GetResultingValue());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpirvAstVisitor::Visit(ShaderAst::DeclareFunctionStatement& node)
|
void SpirvAstVisitor::Visit(ShaderAst::DeclareFunctionStatement& node)
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@
|
||||||
#include <Nazara/Shader/Ast/AstCloner.hpp>
|
#include <Nazara/Shader/Ast/AstCloner.hpp>
|
||||||
#include <Nazara/Shader/Ast/AstOptimizer.hpp>
|
#include <Nazara/Shader/Ast/AstOptimizer.hpp>
|
||||||
#include <Nazara/Shader/Ast/AstRecursiveVisitor.hpp>
|
#include <Nazara/Shader/Ast/AstRecursiveVisitor.hpp>
|
||||||
|
#include <Nazara/Shader/Ast/EliminateUnusedPassVisitor.hpp>
|
||||||
#include <Nazara/Shader/Ast/SanitizeVisitor.hpp>
|
#include <Nazara/Shader/Ast/SanitizeVisitor.hpp>
|
||||||
#include <SpirV/GLSL.std.450.h>
|
#include <SpirV/GLSL.std.450.h>
|
||||||
#include <tsl/ordered_map.h>
|
#include <tsl/ordered_map.h>
|
||||||
|
|
@ -137,8 +138,6 @@ namespace Nz
|
||||||
|
|
||||||
void Visit(ShaderAst::DeclareExternalStatement& node) override
|
void Visit(ShaderAst::DeclareExternalStatement& node) override
|
||||||
{
|
{
|
||||||
assert(node.varIndex);
|
|
||||||
std::size_t varIndex = *node.varIndex;
|
|
||||||
for (auto& extVar : node.externalVars)
|
for (auto& extVar : node.externalVars)
|
||||||
{
|
{
|
||||||
SpirvConstantCache::Variable variable;
|
SpirvConstantCache::Variable variable;
|
||||||
|
|
@ -165,7 +164,8 @@ namespace Nz
|
||||||
|
|
||||||
assert(extVar.bindingIndex.IsResultingValue());
|
assert(extVar.bindingIndex.IsResultingValue());
|
||||||
|
|
||||||
UniformVar& uniformVar = extVars[varIndex++];
|
assert(extVar.varIndex);
|
||||||
|
UniformVar& uniformVar = extVars[*extVar.varIndex];
|
||||||
uniformVar.pointerId = m_constantCache.Register(variable);
|
uniformVar.pointerId = m_constantCache.Register(variable);
|
||||||
uniformVar.bindingIndex = extVar.bindingIndex.GetResultingValue();
|
uniformVar.bindingIndex = extVar.bindingIndex.GetResultingValue();
|
||||||
uniformVar.descriptorSet = (extVar.bindingSet.HasValue()) ? extVar.bindingSet.GetResultingValue() : 0;
|
uniformVar.descriptorSet = (extVar.bindingSet.HasValue()) ? extVar.bindingSet.GetResultingValue() : 0;
|
||||||
|
|
@ -519,7 +519,11 @@ namespace Nz
|
||||||
ShaderAst::StatementPtr optimizedAst;
|
ShaderAst::StatementPtr optimizedAst;
|
||||||
if (states.optimize)
|
if (states.optimize)
|
||||||
{
|
{
|
||||||
optimizedAst = ShaderAst::Optimize(*targetAst);
|
ShaderAst::StatementPtr tempAst;
|
||||||
|
|
||||||
|
tempAst = ShaderAst::Optimize(*targetAst);
|
||||||
|
optimizedAst = ShaderAst::EliminateUnusedPass(*tempAst);
|
||||||
|
|
||||||
targetAst = optimizedAst.get();
|
targetAst = optimizedAst.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
#include <Nazara/Shader/GlslWriter.hpp>
|
#include <Nazara/Shader/GlslWriter.hpp>
|
||||||
#include <Nazara/Shader/LangWriter.hpp>
|
#include <Nazara/Shader/LangWriter.hpp>
|
||||||
#include <Nazara/Shader/Ast/AstOptimizer.hpp>
|
#include <Nazara/Shader/Ast/AstOptimizer.hpp>
|
||||||
|
#include <Nazara/Shader/Ast/EliminateUnusedPassVisitor.hpp>
|
||||||
#include <Nazara/Shader/Ast/SanitizeVisitor.hpp>
|
#include <Nazara/Shader/Ast/SanitizeVisitor.hpp>
|
||||||
#include <Nazara/Shader/SpirvPrinter.hpp>
|
#include <Nazara/Shader/SpirvPrinter.hpp>
|
||||||
#include <Nazara/Shader/SpirvWriter.hpp>
|
#include <Nazara/Shader/SpirvWriter.hpp>
|
||||||
|
|
@ -16,7 +17,7 @@
|
||||||
enum class OutputLanguage
|
enum class OutputLanguage
|
||||||
{
|
{
|
||||||
GLSL,
|
GLSL,
|
||||||
Nazalang,
|
NZSL,
|
||||||
SpirV
|
SpirV
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -27,7 +28,7 @@ m_shaderGraph(shaderGraph)
|
||||||
|
|
||||||
m_outputLang = new QComboBox;
|
m_outputLang = new QComboBox;
|
||||||
m_outputLang->addItem("GLSL", int(OutputLanguage::GLSL));
|
m_outputLang->addItem("GLSL", int(OutputLanguage::GLSL));
|
||||||
m_outputLang->addItem("Nazalang", int(OutputLanguage::Nazalang));
|
m_outputLang->addItem("NZSL", int(OutputLanguage::NZSL));
|
||||||
m_outputLang->addItem("SPIR-V", int(OutputLanguage::SpirV));
|
m_outputLang->addItem("SPIR-V", int(OutputLanguage::SpirV));
|
||||||
connect(m_outputLang, qOverload<int>(&QComboBox::currentIndexChanged), [this](int)
|
connect(m_outputLang, qOverload<int>(&QComboBox::currentIndexChanged), [this](int)
|
||||||
{
|
{
|
||||||
|
|
@ -70,7 +71,8 @@ void CodeOutputWidget::Refresh()
|
||||||
shaderAst = Nz::ShaderAst::Sanitize(*shaderAst, sanitizeOptions);
|
shaderAst = Nz::ShaderAst::Sanitize(*shaderAst, sanitizeOptions);
|
||||||
|
|
||||||
Nz::ShaderAst::AstOptimizer optimiser;
|
Nz::ShaderAst::AstOptimizer optimiser;
|
||||||
shaderAst = optimiser.Optimise(*shaderAst);
|
shaderAst = Nz::ShaderAst::Optimize(*shaderAst);
|
||||||
|
shaderAst = Nz::ShaderAst::EliminateUnusedPass(*shaderAst);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string output;
|
std::string output;
|
||||||
|
|
@ -91,7 +93,7 @@ void CodeOutputWidget::Refresh()
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case OutputLanguage::Nazalang:
|
case OutputLanguage::NZSL:
|
||||||
{
|
{
|
||||||
Nz::LangWriter writer;
|
Nz::LangWriter writer;
|
||||||
output = writer.Generate(*shaderAst, states);
|
output = writer.Generate(*shaderAst, states);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue