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