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