Skip to content

Commit 11aed54

Browse files
reciprocation fixes, move more stuff into the session, add enum for CFrontendIR::CSpectralVariable, epic debug mesages
1 parent bc2295b commit 11aed54

3 files changed

Lines changed: 227 additions & 125 deletions

File tree

include/nbl/asset/material_compiler3/CFrontendIR.h

Lines changed: 141 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,7 @@ class CFrontendIR final : public CNodePool
150150
Mul = 1,
151151
Add = 2,
152152
Complement = 3,
153+
SpectralVariable = 4,
153154
Other = 5
154155
};
155156
virtual inline Type getType() const {return Type::Other;}
@@ -226,8 +227,10 @@ class CFrontendIR final : public CNodePool
226227
inline const std::string_view getTypeName() const override {return TYPE_NAME_STR(CSpectralVariable);}
227228
// Variable length but has no children
228229

229-
using semantics_e = CTrueIR::ISpectralVariable::ESemantics;
230+
//
231+
inline IExprNode::Type getType() const override {return Type::SpectralVariable;}
230232

233+
using semantics_e = CTrueIR::ISpectralVariable::ESemantics;
231234
//
232235
template<uint8_t Count>
233236
struct SCreationParams
@@ -812,7 +815,7 @@ class CFrontendIR final : public CNodePool
812815
if (!rootH) // its a valid material (blackhole)
813816
*outIt = CTrueIR::BlackholeMaterialHandle;
814817
else if (valid(rootH,args.logger))
815-
*outIt = makeFinalIR(rootH,session);
818+
*outIt = session.makeFinalIR(rootH,this);
816819
// now check for failure
817820
if (*outIt)
818821
retval++;
@@ -824,6 +827,7 @@ class CFrontendIR final : public CNodePool
824827
struct SDotPrinter final
825828
{
826829
public:
830+
inline SDotPrinter() = default;
827831
inline SDotPrinter(const CFrontendIR* ir) : m_ir(ir) {}
828832
// assign in reverse because we want materials to print in order
829833
inline SDotPrinter(const CFrontendIR* ir, std::span<const typed_pointer_type<const CLayer>> roots) : m_ir(ir), layerStack(roots.rbegin(),roots.rend())
@@ -832,6 +836,14 @@ class CFrontendIR final : public CNodePool
832836
visitedNodes.reserve(roots.size()<<3);
833837
}
834838

839+
inline void reset(const CFrontendIR* ir)
840+
{
841+
visitedNodes.clear();
842+
layerStack.clear();
843+
exprStack.clear();
844+
m_ir = ir;
845+
}
846+
835847
NBL_API2 void operator()(std::ostringstream& output);
836848
inline core::string operator()()
837849
{
@@ -843,96 +855,108 @@ class CFrontendIR final : public CNodePool
843855
core::unordered_set<typed_pointer_type<const INode>> visitedNodes;
844856
// TODO: track layering depth and indent accordingly?
845857
core::vector<typed_pointer_type<const CLayer>> layerStack;
846-
core::stack<typed_pointer_type<const IExprNode>> exprStack;
858+
core::vector<typed_pointer_type<const IExprNode>> exprStack;
847859
private:
848-
const CFrontendIR* m_ir;
860+
const CFrontendIR* m_ir = nullptr;
849861
};
850862

851863
protected:
852864
using CNodePool::CNodePool;
853865

854-
struct SAdd2IRSession
866+
struct SAdd2IRSession final
855867
{
856-
inline SAdd2IRSession(const SAddMaterialsArgs& _args) : args(_args)
857-
{
858-
tmpAST = CFrontendIR::create({.composed={.blockSizeKBLog2=10},.maxBlocks=64});
859-
// give slightly more memory to IR, since the AST tends to be a bit more compact
860-
tmpIR = CTrueIR::create({.composed={.blockSizeKBLog2=12},.maxBlocks=64});
861-
}
868+
public:
869+
inline SAdd2IRSession(const SAddMaterialsArgs& _args) : args(_args)
870+
{
871+
tmpAST = CFrontendIR::create({.composed={.blockSizeKBLog2=10},.maxBlocks=64});
872+
// give slightly more memory to IR, since the AST tends to be a bit more compact
873+
tmpIR = CTrueIR::create({.composed={.blockSizeKBLog2=12},.maxBlocks=64});
874+
}
862875

863-
using oriented_material_t = CTrueIR::SMaterial::SOriented;
864-
NBL_API2 oriented_material_t makeOrientedMaterial(const CFrontendIR::typed_pointer_type<const CFrontendIR::CLayer> rootH, const CFrontendIR* _srcAST);
865-
866-
NBL_API2 CTrueIR::typed_pointer_type<const CTrueIR::CContributorSum> makeContributors(const CFrontendIR::typed_pointer_type<const CFrontendIR::IExprNode> bxdfRootH);
867-
868-
NBL_API2 CTrueIR::typed_pointer_type<const CTrueIR::CWeightedContributor> popContributor();
869-
870-
// inputs to the addMaterials function
871-
const SAddMaterialsArgs& args;
872-
// for rewriting AST expressions
873-
core::smart_refctd_ptr<CFrontendIR> tmpAST;
874-
// for making IR nodes before we Merkle Hash them and remove duplicates (so main IR doesn't get bloated)
875-
core::smart_refctd_ptr<CTrueIR> tmpIR;
876-
// changes dynamically
877-
const CFrontendIR* srcAST;
878-
bool btdfSubtree = false;
879-
// for going over layers in the AST
880-
core::vector<const CLayer*> layerStack;
881-
// Some of the things we must canonicalize:
882-
// A ( f_0 (B + C) + D f_1 ) = f_0 B A + f_0 C A + f_1 D A
883-
// Expression nodes of the Frontend AST really come in 4 variants:
884-
// - add
885-
// - mul
886-
// - complement, which is equivalent to 1 ADD (-1 MUL x)
887-
// - function/other
888-
// BRDFs can appear only under ADD and MUL nodes in the AST not the function/other/complement, so if we want to canonicalize:
889-
// 1. The Add above can be ignored, we form full multiplication chain to the top
890-
// 2. Adds in sibling nodes (below the last add) cause us to have to add a factored copy to the IR
891-
// DFS from right-to-left (inverse order of adding children to stack), would cause us to keep postifxes of the multiplier chain every time we descend into ADD.
892-
// We want to essentially visit the parent ADD node again after dealing with its subtree (in-order traversal) then mul chain can be reset just to the parent.
893-
// If we perform DFS stack push left-to-right, we'll know the contributor already for all the leaf nodes if we push it onto the stack.
894-
// Then for all other leaf nodes we can accumulate them in the MUL chain, and adding their weighted contributor whenever we're back at an ADD node (be it the ancestor or sibling/cousin).
895-
// If the contributor is null or multiplied with a null we can keep draining the stack until we're back at its immediate parent ADD node.
896-
struct SContributor
897-
{
898-
// the "active" contributor, basically the leftmost item in the subbranch below and ADD
899-
CTrueIR::typed_pointer_type<const CTrueIR::IContributor> contributor;
900-
};
901-
core::vector<SContributor> contributorStack;
902-
// Every time we encounter an AST leaf we must add the current contributor together with all the factors multiplied together
903-
struct SFactor
904-
{
905-
using handle_t = CTrueIR::typed_pointer_type<const CTrueIR::IFactorLeaf>;
906-
// We only track multiplicative factors, we break down every BRDF equally into the canonical form
907-
handle_t handle;
908-
uint8_t negate : 1 = false;
909-
uint8_t monochrome : 1 = true;
910-
// extend later when allowing variable bucket count
911-
uint8_t liveSpectralChannels : 3 = 0b111;
912-
};
913-
// here we keep the multiplication chain unsorted so its each to add/remove nodes as we encounter them
914-
core::vector<SFactor> mulChain;
915-
// scratch for sorting the mul chain before adding a contributor
916-
core::vector<SFactor> mulChainSortScratch;
917-
// By maintaining a hash map of AST nodes which simplify to a Constant (unity, or zero, or other) we could resolve the issue of the `nonMulImmediateAncestorStackEnd`
918-
// which has us adding the same non-mul node multiple times to stack during the traversal.
919-
// However how much of that would be moving IR manipulation into the AST ?
920-
struct StackEntry
921-
{
922-
inline bool notVisited() const {return !visited;}
923-
924-
CFrontendIR::typed_pointer_type<const CFrontendIR::IExprNode> nodeH;
925-
// the ancestor ADD node to go back to if we hit a 0 MUL, or if our ADD or any other node becomes 0
926-
uint16_t nonMulImmediateAncestorStackEnd = 0;
927-
// the length of the `mulChain` at the time we first visited the node
928-
uint16_t mulChainLen = 0;
929-
bool visited = false;
930-
// only relevant for Add nodes
931-
bool addContributor = false;
932-
};
933-
core::vector<StackEntry> exprStack;
876+
NBL_API2 CTrueIR::SMaterialHandle makeFinalIR(const typed_pointer_type<const CLayer> rootH, const CFrontendIR* ast);
877+
878+
private:
879+
inline void printSubtree(const CFrontendIR::typed_pointer_type<const CFrontendIR::IExprNode> nodeH)
880+
{
881+
assert(astPrinter.exprStack.empty());
882+
astPrinter.exprStack.push_back(nodeH);
883+
args.logger.log("Subtree Dot3 : \n%s\n",system::ILogger::ELL_DEBUG,astPrinter().c_str());
884+
assert(astPrinter.exprStack.empty());
885+
}
886+
887+
using oriented_material_t = CTrueIR::SMaterial::SOriented;
888+
NBL_API2 oriented_material_t makeOrientedMaterial(const CFrontendIR::typed_pointer_type<const CFrontendIR::CLayer> rootH, const CFrontendIR* _srcAST);
889+
890+
NBL_API2 CTrueIR::typed_pointer_type<const CTrueIR::CContributorSum> makeContributors(const CFrontendIR::typed_pointer_type<const CFrontendIR::IExprNode> bxdfRootH);
891+
892+
NBL_API2 CTrueIR::typed_pointer_type<const CTrueIR::CWeightedContributor> popContributor();
893+
894+
// inputs to the addMaterials function
895+
const SAddMaterialsArgs& args;
896+
// for rewriting AST expressions
897+
core::smart_refctd_ptr<CFrontendIR> tmpAST;
898+
// for making IR nodes before we Merkle Hash them and remove duplicates (so main IR doesn't get bloated)
899+
core::smart_refctd_ptr<CTrueIR> tmpIR;
900+
// changes dynamically
901+
const CFrontendIR* srcAST;
902+
SDotPrinter astPrinter;
903+
bool btdfSubtree = false;
904+
// for going over layers in the AST
905+
core::vector<const CLayer*> layerStack;
906+
// Some of the things we must canonicalize:
907+
// A ( f_0 (B + C) + D f_1 ) = f_0 B A + f_0 C A + f_1 D A
908+
// Expression nodes of the Frontend AST really come in 4 variants:
909+
// - add
910+
// - mul
911+
// - complement, which is equivalent to 1 ADD (-1 MUL x)
912+
// - function/other
913+
// BRDFs can appear only under ADD and MUL nodes in the AST not the function/other/complement, so if we want to canonicalize:
914+
// 1. The Add above can be ignored, we form full multiplication chain to the top
915+
// 2. Adds in sibling nodes (below the last add) cause us to have to add a factored copy to the IR
916+
// DFS from right-to-left (inverse order of adding children to stack), would cause us to keep postifxes of the multiplier chain every time we descend into ADD.
917+
// We want to essentially visit the parent ADD node again after dealing with its subtree (in-order traversal) then mul chain can be reset just to the parent.
918+
// If we perform DFS stack push left-to-right, we'll know the contributor already for all the leaf nodes if we push it onto the stack.
919+
// Then for all other leaf nodes we can accumulate them in the MUL chain, and adding their weighted contributor whenever we're back at an ADD node (be it the ancestor or sibling/cousin).
920+
// If the contributor is null or multiplied with a null we can keep draining the stack until we're back at its immediate parent ADD node.
921+
struct SContributor
922+
{
923+
// the "active" contributor, basically the leftmost item in the subbranch below and ADD
924+
CTrueIR::typed_pointer_type<const CTrueIR::IContributor> contributor;
925+
};
926+
core::vector<SContributor> contributorStack;
927+
// Every time we encounter an AST leaf we must add the current contributor together with all the factors multiplied together
928+
struct SFactor
929+
{
930+
using handle_t = CTrueIR::typed_pointer_type<const CTrueIR::IFactorLeaf>;
931+
// We only track multiplicative factors, we break down every BRDF equally into the canonical form
932+
handle_t handle;
933+
uint8_t negate : 1 = false;
934+
uint8_t monochrome : 1 = true;
935+
// extend later when allowing variable bucket count
936+
uint8_t liveSpectralChannels : 3 = 0b111;
937+
};
938+
// here we keep the multiplication chain unsorted so its each to add/remove nodes as we encounter them
939+
core::vector<SFactor> mulChain;
940+
// scratch for sorting the mul chain before adding a contributor
941+
core::vector<SFactor> mulChainSortScratch;
942+
// By maintaining a hash map of AST nodes which simplify to a Constant (unity, or zero, or other) we could resolve the issue of the `nonMulImmediateAncestorStackEnd`
943+
// which has us adding the same non-mul node multiple times to stack during the traversal.
944+
// However how much of that would be moving IR manipulation into the AST ?
945+
struct StackEntry
946+
{
947+
inline bool notVisited() const {return !visited;}
948+
949+
CFrontendIR::typed_pointer_type<const CFrontendIR::IExprNode> nodeH;
950+
// the ancestor ADD node to go back to if we hit a 0 MUL, or if our ADD or any other node becomes 0
951+
uint16_t nonMulImmediateAncestorStackEnd = 0;
952+
// the length of the `mulChain` at the time we first visited the node
953+
uint16_t mulChainLen = 0;
954+
bool visited = false;
955+
// only relevant for Add nodes
956+
bool addContributor = false;
957+
};
958+
core::vector<StackEntry> exprStack;
934959
};
935-
NBL_API2 CTrueIR::SMaterialHandle makeFinalIR(const typed_pointer_type<const CLayer> rootH, SAdd2IRSession& session) const;
936960

937961
inline core::string getNodeID(const typed_pointer_type<const INode> handle) const {return core::string("_")+std::to_string(handle.value);}
938962
inline core::string getLabelledNodeID(const typed_pointer_type<const INode> handle) const
@@ -952,6 +976,40 @@ class CFrontendIR final : public CNodePool
952976
return retval;
953977
}
954978
};
979+
}
980+
981+
// specialize the `to_string
982+
namespace nbl::system::impl
983+
{
984+
template<>
985+
struct to_string_helper<nbl::asset::material_compiler3::CFrontendIR::IExprNode::Type>
986+
{
987+
using type = nbl::asset::material_compiler3::CFrontendIR::IExprNode::Type;
988+
989+
static inline std::string __call(const type value)
990+
{
991+
switch (value)
992+
{
993+
case type::Contributor:
994+
return "Contributor";
995+
case type::Mul:
996+
return "Mul";
997+
case type::Complement:
998+
return "Complement";
999+
case type::SpectralVariable:
1000+
return "SpectralVariable";
1001+
case type::Other:
1002+
return "Other";
1003+
default:
1004+
break;
1005+
}
1006+
return "";
1007+
}
1008+
};
1009+
}
1010+
1011+
namespace nbl::asset::material_compiler3
1012+
{
9551013

9561014
inline bool CFrontendIR::valid(const typed_pointer_type<const CLayer> rootHandle, system::logger_opt_ptr logger) const
9571015
{

include/nbl/asset/material_compiler3/CTrueIR.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77

88
#include "nbl/system/ILogger.h"
9+
#include "nbl/system/to_string.h"
910

1011
#include "nbl/asset/material_compiler3/CNodePool.h"
1112
#include "nbl/asset/format/EColorSpace.h"
@@ -657,6 +658,7 @@ class CTrueIR : public CNodePool // TODO: turn into an asset!
657658
public:
658659
inline bool operator==(const SBasicNodes& other) const = default;
659660

661+
typed_pointer_type<const COrientedLayer> errorLayer = {};
660662
typed_pointer_type<const CContributorSum> blackHoleBxDF = {};
661663
typed_pointer_type<const CContributorSum> errorBxDF = {};
662664

0 commit comments

Comments
 (0)