HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
context.h
Go to the documentation of this file.
1 //
2 // Copyright 2025 Pixar
3 //
4 // Licensed under the terms set forth in the LICENSE.txt file available at
5 // https://openusd.org/license.
6 //
7 #ifndef PXR_EXEC_VDF_CONTEXT_H
8 #define PXR_EXEC_VDF_CONTEXT_H
9 
10 /// \file
11 
12 #include "pxr/pxr.h"
13 
14 #include "pxr/exec/vdf/api.h"
16 #include "pxr/exec/vdf/error.h"
20 #include "pxr/exec/vdf/node.h"
22 #include "pxr/exec/vdf/traits.h"
23 #include "pxr/exec/vdf/types.h"
24 #include "pxr/exec/vdf/vector.h"
25 
28 #include "pxr/base/tf/mallocTag.h"
29 
31 
32 class TfToken;
33 
34 ////////////////////////////////////////////////////////////////////////////////
35 ///
36 /// A context is the parameter bundle passed to callbacks of computations.
37 /// It is the only API through which functions have access to their inputs.
38 ///
40 {
41 public:
42 
43  // VdfContext should not be copied or assigned to.
44  VdfContext(const VdfContext &rhs) = delete;
45  VdfContext &operator=(const VdfContext &rhs) = delete;
46 
47  /// Constructs a VdfContext for the given \p node with the current
48  /// evaluation \p state.
49  ///
52  const VdfNode &node) :
53  VdfContext(state, node, VdfScheduleTaskInvalid)
54  {}
55 
56  /// Constructs a VdfContext for the given \p node and node \p invocation
57  /// with the current evaluation \p state.
58  ///
61  const VdfNode &node,
62  const VdfScheduleTaskIndex invocation) :
63  _state(state),
64  _node(node),
65  _invocation(invocation)
66  {}
67 
68  /// Returns a value from the input named \c name of type \c T.
69  /// This method assumes that the caller expects only a single value to
70  /// exist on its input.
71  ///
72  template<typename T>
74  GetInputValue(const TfToken &name) const;
75 
76  /// Returns a pointer to the value from the input named \p name if the
77  /// input has a valid value, otherwise returns nullptr.
78  ///
79  template<typename T>
80  inline const T *
81  GetInputValuePtr(const TfToken &name) const;
82 
83  /// Returns a pointer to the value from the input named \p name if the
84  /// input has a valid value, otherwise returns \p defPtr.
85  ///
86  template<typename T>
87  inline const T *
88  GetInputValuePtr(const TfToken &name, const T *defPtr) const;
89 
90  /// Returns true, if there are input values from the input named \c name
91  /// of type \c T.
92  ///
93  template<typename T>
94  inline bool HasInputValue(const TfToken &name) const;
95 
96  /// Returns true if the output named \p outputName is requested by at least
97  /// one downstream node, or false if there are no consumers for the output
98  /// or if \p outputName isn't a valid output on this node.
99  ///
100  /// This can be used by the node callback to avoid computing expensive
101  /// outputs that are not needed.
102  ///
103  /// NOTE: It's far preferred for computations to be designed with
104  /// appropriate granularity, but this may be used in cases where the
105  /// computation of multiple outputs isn't feasibly separable.
106  ///
107  VDF_API
108  bool IsOutputRequested(const TfToken &outputName) const;
109 
110  /// Sets the value of the output named \p outputName to \p value.
111  ///
112  /// This can be used when the node already has all the answers and
113  /// doesn't want to bother with iterators.
114  ///
115  /// Note that this method currently always performs a full copy, because
116  /// it can't tell if we are allowed to take ownership of the given output.
117  ///
118  template<typename T>
119  inline void SetOutput(const TfToken &outputName,
120  const T &value) const;
121 
122  /// Sets the value of the output to \p value.
123  ///
124  /// This can be used when the node already has all the answers and
125  /// doesn't want to bother with iterators.
126  ///
127  /// Note that this method currently always performs a full copy, because
128  /// it can't tell if we are allowed to take ownership of the given output.
129  ///
130  /// It is invalid to call this method on any node that does not have
131  /// exactly one output.
132  ///
133  template<typename T>
134  inline void SetOutput(const T &value) const;
135 
136  /// Sets the value of the output to \p value.
137  ///
138  /// This can be used when the node already has all the answers and
139  /// doesn't want to bother with iterators.
140  ///
141  /// This method moves the data into the output, and thus avoids a copy.
142  /// However, note that \p value will no longer contain any meaningful data
143  /// after this method returned.
144  ///
145  /// It is invalid to call this method on any node that does not have
146  /// exactly one output.
147  ///
148  template<typename T>
149  inline void SetOutput(T &&value) const;
150 
151  /// Sets the value of the output named \p outputName to \p value.
152  ///
153  /// This can be used when the node already has all the answers and
154  /// doesn't want to bother with iterators.
155  ///
156  /// This method moves the data into the output, and thus avoids a copy.
157  /// However, note that \p value will no longer contain any meaningful data
158  /// after this method returned.
159  ///
160  template<typename T>
161  inline void SetOutput(const TfToken &outputName,
162  T &&value) const;
163 
164  /// Sets an empty value on the output.
165  ///
166  /// It is invalid to call this method on any node that does not have
167  /// exactly one output.
168  ///
169  VDF_API
170  void SetEmptyOutput() const;
171 
172  /// Sets an empty value on the output named \p outputName.
173  ///
174  VDF_API
175  void SetEmptyOutput(const TfToken &outputName) const;
176 
177  /// Sets the one and only output to have the same output value
178  /// as the value on the output connected to input \p inputName.
179  ///
180  /// Calling this method when the input doesn't need to be modified
181  /// gives the system an opportunity to apply some optimizations when
182  /// possible.
183  ///
184  /// Note that this optimization might not take effect in certain
185  /// circumstances.
186  ///
187  VDF_API
188  void SetOutputToReferenceInput(const TfToken &inputName) const;
189 
190 
191  /// \name Error Reporting
192  /// @{
193 
194  /// Reports a warning to the system that was encountered at runtime.
195  ///
196  /// Exactly how the warning is presented to the user, if at all,
197  /// is up to the host system.
198  ///
199  /// Multiple calls to Warn() from the same node will cause the messages
200  /// to be concatenated.
201  ///
202  VDF_API
203  void Warn(const char *fmt, ...) const ARCH_PRINTF_FUNCTION(2, 3);
204 
205 
206  /// @}
207 
208 
209  /// \name Debugging
210  /// @{
211 
212  /// Returns the debug name for the node for this context.
213  ///
214  VDF_API
215  std::string GetNodeDebugName() const;
216 
217  /// Invokes a coding error with an error message and a graph around the
218  /// node that this context is currently referencing.
219  /// It takes a printf-style format specification.
220  ///
221  VDF_API
222  void CodingError(const char *fmt, ...) const ARCH_PRINTF_FUNCTION(2, 3);
223 
224  /// @}
225 
226 
227 private:
228 
229  // This API is for VdfIterators to access internal context data.
230  friend class VdfIterator;
231 
232  // Speculation nodes need to call _GetExecutor.
234 
235  // Returns the first input value on the given input, or a null pointer, if
236  // no such value exists.
237  //
238  template<typename T>
239  inline const T *_GetFirstInputValue(const TfToken &name) const;
240 
241  // Retrieves the request and affects mask of the requested output, if
242  // available. Returns \c true if the output is scheduled, and \c false
243  // otherwise.
244  //
245  // Note, output must be an output on the current node!
246  //
247  VDF_API
248  bool _GetOutputMasks(
249  const VdfOutput &output,
250  const VdfMask **requestMask,
251  const VdfMask **affectsMask) const;
252 
253  // Returns true when the output is scheduled and required, and
254  // false otherwise. Used by special iterators to avoid computing outputs
255  // that aren't necessary.
256  //
257  VDF_API
258  bool _IsRequiredOutput(const VdfOutput &output) const;
259 
260  // Returns the request mask of \p output, if the output has been scheduled
261  // and \c NULL otherwise.
262  //
263  const VdfMask *_GetRequestMask(const VdfOutput &output) const;
264 
265  // Returns the current node
266  //
267  const VdfNode &_GetNode() const { return _node; }
268 
269  // Returns the executor for this context.
270  //
271  const VdfExecutorInterface &_GetExecutor() const { return _state.GetExecutor(); }
272 
273  // Returns the schedule for this context.
274  //
275  const VdfSchedule &_GetSchedule() const { return _state.GetSchedule(); }
276 
277  // Returns the error logger for this context.
278  //
279  VdfExecutorErrorLogger *_GetErrorLogger() const {
280  return _state.GetErrorLogger();
281  }
282 
283 private:
284 
285  // The evaluation state
286  const VdfEvaluationState &_state;
287 
288  // The node this context has been built for.
289  const VdfNode &_node;
290 
291  // The current node invocation index. If this context is not for a node
292  // with multiple invocations, this will be set to VdfScheduleTaskInvalid.
293  const VdfScheduleTaskIndex _invocation;
294 };
295 
296 ///////////////////////////////////////////////////////////////////////////////
297 
298 template<typename T>
301 {
302  // Calling this API means that the client expects there to be one and
303  // only one value, so we always return the first one here if there are
304  // any.
305  if (const T *value = _GetFirstInputValue<T>(name)) {
306  return *value;
307  }
308 
310  "No input value for token '%s' on node '%s'",
311  name.GetText(), GetNodeDebugName().c_str());
312 
313  // Ask the type registry for the fallback value to use.
315 }
316 
317 template<typename T>
318 inline const T *
320 {
321  return _GetFirstInputValue<T>(name);
322 }
323 
324 template<typename T>
325 inline const T *
326 VdfContext::GetInputValuePtr(const TfToken &name, const T *defPtr) const
327 {
328  const T *value = _GetFirstInputValue<T>(name);
329  return value ? value : defPtr;
330 }
331 
332 template<typename T>
333 bool
335 {
336  // Note that we generally shouldn't have to check the result of
337  // _GetFirstInputValue(name) here, as opposed to simply checking whether
338  // there are any connections with non-zero masks on input.
339  //
340  // The one exception, unfortunately, is the EfSelectNode, which selects
341  // amongst its inputs. In the case where it doesn't have any inputs, it
342  // doesn't set an output at all even though it is connected. We technically
343  // shouldn't be compiling a select node at all when there is no input, but
344  // we do so to make sure that "first-time" constraints is fast. We should
345  // revisit that.
346 
347  return _GetFirstInputValue<T>(name);
348 }
349 
350 template<typename T>
351 const T *
352 VdfContext::_GetFirstInputValue(const TfToken &name) const
353 {
354  // We need to implement code fairly similar to what the VdfReadIterator has
355  // to do. The up side is that we can implement a more specific semantic
356  // (namely that we return nullptr when the input is connected but not
357  // executed, whereas the read iterator will error out). Also we have the
358  // opportunity to squeeze some performance out. The downside is that we
359  // have to make sure that whenever we return true, that the read iterator
360  // can reasonably provide a value. So the code must be kept at least
361  // somewhat in sync.
362  const VdfInput *input = _GetNode().GetInput(name);
363  if (!input) {
364  return nullptr;
365  }
366 
367  for (const VdfConnection *connection : input->GetConnections()) {
368  const VdfMask &mask = connection->GetMask();
369  const size_t firstIndex = mask.GetFirstSet();
370  if (firstIndex < mask.GetSize()) {
371  // The connection has a mask on it, make sure there's a value
372  // present.
373 
374  // Get the output to read the value from.
375  const VdfVector *value = _GetExecutor()._GetInputValue(
376  *connection, mask);
377 
378  if (value) {
379  VdfVector::ReadAccessor<T> accessor =
380  value->GetReadAccessor<T>();
381  if (firstIndex < accessor.GetNumValues()) {
382  return &accessor[firstIndex];
383  }
384  }
385  }
386  }
387 
388  // No values on any of the connections.
389  return nullptr;
390 }
391 
392 template<typename T>
393 void
394 VdfContext::SetOutput(const TfToken &outputName,
395  const T &value) const
396 {
397  TfAutoMallocTag2 tag("Vdf", "VdfContext::SetOutput");
398  TfAutoMallocTag2 tag2("Vdf", __ARCH_PRETTY_FUNCTION__);
399 
400  // GetOutput emits an error if it returns NULL.
401  const VdfOutput *output = _node.GetOutput(outputName);
402  if (output && _IsRequiredOutput(*output))
403  if (VdfVector *v = _GetExecutor()._GetOutputValueForWriting(*output))
404  v->Set(value);
405 }
406 
407 template<typename T>
408 void
409 VdfContext::SetOutput(const T &value) const
410 {
411  TfAutoMallocTag2 tag("Vdf", "VdfContext::SetOutput");
412  TfAutoMallocTag2 tag2("Vdf", __ARCH_PRETTY_FUNCTION__);
413 
414  // GetOutput emits an error if it returns NULL. Note that there is no need
415  // to check _IsRequiredOutput: By virtue of the owning node being scheduled,
416  // we can conclude that its only output is therefore scheduled.
417  if (const VdfOutput *output = _node.GetOutput())
418  if (VdfVector *v = _GetExecutor()._GetOutputValueForWriting(*output))
419  v->Set(value);
420 }
421 
422 template<typename T>
423 void
424 VdfContext::SetOutput(T &&value) const
425 {
426  TfAutoMallocTag2 tag("Vdf", "VdfContext::SetOutput (move)");
427  TfAutoMallocTag2 tag2("Vdf", __ARCH_PRETTY_FUNCTION__);
428 
429  // GetOutput emits an error if it returns NULL. Note that there is no need
430  // to check _IsRequiredOutput: By virtue of the owning node being scheduled,
431  // we can conclude that its only output is therefore scheduled.
432  if (const VdfOutput *output = _node.GetOutput())
433  if (VdfVector *v =
434  _GetExecutor()._GetOutputValueForWriting(*output))
435  v->Set(std::forward<T>(value));
436 }
437 
438 template<typename T>
439 void
440 VdfContext::SetOutput(const TfToken &outputName,
441  T &&value) const
442 {
443  TfAutoMallocTag2 tag("Vdf", "VdfContext::SetOutput (move)");
444  TfAutoMallocTag2 tag2("Vdf", __ARCH_PRETTY_FUNCTION__);
445 
446  // GetOutput emits an error if it returns NULL.
447  const VdfOutput *output = _node.GetOutput(outputName);
448  if (output && _IsRequiredOutput(*output))
449  if (VdfVector *v = _GetExecutor()._GetOutputValueForWriting(*output))
450  v->Set(std::forward<T>(value));
451 }
452 
454 
455 #endif
size_t GetFirstSet() const
Definition: mask.h:226
*get result *(waiting if necessary)*A common idiom is to fire a bunch of sub tasks at the and then *wait for them to all complete We provide a helper class
Definition: thread.h:632
const GLdouble * v
Definition: glcorearb.h:837
VDF_API void CodingError(const char *fmt,...) const ARCH_PRINTF_FUNCTION(2
#define PXR_NAMESPACE_OPEN_SCOPE
Definition: pxr.h:73
GLsizei const GLfloat * value
Definition: glcorearb.h:824
#define TF_CODING_ERROR
Definition: node.h:52
A VdfMask is placed on connections to specify the data flowing through them.
Definition: mask.h:36
const VdfOutput * GetOutput(const TfToken &name) const
Definition: node.h:227
const VdfInput * GetInput(const TfToken &inputName) const
Definition: node.h:164
#define VDF_API
Definition: api.h:25
void SetOutput(const TfToken &outputName, const T &value) const
Definition: context.h:394
VdfByValueOrConstRef< T > GetInputValue(const TfToken &name) const
Definition: context.h:300
VdfContext(const VdfEvaluationState &state, const VdfNode &node, const VdfScheduleTaskIndex invocation)
Definition: context.h:59
virtual const VdfVector * _GetInputValue(const VdfConnection &connection, const VdfMask &mask) const =0
const T * GetInputValuePtr(const TfToken &name) const
Definition: context.h:319
Definition: input.h:35
VDF_API bool IsOutputRequested(const TfToken &outputName) const
Definition: token.h:70
VdfContext(const VdfEvaluationState &state, const VdfNode &node)
Definition: context.h:50
#define __ARCH_PRETTY_FUNCTION__
Definition: functionLite.h:29
Contains a specification of how to execute a particular VdfNetwork.
Definition: schedule.h:40
VdfContext & operator=(const VdfContext &rhs)=delete
GLint GLuint mask
Definition: glcorearb.h:124
VdfExecutorErrorLogger * GetErrorLogger() const
const VdfSchedule & GetSchedule() const
VDF_API void Warn(const char *fmt,...) const ARCH_PRINTF_FUNCTION(2
GLuint const GLchar * name
Definition: glcorearb.h:786
A node that pulls on a vector of value that are downstream of the current execution position...
bool HasInputValue(const TfToken &name) const
Definition: context.h:334
char const * GetText() const
Definition: token.h:179
VDF_API void SetOutputToReferenceInput(const TfToken &inputName) const
static VDF_API VdfExecutionTypeRegistry & GetInstance()
size_t GetSize() const
Definition: mask.h:158
VdfContext(const VdfContext &rhs)=delete
virtual VdfVector * _GetOutputValueForWriting(const VdfOutput &output) const =0
ReadAccessor< TYPE > GetReadAccessor() const
Definition: vector.h:521
const VdfExecutorInterface & GetExecutor() const
#define PXR_NAMESPACE_CLOSE_SCOPE
Definition: pxr.h:74
VDF_API std::string GetNodeDebugName() const
uint32_t VdfScheduleTaskIndex
Definition: scheduleTasks.h:29
Abstract base class for classes that execute a VdfNetwork to compute a requested set of values...
size_t GetNumValues() const
Definition: vector.h:489
typename std::conditional_t< std::is_pointer_v< T >||Vdf_AndTypeIsSmall< T, std::is_arithmetic_v< T >>||Vdf_AndTypeIsSmall< T, std::is_enum_v< T >>, T, const T & > VdfByValueOrConstRef
Definition: traits.h:108
state
Definition: core.h:2289
VDF_API void SetEmptyOutput() const
const VdfConnectionVector & GetConnections() const
Definition: input.h:54