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
1821PXR_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>
8386Exec_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
90221void
@@ -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+
102250PXR_NAMESPACE_CLOSE_SCOPE
0 commit comments