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) && !prim.IsInPrototype()) {
114  TF_CODING_ERROR("Attempt to get value for: %s "
115  "which is not within the specified root: %s",
116  prim.GetPath().GetString().c_str(),
117  _rootPath.GetString().c_str());
118  return Strategy::MakeDefault();
119  }
120 
121  return *_GetValue(prim);
122  }
123 
127  query_type const*
128  GetQuery(const UsdPrim& prim) const {
129  return &_GetCacheEntryForPrim(prim)->query;
130  }
131 
133  void Clear() {
134  WorkSwapDestroyAsync(_cache);
135  _cacheVersion = _GetInitialCacheVersion();
136  }
137 
141  void SetTime(UsdTimeCode time) {
142  if (time == _time)
143  return;
144 
145  if (Strategy::ValueMightBeTimeVarying()) {
146  // Mark all cached entries as invalid, but leave the queries behind.
147  // We increment by 2 here and always keep the version an odd number,
148  // this enables the use of even versions as a per-entry spin lock.
149  _cacheVersion += 2;
150  }
151 
152  // Update to correct time.
153  _time = time;
154  }
155 
157  UsdTimeCode GetTime() const { return _time; }
158 
167  void SetRootPath(const SdfPath& rootPath) {
168  if (!rootPath.IsAbsolutePath()) {
169  TF_CODING_ERROR("Invalid root path: %s",
170  rootPath.GetString().c_str());
171  return;
172  }
173 
174  if (rootPath == _rootPath)
175  return;
176 
177  Clear();
178  _rootPath = rootPath;
179  }
180 
183  const SdfPath & GetRootPath() const { return _rootPath; }
184 
195  void UpdateValueOverrides(const ValueOverridesMap &valueOverrides,
196  const std::vector<UsdPrim> &overridesToRemove,
197  std::vector<SdfPath> *dirtySubtreeRoots)
198  {
199  TRACE_FUNCTION();
200 
201  if (valueOverrides.empty() && overridesToRemove.empty())
202  return;
203 
204  ValueOverridesMap valueOverridesToProcess;
205  SdfPathVector processedOverridePaths;
206  TF_FOR_ALL(it, valueOverrides) {
207  const UsdPrim &prim = it->first;
208  const value_type &value = it->second;
209 
210  // If the existing value matches the incoming value, skip
211  // the update and dirtying.
212  if (*_GetValue(prim) == value)
213  continue;
214 
215  valueOverridesToProcess[prim] = value;
216  }
217 
218  TF_FOR_ALL(it, valueOverridesToProcess) {
219  const UsdPrim &prim = it->first;
220  const value_type &value = it->second;
221 
222  // XXX: performance
223  // We could probably make this faster by using a hash table of
224  // prefixes. This hasn't showed up in traces much though as it's not
225  // common to update value overrides for more than one path at a
226  // time.
227  bool isDescendantOfProcessedOverride = false;
228  for (const SdfPath &processedPath : processedOverridePaths) {
229  if (prim.GetPath().HasPrefix(processedPath)) {
230  isDescendantOfProcessedOverride = true;
231  break;
232  }
233  }
234 
235  // Invalidate cache entries if the prim is not a descendant of a
236  // path that has already been processed.
237  if (!isDescendantOfProcessedOverride) {
238  for (UsdPrim descendant: UsdPrimRange(prim)) {
239  if (_Entry* entry = _GetCacheEntryForPrim(descendant)) {
240  entry->version = _GetInvalidVersion();
241  }
242  }
243  processedOverridePaths.push_back(prim.GetPath());
244  dirtySubtreeRoots->push_back(prim.GetPath());
245  }
246 
247  // Update overrides in the internal value overrides map.
248  _valueOverrides[prim] = value;
249  }
250 
251  for (const UsdPrim &prim : overridesToRemove) {
252 
253  // Erase the entry from the map of overrides.
254  size_t numErased = _valueOverrides.erase(prim);
255 
256  // If the override doesn't exist, then there's nothing to do.
257  if (numErased == 0) {
258  continue;
259  }
260 
261  bool isDescendantOfProcessedOverride = false;
262  for (const SdfPath &processedPath : processedOverridePaths) {
263  if (prim.GetPath().HasPrefix(processedPath)) {
264  isDescendantOfProcessedOverride = true;
265  break;
266  }
267  }
268 
269  // Invalidate cache entries if the prim is not a descendant of a
270  // path that has already been processed.
271  if (!isDescendantOfProcessedOverride) {
272  for (UsdPrim descendant: UsdPrimRange(prim)) {
273  if (_Entry* entry = _GetCacheEntryForPrim(descendant)) {
274  entry->version = _GetInvalidVersion();
275  }
276  }
277  dirtySubtreeRoots->push_back(prim.GetPath());
278  processedOverridePaths.push_back(prim.GetPath());
279  }
280  }
281  }
282 
283 private:
284  // Cached value entries. Note that because query objects may be caching
285  // non-time varying data, entries may exist in the cache with invalid
286  // values. The version is used to determine validity.
287  struct _Entry {
288  _Entry()
289  : value(Strategy::MakeDefault())
290  , version(_GetInitialEntryVersion())
291  { }
292 
293  _Entry(const query_type & query_,
294  const value_type& value_,
295  unsigned version_)
296  : query(query_)
297  , value(value_)
298  , version(version_)
299  { }
300 
301  query_type query;
302  value_type value;
303  tbb::atomic<unsigned> version;
304  };
305 
306  // Returns the version number for a valid cache entry
307  unsigned _GetValidVersion() const { return _cacheVersion + 1; }
308 
309  // Returns the version number for an invalid cache entry
310  unsigned _GetInvalidVersion() const { return _cacheVersion - 1; }
311 
312  // Initial version numbers
313  static unsigned _GetInitialCacheVersion() { return 1; }
314  static unsigned _GetInitialEntryVersion() {
315  return _GetInitialCacheVersion()-1;
316  }
317 
318  // Traverse the hierarchy (order is strategy dependent) and compute the
319  // inherited value.
320  value_type const* _GetValue(const UsdPrim& prim) const;
321 
322  // Helper function to get or create a new entry for a prim in the cache.
323  _Entry* _GetCacheEntryForPrim(const UsdPrim &prim) const;
324 
325  // Sets the value of the given cache entry. If multiple threads attempt to
326  // set the same entry, the first in wins and other threads spin until the
327  // new value is set.
328  void _SetCacheEntryForPrim(const UsdPrim &prim,
329  value_type const& value,
330  _Entry* entry) const;
331 
332  // Mutable is required here to allow const methods to update the cache when
333  // it is thread safe, however not all mutations of this map are thread safe.
334  // See underlying map documentation for details.
335  mutable _CacheMap _cache;
336 
337  // The time at which this stack is querying and caching attribute values.
338  UsdTimeCode _time;
339  SdfPath _rootPath;
340 
341  // A serial number indicating the valid state of entries in the cache. When
342  // an entry has an equal or greater value, the entry is valid.
343  tbb::atomic<unsigned> _cacheVersion;
344 
345  // Value overrides for a set of descendents.
346  ValueOverridesMap _valueOverrides;
347 
348  // Supplemental cache if used by this inherited cache.
349  ImplData *_implData;
350 };
351 
352 template<typename Strategy, typename ImplData>
353 void
354 UsdImaging_ResolvedAttributeCache<Strategy,ImplData>::_SetCacheEntryForPrim(
355  const UsdPrim &prim,
356  value_type const& value,
357  _Entry* entry) const
358 {
359  // Note: _cacheVersion is not allowed to change during cache access.
360  unsigned v = entry->version;
361  if (v < _cacheVersion
362  && entry->version.compare_and_swap(_cacheVersion, v) == v)
363  {
364  entry->value = value;
365  entry->version = _GetValidVersion();
366  } else {
367  while (entry->version != _GetValidVersion()) {
368  // Future work: A suggestion is that rather than literally spinning
369  // here, we should use the pause instruction, which sleeps for one
370  // cycle while allowing hyper threads to continue. Folly has a nice
371  // implementation of this packaged up as "sleeper", which we could
372  // also implement in Work and Arch.
373  }
374  }
375 }
376 
377 template<typename Strategy, typename ImplData>
378 typename UsdImaging_ResolvedAttributeCache<Strategy, ImplData>::_Entry*
379 UsdImaging_ResolvedAttributeCache<Strategy, ImplData>::_GetCacheEntryForPrim(
380  const UsdPrim &prim) const
381 {
382  typename _CacheMap::const_iterator it = _cache.find(prim);
383  if (it != _cache.end()) {
384  return &it->second;
385  }
386 
387  _Entry e;
388  e.query = Strategy::MakeQuery(prim, _implData);
389  e.value = Strategy::MakeDefault();
390  e.version = _GetInvalidVersion();
391  return &(_cache.insert(
392  typename _CacheMap::value_type(prim, e)).first->second);
393 }
394 
395 template<typename Strategy, typename ImplData>
396 typename UsdImaging_ResolvedAttributeCache<Strategy, ImplData>::value_type const*
397 UsdImaging_ResolvedAttributeCache<Strategy, ImplData>::_GetValue(
398  const UsdPrim& prim) const
399 {
400  static value_type const default_ = Strategy::MakeDefault();
401 
402  // Base case.
403  if (!prim || prim.IsPrototype() || prim.GetPath() == _rootPath)
404  return &default_;
405 
406  _Entry* entry = _GetCacheEntryForPrim(prim);
407  if (entry->version == _GetValidVersion()) {
408  // Cache hit
409  return &entry->value;
410  }
411 
412  // Future work: Suggestion is that when multiple threads are computing the
413  // same value, we could block all but one thread here, possibly rescheduling
414  // blocked threads as continuations, rather than allowing all threads to
415  // continue to race until a cache hit is encountered.
416 
417  // Future work: A suggestion is that we make this iterative instead of
418  // recursive.
419  typename ValueOverridesMap::const_iterator it =
420  _valueOverrides.find(prim);
421  if (it != _valueOverrides.end()) {
422  _SetCacheEntryForPrim(prim, it->second, entry);
423  } else {
424  _SetCacheEntryForPrim(prim,
425  Strategy::Compute(this, prim, &entry->query),
426  entry);
427  }
428  return &entry->value;
429 }
430 
431 PXR_NAMESPACE_CLOSE_SCOPE
432 
433 // -------------------------------------------------------------------------- //
434 // Xform Cache
435 // -------------------------------------------------------------------------- //
436 
438 #include "pxr/base/gf/matrix4d.h"
439 
440 PXR_NAMESPACE_OPEN_SCOPE
441 
442 struct UsdImaging_XfStrategy;
443 typedef UsdImaging_ResolvedAttributeCache<UsdImaging_XfStrategy> UsdImaging_XformCache;
444 
445 struct UsdImaging_XfStrategy {
446  typedef GfMatrix4d value_type;
447  typedef UsdGeomXformable::XformQuery query_type;
448 
449  static
450  bool ValueMightBeTimeVarying() { return true; }
451  static
452  value_type MakeDefault() { return GfMatrix4d(1); }
453 
454  static
455  query_type MakeQuery(UsdPrim const& prim, bool *) {
456  if (const UsdGeomXformable xf = UsdGeomXformable(prim)) {
457  return query_type(xf);
458  }
459  return query_type();
460  }
461 
462  static
463  value_type
464  Compute(UsdImaging_XformCache const* owner,
465  UsdPrim const& prim,
466  query_type const* query)
467  {
468  value_type xform = MakeDefault();
469  // No need to check query validity here because XformQuery doesn't
470  // support it.
471  query->GetLocalTransformation(&xform, owner->GetTime());
472 
473  return !query->GetResetXformStack()
474  ? (xform * (*owner->_GetValue(prim.GetParent())))
475  : xform;
476  }
477 
478  // Compute the full transform, this is not part of the interface required by
479  // the cache.
480  static
481  value_type
482  ComputeTransform(UsdPrim const& prim,
483  SdfPath const& rootPath,
484  UsdTimeCode time,
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 *) {
599  if (const UsdGeomImageable im = UsdGeomImageable(prim)) {
600  return query_type(im.GetPurposeAttr());
601  }
602  return query_type();
603  }
604 
605  static
606  value_type
607  Compute(UsdImaging_PurposeCache const* owner,
608  UsdPrim const& prim,
609  query_type const* query)
610  {
611  // Fallback to parent if the prim isn't imageable or doesn't have a
612  // purpose attribute. Note that this returns the default purpose if
613  // there's no parent prim.
614  if (!*query) {
615  return *(owner->_GetValue(prim.GetParent()));
616  }
617 
618  // If the prim has an authored purpose value, we get and use that.
619  if (query->HasAuthoredValue()) {
620  value_type info;
621  query->Get(&info.purpose);
622  info.isInheritable = true;
623  return info;
624  }
625 
626  // Otherwise we inherit parent's purpose value, but only if the parent's
627  // purpose is inheritable. An inherited purpose is itself inheritable
628  // by child prims..
629  const value_type *v = owner->_GetValue(prim.GetParent());
630  if (v->isInheritable) {
631  return *v;
632  }
633 
634  // Otherwise, get the fallback value. The fallback purpose will not
635  // be inherited by descendants.
636  value_type info;
637  query->Get(&info.purpose);
638  return info;
639  }
640 
641  static
642  value_type
643  ComputePurposeInfo(UsdPrim const& prim)
644  {
645  return UsdGeomImageable(prim).ComputePurposeInfo();
646  }
647 };
648 
649 PXR_NAMESPACE_CLOSE_SCOPE
650 
651 // -------------------------------------------------------------------------- //
652 // Hydra MaterialBinding Cache
653 // -------------------------------------------------------------------------- //
654 
657 
658 PXR_NAMESPACE_OPEN_SCOPE
659 
660 struct UsdImaging_MaterialBindingImplData {
663  UsdImaging_MaterialBindingImplData(const TfToken &materialPurpose):
664  _materialPurpose(materialPurpose)
665  { }
666 
669  ~UsdImaging_MaterialBindingImplData() {
670  ClearCaches();
671  }
672 
674  const TfToken &GetMaterialPurpose() const {
675  return _materialPurpose;
676  }
677 
680  UsdShadeMaterialBindingAPI::BindingsCache & GetBindingsCache()
681  { return _bindingsCache; }
682 
685  UsdShadeMaterialBindingAPI::CollectionQueryCache & GetCollectionQueryCache()
686  { return _collQueryCache; }
687 
689  void ClearCaches();
690 
691 private:
692  const TfToken _materialPurpose;
695 };
696 
697 struct UsdImaging_MaterialStrategy;
698 typedef UsdImaging_ResolvedAttributeCache<UsdImaging_MaterialStrategy,
699  UsdImaging_MaterialBindingImplData>
700  UsdImaging_MaterialBindingCache;
701 
702 struct UsdImaging_MaterialStrategy {
703  // inherited path to bound target
704  // depending on the load state, override, etc bound target path might not be
705  // queried as a UsdShadeMaterial on the stage.
706 
707  // inherited path to bound target
708  typedef SdfPath value_type;
709  // Hold the computed path of the bound material or target path of the
710  // winning material binding relationship
711  typedef SdfPath query_type;
712 
713  using ImplData = UsdImaging_MaterialBindingImplData;
714 
715  static
716  bool ValueMightBeTimeVarying() { return false; }
717  static
718  value_type MakeDefault() { return SdfPath(); }
719 
720  static
721  query_type MakeQuery(
722  UsdPrim const& prim,
723  ImplData *implData)
724  {
725  UsdRelationship bindingRel;
726  UsdShadeMaterial materialPrim =
728  &implData->GetBindingsCache(),
729  &implData->GetCollectionQueryCache(),
730  implData->GetMaterialPurpose(),
731  &bindingRel);
732 
733  if (materialPrim) {
734  return materialPrim.GetPath();
735  }
736 
737  const SdfPath targetPath =
739  bindingRel);
740  return targetPath;
741  }
742 
743  static
744  value_type
745  Compute(UsdImaging_MaterialBindingCache const* owner,
746  UsdPrim const& prim,
747  query_type const* query)
748  {
749  TF_DEBUG(USDIMAGING_SHADERS).Msg("Looking for \"preview\" material "
750  "binding for %s\n", prim.GetPath().GetText());
751 
752  // query already contains the resolved material binding for the prim.
753  // Hence, we don't need to inherit the binding from the parent here.
754  // Futhermore, it may be wrong to inherit the binding from the parent,
755  // because in the new scheme, a child of a bound prim can be unbound.
756  //
757  // Note that query could be an empty SdfPath, which is the default
758  // value.
759  return *query;
760  }
761 
762  static
763  value_type
764  ComputeMaterialPath(UsdPrim const& prim, ImplData *implData) {
765  // We don't need to walk up the namespace here since
766  // ComputeBoundMaterial does it for us.
767  UsdRelationship bindingRel;
769  &implData->GetBindingsCache(),
770  &implData->GetCollectionQueryCache(),
771  implData->GetMaterialPurpose(),
772  &bindingRel);
773 
774  const SdfPath targetPath =
776  bindingRel);
777  if (!targetPath.IsEmpty()) {
778  return targetPath;
779  }
780  return value_type();
781  }
782 };
783 
784 PXR_NAMESPACE_CLOSE_SCOPE
785 
786 // -------------------------------------------------------------------------- //
787 // ModelDrawMode Cache
788 // -------------------------------------------------------------------------- //
789 
791 
792 PXR_NAMESPACE_OPEN_SCOPE
793 
794 struct UsdImaging_DrawModeStrategy;
795 typedef UsdImaging_ResolvedAttributeCache<UsdImaging_DrawModeStrategy>
796  UsdImaging_DrawModeCache;
797 
798 struct UsdImaging_DrawModeStrategy
799 {
800  typedef TfToken value_type; // origin, bounds, cards, default, inherited
801  typedef UsdAttributeQuery query_type;
802 
803  static
804  bool ValueMightBeTimeVarying() { return false; }
805  static
806  value_type MakeDefault() { return UsdGeomTokens->default_; }
807 
808  static
809  query_type MakeQuery(UsdPrim const& prim, bool *) {
810  if (const UsdGeomModelAPI modelApi = UsdGeomModelAPI(prim)) {
811  return query_type(modelApi.GetModelDrawModeAttr());
812  }
813  return query_type();
814  }
815 
816  static
817  value_type
818  Compute(UsdImaging_DrawModeCache const* owner,
819  UsdPrim const& prim,
820  query_type const* query)
821  {
822  // No attribute defined means inherited, means refer to the parent.
823  // Any defined attribute overrides parent opinion.
824  // If the drawMode is inherited all the way to the root of the scene,
825  // that means "default".
826  value_type v = UsdGeomTokens->inherited;
827  if (*query) {
828  query->Get(&v);
829  }
830  if (v != UsdGeomTokens->inherited) {
831  return v;
832  }
833  v = *owner->_GetValue(prim.GetParent());
834  if (v == UsdGeomTokens->inherited) {
835  return UsdGeomTokens->default_;
836  }
837  return v;
838  }
839 
840  static
841  value_type
842  ComputeDrawMode(UsdPrim const& prim)
843  {
844  return UsdGeomModelAPI(prim).ComputeModelDrawMode();
845  }
846 };
847 
848 PXR_NAMESPACE_CLOSE_SCOPE
849 
850 // -------------------------------------------------------------------------- //
851 // UsdGeomPointInstancer indices cache
852 // -------------------------------------------------------------------------- //
853 
855 
856 PXR_NAMESPACE_OPEN_SCOPE
857 
858 struct UsdImaging_PointInstancerIndicesStrategy;
859 typedef UsdImaging_ResolvedAttributeCache<UsdImaging_PointInstancerIndicesStrategy>
860  UsdImaging_PointInstancerIndicesCache;
861 
862 struct UsdImaging_PointInstancerIndicesStrategy
863 {
864  // map from protoIndex -> instanceIndices.
865  typedef VtArray<VtIntArray> value_type;
866  // We don't use query_type, but can't set it to void.
867  typedef int query_type;
868 
869  // XXX: Most indices values will be static, but since they *can*
870  // be animated, we need to return true here to get invalidation on
871  // time-change. It would be nice to add a per-entry time-varying bit
872  // to the resolved cache, instead of having the global per-attribute
873  // bit.
874  //
875  // In this particular case, instance indices are only recomputed when
876  // we see "DirtyInstanceIndex" in UpdateForTime, so though we'll be
877  // clearing cache entries out of the resolved cache on time-change,
878  // we won't actually call out to the attribute cache on static indices.
879  static
880  bool ValueMightBeTimeVarying() { return true; }
881  static
882  value_type MakeDefault() { return value_type(); }
883 
884  static
885  query_type MakeQuery(UsdPrim const& prim, bool *) {
886  return 0;
887  }
888 
889  static
890  value_type
891  Compute(UsdImaging_PointInstancerIndicesCache const* owner,
892  UsdPrim const& prim,
893  query_type const* query)
894  {
895  return ComputePerPrototypeIndices(prim, owner->GetTime());
896  }
897 
898  static
899  value_type
900  ComputePerPrototypeIndices(UsdPrim const& prim, UsdTimeCode time)
901  {
902  value_type v;
903 
904  UsdGeomPointInstancer pi(prim);
905  VtIntArray protoIndices;
906  if (!pi.GetProtoIndicesAttr().Get(&protoIndices, time)) {
907  TF_WARN("Failed to read point instancer protoIndices");
908  return v;
909  }
910 
911  std::vector<bool> mask = pi.ComputeMaskAtTime(time);
912 
913  for (size_t instanceId = 0; instanceId < protoIndices.size(); ++instanceId) {
914  size_t protoIndex = protoIndices[instanceId];
915 
916  if (protoIndex >= v.size()) {
917  v.resize(protoIndex + 1);
918  }
919 
920  if (mask.size() == 0 || mask[instanceId]) {
921  v[protoIndex].push_back(instanceId);
922  }
923  }
924 
925  return v;
926  }
927 };
928 
929 PXR_NAMESPACE_CLOSE_SCOPE
930 
931 // -------------------------------------------------------------------------- //
932 // CoordSysBinding Cache
933 // -------------------------------------------------------------------------- //
934 
936 #include "pxr/imaging/hd/coordSys.h"
937 
938 PXR_NAMESPACE_OPEN_SCOPE
939 
940 struct UsdImaging_CoordSysBindingStrategy;
941 
942 typedef UsdImaging_ResolvedAttributeCache<UsdImaging_CoordSysBindingStrategy>
943  UsdImaging_CoordSysBindingCache;
944 
945 struct UsdImaging_CoordSysBindingStrategy
946 {
947  typedef std::vector<UsdShadeCoordSysAPI::Binding> UsdBindingVec;
948  typedef std::shared_ptr<UsdBindingVec> UsdBindingVecPtr;
949  typedef std::shared_ptr<SdfPathVector> IdVecPtr;
950 
951  struct value_type {
952  IdVecPtr idVecPtr;
953  UsdBindingVecPtr usdBindingVecPtr;
954  };
955  typedef int query_type;
956 
957  static
958  bool ValueMightBeTimeVarying() { return false; }
959 
960  static
961  value_type MakeDefault() {
962  return value_type();
963  }
964 
965  static
966  query_type MakeQuery(UsdPrim const& prim, bool *) {
967  return 0;
968  }
969 
970  static
971  value_type
972  Compute(UsdImaging_CoordSysBindingCache const* owner,
973  UsdPrim const& prim,
974  query_type const* query)
975  {
976  value_type v;
977 
978  // Pull inherited bindings first.
979  if (UsdPrim parentPrim = prim.GetParent()) {
980  v = *owner->_GetValue(parentPrim);
981  }
982 
983  auto _IterateLocalBindings = [&prim](const UsdBindingVec &localBindings,
984  SdfPathVector &hdIds, UsdBindingVec &usdBindings) {
985  for (const UsdShadeCoordSysAPI::Binding &binding : localBindings) {
986  if (!prim.GetStage()->GetPrimAtPath(
987  binding.coordSysPrimPath).IsValid()) {
988  // The target xform prim does not exist, so ignore this
989  // coord sys binding.
990  TF_WARN("UsdImaging: Ignore coordinate system binding to "
991  "non-existent prim <%s>\n",
992  binding.coordSysPrimPath.GetText());
993  continue;
994  }
995  bool found = false;
996  for (size_t id = 0, n = hdIds.size(); id < n; ++id) {
997  if (usdBindings[id].name == binding.name) {
998  // Found an override -- replace this binding.
999  usdBindings[id] = binding;
1000  hdIds[id] = binding.bindingRelPath;
1001  found = true;
1002  break;
1003  }
1004  }
1005  if (!found) {
1006  // New binding, so append.
1007  usdBindings.push_back(binding);
1008  hdIds.push_back(binding.bindingRelPath);
1009  }
1010  }
1011  };
1012 
1013  // XXX: Make sure to update the following code when
1014  // UsdShadeCoordSysAPI's old non-applied mode is completely removed.
1015  UsdShadeCoordSysAPI coordSysAPI = UsdShadeCoordSysAPI(prim,
1016  TfToken("noop"));
1017  bool hasLocalBindings = coordSysAPI.HasLocalBindings();
1018  UsdBindingVec localBindings = coordSysAPI.GetLocalBindings();
1019 
1020  //Merge any local bindings.
1021  if (hasLocalBindings && !localBindings.empty()) {
1022  SdfPathVector hdIds;
1023  UsdBindingVec usdBindings;
1024  if (v.idVecPtr) {
1025  hdIds = *v.idVecPtr;
1026  }
1027  if (v.usdBindingVecPtr) {
1028  usdBindings = *v.usdBindingVecPtr;
1029  }
1030  _IterateLocalBindings(localBindings, hdIds, usdBindings);
1031  v.idVecPtr.reset(new SdfPathVector(std::move(hdIds)));
1032  v.usdBindingVecPtr.reset(new UsdBindingVec(std::move(usdBindings)));
1033  }
1034 
1035  return v;
1036  }
1037 };
1038 
1039 PXR_NAMESPACE_CLOSE_SCOPE
1040 
1041 // -------------------------------------------------------------------------- //
1042 // Nonlinear sample count Primvar Cache
1043 // -------------------------------------------------------------------------- //
1044 
1045 #include "pxr/usd/usdGeom/motionAPI.h"
1046 
1047 PXR_NAMESPACE_OPEN_SCOPE
1048 
1049 struct UsdImaging_NonlinearSampleCountStrategy;
1050 typedef UsdImaging_ResolvedAttributeCache<
1051  UsdImaging_NonlinearSampleCountStrategy>
1052  UsdImaging_NonlinearSampleCountCache;
1053 
1054 struct UsdImaging_NonlinearSampleCountStrategy
1055 {
1056  typedef int value_type;
1057  typedef UsdAttributeQuery query_type;
1058 
1059  // Used to indicate that no (valid) opinion exists
1060  // for nonlinear sample count.
1061  static constexpr value_type invalidValue = -1;
1062 
1063  static
1064  bool ValueMightBeTimeVarying() { return true; }
1065 
1066  static
1067  value_type MakeDefault() {
1068  return invalidValue;
1069  }
1070 
1071  static
1072  query_type MakeQuery(UsdPrim const& prim, bool *) {
1073  if (const UsdGeomMotionAPI motionAPI = UsdGeomMotionAPI(prim)) {
1074  return query_type(motionAPI.GetNonlinearSampleCountAttr());
1075  }
1076  return query_type();
1077  }
1078 
1079  static
1080  value_type
1081  Compute(UsdImaging_NonlinearSampleCountCache const* owner,
1082  UsdPrim const& prim,
1083  query_type const* query)
1084  {
1085  if (query->HasAuthoredValue()) {
1086  int value;
1087  if (query->Get(&value, owner->GetTime())) {
1088  return value;
1089  }
1090  }
1091 
1092  return *owner->_GetValue(prim.GetParent());
1093  }
1094 
1095  static
1096  value_type
1097  ComputeNonlinearSampleCount(UsdPrim const &prim, UsdTimeCode time)
1098  {
1099  return UsdGeomMotionAPI(prim).ComputeNonlinearSampleCount(time);
1100  }
1101 };
1102 
1103 PXR_NAMESPACE_CLOSE_SCOPE
1104 
1105 // -------------------------------------------------------------------------- //
1106 // Blur scale Primvar Cache
1107 // -------------------------------------------------------------------------- //
1108 
1109 #include "pxr/usd/usdGeom/motionAPI.h"
1110 
1111 PXR_NAMESPACE_OPEN_SCOPE
1112 
1113 struct UsdImaging_BlurScaleStrategy;
1114 typedef UsdImaging_ResolvedAttributeCache<UsdImaging_BlurScaleStrategy>
1115  UsdImaging_BlurScaleCache;
1116 
1117 struct UsdImaging_BlurScaleStrategy
1118 {
1119  struct value_type {
1120  float value;
1121  bool has_value;
1122  };
1123 
1124  typedef UsdAttributeQuery query_type;
1125 
1126  // Used to indicate that no (valid) opinion exists
1127  // for blur scale.
1128  static const value_type invalidValue;
1129 
1130  static
1131  bool ValueMightBeTimeVarying() { return true; }
1132 
1133  static
1134  value_type MakeDefault() {
1135  return invalidValue;
1136  }
1137 
1138  static
1139  query_type MakeQuery(UsdPrim const& prim, bool *) {
1140  if (const UsdGeomMotionAPI motionAPI = UsdGeomMotionAPI(prim)) {
1141  return query_type(motionAPI.GetMotionBlurScaleAttr());
1142  }
1143  return query_type();
1144  }
1145 
1146  static
1147  value_type
1148  Compute(UsdImaging_BlurScaleCache const* owner,
1149  UsdPrim const& prim,
1150  query_type const* query)
1151  {
1152  if (query->HasAuthoredValue()) {
1153  float value;
1154  if (query->Get(&value, owner->GetTime())) {
1155  return { value, true };
1156  }
1157  }
1158 
1159  return *owner->_GetValue(prim.GetParent());
1160  }
1161 
1162  static
1163  value_type
1164  ComputeBlurScale(UsdPrim const &prim, UsdTimeCode time)
1165  {
1166  return { UsdGeomMotionAPI(prim).ComputeMotionBlurScale(time), true };
1167  }
1168 };
1169 
1170 PXR_NAMESPACE_CLOSE_SCOPE
1171 
1172 // -------------------------------------------------------------------------- //
1173 // Inherited Primvar Cache
1174 // -------------------------------------------------------------------------- //
1175 
1177 
1178 PXR_NAMESPACE_OPEN_SCOPE
1179 
1180 struct UsdImaging_InheritedPrimvarStrategy;
1181 typedef UsdImaging_ResolvedAttributeCache<UsdImaging_InheritedPrimvarStrategy>
1182  UsdImaging_InheritedPrimvarCache;
1183 
1184 struct UsdImaging_InheritedPrimvarStrategy
1185 {
1186  struct PrimvarRecord {
1187  std::vector<UsdGeomPrimvar> primvars;
1188  bool variable;
1189  };
1190  typedef std::shared_ptr<PrimvarRecord> value_type;
1191  typedef UsdGeomPrimvarsAPI query_type;
1192 
1193  // While primvar data might be time-varying, the set of primvars applying
1194  // to a prim will not.
1195  static
1196  bool ValueMightBeTimeVarying() { return false; }
1197 
1198  static
1199  value_type MakeDefault() {
1200  return value_type();
1201  }
1202 
1203  static
1204  query_type MakeQuery(UsdPrim const& prim, bool *) {
1205  return query_type(UsdGeomPrimvarsAPI(prim));
1206  }
1207 
1208  static
1209  value_type Compute(UsdImaging_InheritedPrimvarCache const* owner,
1210  UsdPrim const& prim,
1211  query_type const* query)
1212  {
1213  value_type v;
1214  if (*query) {
1215  // Pull inherited bindings first.
1216  if (UsdPrim parentPrim = prim.GetParent()) {
1217  v = *owner->_GetValue(parentPrim);
1218  }
1219  // Merge any local bindings.
1220  std::vector<UsdGeomPrimvar> primvars =
1221  query->FindIncrementallyInheritablePrimvars(
1222  v ? v->primvars : std::vector<UsdGeomPrimvar>());
1223  if (!primvars.empty()) {
1224  v = std::make_shared<PrimvarRecord>();
1225  v->primvars = std::move(primvars);
1226  v->variable = false;
1227  for (UsdGeomPrimvar const& pv : v->primvars) {
1228  if (pv.ValueMightBeTimeVarying()) {
1229  v->variable = true;
1230  break;
1231  }
1232  }
1233  }
1234  }
1235  return v;
1236  }
1237 };
1238 
1239 PXR_NAMESPACE_CLOSE_SCOPE
1240 
1241 #endif
UsdShadeCoordSysAPI provides a way to designate, name, and discover coordinate systems.
Definition: coordSysAPI.h:82
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:2032
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:273
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:87
Represent a time value, which may be either numeric, holding a double value, or a sentinel value UsdT...
Definition: timeCode.h:84
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:1505
Value type containing information about a prim's computed effective purpose as well as storing whethe...
Definition: imageable.h:400
#define TRACE_FUNCTION()
Records a timestamp when constructed and a timespan event when destructed, using the name of the func...
Definition: trace.h:43
SdfPath GetPath() const
Shorthand for GetPrim()->GetPath().
Definition: schemaBase.h:123
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:135
USDSHADE_API bool HasLocalBindings() const
Returns true if the prim has local coordinate system relationship exists.
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
A UsdRelationship creates dependencies between scenegraph objects by allowing a prim to target other ...
Definition: relationship.h:128
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
Computes the resolved bound material for this prim, for the given material purpose.
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:2026
A Material provides a container into which multiple "render targets" can add data that defines a "sha...
Definition: material.h:111
USDSHADE_API std::vector< Binding > GetLocalBindings() const
Get the list of coordinate system bindings local to this prim.
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
static USDSHADE_API const SdfPath GetResolvedTargetPathFromBindingRel(const UsdRelationship &bindingRel)
returns the path of the resolved target identified by bindingRel.
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:203
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.