Skip to content

Commit 0c7c52b

Browse files
sunyabpixar-oss
authored andcommitted
pcp: Small cleanups to instancing utility functions
- Update Pcp_PrimIndexIsInstanceable to use a subtree iterator instead of a stack of nodes for strength order traversals. This gives us the same behavior while simplifying the code and avoiding potential memory allocations. Note that the stack of nodes was originally used instead of a recursive approach to avoid potential stack overflows in large graphs. The subtree iterator maintains that property. - The instancing traversal helpers now use the cached transitive dependency bit stored on each node instead of manually keeping track of whether (Internal change: 2392191)
1 parent 1e7036d commit 0c7c52b

File tree

2 files changed

+19
-55
lines changed

2 files changed

+19
-55
lines changed

pxr/usd/pcp/instancing.cpp

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
#include "pxr/usd/pcp/instancing.h"
99

1010
#include "pxr/base/tf/envSetting.h"
11-
#include "pxr/base/tf/smallVector.h"
1211
#include "pxr/base/trace/trace.h"
1312

1413
PXR_NAMESPACE_OPEN_SCOPE
@@ -73,15 +72,11 @@ Pcp_PrimIndexIsInstanceable(
7372
// Compose the value of the 'instanceable' metadata to see if this
7473
// prim has been tagged as instanceable.
7574
bool isInstance = false;
76-
static const TfToken instanceField = SdfFieldKeys->Instanceable;
77-
// Stack of nodes left to visit, in strong-to-weak order.
78-
// Strongest open node is top of the stack.
79-
TfSmallVector<PcpNodeRef, 64> nodesToVisit;
80-
nodesToVisit.push_back(primIndex.GetRootNode());
8175
bool opinionFound = false;
82-
while (!nodesToVisit.empty()) {
83-
PcpNodeRef node = nodesToVisit.back();
84-
nodesToVisit.pop_back();
76+
static const TfToken instanceField = SdfFieldKeys->Instanceable;
77+
for (const PcpNodeRef& node :
78+
Pcp_GetSubtreeRange(primIndex.GetRootNode())) {
79+
8580
if (node.CanContributeSpecs()) {
8681
const PcpLayerStackSite& site = node.GetSite();
8782
for (SdfLayerRefPtr const& layer: site.layerStack->GetLayers()) {
@@ -94,9 +89,6 @@ Pcp_PrimIndexIsInstanceable(
9489
break;
9590
}
9691
}
97-
TF_REVERSE_FOR_ALL(childIt, Pcp_GetChildrenRange(node)) {
98-
nodesToVisit.push_back(*childIt);
99-
}
10092
}
10193
return isInstance;
10294
}

pxr/usd/pcp/instancing.h

Lines changed: 15 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,7 @@ Pcp_TraverseInstanceableWeakToStrong(
7070

7171
inline bool
7272
Pcp_ChildNodeIsInstanceable(
73-
const PcpNodeRef& node,
74-
bool *hasAnyDirectArcsInNodeChain)
73+
const PcpNodeRef& node)
7574
{
7675
// Non-ancestral nodes are instanceable: they represent a direct
7776
// composition arc to a portion of scenegraph that could be shared
@@ -80,34 +79,22 @@ Pcp_ChildNodeIsInstanceable(
8079
// exist in the graph because they were composed in a subtree of direct
8180
// arc to a subroot path. These nodes are also instanceable as they are
8281
// considered part of the direct arc that brought them in. This is why we
83-
// keep track of and check whether there are any direct arcs in the node's
84-
// chain up to the root node when determining if a node is instanceable.
85-
*hasAnyDirectArcsInNodeChain =
86-
*hasAnyDirectArcsInNodeChain || !node.IsDueToAncestor();
87-
82+
// check whether there are any direct arcs in the node's chain up to the
83+
// root node when determining if a node is instanceable.
84+
//
8885
// If a node has no specs or cannot contribute specs, it is not instanceable
8986
// since it has no opinions to contribute to the prim index. In particular,
9087
// this allows prim indexes with implied arcs in different layer stacks
9188
// that have no overrides to still be considered equivalent for sharing.
92-
return *hasAnyDirectArcsInNodeChain &&
89+
return node.HasTransitiveDirectDependency() &&
9390
node.CanContributeSpecs() && node.HasSpecs();
9491
}
9592

9693
inline bool
9794
Pcp_ChildNodeIsDirectOrInDirectArcSubtree(
9895
const PcpNodeRef& node)
9996
{
100-
if (node.IsRootNode() || !node.IsDueToAncestor()) {
101-
return true;
102-
}
103-
for (PcpNodeRef parent = node.GetParentNode();
104-
!parent.IsRootNode();
105-
parent = parent.GetParentNode()) {
106-
if (!parent.IsDueToAncestor()) {
107-
return true;
108-
}
109-
}
110-
return false;
97+
return node.IsRootNode() || node.HasTransitiveDirectDependency();
11198
}
11299

113100
inline bool
@@ -122,8 +109,7 @@ template <class Visitor>
122109
inline void
123110
Pcp_TraverseInstanceableStrongToWeakHelper(
124111
const PcpNodeRef& node,
125-
Visitor* visitor,
126-
bool hasAnyDirectArcsInNodeChain)
112+
Visitor* visitor)
127113
{
128114
// If the node is culled, the entire subtree rooted at this node
129115
// does not contribute to the prim index, so we can prune the
@@ -132,16 +118,14 @@ Pcp_TraverseInstanceableStrongToWeakHelper(
132118
return;
133119
}
134120

135-
const bool isInstanceable =
136-
Pcp_ChildNodeIsInstanceable(node, &hasAnyDirectArcsInNodeChain);
121+
const bool isInstanceable = Pcp_ChildNodeIsInstanceable(node);
137122
if (!visitor->Visit(node, isInstanceable)) {
138123
return;
139124
}
140125

141126
TF_FOR_ALL(childIt, Pcp_GetChildrenRange(node)) {
142127
const PcpNodeRef& childNode = *childIt;
143-
Pcp_TraverseInstanceableStrongToWeakHelper(
144-
childNode, visitor, hasAnyDirectArcsInNodeChain);
128+
Pcp_TraverseInstanceableStrongToWeakHelper(childNode, visitor);
145129
}
146130
}
147131

@@ -158,17 +142,15 @@ Pcp_TraverseInstanceableStrongToWeak(
158142

159143
TF_FOR_ALL(childIt, Pcp_GetChildrenRange(rootNode)) {
160144
const PcpNodeRef& childNode = *childIt;
161-
Pcp_TraverseInstanceableStrongToWeakHelper(
162-
childNode, visitor, /* hasAnyDirectArcsInNodeChain = */ false);
145+
Pcp_TraverseInstanceableStrongToWeakHelper(childNode, visitor);
163146
}
164147
}
165148

166149
template <class Visitor>
167150
inline void
168151
Pcp_TraverseInstanceableWeakToStrongHelper(
169152
const PcpNodeRef& node,
170-
Visitor* visitor,
171-
bool hasAnyDirectArcsInNodeChain)
153+
Visitor* visitor)
172154
{
173155
// If the node is culled, the entire subtree rooted at this node
174156
// does not contribute to the prim index, so we can prune the
@@ -177,13 +159,11 @@ Pcp_TraverseInstanceableWeakToStrongHelper(
177159
return;
178160
}
179161

180-
const bool isInstanceable =
181-
Pcp_ChildNodeIsInstanceable(node, &hasAnyDirectArcsInNodeChain);
162+
const bool isInstanceable = Pcp_ChildNodeIsInstanceable(node);
182163

183164
TF_REVERSE_FOR_ALL(childIt, Pcp_GetChildrenRange(node)) {
184165
const PcpNodeRef& childNode = *childIt;
185-
Pcp_TraverseInstanceableWeakToStrongHelper(
186-
childNode, visitor, hasAnyDirectArcsInNodeChain);
166+
Pcp_TraverseInstanceableWeakToStrongHelper(childNode, visitor);
187167
}
188168

189169
visitor->Visit(node, isInstanceable);
@@ -198,20 +178,12 @@ Pcp_TraverseInstanceableWeakToStrong(
198178
if (subtreeRootNode.IsRootNode()) {
199179
TF_REVERSE_FOR_ALL(childIt, Pcp_GetChildrenRange(subtreeRootNode)) {
200180
const PcpNodeRef& childNode = *childIt;
201-
Pcp_TraverseInstanceableWeakToStrongHelper(
202-
childNode, visitor, /* hasAnyDirectArcsInNodeChain = */ false);
181+
Pcp_TraverseInstanceableWeakToStrongHelper(childNode, visitor);
203182
}
204183

205184
visitor->Visit(subtreeRootNode, /* nodeIsInstanceable = */ false);
206185
} else {
207-
// Because we're starting below the root node, we need to find out if
208-
// there are any direct arcs between the subtree parent and the true
209-
// root node so that we can correctly determine in there are any direct
210-
// nodes in whole node chain for each subtree node.
211-
const bool hasAnyDirectArcsInNodeChain =
212-
Pcp_ChildNodeIsDirectOrInDirectArcSubtree(subtreeRootNode);
213-
Pcp_TraverseInstanceableWeakToStrongHelper(
214-
subtreeRootNode, visitor, hasAnyDirectArcsInNodeChain);
186+
Pcp_TraverseInstanceableWeakToStrongHelper(subtreeRootNode, visitor);
215187
}
216188
}
217189

0 commit comments

Comments
 (0)