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> bindingSet;
|
||||
ExpressionValue<ExpressionType> type;
|
||||
std::optional<std::size_t> varIndex;
|
||||
std::string name;
|
||||
};
|
||||
|
||||
ExpressionValue<UInt32> bindingSet;
|
||||
std::optional<std::size_t> varIndex;
|
||||
std::vector<ExternalVar> externalVars;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -91,8 +91,6 @@ namespace Nz::ShaderAst
|
|||
StatementPtr AstCloner::Clone(DeclareExternalStatement& node)
|
||||
{
|
||||
auto clone = std::make_unique<DeclareExternalStatement>();
|
||||
clone->varIndex = node.varIndex;
|
||||
|
||||
clone->bindingSet = Clone(node.bindingSet);
|
||||
|
||||
clone->externalVars.reserve(node.externalVars.size());
|
||||
|
|
@ -100,6 +98,7 @@ namespace Nz::ShaderAst
|
|||
{
|
||||
auto& cloneVar = clone->externalVars.emplace_back();
|
||||
cloneVar.name = var.name;
|
||||
cloneVar.varIndex = var.varIndex;
|
||||
cloneVar.type = Clone(var.type);
|
||||
cloneVar.bindingIndex = Clone(var.bindingIndex);
|
||||
cloneVar.bindingSet = Clone(var.bindingSet);
|
||||
|
|
|
|||
|
|
@ -193,14 +193,13 @@ namespace Nz::ShaderAst
|
|||
|
||||
void AstSerializerBase::Serialize(DeclareExternalStatement& node)
|
||||
{
|
||||
OptVal(node.varIndex);
|
||||
|
||||
ExprValue(node.bindingSet);
|
||||
|
||||
Container(node.externalVars);
|
||||
for (auto& extVar : node.externalVars)
|
||||
{
|
||||
Value(extVar.name);
|
||||
OptVal(extVar.varIndex);
|
||||
ExprValue(extVar.type);
|
||||
ExprValue(extVar.bindingIndex);
|
||||
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" };
|
||||
|
||||
extVar.type = std::move(resolvedType);
|
||||
|
||||
std::size_t varIndex = RegisterVariable(extVar.name, std::move(varType));
|
||||
if (!clone->varIndex)
|
||||
clone->varIndex = varIndex; //< First external variable index is node variable index
|
||||
extVar.varIndex = RegisterVariable(extVar.name, std::move(varType));
|
||||
|
||||
SanitizeIdentifier(extVar.name);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
#include <Nazara/Shader/Ast/AstOptimizer.hpp>
|
||||
#include <Nazara/Shader/Ast/AstRecursiveVisitor.hpp>
|
||||
#include <Nazara/Shader/Ast/AstUtils.hpp>
|
||||
#include <Nazara/Shader/Ast/EliminateUnusedPassVisitor.hpp>
|
||||
#include <Nazara/Shader/Ast/SanitizeVisitor.hpp>
|
||||
#include <optional>
|
||||
#include <set>
|
||||
|
|
@ -177,7 +178,11 @@ namespace Nz
|
|||
ShaderAst::StatementPtr optimizedAst;
|
||||
if (states.optimize)
|
||||
{
|
||||
optimizedAst = ShaderAst::Optimize(*targetAst);
|
||||
ShaderAst::StatementPtr tempAst;
|
||||
|
||||
tempAst = ShaderAst::Optimize(*targetAst);
|
||||
optimizedAst = ShaderAst::EliminateUnusedPass(*tempAst);
|
||||
|
||||
targetAst = optimizedAst.get();
|
||||
}
|
||||
|
||||
|
|
@ -992,9 +997,6 @@ namespace Nz
|
|||
|
||||
void GlslWriter::Visit(ShaderAst::DeclareExternalStatement& node)
|
||||
{
|
||||
assert(node.varIndex);
|
||||
std::size_t varIndex = *node.varIndex;
|
||||
|
||||
for (const auto& externalVar : node.externalVars)
|
||||
{
|
||||
bool isStd140 = false;
|
||||
|
|
@ -1075,7 +1077,8 @@ namespace Nz
|
|||
if (IsUniformType(externalVar.type.GetResultingValue()))
|
||||
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)
|
||||
{
|
||||
assert(node.varIndex);
|
||||
std::size_t varIndex = *node.varIndex;
|
||||
|
||||
AppendLine("external");
|
||||
EnterScope();
|
||||
|
||||
|
|
@ -804,7 +801,8 @@ namespace Nz
|
|||
AppendAttributes(false, SetAttribute{ externalVar.bindingSet }, BindingAttribute{ externalVar.bindingIndex });
|
||||
Append(externalVar.name, ": ", externalVar.type);
|
||||
|
||||
RegisterVariable(varIndex++, externalVar.name);
|
||||
assert(externalVar.varIndex);
|
||||
RegisterVariable(*externalVar.varIndex, externalVar.name);
|
||||
}
|
||||
|
||||
LeaveScope();
|
||||
|
|
|
|||
|
|
@ -579,11 +579,11 @@ namespace Nz
|
|||
|
||||
void SpirvAstVisitor::Visit(ShaderAst::DeclareExternalStatement& node)
|
||||
{
|
||||
assert(node.varIndex);
|
||||
|
||||
std::size_t varIndex = *node.varIndex;
|
||||
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)
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
#include <Nazara/Shader/Ast/AstCloner.hpp>
|
||||
#include <Nazara/Shader/Ast/AstOptimizer.hpp>
|
||||
#include <Nazara/Shader/Ast/AstRecursiveVisitor.hpp>
|
||||
#include <Nazara/Shader/Ast/EliminateUnusedPassVisitor.hpp>
|
||||
#include <Nazara/Shader/Ast/SanitizeVisitor.hpp>
|
||||
#include <SpirV/GLSL.std.450.h>
|
||||
#include <tsl/ordered_map.h>
|
||||
|
|
@ -137,8 +138,6 @@ namespace Nz
|
|||
|
||||
void Visit(ShaderAst::DeclareExternalStatement& node) override
|
||||
{
|
||||
assert(node.varIndex);
|
||||
std::size_t varIndex = *node.varIndex;
|
||||
for (auto& extVar : node.externalVars)
|
||||
{
|
||||
SpirvConstantCache::Variable variable;
|
||||
|
|
@ -165,7 +164,8 @@ namespace Nz
|
|||
|
||||
assert(extVar.bindingIndex.IsResultingValue());
|
||||
|
||||
UniformVar& uniformVar = extVars[varIndex++];
|
||||
assert(extVar.varIndex);
|
||||
UniformVar& uniformVar = extVars[*extVar.varIndex];
|
||||
uniformVar.pointerId = m_constantCache.Register(variable);
|
||||
uniformVar.bindingIndex = extVar.bindingIndex.GetResultingValue();
|
||||
uniformVar.descriptorSet = (extVar.bindingSet.HasValue()) ? extVar.bindingSet.GetResultingValue() : 0;
|
||||
|
|
@ -519,7 +519,11 @@ namespace Nz
|
|||
ShaderAst::StatementPtr optimizedAst;
|
||||
if (states.optimize)
|
||||
{
|
||||
optimizedAst = ShaderAst::Optimize(*targetAst);
|
||||
ShaderAst::StatementPtr tempAst;
|
||||
|
||||
tempAst = ShaderAst::Optimize(*targetAst);
|
||||
optimizedAst = ShaderAst::EliminateUnusedPass(*tempAst);
|
||||
|
||||
targetAst = optimizedAst.get();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
#include <Nazara/Shader/GlslWriter.hpp>
|
||||
#include <Nazara/Shader/LangWriter.hpp>
|
||||
#include <Nazara/Shader/Ast/AstOptimizer.hpp>
|
||||
#include <Nazara/Shader/Ast/EliminateUnusedPassVisitor.hpp>
|
||||
#include <Nazara/Shader/Ast/SanitizeVisitor.hpp>
|
||||
#include <Nazara/Shader/SpirvPrinter.hpp>
|
||||
#include <Nazara/Shader/SpirvWriter.hpp>
|
||||
|
|
@ -16,7 +17,7 @@
|
|||
enum class OutputLanguage
|
||||
{
|
||||
GLSL,
|
||||
Nazalang,
|
||||
NZSL,
|
||||
SpirV
|
||||
};
|
||||
|
||||
|
|
@ -27,7 +28,7 @@ m_shaderGraph(shaderGraph)
|
|||
|
||||
m_outputLang = new QComboBox;
|
||||
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));
|
||||
connect(m_outputLang, qOverload<int>(&QComboBox::currentIndexChanged), [this](int)
|
||||
{
|
||||
|
|
@ -70,7 +71,8 @@ void CodeOutputWidget::Refresh()
|
|||
shaderAst = Nz::ShaderAst::Sanitize(*shaderAst, sanitizeOptions);
|
||||
|
||||
Nz::ShaderAst::AstOptimizer optimiser;
|
||||
shaderAst = optimiser.Optimise(*shaderAst);
|
||||
shaderAst = Nz::ShaderAst::Optimize(*shaderAst);
|
||||
shaderAst = Nz::ShaderAst::EliminateUnusedPass(*shaderAst);
|
||||
}
|
||||
|
||||
std::string output;
|
||||
|
|
@ -91,7 +93,7 @@ void CodeOutputWidget::Refresh()
|
|||
break;
|
||||
}
|
||||
|
||||
case OutputLanguage::Nazalang:
|
||||
case OutputLanguage::NZSL:
|
||||
{
|
||||
Nz::LangWriter writer;
|
||||
output = writer.Generate(*shaderAst, states);
|
||||
|
|
|
|||
Loading…
Reference in New Issue