HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
smblData.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_SMBL_DATA_H
8 #define PXR_EXEC_VDF_SMBL_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"
17 #include "pxr/exec/vdf/traits.h"
18 #include "pxr/exec/vdf/types.h"
19 
21 
22 class VdfVector;
23 
24 ///////////////////////////////////////////////////////////////////////////////
25 ///
26 /// \brief VdfSMBLData holds per-output data that is meant to be consumed
27 /// by the executor. This data is an optional part of VdfExecutorData and it
28 /// is specific to sparse mung buffer locking.
29 ///
31 {
32 public:
33  /// Noncopyable.
34  ///
35  VdfSMBLData(const VdfSMBLData &) = delete;
36  VdfSMBLData &operator=(const VdfSMBLData &) = delete;
37 
38  /// Constructs an SMBL data object.
39  ///
41  _cache(NULL)
42  {}
43 
44  VDF_API
45  ~VdfSMBLData();
46 
47 
48  /// \name Memoized mask computations
49  ///
50  /// @{
51 
52  /// Invalidates the executor \p cacheMask given an \p invalidationMask.
53  /// Returns the \p cacheMask with the bits in the \p invalidationMask
54  /// removed.
55  /// This is a memoized computation.
56  ///
58  const VdfMask &cacheMask,
59  const VdfMask &invalidationMask);
60 
61  /// Extends the \p lockedCacheMask by appending the bits stored in the
62  /// executor \p cacheMask.
63  /// This is a memoized computation.
64  ///
66  VdfMask *lockedCacheMask,
67  const VdfMask &cacheMask) {
68  *lockedCacheMask = _cachedExtend(*lockedCacheMask, cacheMask);
69  }
70 
71  /// Make sure that all the bits in the keepMask are provided by the
72  /// cacheMask. Any data bits that are not provided by the cacheMask should
73  /// not be contained in the lockedCacheMask, so remove them from the
74  /// lockedCacheMask. This makes it so that nodes, which must provide data
75  /// to be kept at the output, do not become un-affective.
76  ///
77  inline void RemoveUncachedMask(
78  VdfMask *lockedCacheMask,
79  const VdfMask &cacheMask,
80  const VdfMask &keepMask);
81 
82  /// Computes the affectiveness of the corresponding output given the
83  /// accumulated \p lockedCacheMask and the scheduled \p affectsMask of the
84  /// output.
85  /// This is a memoized computation.
86  ///
88  const VdfMask &lockedCacheMask,
89  const VdfMask &affectsMask) {
90  return !_cachedAffective(lockedCacheMask, affectsMask);
91  }
92 
93  /// @}
94 
95 
96  /// \name Local Cache
97  ///
98  /// @{
99 
100  /// Locally retains the passed in \p cache with the given \p cacheMask.
101  /// This method returns a pointer to a (new) cache, which the client is now
102  /// free to use.
103  /// Consequently, this method passes the ownership of the \p cache pointer
104  /// to this object, while giving up the ownership of the returned vector.
105  /// This is to avoid a copy of the underlying data.
106  ///
107  inline VdfVector* Retain(
108  const VdfOutputSpec &spec,
109  VdfVector *cache,
110  const VdfMask &cacheMask);
111 
112  /// Releases the cache, which has been retained by this object, if any.
113  /// Note, that this method does NOT release ownership of any of its heap
114  /// allocated data! It merely demotes the retained cache to a free cache
115  /// for future use.
116  ///
117  void Release() {
118  if (!_cacheMask.IsEmpty()) {
119  _cacheMask = VdfMask();
120  }
121  }
122 
123  /// Clear any of the data this object is holding on to.
124  ///
125  VDF_API
126  void Clear();
127 
128  /// Returns a pointer to the locally retained cache, if any.
129  ///
130  VdfVector *GetCache() const {
131  return _cache;
132  }
133 
134  /// Returns a mask indicating data available in the locally retained cache.
135  ///
136  const VdfMask &GetCacheMask() const {
137  return _cacheMask;
138  }
139 
140  /// Returns \c true, if a cache has been retained locally, and \c false
141  /// if there is no such cache.
142  ///
143  bool HasCache() const {
144  return _cache && !_cacheMask.IsEmpty();
145  }
146 
147  /// @}
148 
149 private:
150  // This is a helper class used for memoizing expensive mask computations.
151  //
152  // For sparse mung buffer locking mask operations on a specific output are
153  // expected to always yield the same results for any but the first run of
154  // the executor. Memoization allows us to hold on to these results without
155  // having to worry about invalidation. Note, that we exploit the fact that
156  // masks are flyweighted, and hence very cheap to store, as well as
157  // equality compare.
158  template < typename R, typename OP >
159  class _MaskOpMemoizer
160  {
161  public:
162  _MaskOpMemoizer() :
163  // Initialize the default result to avoid correctness problems
164  _result(OP()(_opA, _opB))
165  {}
166 
168  operator()(const VdfMask &opA, const VdfMask &opB) {
169  // Cache miss?
170  if (_opA != opA || _opB != opB) {
171  _opA = opA;
172  _opB = opB;
173  _result = OP()(opA, opB);
174  }
175 
176  // Cache hit!
177  return _result;
178  }
179 
180  private:
181  // Operand A
182  VdfMask _opA;
183 
184  // Operand B
185  VdfMask _opB;
186 
187  // Cached result
188  R _result;
189 
190  };
191 
192  // Functor used for a memoized mask subtraction
193  struct _MaskSubtract {
194  VdfMask operator()(const VdfMask &lhs, const VdfMask &rhs) const {
195  return lhs - rhs;
196  }
197  };
198 
199  // Functor used for a memoized append of two masks
200  struct _MaskSetOrAppend {
201  VdfMask operator()(const VdfMask &lhs, const VdfMask &rhs) const {
202  VdfMask res(lhs);
203  res.SetOrAppend(rhs);
204  return res;
205  }
206  };
207 
208  // Functor used for computing the "Contains" method on a mask
209  struct _MaskContains {
210  bool operator()(const VdfMask &lhs, const VdfMask &rhs) const {
211  return lhs.Contains(rhs);
212  }
213  };
214 
215  // Memoized result of the invalid cache mask
216  _MaskOpMemoizer<VdfMask, _MaskSubtract> _cachedInvalidate;
217 
218  // Memoized result of the extended locked cache mask
219  _MaskOpMemoizer<VdfMask, _MaskSetOrAppend> _cachedExtend;
220 
221  // Memoized result of the affective-ness flag
222  _MaskOpMemoizer<bool, _MaskContains> _cachedAffective;
223 
224  // Memoized result of keepMask - cacheMask. This contains the bits
225  // that are required to be stored at the output.
226  _MaskOpMemoizer<VdfMask, _MaskSubtract> _cachedRequiredMask;
227 
228  // Memoized result of the locked cache mask with all the uncached,
229  // but required bits removed.
230  _MaskOpMemoizer<VdfMask, _MaskSubtract> _cachedRequiredLockedCache;
231 
232  // Locally retained cache and cache mask
233  VdfVector *_cache;
234  VdfMask _cacheMask;
235 
236 };
237 
238 
239 VdfMask
241  const VdfMask &cacheMask,
242  const VdfMask &invalidationMask)
243 {
244  return cacheMask.IsEmpty()
245  ? cacheMask
246  : _cachedInvalidate(cacheMask, invalidationMask);
247 }
248 
249 void
251  VdfMask *lockedCacheMask,
252  const VdfMask &cacheMask,
253  const VdfMask &keepMask)
254 {
255  // Determine which bits in the keep mask are not available in the
256  // local executor cache. These are the bits that we have to remove from
257  // the executor cache mask, if necessary.
258  const VdfMask &uncached =
259  cacheMask.IsEmpty()
260  ? keepMask
261  : _cachedRequiredMask(keepMask, cacheMask);
262 
263  // Remove the uncached bits, if any.
264  *lockedCacheMask = _cachedRequiredLockedCache(*lockedCacheMask, uncached);
265 }
266 
267 VdfVector*
269  const VdfOutputSpec &spec,
270  VdfVector *cache,
271  const VdfMask &cacheMask)
272 {
273  // The local cache is always a free cache. If a local cache has not
274  // been allocated, yet, allocate one here.
275  if (!_cache) {
276  _cache = spec.AllocateCache();
277  }
278 
279  // Store a pointer to the current cache, which is a always a free cache.
280  VdfVector *freeCache = _cache;
281 
282  // Swap the current cache with the passed in cache, to retain it.
283  _cache = cache;
284  _cacheMask = cacheMask;
285 
286  // Return the pointer to the free cache to be re-used by the client.
287  return freeCache;
288 }
289 
291 
292 #endif /* PXR_EXEC_VDF_SMBL_DATA_H */
VdfVector * GetCache() const
Definition: smblData.h:130
bool HasCache() const
Definition: smblData.h:143
bool ComputeAffectiveness(const VdfMask &lockedCacheMask, const VdfMask &affectsMask)
Definition: smblData.h:87
bool IsEmpty() const
Definition: mask.h:168
VDF_API VdfVector * AllocateCache() const
Allocate a new VdfVector with this spec's type.
VdfMask InvalidateCacheMask(const VdfMask &cacheMask, const VdfMask &invalidationMask)
Definition: smblData.h:240
VdfSMBLData & operator=(const VdfSMBLData &)=delete
#define PXR_NAMESPACE_OPEN_SCOPE
Definition: pxr.h:73
VDF_API void Clear()
A VdfMask is placed on connections to specify the data flowing through them.
Definition: mask.h:36
void Release()
Definition: smblData.h:117
#define VDF_API
Definition: api.h:25
VdfSMBLData holds per-output data that is meant to be consumed by the executor. This data is an optio...
Definition: smblData.h:30
VdfVector * Retain(const VdfOutputSpec &spec, VdfVector *cache, const VdfMask &cacheMask)
Definition: smblData.h:268
bool Contains(const VdfMask &mask) const
Definition: mask.h:186
void ExtendLockedCacheMask(VdfMask *lockedCacheMask, const VdfMask &cacheMask)
Definition: smblData.h:65
const VdfMask & GetCacheMask() const
Definition: smblData.h:136
#define PXR_NAMESPACE_CLOSE_SCOPE
Definition: pxr.h:74
VDF_API ~VdfSMBLData()
typename std::conditional_t< std::is_pointer_v< T >||Vdf_AndTypeIsSmall< T, std::is_arithmetic_v< T >>||Vdf_AndTypeIsSmall< T, std::is_enum_v< T >>, T, const T & > VdfByValueOrConstRef
Definition: traits.h:108
void RemoveUncachedMask(VdfMask *lockedCacheMask, const VdfMask &cacheMask, const VdfMask &keepMask)
Definition: smblData.h:250
VdfSMBLData()
Definition: smblData.h:40