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_INHERITED_CACHE_H
25 #define PXR_USD_IMAGING_USD_IMAGING_INHERITED_CACHE_H
26 
27 /// \file usdImaging/resolvedAttributeCache.h
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 /// \class UsdImaging_ResolvedAttributeCache
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  typedef tbb::concurrent_unordered_map<UsdPrim,
74  _Entry,
75  hboost::hash<UsdPrim> > _CacheMap;
76 public:
77  typedef typename Strategy::value_type value_type;
78  typedef typename Strategy::query_type query_type;
79 
82 
83  /// Construct a new for the specified \p time.
85  const UsdTimeCode time,
86  ImplData *implData=nullptr,
87  const ValueOverridesMap valueOverrides=ValueOverridesMap())
88  : _time(time)
89  , _rootPath(SdfPath::AbsoluteRootPath())
90  , _cacheVersion(_GetInitialCacheVersion())
91  , _valueOverrides(valueOverrides)
92  , _implData(implData)
93  {
94  }
95 
96  /// Construct a new cache for UsdTimeCode::Default().
98  : _time(UsdTimeCode::Default())
99  , _rootPath(SdfPath::AbsoluteRootPath())
100  , _cacheVersion(1)
101  {
102  }
103 
105  {
106  WorkSwapDestroyAsync(_cache);
107  }
108 
109 
110  /// Compute the inherited value for the given \p prim, including the value
111  /// authored on the Prim itself, if present.
112  value_type GetValue(const UsdPrim& prim) const
113  {
114  TRACE_FUNCTION();
115  if (!prim.GetPath().HasPrefix(_rootPath)
116  && !prim.IsInMaster()) {
117  TF_CODING_ERROR("Attempt to get value for: %s "
118  "which is not within the specified root: %s",
119  prim.GetPath().GetString().c_str(),
120  _rootPath.GetString().c_str());
121  return Strategy::MakeDefault();
122  }
123 
124  return *_GetValue(prim);
125  }
126 
127  /// Returns the underlying query object for the given prim. If the prim has
128  /// no cache entry, calling this method will trigger the entry to be
129  /// populated in an invalid state, but will return a valid query object.
130  query_type const*
131  GetQuery(const UsdPrim& prim) const {
132  return &_GetCacheEntryForPrim(prim)->query;
133  }
134 
135  /// Clears all pre-cached values.
136  void Clear() {
137  _cache.clear();
138  _cacheVersion = _GetInitialCacheVersion();
139  }
140 
141  /// Use the new \p time when computing values and may clear any existing
142  /// values cached for the previous time. Setting \p time to the current time
143  /// is a no-op.
144  void SetTime(UsdTimeCode time) {
145  if (time == _time)
146  return;
147 
148  if (Strategy::ValueMightBeTimeVarying()) {
149  // Mark all cached entries as invalid, but leave the queries behind.
150  // We increment by 2 here and always keep the version an odd number,
151  // this enables the use of even versions as a per-entry spin lock.
152  _cacheVersion += 2;
153  }
154 
155  // Update to correct time.
156  _time = time;
157  }
158 
159  /// Get the current time from which this cache is reading values.
160  UsdTimeCode GetTime() const { return _time; }
161 
162  /// Set the root ancestor path at which to stop inheritance.
163  /// Note that values on the root are not inherited.
164  ///
165  /// In general, you shouldn't use this function; USD inherited attribute
166  /// resolution will traverse to the pseudo-root, and not doing that in the
167  /// cache can introduce subtle bugs. This exists mainly for the benefit of
168  /// the transform cache, since UsdImagingDelegate transform resolution
169  /// semantics are complicated and special-cased.
170  void SetRootPath(const SdfPath& rootPath) {
171  if (!rootPath.IsAbsolutePath()) {
172  TF_CODING_ERROR("Invalid root path: %s",
173  rootPath.GetString().c_str());
174  return;
175  }
176 
177  if (rootPath == _rootPath)
178  return;
179 
180  Clear();
181  _rootPath = rootPath;
182  }
183 
184  /// Return the root ancestor path at which to stop inheritance.
185  /// See notes on SetRootPath.
186  const SdfPath & GetRootPath() const { return _rootPath; }
187 
188  /// Helper function used to append, update or remove overrides from the
189  /// internal value overrides map. By doing the updates to the map in a
190  /// single pass, we can optimize the dirtying of the cache entries.
191  ///
192  /// \p valueOverrides contains the set of value overrides to be appended
193  /// or updated in the internal value overrides map.
194  /// \p overriesToRemove contains the list of prims for which overrides
195  /// must be removed.
196  /// \p dirtySubtreeRoots is populated with the list of paths to the roots
197  /// of the subtrees that must be recomputed.
198  void UpdateValueOverrides(const ValueOverridesMap &valueOverrides,
199  const std::vector<UsdPrim> &overridesToRemove,
200  std::vector<SdfPath> *dirtySubtreeRoots)
201  {
202  TRACE_FUNCTION();
203 
204  if (valueOverrides.empty() && overridesToRemove.empty())
205  return;
206 
207  ValueOverridesMap valueOverridesToProcess;
208  SdfPathVector processedOverridePaths;
209  TF_FOR_ALL(it, valueOverrides) {
210  const UsdPrim &prim = it->first;
211  const value_type &value = it->second;
212 
213  // If the existing value matches the incoming value, skip
214  // the update and dirtying.
215  if (*_GetValue(prim) == value)
216  continue;
217 
218  valueOverridesToProcess[prim] = value;
219  }
220 
221  TF_FOR_ALL(it, valueOverridesToProcess) {
222  const UsdPrim &prim = it->first;
223  const value_type &value = it->second;
224 
225  // XXX: performance
226  // We could probably make this faster by using a hash table of
227  // prefixes. This hasn't showed up in traces much though as it's not
228  // common to update value overrides for more than one path at a
229  // time.
230  bool isDescendantOfProcessedOverride = false;
231  for (const SdfPath &processedPath : processedOverridePaths) {
232  if (prim.GetPath().HasPrefix(processedPath)) {
233  isDescendantOfProcessedOverride = true;
234  break;
235  }
236  }
237 
238  // Invalidate cache entries if the prim is not a descendant of a
239  // path that has already been processed.
240  if (!isDescendantOfProcessedOverride) {
241  for (UsdPrim descendant: UsdPrimRange(prim)) {
242  if (_Entry* entry = _GetCacheEntryForPrim(descendant)) {
243  entry->version = _GetInvalidVersion();
244  }
245  }
246  processedOverridePaths.push_back(prim.GetPath());
247  dirtySubtreeRoots->push_back(prim.GetPath());
248  }
249 
250  // Update overrides in the internal value overrides map.
251  _valueOverrides[prim] = value;
252  }
253 
254  for (const UsdPrim &prim : overridesToRemove) {
255 
256  // Erase the entry from the map of overrides.
257  size_t numErased = _valueOverrides.erase(prim);
258 
259  // If the override doesn't exist, then there's nothing to do.
260  if (numErased == 0) {
261  continue;
262  }
263 
264  bool isDescendantOfProcessedOverride = false;
265  for (const SdfPath &processedPath : processedOverridePaths) {
266  if (prim.GetPath().HasPrefix(processedPath)) {
267  isDescendantOfProcessedOverride = true;
268  break;
269  }
270  }
271 
272  // Invalidate cache entries if the prim is not a descendant of a
273  // path that has already been processed.
274  if (!isDescendantOfProcessedOverride) {
275  for (UsdPrim descendant: UsdPrimRange(prim)) {
276  if (_Entry* entry = _GetCacheEntryForPrim(descendant)) {
277  entry->version = _GetInvalidVersion();
278  }
279  }
280  dirtySubtreeRoots->push_back(prim.GetPath());
281  processedOverridePaths.push_back(prim.GetPath());
282  }
283  }
284  }
285 
286 private:
287  // Cached value entries. Note that because query objects may be caching
288  // non-time varying data, entries may exist in the cache with invalid
289  // values. The version is used to determine validity.
290  struct _Entry {
291  _Entry()
292  : value(Strategy::MakeDefault())
293  , version(_GetInitialEntryVersion())
294  { }
295 
296  _Entry(const query_type & query_,
297  const value_type& value_,
298  unsigned version_)
299  : query(query_)
300  , value(value_)
301  , version(version_)
302  { }
303 
306  tbb::atomic<unsigned> version;
307  };
308 
309  // Returns the version number for a valid cache entry
310  unsigned _GetValidVersion() const { return _cacheVersion + 1; }
311 
312  // Returns the version number for an invalid cache entry
313  unsigned _GetInvalidVersion() const { return _cacheVersion - 1; }
314 
315  // Initial version numbers
316  static unsigned _GetInitialCacheVersion() { return 1; }
317  static unsigned _GetInitialEntryVersion() {
318  return _GetInitialCacheVersion()-1;
319  }
320 
321  // Traverse the hierarchy (order is strategy dependent) and compute the
322  // inherited value.
323  value_type const* _GetValue(const UsdPrim& prim) const;
324 
325  // Helper function to get or create a new entry for a prim in the cache.
326  _Entry* _GetCacheEntryForPrim(const UsdPrim &prim) const;
327 
328  // Sets the value of the given cache entry. If multiple threads attempt to
329  // set the same entry, the first in wins and other threads spin until the
330  // new value is set.
331  void _SetCacheEntryForPrim(const UsdPrim &prim,
332  value_type const& value,
333  _Entry* entry) const;
334 
335  // Mutable is required here to allow const methods to update the cache when
336  // it is thread safe, however not all mutations of this map are thread safe.
337  // See underlying map documentation for details.
338  mutable _CacheMap _cache;
339 
340  // The time at which this stack is querying and caching attribute values.
341  UsdTimeCode _time;
342  SdfPath _rootPath;
343 
344  // A serial number indicating the valid state of entries in the cache. When
345  // an entry has an equal or greater value, the entry is valid.
346  tbb::atomic<unsigned> _cacheVersion;
347 
348  // Value overrides for a set of descendents.
349  ValueOverridesMap _valueOverrides;
350 
351  // Supplemental cache if used by this inherited cache.
352  ImplData *_implData;
353 };
354 
355 template<typename Strategy, typename ImplData>
356 void
358  const UsdPrim &prim,
359  value_type const& value,
360  _Entry* entry) const
361 {
362  // Note: _cacheVersion is not allowed to change during cache access.
363  unsigned v = entry->version;
364  if (v < _cacheVersion
365  && entry->version.compare_and_swap(_cacheVersion, v) == v)
366  {
367  entry->value = value;
368  entry->version = _GetValidVersion();
369  } else {
370  while (entry->version != _GetValidVersion()) {
371  // Future work: A suggestion is that rather than literally spinning
372  // here, we should use the pause instruction, which sleeps for one
373  // cycle while allowing hyper threads to continue. Folly has a nice
374  // implementation of this packaged up as "sleeper", which we could
375  // also implement in Work and Arch.
376  }
377  }
378 }
379 
380 template<typename Strategy, typename ImplData>
383  const UsdPrim &prim) const
384 {
385  typename _CacheMap::const_iterator it = _cache.find(prim);
386  if (it != _cache.end()) {
387  return &it->second;
388  }
389 
390  _Entry e;
391  e.query = Strategy::MakeQuery(prim, _implData);
392  e.value = Strategy::MakeDefault();
393  e.version = _GetInvalidVersion();
394  return &(_cache.insert(
395  typename _CacheMap::value_type(prim, e)).first->second);
396 }
397 
398 template<typename Strategy, typename ImplData>
401  const UsdPrim& prim) const
402 {
403  static value_type const default_ = Strategy::MakeDefault();
404 
405  // Base case.
406  if (!prim || prim.IsMaster() || prim.GetPath() == _rootPath)
407  return &default_;
408 
409  _Entry* entry = _GetCacheEntryForPrim(prim);
410  if (entry->version == _GetValidVersion()) {
411  // Cache hit
412  return &entry->value;
413  }
414 
415  // Future work: Suggestion is that when multiple threads are computing the
416  // same value, we could block all but one thread here, possibly rescheduling
417  // blocked threads as continuations, rather than allowing all threads to
418  // continue to race until a cache hit is encountered.
419 
420  // Future work: A suggestion is that we make this iterative instead of
421  // recursive.
422  typename ValueOverridesMap::const_iterator it =
423  _valueOverrides.find(prim);
424  if (it != _valueOverrides.end()) {
425  _SetCacheEntryForPrim(prim, it->second, entry);
426  } else {
427  _SetCacheEntryForPrim(prim,
428  Strategy::Compute(this, prim, &entry->query),
429  entry);
430  }
431  return &entry->value;
432 }
433 
435 
436 // -------------------------------------------------------------------------- //
437 // Xform Cache
438 // -------------------------------------------------------------------------- //
439 
441 #include "pxr/base/gf/matrix4d.h"
442 
444 
447 
451 
452  static
453  bool ValueMightBeTimeVarying() { return true; }
454  static
456 
457  static
458  query_type MakeQuery(UsdPrim prim, bool *) {
459  if (UsdGeomXformable xf = UsdGeomXformable(prim))
460  return query_type(xf);
461  return query_type();
462  }
463 
464  static
465  value_type
466  Compute(UsdImaging_XformCache const* owner,
467  UsdPrim prim,
468  query_type const* query)
469  {
470  value_type xform = MakeDefault();
471  // No need to check query validity here because XformQuery doesn't
472  // support it.
473  query->GetLocalTransformation(&xform, owner->GetTime());
474 
475  return !query->GetResetXformStack()
476  ? (xform * (*owner->_GetValue(prim.GetParent())))
477  : xform;
478  }
479 
480  // Compute the full transform, this is not part of the interface required by
481  // the cache.
482  static
483  value_type
484  ComputeTransform(UsdPrim const& prim,
485  SdfPath const& rootPath,
486  UsdTimeCode time,
488  {
489  bool reset = false;
490  GfMatrix4d ctm(1.0);
491  GfMatrix4d localXf(1.0);
492  UsdPrim p = prim;
493  while (p && p.GetPath() != rootPath) {
494  const auto &overIt = ctmOverrides.find(p.GetPath());
495  // If there's a ctm override, use it and break out of the loop.
496  if (overIt != ctmOverrides.end()) {
497  ctm *= overIt->second;
498  break;
499  } else if (UsdGeomXformable xf = UsdGeomXformable(p)) {
500  if (xf.GetLocalTransformation(&localXf, &reset, time))
501  ctm *= localXf;
502  if (reset)
503  break;
504  }
505  p = p.GetParent();
506  }
507  return ctm;
508  }
509 };
510 
512 
513 // -------------------------------------------------------------------------- //
514 // Visibility Cache
515 // -------------------------------------------------------------------------- //
516 
518 #include "pxr/base/tf/token.h"
520 
522 
525 
527  typedef TfToken value_type; // invisible, inherited
529 
530  static
531  bool ValueMightBeTimeVarying() { return true; }
532  static
533  value_type MakeDefault() { return UsdGeomTokens->inherited; }
534 
535  static
536  query_type MakeQuery(UsdPrim prim, bool *) {
537  if (UsdGeomImageable xf = UsdGeomImageable(prim))
538  return query_type(xf.GetVisibilityAttr());
539  return query_type();
540  }
541 
542  static
543  value_type
544  Compute(UsdImaging_VisCache const* owner,
545  UsdPrim prim,
546  query_type const* query)
547  {
548  value_type v = *owner->_GetValue(prim.GetParent());
549  if (v == UsdGeomTokens->invisible)
550  return v;
551  if (*query)
552  query->Get(&v, owner->GetTime());
553  return v;
554  }
555 
556  static
557  value_type
559  {
560  return UsdGeomImageable(prim).ComputeVisibility(time);
561  }
562 };
563 
564 // -------------------------------------------------------------------------- //
565 // Purpose Cache
566 // -------------------------------------------------------------------------- //
567 
571 
573  // For proper inheritance, we need to return the PurposeInfo struct which
574  // stores whether child prims can inherit the parent's computed purpose
575  // when they don't have an authored purpose of their own.
576  typedef UsdGeomImageable::PurposeInfo value_type; // purpose, inherited
578 
579  static
581  // Return the fallback default instead of an empty purpose info.
582  return value_type(UsdGeomTokens->default_, false);
583  }
584 
585  static
586  query_type MakeQuery(UsdPrim prim, bool *) {
588  return im ? query_type(im.GetPurposeAttr()) : query_type();
589  }
590 
591  static
592  value_type
593  Compute(UsdImaging_PurposeCache const* owner,
594  UsdPrim prim,
595  query_type const* query)
596  {
597  // Fallback to parent if the prim isn't imageable or doesn't have a
598  // purpose attribute. Note that this returns the default purpose if
599  // there's no parent prim.
600  if (!*query) {
601  return *(owner->_GetValue(prim.GetParent()));
602  }
603 
604  // If the prim has an authored purpose value, we get and use that.
605  if (query->HasAuthoredValue()) {
606  value_type info;
607  query->Get(&info.purpose);
608  info.isInheritable = true;
609  return info;
610  }
611 
612  // Otherwise we inherit parent's purpose value, but only if the parent's
613  // purpose is inheritable. An inherited purpose is itself inheritable
614  // by child prims..
615  const value_type *v = owner->_GetValue(prim.GetParent());
616  if (v->isInheritable) {
617  return *v;
618  }
619 
620  // Otherwise, get the fallback value. The fallback purpose will not
621  // be inherited by descendants.
622  value_type info;
623  query->Get(&info.purpose);
624  return info;
625  }
626 
627  static
628  value_type
630  {
631  return UsdGeomImageable(prim).ComputePurposeInfo();
632  }
633 };
634 
636 
637 // -------------------------------------------------------------------------- //
638 // Hydra MaterialBinding Cache
639 // -------------------------------------------------------------------------- //
640 
643 
645 
647  /// Constructor takes the purpose for which material bindings are to be
648  /// evaluated.
650  _materialPurpose(materialPurpose)
651  { }
652 
653  /// Destructor invokes ClearCaches(), which does the cache deletion in
654  /// parallel.
656  ClearCaches();
657  }
658 
659  /// Returns the material purpose for which bindings must be computed.
660  const TfToken &GetMaterialPurpose() const {
661  return _materialPurpose;
662  }
663 
664  /// Returns the BindingsCache object to be used when computing resolved
665  /// material bindings.
667  { return _bindingsCache; }
668 
669  /// Returns the BindingsCache object to be used when computing resolved
670  /// material bindings.
672  { return _collQueryCache; }
673 
674  /// Clears all of the held caches.
675  void ClearCaches();
676 
677 private:
678  const TfToken _materialPurpose;
681 };
682 
687 
688 struct UsdImaging_MaterialStrategy {
689  typedef SdfPath value_type; // inherited path to bound shader
691 
693 
694  static
695  bool ValueMightBeTimeVarying() { return false; }
696  static
698 
699  static
701  UsdPrim prim,
702  ImplData *implData)
703  {
705  &implData->GetBindingsCache(),
706  &implData->GetCollectionQueryCache(),
707  implData->GetMaterialPurpose());
708  }
709 
710  static
711  value_type
712  Compute(UsdImaging_MaterialBindingCache const* owner,
713  UsdPrim prim,
714  query_type const* query)
715  {
716  TF_DEBUG(USDIMAGING_SHADERS).Msg("Looking for \"preview\" material "
717  "binding for %s\n", prim.GetPath().GetText());
718  if (*query) {
719  SdfPath binding = query->GetPath();
720  if (!binding.IsEmpty()) {
721  return binding;
722  }
723  }
724  // query already contains the resolved material binding for the prim.
725  // Hence, we don't need to inherit the binding from the parent here.
726  // Futhermore, it may be wrong to inherit the binding from the parent,
727  // because in the new scheme, a child of a bound prim can be unbound.
728  return value_type();
729  }
730 
731  static
732  value_type
733  ComputeMaterialPath(UsdPrim const& prim, ImplData *implData) {
734  // We don't need to walk up the namespace here since
735  // ComputeBoundMaterial does it for us.
737  ComputeBoundMaterial(&implData->GetBindingsCache(),
738  &implData->GetCollectionQueryCache(),
739  implData->GetMaterialPurpose())) {
740  return mat.GetPath();
741  }
742  return value_type();
743  }
744 };
745 
747 
748 // -------------------------------------------------------------------------- //
749 // ModelDrawMode Cache
750 // -------------------------------------------------------------------------- //
751 
753 
755 
759 
761 {
762  typedef TfToken value_type; // origin, bounds, cards, default
764 
765  static
766  bool ValueMightBeTimeVarying() { return false; }
767  static
768  value_type MakeDefault() { return UsdGeomTokens->default_; }
769 
770  static
771  query_type MakeQuery(UsdPrim prim, bool *) {
772  if (UsdAttribute a = UsdGeomModelAPI(prim).GetModelDrawModeAttr())
773  return query_type(a);
774  return query_type();
775  }
776 
777  static
778  value_type
779  Compute(UsdImaging_DrawModeCache const* owner,
780  UsdPrim prim,
781  query_type const* query)
782  {
783  value_type v = UsdGeomTokens->default_;
784  if (*query && query->Get(&v)) {
785  return v;
786  }
787  return *owner->_GetValue(prim.GetParent());
788  }
789 
790  static
791  value_type
793  {
794  return UsdGeomModelAPI(prim).ComputeModelDrawMode();
795  }
796 };
797 
799 
800 // -------------------------------------------------------------------------- //
801 // UsdGeomPointInstancer indices cache
802 // -------------------------------------------------------------------------- //
803 
805 
807 
811 
813 {
814  // map from protoIndex -> instanceIndices.
816  // We don't use query_type, but can't set it to void.
817  typedef int query_type;
818 
819  // XXX: Most indices values will be static, but since they *can*
820  // be animated, we need to return true here to get invalidation on
821  // time-change. It would be nice to add a per-entry time-varying bit
822  // to the resolved cache, instead of having the global per-attribute
823  // bit.
824  //
825  // In this particular case, instance indices are only recomputed when
826  // we see "DirtyInstanceIndex" in UpdateForTime, so though we'll be
827  // clearing cache entries out of the resolved cache on time-change,
828  // we won't actually call out to the attribute cache on static indices.
829  static
830  bool ValueMightBeTimeVarying() { return true; }
831  static
833 
834  static
835  query_type MakeQuery(UsdPrim prim, bool *) {
836  return 0;
837  }
838 
839  static
840  value_type
841  Compute(UsdImaging_PointInstancerIndicesCache const* owner,
842  UsdPrim prim,
843  query_type const* query)
844  {
845  return ComputePerPrototypeIndices(prim, owner->GetTime());
846  }
847 
848  static
849  value_type
851  {
852  value_type v;
853 
855  VtIntArray protoIndices;
856  if (!pi.GetProtoIndicesAttr().Get(&protoIndices, time)) {
857  TF_WARN("Failed to read point instancer protoIndices");
858  return v;
859  }
860 
861  std::vector<bool> mask = pi.ComputeMaskAtTime(time);
862 
863  for (size_t instanceId = 0; instanceId < protoIndices.size(); ++instanceId) {
864  size_t protoIndex = protoIndices[instanceId];
865 
866  if (protoIndex >= v.size()) {
867  v.resize(protoIndex + 1);
868  }
869 
870  if (mask.size() == 0 || mask[instanceId]) {
871  v[protoIndex].push_back(instanceId);
872  }
873  }
874 
875  return v;
876  }
877 };
878 
880 
881 // -------------------------------------------------------------------------- //
882 // CoordSysBinding Cache
883 // -------------------------------------------------------------------------- //
884 
886 #include "pxr/imaging/hd/coordSys.h"
887 
889 
891  // Helper provided by the scene delegate to pre-convert
892  // the binding paths to the equivalent Hydra ID.
893  std::function<SdfPath(SdfPath)> usdToHydraPath;
894 };
895 
897 
902 
903 struct UsdImaging_CoordSysBindingStrategy
904 {
906 
907  typedef std::vector<UsdShadeCoordSysAPI::Binding> UsdBindingVec;
908  typedef std::shared_ptr<UsdBindingVec> UsdBindingVecPtr;
909  typedef std::shared_ptr<SdfPathVector> IdVecPtr;
910 
911  struct value_type {
914  };
915  struct query_type {
918 
919  // Convert a USD binding relationship to a Hydra ID
920  SdfPath
922  return implData->usdToHydraPath(binding.bindingRelPath);
923  }
924  };
925 
926  static
927  bool ValueMightBeTimeVarying() { return false; }
928 
929  static
931  return value_type();
932  }
933 
934  static
936  return query_type({ UsdShadeCoordSysAPI(prim), implData });
937  }
938 
939  static
940  value_type
941  Compute(UsdImaging_CoordSysBindingCache const* owner,
942  UsdPrim prim,
943  query_type const* query)
944  {
945  value_type v;
946  if (query->coordSysAPI) {
947  // Pull inherited bindings first.
948  if (UsdPrim parentPrim = prim.GetParent()) {
949  v = *owner->_GetValue(parentPrim);
950  }
951  // Merge any local bindings.
952  if (query->coordSysAPI.HasLocalBindings()) {
953  SdfPathVector hdIds;
954  UsdBindingVec usdBindings;
955  if (v.idVecPtr) {
956  hdIds = *v.idVecPtr;
957  }
958  if (v.usdBindingVecPtr) {
959  usdBindings = *v.usdBindingVecPtr;
960  }
961  for (auto const& binding:
962  query->coordSysAPI.GetLocalBindings()) {
963  bool found = false;
964  for (size_t i=0, n=hdIds.size(); i<n; ++i) {
965  if (usdBindings[i].name == binding.name) {
966  // Found an override -- replace this binding.
967  usdBindings[i] = binding;
968  hdIds[i] = query->_IdForBinding(binding);
969  found = true;
970  break;
971  }
972  }
973  if (!found) {
974  // New binding, so append.
975  usdBindings.push_back(binding);
976  hdIds.push_back(query->_IdForBinding(binding));
977  }
978  }
979  v.idVecPtr.reset(new SdfPathVector(hdIds));
980  v.usdBindingVecPtr.reset(new UsdBindingVec(usdBindings));
981  }
982  }
983  return v;
984  }
985 };
986 
988 
989 // -------------------------------------------------------------------------- //
990 // Inherited Primvar Cache
991 // -------------------------------------------------------------------------- //
992 
994 
996 
1000 
1002 {
1003  struct PrimvarRecord {
1004  std::vector<UsdGeomPrimvar> primvars;
1005  bool variable;
1006  };
1007  typedef std::shared_ptr<PrimvarRecord> value_type;
1009 
1010  // While primvar data might be time-varying, the set of primvars applying
1011  // to a prim will not.
1012  static
1013  bool ValueMightBeTimeVarying() { return false; }
1014 
1015  static
1017  return value_type();
1018  }
1019 
1020  static
1021  query_type MakeQuery(UsdPrim prim, bool *) {
1022  return query_type(UsdGeomPrimvarsAPI(prim));
1023  }
1024 
1025  static
1026  value_type Compute(UsdImaging_InheritedPrimvarCache const* owner,
1027  UsdPrim prim,
1028  query_type const* query)
1029  {
1030  value_type v;
1031  if (*query) {
1032  // Pull inherited bindings first.
1033  if (UsdPrim parentPrim = prim.GetParent()) {
1034  v = *owner->_GetValue(parentPrim);
1035  }
1036  // Merge any local bindings.
1037  std::vector<UsdGeomPrimvar> primvars =
1039  v ? v->primvars : std::vector<UsdGeomPrimvar>());
1040  if (!primvars.empty()) {
1041  v = std::make_shared<PrimvarRecord>();
1042  v->primvars = std::move(primvars);
1043  v->variable = false;
1044  for (UsdGeomPrimvar const& pv : v->primvars) {
1045  if (pv.ValueMightBeTimeVarying()) {
1046  v->variable = true;
1047  break;
1048  }
1049  }
1050  }
1051  }
1052  return v;
1053  }
1054 };
1055 
1057 
1058 #endif // PXR_USD_IMAGING_USD_IMAGING_INHERITED_CACHE_H
static value_type Compute(UsdImaging_InheritedPrimvarCache const *owner, UsdPrim prim, query_type const *query)
SDF_API const char * GetText() const
Returns the string representation of this path as a c string.
UsdTimeCode GetTime() const
Get the current time from which this cache is reading values.
static value_type Compute(UsdImaging_XformCache const *owner, UsdPrim prim, query_type const *query)
bool Get(T *value, UsdTimeCode time=UsdTimeCode::Default()) const
USDGEOM_API std::vector< UsdGeomPrimvar > FindIncrementallyInheritablePrimvars(const std::vector< UsdGeomPrimvar > &inheritedFromAncestors) const
UsdImaging_ResolvedAttributeCache< UsdImaging_PurposeStrategy > UsdImaging_PurposeCache
static query_type MakeQuery(UsdPrim prim, ImplData *implData)
static value_type ComputeDrawMode(UsdPrim const &prim)
const TfToken & GetMaterialPurpose() const
Returns the material purpose for which bindings must be computed.
GLuint const GLchar * name
Definition: glew.h:1814
bool Get(T *value, UsdTimeCode time=UsdTimeCode::Default()) const
Definition: attribute.h:431
UsdImaging_ResolvedAttributeCache< UsdImaging_MaterialStrategy, UsdImaging_MaterialBindingImplData > UsdImaging_MaterialBindingCache
void SetRootPath(const SdfPath &rootPath)
GT_API const UT_StringHolder time
USDGEOM_API bool ValueMightBeTimeVarying() const
SdfPath _IdForBinding(UsdShadeCoordSysAPI::Binding const &binding) const
iterator end()
Definition: hashmap.h:318
GLboolean GLboolean GLboolean GLboolean a
Definition: glew.h:9477
#define TF_CODING_ERROR
void Clear()
Clears all pre-cached values.
GLenum query
Definition: glew.h:5704
bool IsEmpty() const noexcept
Returns true if this is the empty path (SdfPath::EmptyPath()).
Definition: path.h:413
void UpdateValueOverrides(const ValueOverridesMap &valueOverrides, const std::vector< UsdPrim > &overridesToRemove, std::vector< SdfPath > *dirtySubtreeRoots)
static value_type ComputeTransform(UsdPrim const &prim, SdfPath const &rootPath, UsdTimeCode time, const TfHashMap< SdfPath, GfMatrix4d, SdfPath::Hash > &ctmOverrides)
const GLdouble * v
Definition: glew.h:1391
static query_type MakeQuery(UsdPrim prim, bool *)
size_type erase(const key_type &key)
Definition: hashmap.h:321
USDSHADE_API UsdShadeMaterial ComputeBoundMaterial(BindingsCache *bindingsCache, CollectionQueryCache *collectionQueryCache, const TfToken &materialPurpose=UsdShadeTokens->allPurpose, UsdRelationship *bindingRel=nullptr) const
GLenum GLint GLuint mask
Definition: glew.h:1845
GLboolean reset
Definition: glew.h:4959
static query_type MakeQuery(UsdPrim prim, bool *)
static value_type MakeDefault()
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 value_type ComputePurposeInfo(UsdPrim const &prim)
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
Definition: token.h:87
bool IsMaster() const
Return true if this prim is a master prim, false otherwise.
Definition: prim.h:1405
UsdImaging_ResolvedAttributeCache< UsdImaging_VisStrategy > UsdImaging_VisCache
USDGEOM_API UsdAttribute GetPurposeAttr() const
tbb::concurrent_unordered_map< SdfPath, std::unique_ptr< UsdCollectionAPI::MembershipQuery >, SdfPath::Hash > CollectionQueryCache
USDGEOM_API bool HasLocalBindings() const
UsdImaging_ResolvedAttributeCache< UsdImaging_CoordSysBindingStrategy, UsdImaging_CoordSysBindingImplData > UsdImaging_CoordSysBindingCache
UsdImaging_ResolvedAttributeCache< UsdImaging_DrawModeStrategy > UsdImaging_DrawModeCache
static query_type MakeQuery(UsdPrim prim, bool *)
UsdImaging_ResolvedAttributeCache< UsdImaging_PointInstancerIndicesStrategy > UsdImaging_PointInstancerIndicesCache
query_type const * GetQuery(const UsdPrim &prim) const
USDGEOM_API bool GetLocalTransformation(GfMatrix4d *transform, const UsdTimeCode time) const
#define TF_WARN
USDGEOM_API TfToken ComputeVisibility(UsdTimeCode const &time=UsdTimeCode::Default()) const
GLsizei n
Definition: glew.h:4040
static query_type MakeQuery(UsdPrim prim, bool *)
SDF_API bool IsAbsolutePath() const
Returns whether the path is absolute.
static value_type Compute(UsdImaging_DrawModeCache const *owner, UsdPrim prim, query_type const *query)
static value_type Compute(UsdImaging_CoordSysBindingCache const *owner, UsdPrim prim, query_type const *query)
#define TRACE_FUNCTION()
Definition: trace.h:43
UsdShadeMaterialBindingAPI::CollectionQueryCache & GetCollectionQueryCache()
Definition: prim.h:132
static value_type ComputeVisibility(UsdPrim const &prim, UsdTimeCode time)
static value_type Compute(UsdImaging_PointInstancerIndicesCache const *owner, UsdPrim prim, query_type const *query)
static query_type MakeQuery(UsdPrim prim, ImplData *implData)
static query_type MakeQuery(UsdPrim prim, bool *)
Definition: types.h:166
Definition: path.h:288
SDF_API const std::string & GetString() const
Returns the string representation of this path as a std::string.
USDGEOM_API std::vector< bool > ComputeMaskAtTime(UsdTimeCode time, VtInt64Array const *ids=nullptr) const
TfHashMap< UsdPrim, value_type, hboost::hash< UsdPrim > > ValueOverridesMap
UsdPrim GetParent() const
Definition: prim.h:912
#define TF_DEBUG(enumVal)
Definition: debug.h:501
std::vector< class SdfPath > SdfPathVector
A vector of SdfPaths.
Definition: path.h:209
std::function< SdfPath(SdfPath)> usdToHydraPath
SDF_API bool HasPrefix(const SdfPath &prefix) const
UsdImaging_ResolvedAttributeCache< UsdImaging_XfStrategy > UsdImaging_XformCache
GT_API const UT_StringHolder version
UsdGeomImageable::PurposeInfo value_type
std::shared_ptr< SdfPathVector > IdVecPtr
USDGEOM_API PurposeInfo ComputePurposeInfo() const
GLfloat GLfloat p
Definition: glew.h:16321
UsdShadeMaterialBindingAPI::BindingsCache & GetBindingsCache()
SdfPath GetPath() const
Definition: object.h:194
UsdGeomXformable::XformQuery query_type
USDGEOM_API TfStaticData< UsdGeomTokensType > UsdGeomTokens
PXR_NAMESPACE_CLOSE_SCOPE PXR_NAMESPACE_OPEN_SCOPE
Definition: path.h:1346
static value_type Compute(UsdImaging_MaterialBindingCache const *owner, UsdPrim prim, query_type const *query)
USD_API bool HasAuthoredValue() const
static query_type MakeQuery(UsdPrim prim, bool *)
#define PXR_NAMESPACE_CLOSE_SCOPE
Definition: pxr.h:91
UsdImaging_ResolvedAttributeCache(const UsdTimeCode time, ImplData *implData=nullptr, const ValueOverridesMap valueOverrides=ValueOverridesMap())
Construct a new for the specified time.
USDGEOM_API std::vector< Binding > GetLocalBindings() const
SdfPath GetPath() const
Shorthand for GetPrim()->GetPath().
Definition: schemaBase.h:122
static value_type ComputePerPrototypeIndices(UsdPrim const &prim, UsdTimeCode time)
constexpr T pi()
Pi constant taken from Boost to match old behaviour.
Definition: Math.h:108
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
static value_type Compute(UsdImaging_PurposeCache const *owner, UsdPrim prim, query_type const *query)
USDGEOM_API UsdAttribute GetProtoIndicesAttr() const
bool IsInMaster() const
Definition: prim.h:1412
UsdImaging_ResolvedAttributeCache< UsdImaging_InheritedPrimvarStrategy > UsdImaging_InheritedPrimvarCache
static value_type ComputeMaterialPath(UsdPrim const &prim, ImplData *implData)
GLsizei const GLfloat * value
Definition: glew.h:1849
UsdImaging_MaterialBindingImplData(const TfToken &materialPurpose)
std::vector< UsdShadeCoordSysAPI::Binding > UsdBindingVec
static value_type Compute(UsdImaging_VisCache const *owner, UsdPrim prim, query_type const *query)