Skip to content

Commit 29876ed

Browse files
FlorianZpixar-oss
authored andcommitted
Adds the logic that performs authored value invalidation, but does not yet exercise this logic.
(Internal change: 2365433)
1 parent 3420b60 commit 29876ed

19 files changed

+551
-51
lines changed

pxr/exec/ef/leafNode.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,14 @@ class EF_API_TYPE EfLeafNode final : public VdfNode
5252
return input ? &(*input)[0].GetSourceOutput() : nullptr;
5353
}
5454

55+
/// Returns the single masked output the leaf node sources its value from.
56+
/// Returns an invalid masked output if the leaf node is not connected.
57+
///
58+
static VdfMaskedOutput GetSourceMaskedOutput(const VdfNode &node) {
59+
const VdfInput *const input = node.GetInputsIterator().begin()->second;
60+
return input ? (*input)[0].GetSourceMaskedOutput() : VdfMaskedOutput();
61+
}
62+
5563
EF_API
5664
EfLeafNode(VdfNetwork *network, TfType inputType);
5765

pxr/exec/esf/attribute.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,7 @@ class ESF_API_TYPE EsfAttributeInterface : public EsfPropertyInterface
4949
///
5050
/// \see UsdAttribute::Get
5151
///
52-
bool Get(VtValue *value, UsdTimeCode time) const
53-
{
52+
bool Get(VtValue *value, UsdTimeCode time) const {
5453
return _Get(value, time);
5554
}
5655

pxr/exec/exec/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ pxr_library(exec
2020
api.h
2121
providerResolution.h
2222
registerSchema.h
23+
request.h
2324
types.h
2425

2526
PUBLIC_CLASSES

pxr/exec/exec/attributeInputNode.h

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,18 @@ class Exec_AttributeInputNode final : public VdfNode
3838

3939
~Exec_AttributeInputNode() override;
4040

41+
/// Returns the scene path to the attribute that the input value is sourced
42+
/// from.
43+
///
44+
SdfPath GetAttributePath() const {
45+
return _attribute->GetPath(nullptr);
46+
}
47+
4148
void Compute(VdfContext const& ctx) const override;
4249

4350
private:
44-
// TODO: Long-term, we will need some kind of handle to the attribute that is
45-
// stable across namespace edits.
51+
// TODO: Long-term, we will need some kind of handle to the attribute that
52+
// is stable across namespace edits.
4653
const EsfAttribute _attribute;
4754
};
4855

pxr/exec/exec/cacheView.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ Exec_CacheView::Extract(int idx, VtValue *result) const
4040
return false;
4141
}
4242

43+
// TODO: VdfVector -> VtValue extraction
44+
4345
TF_CODING_ERROR("Extraction is not yet implemented");
4446
return false;
4547
}

pxr/exec/exec/cacheView.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ class Exec_CacheView
4040
bool Extract(int idx, VtValue *result) const;
4141

4242
private:
43-
friend class ExecSystem;
43+
friend class Exec_RequestImpl;
4444
Exec_CacheView(
4545
const VdfExecutorInterface *executor,
4646
TfSpan<const VdfMaskedOutput> outputs)

pxr/exec/exec/program.cpp

Lines changed: 151 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,14 @@
88

99
#include "pxr/base/tf/span.h"
1010
#include "pxr/base/tf/token.h"
11+
#include "pxr/base/trace/trace.h"
1112
#include "pxr/exec/ef/timeInputNode.h"
1213
#include "pxr/exec/ef/timeInterval.h"
14+
#include "pxr/exec/vdf/executorInterface.h"
1315
#include "pxr/exec/vdf/grapher.h"
1416
#include "pxr/exec/vdf/maskedOutput.h"
1517
#include "pxr/exec/vdf/node.h"
18+
#include "pxr/exec/vdf/typedVector.h"
1619
#include "pxr/usd/sdf/path.h"
1720

1821
PXR_NAMESPACE_OPEN_SCOPE
@@ -79,12 +82,140 @@ Exec_Program::Connect(
7982
inputNode->GetId(), inputName, journal);
8083
}
8184

82-
void
85+
std::tuple<const std::vector<const VdfNode *> &, TfBits, EfTimeInterval>
8386
Exec_Program::InvalidateAuthoredValues(
8487
TfSpan<ExecInvalidAuthoredValue> invalidProperties)
8588
{
86-
// TODO: Leaf node and request invalidation, as well as queueing up main
87-
// executor invalidation.
89+
TRACE_FUNCTION();
90+
91+
const size_t numInvalidProperties = invalidProperties.size();
92+
93+
VdfMaskedOutputVector leafInvalidationRequest;
94+
leafInvalidationRequest.reserve(numInvalidProperties);
95+
TfBits compiledProperties(numInvalidProperties);
96+
_uninitializedInputNodes.reserve(numInvalidProperties);
97+
EfTimeInterval totalInvalidInterval;
98+
99+
for (size_t i = 0; i < numInvalidProperties; ++i) {
100+
const auto &[path, interval] = invalidProperties[i];
101+
const auto it = _inputNodes.find(path);
102+
103+
// Not every invalid property is also an input to the exec network.
104+
// If any of these properties have been included in an exec request,
105+
// clients still expect to receive invalidation notices, though.
106+
// However, we can skip including this property in the search for
107+
// dependent leaf nodes in that case.
108+
const bool isCompiled = it != _inputNodes.end();
109+
if (!isCompiled) {
110+
continue;
111+
}
112+
113+
// Indicate this property was compiled.
114+
compiledProperties.Set(i);
115+
116+
// Get the input node from the network.
117+
const VdfId nodeId = it->second;
118+
VdfNode *const node = _network.GetNodeById(nodeId);
119+
120+
// We expect uncompiled input nodes to have been removed from the
121+
// _inputNodes array by now.
122+
if (!TF_VERIFY(node)) {
123+
continue;
124+
}
125+
126+
// If this is an input node to the exec network, we need to make sure
127+
// that it is re-initialized before the next round of evaluation.
128+
_uninitializedInputNodes.push_back(nodeId);
129+
130+
// Queue the input node's output(s) for leaf node invalidation.
131+
leafInvalidationRequest.emplace_back(
132+
node->GetOutput(), VdfMask::AllOnes(1));
133+
134+
// Accumulate the invalid time interval.
135+
totalInvalidInterval |= interval;
136+
}
137+
138+
// Find all the leaf nodes reachable from the input nodes.
139+
// We won't ask the leaf node cache to incur the cost of performing
140+
// incremental updates on the resulting cached traversal, because it is not
141+
// guaranteed that we will repeatedly see the exact same authored value
142+
// invalidation across rounds of structural change processing (in contrast
143+
// to time invalidation).
144+
const std::vector<const VdfNode *> &leafNodes = _leafNodeCache.FindNodes(
145+
leafInvalidationRequest, /* updateIncrementally = */ false);
146+
147+
// TODO: Perform page cache invalidation.
148+
149+
return {leafNodes, compiledProperties, totalInvalidInterval};
150+
}
151+
152+
void
153+
Exec_Program::InitializeTime(
154+
VdfExecutorInterface *const executor,
155+
const EfTime &newTime) const
156+
{
157+
// Retrieve the old time from the executor data manager.
158+
const VdfVector *const oldTimeVector = executor->GetOutputValue(
159+
*_timeInputNode->GetOutput(), VdfMask::AllOnes(1));
160+
161+
// If there isn't already a time value stored in the executor data manager,
162+
// perform first time initialization and return.
163+
if (!oldTimeVector) {
164+
executor->SetOutputValue(
165+
*_timeInputNode->GetOutput(),
166+
VdfTypedVector<EfTime>(newTime),
167+
VdfMask::AllOnes(1));
168+
return;
169+
}
170+
171+
// Get the old time value from the vector. If there is not change in time,
172+
// we can return without performing invalidation.
173+
const EfTime oldTime = oldTimeVector->GetReadAccessor<EfTime>()[0];
174+
if (oldTime == newTime) {
175+
return;
176+
}
177+
178+
TRACE_FUNCTION();
179+
180+
// TODO: Collect time dependent properties and perform executor invalidation
181+
// after time changes.
182+
183+
// Set the new time value on the executor.
184+
executor->SetOutputValue(
185+
*_timeInputNode->GetOutput(),
186+
VdfTypedVector<EfTime>(newTime),
187+
VdfMask::AllOnes(1));
188+
}
189+
190+
VdfMaskedOutputVector
191+
Exec_Program::InitializeInputNodes()
192+
{
193+
if (_uninitializedInputNodes.empty()) {
194+
return {};
195+
}
196+
197+
TRACE_FUNCTION();
198+
199+
// Collect the invalid outputs for all invalid input nodes accumulated
200+
// through previous rounds of authored value invalidation.
201+
VdfMaskedOutputVector invalidationRequest;
202+
invalidationRequest.reserve(_uninitializedInputNodes.size());
203+
for (const VdfId nodeId : _uninitializedInputNodes) {
204+
VdfNode *const node = _network.GetNodeById(nodeId);
205+
206+
// Some nodes may have been uncompiled since they were marked as being
207+
// uninitialized. It's okay to simply skip these nodes.
208+
if (!node) {
209+
continue;
210+
}
211+
212+
invalidationRequest.emplace_back(
213+
node->GetOutput(), VdfMask::AllOnes(1));
214+
}
215+
216+
_uninitializedInputNodes.clear();
217+
218+
return invalidationRequest;
88219
}
89220

90221
void
@@ -99,4 +230,21 @@ Exec_Program::_AddNode(const EsfJournal &journal, const VdfNode *node)
99230
_uncompilationTable.AddRulesForNode(node->GetId(), journal);
100231
}
101232

233+
void
234+
Exec_Program::_RegisterInputNode(const Exec_AttributeInputNode *const inputNode)
235+
{
236+
const auto [it, emplaced] = _inputNodes.emplace(
237+
inputNode->GetAttributePath(), inputNode->GetId());
238+
TF_VERIFY(emplaced);
239+
}
240+
241+
void
242+
Exec_Program::_UnregisterInputNode(
243+
const Exec_AttributeInputNode *const inputNode)
244+
{
245+
const SdfPath attributePath = inputNode->GetAttributePath();
246+
const size_t numErased = _inputNodes.unsafe_erase(attributePath);
247+
TF_VERIFY(numErased);
248+
}
249+
102250
PXR_NAMESPACE_CLOSE_SCOPE

pxr/exec/exec/program.h

Lines changed: 61 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,22 +9,36 @@
99

1010
#include "pxr/pxr.h"
1111

12+
#include "pxr/exec/exec/attributeInputNode.h"
1213
#include "pxr/exec/exec/compiledOutputCache.h"
1314
#include "pxr/exec/exec/types.h"
1415
#include "pxr/exec/exec/uncompilationTable.h"
1516

17+
#include "pxr/base/tf/bits.h"
1618
#include "pxr/exec/ef/leafNodeCache.h"
19+
#include "pxr/exec/ef/time.h"
1720
#include "pxr/exec/vdf/maskedOutput.h"
21+
#include "pxr/exec/vdf/maskedOutputVector.h"
1822
#include "pxr/exec/vdf/network.h"
23+
#include "pxr/exec/vdf/types.h"
24+
#include "pxr/usd/sdf/path.h"
25+
26+
#include <tbb/concurrent_unordered_map.h>
1927

2028
#include <memory>
29+
#include <tuple>
2130
#include <type_traits>
31+
#include <vector>
2232

2333
PXR_NAMESPACE_OPEN_SCOPE
2434

35+
class EfTime;
2536
class EfTimeInputNode;
37+
class EfTimeInterval;
2638
class EsfJournal;
39+
class TfBits;
2740
template <typename> class TfSpan;
41+
class VdfExecutorInterface;
2842
class VdfNode;
2943

3044
/// Owns a VdfNetwork and related data structures to access and modify the
@@ -126,23 +140,61 @@ class Exec_Program
126140
}
127141

128142
/// Notifies the program of authored value invalidation.
129-
void InvalidateAuthoredValues(
143+
std::tuple<const std::vector<const VdfNode *> &, TfBits, EfTimeInterval>
144+
InvalidateAuthoredValues(
130145
TfSpan<ExecInvalidAuthoredValue> invalidProperties);
131146

147+
/// Initializes time in the network.
148+
void InitializeTime(
149+
VdfExecutorInterface *executor,
150+
const EfTime &newTime) const;
151+
152+
/// Initializes all invalid input nodes in the network, and returns a vector
153+
/// of invalid input node outputs.
154+
///
155+
VdfMaskedOutputVector InitializeInputNodes();
156+
132157
/// Writes the compiled network to a file at \p filename.
133158
void GraphNetwork(const char *filename) const;
134159

135160
private:
136-
// Updates data strucutres for a newly-added node.
161+
// Updates data structures for a newly-added node.
137162
void _AddNode(const EsfJournal &journal, const VdfNode *node);
138163

139-
class _EditMonitor;
164+
// Registers an input node for authored value initialization.
165+
void _RegisterInputNode(const Exec_AttributeInputNode *inputNode);
166+
167+
// Unregisters an input node from authored value initialization.
168+
void _UnregisterInputNode(const Exec_AttributeInputNode *inputNode);
140169

170+
private:
171+
// The compiled data flow network.
141172
VdfNetwork _network;
173+
174+
// Every network always has a compiled time input node.
142175
EfTimeInputNode *const _timeInputNode;
176+
177+
// A cache of compiled outputs keys and corresponding data flow outputs.
143178
Exec_CompiledOutputCache _compiledOutputCache;
179+
180+
// Maps scene paths to data flow network that must be uncompiled in response
181+
// to edits to those scene paths.
144182
Exec_UncompilationTable _uncompilationTable;
183+
184+
// Collection of compiled leaf nodes.
145185
EfLeafNodeCache _leafNodeCache;
186+
187+
// Collection of compiled input nodes.
188+
// TODO: We will need to update this map in response to namespace edits,
189+
// once they are supported.
190+
tbb::concurrent_unordered_map<SdfPath, VdfId, SdfPath::Hash> _inputNodes;
191+
192+
// Input nodes currently queued for initialization.
193+
std::vector<VdfId> _uninitializedInputNodes;
194+
195+
// On behalf of the program intercepts and responds to fine-grained network
196+
// edits.
197+
class _EditMonitor;
146198
std::unique_ptr<_EditMonitor> _editMonitor;
147199
};
148200

@@ -162,6 +214,12 @@ NodeType *Exec_Program::CreateNode(
162214
NodeType *const node = new NodeType(
163215
&_network, std::forward<NodeCtorArgs>(nodeCtorArgs)...);
164216
_AddNode(journal, node);
217+
218+
// Input nodes are tracked for authored value initialization.
219+
if constexpr (std::is_same_v<Exec_AttributeInputNode, NodeType>) {
220+
_RegisterInputNode(node);
221+
}
222+
165223
return node;
166224
}
167225

0 commit comments

Comments
 (0)