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 
28 
29 #include "pxr/pxr.h"
30 #include "pxr/usdImaging/usdImaging/api.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 <boost/functional/hash.hpp>
39 #include <tbb/concurrent_unordered_map.h>
40 #include <functional>
41 
42 PXR_NAMESPACE_OPEN_SCOPE
43 
66 template<typename Strategy, typename ImplData=bool>
67 class UsdImaging_ResolvedAttributeCache
68 {
69  friend Strategy;
70  struct _Entry;
71  typedef tbb::concurrent_unordered_map<UsdPrim,
72  _Entry,
73  boost::hash<UsdPrim> > _CacheMap;
74 public:
75  typedef typename Strategy::value_type value_type;
76  typedef typename Strategy::query_type query_type;
77 
78  typedef TfHashMap<UsdPrim, value_type, boost::hash<UsdPrim> >
79  ValueOverridesMap;
80 
82  explicit UsdImaging_ResolvedAttributeCache(
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 
95  UsdImaging_ResolvedAttributeCache()
96  : _time(UsdTimeCode::Default())
97  , _rootPath(SdfPath::AbsoluteRootPath())
98  , _cacheVersion(1)
99  {
100  }
101 
102  ~UsdImaging_ResolvedAttributeCache()
103  {
104  WorkSwapDestroyAsync(_cache);
105  }
106 
107 
110  value_type GetValue(const UsdPrim& prim) const
111  {
112  TRACE_FUNCTION();
113  if (!prim.GetPath().HasPrefix(_rootPath)
114  && !prim.IsInPrototype()) {
115  TF_CODING_ERROR("Attempt to get value for: %s "
116  "which is not within the specified root: %s",
117  prim.GetPath().GetString().c_str(),
118  _rootPath.GetString().c_str());
119  return Strategy::MakeDefault();
120  }
121 
122  return *_GetValue(prim);
123  }
124 
128  query_type const*
129  GetQuery(const UsdPrim& prim) const {
130  return &_GetCacheEntryForPrim(prim)->query;
131  }
132 
134  void Clear() {
135  WorkSwapDestroyAsync(_cache);
136  _cacheVersion = _GetInitialCacheVersion();
137  }
138 
142  void SetTime(UsdTimeCode time) {
143  if (time == _time)
144  return;
145 
146  if (Strategy::ValueMightBeTimeVarying()) {
147  // Mark all cached entries as invalid, but leave the queries behind.
148  // We increment by 2 here and always keep the version an odd number,
149  // this enables the use of even versions as a per-entry spin lock.
150  _cacheVersion += 2;
151  }
152 
153  // Update to correct time.
154  _time = time;
155  }
156 
158  UsdTimeCode GetTime() const { return _time; }
159 
168  void SetRootPath(const SdfPath& rootPath) {
169  if (!rootPath.IsAbsolutePath()) {
170  TF_CODING_ERROR("Invalid root path: %s",
171  rootPath.GetString().c_str());
172  return;
173  }
174 
175  if (rootPath == _rootPath)
176  return;
177 
178  Clear();
179  _rootPath = rootPath;
180  }
181 
184  const SdfPath & GetRootPath() const { return _rootPath; }
185 
196  void UpdateValueOverrides(const ValueOverridesMap &valueOverrides,
197  const std::vector<UsdPrim> &overridesToRemove,
198  std::vector<SdfPath> *dirtySubtreeRoots)
199  {
200  TRACE_FUNCTION();
201 
202  if (valueOverrides.empty() && overridesToRemove.empty())
203  return;
204 
205  ValueOverridesMap valueOverridesToProcess;
206  SdfPathVector processedOverridePaths;
207  TF_FOR_ALL(it, valueOverrides) {
208  const UsdPrim &prim = it->first;
209  const value_type &value = it->second;
210 
211  // If the existing value matches the incoming value, skip
212  // the update and dirtying.
213  if (*_GetValue(prim) == value)
214  continue;
215 
216  valueOverridesToProcess[prim] = value;
217  }
218 
219  TF_FOR_ALL(it, valueOverridesToProcess) {
220  const UsdPrim &prim = it->first;
221  const value_type &value = it->second;
222 
223  // XXX: performance
224  // We could probably make this faster by using a hash table of
225  // prefixes. This hasn't showed up in traces much though as it's not
226  // common to update value overrides for more than one path at a
227  // time.
228  bool isDescendantOfProcessedOverride = false;
229  for (const SdfPath &processedPath : processedOverridePaths) {
230  if (prim.GetPath().HasPrefix(processedPath)) {
231  isDescendantOfProcessedOverride = true;
232  break;
233  }
234  }
235 
236  // Invalidate cache entries if the prim is not a descendant of a
237  // path that has already been processed.
238  if (!isDescendantOfProcessedOverride) {
239  for (UsdPrim descendant: UsdPrimRange(prim)) {
240  if (_Entry* entry = _GetCacheEntryForPrim(descendant)) {
241  entry->version = _GetInvalidVersion();
242  }
243  }
244  processedOverridePaths.push_back(prim.GetPath());
245  dirtySubtreeRoots->push_back(prim.GetPath());
246  }
247 
248  // Update overrides in the internal value overrides map.
249  _valueOverrides[prim] = value;
250  }
251 
252  for (const UsdPrim &prim : overridesToRemove) {
253 
254  // Erase the entry from the map of overrides.
255  size_t numErased = _valueOverrides.erase(prim);
256 
257  // If the override doesn't exist, then there's nothing to do.
258  if (numErased == 0) {
259  continue;
260  }
261 
262  bool isDescendantOfProcessedOverride = false;
263  for (const SdfPath &processedPath : processedOverridePaths) {
264  if (prim.GetPath().HasPrefix(processedPath)) {
265  isDescendantOfProcessedOverride = true;
266  break;
267  }
268  }
269 
270  // Invalidate cache entries if the prim is not a descendant of a
271  // path that has already been processed.
272  if (!isDescendantOfProcessedOverride) {
273  for (UsdPrim descendant: UsdPrimRange(prim)) {
274  if (_Entry* entry = _GetCacheEntryForPrim(descendant)) {
275  entry->version = _GetInvalidVersion();
276  }
277  }
278  dirtySubtreeRoots->push_back(prim.GetPath());
279  processedOverridePaths.push_back(prim.GetPath());
280  }
281  }
282  }
283 
284 private:
285  // Cached value entries. Note that because query objects may be caching
286  // non-time varying data, entries may exist in the cache with invalid
287  // values. The version is used to determine validity.
288  struct _Entry {
289  _Entry()
290  : value(Strategy::MakeDefault())
291  , version(_GetInitialEntryVersion())
292  { }
293 
294  _Entry(const query_type & query_,
295  const value_type& value_,
296  unsigned version_)
297  : query(query_)
298  , value(value_)
299  , version(version_)
300  { }
301 
302  query_type query;
303  value_type value;
304  tbb::atomic<unsigned> version;
305  };
306 
307  // Returns the version number for a valid cache entry
308  unsigned _GetValidVersion() const { return _cacheVersion + 1; }
309 
310  // Returns the version number for an invalid cache entry
311  unsigned _GetInvalidVersion() const { return _cacheVersion - 1; }
312 
313  // Initial version numbers
314  static unsigned _GetInitialCacheVersion() { return 1; }
315  static unsigned _GetInitialEntryVersion() {
316  return _GetInitialCacheVersion()-1;
317  }
318 
319  // Traverse the hierarchy (order is strategy dependent) and compute the
320  // inherited value.
321  value_type const* _GetValue(const UsdPrim& prim) const;
322 
323  // Helper function to get or create a new entry for a prim in the cache.
324  _Entry* _GetCacheEntryForPrim(const UsdPrim &prim) const;
325 
326  // Sets the value of the given cache entry. If multiple threads attempt to
327  // set the same entry, the first in wins and other threads spin until the
328  // new value is set.
329  void _SetCacheEntryForPrim(const UsdPrim &prim,
330  value_type const& value,
331  _Entry* entry) const;
332 
333  // Mutable is required here to allow const methods to update the cache when
334  // it is thread safe, however not all mutations of this map are thread safe.
335  // See underlying map documentation for details.
336  mutable _CacheMap _cache;
337 
338  // The time at which this stack is querying and caching attribute values.
339  UsdTimeCode _time;
340  SdfPath _rootPath;
341 
342  // A serial number indicating the valid state of entries in the cache. When
343  // an entry has an equal or greater value, the entry is valid.
344  tbb::atomic<unsigned> _cacheVersion;
345 
346  // Value overrides for a set of descendents.
347  ValueOverridesMap _valueOverrides;
348 
349  // Supplemental cache if used by this inherited cache.
350  ImplData *_implData;
351 };
352 
353 template<typename Strategy, typename ImplData>
354 void
355 UsdImaging_ResolvedAttributeCache<Strategy,ImplData>::_SetCacheEntryForPrim(
356  const UsdPrim &prim,
357  value_type const& value,
358  _Entry* entry) const
359 {
360  // Note: _cacheVersion is not allowed to change during cache access.
361  unsigned v = entry->version;
362  if (v < _cacheVersion
363  && entry->version.compare_and_swap(_cacheVersion, v) == v)
364  {
365  entry->value = value;
366  entry->version = _GetValidVersion();
367  } else {
368  while (entry->version != _GetValidVersion()) {
369  // Future work: A suggestion is that rather than literally spinning
370  // here, we should use the pause instruction, which sleeps for one
371  // cycle while allowing hyper threads to continue. Folly has a nice
372  // implementation of this packaged up as "sleeper", which we could
373  // also implement in Work and Arch.
374  }
375  }
376 }
377 
378 template<typename Strategy, typename ImplData>
379 typename UsdImaging_ResolvedAttributeCache<Strategy, ImplData>::_Entry*
380 UsdImaging_ResolvedAttributeCache<Strategy, ImplData>::_GetCacheEntryForPrim(
381  const UsdPrim &prim) const
382 {
383  typename _CacheMap::const_iterator it = _cache.find(prim);
384  if (it != _cache.end()) {
385  return &it->second;
386  }
387 
388  _Entry e;
389  e.query = Strategy::MakeQuery(prim, _implData);
390  e.value = Strategy::MakeDefault();
391  e.version = _GetInvalidVersion();
392  return &(_cache.insert(
393  typename _CacheMap::value_type(prim, e)).first->second);
394 }
395 
396 template<typename Strategy, typename ImplData>
397 typename UsdImaging_ResolvedAttributeCache<Strategy, ImplData>::value_type const*
398 UsdImaging_ResolvedAttributeCache<Strategy, ImplData>::_GetValue(
399  const UsdPrim& prim) const
400 {
401  static value_type const default_ = Strategy::MakeDefault();
402 
403  // Base case.
404  if (!prim || prim.IsPrototype() || prim.GetPath() == _rootPath)
405  return &default_;
406 
407  _Entry* entry = _GetCacheEntryForPrim(prim);
408  if (entry->version == _GetValidVersion()) {
409  // Cache hit
410  return &entry->value;
411  }
412 
413  // Future work: Suggestion is that when multiple threads are computing the
414  // same value, we could block all but one thread here, possibly rescheduling
415  // blocked threads as continuations, rather than allowing all threads to
416  // continue to race until a cache hit is encountered.
417 
418  // Future work: A suggestion is that we make this iterative instead of
419  // recursive.
420  typename ValueOverridesMap::const_iterator it =
421  _valueOverrides.find(prim);
422  if (it != _valueOverrides.end()) {
423  _SetCacheEntryForPrim(prim, it->second, entry);
424  } else {
425  _SetCacheEntryForPrim(prim,
426  Strategy::Compute(this, prim, &entry->query),
427  entry);
428  }
429  return &entry->value;
430 }
431 
432 PXR_NAMESPACE_CLOSE_SCOPE
433 
434 // -------------------------------------------------------------------------- //
435 // Xform Cache
436 // -------------------------------------------------------------------------- //
437 
439 #include "pxr/base/gf/matrix4d.h"
440 
441 PXR_NAMESPACE_OPEN_SCOPE
442 
443 struct UsdImaging_XfStrategy;
444 typedef UsdImaging_ResolvedAttributeCache<UsdImaging_XfStrategy> UsdImaging_XformCache;
445 
446 struct UsdImaging_XfStrategy {
447  typedef GfMatrix4d value_type;
448  typedef UsdGeomXformable::XformQuery query_type;
449 
450  static
451  bool ValueMightBeTimeVarying() { return true; }
452  static
453  value_type MakeDefault() { return GfMatrix4d(1); }
454 
455  static
456  query_type MakeQuery(UsdPrim const& prim, bool *) {
457  if (UsdGeomXformable xf = UsdGeomXformable(prim))
458  return query_type(xf);
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,
485  const TfHashMap<SdfPath, GfMatrix4d, SdfPath::Hash> &ctmOverrides)
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 
509 PXR_NAMESPACE_CLOSE_SCOPE
510 
511 // -------------------------------------------------------------------------- //
512 // Visibility Cache
513 // -------------------------------------------------------------------------- //
514 
516 #include "pxr/base/tf/token.h"
517 #include "pxr/usdImaging/usdImaging/debugCodes.h"
518 
519 PXR_NAMESPACE_OPEN_SCOPE
520 
521 struct UsdImaging_VisStrategy;
522 using UsdImaging_VisCache =
523  UsdImaging_ResolvedAttributeCache<UsdImaging_VisStrategy>;
524 
528 struct UsdImaging_VisStrategy {
529  typedef TfToken value_type; // invisible, inherited
530  typedef UsdAttributeQuery query_type;
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
570  ComputeVisibility(UsdPrim const& prim, UsdTimeCode time)
571  {
572  return UsdGeomImageable(prim).ComputeVisibility(time);
573  }
574 };
575 
576 // -------------------------------------------------------------------------- //
577 // Purpose Cache
578 // -------------------------------------------------------------------------- //
579 
580 struct UsdImaging_PurposeStrategy;
581 typedef UsdImaging_ResolvedAttributeCache<UsdImaging_PurposeStrategy>
582  UsdImaging_PurposeCache;
583 
584 struct UsdImaging_PurposeStrategy {
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
589  typedef UsdAttributeQuery query_type;
590 
591  static
592  value_type MakeDefault() {
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 *) {
600  return im ? query_type(im.GetPurposeAttr()) : query_type();
601  }
602 
603  static
604  value_type
605  Compute(UsdImaging_PurposeCache const* owner,
606  UsdPrim const& prim,
607  query_type const* query)
608  {
609  // Fallback to parent if the prim isn't imageable or doesn't have a
610  // purpose attribute. Note that this returns the default purpose if
611  // there's no parent prim.
612  if (!*query) {
613  return *(owner->_GetValue(prim.GetParent()));
614  }
615 
616  // If the prim has an authored purpose value, we get and use that.
617  if (query->HasAuthoredValue()) {
618  value_type info;
619  query->Get(&info.purpose);
620  info.isInheritable = true;
621  return info;
622  }
623 
624  // Otherwise we inherit parent's purpose value, but only if the parent's
625  // purpose is inheritable. An inherited purpose is itself inheritable
626  // by child prims..
627  const value_type *v = owner->_GetValue(prim.GetParent());
628  if (v->isInheritable) {
629  return *v;
630  }
631 
632  // Otherwise, get the fallback value. The fallback purpose will not
633  // be inherited by descendants.
634  value_type info;
635  query->Get(&info.purpose);
636  return info;
637  }
638 
639  static
640  value_type
641  ComputePurposeInfo(UsdPrim const& prim)
642  {
643  return UsdGeomImageable(prim).ComputePurposeInfo();
644  }
645 };
646 
647 PXR_NAMESPACE_CLOSE_SCOPE
648 
649 // -------------------------------------------------------------------------- //
650 // Hydra MaterialBinding Cache
651 // -------------------------------------------------------------------------- //
652 
655 
656 PXR_NAMESPACE_OPEN_SCOPE
657 
658 struct UsdImaging_MaterialBindingImplData {
661  UsdImaging_MaterialBindingImplData(const TfToken &materialPurpose):
662  _materialPurpose(materialPurpose)
663  { }
664 
667  ~UsdImaging_MaterialBindingImplData() {
668  ClearCaches();
669  }
670 
672  const TfToken &GetMaterialPurpose() const {
673  return _materialPurpose;
674  }
675 
678  UsdShadeMaterialBindingAPI::BindingsCache & GetBindingsCache()
679  { return _bindingsCache; }
680 
683  UsdShadeMaterialBindingAPI::CollectionQueryCache & GetCollectionQueryCache()
684  { return _collQueryCache; }
685 
687  void ClearCaches();
688 
689 private:
690  const TfToken _materialPurpose;
693 };
694 
695 struct UsdImaging_MaterialStrategy;
696 typedef UsdImaging_ResolvedAttributeCache<UsdImaging_MaterialStrategy,
697  UsdImaging_MaterialBindingImplData>
698  UsdImaging_MaterialBindingCache;
699 
700 struct UsdImaging_MaterialStrategy {
701  typedef SdfPath value_type; // inherited path to bound shader
702  typedef UsdShadeMaterial query_type;
703 
704  using ImplData = UsdImaging_MaterialBindingImplData;
705 
706  static
707  bool ValueMightBeTimeVarying() { return false; }
708  static
709  value_type MakeDefault() { return SdfPath(); }
710 
711  static
712  query_type MakeQuery(
713  UsdPrim const& prim,
714  ImplData *implData)
715  {
717  &implData->GetBindingsCache(),
718  &implData->GetCollectionQueryCache(),
719  implData->GetMaterialPurpose());
720  }
721 
722  static
723  value_type
724  Compute(UsdImaging_MaterialBindingCache const* owner,
725  UsdPrim const& prim,
726  query_type const* query)
727  {
728  TF_DEBUG(USDIMAGING_SHADERS).Msg("Looking for \"preview\" material "
729  "binding for %s\n", prim.GetPath().GetText());
730  if (*query) {
731  SdfPath binding = query->GetPath();
732  if (!binding.IsEmpty()) {
733  return binding;
734  }
735  }
736  // query already contains the resolved material binding for the prim.
737  // Hence, we don't need to inherit the binding from the parent here.
738  // Futhermore, it may be wrong to inherit the binding from the parent,
739  // because in the new scheme, a child of a bound prim can be unbound.
740  return value_type();
741  }
742 
743  static
744  value_type
745  ComputeMaterialPath(UsdPrim const& prim, ImplData *implData) {
746  // We don't need to walk up the namespace here since
747  // ComputeBoundMaterial does it for us.
749  ComputeBoundMaterial(&implData->GetBindingsCache(),
750  &implData->GetCollectionQueryCache(),
751  implData->GetMaterialPurpose())) {
752  return mat.GetPath();
753  }
754  return value_type();
755  }
756 };
757 
758 PXR_NAMESPACE_CLOSE_SCOPE
759 
760 // -------------------------------------------------------------------------- //
761 // ModelDrawMode Cache
762 // -------------------------------------------------------------------------- //
763 
765 
766 PXR_NAMESPACE_OPEN_SCOPE
767 
768 struct UsdImaging_DrawModeStrategy;
769 typedef UsdImaging_ResolvedAttributeCache<UsdImaging_DrawModeStrategy>
770  UsdImaging_DrawModeCache;
771 
772 struct UsdImaging_DrawModeStrategy
773 {
774  typedef TfToken value_type; // origin, bounds, cards, default, inherited
775  typedef UsdAttributeQuery query_type;
776 
777  static
778  bool ValueMightBeTimeVarying() { return false; }
779  static
780  value_type MakeDefault() { return UsdGeomTokens->default_; }
781 
782  static
783  query_type MakeQuery(UsdPrim const& prim, bool *) {
784  if (UsdAttribute a = UsdGeomModelAPI(prim).GetModelDrawModeAttr())
785  return query_type(a);
786  return query_type();
787  }
788 
789  static
790  value_type
791  Compute(UsdImaging_DrawModeCache const* owner,
792  UsdPrim const& prim,
793  query_type const* query)
794  {
795  // No attribute defined means inherited, means refer to the parent.
796  // Any defined attribute overrides parent opinion.
797  // If the drawMode is inherited all the way to the root of the scene,
798  // that means "default".
799  value_type v = UsdGeomTokens->inherited;
800  if (*query) {
801  query->Get(&v);
802  }
803  if (v != UsdGeomTokens->inherited) {
804  return v;
805  }
806  v = *owner->_GetValue(prim.GetParent());
807  if (v == UsdGeomTokens->inherited) {
808  return UsdGeomTokens->default_;
809  }
810  return v;
811  }
812 
813  static
814  value_type
815  ComputeDrawMode(UsdPrim const& prim)
816  {
817  return UsdGeomModelAPI(prim).ComputeModelDrawMode();
818  }
819 };
820 
821 PXR_NAMESPACE_CLOSE_SCOPE
822 
823 // -------------------------------------------------------------------------- //
824 // UsdGeomPointInstancer indices cache
825 // -------------------------------------------------------------------------- //
826 
828 
829 PXR_NAMESPACE_OPEN_SCOPE
830 
831 struct UsdImaging_PointInstancerIndicesStrategy;
832 typedef UsdImaging_ResolvedAttributeCache<UsdImaging_PointInstancerIndicesStrategy>
833  UsdImaging_PointInstancerIndicesCache;
834 
835 struct UsdImaging_PointInstancerIndicesStrategy
836 {
837  // map from protoIndex -> instanceIndices.
838  typedef VtArray<VtIntArray> value_type;
839  // We don't use query_type, but can't set it to void.
840  typedef int query_type;
841 
842  // XXX: Most indices values will be static, but since they *can*
843  // be animated, we need to return true here to get invalidation on
844  // time-change. It would be nice to add a per-entry time-varying bit
845  // to the resolved cache, instead of having the global per-attribute
846  // bit.
847  //
848  // In this particular case, instance indices are only recomputed when
849  // we see "DirtyInstanceIndex" in UpdateForTime, so though we'll be
850  // clearing cache entries out of the resolved cache on time-change,
851  // we won't actually call out to the attribute cache on static indices.
852  static
853  bool ValueMightBeTimeVarying() { return true; }
854  static
855  value_type MakeDefault() { return value_type(); }
856 
857  static
858  query_type MakeQuery(UsdPrim const& prim, bool *) {
859  return 0;
860  }
861 
862  static
863  value_type
864  Compute(UsdImaging_PointInstancerIndicesCache const* owner,
865  UsdPrim const& prim,
866  query_type const* query)
867  {
868  return ComputePerPrototypeIndices(prim, owner->GetTime());
869  }
870 
871  static
872  value_type
873  ComputePerPrototypeIndices(UsdPrim const& prim, UsdTimeCode time)
874  {
875  value_type v;
876 
877  UsdGeomPointInstancer pi(prim);
878  VtIntArray protoIndices;
879  if (!pi.GetProtoIndicesAttr().Get(&protoIndices, time)) {
880  TF_WARN("Failed to read point instancer protoIndices");
881  return v;
882  }
883 
884  std::vector<bool> mask = pi.ComputeMaskAtTime(time);
885 
886  for (size_t instanceId = 0; instanceId < protoIndices.size(); ++instanceId) {
887  size_t protoIndex = protoIndices[instanceId];
888 
889  if (protoIndex >= v.size()) {
890  v.resize(protoIndex + 1);
891  }
892 
893  if (mask.size() == 0 || mask[instanceId]) {
894  v[protoIndex].push_back(instanceId);
895  }
896  }
897 
898  return v;
899  }
900 };
901 
902 PXR_NAMESPACE_CLOSE_SCOPE
903 
904 // -------------------------------------------------------------------------- //
905 // CoordSysBinding Cache
906 // -------------------------------------------------------------------------- //
907 
909 #include "pxr/imaging/hd/coordSys.h"
910 
911 PXR_NAMESPACE_OPEN_SCOPE
912 
913 struct UsdImaging_CoordSysBindingImplData {
914  // Helper provided by the scene delegate to pre-convert
915  // the binding paths to the equivalent Hydra ID.
916  std::function<SdfPath(SdfPath)> usdToHydraPath;
917 };
918 
919 struct UsdImaging_CoordSysBindingStrategy;
920 
921 typedef UsdImaging_ResolvedAttributeCache<
922  UsdImaging_CoordSysBindingStrategy,
923  UsdImaging_CoordSysBindingImplData>
924  UsdImaging_CoordSysBindingCache;
925 
926 struct UsdImaging_CoordSysBindingStrategy
927 {
928  using ImplData = UsdImaging_CoordSysBindingImplData;
929 
930  typedef std::vector<UsdShadeCoordSysAPI::Binding> UsdBindingVec;
931  typedef std::shared_ptr<UsdBindingVec> UsdBindingVecPtr;
932  typedef std::shared_ptr<SdfPathVector> IdVecPtr;
933 
934  struct value_type {
935  IdVecPtr idVecPtr;
936  UsdBindingVecPtr usdBindingVecPtr;
937  };
938  struct query_type {
939  UsdShadeCoordSysAPI coordSysAPI;
940  ImplData *implData;
941 
942  // Convert a USD binding relationship to a Hydra ID
943  SdfPath
944  _IdForBinding(UsdShadeCoordSysAPI::Binding const& binding) const {
945  return implData->usdToHydraPath(binding.bindingRelPath);
946  }
947  };
948 
949  static
950  bool ValueMightBeTimeVarying() { return false; }
951 
952  static
953  value_type MakeDefault() {
954  return value_type();
955  }
956 
957  static
958  query_type MakeQuery(UsdPrim const& prim, ImplData *implData) {
959  return query_type({ UsdShadeCoordSysAPI(prim), implData });
960  }
961 
962  static
963  value_type
964  Compute(UsdImaging_CoordSysBindingCache const* owner,
965  UsdPrim const& prim,
966  query_type const* query)
967  {
968  value_type v;
969  if (query->coordSysAPI) {
970  // Pull inherited bindings first.
971  if (UsdPrim parentPrim = prim.GetParent()) {
972  v = *owner->_GetValue(parentPrim);
973  }
974  // Merge any local bindings.
975  if (query->coordSysAPI.HasLocalBindings()) {
976  SdfPathVector hdIds;
977  UsdBindingVec usdBindings;
978  if (v.idVecPtr) {
979  hdIds = *v.idVecPtr;
980  }
981  if (v.usdBindingVecPtr) {
982  usdBindings = *v.usdBindingVecPtr;
983  }
984  for (auto const& binding:
985  query->coordSysAPI.GetLocalBindings()) {
986  if (!prim.GetStage()->GetPrimAtPath(
987  binding.coordSysPrimPath).IsValid()) {
988  // The target xform prim does not exist, so ignore
989  // this coord sys binding.
990  TF_WARN("UsdImaging: Ignoring coordinate system "
991  "binding to non-existent prim <%s>\n",
992  binding.coordSysPrimPath.GetText());
993  continue;
994  }
995  bool found = false;
996  for (size_t i=0, n=hdIds.size(); i<n; ++i) {
997  if (usdBindings[i].name == binding.name) {
998  // Found an override -- replace this binding.
999  usdBindings[i] = binding;
1000  hdIds[i] = query->_IdForBinding(binding);
1001  found = true;
1002  break;
1003  }
1004  }
1005  if (!found) {
1006  // New binding, so append.
1007  usdBindings.push_back(binding);
1008  hdIds.push_back(query->_IdForBinding(binding));
1009  }
1010  }
1011  v.idVecPtr.reset(new SdfPathVector(hdIds));
1012  v.usdBindingVecPtr.reset(new UsdBindingVec(usdBindings));
1013  }
1014  }
1015  return v;
1016  }
1017 };
1018 
1019 PXR_NAMESPACE_CLOSE_SCOPE
1020 
1021 // -------------------------------------------------------------------------- //
1022 // Inherited Primvar Cache
1023 // -------------------------------------------------------------------------- //
1024 
1026 
1027 PXR_NAMESPACE_OPEN_SCOPE
1028 
1029 struct UsdImaging_InheritedPrimvarStrategy;
1030 typedef UsdImaging_ResolvedAttributeCache<UsdImaging_InheritedPrimvarStrategy>
1031  UsdImaging_InheritedPrimvarCache;
1032 
1033 struct UsdImaging_InheritedPrimvarStrategy
1034 {
1035  struct PrimvarRecord {
1036  std::vector<UsdGeomPrimvar> primvars;
1037  bool variable;
1038  };
1039  typedef std::shared_ptr<PrimvarRecord> value_type;
1040  typedef UsdGeomPrimvarsAPI query_type;
1041 
1042  // While primvar data might be time-varying, the set of primvars applying
1043  // to a prim will not.
1044  static
1045  bool ValueMightBeTimeVarying() { return false; }
1046 
1047  static
1048  value_type MakeDefault() {
1049  return value_type();
1050  }
1051 
1052  static
1053  query_type MakeQuery(UsdPrim const& prim, bool *) {
1054  return query_type(UsdGeomPrimvarsAPI(prim));
1055  }
1056 
1057  static
1058  value_type Compute(UsdImaging_InheritedPrimvarCache const* owner,
1059  UsdPrim const& prim,
1060  query_type const* query)
1061  {
1062  value_type v;
1063  if (*query) {
1064  // Pull inherited bindings first.
1065  if (UsdPrim parentPrim = prim.GetParent()) {
1066  v = *owner->_GetValue(parentPrim);
1067  }
1068  // Merge any local bindings.
1069  std::vector<UsdGeomPrimvar> primvars =
1070  query->FindIncrementallyInheritablePrimvars(
1071  v ? v->primvars : std::vector<UsdGeomPrimvar>());
1072  if (!primvars.empty()) {
1073  v = std::make_shared<PrimvarRecord>();
1074  v->primvars = std::move(primvars);
1075  v->variable = false;
1076  for (UsdGeomPrimvar const& pv : v->primvars) {
1077  if (pv.ValueMightBeTimeVarying()) {
1078  v->variable = true;
1079  break;
1080  }
1081  }
1082  }
1083  }
1084  return v;
1085  }
1086 };
1087 
1088 PXR_NAMESPACE_CLOSE_SCOPE
1089 
1090 #endif
USD_API UsdStageWeakPtr GetStage() const
Return the stage that owns the object, and to whose state and lifetime this object&#39;s validity is tied...
UsdShadeCoordSysAPI provides a way to designate, name, and discover coordinate systems.
Definition: coordSysAPI.h:79
UsdGeomModelAPI extends the generic UsdModelAPI schema with geometry specific concepts such as cached...
Definition: modelAPI.h:148
USDGEOM_API UsdAttribute GetPurposeAttr() const
Purpose is a classification of geometry into categories that can each be independently included or ex...
UsdPrim GetParent() const
Return this prim&#39;s parent prim.
Definition: prim.h:1038
Object for efficiently making repeated queries for attribute values.
#define TF_WARN(...)
Issue a warning, but continue execution.
Definition: diagnostic.h:149
tbb::concurrent_unordered_map< SdfPath, std::unique_ptr< UsdCollectionAPI::MembershipQuery >, SdfPath::Hash > CollectionQueryCache
An unordered list of collection paths mapped to the associated collection&#39;s MembershipQuery object...
#define TF_CODING_ERROR(fmt, args)
Issue an internal programming error, but continue execution.
Definition: diagnostic.h:85
SdfPath GetPath() const
Return the complete scene path to this object on its UsdStage, which may (UsdPrim) or may not (all ot...
Definition: object.h:194
SDF_API bool IsAbsolutePath() const
Returns whether the path is absolute.
Scenegraph object for authoring and retrieving numeric, string, and array valued data, sampled over time.
Definition: attribute.h:176
bool IsPrototype() const
Return true if this prim is an instancing prototype prim, false otherwise.
Definition: prim.h:1559
tbb::concurrent_unordered_map< SdfPath, std::unique_ptr< BindingsAtPrim >, SdfPath::Hash > BindingsCache
An unordered list of prim-paths mapped to the corresponding set of bindings at the associated prim...
A coordinate system binding.
Definition: coordSysAPI.h:163
UsdShadeMaterialBindingAPI is an API schema that provides an interface for binding materials to prims...
UsdGeomPrimvarsAPI encodes geometric &quot;primitive variables&quot;, as UsdGeomPrimvar, which interpolate ac...
Definition: primvarsAPI.h:82
bool IsInPrototype() const
Return true if this prim is a prototype prim or a descendant of a prototype prim, false otherwise...
Definition: prim.h:1565
Helper class that caches the ordered vector of UsGeomXformOps that contribute to the local transforma...
Definition: xformable.h:379
Token for efficient comparison, assignment, and hashing of known strings.
Definition: token.h:87
USDGEOM_API TfToken ComputeModelDrawMode(const TfToken &parentDrawMode=TfToken()) const
Calculate the effective model:drawMode of this prim.
USDSHADE_API UsdShadeMaterial ComputeBoundMaterial(BindingsCache *bindingsCache, CollectionQueryCache *collectionQueryCache, const TfToken &materialPurpose=UsdShadeTokens->allPurpose, UsdRelationship *bindingRel=nullptr) const
This is an overloaded member function, provided for convenience. It differs from the above function o...
#define TF_FOR_ALL(iter, c)
Macro for iterating over a container.
Definition: iterator.h:390
Stores a 4x4 matrix of double elements.
Definition: matrix4d.h:88
Represent a time value, which may be either numeric, holding a double value, or a sentinel value UsdT...
Definition: timeCode.h:85
USDGEOM_API TfStaticData< UsdGeomTokensType > UsdGeomTokens
A global variable with static, efficient TfTokens for use in all public USD API.
Value type containing information about a prim&#39;s computed effective purpose as well as storing whethe...
Definition: imageable.h:391
#define TRACE_FUNCTION()
Records a timestamp when constructed and a timespan event when destructed, using the name of the func...
Definition: trace.h:43
UsdPrim is the sole persistent scenegraph object on a UsdStage, and is the embodiment of a &quot;Prim&quot; as ...
Definition: prim.h:132
USDGEOM_API bool ValueMightBeTimeVarying() const
Return true if it is possible, but not certain, that this primvar&#39;s value changes over time...
Represents an arbitrary dimensional rectangular container class.
Definition: array.h:229
A path value used to locate objects in layers or scenegraphs.
Definition: path.h:288
#define TF_DEBUG(enumVal)
Evaluate and print debugging message msg if enumVal is enabled for debugging.
Definition: debug.h:501
SDF_API const std::string & GetString() const
Return the string representation of this path as a std::string.
USDGEOM_API PurposeInfo ComputePurposeInfo() const
Calculate the effective purpose information about this prim which includes final computed purpose val...
SDF_API bool HasPrefix(const SdfPath &prefix) const
Return true if both this path and prefix are not the empty path and this path has prefix as a prefix...
An forward-iterable range that traverses a subtree of prims rooted at a given prim in depth-first ord...
Definition: primRange.h:118
A Material provides a container into which multiple &quot;render targets&quot; can add data that defines a &quot;sha...
Definition: material.h:111
Encodes vectorized instancing of multiple, potentially animated, prototypes (object/instance masters)...
Schema wrapper for UsdAttribute for authoring and introspecting attributes that are primvars...
Definition: primvar.h:260
void WorkSwapDestroyAsync(T &obj)
Swap obj with a default-constructed T instance, return and arrange for the swapped-out instance to be...
Definition: utils.h:83
USDGEOM_API TfToken ComputeVisibility(UsdTimeCode const &time=UsdTimeCode::Default()) const
Calculate the effective visibility of this prim, as defined by its most ancestral authored &quot;invisible...
bool IsEmpty() const noexcept
Returns true if this is the empty path (SdfPath::EmptyPath()).
Definition: path.h:417
Base class for all prims that may require rendering or visualization of some sort.
Definition: imageable.h:74
Base class for all transformable prims, which allows arbitrary sequences of component affine transfor...
Definition: xformable.h:252
SDF_API const char * GetText() const
Returns the string representation of this path as a c string.
TfToken class for efficient string referencing and hashing, plus conversions to and from stl string c...