HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
computationBuilders.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_EXEC_COMPUTATION_BUILDERS_H
8 #define PXR_EXEC_EXEC_COMPUTATION_BUILDERS_H
9 
10 /// \file
11 ///
12 /// This is a public header, but many of the symbols have private names because
13 /// they are not intended for direct use by client code. The public API here is
14 /// accessed by client code via the 'self' parameter generated by the
15 /// EXEC_REGISTER_COMPUTATIONS_FOR_SCHEMA macro. The documentation is set up to
16 /// highlight all relevant public details.
17 ///
18 
19 #include "pxr/pxr.h"
20 
21 #include "pxr/exec/exec/api.h"
25 #include "pxr/exec/exec/types.h"
26 
27 #include "pxr/base/tf/token.h"
28 #include "pxr/base/tf/type.h"
29 #include "pxr/base/vt/traits.h"
30 #include "pxr/base/vt/value.h"
31 #include "pxr/exec/vdf/context.h"
32 #include "pxr/exec/vdf/traits.h"
33 #include "pxr/usd/sdf/path.h"
34 
35 #include <memory>
36 #include <type_traits>
37 #include <utility>
38 
40 
41 struct Exec_InputKey;
42 
43 
44 /// \defgroup group_Exec_ComputationDefinitionLanguage Computation Definition Language
45 ///
46 /// Plugin computations are defined using the domain-specific **Computation
47 /// Definition Language**.
48 ///
49 /// Each plugin computation is registered for a particular schema, either typed
50 /// or applied. When a computation is requested on a provider prim or attribute,
51 /// if the requested computation name is not a [builtin
52 /// computation](#group_Exec_Builtin_Computations) name, exec compilation
53 /// considers the computations registered for the typed schema for the prim, the
54 /// ancestor schema types, and API schemas applied to the prim, and looks for a
55 /// computation of the requested name.
56 ///
57 /// To define computations for a schema, the plugin code must invoke the
58 /// EXEC_REGISTER_COMPUTATIONS_FOR_SCHEMA() macro. The macro invocation is
59 /// immediately followed by a block of code that uses [computation
60 /// registrations](#group_Exec_ComputationRegistrations) that registers the
61 /// associated plugin computations. Most of the language is dedicated to
62 /// expressing [input registrations](#group_Exec_InputRegistrations), which
63 /// provide exec compilation with the information it needs to compile the input
64 /// connections that supply input values when the network is evaluated.
65 ///
66 /// # Example
67 ///
68 /// The following cpp file could be used in a plugin library to define the
69 /// `computeMyAttributeValue` prim computation for the `MySchemaType` schema:
70 ///
71 /// ```{.cpp}
72 /// #include "pxr/exec/exec/registerSchema.h"
73 /// #include "pxr/exec/vdf/context.h"
74 ///
75 /// EXEC_REGISTER_COMPUTATIONS_FOR_SCHEMA(MySchemaType)
76 /// {
77 /// // Register a prim computation that returns the computed value of an
78 /// // attribute.
79 /// self.PrimComputation(_tokens->computeMyAttributeValue)
80 /// .Callback<double>(+[](const VdfContext &ctx) {
81 /// ctx->SetOutput(ctx.GetInputValue<double>(_tokens->myAttribute));
82 /// })
83 /// .Inputs(
84 /// AttributeValue<double>(_tokens->myAttribute).Required());
85 /// }
86 /// ```
87 ///
88 /// The library's `plugInfo.json` must contain the following data in the `Info`
89 /// block in order for the execution system to load the library when
90 /// computations are requested on a prim that uses `MySchemaType`:
91 ///
92 /// ```
93 /// "Info": {
94 /// "Exec": {
95 /// "Schemas": {
96 /// "MyComputationalSchema1": {
97 /// "allowsPluginComputations": true
98 /// },
99 /// "MyComputationalSchema2": {
100 /// },
101 /// "MyNonComputationalSchema": {
102 /// "allowsPluginComputations": false
103 /// }
104 /// }
105 /// }
106 /// }
107 /// ```
108 ///
109 /// The boolean `allowsPluginComputations` is used to declare schemas for which
110 /// computations _cannot_ be registered. If `allowsPluginComputations` isn't
111 /// present in the plugInfo, its value defaults to true. I.e., schemas that
112 /// appear in the Exec/Schemas plugInfo allow plugin computations by default.
113 
114 /// \defgroup group_Exec_ComputationRegistrations Computation Registrations
115 ///
116 /// Computation registrations initiate the process of defining computations. The
117 /// object returned by a computation registration has methods that are used to
118 /// specify the callback that implements the computation and the inputs that are
119 /// provided to the callback at evaluation time.
120 ///
121 /// \ingroup group_Exec_ComputationDefinitionLanguage
122 
123 /// \defgroup group_Exec_InputRegistrations Input Registrations
124 ///
125 /// An **input registration** is a specification of how an input value will be
126 /// provided to a computation callback at evaluation time.
127 ///
128 /// An input registration is a sequence of:
129 /// - zero or more [object accessors](#group_Exec_Accessors), which provide
130 /// access to one or more scene objects that act as computation providers, and
131 /// which _must_ be followed by:
132 /// - exactly one [value specifier](#group_Exec_ValueSpecifiers), which request
133 /// a value from the computation provider(s), and which _may_ be followed
134 /// by:
135 /// - zero or more [input options](#group_Exec_InputOptions), which modify the
136 /// behavior of the resulting input registration.
137 ///
138 /// For convenience, certain object accessor/value specifier/input option
139 /// sequences may be replaced by an [alias](#group_Exec_Aliases), which
140 /// compactly represents a compound input registration.
141 ///
142 /// \ingroup group_Exec_ComputationDefinitionLanguage
143 
144 /// \defgroup group_Exec_Accessors Object Accessors
145 ///
146 /// **Object accessors** provide access to computation providers, the scene
147 /// objects from which input values are requested. An [input
148 /// registration](#group_Exec_InputRegistrations) starts with a sequence of zero
149 /// or more accessors. If no accessor is present, the origin object, the object
150 /// that owns the consuming computation, is the provider. Otherwise, starting
151 /// from that object, the sequence of accessors describes hops through namespace
152 /// that end at the computation provider.
153 ///
154 /// A sequence of object accessors does not fully specify an input, however. The
155 /// sequence _must_ be followed by exactly one [value
156 /// specifier](#group_Exec_ValueSpecifiers) to fully specify an input
157 /// registration.
158 ///
159 /// \ingroup group_Exec_InputRegistrations
160 
161 /// \defgroup group_Exec_ValueSpecifiers Value Specifiers
162 ///
163 /// A **value specifier** is an element of an [input
164 /// registration](#group_Exec_InputRegistrations) that identifies the value that
165 /// is requested from a given computation provider.
166 ///
167 /// Each computation input registration must contain exactly one value
168 /// specifier. A value specifier comes after a sequence of zero or more [object
169 /// accessors](#group_Exec_Accessors), which determine the provider. A value
170 /// specifier may be followed by one or more [input
171 /// options](#group_Exec_InputOptions).
172 ///
173 /// \ingroup group_Exec_InputRegistrations
174 
175 /// \defgroup group_Exec_InputOptions Input Options
176 ///
177 /// An **input option** is an element of an [input
178 /// registration](#group_Exec_InputRegistrations) that applies to a [value
179 /// specifier](#group_Exec_ValueSpecifiers), modifying its behavior.
180 ///
181 /// A value specifier may be followed by zero or more input options.
182 ///
183 /// \ingroup group_Exec_InputRegistrations
184 
185 /// \defgroup group_Exec_Aliases Aliases
186 ///
187 /// Aliases are compact representations of compound [input
188 /// registrations](#group_Exec_InputRegistrations), combining one or more
189 /// [object accessors](#group_Exec_Accessors) with a [value
190 /// specifier](#group_Exec_ValueSpecifiers) into a single input registration.
191 ///
192 /// \ingroup group_Exec_InputRegistrations
193 
194 
195 /// An enum that is used as a template parameter to specify which kinds of
196 /// providers a given input registration is allowed to be used on.
197 ///
198 enum class Exec_ComputationBuilderProviderTypes: unsigned char
199 {
200  Prim = 1 << 0,
201  Attribute = 1 << 1,
202  Any = 0xff
203 };
204 
205 constexpr bool operator&(
208 {
209  return static_cast<unsigned char>(a) & static_cast<unsigned char>(b);
210 }
211 
212 template <Exec_ComputationBuilderProviderTypes allowed>
214 
215 // Common base class for value specifiers and object accessors.
217 {
218 protected:
219  // Returns a value specifier for computing a metadata value.
220  template <Exec_ComputationBuilderProviderTypes allowed>
221  EXEC_API
224  const TfType resultType,
225  const SdfPath &localTraversal,
226  const TfToken &metadataKey);
227 };
228 
229 // Untemplated value specifier base class.
230 //
231 // This class builds up an Exec_InputKey that specifies how to source an input
232 // value at exec compilation time.
233 //
236 {
237 public:
238  EXEC_API
240  const TfToken &computationName,
241  TfType resultType,
242  ExecProviderResolution &&providerResolution,
243  const TfToken &inputName,
244  const TfToken &disambiguatingId);
245 
246  EXEC_API
248  const Exec_ComputationBuilderValueSpecifierBase&);
249 
250  EXEC_API
252 
253 protected:
254  EXEC_API
255  void _SetInputName(const TfToken &inputName);
256 
257  EXEC_API
258  void _SetOptional (const bool optional);
259 
260  EXEC_API
261  void _SetFallsBackToDispatched(bool fallsBackToDispatched);
262 
263 private:
264  // Only computation builders can get the input key.
266 
267  EXEC_API
268  void _GetInputKey(Exec_InputKey *inputKey) const;
269 
270 private:
271  // We PIMPL the data for this class to avoid exposing more private details
272  // in this public header.
273  struct _Data;
274  const std::unique_ptr<_Data> _data;
275 };
276 
277 // A value specifier that requests a constant value, valid on a prim or
278 // attribute computation
279 //
282 {
285 
286  EXEC_API
288  const TfType resultType,
289  const SdfPath &localTraversal,
290  const TfToken &inputName,
291  VtValue &&constantValue);
292 };
293 
294 // A value specifier that requests the value of a computation.
295 //
296 // The template parameter determines which types of providers the input
297 // registration is allowed to be used on.
298 //
299 template <Exec_ComputationBuilderProviderTypes allowed>
302 {
304  const TfToken &computationName,
305  const TfType resultType,
306  ExecProviderResolution &&providerResolution,
307  const TfToken &disambiguatingId = TfToken())
309  computationName, resultType,
310  std::move(providerResolution),
311  computationName /* inputName */,
312  disambiguatingId)
313  {
314  }
315 
317 
319  allowed;
320 
321  /// \addtogroup group_Exec_InputOptions
322  /// @{
323 
324  /// Overrides the default input name, setting it to \p inputName.
325  ///
326  /// # Example
327  ///
328  /// ```{.cpp}
329  /// EXEC_REGISTER_COMPUTATIONS_FOR_SCHEMA(MySchemaType)
330  /// {
331  /// // Register a prim computation that returns the value of another
332  /// // prim computation, using a non-default input name.
333  /// self.PrimComputation(_tokens->myComputation)
334  /// .Callback<double>(+[](const VdfContext &ctx) {
335  /// const double *const valuePtr =
336  /// ctx.GetInputValuePtr<double>(_tokens->myInputName);
337  /// return valuePtr ? *valuePtr : 0.0;
338  /// })
339  /// .Inputs(
340  /// Computation<double>(_tokens->anotherComputation)
341  /// .InputName(_tokens->myInputName));
342  /// }
343  /// ```
344  ///
345  This&
346  InputName(const TfToken &inputName)
347  {
348  _SetInputName(inputName);
349  return *this;
350  }
351 
352  /// Declares the input is required, i.e., that the computation expects an
353  /// input value always to be provided at evaluation time.
354  ///
355  /// If exec compilation is unable to compile input connections for a
356  /// required input, an error will be emitted.
357  ///
358  /// # Example
359  ///
360  /// ```{.cpp}
361  /// EXEC_REGISTER_COMPUTATIONS_FOR_SCHEMA(MySchemaType)
362  /// {
363  /// // Register a prim computation that returns the value of another
364  /// // prim computation, using a non-default input name.
365  /// self.PrimComputation(_tokens->myComputation)
366  /// .Callback<int>(+[](const VdfContext &ctx) {
367  /// return ctx.GetInputValue<int>(_tokens->myInputName);
368  /// })
369  /// .Inputs(
370  /// Computation<int>(_tokens->anotherComputation).Required());
371  /// }
372  /// ```
373  ///
374  This&
376  {
377  _SetOptional(false);
378  return *this;
379  }
380 
381  /// Declares the input can find dispatched computations *if* the requested
382  /// computation name doesn't match a local computation on the provider.
383  ///
384  /// \sa
385  /// [DispatchedPrimComputation](#ExecComputationBuilder::DispatchedPrimComputation)
386  ///
387  /// # Example
388  ///
389  /// ```{.cpp}
390  /// EXEC_REGISTER_COMPUTATIONS_FOR_SCHEMA(MySchemaType)
391  /// {
392  /// // Register a dispatched prim computation.
393  /// self.DispatchedPrimComputation(_tokens->myDispatchedComputation)
394  /// .Callback<double>(+[](const VdfContext &) { return 11.0; })
395  ///
396  /// // Register a prim computation that requests the above dispatched
397  /// // computation via uses relationship targets.
398  /// self.PrimComputation(_tokens->myComputation)
399  /// .Callback<double>(+[](const VdfContext &ctx) {
400  /// const double *const valuePtr =
401  /// ctx.GetInputValuePtr<double>(
402  /// _tokens->myDispatchedComputation);
403  /// return valuePtr ? *valuePtr : -1.0;
404  /// })
405  /// .Inputs(
406  /// Relationship(_tokens->myRelationship)
407  /// .TargetedObjects<double>(
408  /// _tokens->myDispatchedComputation)
409  /// .FallsBackToDispatched())
410  /// }
411  /// ```
412  ///
413  This&
415  {
417  return *this;
418  }
419 
420  /// @}
421 };
422 
423 
424 // Untemplated object accessor base class.
427 {
428 
430  : _localTraversal(localTraversal)
431  {
432  }
433 
434 protected:
435  const SdfPath &_GetLocalTraversal() const {
436  return _localTraversal;
437  }
438 
439 private:
440  // The relative path used for the first phase of provider resolution.
441  SdfPath _localTraversal;
442 };
443 
444 // Untemplated base class for accessors used to provide constant values as
445 // computation inputs.
446 //
449 {
450  // We specialize the InputName() accessor because it is required for
451  // constant values. I.e., Constant() returns an accessor, and the
452  // InputName() option must be used to generate a value specifier.
453  //
455  InputName(const TfToken &inputName) &&
456  {
458  _valueType,
460  inputName,
461  std::move(_constantValue));
462  }
463 
464 protected:
465  EXEC_API
467  VtValue &&constantValue,
468  TfType valueType);
469 
470 private:
471  VtValue _constantValue;
472  const TfType _valueType;
473 };
474 
475 /// Accessor common to all scene object types that support requesting
476 /// computations on the object.
477 ///
478 /// This class is templated in order to classify accessors that are allowed as
479 /// inputs for prim computations vs attribute computations.
480 ///
481 template <Exec_ComputationBuilderProviderTypes allowed>
484 {
486  : Exec_ComputationBuilderAccessorBase(localTraversal)
487  {
488  }
489 
490  using ValueSpecifier =
492 
493  /// \addtogroup group_Exec_ValueSpecifiers
494  /// @{
495 
496  /// See [Computation()](#exec_registration::Computation::Computation)
497  template <typename ResultType>
499  Computation(const TfToken &computationName)
500  {
501  static_assert(!VtIsArray<ResultType>::value,
502  "VtArray is not a supported result type");
503 
504  return ValueSpecifier(
505  computationName,
506  ExecTypeRegistry::GetInstance().CheckForRegistration<ResultType>(),
509  }
510 
511  /// See [IncomingConnections()](#exec_registration::IncomingConnections)
512  template <typename ResultType>
514  IncomingConnections(const TfToken &computationName)
515  {
516  return ValueSpecifier(
517  computationName,
518  ExecTypeRegistry::GetInstance().CheckForRegistration<ResultType>(),
522  }
523 
524  /// See [Metadata()](#exec_registration::Metadata)
525  template <typename ResultType>
527  Metadata(const TfToken &metadataKey)
528  {
529  static_assert(!VtIsArray<ResultType>::value,
530  "VtArray is not a supported result type");
531 
532  return _GetMetadataValueSpecifier<allowed>(
535  metadataKey);
536  }
537 
538  /// @} // Value specifiers
539 };
540 
541 /// Property accessor
542 template <Exec_ComputationBuilderProviderTypes allowed>
544  : public Exec_ComputationBuilderAccessor<allowed>
545 {
547  : Exec_ComputationBuilderAccessor<allowed>(localTraversal)
548  {
549  }
550 };
551 
552 /// Attribute accessor
553 template <Exec_ComputationBuilderProviderTypes allowed>
556 {
558  : Exec_ComputationBuilderPropertyAccessor<allowed>(localTraversal)
559  {
560  }
561 
562  using ValueSpecifier =
564 
565  /// \addtogroup group_Exec_ValueSpecifiers
566  /// @{
567 
568  /// See [Connections()](#exec_registration::Connections)
569  template <typename ResultType>
571  Connections(const TfToken &computationName)
572  {
573  return ValueSpecifier(
574  computationName,
575  ExecTypeRegistry::GetInstance().CheckForRegistration<ResultType>(),
579  }
580 
581  /// @}
582 
583  // XXX:TODO
584  // Accessors for AnimSpline, etc.
585 };
586 
587 /// Relationship accessor
588 template <Exec_ComputationBuilderProviderTypes allowed>
591 {
593  : Exec_ComputationBuilderPropertyAccessor<allowed>(localTraversal)
594  {
595  }
596 
597  using ValueSpecifier =
599 
600  /// \addtogroup group_Exec_ValueSpecifiers
601  /// @{
602 
603  /// After a [Relationship()](#exec_registration::Relationship::Relationship)
604  /// accessor, requests input values from the computation \p computationName
605  /// of type \p ResultType on the objects targeted by the relationship.
606  ///
607  /// Relationship forwarding is applied, so if the relationship targets
608  /// another relationship, the targets are transitively expanded, resulting
609  /// in the ultimately targeted, non-relationship objects.
610  ///
611  /// The default input name is \p computationName; use `InputName` to specify
612  /// a different input name.
613  ///
614  /// # Example
615  ///
616  /// ```{.cpp}
617  /// EXEC_REGISTER_COMPUTATIONS_FOR_SCHEMA(MySchemaType)
618  /// {
619  /// // Register a prim computation that looks for the computation
620  /// // 'sourceComputation' on all targeted objects of the relationship
621  /// // 'myRel' and returns the number of matching targets.
622  /// self.PrimComputation(_tokens->myComputation)
623  /// .Callback<int>(+[](const VdfContext &ctx) {
624  /// VdfReadIterator<int> it(_tokens->sourceComputation);
625  /// return static_cast<int>(it.ComputeSize());
626  /// })
627  /// .Inputs(
628  /// Relationship(_tokens->myRel)
629  /// .TargetedObjects<int>(_tokens->sourceComputation));
630  /// }
631  /// ```
632  ///
633  template <typename ResultType>
635  TargetedObjects(const TfToken &computationName)
636  {
637  return ValueSpecifier(
638  computationName,
639  ExecTypeRegistry::GetInstance().CheckForRegistration<ResultType>(),
643  }
644 
645  /// @}
646 };
647 
648 
649 // The following registrations are in the exec_registration namespace so that
650 // the registration macro can make them available (without the namespace) as
651 // arguments to registrations methods (i.e., Inputs()).
652 namespace exec_registration {
653 
654 
655 /// Attribute accessor, valid for providing input to a prim computation.
656 struct Attribute final
658  Exec_ComputationBuilderProviderTypes::Prim>
659 {
660  /// \addtogroup group_Exec_Accessors
661  /// @{
662 
663  /// On a prim computation, provides access to the attribute named
664  /// \p attributeName.
665  ///
666  /// # Example
667  ///
668  /// ```{.cpp}
669  /// EXEC_REGISTER_COMPUTATIONS_FOR_SCHEMA(MySchemaType)
670  /// {
671  /// // Register a prim computation that returns the value of an
672  /// // attribute owned by the prim.
673  /// self.PrimComputation(_tokens->myComputation)
674  /// .Callback<double>(+[](const VdfContext &ctx) {
675  /// return ctx.GetInputValue<double>(
676  /// ExecBuiltinComputations->computeValue));
677  /// })
678  /// .Inputs(
679  /// Attribute(_tokens->doubleAttribute)
680  /// .Computation<double>(
681  /// ExecBuiltinComputations->computeValue).Required());
682  /// }
683  /// ```
684  ///
685  Attribute(const TfToken &attributeName)
688  SdfPath::ReflexiveRelativePath().AppendProperty(attributeName))
689  {
690  }
691 
692  /// @} // Accessors
693 };
694 
695 
696 /// Relationship accessor, valid for providing input to a prim computation.
697 struct Relationship final
699  Exec_ComputationBuilderProviderTypes::Prim>
700 {
701  /// \addtogroup group_Exec_Accessors
702  /// @{
703 
704  /// On a prim computation, provides access to the relationship named
705  /// \p relationshipName.
706  ///
707  /// \sa
708  /// [TargetedObjects()](#Exec_ComputationBuilderRelationshipAccessor::TargetedObjects)
709  ///
710  Relationship(const TfToken &relationshipName)
713  SdfPath::ReflexiveRelativePath().AppendProperty(
714  relationshipName))
715  {
716  }
717 
718  /// @} // Accessors
719 };
720 
721 
722 /// Prim accessor, valid for providing input to an attribute computation.
723 struct Prim final
725  Exec_ComputationBuilderProviderTypes::Attribute>
726 {
727  /// \addtogroup group_Exec_Accessors
728  /// @{
729 
730  /// On an attribute computation, provides access to the owning prim.
731  ///
732  /// # Example
733  ///
734  /// ```{.cpp}
735  /// EXEC_REGISTER_COMPUTATIONS_FOR_SCHEMA(MySchemaType)
736  /// {
737  /// // Register an attribute computation on 'attr' that yields the
738  /// // value of a sibling attribute 'otherAttr'.
739  /// self.AttributeComputation(
740  /// _tokens->attr,
741  /// _tokens->myComputation)
742  /// .Callback<int>(+[](const VdfContext &ctx) {
743  /// return ctx.GetInputValue<int>(
744  /// ExecBuiltinComputations->computeValue));
745  /// })
746  /// .Inputs(
747  /// Prim().AttributeValue<int>(_tokens->otherAttr).Required());
748  /// }
749  /// ```
750  ///
754  SdfPath(".."))
755  {
756  }
757 
758  /// See [Attribute()](#Attribute::Attribute)
761  Attribute(const TfToken &attributeName)
762  {
765  SdfPath("..").AppendProperty(attributeName));
766  }
767 
768  /// See [Relationship()](#Relationship::Relationship)
771  Relationship(const TfToken &relationshipName)
772  {
775  SdfPath("..").AppendProperty(relationshipName));
776  }
777 
778  /// @} // Accessors
779 
780  /// \addtogroup group_Exec_Aliases
781  /// @{
782 
783  /// See [AttributeValue()](#exec_registration::AttributeValue)
784  template <typename ValueType>
785  auto
786  AttributeValue(const TfToken &attributeName)
787  {
788  return Attribute(attributeName)
789  .Computation<ValueType>(ExecBuiltinComputations->computeValue)
790  .InputName(attributeName);
791  }
792 
793  /// @} // Aliases
794 };
795 
796 
797 /// Provides access to the stage, valid for providing input to any computation.
798 struct Stage final
800  Exec_ComputationBuilderProviderTypes::Any>
801 {
802  /// \addtogroup group_Exec_Accessors
803  /// @{
804 
805  /// On any computation, provides access to the stage. This accessor can be
806  /// used to access stage-level builtin computations.
807  ///
808  /// > **Note:**
809  /// > The Stage() accessor must be the sole accessor in any input
810  /// > registration in which it appears.
811  ///
812  /// # Example
813  ///
814  /// ```{.cpp}
815  /// EXEC_REGISTER_COMPUTATIONS_FOR_SCHEMA(MySchemaType)
816  /// {
817  /// // Register a prim computation that returns the current time.
818  /// self.PrimComputation(_tokens->myComputation)
819  /// .Callback<EfTime>(+[](const VdfContext &ctx) {
820  /// return ctx.GetInputValue<EfTime>(
821  /// ExecBuiltinComputations->computeTime));
822  /// })
823  /// .Inputs(
824  /// Stage().Computation<EfTime>(
825  /// ExecBuiltinComputations->computeTime).Required());
826  /// }
827  /// ```
828  ///
832  SdfPath::AbsoluteRootPath())
833  {
834  }
835 
836  /// @} // Accessors
837 };
838 
839 // XXX:TODO
840 // Property, NamespaceParent, NamespaceChildren, etc.
841 
842 
843 /// Computation value specifier, valid for providing input to any computation.
844 template <typename ResultType>
845 struct Computation final
847  Exec_ComputationBuilderProviderTypes::Any>
848 {
849  /// \addtogroup group_Exec_ValueSpecifiers
850  /// @{
851 
852  /// Requests an input value from the computation \p computationName of type
853  /// \p ResultType.
854  ///
855  /// The default input name is \p computationName; use `InputName` to specify
856  /// a different input name.
857  ///
858  /// # Example
859  ///
860  /// ```{.cpp}
861  /// EXEC_REGISTER_COMPUTATIONS_FOR_SCHEMA(MySchemaType)
862  /// {
863  /// // Register a prim computation that returns the value of another
864  /// // prim computation.
865  /// self.PrimComputation(_tokens->myComputation)
866  /// .Callback<double>(+[](const VdfContext &ctx) {
867  /// const double *const valuePtr =
868  /// ctx.GetInputValuePtr<double>(_tokens->sourceComputation);
869  /// return valuePtr ? *valuePtr : 0.0;
870  /// })
871  /// .Inputs(
872  /// Computation<double>(_tokens->sourceComputation)
873  /// }
874  /// ```
875  ///
876  Computation(const TfToken &computationName)
879  computationName,
880  ExecTypeRegistry::GetInstance().
881  CheckForRegistration<ResultType>(),
884  {
885  }
886 
887  /// @}
888 };
889 
890 /// Metadata value specifier, valid on a prim or attribute computation
891 template <typename ValueType>
892 struct Metadata final
894  Exec_ComputationBuilderProviderTypes::Any>
895 {
896  /// \addtogroup group_Exec_ValueSpecifiers
897  /// @{
898 
899  /// Requests an input value from the metadata field indicated by \p
900  /// metadataKey, of type \p ResultType.
901  ///
902  /// The default input name is \p metadataKey; use InputName to specify a
903  /// different input name.
904  ///
905  /// # Example
906  ///
907  /// ```{.cpp}
908  /// self.PrimComputation(_tokens->computeDocMetadata)
909  /// .Callback<std::string>(+[](const VdfContext &ctx) {
910  /// return ctx.GetInputValue<std::string>(
911  /// SdfFieldKeys->Documentation);
912  /// })
913  /// .Inputs(
914  /// Metadata<std::string>(SdfFieldKeys->Documentation).Required()
915  /// );
916  /// ```
917  ///
918  Metadata(const TfToken &metadataKey)
922  ExecTypeRegistry::GetInstance()
923  .CheckForRegistration<ValueType>(),
924  SdfPath::ReflexiveRelativePath(),
925  metadataKey))
926  {
927  static_assert(!VtIsArray<ValueType>::value,
928  "VtArray is not a supported result type");
929 
930  InputName(metadataKey);
931  }
932 
933  /// @}
934 };
935 
936 // Constant accessor
937 template <typename ValueType>
938 struct Constant final
940 {
941  /// \addtogroup group_Exec_ValueSpecifiers
942  /// @{
943 
944  /// Requests a constant input value of type \p ValueType.
945  ///
946  /// \note
947  /// No default input name is assigned. `Constant(value)` *must* be
948  /// followed by `.InputName(name)`.
949  ///
950  /// This kind of input isn't necessarily useful when used with a
951  /// self-contained computation definition. But it becomes useful for more
952  /// complicated registrations, where one piece of code registers a callback
953  /// that configures its evaluation-time behavior based on an input value and
954  /// a separate piece of code registers a constant input that selects the
955  /// desired behavior.
956  ///
957  /// This can happen:
958  /// - When computation definitions are assembled programatically by
959  /// parameterized registration code that is called to register various
960  /// versions of a computation, possibly for multiple schemas
961  /// - When computation definitions are composed from registrations made for
962  /// different schemas on the same prim (support for composed computation
963  /// definitions is still TBD in OpenExec)
964  /// - When computation registration is configured (also TBD), allowing
965  /// registrations for a single schema to be dynamic, depending on metadata
966  /// values that drive the configuration process
967  ///
968  /// # Value Types
969  ///
970  /// All computation input value types, including value types used to provide
971  /// constant inputs, must be known to the execution system. All types that
972  /// can be used to author attribute and metadata values in USD are known to
973  /// exec by default. User-defined types must be registered by calling
974  /// ExecTypeRegistry::RegisterType.
975  ///
976  /// \note
977  /// Types that are used for constant inputs must be hashable (see
978  /// VtIsHashable()).
979  ///
980  /// # Simple Example
981  ///
982  /// This simple example shows the mechanics of using a constant input,
983  /// without being suggestive of how it might be useful.
984  ///
985  /// ```{.cpp}
986  /// EXEC_REGISTER_COMPUTATIONS_FOR_SCHEMA(MySchemaType)
987  /// {
988  /// // Register a prim computation that returns the value of its
989  /// // constant input.
990  /// self.PrimComputation(_tokens->myComputation)
991  /// .Callback<double>(+[](const VdfContext &ctx) {
992  /// return ctx.GetInputValue<double>(_tokens->myConstant);
993  /// })
994  /// .Inputs(
995  /// Constant(42.0).InputName(_tokens->myConstant));
996  /// }
997  /// ```
998  ///
999  /// # Complex Example
1000  ///
1001  /// This example demonstrate how more complicated registration code might
1002  /// make use of constant inputs to configure the behavior of a callback at
1003  /// evaluation time.
1004  ///
1005  /// ```{.cpp}
1006  /// template <typename RegistrationType>
1007  /// void RegisterCallback(RegistrationType &reg)
1008  /// {
1009  /// reg.Callback<std::string>(+[](const VdfContext &ctx) {
1010  /// const TfToken &mode = ctx.GetInputValue<TfToken>(_tokens->mode);
1011  /// if (mode == _tokens->mode1) {
1012  /// return "Mode 1 selected";
1013  /// else if (mode == _tokens->mode2) {
1014  /// return "Mode 2 selected";
1015  /// }
1016  /// }
1017  ///
1018  /// template <typename RegistrationType>
1019  /// void RegisterInput(RegistrationType &reg, const int mode)
1020  /// {
1021  /// if (mode == 1) {
1022  /// reg.Inputs(Constant(_tokens->mode1).InputName(_tokens->mode));
1023  /// } else if (mode == 2) {
1024  /// reg.Inputs(Constant(_tokens->mode2).InputName(_tokens->mode));
1025  /// }
1026  /// }
1027  ///
1028  /// EXEC_REGISTER_COMPUTATIONS_FOR_SCHEMA(MySchemaType)
1029  /// {
1030  /// auto reg = self.PrimComputation(_tokens->myComputation);
1031  ///
1032  /// // ...
1033  ///
1034  /// RegisterCallback(reg);
1035  ///
1036  /// // ...
1037  ///
1038  /// RegisterInput(reg, mode);
1039  /// }
1040  /// ```
1041  ///
1043  ValueType &&constantValue)
1045  VtValue(std::move(constantValue)),
1046  ExecTypeRegistry::GetInstance().
1047  CheckForRegistration<ValueType>())
1048  {
1049  static_assert(
1050  !std::is_same_v<std::decay_t<ValueType>, char*> &&
1051  !std::is_same_v<std::decay_t<ValueType>, const char*>,
1052  "Must use std::string to represent string literal types.");
1053  static_assert(
1054  VtIsHashable<ValueType>(),
1055  "Types used to provide constant input values must be hashable.");
1056  }
1057 
1059  const ValueType &constantValue)
1061  VtValue(constantValue),
1062  ExecTypeRegistry::GetInstance().
1063  CheckForRegistration<ValueType>())
1064  {
1065  static_assert(
1066  !std::is_same_v<std::decay_t<ValueType>, char*> &&
1067  !std::is_same_v<std::decay_t<ValueType>, const char*>,
1068  "Must use std::string to represent string literal types.");
1069  static_assert(
1070  VtIsHashable<ValueType>(),
1071  "Types used to provide constant input values must be hashable.");
1072  }
1073 
1074  /// @}
1075 };
1076 
1077 // Deduction guides that ensure std::string is the value type used to store
1078 // character string literals.
1079 Constant(const char *) -> Constant<std::string>;
1080 Constant(char *) -> Constant<std::string>;
1081 
1082 
1083 // XXX:TODO
1084 // This should be implemented as an alias for an accessor that takes a predicate
1085 // plus .Compute(), but that requires implementing predicates plus having a way
1086 // to express the computation name and result type as computation parameters.
1087 // Therefore, for now, this is implemented as a value specifier.
1088 template <typename ResultType>
1089 struct NamespaceAncestor final
1091  Exec_ComputationBuilderProviderTypes::Prim>
1092 {
1093  /// \addtogroup group_Exec_ValueSpecifiers
1094  /// @{
1095 
1096  /// On a prim computation, requests an input value from the computation
1097  /// \p computationName of type \p ResultType on the nearest namespace
1098  /// ancestor prim.
1099  ///
1100  /// The default input name is \p computationName; use `InputName` to specify
1101  /// a different input name.
1102  ///
1103  /// # Example
1104  ///
1105  /// ```{.cpp}
1106  /// EXEC_REGISTER_COMPUTATIONS_FOR_SCHEMA(MySchemaType)
1107  /// {
1108  /// // Register a prim computation that finds the nearest namespace
1109  /// // ancestor that defines a computation 'sourceComputation' with
1110  /// // an `int` result type. If found, the result is the value of the
1111  /// // ancestor compuation; otherwise, returns 0.
1112  /// self.PrimComputation(_tokens->myComputation)
1113  /// .Callback<int>(+[](const VdfContext &ctx) {
1114  /// const int *const valuePtr =
1115  /// ctx.GetInputValuePtr<int>(_tokens->sourceComputation);
1116  /// return valuePtr ? *valuePtr : 0;
1117  /// })
1118  /// .Inputs(
1119  /// NamespaceAncestor<int>(_tokens->sourceComputation));
1120  /// }
1121  /// ```
1122  ///
1123  NamespaceAncestor(const TfToken &computationName)
1126  computationName,
1127  ExecTypeRegistry::GetInstance().
1128  CheckForRegistration<ResultType>(),
1131  {
1132  }
1133 
1134  /// @}
1135 };
1136 
1137 // XXX:TODO
1138 // AnimSpline
1139 
1140 
1141 /// \addtogroup group_Exec_Aliases
1142 /// @{
1143 
1144 // Note:
1145 // Aliases are implemented as generator functions, rather than as structs,
1146 // because that way they can simply be expressed as registrations.
1147 
1148 /// Input alias that yields the value of the named attribute.
1149 ///
1150 /// This registration must follow a
1151 /// [PrimComputation](#ExecComputationBuilder::PrimComputation) registration.
1152 ///
1153 /// > **Note:**
1154 /// > ```{.cpp}
1155 /// > AttributeValue<T>(attrToken)
1156 /// > ```
1157 /// >
1158 /// > is equivalent to:
1159 /// >
1160 /// > ```{.cpp}
1161 /// > Attribute(attrToken)
1162 /// > .Compute<T>(ExecBuiltinComputations->computeValue)
1163 /// > .InputName(attrToken)
1164 /// > ```
1165 ///
1166 /// # Example
1167 ///
1168 /// ```{.cpp}
1169 /// EXEC_REGISTER_COMPUTATIONS_FOR_SCHEMA(MySchemaType)
1170 /// {
1171 /// // Register a prim computation that returns the computed value of an
1172 /// // attribute.
1173 /// self.PrimComputation(_tokens->eleven)
1174 /// .Callback<double>(+[](const VdfContext &ctx) {
1175 /// ctx->SetOutput(ctx.GetInputValue<double>(_tokens->myAttribute));
1176 /// })
1177 /// .Inputs(
1178 /// AttributeValue<double>(_tokens->myAttribute).Required());
1179 /// }
1180 /// ```
1181 ///
1182 template <typename ValueType>
1183 auto
1184 AttributeValue(const TfToken &attributeName)
1185 {
1186  return Attribute(attributeName)
1188  .InputName(attributeName);
1189 }
1190 
1191 /// @} // Aliases
1192 
1193 /// \addtogroup group_Exec_ValueSpecifiers
1194 /// @{
1195 
1196 /// As a direct input to an attribute computation or after an
1197 /// [Attribute()](#exec_registration::Attribute::Attribute) accessor, requests
1198 /// input values from the computation \p computationName of type \p ResultType
1199 /// on the objects targeted by the attribute's connections.
1200 ///
1201 /// \note
1202 /// Conceptually, this input registration provides access to the owning
1203 /// attribute's connections, but as outlined in the paragraph above, in practice
1204 /// it requests the named computation from the objects that are targeted by
1205 /// those connections. The reason we choose "Connections" as the name, rather
1206 /// than "ConnectionTargetedObjects," is to allow for future expansion of USD to
1207 /// allow for value-transforming behaviors on attribute connections themselves.
1208 ///
1209 /// The default input name is \p computationName; use `InputName` to specify a
1210 /// different input name.
1211 ///
1212 /// # Example
1213 ///
1214 /// ```{.cpp}
1215 /// EXEC_REGISTER_COMPUTATIONS_FOR_SCHEMA(MySchemaType)
1216 /// {
1217 /// // Register an attribute computation on the attribute 'myAttr' that
1218 /// // sums the results of the integer values flowing over myAttr's
1219 /// // connections from the objects targeted by those connections.
1220 /// self.AttributeComputation(_tokens->myAttr, _tokens->computeSum)
1221 /// .Callback<int>(+[](const VdfContext &ctx) {
1222 /// int sum = 0;
1223 /// for (VdfReadIterator<int> it(
1224 /// ExecBuiltinComputations->computeValue);
1225 /// !it.IsAtEnd(); ++it) {
1226 /// sum += *it;
1227 /// }
1228 /// return sum;
1229 /// })
1230 /// .Inputs(
1231 /// Connections<int>(ExecBuiltinComputations->computeValue));
1232 /// }
1233 /// ```
1234 ///
1235 template <typename ResultType>
1236 auto
1237 Connections(const TfToken &computationName)
1238 {
1241  computationName,
1246 }
1247 
1248 /// On any provider, requests input values from the computation \p
1249 /// computationName of type \p ResultType on the attributes that own any
1250 /// attribute connections that target the provider object.
1251 ///
1252 /// When this input parameter produces multiple input values, there is no
1253 /// deterministic ordering.
1254 ///
1255 /// \note
1256 /// Conceptually, this input registration provides access to the connections
1257 /// that target the provider, but as outlined in the paragraph above, in
1258 /// practice it requests the named computation from the attributes that own
1259 /// those connections. The reason we choose "IncomingConnections" as the name,
1260 /// rather than "IncomingConnectionOwningAttributes," is to allow for future
1261 /// expansion of USD to allow for value-transforming behaviors on attribute
1262 /// connections themselves.
1263 ///
1264 /// The default input name is \p computationName; use `InputName` to specify a
1265 /// different input name.
1266 ///
1267 /// # Example
1268 ///
1269 /// ```{.cpp}
1270 /// EXEC_REGISTER_COMPUTATIONS_FOR_SCHEMA(MySchemaType)
1271 /// {
1272 /// // Register a prim computation that sums the values of the
1273 /// // integer-valued attributes that own connections that target the
1274 /// // provider prim.
1275 /// self.PrimComputation(_tokens->computeSum)
1276 /// .Callback<int>(+[](const VdfContext &ctx) {
1277 /// VdfReadIteratorRange<int> range(
1278 /// ctx, ExecBuiltinComputations->computeValue);
1279 /// return std::accumulate(range.begin(), range.end(), 0);
1280 /// })
1281 /// .Inputs(
1282 /// IncomingConnections<int>(ExecBuiltinComputations->computeValue));
1283 /// }
1284 /// ```
1285 ///
1286 template <typename ResultType>
1287 auto
1288 IncomingConnections(const TfToken &computationName)
1289 {
1292  computationName,
1297 }
1298 
1299 /// @} // Value Specifiers
1300 
1301 } // namespace exec_registration
1302 
1303 
1304 // We forward declare these classes so the generated documentation for
1305 // PrimComputation(), AttributeComputation(), and AttributeExpression() comes
1306 // before the Callback() and Inputs() docs.
1307 //
1311 
1312 /// The top-level builder object (aka, the `self` variable generated by
1313 /// EXEC_REGISTER_COMPUTATIONS_FOR_SCHEMA()).
1314 ///
1316 {
1317  EXEC_API
1318  ExecComputationBuilder(TfType schemaType);
1319 
1320 public:
1321  EXEC_API
1323 
1324  // Allows access to the constructor.
1325  //
1326  // Only schema computation registration functions should create computation
1327  // builders.
1329  static ExecComputationBuilder
1330  Construct(TfType schemaType) {
1331  return ExecComputationBuilder(schemaType);
1332  }
1333  };
1334 
1335  /// \addtogroup group_Exec_ComputationRegistrations
1336  /// @{
1337 
1338  /// Registers a prim computation named \p computationName.
1339  ///
1340  /// # Example
1341  ///
1342  /// ```{.cpp}
1343  /// EXEC_REGISTER_COMPUTATIONS_FOR_SCHEMA(MySchemaType)
1344  /// {
1345  /// // Register a trivial prim computation.
1346  /// self.PrimComputation(_tokens->eleven)
1347  /// .Callback<double>(+[](const VdfContext &) { return 11.0; })
1348  /// }
1349  /// ```
1350  ///
1351  EXEC_API
1353  PrimComputation(const TfToken &computationName);
1354 
1355  /// Registers an attribute computation named \p computationName on
1356  /// attributes named \p attributeName.
1357  ///
1358  /// # Example
1359  ///
1360  /// ```{.cpp}
1361  /// EXEC_REGISTER_COMPUTATIONS_FOR_SCHEMA(MySchemaType)
1362  /// {
1363  /// // Register a trivial attribute computation.
1364  /// self.AttributeComputation(
1365  /// _tokens->attr, // attributeName
1366  /// _tokens->eleven) // computationName
1367  /// .Callback<double>(+[](const VdfContext &) { return 11.0; })
1368  /// }
1369  /// ```
1370  ///
1371  EXEC_API
1374  const TfToken &attributeName,
1375  const TfToken &computationName);
1376 
1377  /// Registers an attribute expression for attributes named \p attributeName.
1378  ///
1379  /// All attributes have a *computed value* that can be consumed by
1380  /// computation inputs, either by explicitly requesting the built-in
1381  /// computation [computeValue](#Exec_BuiltinComputationTokens::computeValue)
1382  /// or by using [AttributeValue](#exec_registration::AttributeValue).
1383  /// The *attribute expression* allows plugin-writers to customize this
1384  /// computed value. If no attribute expression is defined, then
1385  /// [computeValue](#Exec_BuiltinComputationTokens::computeValue) simply
1386  /// provides the resolved value of the attribute.
1387  ///
1388  /// When defining an attribute expression, it is often desired that it
1389  /// consume the attribute's resolved value. The expression can obtain the
1390  /// resolved value by registering an input from the computation
1391  /// [computeResolvedValue](#Exec_BuiltinComputationTokens::computeResolvedValue)
1392  /// on the provider attribute.
1393  ///
1394  /// \note
1395  /// The attribute expression may produce a different type from the attribute
1396  /// on which it has been registered. Though allowed, this can lead to
1397  /// confusion, and this may become restricted in the future.
1398  ///
1399  /// # Example
1400  ///
1401  /// ```{.cpp}
1402  /// EXEC_REGISTER_COMPUTATIONS_FOR_SCHEMA(MySchemaType)
1403  /// {
1404  /// // Register an attribute expression for the string-valued attribute
1405  /// // 'myString', such that its computed value is its resolved value
1406  /// // in upper-case.
1407  /// self.AttributeExpression(_tokens->myString)
1408  /// .Inputs(
1409  /// Computation<std::string>(
1410  /// ExecBuiltinComputations->computeResolvedValue))
1411  /// .Callback(+[](const VdfContext &ctx) -> std::string {
1412  /// return TfStringToUpper(ctx.GetInputValue<std::string>(
1413  /// ExecBuiltinComputations->computeResolvedValue));
1414  /// });
1415  /// }
1416  /// ```
1417  ///
1418  EXEC_API
1420  AttributeExpression(const TfToken &attributeName);
1421 
1422  /// Registers a dispatched prim computation named \p computationName.
1423  ///
1424  /// A dispatched prim computation is only visible to computations on the
1425  /// prim that does the dispatching. I.e., the computation registrations for
1426  /// a schema can include dispatched computations and inputs to computations
1427  /// registered on the same schema can request the dispatched computations,
1428  /// using the input option FallsBackToDispatched(), from *other provider
1429  /// prims* and find them there. *Other schema computation registrations*
1430  /// will not be able to find the dispatched computations, however.
1431  ///
1432  /// Dispatched computations can be restricted as to which prims they can
1433  /// dispatch onto, based on the typed and applied schemas of a given target
1434  /// prim. The second parameter to the DispatchedPrimComputation registration
1435  /// function can be used to specify zero or more schema types (as
1436  /// TfType%s). If any types are given, the dispatched computation will only
1437  /// be found on a target prim if that prim's typed schema type (or one of
1438  /// its base type) is among the given schema types or if the fully expanded
1439  /// list of API schemas applied to the prim includes a schema that is among
1440  /// the given schema types.
1441  ///
1442  /// # Example
1443  ///
1444  /// ```{.cpp}
1445  /// EXEC_REGISTER_COMPUTATIONS_FOR_SCHEMA(MySchemaType)
1446  /// {
1447  /// // Register a dispatched prim computation that can be found on
1448  /// // scopes.
1449  /// const TfType scopeType = TfType::FindByName("UsdGeomScope");
1450  /// self.DispatchedPrimComputation(_tokens->eleven, scopeType)
1451  /// .Callback<double>(+[](const VdfContext &) { return 11.0; })
1452  ///
1453  /// // Register a prim computation that requests the above dispatched
1454  /// // computation via uses relationship targets. Any targeted prim
1455  /// // whose type is UsdGeomScope will find the requested computation.
1456  /// self.PrimComputation(_tokens->myComputation)
1457  /// .Callback<double>(+[](const VdfContext &ctx) {
1458  /// const double *const valuePtr =
1459  /// ctx.GetInputValuePtr<double>(_tokens->eleven);
1460  /// return valuePtr ? *valuePtr : -1.0;
1461  /// })
1462  /// .Inputs(
1463  ///
1464  /// // This input opts-in to finding dispatched computations.
1465  /// Relationship(_tokens->myRelationship)
1466  /// .TargetedObjects<double>(_tokens->eleven)
1467  /// .FallsBackToDispatched())
1468  /// }
1469  /// ```
1470  ///
1471  template <class... DispatchedOntoSchemaTypes>
1474  const TfToken &computationName,
1475  DispatchedOntoSchemaTypes &&...schemaTypes);
1476 
1477  // overload that takes a vector of TfTypes
1478  EXEC_API
1481  const TfToken &computationName,
1482  ExecDispatchesOntoSchemas &&ontoSchemas);
1483 
1484  /// Registers a dispatched attribute computation named \p computationName.
1485  ///
1486  /// \sa DispatchedPrimComputation
1487  ///
1488  /// # Example
1489  ///
1490  /// ```{.cpp}
1491  /// EXEC_REGISTER_COMPUTATIONS_FOR_SCHEMA(MySchemaType)
1492  /// {
1493  /// // Register a dispatched attribute computation that can be found on
1494  /// // attributes on scopes.
1495  /// const TfType scopeType = TfType::FindByName("UsdGeomScope");
1496  /// self.DispatchedAttributeComputation(_tokens->eleven, scopeType)
1497  /// .Callback<double>(+[](const VdfContext &) { return 11.0; })
1498  ///
1499  /// // Register a prim computation that requests the above dispatched
1500  /// // computation on an attribute on the owning prim named 'attr'.
1501  /// self.PrimComputation(_tokens->myComputation)
1502  /// .Callback<double>(+[](const VdfContext &ctx) {
1503  /// const double *const valuePtr =
1504  /// ctx.GetInputValuePtr<double>(_tokens->eleven);
1505  /// return valuePtr ? *valuePtr : -1.0;
1506  /// })
1507  /// .Inputs(
1508  ///
1509  /// // This input opts-in to finding dispatched computations.
1510  /// Attribute(_tokens->attr)
1511  /// .Computation<double>(_tokens->eleven)
1512  /// .FallsBackToDispatched())
1513  /// }
1514  /// ```
1515  ///
1516  template <class... DispatchedOntoSchemaTypes>
1519  const TfToken &computationName,
1520  DispatchedOntoSchemaTypes &&...schemaTypes);
1521 
1522  // overload that takes a vector of TfTypes
1523  EXEC_API
1526  const TfToken &computationName,
1527  ExecDispatchesOntoSchemas &&ontoSchemas);
1528 
1529  /// @}
1530 
1531 private:
1532  // The type of the schema for which this builder defines computations.
1533  TfType _schemaType;
1534 };
1535 
1536 
1537 // Untemplated base class for classes used to build computation definitions.
1539 {
1540 protected:
1541  EXEC_API
1543  const TfToken &attributeName,
1544  TfType schemaType,
1545  const TfToken &computationName,
1546  bool dispatched,
1547  ExecDispatchesOntoSchemas &&dispatchesOntoSchemas);
1548 
1550 
1551  // Adds the callback with result type.
1552  EXEC_API
1553  void _AddCallback(ExecCallbackFn &&calback, TfType resultType);
1554 
1555  // Validates that all inputs are allowed to be registered on computations of
1556  // the \p allowed provider types.
1557  //
1558  template <Exec_ComputationBuilderProviderTypes allowed, typename T>
1559  static void _ValidateInputs();
1560 
1561  // Adds an input key from the given value specifier.
1562  //
1563  // This extra level of indirection helps keep Exec_InputKey out of the
1564  // header so that type can remain private.
1565  //
1566  EXEC_API
1567  void _AddInputKey(
1568  const Exec_ComputationBuilderValueSpecifierBase *valueSpecifier);
1569 
1570  // Returns a pointer to the dispatches-onto schemas if the computation is
1571  // dispatched, or a null pointer, otherwise.
1572  //
1573  std::unique_ptr<ExecDispatchesOntoSchemas>
1575 
1576  // We PIMPL the data for this class to avoid exposing more private details
1577  // in this public header.
1578  //
1579  struct _Data;
1580  _Data &_GetData();
1581 
1582 private:
1583  const std::unique_ptr<_Data> _data;
1584 };
1585 
1586 
1587 // CRTP base class for classes used to build computation definitions.
1588 template <typename Derived>
1590 {
1591  // Type used as a default template parameter type for metaprogramming.
1592  struct _UnspecifiedType {};
1593 
1594 protected:
1595  EXEC_API
1597  const TfToken &attributeName,
1598  TfType schemaType,
1599  const TfToken &computationName,
1600  bool dispatched,
1601  ExecDispatchesOntoSchemas &&dispatchesOntoSchemas);
1602 
1603  EXEC_API
1605 
1606 public:
1607  /// \ingroup group_Exec_ComputationRegistrations
1608  ///
1609  /// Registers a callback function that implements the evaluation logic for a
1610  /// computation.
1611  ///
1612  /// This registration must follow a [computation
1613  /// registration](#group_Exec_ComputationRegistrations).
1614  ///
1615  /// Callback functions must be function pointers where the signature is
1616  /// `ReturnType (*)(const VdfContext &)` and \p ReturnType can be any of the
1617  /// following:
1618  ///
1619  /// - The result type of the computation, in which case `ResultType` can be
1620  /// deduced from the callback type.
1621  /// - A type that is convertible to the result type of the computaion, in
1622  /// which case \p ResultType must be explicitly specified as a template
1623  /// parameter.
1624  /// - `void` in which case \p ResultType must be explicitly specified as a
1625  /// template parameter *and* the callback must call VdfContext::SetOutput
1626  /// to provide the output value.
1627  ///
1628  /// # Result Types
1629  ///
1630  /// Note that the types used as computation result types (and as computation
1631  /// input value types) must be known to the execution system. All types that
1632  /// can be used to author attribute and metadata values in USD are known to
1633  /// exec by default. User-defined types must be registered by calling
1634  /// ExecTypeRegistry::RegisterType.
1635  ///
1636  /// # Example
1637  ///
1638  /// ```{.cpp}
1639  /// EXEC_REGISTER_COMPUTATIONS_FOR_SCHEMA(MySchemaType)
1640  /// {
1641  /// // Register a prim computation with a callback where the result type
1642  /// // is deduced to be `float`.
1643  /// self.PrimComputation(_tokens->doubleValuedComputation)
1644  /// .Callback(
1645  /// +[](const VdfContext &) { return 11.0f; });
1646  ///
1647  /// // Register a prim computation with a callback where the explicit
1648  /// // result type is `std::string`.
1649  /// self.PrimComputation(_tokens->stringValuedComputation)
1650  /// .Callback<std::string>(
1651  /// +[](const VdfContext &) { return "a string value"; });
1652  ///
1653  /// // Register a prim computation with a callback that explicitly calls
1654  /// // SetValue.
1655  /// self.PrimComputation(_tokens->stringValuedComputation)
1656  /// .Callback<int>(
1657  /// +[](const VdfContext &) { ctx.SetValue(42); });
1658  /// }
1659  /// ```
1660  ///
1661  template<
1662  typename ResultType = _UnspecifiedType,
1663  typename ReturnType = _UnspecifiedType>
1664  Derived&
1665  Callback(ReturnType (*callback)(const VdfContext &));
1666 };
1667 
1668 
1669 /// Class used to build prim computation definitions.
1671  : public Exec_ComputationBuilderCRTPBase<ExecPrimComputationBuilder>
1672 {
1673  // Only ExecComputationBuilder can create instances.
1675 
1676  EXEC_API
1678  TfType schemaType,
1679  const TfToken &computationName,
1680  bool dispatched = false,
1681  ExecDispatchesOntoSchemas &&dispatchesOntoSchemas = {});
1682 
1683 public:
1684  EXEC_API
1686 
1687  /// \ingroup group_Exec_ComputationRegistrations
1688  ///
1689  /// Takes one or more [input registrations](#group_Exec_InputRegistrations)
1690  /// that specify how to source input values for a prim computation.
1691  ///
1692  /// This registration must follow a [computation
1693  /// registration](#group_Exec_ComputationRegistrations).
1694  ///
1695  /// # Example
1696  ///
1697  /// ```{.cpp}
1698  /// EXEC_REGISTER_COMPUTATIONS_FOR_SCHEMA(MySchemaType)
1699  /// {
1700  /// // Register a prim computation that reads from two inputs.
1701  /// self.PrimComputation(_tokens->myPrimComputation)
1702  /// .Callback<int>(&_MyCallbackFn)
1703  /// .Inputs(
1704  /// AttributeValue<int>(_tokens->myAttribute),
1705  /// NamespaceAncestor<double>(_tokens->anotherPrimComputation));
1706  /// }
1707  /// ```
1708  ///
1709  template <typename... Args>
1711  Inputs(Args && ... args);
1712 };
1713 
1714 
1715 /// Class used to build attribute computation definitions.
1717  : public Exec_ComputationBuilderCRTPBase<ExecAttributeComputationBuilder>
1718 {
1719  // Only ExecComputationBuilder can create instances.
1721 
1722  EXEC_API
1724  const TfToken &attributeName,
1725  TfType schemaType,
1726  const TfToken &computationName,
1727  bool dispatched = false,
1728  ExecDispatchesOntoSchemas &&dispatchesOntoSchemas = {});
1729 
1730 public:
1731  EXEC_API
1733 
1734  /// \ingroup group_Exec_ComputationRegistrations
1735  ///
1736  /// Takes one or more [input registrations](#group_Exec_InputRegistrations)
1737  /// that specify how to source input values for an attribute computation.
1738  ///
1739  /// This registration must follow a [computation
1740  /// registration](#group_Exec_ComputationRegistrations).
1741  ///
1742  /// # Example
1743  ///
1744  /// ```{.cpp}
1745  /// EXEC_REGISTER_COMPUTATIONS_FOR_SCHEMA(MySchemaType)
1746  /// {
1747  /// // Register an attribute computation that reads from another
1748  /// // computation on the same attribute, and from a sibling attribute's
1749  /// // computed value.
1750  /// self.AttributeComputation(
1751  /// _tokens->attr,
1752  /// _tokens->myAttrComputation)
1753  /// .Callback<int>(&_MyCallbackFn)
1754  /// .Inputs(
1755  /// Computation<double>(_tokens->anotherAttrComputation),
1756  /// Prim().AttributeValue<double>(_tokens->anotherAttr));
1757  /// }
1758  /// ```
1759  ///
1760  template <typename... Args>
1762  Inputs(Args && ... args);
1763 };
1764 
1765 /// Class used to build attribute expression definitions.
1767  : public Exec_ComputationBuilderCRTPBase<ExecAttributeExpressionBuilder>
1768 {
1769  // Only ExecComputationBuilder can create instances.
1771 
1772  EXEC_API
1774  const TfToken &attributeName,
1775  TfType schemaType);
1776 
1777 public:
1778  EXEC_API
1780 
1781  /// \ingroup group_Exec_ComputationRegistrations
1782  ///
1783  /// Takes one or more [input registrations](#group_Exec_InputRegistrations)
1784  /// that specify how to source input values for an attribute expression.
1785  ///
1786  /// This registration must follow a [computation
1787  /// registration](#group_Exec_ComputationRegistrations).
1788  ///
1789  /// # Example
1790  ///
1791  /// ```{.cpp}
1792  /// EXEC_REGISTER_COMPUTATIONS_FOR_SCHEMA(MySchemaType)
1793  /// {
1794  /// // Register an attribute expression that uses the attribute's
1795  /// // resolved value, and the computed value of all connected
1796  /// // attributes.
1797  /// self.AttributeExpression(_tokens->attr)
1798  /// .Callback<int>(&_MyCallbackFn)
1799  /// .Inputs(
1800  /// Computation<double>(
1801  /// ExecBuiltinComputations->computeResolvedValue),
1802  /// Connections<double>(ExecBuiltinComputations->computeValue));
1803  /// }
1804  /// ```
1805  ///
1806  template <typename... Args>
1808  Inputs(Args && ... args);
1809 };
1810 
1811 
1812 //
1813 // Exec_ComputationBuilderBase
1814 //
1815 
1816 template <Exec_ComputationBuilderProviderTypes allowed, typename T>
1817 void
1819  using regType = std::decay_t<T>;
1820  static_assert(
1821  !std::is_base_of_v<Exec_ComputationBuilderAccessorBase, regType>,
1822  "Accessor can't provide an input value.");
1823  static_assert(
1824  !std::is_same_v<Exec_ComputationBuilderConstantAccessorBase, regType>,
1825  "Constant(value) must be followed by .InputName(inputNameToken)");
1826  static_assert(
1827  std::is_base_of_v<Exec_ComputationBuilderValueSpecifierBase, regType>,
1828  "Invalid type used as an input registration.");
1829  static_assert(
1830  regType::allowedProviders & allowed,
1831  "Input is not allowed on a provider of this type.");
1832 }
1833 
1834 //
1835 // Exec_ComputationBuilderCRTPBase
1836 //
1837 
1838 template <typename Derived>
1839 template <typename InputResultType, typename ReturnType>
1840 Derived&
1842  ReturnType (*callback)(const VdfContext &))
1843 {
1844  // In order to allow the return type of the callback to be different from
1845  // the computation result type in some cases AND be able to deduce the
1846  // result type from the return type in others, we have to default both
1847  // template parameters to _UnspecifiedType and use metaprogramming to get
1848  // the actual result type.
1849  using ResultType =
1851  std::is_same_v<InputResultType, _UnspecifiedType>,
1852  ReturnType,
1853  InputResultType>;
1854 
1855  static_assert(
1856  !std::is_void_v<ResultType> ||
1857  std::is_convertible_v<ReturnType, ResultType>,
1858  "Callback return type must be convertible to the computation result "
1859  "type");
1860  static_assert(
1861  !std::is_reference_v<ResultType>,
1862  "Callback functions must return by value");
1863  static_assert(
1865  "VtArray is not a supported result type");
1866 
1867  const TfType resultType =
1869 
1870  // If the return type is void, the callback is on the hook to call
1871  // VdfContext::SetOutput; otherwise, we wrap it in a lambda that passes
1872  // the callback return value to SetOutput.
1873  if constexpr (std::is_void_v<ReturnType>) {
1874  _AddCallback(callback, resultType);
1875  } else {
1876  _AddCallback(
1877  [callback](const VdfContext& ctx) {
1878  ctx.SetOutput<ResultType>(callback(ctx));
1879  },
1880  resultType);
1881  }
1882 
1883  return *static_cast<Derived*>(this);
1884 }
1885 
1886 //
1887 // ExecPrimComputationBuilder
1888 //
1889 
1890 template <typename... Args>
1893  Args && ... args)
1894 {
1895  // Validate inputs
1896  (_ValidateInputs<
1898 
1899  // Add inputs
1900  (_AddInputKey(&args), ...);
1901 
1902  return *this;
1903 }
1904 
1905 //
1906 // ExecAttributeComputationBuilder
1907 //
1908 
1909 template <typename... Args>
1912  Args && ... args)
1913 {
1914  // Validate inputs
1915  (_ValidateInputs<
1917 
1918  // Add inputs
1919  (_AddInputKey(&args), ...);
1920 
1921  return *this;
1922 }
1923 
1924 //
1925 // ExecAttributeExpressionBuilder
1926 //
1927 
1928 template <typename... Args>
1931  Args && ... args)
1932 {
1933  // Validate inputs
1934  (_ValidateInputs<
1936 
1937  // Add inputs
1938  (_AddInputKey(&args), ...);
1939 
1940  return *this;
1941 }
1942 
1943 //
1944 // ExecComputationBuilder
1945 //
1946 
1947 template <class... DispatchedOntoSchemaTypes>
1950  const TfToken &computationName,
1951  DispatchedOntoSchemaTypes &&...schemaTypes)
1952 {
1953  static_assert(
1954  (std::is_same_v<
1955  std::decay_t<DispatchedOntoSchemaTypes>, TfType> && ...));
1956 
1958  computationName,
1959  {std::forward<DispatchedOntoSchemaTypes>(schemaTypes)...});
1960 }
1961 
1962 template <class... DispatchedOntoSchemaTypes>
1965  const TfToken &computationName,
1966  DispatchedOntoSchemaTypes &&...schemaTypes)
1967 {
1968  static_assert(
1969  (std::is_same_v<
1970  std::decay_t<DispatchedOntoSchemaTypes>, TfType> && ...));
1971 
1973  computationName,
1974  {std::forward<DispatchedOntoSchemaTypes>(schemaTypes)...});
1975 }
1976 
1978 
1979 #endif
Exec_ComputationBuilderPropertyAccessor(const SdfPath &localTraversal)
EXEC_API ~ExecComputationBuilder()
auto IncomingConnections(const TfToken &computationName)
NamespaceAncestor(const TfToken &computationName)
Exec_ComputationBuilderAttributeAccessor(const SdfPath &localTraversal)
Class used to build prim computation definitions.
EXEC_API ExecPrimComputationBuilder PrimComputation(const TfToken &computationName)
static constexpr Exec_ComputationBuilderProviderTypes allowedProviders
Computation(const TfToken &computationName)
ExecPrimComputationBuilder & Inputs(Args &&...args)
Exec_ComputationBuilderAccessorBase(const SdfPath &localTraversal)
typename std::conditional< B, T, F >::type conditional_t
Definition: core.h:266
auto AttributeValue(const TfToken &attributeName)
See AttributeValue()
#define PXR_NAMESPACE_OPEN_SCOPE
Definition: pxr.h:73
ExecAttributeComputationBuilder & Inputs(Args &&...args)
EXEC_API void _SetInputName(const TfToken &inputName)
EXEC_API Exec_ComputationBuilderCRTPBase(const TfToken &attributeName, TfType schemaType, const TfToken &computationName, bool dispatched, ExecDispatchesOntoSchemas &&dispatchesOntoSchemas)
GLboolean GLboolean GLboolean GLboolean a
Definition: glcorearb.h:1222
void SetOutput(const TfToken &outputName, const T &value) const
Definition: context.h:394
auto Connections(const TfToken &computationName)
Attribute accessor, valid for providing input to a prim computation.
EXEC_API Exec_ComputationBuilderConstantValueSpecifier(const TfType resultType, const SdfPath &localTraversal, const TfToken &inputName, VtValue &&constantValue)
Metadata value specifier, valid on a prim or attribute computation.
Exec_ComputationBuilderComputationValueSpecifier(const TfToken &computationName, const TfType resultType, ExecProviderResolution &&providerResolution, const TfToken &disambiguatingId=TfToken())
ValueSpecifier IncomingConnections(const TfToken &computationName)
See IncomingConnections()
ValueSpecifier Metadata(const TfToken &metadataKey)
See Metadata()
EXEC_API void _SetFallsBackToDispatched(bool fallsBackToDispatched)
ExecAttributeComputationBuilder DispatchedAttributeComputation(const TfToken &computationName, DispatchedOntoSchemaTypes &&...schemaTypes)
Definition: token.h:70
Exec_ComputationBuilderComputationValueSpecifier< allowed > ValueSpecifier
static ExecComputationBuilder Construct(TfType schemaType)
The localTraversal path directly indicates the computation provider.
ExecAttributeExpressionBuilder & Inputs(Args &&...args)
static constexpr Exec_ComputationBuilderProviderTypes allowedProviders
constexpr bool operator&(const Exec_ComputationBuilderProviderTypes a, const Exec_ComputationBuilderProviderTypes b)
std::unique_ptr< ExecDispatchesOntoSchemas > _GetDispatchesOntoSchemas()
std::function< void(const class VdfContext &context)> ExecCallbackFn
Function type used for computation callbacks.
Definition: types.h:28
Exec_ComputationBuilderProviderTypes
Exec_ComputationBuilderRelationshipAccessor(const SdfPath &localTraversal)
EXEC_API TfStaticData< Exec_BuiltinComputationTokens > ExecBuiltinComputations
ValueSpecifier TargetedObjects(const TfToken &computationName)
Prim accessor, valid for providing input to an attribute computation.
Relationship accessor, valid for providing input to a prim computation.
#define EXEC_API
Definition: api.h:25
Definition: path.h:280
GLboolean GLboolean GLboolean b
Definition: glcorearb.h:1222
EXEC_API void _AddInputKey(const Exec_ComputationBuilderValueSpecifierBase *valueSpecifier)
static EXEC_API const ExecTypeRegistry & GetInstance()
Constant(const char *) -> Constant< std::string >
Constant(const ValueType &constantValue)
SDF_API SdfPath AppendProperty(TfToken const &propName) const
Exec_ComputationBuilderAttributeAccessor< Exec_ComputationBuilderProviderTypes::Attribute > Attribute(const TfToken &attributeName)
See Attribute()
A trait to detect instantiations of VtArray, specialized in array.h.
Definition: traits.h:22
TfType CheckForRegistration() const
Definition: typeRegistry.h:120
ValueSpecifier Computation(const TfToken &computationName)
See Computation()
Exec_ComputationBuilderComputationValueSpecifier< allowed > ValueSpecifier
Constant(ValueType &&constantValue)
Exec_ComputationBuilderConstantValueSpecifier InputName(const TfToken &inputName)&&
Exec_ComputationBuilderComputationValueSpecifier< allowed > ValueSpecifier
Metadata(const TfToken &metadataKey)
Find the provider by traversing upward in namespace.
Computation value specifier, valid for providing input to any computation.
#define PXR_NAMESPACE_CLOSE_SCOPE
Definition: pxr.h:74
Exec_ComputationBuilderRelationshipAccessor< Exec_ComputationBuilderProviderTypes::Attribute > Relationship(const TfToken &relationshipName)
See Relationship()
EXEC_API ~ExecAttributeExpressionBuilder()
auto AttributeValue(const TfToken &attributeName)
**If you just want to fire and args
Definition: thread.h:618
Definition: type.h:47
ValueSpecifier Connections(const TfToken &computationName)
See Connections()
EXEC_API void _AddCallback(ExecCallbackFn &&calback, TfType resultType)
EXEC_API Exec_ComputationBuilderConstantAccessorBase(VtValue &&constantValue, TfType valueType)
EXEC_API void _SetOptional(const bool optional)
EXEC_API ~ExecPrimComputationBuilder()
EXEC_API Exec_ComputationBuilderBase(const TfToken &attributeName, TfType schemaType, const TfToken &computationName, bool dispatched, ExecDispatchesOntoSchemas &&dispatchesOntoSchemas)
EXEC_API ExecAttributeComputationBuilder AttributeComputation(const TfToken &attributeName, const TfToken &computationName)
static SDF_API const SdfPath & ReflexiveRelativePath()
The relative path representing "self".
EXEC_API Exec_ComputationBuilderValueSpecifierBase(const TfToken &computationName, TfType resultType, ExecProviderResolution &&providerResolution, const TfToken &inputName, const TfToken &disambiguatingId)
Attribute(const TfToken &attributeName)
bool ValueType
Definition: NanoVDB.h:5729
Class used to build attribute expression definitions.
const SdfPath & _GetLocalTraversal() const
Definition: value.h:89
Provides access to the stage, valid for providing input to any computation.
Exec_ComputationBuilderAccessor(const SdfPath &localTraversal)
Derived & Callback(ReturnType(*callback)(const VdfContext &))
Class used to build attribute computation definitions.
static EXEC_API Exec_ComputationBuilderComputationValueSpecifier< allowed > _GetMetadataValueSpecifier(const TfType resultType, const SdfPath &localTraversal, const TfToken &metadataKey)
EXEC_API ExecAttributeExpressionBuilder AttributeExpression(const TfToken &attributeName)
ExecPrimComputationBuilder DispatchedPrimComputation(const TfToken &computationName, DispatchedOntoSchemaTypes &&...schemaTypes)
Exec_ComputationBuilderComputationValueSpecifier< allowed > This
Relationship(const TfToken &relationshipName)