Loading...
Searching...
No Matches
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/tf/hash.h"
37#include "pxr/base/work/utils.h"
38
39#include "pxr/base/tf/hash.h"
40
41#include <tbb/concurrent_unordered_map.h>
42#include <functional>
43
44PXR_NAMESPACE_OPEN_SCOPE
45
68template<typename Strategy, typename ImplData=bool>
69class UsdImaging_ResolvedAttributeCache
70{
71 friend Strategy;
72 struct _Entry;
73 using _CacheMap = tbb::concurrent_unordered_map<UsdPrim, _Entry, TfHash>;
74public:
75 typedef typename Strategy::value_type value_type;
76 typedef typename Strategy::query_type query_type;
77
78 using ValueOverridesMap = TfHashMap<UsdPrim, value_type, TfHash>;
79
81 explicit UsdImaging_ResolvedAttributeCache(
82 const UsdTimeCode time,
83 ImplData *implData=nullptr,
84 const ValueOverridesMap valueOverrides=ValueOverridesMap())
85 : _time(time)
86 , _rootPath(SdfPath::AbsoluteRootPath())
87 , _cacheVersion(_GetInitialCacheVersion())
88 , _valueOverrides(valueOverrides)
89 , _implData(implData)
90 {
91 }
92
94 UsdImaging_ResolvedAttributeCache()
95 : _time(UsdTimeCode::Default())
96 , _rootPath(SdfPath::AbsoluteRootPath())
97 , _cacheVersion(1)
98 {
99 }
100
101 ~UsdImaging_ResolvedAttributeCache()
102 {
103 WorkSwapDestroyAsync(_cache);
104 }
105
106
109 value_type GetValue(const UsdPrim& prim) const
110 {
112 if (!prim.GetPath().HasPrefix(_rootPath) && !prim.IsInPrototype()) {
113 TF_CODING_ERROR("Attempt to get value for: %s "
114 "which is not within the specified root: %s",
115 prim.GetPath().GetString().c_str(),
116 _rootPath.GetString().c_str());
117 return Strategy::MakeDefault();
118 }
119
120 return *_GetValue(prim);
121 }
122
126 query_type const*
127 GetQuery(const UsdPrim& prim) const {
128 return &_GetCacheEntryForPrim(prim)->query;
129 }
130
132 void Clear() {
133 WorkSwapDestroyAsync(_cache);
134 _cacheVersion = _GetInitialCacheVersion();
135 }
136
140 void SetTime(UsdTimeCode time) {
141 if (time == _time)
142 return;
143
144 if (Strategy::ValueMightBeTimeVarying()) {
145 // Mark all cached entries as invalid, but leave the queries behind.
146 // We increment by 2 here and always keep the version an odd number,
147 // this enables the use of even versions as a per-entry spin lock.
148 _cacheVersion += 2;
149 }
150
151 // Update to correct time.
152 _time = time;
153 }
154
156 UsdTimeCode GetTime() const { return _time; }
157
166 void SetRootPath(const SdfPath& rootPath) {
167 if (!rootPath.IsAbsolutePath()) {
168 TF_CODING_ERROR("Invalid root path: %s",
169 rootPath.GetString().c_str());
170 return;
171 }
172
173 if (rootPath == _rootPath)
174 return;
175
176 Clear();
177 _rootPath = rootPath;
178 }
179
182 const SdfPath & GetRootPath() const { return _rootPath; }
183
194 void UpdateValueOverrides(const ValueOverridesMap &valueOverrides,
195 const std::vector<UsdPrim> &overridesToRemove,
196 std::vector<SdfPath> *dirtySubtreeRoots)
197 {
199
200 if (valueOverrides.empty() && overridesToRemove.empty())
201 return;
202
203 ValueOverridesMap valueOverridesToProcess;
204 SdfPathVector processedOverridePaths;
205 TF_FOR_ALL(it, valueOverrides) {
206 const UsdPrim &prim = it->first;
207 const value_type &value = it->second;
208
209 // If the existing value matches the incoming value, skip
210 // the update and dirtying.
211 if (*_GetValue(prim) == value)
212 continue;
213
214 valueOverridesToProcess[prim] = value;
215 }
216
217 TF_FOR_ALL(it, valueOverridesToProcess) {
218 const UsdPrim &prim = it->first;
219 const value_type &value = it->second;
220
221 // XXX: performance
222 // We could probably make this faster by using a hash table of
223 // prefixes. This hasn't showed up in traces much though as it's not
224 // common to update value overrides for more than one path at a
225 // time.
226 bool isDescendantOfProcessedOverride = false;
227 for (const SdfPath &processedPath : processedOverridePaths) {
228 if (prim.GetPath().HasPrefix(processedPath)) {
229 isDescendantOfProcessedOverride = true;
230 break;
231 }
232 }
233
234 // Invalidate cache entries if the prim is not a descendant of a
235 // path that has already been processed.
236 if (!isDescendantOfProcessedOverride) {
237 for (UsdPrim descendant: UsdPrimRange(prim)) {
238 if (_Entry* entry = _GetCacheEntryForPrim(descendant)) {
239 entry->version = _GetInvalidVersion();
240 }
241 }
242 processedOverridePaths.push_back(prim.GetPath());
243 dirtySubtreeRoots->push_back(prim.GetPath());
244 }
245
246 // Update overrides in the internal value overrides map.
247 _valueOverrides[prim] = value;
248 }
249
250 for (const UsdPrim &prim : overridesToRemove) {
251
252 // Erase the entry from the map of overrides.
253 size_t numErased = _valueOverrides.erase(prim);
254
255 // If the override doesn't exist, then there's nothing to do.
256 if (numErased == 0) {
257 continue;
258 }
259
260 bool isDescendantOfProcessedOverride = false;
261 for (const SdfPath &processedPath : processedOverridePaths) {
262 if (prim.GetPath().HasPrefix(processedPath)) {
263 isDescendantOfProcessedOverride = true;
264 break;
265 }
266 }
267
268 // Invalidate cache entries if the prim is not a descendant of a
269 // path that has already been processed.
270 if (!isDescendantOfProcessedOverride) {
271 for (UsdPrim descendant: UsdPrimRange(prim)) {
272 if (_Entry* entry = _GetCacheEntryForPrim(descendant)) {
273 entry->version = _GetInvalidVersion();
274 }
275 }
276 dirtySubtreeRoots->push_back(prim.GetPath());
277 processedOverridePaths.push_back(prim.GetPath());
278 }
279 }
280 }
281
282private:
283 // Cached value entries. Note that because query objects may be caching
284 // non-time varying data, entries may exist in the cache with invalid
285 // values. The version is used to determine validity.
286 struct _Entry {
287 _Entry()
288 : value(Strategy::MakeDefault())
289 , version(_GetInitialEntryVersion())
290 { }
291
292 _Entry(const query_type & query_,
293 const value_type& value_,
294 unsigned version_)
295 : query(query_)
296 , value(value_)
297 , version(version_)
298 { }
299
300 query_type query;
301 value_type value;
302 tbb::atomic<unsigned> version;
303 };
304
305 // Returns the version number for a valid cache entry
306 unsigned _GetValidVersion() const { return _cacheVersion + 1; }
307
308 // Returns the version number for an invalid cache entry
309 unsigned _GetInvalidVersion() const { return _cacheVersion - 1; }
310
311 // Initial version numbers
312 static unsigned _GetInitialCacheVersion() { return 1; }
313 static unsigned _GetInitialEntryVersion() {
314 return _GetInitialCacheVersion()-1;
315 }
316
317 // Traverse the hierarchy (order is strategy dependent) and compute the
318 // inherited value.
319 value_type const* _GetValue(const UsdPrim& prim) const;
320
321 // Helper function to get or create a new entry for a prim in the cache.
322 _Entry* _GetCacheEntryForPrim(const UsdPrim &prim) const;
323
324 // Sets the value of the given cache entry. If multiple threads attempt to
325 // set the same entry, the first in wins and other threads spin until the
326 // new value is set.
327 void _SetCacheEntryForPrim(const UsdPrim &prim,
328 value_type const& value,
329 _Entry* entry) const;
330
331 // Mutable is required here to allow const methods to update the cache when
332 // it is thread safe, however not all mutations of this map are thread safe.
333 // See underlying map documentation for details.
334 mutable _CacheMap _cache;
335
336 // The time at which this stack is querying and caching attribute values.
337 UsdTimeCode _time;
338 SdfPath _rootPath;
339
340 // A serial number indicating the valid state of entries in the cache. When
341 // an entry has an equal or greater value, the entry is valid.
342 tbb::atomic<unsigned> _cacheVersion;
343
344 // Value overrides for a set of descendents.
345 ValueOverridesMap _valueOverrides;
346
347 // Supplemental cache if used by this inherited cache.
348 ImplData *_implData;
349};
350
351template<typename Strategy, typename ImplData>
352void
353UsdImaging_ResolvedAttributeCache<Strategy,ImplData>::_SetCacheEntryForPrim(
354 const UsdPrim &prim,
355 value_type const& value,
356 _Entry* entry) const
357{
358 // Note: _cacheVersion is not allowed to change during cache access.
359 unsigned v = entry->version;
360 if (v < _cacheVersion
361 && entry->version.compare_and_swap(_cacheVersion, v) == v)
362 {
363 entry->value = value;
364 entry->version = _GetValidVersion();
365 } else {
366 while (entry->version != _GetValidVersion()) {
367 // Future work: A suggestion is that rather than literally spinning
368 // here, we should use the pause instruction, which sleeps for one
369 // cycle while allowing hyper threads to continue. Folly has a nice
370 // implementation of this packaged up as "sleeper", which we could
371 // also implement in Work and Arch.
372 }
373 }
374}
375
376template<typename Strategy, typename ImplData>
377typename UsdImaging_ResolvedAttributeCache<Strategy, ImplData>::_Entry*
378UsdImaging_ResolvedAttributeCache<Strategy, ImplData>::_GetCacheEntryForPrim(
379 const UsdPrim &prim) const
380{
381 typename _CacheMap::const_iterator it = _cache.find(prim);
382 if (it != _cache.end()) {
383 return &it->second;
384 }
385
386 _Entry e;
387 e.query = Strategy::MakeQuery(prim, _implData);
388 e.value = Strategy::MakeDefault();
389 e.version = _GetInvalidVersion();
390 return &(_cache.insert(
391 typename _CacheMap::value_type(prim, e)).first->second);
392}
393
394template<typename Strategy, typename ImplData>
395typename UsdImaging_ResolvedAttributeCache<Strategy, ImplData>::value_type const*
396UsdImaging_ResolvedAttributeCache<Strategy, ImplData>::_GetValue(
397 const UsdPrim& prim) const
398{
399 static value_type const default_ = Strategy::MakeDefault();
400
401 // Base case.
402 if (!prim || prim.IsPrototype() || prim.GetPath() == _rootPath)
403 return &default_;
404
405 _Entry* entry = _GetCacheEntryForPrim(prim);
406 if (entry->version == _GetValidVersion()) {
407 // Cache hit
408 return &entry->value;
409 }
410
411 // Future work: Suggestion is that when multiple threads are computing the
412 // same value, we could block all but one thread here, possibly rescheduling
413 // blocked threads as continuations, rather than allowing all threads to
414 // continue to race until a cache hit is encountered.
415
416 // Future work: A suggestion is that we make this iterative instead of
417 // recursive.
418 typename ValueOverridesMap::const_iterator it =
419 _valueOverrides.find(prim);
420 if (it != _valueOverrides.end()) {
421 _SetCacheEntryForPrim(prim, it->second, entry);
422 } else {
423 _SetCacheEntryForPrim(prim,
424 Strategy::Compute(this, prim, &entry->query),
425 entry);
426 }
427 return &entry->value;
428}
429
430PXR_NAMESPACE_CLOSE_SCOPE
431
432// -------------------------------------------------------------------------- //
433// Xform Cache
434// -------------------------------------------------------------------------- //
435
437#include "pxr/base/gf/matrix4d.h"
438
439PXR_NAMESPACE_OPEN_SCOPE
440
441struct UsdImaging_XfStrategy;
442typedef UsdImaging_ResolvedAttributeCache<UsdImaging_XfStrategy> UsdImaging_XformCache;
443
444struct UsdImaging_XfStrategy {
445 typedef GfMatrix4d value_type;
446 typedef UsdGeomXformable::XformQuery query_type;
447
448 static
449 bool ValueMightBeTimeVarying() { return true; }
450 static
451 value_type MakeDefault() { return GfMatrix4d(1); }
452
453 static
454 query_type MakeQuery(UsdPrim const& prim, bool *) {
455 if (const UsdGeomXformable xf = UsdGeomXformable(prim)) {
456 return query_type(xf);
457 }
458 return query_type();
459 }
460
461 static
462 value_type
463 Compute(UsdImaging_XformCache const* owner,
464 UsdPrim const& prim,
465 query_type const* query)
466 {
467 value_type xform = MakeDefault();
468 // No need to check query validity here because XformQuery doesn't
469 // support it.
470 query->GetLocalTransformation(&xform, owner->GetTime());
471
472 return !query->GetResetXformStack()
473 ? (xform * (*owner->_GetValue(prim.GetParent())))
474 : xform;
475 }
476
477 // Compute the full transform, this is not part of the interface required by
478 // the cache.
479 static
480 value_type
481 ComputeTransform(UsdPrim const& prim,
482 SdfPath const& rootPath,
483 UsdTimeCode time,
484 const TfHashMap<SdfPath, GfMatrix4d, SdfPath::Hash> &ctmOverrides)
485 {
486 bool reset = false;
487 GfMatrix4d ctm(1.0);
488 GfMatrix4d localXf(1.0);
489 UsdPrim p = prim;
490 while (p && p.GetPath() != rootPath) {
491 const auto &overIt = ctmOverrides.find(p.GetPath());
492 // If there's a ctm override, use it and break out of the loop.
493 if (overIt != ctmOverrides.end()) {
494 ctm *= overIt->second;
495 break;
496 } else if (UsdGeomXformable xf = UsdGeomXformable(p)) {
497 if (xf.GetLocalTransformation(&localXf, &reset, time))
498 ctm *= localXf;
499 if (reset)
500 break;
501 }
502 p = p.GetParent();
503 }
504 return ctm;
505 }
506};
507
508PXR_NAMESPACE_CLOSE_SCOPE
509
510// -------------------------------------------------------------------------- //
511// Visibility Cache
512// -------------------------------------------------------------------------- //
513
515#include "pxr/base/tf/token.h"
516#include "pxr/usdImaging/usdImaging/debugCodes.h"
517
518PXR_NAMESPACE_OPEN_SCOPE
519
520struct UsdImaging_VisStrategy;
521using UsdImaging_VisCache =
522 UsdImaging_ResolvedAttributeCache<UsdImaging_VisStrategy>;
523
527struct UsdImaging_VisStrategy {
528 typedef TfToken value_type; // invisible, inherited
529 typedef UsdAttributeQuery query_type;
530
531 static
532 bool ValueMightBeTimeVarying() { return true; }
533
534 static
535 value_type MakeDefault() { return UsdGeomTokens->inherited; }
536
537 static
538 query_type MakeQuery(UsdPrim const& prim, bool *)
539 {
540 if (const UsdGeomImageable xf = UsdGeomImageable(prim)) {
541 return query_type(xf.GetVisibilityAttr());
542 }
543 return query_type();
544 }
545
546 static
547 value_type
548 Compute(UsdImaging_VisCache const* owner,
549 UsdPrim const& prim,
550 query_type const* query)
551 {
552 value_type v = *owner->_GetValue(prim.GetParent());
553
554 // If prim inherits 'invisible', then it's invisible, due to pruning
555 // visibility.
556 if (v == UsdGeomTokens->invisible) {
557 return v;
558 }
559
560 // Otherwise, prim's value, if it has one, determines its visibility.
561 if (*query) {
562 query->Get(&v, owner->GetTime());
563 }
564 return v;
565 }
566
567 static
568 value_type
569 ComputeVisibility(UsdPrim const& prim, UsdTimeCode time)
570 {
571 return UsdGeomImageable(prim).ComputeVisibility(time);
572 }
573};
574
575// -------------------------------------------------------------------------- //
576// Purpose Cache
577// -------------------------------------------------------------------------- //
578
579struct UsdImaging_PurposeStrategy;
580typedef UsdImaging_ResolvedAttributeCache<UsdImaging_PurposeStrategy>
581 UsdImaging_PurposeCache;
582
583struct UsdImaging_PurposeStrategy {
584 // For proper inheritance, we need to return the PurposeInfo struct which
585 // stores whether child prims can inherit the parent's computed purpose
586 // when they don't have an authored purpose of their own.
587 typedef UsdGeomImageable::PurposeInfo value_type; // purpose, inherited
588 typedef UsdAttributeQuery query_type;
589
590 static
591 value_type MakeDefault() {
592 // Return the fallback default instead of an empty purpose info.
593 return value_type(UsdGeomTokens->default_, false);
594 }
595
596 static
597 query_type MakeQuery(UsdPrim const& prim, bool *) {
598 if (const UsdGeomImageable im = UsdGeomImageable(prim)) {
599 return query_type(im.GetPurposeAttr());
600 }
601 return query_type();
602 }
603
604 static
605 value_type
606 Compute(UsdImaging_PurposeCache const* owner,
607 UsdPrim const& prim,
608 query_type const* query)
609 {
610 // Fallback to parent if the prim isn't imageable or doesn't have a
611 // purpose attribute. Note that this returns the default purpose if
612 // there's no parent prim.
613 if (!*query) {
614 return *(owner->_GetValue(prim.GetParent()));
615 }
616
617 // If the prim has an authored purpose value, we get and use that.
618 if (query->HasAuthoredValue()) {
619 value_type info;
620 query->Get(&info.purpose);
621 info.isInheritable = true;
622 return info;
623 }
624
625 // Otherwise we inherit parent's purpose value, but only if the parent's
626 // purpose is inheritable. An inherited purpose is itself inheritable
627 // by child prims..
628 const value_type *v = owner->_GetValue(prim.GetParent());
629 if (v->isInheritable) {
630 return *v;
631 }
632
633 // Otherwise, get the fallback value. The fallback purpose will not
634 // be inherited by descendants.
635 value_type info;
636 query->Get(&info.purpose);
637 return info;
638 }
639
640 static
641 value_type
642 ComputePurposeInfo(UsdPrim const& prim)
643 {
645 }
646};
647
648PXR_NAMESPACE_CLOSE_SCOPE
649
650// -------------------------------------------------------------------------- //
651// Hydra MaterialBinding Cache
652// -------------------------------------------------------------------------- //
653
656
657PXR_NAMESPACE_OPEN_SCOPE
658
659struct UsdImaging_MaterialBindingImplData {
662 UsdImaging_MaterialBindingImplData(const TfToken &materialPurpose):
663 _materialPurpose(materialPurpose)
664 { }
665
668 ~UsdImaging_MaterialBindingImplData() {
669 ClearCaches();
670 }
671
673 const TfToken &GetMaterialPurpose() const {
674 return _materialPurpose;
675 }
676
680 { return _bindingsCache; }
681
684 UsdShadeMaterialBindingAPI::CollectionQueryCache & GetCollectionQueryCache()
685 { return _collQueryCache; }
686
688 void ClearCaches();
689
690private:
691 const TfToken _materialPurpose;
694};
695
696struct UsdImaging_MaterialStrategy;
697typedef UsdImaging_ResolvedAttributeCache<UsdImaging_MaterialStrategy,
698 UsdImaging_MaterialBindingImplData>
699 UsdImaging_MaterialBindingCache;
700
701struct UsdImaging_MaterialStrategy {
702 // inherited path to bound target
703 // depending on the load state, override, etc bound target path might not be
704 // queried as a UsdShadeMaterial on the stage.
705
706 // inherited path to bound target
707 typedef SdfPath value_type;
708 // Hold the computed path of the bound material or target path of the
709 // winning material binding relationship
710 typedef SdfPath query_type;
711
712 using ImplData = UsdImaging_MaterialBindingImplData;
713
714 static
715 bool ValueMightBeTimeVarying() { return false; }
716 static
717 value_type MakeDefault() { return SdfPath(); }
718
719 static
720 query_type MakeQuery(
721 UsdPrim const& prim,
722 ImplData *implData)
723 {
724 UsdRelationship bindingRel;
725 UsdShadeMaterial materialPrim =
727 &implData->GetBindingsCache(),
728 &implData->GetCollectionQueryCache(),
729 implData->GetMaterialPurpose(),
730 &bindingRel,
731 true /*supportLegacyBindings*/);
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
784PXR_NAMESPACE_CLOSE_SCOPE
785
786// -------------------------------------------------------------------------- //
787// ModelDrawMode Cache
788// -------------------------------------------------------------------------- //
789
791
792PXR_NAMESPACE_OPEN_SCOPE
793
794struct UsdImaging_DrawModeStrategy;
795typedef UsdImaging_ResolvedAttributeCache<UsdImaging_DrawModeStrategy>
796 UsdImaging_DrawModeCache;
797
798struct 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 {
845 }
846};
847
848PXR_NAMESPACE_CLOSE_SCOPE
849
850// -------------------------------------------------------------------------- //
851// UsdGeomPointInstancer indices cache
852// -------------------------------------------------------------------------- //
853
855
856PXR_NAMESPACE_OPEN_SCOPE
857
858struct UsdImaging_PointInstancerIndicesStrategy;
859typedef UsdImaging_ResolvedAttributeCache<UsdImaging_PointInstancerIndicesStrategy>
860 UsdImaging_PointInstancerIndicesCache;
861
862struct 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
929PXR_NAMESPACE_CLOSE_SCOPE
930
931// -------------------------------------------------------------------------- //
932// CoordSysBinding Cache
933// -------------------------------------------------------------------------- //
934
936#include "pxr/imaging/hd/coordSys.h"
937
938PXR_NAMESPACE_OPEN_SCOPE
939
940struct UsdImaging_CoordSysBindingStrategy;
941
942typedef UsdImaging_ResolvedAttributeCache<UsdImaging_CoordSysBindingStrategy>
943 UsdImaging_CoordSysBindingCache;
944
945struct 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
1039PXR_NAMESPACE_CLOSE_SCOPE
1040
1041// -------------------------------------------------------------------------- //
1042// Nonlinear sample count Primvar Cache
1043// -------------------------------------------------------------------------- //
1044
1046
1047PXR_NAMESPACE_OPEN_SCOPE
1048
1049struct UsdImaging_NonlinearSampleCountStrategy;
1050typedef UsdImaging_ResolvedAttributeCache<
1051 UsdImaging_NonlinearSampleCountStrategy>
1052 UsdImaging_NonlinearSampleCountCache;
1053
1054struct 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 {
1100 }
1101};
1102
1103PXR_NAMESPACE_CLOSE_SCOPE
1104
1105// -------------------------------------------------------------------------- //
1106// Blur scale Primvar Cache
1107// -------------------------------------------------------------------------- //
1108
1110
1111PXR_NAMESPACE_OPEN_SCOPE
1112
1113struct UsdImaging_BlurScaleStrategy;
1114typedef UsdImaging_ResolvedAttributeCache<UsdImaging_BlurScaleStrategy>
1115 UsdImaging_BlurScaleCache;
1116
1117struct 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
1170PXR_NAMESPACE_CLOSE_SCOPE
1171
1172// -------------------------------------------------------------------------- //
1173// Inherited Primvar Cache
1174// -------------------------------------------------------------------------- //
1175
1177
1178PXR_NAMESPACE_OPEN_SCOPE
1179
1180struct UsdImaging_InheritedPrimvarStrategy;
1181typedef UsdImaging_ResolvedAttributeCache<UsdImaging_InheritedPrimvarStrategy>
1182 UsdImaging_InheritedPrimvarCache;
1183
1184struct 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
1239PXR_NAMESPACE_CLOSE_SCOPE
1240
1241#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:83
Stores a 4x4 matrix of double elements.
Definition: matrix4d.h:88
A path value used to locate objects in layers or scenegraphs.
Definition: path.h:291
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:415
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:88
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:75
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:154
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:68
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:262
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:83
Helper class that caches the ordered vector of UsGeomXformOps that contribute to the local transforma...
Definition: xformable.h:379
Base class for all transformable prims, which allows arbitrary sequences of component affine transfor...
Definition: xformable.h:253
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
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:134
UsdPrim GetParent() const
Return this prim's parent prim.
Definition: prim.h:1546
bool IsPrototype() const
Return true if this prim is an instancing prototype prim, false otherwise.
Definition: prim.h:2088
bool IsInPrototype() const
Return true if this prim is a prototype prim or a descendant of a prototype prim, false otherwise.
Definition: prim.h:2094
An forward-iterable range that traverses a subtree of prims rooted at a given prim in depth-first ord...
Definition: primRange.h:119
A UsdRelationship creates dependencies between scenegraph objects by allowing a prim to target other ...
Definition: relationship.h:128
SdfPath GetPath() const
Shorthand for GetPrim()->GetPath().
Definition: schemaBase.h:123
UsdShadeCoordSysAPI provides a way to designate, name, and discover coordinate systems.
Definition: coordSysAPI.h:83
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:273
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:113
Represent a time value, which may be either numeric, holding a double value, or a sentinel value UsdT...
Definition: timeCode.h:84
Represents an arbitrary dimensional rectangular container class.
Definition: array.h:228
#define TF_FOR_ALL(iter, c)
Macro for iterating over a container.
Definition: iterator.h:390
#define TF_DEBUG(enumVal)
Evaluate and print debugging message msg if enumVal is enabled for debugging.
Definition: debug.h:501
#define TF_CODING_ERROR(fmt, args)
Issue an internal programming error, but continue execution.
Definition: diagnostic.h:85
#define TF_WARN(...)
Issue a warning, but continue execution.
Definition: diagnostic.h:149
Value type containing information about a prim's computed effective purpose as well as storing whethe...
Definition: imageable.h:400
TfToken class for efficient string referencing and hashing, plus conversions to and from stl string c...
#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 TfStaticData< UsdGeomTokensType > UsdGeomTokens
A global variable with static, efficient TfTokens for use in all public USD API.