Loading...
Searching...
No Matches
resolvedAttributeCache.h
Go to the documentation of this file.
1//
2// Copyright 2016 Pixar
3//
4// Licensed under the terms set forth in the LICENSE.txt file available at
5// https://openusd.org/license.
6//
7#ifndef PXR_USD_IMAGING_USD_IMAGING_RESOLVED_ATTRIBUTE_CACHE_H
8#define PXR_USD_IMAGING_USD_IMAGING_RESOLVED_ATTRIBUTE_CACHE_H
9
11
12#include "pxr/pxr.h"
13#include "pxr/usdImaging/usdImaging/api.h"
14#include "pxr/usd/usd/prim.h"
15#include "pxr/usd/usd/primRange.h"
17#include "pxr/usd/sdf/path.h"
18
19#include "pxr/base/tf/hash.h"
20#include "pxr/base/work/utils.h"
21
22#include "pxr/base/tf/hash.h"
23
24#include <tbb/concurrent_unordered_map.h>
25#include <functional>
26
27PXR_NAMESPACE_OPEN_SCOPE
28
51template<typename Strategy, typename ImplData=bool>
52class UsdImaging_ResolvedAttributeCache
53{
54 friend Strategy;
55 struct _Entry;
56 using _CacheMap = tbb::concurrent_unordered_map<UsdPrim, _Entry, TfHash>;
57public:
58 typedef typename Strategy::value_type value_type;
59 typedef typename Strategy::query_type query_type;
60
61 using ValueOverridesMap = TfHashMap<UsdPrim, value_type, TfHash>;
62
64 explicit UsdImaging_ResolvedAttributeCache(
65 const UsdTimeCode time,
66 ImplData *implData=nullptr,
67 const ValueOverridesMap valueOverrides=ValueOverridesMap())
68 : _time(time)
69 , _rootPath(SdfPath::AbsoluteRootPath())
70 , _cacheVersion(_GetInitialCacheVersion())
71 , _valueOverrides(valueOverrides)
72 , _implData(implData)
73 {
74 }
75
77 UsdImaging_ResolvedAttributeCache()
78 : _time(UsdTimeCode::Default())
79 , _rootPath(SdfPath::AbsoluteRootPath())
80 , _cacheVersion(1)
81 {
82 }
83
84 ~UsdImaging_ResolvedAttributeCache()
85 {
87 }
88
89
92 value_type GetValue(const UsdPrim& prim) const
93 {
94 TRACE_FUNCTION();
95 if (!prim.GetPath().HasPrefix(_rootPath) && !prim.IsInPrototype()) {
96 TF_CODING_ERROR("Attempt to get value for: %s "
97 "which is not within the specified root: %s",
98 prim.GetPath().GetString().c_str(),
99 _rootPath.GetString().c_str());
100 return Strategy::MakeDefault();
101 }
102
103 return *_GetValue(prim);
104 }
105
109 query_type const*
110 GetQuery(const UsdPrim& prim) const {
111 return &_GetCacheEntryForPrim(prim)->query;
112 }
113
115 void Clear() {
116 WorkSwapDestroyAsync(_cache);
117 _cacheVersion = _GetInitialCacheVersion();
118 }
119
123 void SetTime(UsdTimeCode time) {
124 if (time == _time)
125 return;
126
127 if (Strategy::ValueMightBeTimeVarying()) {
128 // Mark all cached entries as invalid, but leave the queries behind.
129 // We increment by 2 here and always keep the version an odd number,
130 // this enables the use of even versions as a per-entry spin lock.
131 _cacheVersion += 2;
132 }
133
134 // Update to correct time.
135 _time = time;
136 }
137
139 UsdTimeCode GetTime() const { return _time; }
140
149 void SetRootPath(const SdfPath& rootPath) {
150 if (!rootPath.IsAbsolutePath()) {
151 TF_CODING_ERROR("Invalid root path: %s",
152 rootPath.GetString().c_str());
153 return;
154 }
155
156 if (rootPath == _rootPath)
157 return;
158
159 Clear();
160 _rootPath = rootPath;
161 }
162
165 const SdfPath & GetRootPath() const { return _rootPath; }
166
177 void UpdateValueOverrides(const ValueOverridesMap &valueOverrides,
178 const std::vector<UsdPrim> &overridesToRemove,
179 std::vector<SdfPath> *dirtySubtreeRoots)
180 {
181 TRACE_FUNCTION();
182
183 if (valueOverrides.empty() && overridesToRemove.empty())
184 return;
185
186 ValueOverridesMap valueOverridesToProcess;
187 SdfPathVector processedOverridePaths;
188 TF_FOR_ALL(it, valueOverrides) {
189 const UsdPrim &prim = it->first;
190 const value_type &value = it->second;
191
192 // If the existing value matches the incoming value, skip
193 // the update and dirtying.
194 if (*_GetValue(prim) == value)
195 continue;
196
197 valueOverridesToProcess[prim] = value;
198 }
199
200 TF_FOR_ALL(it, valueOverridesToProcess) {
201 const UsdPrim &prim = it->first;
202 const value_type &value = it->second;
203
204 // XXX: performance
205 // We could probably make this faster by using a hash table of
206 // prefixes. This hasn't showed up in traces much though as it's not
207 // common to update value overrides for more than one path at a
208 // time.
209 bool isDescendantOfProcessedOverride = false;
210 for (const SdfPath &processedPath : processedOverridePaths) {
211 if (prim.GetPath().HasPrefix(processedPath)) {
212 isDescendantOfProcessedOverride = true;
213 break;
214 }
215 }
216
217 // Invalidate cache entries if the prim is not a descendant of a
218 // path that has already been processed.
219 if (!isDescendantOfProcessedOverride) {
220 for (UsdPrim descendant: UsdPrimRange(prim)) {
221 if (_Entry* entry = _GetCacheEntryForPrim(descendant)) {
222 entry->version = _GetInvalidVersion();
223 }
224 }
225 processedOverridePaths.push_back(prim.GetPath());
226 dirtySubtreeRoots->push_back(prim.GetPath());
227 }
228
229 // Update overrides in the internal value overrides map.
230 _valueOverrides[prim] = value;
231 }
232
233 for (const UsdPrim &prim : overridesToRemove) {
234
235 // Erase the entry from the map of overrides.
236 size_t numErased = _valueOverrides.erase(prim);
237
238 // If the override doesn't exist, then there's nothing to do.
239 if (numErased == 0) {
240 continue;
241 }
242
243 bool isDescendantOfProcessedOverride = false;
244 for (const SdfPath &processedPath : processedOverridePaths) {
245 if (prim.GetPath().HasPrefix(processedPath)) {
246 isDescendantOfProcessedOverride = true;
247 break;
248 }
249 }
250
251 // Invalidate cache entries if the prim is not a descendant of a
252 // path that has already been processed.
253 if (!isDescendantOfProcessedOverride) {
254 for (UsdPrim descendant: UsdPrimRange(prim)) {
255 if (_Entry* entry = _GetCacheEntryForPrim(descendant)) {
256 entry->version = _GetInvalidVersion();
257 }
258 }
259 dirtySubtreeRoots->push_back(prim.GetPath());
260 processedOverridePaths.push_back(prim.GetPath());
261 }
262 }
263 }
264
265private:
266 // Cached value entries. Note that because query objects may be caching
267 // non-time varying data, entries may exist in the cache with invalid
268 // values. The version is used to determine validity.
269 struct _Entry {
270 _Entry()
271 : value(Strategy::MakeDefault())
272 , version(_GetInitialEntryVersion())
273 { }
274
275 _Entry(const query_type & query_,
276 const value_type& value_,
277 unsigned version_)
278 : query(query_)
279 , value(value_)
280 , version(version_)
281 { }
282
283 _Entry(const _Entry &other)
284 : query(other.query)
285 , value(other.value)
286 {
287 version.store(other.version.load());
288 }
289
290 _Entry(_Entry &&other)
291 : query(std::move(other.query))
292 , value(std::move(other.value))
293 {
294 version.store(other.version.load());
295 }
296
297 query_type query;
298 value_type value;
299 std::atomic<unsigned> version;
300 };
301
302 // Returns the version number for a valid cache entry
303 unsigned _GetValidVersion() const { return _cacheVersion + 1; }
304
305 // Returns the version number for an invalid cache entry
306 unsigned _GetInvalidVersion() const { return _cacheVersion - 1; }
307
308 // Initial version numbers
309 static unsigned _GetInitialCacheVersion() { return 1; }
310 static unsigned _GetInitialEntryVersion() {
311 return _GetInitialCacheVersion()-1;
312 }
313
314 // Traverse the hierarchy (order is strategy dependent) and compute the
315 // inherited value.
316 value_type const* _GetValue(const UsdPrim& prim) const;
317
318 // Helper function to get or create a new entry for a prim in the cache.
319 _Entry* _GetCacheEntryForPrim(const UsdPrim &prim) const;
320
321 // Sets the value of the given cache entry. If multiple threads attempt to
322 // set the same entry, the first in wins and other threads spin until the
323 // new value is set.
324 void _SetCacheEntryForPrim(const UsdPrim &prim,
325 value_type const& value,
326 _Entry* entry) const;
327
328 // Mutable is required here to allow const methods to update the cache when
329 // it is thread safe, however not all mutations of this map are thread safe.
330 // See underlying map documentation for details.
331 mutable _CacheMap _cache;
332
333 // The time at which this stack is querying and caching attribute values.
334 UsdTimeCode _time;
335 SdfPath _rootPath;
336
337 // A serial number indicating the valid state of entries in the cache. When
338 // an entry has an equal or greater value, the entry is valid.
339 std::atomic<unsigned> _cacheVersion;
340
341 // Value overrides for a set of descendents.
342 ValueOverridesMap _valueOverrides;
343
344 // Supplemental cache if used by this inherited cache.
345 ImplData *_implData;
346};
347
348template<typename Strategy, typename ImplData>
349void
350UsdImaging_ResolvedAttributeCache<Strategy,ImplData>::_SetCacheEntryForPrim(
351 const UsdPrim &prim,
352 value_type const& value,
353 _Entry* entry) const
354{
355 // Note: _cacheVersion is not allowed to change during cache access.
356 unsigned v = entry->version;
357 if (v < _cacheVersion
358 && entry->version.compare_exchange_strong(v,_cacheVersion.load()))
359 {
360 entry->value = value;
361 entry->version = _GetValidVersion();
362 } else {
363 while (entry->version != _GetValidVersion()) {
364 // Future work: A suggestion is that rather than literally spinning
365 // here, we should use the pause instruction, which sleeps for one
366 // cycle while allowing hyper threads to continue. Folly has a nice
367 // implementation of this packaged up as "sleeper", which we could
368 // also implement in Work and Arch.
369 }
370 }
371}
372
373template<typename Strategy, typename ImplData>
374typename UsdImaging_ResolvedAttributeCache<Strategy, ImplData>::_Entry*
375UsdImaging_ResolvedAttributeCache<Strategy, ImplData>::_GetCacheEntryForPrim(
376 const UsdPrim &prim) const
377{
378 typename _CacheMap::iterator it = _cache.find(prim);
379 if (it != _cache.end()) {
380 return &it->second;
381 }
382
383 _Entry e;
384 e.query = Strategy::MakeQuery(prim, _implData);
385 e.value = Strategy::MakeDefault();
386 e.version = _GetInvalidVersion();
387 return &(_cache.insert(
388 typename _CacheMap::value_type(prim, e)).first->second);
389}
390
391template<typename Strategy, typename ImplData>
392typename UsdImaging_ResolvedAttributeCache<Strategy, ImplData>::value_type const*
393UsdImaging_ResolvedAttributeCache<Strategy, ImplData>::_GetValue(
394 const UsdPrim& prim) const
395{
396 static value_type const default_ = Strategy::MakeDefault();
397
398 // Base case.
399 if (!prim || prim.IsPrototype() || prim.GetPath() == _rootPath)
400 return &default_;
401
402 _Entry* entry = _GetCacheEntryForPrim(prim);
403 if (entry->version == _GetValidVersion()) {
404 // Cache hit
405 return &entry->value;
406 }
407
408 // Future work: Suggestion is that when multiple threads are computing the
409 // same value, we could block all but one thread here, possibly rescheduling
410 // blocked threads as continuations, rather than allowing all threads to
411 // continue to race until a cache hit is encountered.
412
413 // Future work: A suggestion is that we make this iterative instead of
414 // recursive.
415 typename ValueOverridesMap::const_iterator it =
416 _valueOverrides.find(prim);
417 if (it != _valueOverrides.end()) {
418 _SetCacheEntryForPrim(prim, it->second, entry);
419 } else {
420 _SetCacheEntryForPrim(prim,
421 Strategy::Compute(this, prim, &entry->query),
422 entry);
423 }
424 return &entry->value;
425}
426
427PXR_NAMESPACE_CLOSE_SCOPE
428
429// -------------------------------------------------------------------------- //
430// Xform Cache
431// -------------------------------------------------------------------------- //
432
434#include "pxr/base/gf/matrix4d.h"
435
436PXR_NAMESPACE_OPEN_SCOPE
437
438struct UsdImaging_XfStrategy;
439typedef UsdImaging_ResolvedAttributeCache<UsdImaging_XfStrategy> UsdImaging_XformCache;
440
441struct UsdImaging_XfStrategy {
442 typedef GfMatrix4d value_type;
443 typedef UsdGeomXformable::XformQuery query_type;
444
445 static
446 bool ValueMightBeTimeVarying() { return true; }
447 static
448 value_type MakeDefault() { return GfMatrix4d(1); }
449
450 static
451 query_type MakeQuery(UsdPrim const& prim, bool *) {
452 if (const UsdGeomXformable xf = UsdGeomXformable(prim)) {
453 return query_type(xf);
454 }
455 return query_type();
456 }
457
458 static
459 value_type
460 Compute(UsdImaging_XformCache const* owner,
461 UsdPrim const& prim,
462 query_type const* query)
463 {
464 value_type xform = MakeDefault();
465 // No need to check query validity here because XformQuery doesn't
466 // support it.
467 query->GetLocalTransformation(&xform, owner->GetTime());
468
469 return !query->GetResetXformStack()
470 ? (xform * (*owner->_GetValue(prim.GetParent())))
471 : xform;
472 }
473
474 // Compute the full transform, this is not part of the interface required by
475 // the cache.
476 static
477 value_type
478 ComputeTransform(UsdPrim const& prim,
479 SdfPath const& rootPath,
480 UsdTimeCode time,
481 const TfHashMap<SdfPath, GfMatrix4d, SdfPath::Hash> &ctmOverrides)
482 {
483 bool reset = false;
484 GfMatrix4d ctm(1.0);
485 GfMatrix4d localXf(1.0);
486 UsdPrim p = prim;
487 while (p && p.GetPath() != rootPath) {
488 const auto &overIt = ctmOverrides.find(p.GetPath());
489 // If there's a ctm override, use it and break out of the loop.
490 if (overIt != ctmOverrides.end()) {
491 ctm *= overIt->second;
492 break;
493 } else if (UsdGeomXformable xf = UsdGeomXformable(p)) {
494 if (xf.GetLocalTransformation(&localXf, &reset, time))
495 ctm *= localXf;
496 if (reset)
497 break;
498 }
499 p = p.GetParent();
500 }
501 return ctm;
502 }
503};
504
505PXR_NAMESPACE_CLOSE_SCOPE
506
507// -------------------------------------------------------------------------- //
508// Visibility Cache
509// -------------------------------------------------------------------------- //
510
512#include "pxr/base/tf/token.h"
513#include "pxr/usdImaging/usdImaging/debugCodes.h"
514
515PXR_NAMESPACE_OPEN_SCOPE
516
517struct UsdImaging_VisStrategy;
518using UsdImaging_VisCache =
519 UsdImaging_ResolvedAttributeCache<UsdImaging_VisStrategy>;
520
524struct UsdImaging_VisStrategy {
525 typedef TfToken value_type; // invisible, inherited
526 typedef UsdAttributeQuery query_type;
527
528 static
529 bool ValueMightBeTimeVarying() { return true; }
530
531 static
532 value_type MakeDefault() { return UsdGeomTokens->inherited; }
533
534 static
535 query_type MakeQuery(UsdPrim const& prim, bool *)
536 {
537 if (const UsdGeomImageable xf = UsdGeomImageable(prim)) {
538 return query_type(xf.GetVisibilityAttr());
539 }
540 return query_type();
541 }
542
543 static
544 value_type
545 Compute(UsdImaging_VisCache const* owner,
546 UsdPrim const& prim,
547 query_type const* query)
548 {
549 value_type v = *owner->_GetValue(prim.GetParent());
550
551 // If prim inherits 'invisible', then it's invisible, due to pruning
552 // visibility.
553 if (v == UsdGeomTokens->invisible) {
554 return v;
555 }
556
557 // Otherwise, prim's value, if it has one, determines its visibility.
558 if (*query) {
559 query->Get(&v, owner->GetTime());
560 }
561 return v;
562 }
563
564 static
565 value_type
566 ComputeVisibility(UsdPrim const& prim, UsdTimeCode time)
567 {
568 return UsdGeomImageable(prim).ComputeVisibility(time);
569 }
570};
571
572// -------------------------------------------------------------------------- //
573// Purpose Cache
574// -------------------------------------------------------------------------- //
575
576struct UsdImaging_PurposeStrategy;
577typedef UsdImaging_ResolvedAttributeCache<UsdImaging_PurposeStrategy>
578 UsdImaging_PurposeCache;
579
580struct UsdImaging_PurposeStrategy {
581 // For proper inheritance, we need to return the PurposeInfo struct which
582 // stores whether child prims can inherit the parent's computed purpose
583 // when they don't have an authored purpose of their own.
584 typedef UsdGeomImageable::PurposeInfo value_type; // purpose, inherited
585 typedef UsdAttributeQuery query_type;
586
587 static
588 value_type MakeDefault() {
589 // Return the fallback default instead of an empty purpose info.
590 return value_type(UsdGeomTokens->default_, false);
591 }
592
593 static
594 query_type MakeQuery(UsdPrim const& prim, bool *) {
595 if (const UsdGeomImageable im = UsdGeomImageable(prim)) {
596 return query_type(im.GetPurposeAttr());
597 }
598 return query_type();
599 }
600
601 static
602 value_type
603 Compute(UsdImaging_PurposeCache const* owner,
604 UsdPrim const& prim,
605 query_type const* query)
606 {
607 // Fallback to parent if the prim isn't imageable or doesn't have a
608 // purpose attribute. Note that this returns the default purpose if
609 // there's no parent prim.
610 if (!*query) {
611 return *(owner->_GetValue(prim.GetParent()));
612 }
613
614 // If the prim has an authored purpose value, we get and use that.
615 if (query->HasAuthoredValue()) {
616 value_type info;
617 query->Get(&info.purpose);
618 info.isInheritable = true;
619 return info;
620 }
621
622 // Otherwise we inherit parent's purpose value, but only if the parent's
623 // purpose is inheritable. An inherited purpose is itself inheritable
624 // by child prims..
625 const value_type *v = owner->_GetValue(prim.GetParent());
626 if (v->isInheritable) {
627 return *v;
628 }
629
630 // Otherwise, get the fallback value. The fallback purpose will not
631 // be inherited by descendants.
632 value_type info;
633 query->Get(&info.purpose);
634 return info;
635 }
636
637 static
638 value_type
639 ComputePurposeInfo(UsdPrim const& prim)
640 {
642 }
643};
644
645PXR_NAMESPACE_CLOSE_SCOPE
646
647// -------------------------------------------------------------------------- //
648// Hydra MaterialBinding Cache
649// -------------------------------------------------------------------------- //
650
653
654PXR_NAMESPACE_OPEN_SCOPE
655
656struct UsdImaging_MaterialBindingImplData {
659 UsdImaging_MaterialBindingImplData(const TfToken &materialPurpose):
660 _materialPurpose(materialPurpose)
661 { }
662
665 ~UsdImaging_MaterialBindingImplData() {
666 ClearCaches();
667 }
668
670 const TfToken &GetMaterialPurpose() const {
671 return _materialPurpose;
672 }
673
677 { return _bindingsCache; }
678
681 UsdShadeMaterialBindingAPI::CollectionQueryCache & GetCollectionQueryCache()
682 { return _collQueryCache; }
683
685 void ClearCaches();
686
687private:
688 const TfToken _materialPurpose;
691};
692
693struct UsdImaging_MaterialStrategy;
694typedef UsdImaging_ResolvedAttributeCache<UsdImaging_MaterialStrategy,
695 UsdImaging_MaterialBindingImplData>
696 UsdImaging_MaterialBindingCache;
697
698struct UsdImaging_MaterialStrategy {
699 // inherited path to bound target
700 // depending on the load state, override, etc bound target path might not be
701 // queried as a UsdShadeMaterial on the stage.
702
703 // inherited path to bound target
704 typedef SdfPath value_type;
705 // Hold the computed path of the bound material or target path of the
706 // winning material binding relationship
707 typedef SdfPath query_type;
708
709 using ImplData = UsdImaging_MaterialBindingImplData;
710
711 static
712 bool ValueMightBeTimeVarying() { return false; }
713 static
714 value_type MakeDefault() { return SdfPath(); }
715
716 static
717 query_type MakeQuery(
718 UsdPrim const& prim,
719 ImplData *implData)
720 {
721 UsdRelationship bindingRel;
722 UsdShadeMaterial materialPrim =
724 &implData->GetBindingsCache(),
725 &implData->GetCollectionQueryCache(),
726 implData->GetMaterialPurpose(),
727 &bindingRel,
728 true /*supportLegacyBindings*/);
729
730 if (materialPrim) {
731 return materialPrim.GetPath();
732 }
733
734 const SdfPath targetPath =
736 bindingRel);
737 return targetPath;
738 }
739
740 static
741 value_type
742 Compute(UsdImaging_MaterialBindingCache const* owner,
743 UsdPrim const& prim,
744 query_type const* query)
745 {
746 TF_DEBUG(USDIMAGING_SHADERS).Msg("Looking for \"preview\" material "
747 "binding for %s\n", prim.GetPath().GetText());
748
749 // query already contains the resolved material binding for the prim.
750 // Hence, we don't need to inherit the binding from the parent here.
751 // Futhermore, it may be wrong to inherit the binding from the parent,
752 // because in the new scheme, a child of a bound prim can be unbound.
753 //
754 // Note that query could be an empty SdfPath, which is the default
755 // value.
756 return *query;
757 }
758
759 static
760 value_type
761 ComputeMaterialPath(UsdPrim const& prim, ImplData *implData) {
762 // We don't need to walk up the namespace here since
763 // ComputeBoundMaterial does it for us.
764 UsdRelationship bindingRel;
766 &implData->GetBindingsCache(),
767 &implData->GetCollectionQueryCache(),
768 implData->GetMaterialPurpose(),
769 &bindingRel);
770
771 const SdfPath targetPath =
773 bindingRel);
774 if (!targetPath.IsEmpty()) {
775 return targetPath;
776 }
777 return value_type();
778 }
779};
780
781PXR_NAMESPACE_CLOSE_SCOPE
782
783// -------------------------------------------------------------------------- //
784// ModelDrawMode Cache
785// -------------------------------------------------------------------------- //
786
788
789PXR_NAMESPACE_OPEN_SCOPE
790
791struct UsdImaging_DrawModeStrategy;
792typedef UsdImaging_ResolvedAttributeCache<UsdImaging_DrawModeStrategy>
793 UsdImaging_DrawModeCache;
794
795struct UsdImaging_DrawModeStrategy
796{
797 typedef TfToken value_type; // origin, bounds, cards, default, inherited
798 typedef UsdAttributeQuery query_type;
799
800 static
801 bool ValueMightBeTimeVarying() { return false; }
802 static
803 value_type MakeDefault() { return UsdGeomTokens->default_; }
804
805 static
806 query_type MakeQuery(UsdPrim const& prim, bool *) {
807 if (const UsdGeomModelAPI modelApi = UsdGeomModelAPI(prim)) {
808 return query_type(modelApi.GetModelDrawModeAttr());
809 }
810 return query_type();
811 }
812
813 static
814 value_type
815 Compute(UsdImaging_DrawModeCache const* owner,
816 UsdPrim const& prim,
817 query_type const* query)
818 {
819 // No attribute defined means inherited, means refer to the parent.
820 // Any defined attribute overrides parent opinion.
821 // If the drawMode is inherited all the way to the root of the scene,
822 // that means "default".
823 value_type v = UsdGeomTokens->inherited;
824 if (*query) {
825 query->Get(&v);
826 }
827 if (v != UsdGeomTokens->inherited) {
828 return v;
829 }
830 v = *owner->_GetValue(prim.GetParent());
831 if (v == UsdGeomTokens->inherited) {
832 return UsdGeomTokens->default_;
833 }
834 return v;
835 }
836
837 static
838 value_type
839 ComputeDrawMode(UsdPrim const& prim)
840 {
842 }
843};
844
845PXR_NAMESPACE_CLOSE_SCOPE
846
847// -------------------------------------------------------------------------- //
848// UsdGeomPointInstancer indices cache
849// -------------------------------------------------------------------------- //
850
852
853PXR_NAMESPACE_OPEN_SCOPE
854
855struct UsdImaging_PointInstancerIndicesStrategy;
856typedef UsdImaging_ResolvedAttributeCache<UsdImaging_PointInstancerIndicesStrategy>
857 UsdImaging_PointInstancerIndicesCache;
858
859struct UsdImaging_PointInstancerIndicesStrategy
860{
861 // map from protoIndex -> instanceIndices.
862 typedef VtArray<VtIntArray> value_type;
863 // We don't use query_type, but can't set it to void.
864 typedef int query_type;
865
866 // XXX: Most indices values will be static, but since they *can*
867 // be animated, we need to return true here to get invalidation on
868 // time-change. It would be nice to add a per-entry time-varying bit
869 // to the resolved cache, instead of having the global per-attribute
870 // bit.
871 //
872 // In this particular case, instance indices are only recomputed when
873 // we see "DirtyInstanceIndex" in UpdateForTime, so though we'll be
874 // clearing cache entries out of the resolved cache on time-change,
875 // we won't actually call out to the attribute cache on static indices.
876 static
877 bool ValueMightBeTimeVarying() { return true; }
878 static
879 value_type MakeDefault() { return value_type(); }
880
881 static
882 query_type MakeQuery(UsdPrim const& prim, bool *) {
883 return 0;
884 }
885
886 static
887 value_type
888 Compute(UsdImaging_PointInstancerIndicesCache const* owner,
889 UsdPrim const& prim,
890 query_type const* query)
891 {
892 return ComputePerPrototypeIndices(prim, owner->GetTime());
893 }
894
895 static
896 value_type
897 ComputePerPrototypeIndices(UsdPrim const& prim, UsdTimeCode time)
898 {
899 value_type v;
900
901 UsdGeomPointInstancer pi(prim);
902 VtIntArray protoIndices;
903 if (!pi.GetProtoIndicesAttr().Get(&protoIndices, time)) {
904 TF_WARN("Failed to read point instancer protoIndices");
905 return v;
906 }
907
908 std::vector<bool> mask = pi.ComputeMaskAtTime(time);
909
910 for (size_t instanceId = 0; instanceId < protoIndices.size(); ++instanceId) {
911 size_t protoIndex = protoIndices.AsConst()[instanceId];
912
913 if (protoIndex >= v.size()) {
914 v.resize(protoIndex + 1);
915 }
916
917 if (mask.size() == 0 || mask[instanceId]) {
918 v[protoIndex].push_back(instanceId);
919 }
920 }
921
922 return v;
923 }
924};
925
926PXR_NAMESPACE_CLOSE_SCOPE
927
928// -------------------------------------------------------------------------- //
929// CoordSysBinding Cache
930// -------------------------------------------------------------------------- //
931
933#include "pxr/imaging/hd/coordSys.h"
934
935PXR_NAMESPACE_OPEN_SCOPE
936
937struct UsdImaging_CoordSysBindingStrategy;
938
939typedef UsdImaging_ResolvedAttributeCache<UsdImaging_CoordSysBindingStrategy>
940 UsdImaging_CoordSysBindingCache;
941
942struct UsdImaging_CoordSysBindingStrategy
943{
944 typedef std::vector<UsdShadeCoordSysAPI::Binding> UsdBindingVec;
945 typedef std::shared_ptr<UsdBindingVec> UsdBindingVecPtr;
946 typedef std::shared_ptr<SdfPathVector> IdVecPtr;
947
948 struct value_type {
949 IdVecPtr idVecPtr;
950 UsdBindingVecPtr usdBindingVecPtr;
951 };
952 typedef int query_type;
953
954 static
955 bool ValueMightBeTimeVarying() { return false; }
956
957 static
958 value_type MakeDefault() {
959 return value_type();
960 }
961
962 static
963 query_type MakeQuery(UsdPrim const& prim, bool *) {
964 return 0;
965 }
966
967 static
968 value_type
969 Compute(UsdImaging_CoordSysBindingCache const* owner,
970 UsdPrim const& prim,
971 query_type const* query)
972 {
973 value_type v;
974
975 // Pull inherited bindings first.
976 if (UsdPrim parentPrim = prim.GetParent()) {
977 v = *owner->_GetValue(parentPrim);
978 }
979
980 auto _IterateLocalBindings = [&prim](const UsdBindingVec &localBindings,
981 SdfPathVector &hdIds, UsdBindingVec &usdBindings) {
982 for (const UsdShadeCoordSysAPI::Binding &binding : localBindings) {
983 if (!prim.GetStage()->GetPrimAtPath(
984 binding.coordSysPrimPath).IsValid()) {
985 // The target xform prim does not exist, so ignore this
986 // coord sys binding.
987 TF_WARN("UsdImaging: Ignore coordinate system binding to "
988 "non-existent prim <%s>\n",
989 binding.coordSysPrimPath.GetText());
990 continue;
991 }
992 bool found = false;
993 for (size_t id = 0, n = hdIds.size(); id < n; ++id) {
994 if (usdBindings[id].name == binding.name) {
995 // Found an override -- replace this binding.
996 usdBindings[id] = binding;
997 hdIds[id] = binding.bindingRelPath;
998 found = true;
999 break;
1000 }
1001 }
1002 if (!found) {
1003 // New binding, so append.
1004 usdBindings.push_back(binding);
1005 hdIds.push_back(binding.bindingRelPath);
1006 }
1007 }
1008 };
1009
1010 // XXX: Make sure to update the following code when
1011 // UsdShadeCoordSysAPI's old non-applied mode is completely removed.
1012 UsdShadeCoordSysAPI coordSysAPI = UsdShadeCoordSysAPI(prim,
1013 TfToken("noop"));
1014 bool hasLocalBindings = coordSysAPI.HasLocalBindings();
1015 UsdBindingVec localBindings = coordSysAPI.GetLocalBindings();
1016
1017 //Merge any local bindings.
1018 if (hasLocalBindings && !localBindings.empty()) {
1019 SdfPathVector hdIds;
1020 UsdBindingVec usdBindings;
1021 if (v.idVecPtr) {
1022 hdIds = *v.idVecPtr;
1023 }
1024 if (v.usdBindingVecPtr) {
1025 usdBindings = *v.usdBindingVecPtr;
1026 }
1027 _IterateLocalBindings(localBindings, hdIds, usdBindings);
1028 v.idVecPtr.reset(new SdfPathVector(std::move(hdIds)));
1029 v.usdBindingVecPtr.reset(new UsdBindingVec(std::move(usdBindings)));
1030 }
1031
1032 return v;
1033 }
1034};
1035
1036PXR_NAMESPACE_CLOSE_SCOPE
1037
1038// -------------------------------------------------------------------------- //
1039// Nonlinear sample count Primvar Cache
1040// -------------------------------------------------------------------------- //
1041
1043
1044PXR_NAMESPACE_OPEN_SCOPE
1045
1046struct UsdImaging_NonlinearSampleCountStrategy;
1047typedef UsdImaging_ResolvedAttributeCache<
1048 UsdImaging_NonlinearSampleCountStrategy>
1049 UsdImaging_NonlinearSampleCountCache;
1050
1051struct UsdImaging_NonlinearSampleCountStrategy
1052{
1053 typedef int value_type;
1054 typedef UsdAttributeQuery query_type;
1055
1056 // Used to indicate that no (valid) opinion exists
1057 // for nonlinear sample count.
1058 static constexpr value_type invalidValue = -1;
1059
1060 static
1061 bool ValueMightBeTimeVarying() { return true; }
1062
1063 static
1064 value_type MakeDefault() {
1065 return invalidValue;
1066 }
1067
1068 static
1069 query_type MakeQuery(UsdPrim const& prim, bool *) {
1070 if (const UsdGeomMotionAPI motionAPI = UsdGeomMotionAPI(prim)) {
1071 return query_type(motionAPI.GetNonlinearSampleCountAttr());
1072 }
1073 return query_type();
1074 }
1075
1076 static
1077 value_type
1078 Compute(UsdImaging_NonlinearSampleCountCache const* owner,
1079 UsdPrim const& prim,
1080 query_type const* query)
1081 {
1082 if (query->HasAuthoredValue()) {
1083 int value;
1084 if (query->Get(&value, owner->GetTime())) {
1085 return value;
1086 }
1087 }
1088
1089 return *owner->_GetValue(prim.GetParent());
1090 }
1091
1092 static
1093 value_type
1094 ComputeNonlinearSampleCount(UsdPrim const &prim, UsdTimeCode time)
1095 {
1097 }
1098};
1099
1100PXR_NAMESPACE_CLOSE_SCOPE
1101
1102// -------------------------------------------------------------------------- //
1103// Blur scale Primvar Cache
1104// -------------------------------------------------------------------------- //
1105
1107
1108PXR_NAMESPACE_OPEN_SCOPE
1109
1110struct UsdImaging_BlurScaleStrategy;
1111typedef UsdImaging_ResolvedAttributeCache<UsdImaging_BlurScaleStrategy>
1112 UsdImaging_BlurScaleCache;
1113
1114struct UsdImaging_BlurScaleStrategy
1115{
1116 struct value_type {
1117 float value;
1118 bool has_value;
1119 };
1120
1121 typedef UsdAttributeQuery query_type;
1122
1123 // Used to indicate that no (valid) opinion exists
1124 // for blur scale.
1125 static const value_type invalidValue;
1126
1127 static
1128 bool ValueMightBeTimeVarying() { return true; }
1129
1130 static
1131 value_type MakeDefault() {
1132 return invalidValue;
1133 }
1134
1135 static
1136 query_type MakeQuery(UsdPrim const& prim, bool *) {
1137 if (const UsdGeomMotionAPI motionAPI = UsdGeomMotionAPI(prim)) {
1138 return query_type(motionAPI.GetMotionBlurScaleAttr());
1139 }
1140 return query_type();
1141 }
1142
1143 static
1144 value_type
1145 Compute(UsdImaging_BlurScaleCache const* owner,
1146 UsdPrim const& prim,
1147 query_type const* query)
1148 {
1149 if (query->HasAuthoredValue()) {
1150 float value;
1151 if (query->Get(&value, owner->GetTime())) {
1152 return { value, true };
1153 }
1154 }
1155
1156 return *owner->_GetValue(prim.GetParent());
1157 }
1158
1159 static
1160 value_type
1161 ComputeBlurScale(UsdPrim const &prim, UsdTimeCode time)
1162 {
1163 return { UsdGeomMotionAPI(prim).ComputeMotionBlurScale(time), true };
1164 }
1165};
1166
1167PXR_NAMESPACE_CLOSE_SCOPE
1168
1169// -------------------------------------------------------------------------- //
1170// Inherited Primvar Cache
1171// -------------------------------------------------------------------------- //
1172
1174
1175PXR_NAMESPACE_OPEN_SCOPE
1176
1177struct UsdImaging_InheritedPrimvarStrategy;
1178typedef UsdImaging_ResolvedAttributeCache<UsdImaging_InheritedPrimvarStrategy>
1179 UsdImaging_InheritedPrimvarCache;
1180
1181struct UsdImaging_InheritedPrimvarStrategy
1182{
1183 struct PrimvarRecord {
1184 std::vector<UsdGeomPrimvar> primvars;
1185 bool variable;
1186 };
1187 typedef std::shared_ptr<PrimvarRecord> value_type;
1188 typedef UsdGeomPrimvarsAPI query_type;
1189
1190 // While primvar data might be time-varying, the set of primvars applying
1191 // to a prim will not.
1192 static
1193 bool ValueMightBeTimeVarying() { return false; }
1194
1195 static
1196 value_type MakeDefault() {
1197 return value_type();
1198 }
1199
1200 static
1201 query_type MakeQuery(UsdPrim const& prim, bool *) {
1202 return query_type(UsdGeomPrimvarsAPI(prim));
1203 }
1204
1205 static
1206 value_type Compute(UsdImaging_InheritedPrimvarCache const* owner,
1207 UsdPrim const& prim,
1208 query_type const* query)
1209 {
1210 value_type v;
1211 if (*query) {
1212 // Pull inherited bindings first.
1213 if (UsdPrim parentPrim = prim.GetParent()) {
1214 v = *owner->_GetValue(parentPrim);
1215 }
1216 // Merge any local bindings.
1217 std::vector<UsdGeomPrimvar> primvars =
1218 query->FindIncrementallyInheritablePrimvars(
1219 v ? v->primvars : std::vector<UsdGeomPrimvar>());
1220 if (!primvars.empty()) {
1221 v = std::make_shared<PrimvarRecord>();
1222 v->primvars = std::move(primvars);
1223 v->variable = false;
1224 for (UsdGeomPrimvar const& pv : v->primvars) {
1225 if (pv.ValueMightBeTimeVarying()) {
1226 v->variable = true;
1227 break;
1228 }
1229 }
1230 }
1231 }
1232 return v;
1233 }
1234};
1235
1236PXR_NAMESPACE_CLOSE_SCOPE
1237
1238#endif
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:66
Stores a 4x4 matrix of double elements.
Definition: matrix4d.h:71
A path value used to locate objects in layers or scenegraphs.
Definition: path.h:274
SDF_API const std::string & GetString() const
Return the string representation of this path as a std::string.
SDF_API const char * GetText() const
Returns the string representation of this path as a c string.
bool IsEmpty() const noexcept
Returns true if this is the empty path (SdfPath::EmptyPath()).
Definition: path.h:398
SDF_API bool IsAbsolutePath() const
Returns whether the path is absolute.
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.
Token for efficient comparison, assignment, and hashing of known strings.
Definition: token.h:71
Object for efficiently making repeated queries for attribute values.
Base class for all prims that may require rendering or visualization of some sort.
Definition: imageable.h:58
USDGEOM_API PurposeInfo ComputePurposeInfo() const
Calculate the effective purpose information about this prim which includes final computed purpose val...
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...
UsdGeomModelAPI extends the generic UsdModelAPI schema with geometry specific concepts such as cached...
Definition: modelAPI.h:137
USDGEOM_API TfToken ComputeModelDrawMode(const TfToken &parentDrawMode=TfToken()) const
Calculate the effective model:drawMode of this prim.
UsdGeomMotionAPI encodes data that can live on any prim that may affect computations involving:
Definition: motionAPI.h:51
USDGEOM_API float ComputeMotionBlurScale(UsdTimeCode time=UsdTimeCode::Default()) const
Compute the inherited value of motion:blurScale at time, i.e.
USDGEOM_API int ComputeNonlinearSampleCount(UsdTimeCode time=UsdTimeCode::Default()) const
Compute the inherited value of nonlinearSampleCount at time, i.e.
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:248
USDGEOM_API bool ValueMightBeTimeVarying() const
Return true if it is possible, but not certain, that this primvar's value changes over time,...
UsdGeomPrimvarsAPI encodes geometric "primitive variables", as UsdGeomPrimvar, which interpolate acro...
Definition: primvarsAPI.h:66
Helper class that caches the ordered vector of UsGeomXformOps that contribute to the local transforma...
Definition: xformable.h:368
Base class for all transformable prims, which allows arbitrary sequences of component affine transfor...
Definition: xformable.h:242
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:186
USD_API UsdStageWeakPtr GetStage() const
Return the stage that owns the object, and to whose state and lifetime this object's validity is tied...
UsdPrim is the sole persistent scenegraph object on a UsdStage, and is the embodiment of a "Prim" as ...
Definition: prim.h:117
UsdPrim GetParent() const
Return this prim's parent prim.
Definition: prim.h:1535
bool IsPrototype() const
Return true if this prim is an instancing prototype prim, false otherwise.
Definition: prim.h:2077
bool IsInPrototype() const
Return true if this prim is a prototype prim or a descendant of a prototype prim, false otherwise.
Definition: prim.h:2083
An forward-iterable range that traverses a subtree of prims rooted at a given prim in depth-first ord...
Definition: primRange.h:102
A UsdRelationship creates dependencies between scenegraph objects by allowing a prim to target other ...
Definition: relationship.h:111
SdfPath GetPath() const
Shorthand for GetPrim()->GetPath().
Definition: schemaBase.h:106
UsdShadeCoordSysAPI provides a way to designate, name, and discover coordinate systems.
Definition: coordSysAPI.h:66
USDSHADE_API std::vector< Binding > GetLocalBindings() const
Get the list of coordinate system bindings local to this prim.
USDSHADE_API bool HasLocalBindings() const
Returns true if the prim has local coordinate system relationship exists.
A coordinate system binding.
Definition: coordSysAPI.h:256
UsdShadeMaterialBindingAPI is an API schema that provides an interface for binding materials to prims...
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.
static USDSHADE_API const SdfPath GetResolvedTargetPathFromBindingRel(const UsdRelationship &bindingRel)
returns the path of the resolved target identified by bindingRel.
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.
USDSHADE_API UsdShadeMaterial ComputeBoundMaterial(BindingsCache *bindingsCache, CollectionQueryCache *collectionQueryCache, const TfToken &materialPurpose=UsdShadeTokens->allPurpose, UsdRelationship *bindingRel=nullptr, bool supportLegacyBindings=true) const
Computes the resolved bound material for this prim, for the given material purpose.
A Material provides a container into which multiple "render contexts" can add data that defines a "sh...
Definition: material.h:96
Represent a time value, which may be either numeric, holding a double value, or a sentinel value UsdT...
Definition: timeCode.h:72
Represents an arbitrary dimensional rectangular container class.
Definition: array.h:213
#define TF_FOR_ALL(iter, c)
Macro for iterating over a container.
Definition: iterator.h:373
#define TF_DEBUG(enumVal)
Evaluate and print debugging message msg if enumVal is enabled for debugging.
Definition: debug.h:484
#define TF_CODING_ERROR(fmt, args)
Issue an internal programming error, but continue execution.
Definition: diagnostic.h:68
#define TF_WARN(...)
Issue a warning, but continue execution.
Definition: diagnostic.h:132
STL namespace.
Value type containing information about a prim's computed effective purpose as well as storing whethe...
Definition: imageable.h:383
TfToken class for efficient string referencing and hashing, plus conversions to and from stl string c...
USDGEOM_API TfStaticData< UsdGeomTokensType > UsdGeomTokens
A global variable with static, efficient TfTokens for use in all public USD API.