HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
resolvedAttributeCache.h
Go to the documentation of this file.
1 //
2 // Copyright 2016 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_USD_IMAGING_USD_IMAGING_RESOLVED_ATTRIBUTE_CACHE_H
8 #define PXR_USD_IMAGING_USD_IMAGING_RESOLVED_ATTRIBUTE_CACHE_H
9 
10 /// \file
11 
12 #include "pxr/pxr.h"
14 #include "pxr/usd/usd/prim.h"
15 #include "pxr/usd/usd/primRange.h"
17 #include "pxr/usd/sdf/path.h"
18 
19 #include "pxr/base/tf/hash.h"
20 #include "pxr/base/work/utils.h"
21 
22 #include "pxr/base/tf/hash.h"
23 
24 #include <tbb/concurrent_unordered_map.h>
25 #include <functional>
26 
28 
29 /// A general caching mechanism for attributes that are nontrivial to resolve,
30 /// such as attributes inherited up or down the ancestor chain or attributes
31 /// with significant load-time processing involved.
32 ///
33 /// This class is thread safe following the basic guarantee that calling const
34 /// methods are thread safe, non-const methods are not.
35 ///
36 /// This cache is generalized based on a strategy object which dictates what
37 /// value type it will hold along with a "query" object, which can be as simple
38 /// as a UsdObject or in the case of Xform cache, we use something more fancy, a
39 /// UsdGeomXformable::XformQuery. This cache is thread safe and lock free. It is
40 /// not wait free, however waits are expected to be extremely short (a small
41 /// number of cycles).
42 ///
43 /// An optional implementation data (ImplData) object may be used for computing
44 /// the values to be cached, if necessary. This object is passed along to the
45 /// MakeQuery() method of the strategy object, making it available for use in
46 /// computations. If MakeQuery() is expected to modify the ImplData object in
47 /// any way, care must be taken to ensure that the modifications are
48 /// thread-safe. The fallback type for ImplData is bool, when it's not specified
49 /// by a cache.
50 ///
51 template<typename Strategy, typename ImplData=bool>
53 {
54  friend Strategy;
55  struct _Entry;
56  using _CacheMap = tbb::concurrent_unordered_map<UsdPrim, _Entry, TfHash>;
57 public:
58  typedef typename Strategy::value_type value_type;
59  typedef typename Strategy::query_type query_type;
60 
62 
63  /// Construct a new for the specified \p time.
65  const UsdTimeCode time,
66  ImplData *implData=nullptr,
67  const ValueOverridesMap valueOverrides=ValueOverridesMap())
68  : _time(time)
69  , _rootPath(SdfPath::AbsoluteRootPath())
70  , _cacheVersion(_GetInitialCacheVersion())
71  , _valueOverrides(valueOverrides)
72  , _implData(implData)
73  {
74  }
75 
76  /// Construct a new cache for UsdTimeCode::Default().
78  : _time(UsdTimeCode::Default())
79  , _rootPath(SdfPath::AbsoluteRootPath())
80  , _cacheVersion(1)
81  {
82  }
83 
85  {
86  WorkSwapDestroyAsync(_cache);
87  }
88 
89 
90  /// Compute the inherited value for the given \p prim, including the value
91  /// authored on the Prim itself, if present.
92  value_type GetValue(const UsdPrim& prim) const
93  {
95  if (!prim.GetPath().HasPrefix(_rootPath) && !prim.IsInPrototype()) {
96  TF_CODING_ERROR("Attempt to get value for: %s "
97  "which is not within the specified root: %s",
98  prim.GetPath().GetString().c_str(),
99  _rootPath.GetString().c_str());
100  return Strategy::MakeDefault();
101  }
102 
103  return *_GetValue(prim);
104  }
105 
106  /// Returns the underlying query object for the given prim. If the prim has
107  /// no cache entry, calling this method will trigger the entry to be
108  /// populated in an invalid state, but will return a valid query object.
109  query_type const*
110  GetQuery(const UsdPrim& prim) const {
111  return &_GetCacheEntryForPrim(prim)->query;
112  }
113 
114  /// Clears all pre-cached values.
115  void Clear() {
116  WorkSwapDestroyAsync(_cache);
117  _cacheVersion = _GetInitialCacheVersion();
118  }
119 
120  /// Use the new \p time when computing values and may clear any existing
121  /// values cached for the previous time. Setting \p time to the current time
122  /// is a no-op.
123  void SetTime(UsdTimeCode time) {
124  if (time == _time)
125  return;
126 
127  if (Strategy::ValueMightBeTimeVarying()) {
128  // Mark all cached entries as invalid, but leave the queries behind.
129  // We increment by 2 here and always keep the version an odd number,
130  // this enables the use of even versions as a per-entry spin lock.
131  _cacheVersion += 2;
132  }
133 
134  // Update to correct time.
135  _time = time;
136  }
137 
138  /// Get the current time from which this cache is reading values.
139  UsdTimeCode GetTime() const { return _time; }
140 
141  /// Set the root ancestor path at which to stop inheritance.
142  /// Note that values on the root are not inherited.
143  ///
144  /// In general, you shouldn't use this function; USD inherited attribute
145  /// resolution will traverse to the pseudo-root, and not doing that in the
146  /// cache can introduce subtle bugs. This exists mainly for the benefit of
147  /// the transform cache, since UsdImagingDelegate transform resolution
148  /// semantics are complicated and special-cased.
149  void SetRootPath(const SdfPath& rootPath) {
150  if (!rootPath.IsAbsolutePath()) {
151  TF_CODING_ERROR("Invalid root path: %s",
152  rootPath.GetString().c_str());
153  return;
154  }
155 
156  if (rootPath == _rootPath)
157  return;
158 
159  Clear();
160  _rootPath = rootPath;
161  }
162 
163  /// Return the root ancestor path at which to stop inheritance.
164  /// See notes on SetRootPath.
165  const SdfPath & GetRootPath() const { return _rootPath; }
166 
167  /// Helper function used to append, update or remove overrides from the
168  /// internal value overrides map. By doing the updates to the map in a
169  /// single pass, we can optimize the dirtying of the cache entries.
170  ///
171  /// \p valueOverrides contains the set of value overrides to be appended
172  /// or updated in the internal value overrides map.
173  /// \p overriesToRemove contains the list of prims for which overrides
174  /// must be removed.
175  /// \p dirtySubtreeRoots is populated with the list of paths to the roots
176  /// of the subtrees that must be recomputed.
177  void UpdateValueOverrides(const ValueOverridesMap &valueOverrides,
178  const std::vector<UsdPrim> &overridesToRemove,
179  std::vector<SdfPath> *dirtySubtreeRoots)
180  {
181  TRACE_FUNCTION();
182 
183  if (valueOverrides.empty() && overridesToRemove.empty())
184  return;
185 
186  ValueOverridesMap valueOverridesToProcess;
187  SdfPathVector processedOverridePaths;
188  TF_FOR_ALL(it, valueOverrides) {
189  const UsdPrim &prim = it->first;
190  const value_type &value = it->second;
191 
192  // If the existing value matches the incoming value, skip
193  // the update and dirtying.
194  if (*_GetValue(prim) == value)
195  continue;
196 
197  valueOverridesToProcess[prim] = value;
198  }
199 
200  TF_FOR_ALL(it, valueOverridesToProcess) {
201  const UsdPrim &prim = it->first;
202  const value_type &value = it->second;
203 
204  // XXX: performance
205  // We could probably make this faster by using a hash table of
206  // prefixes. This hasn't showed up in traces much though as it's not
207  // common to update value overrides for more than one path at a
208  // time.
209  bool isDescendantOfProcessedOverride = false;
210  for (const SdfPath &processedPath : processedOverridePaths) {
211  if (prim.GetPath().HasPrefix(processedPath)) {
212  isDescendantOfProcessedOverride = true;
213  break;
214  }
215  }
216 
217  // Invalidate cache entries if the prim is not a descendant of a
218  // path that has already been processed.
219  if (!isDescendantOfProcessedOverride) {
220  for (UsdPrim descendant: UsdPrimRange(prim)) {
221  if (_Entry* entry = _GetCacheEntryForPrim(descendant)) {
222  entry->version = _GetInvalidVersion();
223  }
224  }
225  processedOverridePaths.push_back(prim.GetPath());
226  dirtySubtreeRoots->push_back(prim.GetPath());
227  }
228 
229  // Update overrides in the internal value overrides map.
230  _valueOverrides[prim] = value;
231  }
232 
233  for (const UsdPrim &prim : overridesToRemove) {
234 
235  // Erase the entry from the map of overrides.
236  size_t numErased = _valueOverrides.erase(prim);
237 
238  // If the override doesn't exist, then there's nothing to do.
239  if (numErased == 0) {
240  continue;
241  }
242 
243  bool isDescendantOfProcessedOverride = false;
244  for (const SdfPath &processedPath : processedOverridePaths) {
245  if (prim.GetPath().HasPrefix(processedPath)) {
246  isDescendantOfProcessedOverride = true;
247  break;
248  }
249  }
250 
251  // Invalidate cache entries if the prim is not a descendant of a
252  // path that has already been processed.
253  if (!isDescendantOfProcessedOverride) {
254  for (UsdPrim descendant: UsdPrimRange(prim)) {
255  if (_Entry* entry = _GetCacheEntryForPrim(descendant)) {
256  entry->version = _GetInvalidVersion();
257  }
258  }
259  dirtySubtreeRoots->push_back(prim.GetPath());
260  processedOverridePaths.push_back(prim.GetPath());
261  }
262  }
263  }
264 
265 private:
266  // Cached value entries. Note that because query objects may be caching
267  // non-time varying data, entries may exist in the cache with invalid
268  // values. The version is used to determine validity.
269  struct _Entry {
270  _Entry()
271  : value(Strategy::MakeDefault())
272  , version(_GetInitialEntryVersion())
273  { }
274 
275  _Entry(const query_type & query_,
276  const value_type& value_,
277  unsigned version_)
278  : query(query_)
279  , value(value_)
280  , version(version_)
281  { }
282 
283  _Entry(const _Entry &other)
284  : query(other.query)
285  , value(other.value)
286  {
287  version.store(other.version.load());
288  }
289 
290  _Entry(_Entry &&other)
291  : query(std::move(other.query))
292  , value(std::move(other.value))
293  {
294  version.store(other.version.load());
295  }
296 
299  std::atomic<unsigned> version;
300  };
301 
302  // Returns the version number for a valid cache entry
303  unsigned _GetValidVersion() const { return _cacheVersion + 1; }
304 
305  // Returns the version number for an invalid cache entry
306  unsigned _GetInvalidVersion() const { return _cacheVersion - 1; }
307 
308  // Initial version numbers
309  static unsigned _GetInitialCacheVersion() { return 1; }
310  static unsigned _GetInitialEntryVersion() {
311  return _GetInitialCacheVersion()-1;
312  }
313 
314  // Traverse the hierarchy (order is strategy dependent) and compute the
315  // inherited value.
316  value_type const* _GetValue(const UsdPrim& prim) const;
317 
318  // Helper function to get or create a new entry for a prim in the cache.
319  _Entry* _GetCacheEntryForPrim(const UsdPrim &prim) const;
320 
321  // Sets the value of the given cache entry. If multiple threads attempt to
322  // set the same entry, the first in wins and other threads spin until the
323  // new value is set.
324  void _SetCacheEntryForPrim(const UsdPrim &prim,
325  value_type const& value,
326  _Entry* entry) const;
327 
328  // Mutable is required here to allow const methods to update the cache when
329  // it is thread safe, however not all mutations of this map are thread safe.
330  // See underlying map documentation for details.
331  mutable _CacheMap _cache;
332 
333  // The time at which this stack is querying and caching attribute values.
334  UsdTimeCode _time;
335  SdfPath _rootPath;
336 
337  // A serial number indicating the valid state of entries in the cache. When
338  // an entry has an equal or greater value, the entry is valid.
339  std::atomic<unsigned> _cacheVersion;
340 
341  // Value overrides for a set of descendents.
342  ValueOverridesMap _valueOverrides;
343 
344  // Supplemental cache if used by this inherited cache.
345  ImplData *_implData;
346 };
347 
348 template<typename Strategy, typename ImplData>
349 void
351  const UsdPrim &prim,
352  value_type const& value,
353  _Entry* entry) const
354 {
355  // Note: _cacheVersion is not allowed to change during cache access.
356  unsigned v = entry->version;
357  if (v < _cacheVersion
358  && entry->version.compare_exchange_strong(v,_cacheVersion.load()))
359  {
360  entry->value = value;
361  entry->version = _GetValidVersion();
362  } else {
363  while (entry->version != _GetValidVersion()) {
364  // Future work: A suggestion is that rather than literally spinning
365  // here, we should use the pause instruction, which sleeps for one
366  // cycle while allowing hyper threads to continue. Folly has a nice
367  // implementation of this packaged up as "sleeper", which we could
368  // also implement in Work and Arch.
369  }
370  }
371 }
372 
373 template<typename Strategy, typename ImplData>
376  const UsdPrim &prim) const
377 {
378  typename _CacheMap::iterator it = _cache.find(prim);
379  if (it != _cache.end()) {
380  return &it->second;
381  }
382 
383  _Entry e;
384  e.query = Strategy::MakeQuery(prim, _implData);
385  e.value = Strategy::MakeDefault();
386  e.version = _GetInvalidVersion();
387  return &(_cache.insert(
388  typename _CacheMap::value_type(prim, e)).first->second);
389 }
390 
391 template<typename Strategy, typename ImplData>
394  const UsdPrim& prim) const
395 {
396  static value_type const default_ = Strategy::MakeDefault();
397 
398  // Base case.
399  if (!prim || prim.IsPrototype() || prim.GetPath() == _rootPath)
400  return &default_;
401 
402  _Entry* entry = _GetCacheEntryForPrim(prim);
403  if (entry->version == _GetValidVersion()) {
404  // Cache hit
405  return &entry->value;
406  }
407 
408  // Future work: Suggestion is that when multiple threads are computing the
409  // same value, we could block all but one thread here, possibly rescheduling
410  // blocked threads as continuations, rather than allowing all threads to
411  // continue to race until a cache hit is encountered.
412 
413  // Future work: A suggestion is that we make this iterative instead of
414  // recursive.
415  typename ValueOverridesMap::const_iterator it =
416  _valueOverrides.find(prim);
417  if (it != _valueOverrides.end()) {
418  _SetCacheEntryForPrim(prim, it->second, entry);
419  } else {
420  _SetCacheEntryForPrim(prim,
421  Strategy::Compute(this, prim, &entry->query),
422  entry);
423  }
424  return &entry->value;
425 }
426 
428 
429 // -------------------------------------------------------------------------- //
430 // Xform Cache
431 // -------------------------------------------------------------------------- //
432 
434 #include "pxr/base/gf/matrix4d.h"
435 
437 
440 
444 
445  static
446  bool ValueMightBeTimeVarying() { return true; }
447  static
449 
450  static
451  query_type MakeQuery(UsdPrim const& prim, bool *) {
452  if (const UsdGeomXformable xf = UsdGeomXformable(prim)) {
453  return query_type(xf);
454  }
455  return query_type();
456  }
457 
458  static
459  value_type
460  Compute(UsdImaging_XformCache const* owner,
461  UsdPrim const& prim,
462  query_type const* query)
463  {
464  value_type xform = MakeDefault();
465  // No need to check query validity here because XformQuery doesn't
466  // support it.
467  query->GetLocalTransformation(&xform, owner->GetTime());
468 
469  return !query->GetResetXformStack()
470  ? (xform * (*owner->_GetValue(prim.GetParent())))
471  : xform;
472  }
473 
474  // Compute the full transform, this is not part of the interface required by
475  // the cache.
476  static
477  value_type
478  ComputeTransform(UsdPrim const& prim,
479  SdfPath const& rootPath,
480  UsdTimeCode time,
482  {
483  bool reset = false;
484  GfMatrix4d ctm(1.0);
485  GfMatrix4d localXf(1.0);
486  UsdPrim p = prim;
487  while (p && p.GetPath() != rootPath) {
488  const auto &overIt = ctmOverrides.find(p.GetPath());
489  // If there's a ctm override, use it and break out of the loop.
490  if (overIt != ctmOverrides.end()) {
491  ctm *= overIt->second;
492  break;
493  } else if (UsdGeomXformable xf = UsdGeomXformable(p)) {
494  if (xf.GetLocalTransformation(&localXf, &reset, time))
495  ctm *= localXf;
496  if (reset)
497  break;
498  }
499  p = p.GetParent();
500  }
501  return ctm;
502  }
503 };
504 
506 
507 // -------------------------------------------------------------------------- //
508 // Visibility Cache
509 // -------------------------------------------------------------------------- //
510 
512 #include "pxr/base/tf/token.h"
514 
516 
518 using UsdImaging_VisCache =
520 
521 /// Strategy used to cache inherited 'visibility' values, implementing pruning
522 /// visibility semantics.
523 ///
525  typedef TfToken value_type; // invisible, inherited
527 
528  static
529  bool ValueMightBeTimeVarying() { return true; }
530 
531  static
532  value_type MakeDefault() { return UsdGeomTokens->inherited; }
533 
534  static
535  query_type MakeQuery(UsdPrim const& prim, bool *)
536  {
537  if (const UsdGeomImageable xf = UsdGeomImageable(prim)) {
538  return query_type(xf.GetVisibilityAttr());
539  }
540  return query_type();
541  }
542 
543  static
544  value_type
545  Compute(UsdImaging_VisCache const* owner,
546  UsdPrim const& prim,
547  query_type const* query)
548  {
549  value_type v = *owner->_GetValue(prim.GetParent());
550 
551  // If prim inherits 'invisible', then it's invisible, due to pruning
552  // visibility.
553  if (v == UsdGeomTokens->invisible) {
554  return v;
555  }
556 
557  // Otherwise, prim's value, if it has one, determines its visibility.
558  if (*query) {
559  query->Get(&v, owner->GetTime());
560  }
561  return v;
562  }
563 
564  static
565  value_type
567  {
568  return UsdGeomImageable(prim).ComputeVisibility(time);
569  }
570 };
571 
572 // -------------------------------------------------------------------------- //
573 // Purpose Cache
574 // -------------------------------------------------------------------------- //
575 
579 
581  // For proper inheritance, we need to return the PurposeInfo struct which
582  // stores whether child prims can inherit the parent's computed purpose
583  // when they don't have an authored purpose of their own.
584  typedef UsdGeomImageable::PurposeInfo value_type; // purpose, inherited
586 
587  static
589  // Return the fallback default instead of an empty purpose info.
590  return value_type(UsdGeomTokens->default_, false);
591  }
592 
593  static
594  query_type MakeQuery(UsdPrim const& prim, bool *) {
595  if (const UsdGeomImageable im = UsdGeomImageable(prim)) {
596  return query_type(im.GetPurposeAttr());
597  }
598  return query_type();
599  }
600 
601  static
602  value_type
603  Compute(UsdImaging_PurposeCache const* owner,
604  UsdPrim const& prim,
605  query_type const* query)
606  {
607  // Fallback to parent if the prim isn't imageable or doesn't have a
608  // purpose attribute. Note that this returns the default purpose if
609  // there's no parent prim.
610  if (!*query) {
611  return *(owner->_GetValue(prim.GetParent()));
612  }
613 
614  // If the prim has an authored purpose value, we get and use that.
615  if (query->HasAuthoredValue()) {
616  value_type info;
617  query->Get(&info.purpose);
618  info.isInheritable = true;
619  return info;
620  }
621 
622  // Otherwise we inherit parent's purpose value, but only if the parent's
623  // purpose is inheritable. An inherited purpose is itself inheritable
624  // by child prims..
625  const value_type *v = owner->_GetValue(prim.GetParent());
626  if (v->isInheritable) {
627  return *v;
628  }
629 
630  // Otherwise, get the fallback value. The fallback purpose will not
631  // be inherited by descendants.
632  value_type info;
633  query->Get(&info.purpose);
634  return info;
635  }
636 
637  static
638  value_type
640  {
641  return UsdGeomImageable(prim).ComputePurposeInfo();
642  }
643 };
644 
646 
647 // -------------------------------------------------------------------------- //
648 // Hydra MaterialBinding Cache
649 // -------------------------------------------------------------------------- //
650 
653 
655 
657  /// Constructor takes the purpose for which material bindings are to be
658  /// evaluated.
660  _materialPurpose(materialPurpose)
661  { }
662 
663  /// Destructor invokes ClearCaches(), which does the cache deletion in
664  /// parallel.
666  ClearCaches();
667  }
668 
669  /// Returns the material purpose for which bindings must be computed.
670  const TfToken &GetMaterialPurpose() const {
671  return _materialPurpose;
672  }
673 
674  /// Returns the BindingsCache object to be used when computing resolved
675  /// material bindings.
677  { return _bindingsCache; }
678 
679  /// Returns the BindingsCache object to be used when computing resolved
680  /// material bindings.
682  { return _collQueryCache; }
683 
684  /// Clears all of the held caches.
685  void ClearCaches();
686 
687 private:
688  const TfToken _materialPurpose;
691 };
692 
697 
698 struct UsdImaging_MaterialStrategy {
699  // inherited path to bound target
700  // depending on the load state, override, etc bound target path might not be
701  // queried as a UsdShadeMaterial on the stage.
702 
703  // inherited path to bound target
704  typedef SdfPath value_type;
705  // Hold the computed path of the bound material or target path of the
706  // winning material binding relationship
707  typedef SdfPath query_type;
708 
710 
711  static
712  bool ValueMightBeTimeVarying() { return false; }
713  static
715 
716  static
718  UsdPrim const& prim,
719  ImplData *implData)
720  {
721  UsdRelationship bindingRel;
722  UsdShadeMaterial materialPrim =
724  &implData->GetBindingsCache(),
725  &implData->GetCollectionQueryCache(),
726  implData->GetMaterialPurpose(),
727  &bindingRel,
728  true /*supportLegacyBindings*/);
729 
730  if (materialPrim) {
731  return materialPrim.GetPath();
732  }
733 
734  const SdfPath targetPath =
736  bindingRel);
737  return targetPath;
738  }
739 
740  static
741  value_type
742  Compute(UsdImaging_MaterialBindingCache const* owner,
743  UsdPrim const& prim,
744  query_type const* query)
745  {
746  TF_DEBUG(USDIMAGING_SHADERS).Msg("Looking for \"preview\" material "
747  "binding for %s\n", prim.GetPath().GetText());
748 
749  // query already contains the resolved material binding for the prim.
750  // Hence, we don't need to inherit the binding from the parent here.
751  // Futhermore, it may be wrong to inherit the binding from the parent,
752  // because in the new scheme, a child of a bound prim can be unbound.
753  //
754  // Note that query could be an empty SdfPath, which is the default
755  // value.
756  return *query;
757  }
758 
759  static
760  value_type
761  ComputeMaterialPath(UsdPrim const& prim, ImplData *implData) {
762  // We don't need to walk up the namespace here since
763  // ComputeBoundMaterial does it for us.
764  UsdRelationship bindingRel;
766  &implData->GetBindingsCache(),
767  &implData->GetCollectionQueryCache(),
768  implData->GetMaterialPurpose(),
769  &bindingRel);
770 
771  const SdfPath targetPath =
773  bindingRel);
774  if (!targetPath.IsEmpty()) {
775  return targetPath;
776  }
777  return value_type();
778  }
779 };
780 
782 
783 // -------------------------------------------------------------------------- //
784 // ModelDrawMode Cache
785 // -------------------------------------------------------------------------- //
786 
788 
790 
794 
796 {
797  typedef TfToken value_type; // origin, bounds, cards, default, inherited
799 
800  static
801  bool ValueMightBeTimeVarying() { return false; }
802  static
803  value_type MakeDefault() { return UsdGeomTokens->default_; }
804 
805  static
806  query_type MakeQuery(UsdPrim const& prim, bool *) {
807  if (const UsdGeomModelAPI modelApi = UsdGeomModelAPI(prim)) {
808  return query_type(modelApi.GetModelDrawModeAttr());
809  }
810  return query_type();
811  }
812 
813  static
814  value_type
815  Compute(UsdImaging_DrawModeCache const* owner,
816  UsdPrim const& prim,
817  query_type const* query)
818  {
819  // No attribute defined means inherited, means refer to the parent.
820  // Any defined attribute overrides parent opinion.
821  // If the drawMode is inherited all the way to the root of the scene,
822  // that means "default".
823  value_type v = UsdGeomTokens->inherited;
824  if (*query) {
825  query->Get(&v);
826  }
827  if (v != UsdGeomTokens->inherited) {
828  return v;
829  }
830  v = *owner->_GetValue(prim.GetParent());
831  if (v == UsdGeomTokens->inherited) {
832  return UsdGeomTokens->default_;
833  }
834  return v;
835  }
836 
837  static
838  value_type
840  {
841  return UsdGeomModelAPI(prim).ComputeModelDrawMode();
842  }
843 };
844 
846 
847 // -------------------------------------------------------------------------- //
848 // UsdGeomPointInstancer indices cache
849 // -------------------------------------------------------------------------- //
850 
852 
854 
858 
860 {
861  // map from protoIndex -> instanceIndices.
863  // We don't use query_type, but can't set it to void.
864  typedef int query_type;
865 
866  // XXX: Most indices values will be static, but since they *can*
867  // be animated, we need to return true here to get invalidation on
868  // time-change. It would be nice to add a per-entry time-varying bit
869  // to the resolved cache, instead of having the global per-attribute
870  // bit.
871  //
872  // In this particular case, instance indices are only recomputed when
873  // we see "DirtyInstanceIndex" in UpdateForTime, so though we'll be
874  // clearing cache entries out of the resolved cache on time-change,
875  // we won't actually call out to the attribute cache on static indices.
876  static
877  bool ValueMightBeTimeVarying() { return true; }
878  static
880 
881  static
882  query_type MakeQuery(UsdPrim const& prim, bool *) {
883  return 0;
884  }
885 
886  static
887  value_type
888  Compute(UsdImaging_PointInstancerIndicesCache const* owner,
889  UsdPrim const& prim,
890  query_type const* query)
891  {
892  return ComputePerPrototypeIndices(prim, owner->GetTime());
893  }
894 
895  static
896  value_type
898  {
899  value_type v;
900 
902  VtIntArray protoIndices;
903  if (!pi.GetProtoIndicesAttr().Get(&protoIndices, time)) {
904  TF_WARN("Failed to read point instancer protoIndices");
905  return v;
906  }
907 
908  std::vector<bool> mask = pi.ComputeMaskAtTime(time);
909 
910  for (size_t instanceId = 0; instanceId < protoIndices.size(); ++instanceId) {
911  size_t protoIndex = protoIndices[instanceId];
912 
913  if (protoIndex >= v.size()) {
914  v.resize(protoIndex + 1);
915  }
916 
917  if (mask.size() == 0 || mask[instanceId]) {
918  v[protoIndex].push_back(instanceId);
919  }
920  }
921 
922  return v;
923  }
924 };
925 
927 
928 // -------------------------------------------------------------------------- //
929 // CoordSysBinding Cache
930 // -------------------------------------------------------------------------- //
931 
933 #include "pxr/imaging/hd/coordSys.h"
934 
936 
938 
941 
943 {
944  typedef std::vector<UsdShadeCoordSysAPI::Binding> UsdBindingVec;
945  typedef std::shared_ptr<UsdBindingVec> UsdBindingVecPtr;
946  typedef std::shared_ptr<SdfPathVector> IdVecPtr;
947 
948  struct value_type {
951  };
952  typedef int query_type;
953 
954  static
955  bool ValueMightBeTimeVarying() { return false; }
956 
957  static
959  return value_type();
960  }
961 
962  static
963  query_type MakeQuery(UsdPrim const& prim, bool *) {
964  return 0;
965  }
966 
967  static
968  value_type
969  Compute(UsdImaging_CoordSysBindingCache const* owner,
970  UsdPrim const& prim,
971  query_type const* query)
972  {
973  value_type v;
974 
975  // Pull inherited bindings first.
976  if (UsdPrim parentPrim = prim.GetParent()) {
977  v = *owner->_GetValue(parentPrim);
978  }
979 
980  auto _IterateLocalBindings = [&prim](const UsdBindingVec &localBindings,
981  SdfPathVector &hdIds, UsdBindingVec &usdBindings) {
982  for (const UsdShadeCoordSysAPI::Binding &binding : localBindings) {
983  if (!prim.GetStage()->GetPrimAtPath(
984  binding.coordSysPrimPath).IsValid()) {
985  // The target xform prim does not exist, so ignore this
986  // coord sys binding.
987  TF_WARN("UsdImaging: Ignore coordinate system binding to "
988  "non-existent prim <%s>\n",
989  binding.coordSysPrimPath.GetText());
990  continue;
991  }
992  bool found = false;
993  for (size_t id = 0, n = hdIds.size(); id < n; ++id) {
994  if (usdBindings[id].name == binding.name) {
995  // Found an override -- replace this binding.
996  usdBindings[id] = binding;
997  hdIds[id] = binding.bindingRelPath;
998  found = true;
999  break;
1000  }
1001  }
1002  if (!found) {
1003  // New binding, so append.
1004  usdBindings.push_back(binding);
1005  hdIds.push_back(binding.bindingRelPath);
1006  }
1007  }
1008  };
1009 
1010  // XXX: Make sure to update the following code when
1011  // UsdShadeCoordSysAPI's old non-applied mode is completely removed.
1012  UsdShadeCoordSysAPI coordSysAPI = UsdShadeCoordSysAPI(prim,
1013  TfToken("noop"));
1014  bool hasLocalBindings = coordSysAPI.HasLocalBindings();
1015  UsdBindingVec localBindings = coordSysAPI.GetLocalBindings();
1016 
1017  //Merge any local bindings.
1018  if (hasLocalBindings && !localBindings.empty()) {
1019  SdfPathVector hdIds;
1020  UsdBindingVec usdBindings;
1021  if (v.idVecPtr) {
1022  hdIds = *v.idVecPtr;
1023  }
1024  if (v.usdBindingVecPtr) {
1025  usdBindings = *v.usdBindingVecPtr;
1026  }
1027  _IterateLocalBindings(localBindings, hdIds, usdBindings);
1028  v.idVecPtr.reset(new SdfPathVector(std::move(hdIds)));
1029  v.usdBindingVecPtr.reset(new UsdBindingVec(std::move(usdBindings)));
1030  }
1031 
1032  return v;
1033  }
1034 };
1035 
1037 
1038 // -------------------------------------------------------------------------- //
1039 // Nonlinear sample count Primvar Cache
1040 // -------------------------------------------------------------------------- //
1041 
1042 #include "pxr/usd/usdGeom/motionAPI.h"
1043 
1045 
1050 
1052 {
1053  typedef int value_type;
1055 
1056  // Used to indicate that no (valid) opinion exists
1057  // for nonlinear sample count.
1058  static constexpr value_type invalidValue = -1;
1059 
1060  static
1061  bool ValueMightBeTimeVarying() { return true; }
1062 
1063  static
1065  return invalidValue;
1066  }
1067 
1068  static
1069  query_type MakeQuery(UsdPrim const& prim, bool *) {
1070  if (const UsdGeomMotionAPI motionAPI = UsdGeomMotionAPI(prim)) {
1071  return query_type(motionAPI.GetNonlinearSampleCountAttr());
1072  }
1073  return query_type();
1074  }
1075 
1076  static
1077  value_type
1078  Compute(UsdImaging_NonlinearSampleCountCache const* owner,
1079  UsdPrim const& prim,
1080  query_type const* query)
1081  {
1082  if (query->HasAuthoredValue()) {
1083  int value;
1084  if (query->Get(&value, owner->GetTime())) {
1085  return value;
1086  }
1087  }
1088 
1089  return *owner->_GetValue(prim.GetParent());
1090  }
1091 
1092  static
1093  value_type
1095  {
1096  return UsdGeomMotionAPI(prim).ComputeNonlinearSampleCount(time);
1097  }
1098 };
1099 
1101 
1102 // -------------------------------------------------------------------------- //
1103 // Blur scale Primvar Cache
1104 // -------------------------------------------------------------------------- //
1105 
1106 #include "pxr/usd/usdGeom/motionAPI.h"
1107 
1109 
1113 
1115 {
1116  struct value_type {
1117  float value;
1119  };
1120 
1122 
1123  // Used to indicate that no (valid) opinion exists
1124  // for blur scale.
1125  static const value_type invalidValue;
1126 
1127  static
1128  bool ValueMightBeTimeVarying() { return true; }
1129 
1130  static
1132  return invalidValue;
1133  }
1134 
1135  static
1136  query_type MakeQuery(UsdPrim const& prim, bool *) {
1137  if (const UsdGeomMotionAPI motionAPI = UsdGeomMotionAPI(prim)) {
1138  return query_type(motionAPI.GetMotionBlurScaleAttr());
1139  }
1140  return query_type();
1141  }
1142 
1143  static
1144  value_type
1145  Compute(UsdImaging_BlurScaleCache const* owner,
1146  UsdPrim const& prim,
1147  query_type const* query)
1148  {
1149  if (query->HasAuthoredValue()) {
1150  float value;
1151  if (query->Get(&value, owner->GetTime())) {
1152  return { value, true };
1153  }
1154  }
1155 
1156  return *owner->_GetValue(prim.GetParent());
1157  }
1158 
1159  static
1160  value_type
1162  {
1163  return { UsdGeomMotionAPI(prim).ComputeMotionBlurScale(time), true };
1164  }
1165 };
1166 
1168 
1169 // -------------------------------------------------------------------------- //
1170 // Inherited Primvar Cache
1171 // -------------------------------------------------------------------------- //
1172 
1174 
1176 
1180 
1182 {
1183  struct PrimvarRecord {
1184  std::vector<UsdGeomPrimvar> primvars;
1185  bool variable;
1186  };
1187  typedef std::shared_ptr<PrimvarRecord> value_type;
1189 
1190  // While primvar data might be time-varying, the set of primvars applying
1191  // to a prim will not.
1192  static
1193  bool ValueMightBeTimeVarying() { return false; }
1194 
1195  static
1197  return value_type();
1198  }
1199 
1200  static
1201  query_type MakeQuery(UsdPrim const& prim, bool *) {
1202  return query_type(UsdGeomPrimvarsAPI(prim));
1203  }
1204 
1205  static
1206  value_type Compute(UsdImaging_InheritedPrimvarCache const* owner,
1207  UsdPrim const& prim,
1208  query_type const* query)
1209  {
1210  value_type v;
1211  if (*query) {
1212  // Pull inherited bindings first.
1213  if (UsdPrim parentPrim = prim.GetParent()) {
1214  v = *owner->_GetValue(parentPrim);
1215  }
1216  // Merge any local bindings.
1217  std::vector<UsdGeomPrimvar> primvars =
1219  v ? v->primvars : std::vector<UsdGeomPrimvar>());
1220  if (!primvars.empty()) {
1221  v = std::make_shared<PrimvarRecord>();
1222  v->primvars = std::move(primvars);
1223  v->variable = false;
1224  for (UsdGeomPrimvar const& pv : v->primvars) {
1225  if (pv.ValueMightBeTimeVarying()) {
1226  v->variable = true;
1227  break;
1228  }
1229  }
1230  }
1231  }
1232  return v;
1233  }
1234 };
1235 
1237 
1238 #endif
USDSHADE_API std::vector< Binding > GetLocalBindings() const
SDF_API const char * GetText() const
GLenum query
Definition: glad.h:2772
UsdTimeCode GetTime() const
Get the current time from which this cache is reading values.
USDSHADE_API bool HasLocalBindings() const
bool Get(T *value, UsdTimeCode time=UsdTimeCode::Default()) const
static value_type Compute(UsdImaging_InheritedPrimvarCache const *owner, UsdPrim const &prim, query_type const *query)
USDGEOM_API std::vector< UsdGeomPrimvar > FindIncrementallyInheritablePrimvars(const std::vector< UsdGeomPrimvar > &inheritedFromAncestors) const
UsdImaging_ResolvedAttributeCache< UsdImaging_PurposeStrategy > UsdImaging_PurposeCache
static value_type ComputeDrawMode(UsdPrim const &prim)
const TfToken & GetMaterialPurpose() const
Returns the material purpose for which bindings must be computed.
bool Get(T *value, UsdTimeCode time=UsdTimeCode::Default()) const
Definition: attribute.h:452
UsdImaging_ResolvedAttributeCache< UsdImaging_MaterialStrategy, UsdImaging_MaterialBindingImplData > UsdImaging_MaterialBindingCache
void SetRootPath(const SdfPath &rootPath)
GT_API const UT_StringHolder time
USDGEOM_API bool ValueMightBeTimeVarying() const
const GLdouble * v
Definition: glcorearb.h:837
iterator end()
Definition: hashmap.h:301
GLsizei const GLfloat * value
Definition: glcorearb.h:824
static USDSHADE_API const SdfPath GetResolvedTargetPathFromBindingRel(const UsdRelationship &bindingRel)
returns the path of the resolved target identified by bindingRel.
static value_type Compute(UsdImaging_PurposeCache const *owner, UsdPrim const &prim, query_type const *query)
#define TF_CODING_ERROR
static value_type ComputeBlurScale(UsdPrim const &prim, UsdTimeCode time)
void Clear()
Clears all pre-cached values.
bool IsEmpty() const noexcept
Returns true if this is the empty path (SdfPath::EmptyPath()).
Definition: path.h:398
void UpdateValueOverrides(const ValueOverridesMap &valueOverrides, const std::vector< UsdPrim > &overridesToRemove, std::vector< SdfPath > *dirtySubtreeRoots)
static value_type Compute(UsdImaging_BlurScaleCache const *owner, UsdPrim const &prim, query_type const *query)
static value_type ComputeTransform(UsdPrim const &prim, SdfPath const &rootPath, UsdTimeCode time, const TfHashMap< SdfPath, GfMatrix4d, SdfPath::Hash > &ctmOverrides)
size_type erase(const key_type &key)
Definition: hashmap.h:304
USDGEOM_API int ComputeNonlinearSampleCount(UsdTimeCode time=UsdTimeCode::Default()) const
static value_type MakeDefault()
static query_type MakeQuery(UsdPrim const &prim, bool *)
USDGEOM_API TfToken ComputeModelDrawMode(const TfToken &parentDrawMode=TfToken()) const
void ClearCaches()
Clears all of the held caches.
std::shared_ptr< UsdBindingVec > UsdBindingVecPtr
uint64 value_type
Definition: GA_PrimCompat.h:29
static query_type MakeQuery(UsdPrim const &prim, bool *)
static value_type ComputePurposeInfo(UsdPrim const &prim)
static value_type ComputeNonlinearSampleCount(UsdPrim const &prim, UsdTimeCode time)
UsdImaging_ResolvedAttributeCache()
Construct a new cache for UsdTimeCode::Default().
TfHashMap< UsdPrim, value_type, TfHash > ValueOverridesMap
bool GetResetXformStack() const
Returns whether the xformable resets its parent's transformation.
Definition: xformable.h:387
GLdouble n
Definition: glcorearb.h:2008
Definition: token.h:70
USDGEOM_API float ComputeMotionBlurScale(UsdTimeCode time=UsdTimeCode::Default()) const
GLboolean reset
Definition: glad.h:5138
tbb::concurrent_unordered_map< SdfPath, std::unique_ptr< UsdCollectionAPI::MembershipQuery >, SdfPath::Hash > CollectionQueryCache
static value_type Compute(UsdImaging_PointInstancerIndicesCache const *owner, UsdPrim const &prim, query_type const *query)
UsdImaging_ResolvedAttributeCache< UsdImaging_DrawModeStrategy > UsdImaging_DrawModeCache
std::vector< class SdfPath > SdfPathVector
UsdImaging_ResolvedAttributeCache< UsdImaging_PointInstancerIndicesStrategy > UsdImaging_PointInstancerIndicesCache
query_type const * GetQuery(const UsdPrim &prim) const
USDGEOM_API bool GetLocalTransformation(GfMatrix4d *transform, const UsdTimeCode time) const
static value_type Compute(UsdImaging_XformCache const *owner, UsdPrim const &prim, query_type const *query)
UsdImaging_ResolvedAttributeCache< UsdImaging_NonlinearSampleCountStrategy > UsdImaging_NonlinearSampleCountCache
#define TF_WARN
USDGEOM_API TfToken ComputeVisibility(UsdTimeCode const &time=UsdTimeCode::Default()) const
GLint GLuint mask
Definition: glcorearb.h:124
SDF_API bool IsAbsolutePath() const
Returns whether the path is absolute.
#define TRACE_FUNCTION()
Definition: trace.h:26
UsdShadeMaterialBindingAPI::CollectionQueryCache & GetCollectionQueryCache()
Definition: prim.h:116
UsdImaging_ResolvedAttributeCache< UsdImaging_CoordSysBindingStrategy > UsdImaging_CoordSysBindingCache
static query_type MakeQuery(UsdPrim const &prim, bool *)
static query_type MakeQuery(UsdPrim const &prim, bool *)
UsdImaging_ResolvedAttributeCache< UsdImaging_BlurScaleStrategy > UsdImaging_BlurScaleCache
GLuint id
Definition: glcorearb.h:655
static value_type ComputeVisibility(UsdPrim const &prim, UsdTimeCode time)
static value_type Compute(UsdImaging_DrawModeCache const *owner, UsdPrim const &prim, query_type const *query)
GLuint const GLchar * name
Definition: glcorearb.h:786
static value_type Compute(UsdImaging_CoordSysBindingCache const *owner, UsdPrim const &prim, query_type const *query)
Definition: types.h:153
Definition: path.h:273
bool IsPrototype() const
Definition: prim.h:2071
SDF_API const std::string & GetString() const
USDGEOM_API std::vector< bool > ComputeMaskAtTime(UsdTimeCode time, VtInt64Array const *ids=nullptr) const
USDSHADE_API UsdShadeMaterial ComputeBoundMaterial(BindingsCache *bindingsCache, CollectionQueryCache *collectionQueryCache, const TfToken &materialPurpose=UsdShadeTokens->allPurpose, UsdRelationship *bindingRel=nullptr, bool supportLegacyBindings=true) const
UsdPrim GetParent() const
Definition: prim.h:1529
#define TF_DEBUG(enumVal)
Definition: debug.h:484
SDF_API bool HasPrefix(const SdfPath &prefix) const
UsdImaging_ResolvedAttributeCache< UsdImaging_XfStrategy > UsdImaging_XformCache
USD_API UsdStageWeakPtr GetStage() const
GT_API const UT_StringHolder version
UsdGeomImageable::PurposeInfo value_type
std::shared_ptr< SdfPathVector > IdVecPtr
USDGEOM_API PurposeInfo ComputePurposeInfo() const
static value_type Compute(UsdImaging_NonlinearSampleCountCache const *owner, UsdPrim const &prim, query_type const *query)
UsdShadeMaterialBindingAPI::BindingsCache & GetBindingsCache()
static query_type MakeQuery(UsdPrim const &prim, bool *)
SdfPath GetPath() const
Definition: object.h:186
UsdGeomXformable::XformQuery query_type
USDGEOM_API TfStaticData< UsdGeomTokensType > UsdGeomTokens
PXR_NAMESPACE_CLOSE_SCOPE PXR_NAMESPACE_OPEN_SCOPE
Definition: path.h:1425
USD_API bool HasAuthoredValue() const
__hostdev__ constexpr T pi()
Pi constant taken from Boost to match old behaviour.
Definition: NanoVDB.h:976
#define PXR_NAMESPACE_CLOSE_SCOPE
Definition: pxr.h:74
static query_type MakeQuery(UsdPrim const &prim, bool *)
UsdImaging_ResolvedAttributeCache(const UsdTimeCode time, ImplData *implData=nullptr, const ValueOverridesMap valueOverrides=ValueOverridesMap())
Construct a new for the specified time.
static query_type MakeQuery(UsdPrim const &prim, ImplData *implData)
static query_type MakeQuery(UsdPrim const &prim, bool *)
static value_type Compute(UsdImaging_MaterialBindingCache const *owner, UsdPrim const &prim, query_type const *query)
SdfPath GetPath() const
Shorthand for GetPrim()->GetPath().
Definition: schemaBase.h:106
static value_type Compute(UsdImaging_VisCache const *owner, UsdPrim const &prim, query_type const *query)
static value_type ComputePerPrototypeIndices(UsdPrim const &prim, UsdTimeCode time)
static query_type MakeQuery(UsdPrim const &prim, bool *)
tbb::concurrent_unordered_map< SdfPath, std::unique_ptr< BindingsAtPrim >, SdfPath::Hash > BindingsCache
std::shared_ptr< PrimvarRecord > value_type
#define TF_FOR_ALL(iter, c)
Definition: iterator.h:373
static value_type MakeDefault()
void WorkSwapDestroyAsync(T &obj)
Definition: utils.h:66
value_type GetValue(const UsdPrim &prim) const
USDGEOM_API UsdAttribute GetProtoIndicesAttr() const
UsdImaging_ResolvedAttributeCache< UsdImaging_InheritedPrimvarStrategy > UsdImaging_InheritedPrimvarCache
static value_type ComputeMaterialPath(UsdPrim const &prim, ImplData *implData)
static query_type MakeQuery(UsdPrim const &prim, bool *)
UsdImaging_MaterialBindingImplData(const TfToken &materialPurpose)
bool IsInPrototype() const
Definition: prim.h:2077
static const value_type invalidValue
std::vector< UsdShadeCoordSysAPI::Binding > UsdBindingVec