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 (const UsdGeomXformable xf = UsdGeomXformable(prim)) {
458  return query_type(xf);
459  }
460  return query_type();
461  }
462 
463  static
464  value_type
465  Compute(UsdImaging_XformCache const* owner,
466  UsdPrim const& prim,
467  query_type const* query)
468  {
469  value_type xform = MakeDefault();
470  // No need to check query validity here because XformQuery doesn't
471  // support it.
472  query->GetLocalTransformation(&xform, owner->GetTime());
473 
474  return !query->GetResetXformStack()
475  ? (xform * (*owner->_GetValue(prim.GetParent())))
476  : xform;
477  }
478 
479  // Compute the full transform, this is not part of the interface required by
480  // the cache.
481  static
482  value_type
483  ComputeTransform(UsdPrim const& prim,
484  SdfPath const& rootPath,
485  UsdTimeCode time,
486  const TfHashMap<SdfPath, GfMatrix4d, SdfPath::Hash> &ctmOverrides)
487  {
488  bool reset = false;
489  GfMatrix4d ctm(1.0);
490  GfMatrix4d localXf(1.0);
491  UsdPrim p = prim;
492  while (p && p.GetPath() != rootPath) {
493  const auto &overIt = ctmOverrides.find(p.GetPath());
494  // If there's a ctm override, use it and break out of the loop.
495  if (overIt != ctmOverrides.end()) {
496  ctm *= overIt->second;
497  break;
498  } else if (UsdGeomXformable xf = UsdGeomXformable(p)) {
499  if (xf.GetLocalTransformation(&localXf, &reset, time))
500  ctm *= localXf;
501  if (reset)
502  break;
503  }
504  p = p.GetParent();
505  }
506  return ctm;
507  }
508 };
509 
510 PXR_NAMESPACE_CLOSE_SCOPE
511 
512 // -------------------------------------------------------------------------- //
513 // Visibility Cache
514 // -------------------------------------------------------------------------- //
515 
517 #include "pxr/base/tf/token.h"
518 #include "pxr/usdImaging/usdImaging/debugCodes.h"
519 
520 PXR_NAMESPACE_OPEN_SCOPE
521 
522 struct UsdImaging_VisStrategy;
523 using UsdImaging_VisCache =
524  UsdImaging_ResolvedAttributeCache<UsdImaging_VisStrategy>;
525 
529 struct UsdImaging_VisStrategy {
530  typedef TfToken value_type; // invisible, inherited
531  typedef UsdAttributeQuery query_type;
532 
533  static
534  bool ValueMightBeTimeVarying() { return true; }
535 
536  static
537  value_type MakeDefault() { return UsdGeomTokens->inherited; }
538 
539  static
540  query_type MakeQuery(UsdPrim const& prim, bool *)
541  {
542  if (const UsdGeomImageable xf = UsdGeomImageable(prim)) {
543  return query_type(xf.GetVisibilityAttr());
544  }
545  return query_type();
546  }
547 
548  static
549  value_type
550  Compute(UsdImaging_VisCache const* owner,
551  UsdPrim const& prim,
552  query_type const* query)
553  {
554  value_type v = *owner->_GetValue(prim.GetParent());
555 
556  // If prim inherits 'invisible', then it's invisible, due to pruning
557  // visibility.
558  if (v == UsdGeomTokens->invisible) {
559  return v;
560  }
561 
562  // Otherwise, prim's value, if it has one, determines its visibility.
563  if (*query) {
564  query->Get(&v, owner->GetTime());
565  }
566  return v;
567  }
568 
569  static
570  value_type
571  ComputeVisibility(UsdPrim const& prim, UsdTimeCode time)
572  {
573  return UsdGeomImageable(prim).ComputeVisibility(time);
574  }
575 };
576 
577 // -------------------------------------------------------------------------- //
578 // Purpose Cache
579 // -------------------------------------------------------------------------- //
580 
581 struct UsdImaging_PurposeStrategy;
582 typedef UsdImaging_ResolvedAttributeCache<UsdImaging_PurposeStrategy>
583  UsdImaging_PurposeCache;
584 
585 struct UsdImaging_PurposeStrategy {
586  // For proper inheritance, we need to return the PurposeInfo struct which
587  // stores whether child prims can inherit the parent's computed purpose
588  // when they don't have an authored purpose of their own.
589  typedef UsdGeomImageable::PurposeInfo value_type; // purpose, inherited
590  typedef UsdAttributeQuery query_type;
591 
592  static
593  value_type MakeDefault() {
594  // Return the fallback default instead of an empty purpose info.
595  return value_type(UsdGeomTokens->default_, false);
596  }
597 
598  static
599  query_type MakeQuery(UsdPrim const& prim, bool *) {
600  if (const UsdGeomImageable im = UsdGeomImageable(prim)) {
601  return query_type(im.GetPurposeAttr());
602  }
603  return query_type();
604  }
605 
606  static
607  value_type
608  Compute(UsdImaging_PurposeCache const* owner,
609  UsdPrim const& prim,
610  query_type const* query)
611  {
612  // Fallback to parent if the prim isn't imageable or doesn't have a
613  // purpose attribute. Note that this returns the default purpose if
614  // there's no parent prim.
615  if (!*query) {
616  return *(owner->_GetValue(prim.GetParent()));
617  }
618 
619  // If the prim has an authored purpose value, we get and use that.
620  if (query->HasAuthoredValue()) {
621  value_type info;
622  query->Get(&info.purpose);
623  info.isInheritable = true;
624  return info;
625  }
626 
627  // Otherwise we inherit parent's purpose value, but only if the parent's
628  // purpose is inheritable. An inherited purpose is itself inheritable
629  // by child prims..
630  const value_type *v = owner->_GetValue(prim.GetParent());
631  if (v->isInheritable) {
632  return *v;
633  }
634 
635  // Otherwise, get the fallback value. The fallback purpose will not
636  // be inherited by descendants.
637  value_type info;
638  query->Get(&info.purpose);
639  return info;
640  }
641 
642  static
643  value_type
644  ComputePurposeInfo(UsdPrim const& prim)
645  {
646  return UsdGeomImageable(prim).ComputePurposeInfo();
647  }
648 };
649 
650 PXR_NAMESPACE_CLOSE_SCOPE
651 
652 // -------------------------------------------------------------------------- //
653 // Hydra MaterialBinding Cache
654 // -------------------------------------------------------------------------- //
655 
658 
659 PXR_NAMESPACE_OPEN_SCOPE
660 
661 struct UsdImaging_MaterialBindingImplData {
664  UsdImaging_MaterialBindingImplData(const TfToken &materialPurpose):
665  _materialPurpose(materialPurpose)
666  { }
667 
670  ~UsdImaging_MaterialBindingImplData() {
671  ClearCaches();
672  }
673 
675  const TfToken &GetMaterialPurpose() const {
676  return _materialPurpose;
677  }
678 
681  UsdShadeMaterialBindingAPI::BindingsCache & GetBindingsCache()
682  { return _bindingsCache; }
683 
686  UsdShadeMaterialBindingAPI::CollectionQueryCache & GetCollectionQueryCache()
687  { return _collQueryCache; }
688 
690  void ClearCaches();
691 
692 private:
693  const TfToken _materialPurpose;
696 };
697 
698 struct UsdImaging_MaterialStrategy;
699 typedef UsdImaging_ResolvedAttributeCache<UsdImaging_MaterialStrategy,
700  UsdImaging_MaterialBindingImplData>
701  UsdImaging_MaterialBindingCache;
702 
703 struct UsdImaging_MaterialStrategy {
704  typedef SdfPath value_type; // inherited path to bound shader
705  typedef UsdShadeMaterial query_type;
706 
707  using ImplData = UsdImaging_MaterialBindingImplData;
708 
709  static
710  bool ValueMightBeTimeVarying() { return false; }
711  static
712  value_type MakeDefault() { return SdfPath(); }
713 
714  static
715  query_type MakeQuery(
716  UsdPrim const& prim,
717  ImplData *implData)
718  {
720  &implData->GetBindingsCache(),
721  &implData->GetCollectionQueryCache(),
722  implData->GetMaterialPurpose());
723  }
724 
725  static
726  value_type
727  Compute(UsdImaging_MaterialBindingCache const* owner,
728  UsdPrim const& prim,
729  query_type const* query)
730  {
731  TF_DEBUG(USDIMAGING_SHADERS).Msg("Looking for \"preview\" material "
732  "binding for %s\n", prim.GetPath().GetText());
733  if (*query) {
734  SdfPath binding = query->GetPath();
735  if (!binding.IsEmpty()) {
736  return binding;
737  }
738  }
739  // query already contains the resolved material binding for the prim.
740  // Hence, we don't need to inherit the binding from the parent here.
741  // Futhermore, it may be wrong to inherit the binding from the parent,
742  // because in the new scheme, a child of a bound prim can be unbound.
743  return value_type();
744  }
745 
746  static
747  value_type
748  ComputeMaterialPath(UsdPrim const& prim, ImplData *implData) {
749  // We don't need to walk up the namespace here since
750  // ComputeBoundMaterial does it for us.
752  ComputeBoundMaterial(&implData->GetBindingsCache(),
753  &implData->GetCollectionQueryCache(),
754  implData->GetMaterialPurpose())) {
755  return mat.GetPath();
756  }
757  return value_type();
758  }
759 };
760 
761 PXR_NAMESPACE_CLOSE_SCOPE
762 
763 // -------------------------------------------------------------------------- //
764 // ModelDrawMode Cache
765 // -------------------------------------------------------------------------- //
766 
768 
769 PXR_NAMESPACE_OPEN_SCOPE
770 
771 struct UsdImaging_DrawModeStrategy;
772 typedef UsdImaging_ResolvedAttributeCache<UsdImaging_DrawModeStrategy>
773  UsdImaging_DrawModeCache;
774 
775 struct UsdImaging_DrawModeStrategy
776 {
777  typedef TfToken value_type; // origin, bounds, cards, default, inherited
778  typedef UsdAttributeQuery query_type;
779 
780  static
781  bool ValueMightBeTimeVarying() { return false; }
782  static
783  value_type MakeDefault() { return UsdGeomTokens->default_; }
784 
785  static
786  query_type MakeQuery(UsdPrim const& prim, bool *) {
787  if (const UsdGeomModelAPI modelApi = UsdGeomModelAPI(prim)) {
788  return query_type(modelApi.GetModelDrawModeAttr());
789  }
790  return query_type();
791  }
792 
793  static
794  value_type
795  Compute(UsdImaging_DrawModeCache const* owner,
796  UsdPrim const& prim,
797  query_type const* query)
798  {
799  // No attribute defined means inherited, means refer to the parent.
800  // Any defined attribute overrides parent opinion.
801  // If the drawMode is inherited all the way to the root of the scene,
802  // that means "default".
803  value_type v = UsdGeomTokens->inherited;
804  if (*query) {
805  query->Get(&v);
806  }
807  if (v != UsdGeomTokens->inherited) {
808  return v;
809  }
810  v = *owner->_GetValue(prim.GetParent());
811  if (v == UsdGeomTokens->inherited) {
812  return UsdGeomTokens->default_;
813  }
814  return v;
815  }
816 
817  static
818  value_type
819  ComputeDrawMode(UsdPrim const& prim)
820  {
821  return UsdGeomModelAPI(prim).ComputeModelDrawMode();
822  }
823 };
824 
825 PXR_NAMESPACE_CLOSE_SCOPE
826 
827 // -------------------------------------------------------------------------- //
828 // UsdGeomPointInstancer indices cache
829 // -------------------------------------------------------------------------- //
830 
832 
833 PXR_NAMESPACE_OPEN_SCOPE
834 
835 struct UsdImaging_PointInstancerIndicesStrategy;
836 typedef UsdImaging_ResolvedAttributeCache<UsdImaging_PointInstancerIndicesStrategy>
837  UsdImaging_PointInstancerIndicesCache;
838 
839 struct UsdImaging_PointInstancerIndicesStrategy
840 {
841  // map from protoIndex -> instanceIndices.
842  typedef VtArray<VtIntArray> value_type;
843  // We don't use query_type, but can't set it to void.
844  typedef int query_type;
845 
846  // XXX: Most indices values will be static, but since they *can*
847  // be animated, we need to return true here to get invalidation on
848  // time-change. It would be nice to add a per-entry time-varying bit
849  // to the resolved cache, instead of having the global per-attribute
850  // bit.
851  //
852  // In this particular case, instance indices are only recomputed when
853  // we see "DirtyInstanceIndex" in UpdateForTime, so though we'll be
854  // clearing cache entries out of the resolved cache on time-change,
855  // we won't actually call out to the attribute cache on static indices.
856  static
857  bool ValueMightBeTimeVarying() { return true; }
858  static
859  value_type MakeDefault() { return value_type(); }
860 
861  static
862  query_type MakeQuery(UsdPrim const& prim, bool *) {
863  return 0;
864  }
865 
866  static
867  value_type
868  Compute(UsdImaging_PointInstancerIndicesCache const* owner,
869  UsdPrim const& prim,
870  query_type const* query)
871  {
872  return ComputePerPrototypeIndices(prim, owner->GetTime());
873  }
874 
875  static
876  value_type
877  ComputePerPrototypeIndices(UsdPrim const& prim, UsdTimeCode time)
878  {
879  value_type v;
880 
881  UsdGeomPointInstancer pi(prim);
882  VtIntArray protoIndices;
883  if (!pi.GetProtoIndicesAttr().Get(&protoIndices, time)) {
884  TF_WARN("Failed to read point instancer protoIndices");
885  return v;
886  }
887 
888  std::vector<bool> mask = pi.ComputeMaskAtTime(time);
889 
890  for (size_t instanceId = 0; instanceId < protoIndices.size(); ++instanceId) {
891  size_t protoIndex = protoIndices[instanceId];
892 
893  if (protoIndex >= v.size()) {
894  v.resize(protoIndex + 1);
895  }
896 
897  if (mask.size() == 0 || mask[instanceId]) {
898  v[protoIndex].push_back(instanceId);
899  }
900  }
901 
902  return v;
903  }
904 };
905 
906 PXR_NAMESPACE_CLOSE_SCOPE
907 
908 // -------------------------------------------------------------------------- //
909 // CoordSysBinding Cache
910 // -------------------------------------------------------------------------- //
911 
913 #include "pxr/imaging/hd/coordSys.h"
914 
915 PXR_NAMESPACE_OPEN_SCOPE
916 
917 struct UsdImaging_CoordSysBindingImplData {
918  // Helper provided by the scene delegate to pre-convert
919  // the binding paths to the equivalent Hydra ID.
920  std::function<SdfPath(SdfPath)> usdToHydraPath;
921 };
922 
923 struct UsdImaging_CoordSysBindingStrategy;
924 
925 typedef UsdImaging_ResolvedAttributeCache<
926  UsdImaging_CoordSysBindingStrategy,
927  UsdImaging_CoordSysBindingImplData>
928  UsdImaging_CoordSysBindingCache;
929 
930 struct UsdImaging_CoordSysBindingStrategy
931 {
932  using ImplData = UsdImaging_CoordSysBindingImplData;
933 
934  typedef std::vector<UsdShadeCoordSysAPI::Binding> UsdBindingVec;
935  typedef std::shared_ptr<UsdBindingVec> UsdBindingVecPtr;
936  typedef std::shared_ptr<SdfPathVector> IdVecPtr;
937 
938  struct value_type {
939  IdVecPtr idVecPtr;
940  UsdBindingVecPtr usdBindingVecPtr;
941  };
942  struct query_type {
943  UsdShadeCoordSysAPI coordSysAPI;
944  ImplData *implData;
945 
946  // Convert a USD binding relationship to a Hydra ID
947  SdfPath
948  _IdForBinding(UsdShadeCoordSysAPI::Binding const& binding) const {
949  return implData->usdToHydraPath(binding.bindingRelPath);
950  }
951  };
952 
953  static
954  bool ValueMightBeTimeVarying() { return false; }
955 
956  static
957  value_type MakeDefault() {
958  return value_type();
959  }
960 
961  static
962  query_type MakeQuery(UsdPrim const& prim, ImplData *implData) {
963  return query_type({ UsdShadeCoordSysAPI(prim), implData });
964  }
965 
966  static
967  value_type
968  Compute(UsdImaging_CoordSysBindingCache const* owner,
969  UsdPrim const& prim,
970  query_type const* query)
971  {
972  value_type v;
973  if (query->coordSysAPI) {
974  // Pull inherited bindings first.
975  if (UsdPrim parentPrim = prim.GetParent()) {
976  v = *owner->_GetValue(parentPrim);
977  }
978  // Merge any local bindings.
979  if (query->coordSysAPI.HasLocalBindings()) {
980  SdfPathVector hdIds;
981  UsdBindingVec usdBindings;
982  if (v.idVecPtr) {
983  hdIds = *v.idVecPtr;
984  }
985  if (v.usdBindingVecPtr) {
986  usdBindings = *v.usdBindingVecPtr;
987  }
988  for (auto const& binding:
989  query->coordSysAPI.GetLocalBindings()) {
990  if (!prim.GetStage()->GetPrimAtPath(
991  binding.coordSysPrimPath).IsValid()) {
992  // The target xform prim does not exist, so ignore
993  // this coord sys binding.
994  TF_WARN("UsdImaging: Ignoring coordinate system "
995  "binding to non-existent prim <%s>\n",
996  binding.coordSysPrimPath.GetText());
997  continue;
998  }
999  bool found = false;
1000  for (size_t i=0, n=hdIds.size(); i<n; ++i) {
1001  if (usdBindings[i].name == binding.name) {
1002  // Found an override -- replace this binding.
1003  usdBindings[i] = binding;
1004  hdIds[i] = query->_IdForBinding(binding);
1005  found = true;
1006  break;
1007  }
1008  }
1009  if (!found) {
1010  // New binding, so append.
1011  usdBindings.push_back(binding);
1012  hdIds.push_back(query->_IdForBinding(binding));
1013  }
1014  }
1015  v.idVecPtr.reset(new SdfPathVector(hdIds));
1016  v.usdBindingVecPtr.reset(new UsdBindingVec(usdBindings));
1017  }
1018  }
1019  return v;
1020  }
1021 };
1022 
1023 PXR_NAMESPACE_CLOSE_SCOPE
1024 
1025 // -------------------------------------------------------------------------- //
1026 // Nonlinear sample count Primvar Cache
1027 // -------------------------------------------------------------------------- //
1028 
1029 #include "pxr/usd/usdGeom/motionAPI.h"
1030 
1031 PXR_NAMESPACE_OPEN_SCOPE
1032 
1033 struct UsdImaging_NonlinearSampleCountStrategy;
1034 typedef UsdImaging_ResolvedAttributeCache<
1035  UsdImaging_NonlinearSampleCountStrategy>
1036  UsdImaging_NonlinearSampleCountCache;
1037 
1038 struct UsdImaging_NonlinearSampleCountStrategy
1039 {
1040  typedef int value_type;
1041  typedef UsdAttributeQuery query_type;
1042 
1043  // Used to indicate that no (valid) opinion exists
1044  // for nonlinear sample count.
1045  static constexpr value_type invalidValue = -1;
1046 
1047  static
1048  bool ValueMightBeTimeVarying() { return true; }
1049 
1050  static
1051  value_type MakeDefault() {
1052  return invalidValue;
1053  }
1054 
1055  static
1056  query_type MakeQuery(UsdPrim const& prim, bool *) {
1057  if (const UsdGeomMotionAPI motionAPI = UsdGeomMotionAPI(prim)) {
1058  return query_type(motionAPI.GetNonlinearSampleCountAttr());
1059  }
1060  return query_type();
1061  }
1062 
1063  static
1064  value_type
1065  Compute(UsdImaging_NonlinearSampleCountCache const* owner,
1066  UsdPrim const& prim,
1067  query_type const* query)
1068  {
1069  if (query->HasAuthoredValue()) {
1070  int value;
1071  if (query->Get(&value, owner->GetTime())) {
1072  return value;
1073  }
1074  }
1075 
1076  return *owner->_GetValue(prim.GetParent());
1077  }
1078 
1079  static
1080  value_type
1081  ComputeNonlinearSampleCount(UsdPrim const &prim, UsdTimeCode time)
1082  {
1083  return UsdGeomMotionAPI(prim).ComputeNonlinearSampleCount(time);
1084  }
1085 };
1086 
1087 PXR_NAMESPACE_CLOSE_SCOPE
1088 
1089 // -------------------------------------------------------------------------- //
1090 // Blur scale Primvar Cache
1091 // -------------------------------------------------------------------------- //
1092 
1093 #include "pxr/usd/usdGeom/motionAPI.h"
1094 
1095 PXR_NAMESPACE_OPEN_SCOPE
1096 
1097 struct UsdImaging_BlurScaleStrategy;
1098 typedef UsdImaging_ResolvedAttributeCache<UsdImaging_BlurScaleStrategy>
1099  UsdImaging_BlurScaleCache;
1100 
1101 struct UsdImaging_BlurScaleStrategy
1102 {
1103  struct value_type {
1104  float value;
1105  bool has_value;
1106  };
1107 
1108  typedef UsdAttributeQuery query_type;
1109 
1110  // Used to indicate that no (valid) opinion exists
1111  // for blur scale.
1112  static const value_type invalidValue;
1113 
1114  static
1115  bool ValueMightBeTimeVarying() { return true; }
1116 
1117  static
1118  value_type MakeDefault() {
1119  return invalidValue;
1120  }
1121 
1122  static
1123  query_type MakeQuery(UsdPrim const& prim, bool *) {
1124  if (const UsdGeomMotionAPI motionAPI = UsdGeomMotionAPI(prim)) {
1125  return query_type(motionAPI.GetMotionBlurScaleAttr());
1126  }
1127  return query_type();
1128  }
1129 
1130  static
1131  value_type
1132  Compute(UsdImaging_BlurScaleCache const* owner,
1133  UsdPrim const& prim,
1134  query_type const* query)
1135  {
1136  if (query->HasAuthoredValue()) {
1137  float value;
1138  if (query->Get(&value, owner->GetTime())) {
1139  return { value, true };
1140  }
1141  }
1142 
1143  return *owner->_GetValue(prim.GetParent());
1144  }
1145 
1146  static
1147  value_type
1148  ComputeBlurScale(UsdPrim const &prim, UsdTimeCode time)
1149  {
1150  return { UsdGeomMotionAPI(prim).ComputeMotionBlurScale(time), true };
1151  }
1152 };
1153 
1154 PXR_NAMESPACE_CLOSE_SCOPE
1155 
1156 // -------------------------------------------------------------------------- //
1157 // Inherited Primvar Cache
1158 // -------------------------------------------------------------------------- //
1159 
1161 
1162 PXR_NAMESPACE_OPEN_SCOPE
1163 
1164 struct UsdImaging_InheritedPrimvarStrategy;
1165 typedef UsdImaging_ResolvedAttributeCache<UsdImaging_InheritedPrimvarStrategy>
1166  UsdImaging_InheritedPrimvarCache;
1167 
1168 struct UsdImaging_InheritedPrimvarStrategy
1169 {
1170  struct PrimvarRecord {
1171  std::vector<UsdGeomPrimvar> primvars;
1172  bool variable;
1173  };
1174  typedef std::shared_ptr<PrimvarRecord> value_type;
1175  typedef UsdGeomPrimvarsAPI query_type;
1176 
1177  // While primvar data might be time-varying, the set of primvars applying
1178  // to a prim will not.
1179  static
1180  bool ValueMightBeTimeVarying() { return false; }
1181 
1182  static
1183  value_type MakeDefault() {
1184  return value_type();
1185  }
1186 
1187  static
1188  query_type MakeQuery(UsdPrim const& prim, bool *) {
1189  return query_type(UsdGeomPrimvarsAPI(prim));
1190  }
1191 
1192  static
1193  value_type Compute(UsdImaging_InheritedPrimvarCache const* owner,
1194  UsdPrim const& prim,
1195  query_type const* query)
1196  {
1197  value_type v;
1198  if (*query) {
1199  // Pull inherited bindings first.
1200  if (UsdPrim parentPrim = prim.GetParent()) {
1201  v = *owner->_GetValue(parentPrim);
1202  }
1203  // Merge any local bindings.
1204  std::vector<UsdGeomPrimvar> primvars =
1205  query->FindIncrementallyInheritablePrimvars(
1206  v ? v->primvars : std::vector<UsdGeomPrimvar>());
1207  if (!primvars.empty()) {
1208  v = std::make_shared<PrimvarRecord>();
1209  v->primvars = std::move(primvars);
1210  v->variable = false;
1211  for (UsdGeomPrimvar const& pv : v->primvars) {
1212  if (pv.ValueMightBeTimeVarying()) {
1213  v->variable = true;
1214  break;
1215  }
1216  }
1217  }
1218  }
1219  return v;
1220  }
1221 };
1222 
1223 PXR_NAMESPACE_CLOSE_SCOPE
1224 
1225 #endif
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
USD_API UsdStageWeakPtr GetStage() const
Return the stage that owns the object, and to whose state and lifetime this object's validity is tied...
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's MembershipQuery object.
#define TF_CODING_ERROR(fmt, args)
Issue an internal programming error, but continue execution.
Definition: diagnostic.h:85
SDF_API const char * GetText() const
Returns the string representation of this path as a c string.
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.
bool IsInPrototype() const
Return true if this prim is a prototype prim or a descendant of a prototype prim, false otherwise.
Definition: prim.h:1584
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 "primitive variables", as UsdGeomPrimvar, which interpolate acro...
Definition: primvarsAPI.h:82
USDGEOM_API PurposeInfo ComputePurposeInfo() const
Calculate the effective purpose information about this prim which includes final computed purpose val...
USDGEOM_API int ComputeNonlinearSampleCount(UsdTimeCode time=UsdTimeCode::Default()) const
Compute the inherited value of nonlinearSampleCount at time, i.e.
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
#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.
UsdPrim GetParent() const
Return this prim's parent prim.
Definition: prim.h:1057
Value type containing information about a prim's computed effective purpose as well as storing whethe...
Definition: imageable.h:397
#define TRACE_FUNCTION()
Records a timestamp when constructed and a timespan event when destructed, using the name of the func...
Definition: trace.h:43
USDGEOM_API TfToken ComputeVisibility(UsdTimeCode const &time=UsdTimeCode::Default()) const
Calculate the effective visibility of this prim, as defined by its most ancestral authored "invisible...
UsdPrim is the sole persistent scenegraph object on a UsdStage, and is the embodiment of a "Prim" as ...
Definition: prim.h:132
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:290
SDF_API const std::string & GetString() const
Return the string representation of this path as a std::string.
#define TF_DEBUG(enumVal)
Evaluate and print debugging message msg if enumVal is enabled for debugging.
Definition: debug.h:501
UsdGeomMotionAPI encodes data that can live on any prim that may affect computations involving:
Definition: motionAPI.h:67
SDF_API bool IsAbsolutePath() const
Returns whether the path is absolute.
An forward-iterable range that traverses a subtree of prims rooted at a given prim in depth-first ord...
Definition: primRange.h:118
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...
USDGEOM_API TfToken ComputeModelDrawMode(const TfToken &parentDrawMode=TfToken()) const
Calculate the effective model:drawMode of this prim.
bool IsPrototype() const
Return true if this prim is an instancing prototype prim, false otherwise.
Definition: prim.h:1578
A Material provides a container into which multiple "render targets" can add data that defines a "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:261
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
bool IsEmpty() const noexcept
Returns true if this is the empty path (SdfPath::EmptyPath()).
Definition: path.h:419
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
TfToken class for efficient string referencing and hashing, plus conversions to and from stl string c...
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
USDGEOM_API bool ValueMightBeTimeVarying() const
Return true if it is possible, but not certain, that this primvar's value changes over time,...
USDGEOM_API float ComputeMotionBlurScale(UsdTimeCode time=UsdTimeCode::Default()) const
Compute the inherited value of motion:blurScale at time, i.e.