HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
executionTypeRegistry.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_EXECUTION_TYPE_REGISTRY_H
8 #define PXR_EXEC_VDF_EXECUTION_TYPE_REGISTRY_H
9 
10 /// \file
11 
12 #include "pxr/pxr.h"
13 
14 #include "pxr/exec/vdf/api.h"
17 
19 #include "pxr/base/tf/mallocTag.h"
20 #include "pxr/base/tf/singleton.h"
21 #include "pxr/base/tf/type.h"
22 
23 #include <tbb/spin_rw_mutex.h>
24 
25 #include <map>
26 #include <utility>
27 
29 
30 /// Manages low-level value type functionality used within execution.
31 ///
32 /// All types used as values in execution must be registered with
33 /// VdfExecutionTypeRegistry::Define.
34 ///
35 /// All API is thread safe.
36 ///
38 {
39 public:
40 
41  // Non-copyable
42  //
45  const VdfExecutionTypeRegistry &) = delete;
46 
47  VDF_API
49 
50  /// Returns the VdfExecutionTypeRegistry singleton instance.
51  ///
52  VDF_API
54 
55  /// Registers `T` with execution's runtime type dispatch system.
56  ///
57  /// \p fallback is required because execution supports types that are not
58  /// default constructible as well as types for which a default-constructed
59  /// value is not the desired fallback value.
60  ///
61  /// This call will also define `T` with TfType if it is not registered
62  /// yet.
63  ///
64  template <typename T>
65  static TfType Define(const T &fallback);
66 
67  /// Registers `T` with execution's runtime type dispatch system as a
68  /// derived type of `B`.
69  ///
70  template <typename T, typename B>
71  static TfType Define(const T &fallback);
72 
73  /// Returns the registered fallback value for `T` from the registry.
74  ///
75  /// It is a fatal error to query types that are not registered.
76  ///
77  template <typename T>
78  inline const T &GetFallback() const;
79 
80  /// Checks if `T` is defined as an execution value type.
81  ///
82  /// Returns the TfType of `T`. If the check fails, a fatal error will be
83  /// issued. The intent is to make sure that all required types are
84  /// registered at the time this method is called.
85  ///
86  /// Use \p additionalErrorMsg to append a custom message if a fatal error is
87  /// emitted.
88  ///
89  template <typename T>
91  const char *const additionalErrorMsg=nullptr) {
92  return CheckForRegistration(typeid(T), additionalErrorMsg);
93  }
94 
95  /// Checks if \p ti is defined as an execution value type.
96  ///
97  /// This method will issue a fatal error if the type isn't registered.
98  ///
99  VDF_API
101  const std::type_info &typeInfo,
102  const char *const additionalErrorMsg);
103 
104  /// Create an empty VdfVector holding empty data of the given TfType.
105  ///
106  /// Note this creates an empty vector, not a fallback-valued vector.
107  /// See also VdfTypedVector for creating empty vectors by type.
108  ///
109  VDF_API
111 
112  /// Fills \p vector with the fallback value registered for the given type.
113  ///
114  VDF_API
115  static void FillVector(TfType type, size_t numElements, VdfVector *vector);
116 
117 private:
118 
121 
122  // Provides functionality common to both overloads of Define().
123  template <typename T>
124  void _Define(const T &fallback, TfType scalarType);
125 
126  // A very simple type-erased container used to hold fallback values.
127  class _Value;
128 
129  // Inserts fallback as the value for type.
130  //
131  // Attempting to register a fallback with unknown type is a fatal error.
132  //
133  VDF_API
134  std::pair<const _Value &, bool> _InsertRegistration(
135  TfType type, _Value &&fallback);
136 
137  // Helper method to share code for looking up fallback values that is
138  // common to all instantiations of GetFallback.
139  //
140  VDF_API
141  const _Value &_GetFallback(TfType type) const;
142 
143  // Typed implementation of CreateEmptyVector.
144  template <typename T>
145  struct _CreateEmptyVector {
146  static VdfVector Call() {
147  return VdfTypedVector<T>();
148  }
149  };
150 
151  // Typed implementation of FillVector.
152  template <typename T>
153  struct _FillVector {
154  static bool Call(
155  const _Value &fallback, size_t numElements, VdfVector *vector);
156  };
157 
158 private:
159 
160  // Map of (scalar) value types to their type-erased fallback values and
161  // mutex that serializes access to it.
162  //
163  // Writes occur once per type definition but reads occur many times during
164  // various phases of execution.
165  std::map<TfType, _Value> _fallbackMap;
166  mutable tbb::spin_rw_mutex _fallbackMapMutex;
167 
168  VdfTypeDispatchTable<_CreateEmptyVector> _createEmptyVectorTable;
169  VdfTypeDispatchTable<_FillVector> _fillVectorDispatchTable;
170 };
171 
172 // A very simple type-erased container.
173 //
174 // This provides only functionality that is relevant to storing execution
175 // fallback values. Other, more general type-erased containers can cause
176 // substantial compilation time increases because we store many types and
177 // their unused functionality must still be emitted.
178 //
180 {
181 public:
182  template <typename T>
183  explicit _Value(const T &fallback)
184  : _ptr(TfAnyUniquePtr::New(fallback))
185  {}
186 
187  // Returns a reference to the held value.
188  //
189  // There is no checked Get. The registry must ensure that nobody is
190  // able to register values for the wrong type.
191  //
192  template <typename T>
193  const T & UncheckedGet() const {
194  return *static_cast<const T*>(_ptr.Get());
195  }
196 
197  // Compares values for types that define equality comparision; returns
198  // true if not equality comparable.
199  //
200  template <typename T>
201  bool Equals(const T &rhs) const {
202  if constexpr (VdfIsEqualityComparable<T>) {
203  return UncheckedGet<T>() == rhs;
204  }
205  else {
206  return true;
207  }
208  }
209 
210 private:
211  TfAnyUniquePtr _ptr;
212 };
213 
214 template <typename T>
215 TfType
217 {
218  TfAutoMallocTag mallocTag("Vdf", "VdfExecutionTypeRegistry::Define");
219  // Define type with Tf if needed.
220  TfType scalarType = TfType::Find<T>();
221  if (scalarType.IsUnknown() ||
222  !TF_VERIFY(scalarType.GetTypeid() != typeid(void),
223  "Type '%s' was declared but not defined",
224  scalarType.GetTypeName().c_str())) {
225 
226  scalarType = TfType::Define<T>();
227  }
228 
229  VdfExecutionTypeRegistry::GetInstance()._Define(fallback, scalarType);
230  return scalarType;
231 }
232 
233 template <typename T, typename B>
234 TfType
236 {
237  TfAutoMallocTag mallocTag("Vdf", "VdfExecutionTypeRegistry::Define");
238  // Define type with Tf if needed.
239  TfType scalarType = TfType::Find<T>();
240  if (scalarType.IsUnknown() ||
241  !TF_VERIFY(scalarType.GetTypeid() != typeid(void),
242  "Type '%s' was declared but not defined",
243  scalarType.GetTypeName().c_str())) {
244 
245  scalarType = TfType::Define<T, B>();
246  }
247 
248  GetInstance()._Define(fallback, scalarType);
249  return scalarType;
250 }
251 
252 template <typename T>
253 void
254 VdfExecutionTypeRegistry::_Define(const T &fallback, TfType scalarType)
255 {
256  // Use the presence of an entry in the fallback map to avoid redundant
257  // registration with other maps in cases where multiple plugins register
258  // the same type, which is allowed.
259  if (const auto [registeredFallback, inserted] = _InsertRegistration(
260  scalarType, _Value(fallback)); !inserted) {
261  TF_VERIFY(
262  registeredFallback.Equals(fallback),
263  "Type %s registered more than once with different fallback "
264  "values.",
265  scalarType.GetTypeName().c_str());
266  return;
267  }
268 
269  VdfOutputSpec::_RegisterType<T>();
270  _createEmptyVectorTable.RegisterType<T>();
271  _fillVectorDispatchTable.RegisterType<T>();
272 }
273 
274 template <typename T>
275 const T &
277 {
278  const _Value &fallback = _GetFallback(TfType::Find<T>());
279  return fallback.UncheckedGet<T>();
280 }
281 
282 template <typename T>
283 bool
284 VdfExecutionTypeRegistry::_FillVector<T>::Call(
285  const _Value &fallback,
286  size_t numElements,
287  VdfVector *vector)
288 {
289  const T &fallbackValue = fallback.UncheckedGet<T>();
290 
291  vector->Resize<T>(numElements);
293  vector->GetReadWriteAccessor<T>();
294  for (size_t i = 0; i < numElements; ++i) {
295  accessor[i] = fallbackValue;
296  }
297 
298  return true;
299 }
300 
302 
303 #endif
ReadWriteAccessor< TYPE > GetReadWriteAccessor() const
Definition: vector.h:456
bool IsUnknown() const
Definition: type.h:374
void
Definition: png.h:1083
#define PXR_NAMESPACE_OPEN_SCOPE
Definition: pxr.h:73
static VDF_API VdfVector CreateEmptyVector(TfType type)
#define VDF_API
Definition: api.h:25
static VDF_API void FillVector(TfType type, size_t numElements, VdfVector *vector)
static TfType Define(const T &fallback)
GLint GLint GLsizei GLint GLenum GLenum type
Definition: glcorearb.h:108
VDF_API ~VdfExecutionTypeRegistry()
static TfType CheckForRegistration(const char *const additionalErrorMsg=nullptr)
static VDF_API VdfExecutionTypeRegistry & GetInstance()
TF_API const std::string & GetTypeName() const
#define PXR_NAMESPACE_CLOSE_SCOPE
Definition: pxr.h:74
Definition: type.h:47
TF_API const std::type_info & GetTypeid() const
VdfExecutionTypeRegistry & operator=(const VdfExecutionTypeRegistry &)=delete
void const * Get() const
Return a pointer to the owned object.
Definition: anyUniquePtr.h:69
void Resize(size_t size)
Definition: vector.h:218