Loading...
Searching...
No Matches
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
11
12#include "pxr/pxr.h"
13
14#include "pxr/exec/vdf/api.h"
15#include "pxr/exec/vdf/mask.h"
17
18#include <atomic>
19
20PXR_NAMESPACE_OPEN_SCOPE
21
22class VdfOutputSpec;
23class VdfVector;
24
32{
33public:
37 VdfExecutorBufferData &operator=(const VdfExecutorBufferData &) = delete;
38
41 VdfExecutorBufferData() : _cacheAndFlags() {}
42
45 VDF_API
47
50 VDF_API
51 void Reset();
52
55 VDF_API
56 void Clone(VdfExecutorBufferData *dest) const;
57
60 inline VdfVector *CreateExecutorCache(const VdfOutputSpec &spec);
61
66 const VdfOutputSpec &spec,
67 const VdfMask::Bits &bits);
68
72
75 inline VdfVector *GetExecutorCache() const;
76
79 inline const VdfMask &GetExecutorCacheMask() const;
80
83 inline void SetExecutorCacheMask(const VdfMask &mask);
84
88 inline void ResetExecutorCache(const VdfMask &mask);
89
92 inline void ResetExecutorCache();
93
97 VDF_API
98 void RetainExecutorCache(const VdfOutputSpec &spec, VdfSMBLData *smblData);
99
104 VDF_API
106
110 inline bool HasOwnership() const;
111
115 inline void YieldOwnership();
116
120 inline void YieldOwnership(VdfVector *v);
121
127 inline void TakeOwnership(VdfVector *v);
128
129private:
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
192
193VdfVector *
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
219VdfVector *
221 const VdfOutputSpec &spec,
222 const VdfMask::Bits &bits)
223{
225 spec.ResizeCache(v, bits);
226 return v;
227}
228
229VdfVector *
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
242VdfVector *
244{
245 VdfVector *cacheAndFlags = _cacheAndFlags.load(std::memory_order_acquire);
246 return (_GetFlags(cacheAndFlags) & _IsOccupiedFlag)
247 ? _GetCache(cacheAndFlags)
248 : nullptr;
249}
250
251const VdfMask &
253{
254 return _mask;
255}
256
257void
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
275void
277{
279}
280
281void
283{
284 _mask = mask;
285}
286
287bool
289{
290 VdfVector *cacheAndFlags = _cacheAndFlags.load(std::memory_order_relaxed);
291 return (_GetFlags(cacheAndFlags) & _IsOwnedFlag) != 0;
292}
293
294void
296{
297 VdfVector *cacheAndFlags = _cacheAndFlags.load(std::memory_order_acquire);
298 _cacheAndFlags.store(
299 _UnsetFlags(cacheAndFlags, _IsOwnedFlag), std::memory_order_release);
300}
301
302void
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
314void
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
327PXR_NAMESPACE_CLOSE_SCOPE
328
329#endif
Fast, compressed bit array which is capable of performing logical operations without first decompress...
This object is responsible for storing the executor buffer data, comprised of the executor cache vect...
VDF_API void Clone(VdfExecutorBufferData *dest) const
Clones this VdfExecutorBufferData instance to dest.
VdfVector * SwapExecutorCache(VdfExecutorBufferData *rhs)
Swaps the executor cache at this buffer, with that of another buffer.
VDF_API void RetainExecutorCache(const VdfOutputSpec &spec, VdfSMBLData *smblData)
Takes the existing executor cache and retains it within the existing VdfSMBLData object.
const VdfMask & GetExecutorCacheMask() const
Get the available mask.
bool HasOwnership() const
Returns true if the buffer owns the executor cache.
VDF_API ~VdfExecutorBufferData()
Destructor.
VdfExecutorBufferData()
Constructor.
void ResetExecutorCache()
Reset the executor cache without releasing any memory.
VdfExecutorBufferData(const VdfExecutorBufferData &)=delete
Noncopyable.
VdfVector * GetExecutorCache() const
Returns the executor cache stored at this buffer data instance.
void TakeOwnership(VdfVector *v)
Assumes ownership of the given vector.
VDF_API VdfMask ReleaseExecutorCache(VdfSMBLData *smblData)
Merges the executor cache previously retained in smblData into this cache and releases the SMBL data.
VdfVector * CreateExecutorCache(const VdfOutputSpec &spec)
Creates a new executor cache for this buffer.
void SetExecutorCacheMask(const VdfMask &mask)
Sets the available mask.
void YieldOwnership()
Yields ownership of the internal vector, i.e.
VDF_API void Reset()
Reset the instance to its original, newly constructed state.
A VdfMask is placed on connections to specify the data flowing through them.
Definition: mask.h:37
A VdfOuptutSpec describes an output connector.
Definition: outputSpec.h:40
VDF_API VdfVector * AllocateCache() const
Allocate a new VdfVector with this spec's type.
VDF_API void ResizeCache(VdfVector *vector, const VdfMask::Bits &bits) const
Resize an existing VdfVector to accomodate all the data set in the bits.
VdfSMBLData holds per-output data that is meant to be consumed by the executor.
Definition: smblData.h:31
This class is used to abstract away knowledge of the cache data used for each node.
Definition: vector.h:56
#define TF_DEV_AXIOM(cond)
The same as TF_AXIOM, but compiled only in dev builds.
Definition: diagnostic.h:205