HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
executorBufferData.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_EXECUTOR_BUFFER_DATA_H
8 #define PXR_EXEC_VDF_EXECUTOR_BUFFER_DATA_H
9 
10 /// \file
11 
12 #include "pxr/pxr.h"
13 
14 #include "pxr/exec/vdf/api.h"
15 #include "pxr/exec/vdf/mask.h"
16 #include "pxr/exec/vdf/smblData.h"
17 
18 #include <atomic>
19 
21 
22 class VdfOutputSpec;
23 class VdfVector;
24 
25 ///////////////////////////////////////////////////////////////////////////////
26 ///
27 /// \brief This object is responsible for storing the executor buffer data,
28 /// comprised of the executor cache vector, as well as a mask that denotes the
29 /// available data.
30 ///
32 {
33 public:
34  /// Noncopyable.
35  ///
38 
39  /// Constructor
40  ///
41  VdfExecutorBufferData() : _cacheAndFlags() {}
42 
43  /// Destructor.
44  ///
45  VDF_API
47 
48  /// Reset the instance to its original, newly constructed state.
49  ///
50  VDF_API
51  void Reset();
52 
53  /// Clones this VdfExecutorBufferData instance to \p dest.
54  ///
55  VDF_API
56  void Clone(VdfExecutorBufferData *dest) const;
57 
58  /// Creates a new executor cache for this buffer.
59  ///
60  inline VdfVector *CreateExecutorCache(const VdfOutputSpec &spec);
61 
62  /// Creates a new executor cache for this buffer. The executor cache will
63  /// be sized to accommodate all the entries set in the given \p bits.
64  ///
66  const VdfOutputSpec &spec,
67  const VdfMask::Bits &bits);
68 
69  /// Swaps the executor cache at this buffer, with that of another buffer.
70  ///
72 
73  /// Returns the executor cache stored at this buffer data instance.
74  ///
75  inline VdfVector *GetExecutorCache() const;
76 
77  /// Get the available mask.
78  ///
79  inline const VdfMask &GetExecutorCacheMask() const;
80 
81  /// Sets the available mask.
82  ///
83  inline void SetExecutorCacheMask(const VdfMask &mask);
84 
85  /// Reset the executor cache without releasing any memory and set the
86  /// executor cache mask to \p mask.
87  ///
88  inline void ResetExecutorCache(const VdfMask &mask);
89 
90  /// Reset the executor cache without releasing any memory.
91  ///
92  inline void ResetExecutorCache();
93 
94  /// Takes the existing executor cache and retains it within the
95  /// existing VdfSMBLData object.
96  ///
97  VDF_API
98  void RetainExecutorCache(const VdfOutputSpec &spec, VdfSMBLData *smblData);
99 
100  /// Merges the executor cache previously retained in \p smblData into
101  /// this cache and releases the SMBL data. Returns the mask denoting the
102  /// data merged into the executor cache.
103  ///
104  VDF_API
106 
107  /// Returns \c true if the buffer owns the executor cache. The owner of the
108  /// cache is responsible for its lifetime management.
109  ///
110  inline bool HasOwnership() const;
111 
112  /// Yields ownership of the internal vector, i.e. the vector will no
113  /// longer be deallocated when this object goes out of scope.
114  ///
115  inline void YieldOwnership();
116 
117  /// Yields ownership of the given \p vector. Note, this method deallocates
118  /// any vector previously owned by this instance.
119  ///
120  inline void YieldOwnership(VdfVector *v);
121 
122  /// Assumes ownership of the given vector. Note, this will cause the
123  /// given vector to be deallocated when this instance goes out of scope.
124  /// The client must ensure that only a single buffer instance maintains
125  /// ownership over any vector.
126  ///
127  inline void TakeOwnership(VdfVector *v);
128 
129 private:
130 
131  // Flag denotes whether the VdfVector is owned by this buffer.
132  static constexpr uintptr_t _IsOwnedFlag = 1 << 0;
133 
134  // Flag denotes whether the cache is occupied, rather than merely allocated.
135  static constexpr uintptr_t _IsOccupiedFlag = 1 << 1;
136 
137  // Masks the flags in the cache pointer.
138  static constexpr uintptr_t _FlagsMask = _IsOwnedFlag | _IsOccupiedFlag;
139 
140  // Casts the integer value to a pointer value.
141  static VdfVector *_CastToPointer(uintptr_t v) {
142  return reinterpret_cast<VdfVector *>(reinterpret_cast<void *>(v));
143  }
144 
145  // Casts the pointer value to an integer value.
146  static uintptr_t _CastToInteger(VdfVector *v) {
147  return reinterpret_cast<uintptr_t>(reinterpret_cast<void *>(v));
148  }
149 
150  // Returns the cache pointer from the cache-with-flags value.
151  static VdfVector *_GetCache(VdfVector *cacheAndFlags) {
152  return _CastToPointer(_CastToInteger(cacheAndFlags) & ~_FlagsMask);
153  }
154 
155  // Retuns the flags from the cache-with-flags value.
156  static uintptr_t _GetFlags(VdfVector *cacheAndFlags) {
157  return _CastToInteger(cacheAndFlags) & _FlagsMask;
158  }
159 
160  // Sets the flags on the cache-with-flags value.
161  static VdfVector *_SetFlags(
162  VdfVector *cacheAndFlags, uintptr_t flags) {
163  return _CastToPointer(_CastToInteger(cacheAndFlags) | flags);
164  }
165 
166  // Unsets the flags on the cache-with-flags value.
167  static VdfVector *_UnsetFlags(
168  VdfVector *cacheAndFlags, uintptr_t flags) {
169  return _CastToPointer(_CastToInteger(cacheAndFlags) & ~flags);
170  }
171 
172  // Free all the data allocated by this object
173  VDF_API
174  void _Free();
175 
176  // The VdfVector, as well as two bits denoting ownership and cache
177  // occupation.
178  // Note, even though this is an atomic, VdfExecutorBufferData makes no
179  // thread-safety guarantees beyond concurrent read access to the data. The
180  // only reason this is an atomic is so that the flags can be stored along
181  // with the cache pointer, while still being able to modify the flags
182  // concurrently to reading the cache pointer (as if those were two separate
183  // member variables) without technically triggering undefined behavior.
184  std::atomic<VdfVector *> _cacheAndFlags;
185 
186  // Mask of the entries computed in _cacheAndFlags.
187  VdfMask _mask;
188 
189 };
190 
191 ////////////////////////////////////////////////////////////////////////////////
192 
193 VdfVector *
195 {
196  VdfVector *cacheAndFlags = _cacheAndFlags.load(std::memory_order_acquire);
197 
198  // If this buffer maintains ownership over a previously allocated vector,
199  // make it occupy the executor cache.
200  if (_GetCache(cacheAndFlags) && _GetFlags(cacheAndFlags) & _IsOwnedFlag) {
201  _cacheAndFlags.store(
202  _SetFlags(cacheAndFlags, _IsOccupiedFlag),
203  std::memory_order_release);
204  return _GetCache(cacheAndFlags);
205  }
206 
207  // If the buffer does not have ownership of the cache, or has not
208  // previously allocated a cache, allocate a new one. Take ownership
209  // of the new buffer.
210  VdfVector *newCache = spec.AllocateCache();
211  _cacheAndFlags.store(
212  _SetFlags(newCache, _IsOwnedFlag | _IsOccupiedFlag),
213  std::memory_order_release);
214 
215  // Return the newly allocated cache.
216  return newCache;
217 }
218 
219 VdfVector *
221  const VdfOutputSpec &spec,
222  const VdfMask::Bits &bits)
223 {
225  spec.ResizeCache(v, bits);
226  return v;
227 }
228 
229 VdfVector *
231 {
232  VdfVector *cacheAndFlags = _cacheAndFlags.load(std::memory_order_acquire);
233  VdfVector *rhsCacheAndFlags =
234  rhs->_cacheAndFlags.load(std::memory_order_acquire);
235 
236  _cacheAndFlags.store(rhsCacheAndFlags, std::memory_order_release);
237  rhs->_cacheAndFlags.store(cacheAndFlags, std::memory_order_release);
238 
239  return _GetCache(rhsCacheAndFlags);
240 }
241 
242 VdfVector *
244 {
245  VdfVector *cacheAndFlags = _cacheAndFlags.load(std::memory_order_acquire);
246  return (_GetFlags(cacheAndFlags) & _IsOccupiedFlag)
247  ? _GetCache(cacheAndFlags)
248  : nullptr;
249 }
250 
251 const VdfMask &
253 {
254  return _mask;
255 }
256 
257 void
259 {
260  // Untoggle the occupation flag of the executor cache without
261  // modifying the ownership flag.
262  VdfVector *cacheAndFlags = _cacheAndFlags.load(std::memory_order_acquire);
263  if (_GetFlags(cacheAndFlags) & _IsOccupiedFlag) {
264  _cacheAndFlags.store(
265  _UnsetFlags(cacheAndFlags, _IsOccupiedFlag),
266  std::memory_order_release);
267  }
268 
269  // Reset the executor cache mask to the mask provided.
270  if (_mask != mask) {
271  _mask = mask;
272  }
273 }
274 
275 void
277 {
279 }
280 
281 void
283 {
284  _mask = mask;
285 }
286 
287 bool
289 {
290  VdfVector *cacheAndFlags = _cacheAndFlags.load(std::memory_order_relaxed);
291  return (_GetFlags(cacheAndFlags) & _IsOwnedFlag) != 0;
292 }
293 
294 void
296 {
297  VdfVector *cacheAndFlags = _cacheAndFlags.load(std::memory_order_acquire);
298  _cacheAndFlags.store(
299  _UnsetFlags(cacheAndFlags, _IsOwnedFlag), std::memory_order_release);
300 }
301 
302 void
304 {
305  // The call to _Free won't actually deallocate the cache if it's not
306  // owned by this instance, so it's okay to "self-assign" in that case.
308 
309  _Free();
310  _cacheAndFlags.store(
311  _SetFlags(v, _IsOccupiedFlag), std::memory_order_release);
312 }
313 
314 void
316 {
317  // The call to _Free won't actually deallocate the cache if it's not
318  // owned by this instance, so it's okay to "self-assign" in that case.
320 
321  _Free();
322  _cacheAndFlags.store(
323  _SetFlags(v, _IsOccupiedFlag | _IsOwnedFlag),
324  std::memory_order_release);
325 }
326 
328 
329 #endif
GLbitfield flags
Definition: glcorearb.h:1596
void TakeOwnership(VdfVector *v)
VDF_API VdfVector * AllocateCache() const
Allocate a new VdfVector with this spec's type.
const GLdouble * v
Definition: glcorearb.h:837
uint128_t uintptr_t
Definition: format.h:479
#define PXR_NAMESPACE_OPEN_SCOPE
Definition: pxr.h:73
A VdfMask is placed on connections to specify the data flowing through them.
Definition: mask.h:36
#define VDF_API
Definition: api.h:25
VDF_API VdfMask ReleaseExecutorCache(VdfSMBLData *smblData)
Fast, compressed bit array which is capable of performing logical operations without first decompress...
#define TF_DEV_AXIOM(cond)
VdfVector * CreateExecutorCache(const VdfOutputSpec &spec)
VdfSMBLData holds per-output data that is meant to be consumed by the executor. This data is an optio...
Definition: smblData.h:30
GLint GLuint mask
Definition: glcorearb.h:124
void SetExecutorCacheMask(const VdfMask &mask)
This object is responsible for storing the executor buffer data, comprised of the executor cache vect...
VdfExecutorBufferData & operator=(const VdfExecutorBufferData &)=delete
const VdfMask & GetExecutorCacheMask() const
#define PXR_NAMESPACE_CLOSE_SCOPE
Definition: pxr.h:74
VDF_API void Reset()
VdfVector * SwapExecutorCache(VdfExecutorBufferData *rhs)
VdfVector * GetExecutorCache() const
VDF_API void Clone(VdfExecutorBufferData *dest) const
VDF_API void ResizeCache(VdfVector *vector, const VdfMask::Bits &bits) const
Resize an existing VdfVector to accomodate all the data set in the bits.
VDF_API ~VdfExecutorBufferData()
VDF_API void RetainExecutorCache(const VdfOutputSpec &spec, VdfSMBLData *smblData)