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 #include "pxr/pxr.h"
25 #include "pxr/usd/usd/stage.h"
26 
27 #include "pxr/usd/usd/attribute.h"
28 #include "pxr/usd/usd/attributeQuery.h"
29 #include "pxr/usd/usd/clip.h"
30 #include "pxr/usd/usd/clipCache.h"
31 #include "pxr/usd/usd/clipSet.h"
32 #include "pxr/usd/usd/common.h"
33 #include "pxr/usd/usd/debugCodes.h"
34 #include "pxr/usd/usd/instanceCache.h"
35 #include "pxr/usd/usd/interpolators.h"
36 #include "pxr/usd/usd/notice.h"
37 #include "pxr/usd/usd/prim.h"
38 #include "pxr/usd/usd/primDefinition.h"
39 #include "pxr/usd/usd/primRange.h"
40 #include "pxr/usd/usd/primTypeInfoCache.h"
41 #include "pxr/usd/usd/relationship.h"
42 #include "pxr/usd/usd/resolver.h"
43 #include "pxr/usd/usd/resolveInfo.h"
44 #include "pxr/usd/usd/schemaBase.h"
45 #include "pxr/usd/usd/schemaRegistry.h"
46 #include "pxr/usd/usd/stageCache.h"
47 #include "pxr/usd/usd/stageCacheContext.h"
48 #include "pxr/usd/usd/tokens.h"
49 #include "pxr/usd/usd/usdFileFormat.h"
50 #include "pxr/usd/usd/valueUtils.h"
51 
52 #include "pxr/usd/pcp/changes.h"
53 #include "pxr/usd/pcp/errors.h"
54 #include "pxr/usd/pcp/layerStack.h"
55 #include "pxr/usd/pcp/layerStackIdentifier.h"
56 #include "pxr/usd/pcp/site.h"
57 
58 // used for creating prims
59 #include "pxr/usd/sdf/attributeSpec.h"
60 #include "pxr/usd/sdf/changeBlock.h"
61 #include "pxr/usd/sdf/layerUtils.h"
62 #include "pxr/usd/sdf/primSpec.h"
63 #include "pxr/usd/sdf/relationshipSpec.h"
64 #include "pxr/usd/sdf/fileFormat.h"
65 #include "pxr/usd/sdf/schema.h"
66 #include "pxr/usd/sdf/types.h"
67 
68 #include "pxr/base/trace/trace.h"
69 #include "pxr/usd/ar/resolver.h"
70 #include "pxr/usd/ar/resolverContext.h"
71 #include "pxr/usd/ar/resolverContextBinder.h"
72 #include "pxr/usd/ar/resolverScopedCache.h"
73 
74 #include "pxr/base/gf/interval.h"
75 #include "pxr/base/gf/multiInterval.h"
76 
77 #include "pxr/base/arch/demangle.h"
78 #include "pxr/base/arch/pragmas.h"
79 
80 #include "pxr/base/plug/plugin.h"
81 #include "pxr/base/plug/registry.h"
82 #include "pxr/base/tf/enum.h"
83 #include "pxr/base/tf/envSetting.h"
84 #include "pxr/base/tf/hashset.h"
85 #include "pxr/base/tf/mallocTag.h"
86 #include "pxr/base/tf/ostreamMethods.h"
87 #include "pxr/base/tf/pyLock.h"
88 #include "pxr/base/tf/registryManager.h"
89 #include "pxr/base/tf/scoped.h"
90 #include "pxr/base/tf/span.h"
91 #include "pxr/base/tf/stl.h"
92 #include "pxr/base/tf/stringUtils.h"
93 #include "pxr/base/work/dispatcher.h"
94 #include "pxr/base/work/loops.h"
95 #include "pxr/base/work/utils.h"
96 #include "pxr/base/work/withScopedParallelism.h"
97 
98 #include <boost/optional.hpp>
99 #include <boost/iterator/transform_iterator.hpp>
100 #include <boost/utility/in_place_factory.hpp>
101 
102 #include <tbb/spin_rw_mutex.h>
103 #include <tbb/spin_mutex.h>
104 
105 #include <algorithm>
106 #include <functional>
107 #include <memory>
108 #include <mutex>
109 #include <string>
110 #include <utility>
111 #include <vector>
112 
113 PXR_NAMESPACE_OPEN_SCOPE
114 
115 using boost::make_transform_iterator;
116 using std::pair;
117 using std::make_pair;
118 using std::map;
119 using std::string;
120 using std::vector;
121 
122 // ------------------------------------------------------------------------- //
123 // UsdStage Helpers
124 // ------------------------------------------------------------------------- //
125 
126 using _ColorConfigurationFallbacks = pair<SdfAssetPath, TfToken>;
127 
128 // Fetch the color configuration fallback values from the plugins.
TF_MAKE_STATIC_DATA(_ColorConfigurationFallbacks,_colorConfigurationFallbacks)129 TF_MAKE_STATIC_DATA(_ColorConfigurationFallbacks, _colorConfigurationFallbacks)
130 {
131     PlugPluginPtrVector plugs = PlugRegistry::GetInstance().GetAllPlugins();
132     for (const auto& plug : plugs) {
133         JsObject metadata = plug->GetMetadata();
134         JsValue dictVal;
135         if (TfMapLookup(metadata, "UsdColorConfigFallbacks", &dictVal)) {
136             if (!dictVal.Is<JsObject>()) {
137                 TF_CODING_ERROR(
138                         "%s[UsdColorConfigFallbacks] was not a dictionary.",
139                         plug->GetName().c_str());
140                 continue;
141             }
142 
143             JsObject dict = dictVal.Get<JsObject>();
144             for (const auto& d : dict) {
145                 const std::string &key = d.first;
146                 if (key == SdfFieldKeys->ColorConfiguration) {
147                     if (!d.second.IsString()) {
148                         TF_CODING_ERROR("'colorConfiguration' value in "
149                             "%s[UsdColorConfigFallbacks] must be a string.",
150                             plug->GetName().c_str());
151                         continue;
152                     }
153                     std::string colorConfig = d.second.GetString();
154                     if (!colorConfig.empty()) {
155                         _colorConfigurationFallbacks->first =
156                             SdfAssetPath(colorConfig);
157                     }
158                 } else if (key == SdfFieldKeys->ColorManagementSystem) {
159                     if (!d.second.IsString()) {
160                         TF_CODING_ERROR("'colorManagementSystem' value in "
161                             "%s[UsdColorConfigFallbacks] must be a string.",
162                             plug->GetName().c_str());
163                         continue;
164                     }
165                     std::string cms = d.second.GetString();
166                     if (!cms.empty()) {
167                         _colorConfigurationFallbacks->second = TfToken(cms);
168                     }
169                 } else {
170                     TF_CODING_ERROR("Unknown key '%s' found in "
171                         "%s[UsdColorConfigFallbacks].", key.c_str(),
172                         plug->GetName().c_str());
173                 }
174             }
175             // Once we file a plugInfo file with UsdColorConfigFallbacks and
176             // there were no errors in retrieving the fallbacks, skip the
177             // remaining plugins. There should only be one plugin site-wide
178             // that defines this.
179             continue;
180         }
181     }
182 }
183 
184 //
185 // Usd lets you configure the fallback variants to use in plugInfo.json.
186 // This static data goes to discover that on first access.
187 //
TF_MAKE_STATIC_DATA(PcpVariantFallbackMap,_usdGlobalVariantFallbackMap)188 TF_MAKE_STATIC_DATA(PcpVariantFallbackMap, _usdGlobalVariantFallbackMap)
189 {
190     PcpVariantFallbackMap fallbacks;
191 
192     PlugPluginPtrVector plugs = PlugRegistry::GetInstance().GetAllPlugins();
193     for (const auto& plug : plugs) {
194         JsObject metadata = plug->GetMetadata();
195         JsValue dictVal;
196         if (TfMapLookup(metadata, "UsdVariantFallbacks", &dictVal)) {
197             if (!dictVal.Is<JsObject>()) {
198                 TF_CODING_ERROR(
199                         "%s[UsdVariantFallbacks] was not a dictionary.",
200                         plug->GetName().c_str());
201                 continue;
202             }
203             JsObject dict = dictVal.Get<JsObject>();
204             for (const auto& d : dict) {
205                 std::string vset = d.first;
206                 if (!d.second.IsArray()) {
207                     TF_CODING_ERROR(
208                             "%s[UsdVariantFallbacks] value for %s must "
209                             "be an arrays.",
210                             plug->GetName().c_str(), vset.c_str());
211                     continue;
212                 }
213                 std::vector<std::string> vsels =
214                     d.second.GetArrayOf<std::string>();
215                 if (!vsels.empty()) {
216                     fallbacks[vset] = vsels;
217                 }
218             }
219         }
220     }
221 
222     *_usdGlobalVariantFallbackMap = fallbacks;
223 }
224 static tbb::spin_rw_mutex _usdGlobalVariantFallbackMapMutex;
225 
226 PcpVariantFallbackMap
GetGlobalVariantFallbacks()227 UsdStage::GetGlobalVariantFallbacks()
228 {
229     tbb::spin_rw_mutex::scoped_lock
230         lock(_usdGlobalVariantFallbackMapMutex, /*write=*/false);
231     return *_usdGlobalVariantFallbackMap;
232 }
233 
234 void
SetGlobalVariantFallbacks(const PcpVariantFallbackMap & fallbacks)235 UsdStage::SetGlobalVariantFallbacks(const PcpVariantFallbackMap &fallbacks)
236 {
237     tbb::spin_rw_mutex::scoped_lock
238         lock(_usdGlobalVariantFallbackMapMutex, /*write=*/true);
239     *_usdGlobalVariantFallbackMap = fallbacks;
240 }
241 
242 // Returns the SdfLayerOffset that maps times in \a layer in the local layer
243 // stack of \a node up to the root of the pcp node tree.  Use
244 // SdfLayerOffset::GetInverse() to go the other direction.
245 template <class LayerPtr>
246 static SdfLayerOffset
_GetLayerToStageOffset(const PcpNodeRef & pcpNode,const LayerPtr & layer)247 _GetLayerToStageOffset(const PcpNodeRef& pcpNode,
248                        const LayerPtr& layer)
249 {
250     // PERFORMANCE: This is cached in the PcpNode and should be cheap.
251     // Get the node-local path and layer offset.
252     const SdfLayerOffset &nodeToRootNodeOffset =
253         pcpNode.GetMapToRoot().GetTimeOffset();
254 
255     //
256     // Each sublayer may have a layer offset, so we must adjust the
257     // time accordingly here.
258     //
259     // This is done by first translating the current layer's time to
260     // the root layer's time (for this LayerStack) followed by a
261     // translation from the local PcpNode to the root PcpNode.
262     //
263     SdfLayerOffset localOffset = nodeToRootNodeOffset;
264 
265     if (const SdfLayerOffset *layerToRootLayerOffset =
266         pcpNode.GetLayerStack()->GetLayerOffsetForLayer(layer)) {
267         localOffset = localOffset * (*layerToRootLayerOffset);
268     }
269 
270     // NOTE: FPS is intentionally excluded here; in Usd FPS is treated as pure
271     // metadata, and does not factor into the layer offset scale. Additionally,
272     // it is a validation error to compose mixed frame rates. This was done as a
273     // performance optimization.
274 
275     return localOffset;
276 }
277 
278 char const *_dormantMallocTagID = "UsdStages in aggregate";
279 
280 inline
281 std::string
_StageTag(const std::string & id)282 _StageTag(const std::string &id)
283 {
284     return "UsdStage: @" + id + "@";
285 }
286 
287 class UsdStage::_PendingChanges
288 {
289 public:
290     // Set to true to force ObjectsChanged notice to indicate recomposition
291     // of the pseudo-root regardless of what was actually recomposed.
292     bool notifyPseudoRootResync = false;
293 
294     PcpChanges pcpChanges;
295 
296     using PathsToChangesMap = UsdNotice::ObjectsChanged::_PathsToChangesMap;
297     PathsToChangesMap recomposeChanges, otherResyncChanges, otherInfoChanges;
298 };
299 
300 // ------------------------------------------------------------------------- //
301 // UsdStage implementation
302 // ------------------------------------------------------------------------- //
303 
TF_REGISTRY_FUNCTION(TfEnum)304 TF_REGISTRY_FUNCTION(TfEnum)
305 {
306     TF_ADD_ENUM_NAME(UsdStage::LoadAll, "Load all loadable prims");
307     TF_ADD_ENUM_NAME(UsdStage::LoadNone, "Load no loadable prims");
308 }
309 
310 static ArResolverContext
_CreatePathResolverContext(const SdfLayerHandle & layer)311 _CreatePathResolverContext(
312     const SdfLayerHandle& layer)
313 {
314     if (layer && !layer->IsAnonymous()) {
315         // Ask for a default context for the layer based on the repository
316         // path, or if that's empty (i.e. the asset system is not
317         // initialized), use the file path.
318         // XXX: This should ultimately not be based on repository path.
319         return ArGetResolver().CreateDefaultContextForAsset(
320             layer->GetRepositoryPath().empty() ?
321                 layer->GetRealPath() : layer->GetRepositoryPath());
322     }
323 
324     return ArGetResolver().CreateDefaultContext();
325 }
326 
327 static std::string
_AnchorAssetPathRelativeToLayer(const SdfLayerHandle & anchor,const std::string & assetPath)328 _AnchorAssetPathRelativeToLayer(
329     const SdfLayerHandle& anchor,
330     const std::string& assetPath)
331 {
332     if (assetPath.empty() ||
333         SdfLayer::IsAnonymousLayerIdentifier(assetPath)) {
334         return assetPath;
335     }
336 
337     return SdfComputeAssetPathRelativeToLayer(anchor, assetPath);
338 }
339 
340 static std::string
_ResolveAssetPathRelativeToLayer(const SdfLayerHandle & anchor,const std::string & assetPath)341 _ResolveAssetPathRelativeToLayer(
342     const SdfLayerHandle& anchor,
343     const std::string& assetPath)
344 {
345     const std::string computedAssetPath =
346         _AnchorAssetPathRelativeToLayer(anchor, assetPath);
347     if (computedAssetPath.empty()) {
348         return computedAssetPath;
349     }
350 
351     return ArGetResolver().Resolve(computedAssetPath);
352 }
353 
354 // If anchorAssetPathsOnly is true, this function will only
355 // update the authored assetPaths by anchoring them to the
356 // anchor layer; it will not fill in the resolved path field.
357 static void
_MakeResolvedAssetPathsImpl(const SdfLayerRefPtr & anchor,const ArResolverContext & context,SdfAssetPath * assetPaths,size_t numAssetPaths,bool anchorAssetPathsOnly)358 _MakeResolvedAssetPathsImpl(const SdfLayerRefPtr &anchor,
359                             const ArResolverContext &context,
360                             SdfAssetPath *assetPaths,
361                             size_t numAssetPaths,
362                             bool anchorAssetPathsOnly)
363 {
364     ArResolverContextBinder binder(context);
365     for (size_t i = 0; i != numAssetPaths; ++i) {
366         if (anchorAssetPathsOnly) {
367             assetPaths[i] = SdfAssetPath(
368                 _AnchorAssetPathRelativeToLayer(
369                     anchor, assetPaths[i].GetAssetPath()));
370         }
371         else {
372             assetPaths[i] = SdfAssetPath(
373                 assetPaths[i].GetAssetPath(),
374                 _ResolveAssetPathRelativeToLayer(
375                     anchor, assetPaths[i].GetAssetPath()));
376         }
377     }
378 }
379 
380 void
_MakeResolvedAssetPaths(UsdTimeCode time,const UsdAttribute & attr,SdfAssetPath * assetPaths,size_t numAssetPaths,bool anchorAssetPathsOnly) const381 UsdStage::_MakeResolvedAssetPaths(UsdTimeCode time,
382                                   const UsdAttribute& attr,
383                                   SdfAssetPath *assetPaths,
384                                   size_t numAssetPaths,
385                                   bool anchorAssetPathsOnly) const
386 {
387     // Get the layer providing the strongest value and use that to anchor the
388     // resolve.
389     auto anchor = _GetLayerWithStrongestValue(time, attr);
390     if (anchor) {
391         _MakeResolvedAssetPathsImpl(
392             anchor, GetPathResolverContext(), assetPaths, numAssetPaths,
393             anchorAssetPathsOnly);
394     }
395 }
396 
397 void
_MakeResolvedAssetPathsValue(UsdTimeCode time,const UsdAttribute & attr,VtValue * value,bool anchorAssetPathsOnly) const398 UsdStage::_MakeResolvedAssetPathsValue(UsdTimeCode time,
399                                        const UsdAttribute& attr,
400                                        VtValue* value,
401                                        bool anchorAssetPathsOnly) const
402 {
403     if (value->IsHolding<SdfAssetPath>()) {
404         SdfAssetPath assetPath;
405         value->UncheckedSwap(assetPath);
406         _MakeResolvedAssetPaths(
407             time, attr, &assetPath, 1, anchorAssetPathsOnly);
408         value->UncheckedSwap(assetPath);
409 
410     }
411     else if (value->IsHolding<VtArray<SdfAssetPath>>()) {
412         VtArray<SdfAssetPath> assetPaths;
413         value->UncheckedSwap(assetPaths);
414         _MakeResolvedAssetPaths(
415             time, attr, assetPaths.data(), assetPaths.size(),
416             anchorAssetPathsOnly);
417         value->UncheckedSwap(assetPaths);
418     }
419 }
420 
421 void
_MakeResolvedTimeCodes(UsdTimeCode time,const UsdAttribute & attr,SdfTimeCode * timeCodes,size_t numTimeCodes) const422 UsdStage::_MakeResolvedTimeCodes(UsdTimeCode time, const UsdAttribute &attr,
423                                  SdfTimeCode *timeCodes,
424                                  size_t numTimeCodes) const
425 {
426     UsdResolveInfo info;
427     _GetResolveInfo(attr, &info, &time);
428     if (!info._layerToStageOffset.IsIdentity()) {
429         for (size_t i = 0; i != numTimeCodes; ++i) {
430             Usd_ApplyLayerOffsetToValue(&timeCodes[i], info._layerToStageOffset);
431         }
432     }
433 }
434 
435 void
_MakeResolvedAttributeValue(UsdTimeCode time,const UsdAttribute & attr,VtValue * value) const436 UsdStage::_MakeResolvedAttributeValue(
437     UsdTimeCode time, const UsdAttribute &attr, VtValue *value) const
438 {
439     if (value->IsHolding<SdfTimeCode>()) {
440         SdfTimeCode timeCode;
441         value->UncheckedSwap(timeCode);
442         _MakeResolvedTimeCodes(time, attr, &timeCode, 1);
443         value->UncheckedSwap(timeCode);
444 
445     }
446     else if (value->IsHolding<VtArray<SdfTimeCode>>()) {
447         VtArray<SdfTimeCode> timeCodes;
448         value->UncheckedSwap(timeCodes);
449         _MakeResolvedTimeCodes(
450             time, attr, timeCodes.data(), timeCodes.size());
451         value->UncheckedSwap(timeCodes);
452     } else {
453         _MakeResolvedAssetPathsValue(time, attr, value);
454     }
455 }
456 
457 static SdfLayerRefPtr
_CreateAnonymousSessionLayer(const SdfLayerHandle & rootLayer)458 _CreateAnonymousSessionLayer(const SdfLayerHandle &rootLayer)
459 {
460     return SdfLayer::CreateAnonymous(
461         TfStringGetBeforeSuffix(
462             SdfLayer::GetDisplayNameFromIdentifier(rootLayer->GetIdentifier())) +
463         "-session.usda");
464 }
465 
UsdStage(const SdfLayerRefPtr & rootLayer,const SdfLayerRefPtr & sessionLayer,const ArResolverContext & pathResolverContext,const UsdStagePopulationMask & mask,InitialLoadSet load)466 UsdStage::UsdStage(const SdfLayerRefPtr& rootLayer,
467                    const SdfLayerRefPtr& sessionLayer,
468                    const ArResolverContext& pathResolverContext,
469                    const UsdStagePopulationMask& mask,
470                    InitialLoadSet load)
471     : _pseudoRoot(nullptr)
472     , _rootLayer(rootLayer)
473     , _sessionLayer(sessionLayer)
474     , _editTarget(_rootLayer)
475     , _cache(new PcpCache(PcpLayerStackIdentifier(
476                               _rootLayer, _sessionLayer, pathResolverContext),
477                           UsdUsdFileFormatTokens->Target,
478                           /*usdMode=*/true))
479     , _clipCache(new Usd_ClipCache)
480     , _instanceCache(new Usd_InstanceCache)
481     , _usedLayersRevision(0)
482     , _interpolationType(UsdInterpolationTypeLinear)
483     , _lastChangeSerialNumber(0)
484     , _pendingChanges(nullptr)
485     , _initialLoadSet(load)
486     , _populationMask(mask)
487     , _isClosingStage(false)
488     , _isWritingFallbackPrimTypes(false)
489 {
490     if (!TF_VERIFY(_rootLayer))
491         return;
492 
493     TF_DEBUG(USD_STAGE_LIFETIMES).Msg(
494         "UsdStage::UsdStage(rootLayer=@%s@, sessionLayer=@%s@)\n",
495         _rootLayer->GetIdentifier().c_str(),
496         _sessionLayer ? _sessionLayer->GetIdentifier().c_str() : "<null>");
497 
498 ARCH_PRAGMA_PUSH
499 ARCH_PRAGMA_DEPRECATED_POSIX_NAME
500     _mallocTagID = TfMallocTag::IsInitialized() ?
501         strdup(_StageTag(rootLayer->GetIdentifier()).c_str()) :
502         _dormantMallocTagID;
503 ARCH_PRAGMA_POP
504 
505     _cache->SetVariantFallbacks(GetGlobalVariantFallbacks());
506 }
507 
~UsdStage()508 UsdStage::~UsdStage()
509 {
510     TF_DEBUG(USD_STAGE_LIFETIMES).Msg(
511         "UsdStage::~UsdStage(rootLayer=@%s@, sessionLayer=@%s@)\n",
512         _rootLayer ? _rootLayer->GetIdentifier().c_str() : "<null>",
513         _sessionLayer ? _sessionLayer->GetIdentifier().c_str() : "<null>");
514     _Close();
515     if (_mallocTagID != _dormantMallocTagID){
516         free(const_cast<char*>(_mallocTagID));
517     }
518 }
519 
520 void
_Close()521 UsdStage::_Close()
522 {
523     TfScopedVar<bool> resetIsClosing(_isClosingStage, true);
524 
525     TF_PY_ALLOW_THREADS_IN_SCOPE();
526 
527     WorkWithScopedParallelism([this]() {
528 
529             // Destroy prim structure.
530             vector<SdfPath> primsToDestroy;
531             {
532                 // Scope the dispatcher so that its dtor Wait()s for work to
533                 // complete before primsToDestroy is destroyed, since tasks we
534                 // schedule in the dispatcher access it.
535                 WorkDispatcher wd;
536 
537                 // Stop listening for notices.
538                 wd.Run([this]() {
539                         for (auto &p: _layersAndNoticeKeys)
540                             TfNotice::Revoke(p.second);
541                         TfNotice::Revoke(_resolverChangeKey);
542                     });
543 
544                 if (_pseudoRoot) {
545                     // Instancing prototypes are not children of the pseudo-root
546                     // so we need to explicitly destroy those subtrees.
547                     primsToDestroy = _instanceCache->GetAllPrototypes();
548                     wd.Run([this, &primsToDestroy]() {
549                             primsToDestroy.push_back(
550                                 SdfPath::AbsoluteRootPath());
551                             _DestroyPrimsInParallel(primsToDestroy);
552                             _pseudoRoot = nullptr;
553                             WorkMoveDestroyAsync(primsToDestroy);
554                         });
555                 }
556 
557                 // Clear members.
558                 wd.Run([this]() { _cache.reset(); });
559                 wd.Run([this]() { _clipCache.reset(); });
560                 wd.Run([this]() { _instanceCache.reset(); });
561                 wd.Run([this]() { _sessionLayer.Reset(); });
562                 wd.Run([this]() { _rootLayer.Reset(); });
563                 _editTarget = UsdEditTarget();
564             }
565         });
566 
567     WorkSwapDestroyAsync(_primMap);
568     // XXX: Do not do this async, since python might shut down concurrently with
569     // this vector's destruction, and if any of the layers within have been
570     // reflected to python, the identity management stuff can blow up (since it
571     // accesses python).
572     //WorkSwapDestroyAsync(_layersAndNoticeKeys);
573 }
574 
575 namespace {
576 
577 // A predicate we pass to PcpCache::ComputePrimIndexesInParallel() to avoid
578 // computing indexes for children of inactive prims or instance prims.
579 // We don't populate such prims in Usd.
580 struct _NameChildrenPred
581 {
_NameChildrenPred__anon7d3fbd5f0911::_NameChildrenPred582     explicit _NameChildrenPred(const UsdStagePopulationMask *mask,
583                                const UsdStageLoadRules *loadRules,
584                                Usd_InstanceCache* instanceCache)
585         : _mask(mask)
586         , _loadRules(loadRules)
587         , _instanceCache(instanceCache)
588     { }
589 
operator ()__anon7d3fbd5f0911::_NameChildrenPred590     bool operator()(const PcpPrimIndex &index,
591                     TfTokenVector* childNamesToCompose) const
592     {
593         // Use a resolver to walk the index and find the strongest active
594         // opinion.
595         Usd_Resolver res(&index);
596         for (; res.IsValid(); res.NextLayer()) {
597             bool active = true;
598             if (res.GetLayer()->HasField(
599                     res.GetLocalPath(), SdfFieldKeys->Active, &active)) {
600                 if (!active) {
601                     return false;
602                 }
603                 break;
604             }
605         }
606 
607         // UsdStage doesn't expose any prims beneath instances, so we don't need
608         // to compute indexes for children of instances unless the index will be
609         // used as a source for a prototype prim.
610         if (index.IsInstanceable()) {
611             return _instanceCache->RegisterInstancePrimIndex(
612                 index, _mask, *_loadRules);
613         }
614 
615         // Compose only the child prims that are included in the population
616         // mask, if any.  Masks are included in instancing keys, so this works
617         // correctly with instancing.
618         return !_mask ||
619             _mask->GetIncludedChildNames(index.GetPath(), childNamesToCompose);
620     }
621 
622 private:
623     const UsdStagePopulationMask *_mask;
624     const UsdStageLoadRules *_loadRules;
625     Usd_InstanceCache *_instanceCache;
626 };
627 
628 } // anon
629 
630 /* static */
631 UsdStageRefPtr
_InstantiateStage(const SdfLayerRefPtr & rootLayer,const SdfLayerRefPtr & sessionLayer,const ArResolverContext & pathResolverContext,const UsdStagePopulationMask & mask,InitialLoadSet load)632 UsdStage::_InstantiateStage(const SdfLayerRefPtr &rootLayer,
633                             const SdfLayerRefPtr &sessionLayer,
634                             const ArResolverContext &pathResolverContext,
635                             const UsdStagePopulationMask &mask,
636                             InitialLoadSet load)
637 {
638     TF_DEBUG(USD_STAGE_OPEN)
639         .Msg("UsdStage::_InstantiateStage: Creating new UsdStage\n");
640 
641     // We don't want to pay for the tag-string construction unless
642     // we instrumentation is on, since some Stage ctors (InMemory) can be
643     // very lightweight.
644     boost::optional<TfAutoMallocTag2> tag;
645 
646     if (TfMallocTag::IsInitialized()){
647         tag = boost::in_place("Usd", _StageTag(rootLayer->GetIdentifier()));
648     }
649 
650     // Debug timing info
651     TfStopwatch stopwatch;
652     const bool usdInstantiationTimeDebugCodeActive =
653         TfDebug::IsEnabled(USD_STAGE_INSTANTIATION_TIME);
654 
655     if (usdInstantiationTimeDebugCodeActive) {
656         stopwatch.Start();
657     }
658 
659     if (!rootLayer)
660         return TfNullPtr;
661 
662     UsdStageRefPtr stage = TfCreateRefPtr(
663         new UsdStage(rootLayer, sessionLayer, pathResolverContext, mask, load));
664 
665     ArResolverScopedCache resolverCache;
666 
667     // Set the stage's load rules.
668     stage->_loadRules = (load == LoadAll) ?
669         UsdStageLoadRules::LoadAll() : UsdStageLoadRules::LoadNone();
670 
671     Usd_InstanceChanges instanceChanges;
672     const SdfPath& absoluteRootPath = SdfPath::AbsoluteRootPath();
673 
674     // Populate the stage, request payloads according to InitialLoadSet load.
675     stage->_ComposePrimIndexesInParallel(
676             {absoluteRootPath}, "instantiating stage", &instanceChanges);
677     stage->_pseudoRoot = stage->_InstantiatePrim(absoluteRootPath);
678 
679     const size_t subtreeCount = instanceChanges.newPrototypePrims.size() + 1;
680     std::vector<Usd_PrimDataPtr> subtreesToCompose;
681     SdfPathVector primIndexPathsForSubtrees;
682     subtreesToCompose.reserve(subtreeCount);
683     primIndexPathsForSubtrees.reserve(subtreeCount);
684     subtreesToCompose.push_back(stage->_pseudoRoot);
685     primIndexPathsForSubtrees.push_back(absoluteRootPath);
686 
687     // We only need to add new prototypes since, during stage initialization
688     // there should not be any changed prototypes
689     for (size_t i = 0; i != instanceChanges.newPrototypePrims.size(); ++i) {
690         const SdfPath& protoPath = instanceChanges.newPrototypePrims[i];
691         const SdfPath& protoPrimIndexPath =
692             instanceChanges.newPrototypePrimIndexes[i];
693 
694         Usd_PrimDataPtr protoPrim = stage->_InstantiatePrototypePrim(protoPath);
695         subtreesToCompose.push_back(protoPrim);
696         primIndexPathsForSubtrees.push_back(protoPrimIndexPath);
697     }
698 
699     stage->_ComposeSubtreesInParallel(
700         subtreesToCompose, &primIndexPathsForSubtrees);
701 
702     stage->_RegisterPerLayerNotices();
703     stage->_RegisterResolverChangeNotice();
704 
705     // Publish this stage into all current writable caches.
706     for (const auto cache : UsdStageCacheContext::_GetWritableCaches()) {
707         cache->Insert(stage);
708     }
709 
710     // Debug timing info
711     if (usdInstantiationTimeDebugCodeActive) {
712         stopwatch.Stop();
713         TF_DEBUG(USD_STAGE_INSTANTIATION_TIME)
714             .Msg("UsdStage::_InstantiateStage: Time elapsed (s): %f\n",
715                  stopwatch.GetSeconds());
716     }
717 
718     return stage;
719 }
720 
721 // Attempt to create a new layer with \p identifier.  Issue an error in case of
722 // failure.
723 static SdfLayerRefPtr
_CreateNewLayer(const std::string & identifier)724 _CreateNewLayer(const std::string &identifier)
725 {
726     TfErrorMark mark;
727     SdfLayerRefPtr rootLayer = SdfLayer::CreateNew(identifier);
728     if (!rootLayer) {
729         // If Sdf did not report an error message, we must.
730         if (mark.IsClean()) {
731             TF_RUNTIME_ERROR("Failed to CreateNew layer with identifier '%s'",
732                              identifier.c_str());
733         }
734     }
735     return rootLayer;
736 }
737 
738 /* static */
739 UsdStageRefPtr
CreateNew(const std::string & identifier,InitialLoadSet load)740 UsdStage::CreateNew(const std::string& identifier,
741                     InitialLoadSet load)
742 {
743     TfAutoMallocTag2 tag("Usd", _StageTag(identifier));
744 
745     if (SdfLayerRefPtr layer = _CreateNewLayer(identifier))
746         return Open(layer, _CreateAnonymousSessionLayer(layer), load);
747     return TfNullPtr;
748 }
749 
750 /* static */
751 UsdStageRefPtr
CreateNew(const std::string & identifier,const SdfLayerHandle & sessionLayer,InitialLoadSet load)752 UsdStage::CreateNew(const std::string& identifier,
753                     const SdfLayerHandle& sessionLayer,
754                     InitialLoadSet load)
755 {
756     TfAutoMallocTag2 tag("Usd", _StageTag(identifier));
757 
758     if (SdfLayerRefPtr layer = _CreateNewLayer(identifier))
759         return Open(layer, sessionLayer, load);
760     return TfNullPtr;
761 }
762 
763 /* static */
764 UsdStageRefPtr
CreateNew(const std::string & identifier,const ArResolverContext & pathResolverContext,InitialLoadSet load)765 UsdStage::CreateNew(const std::string& identifier,
766                     const ArResolverContext& pathResolverContext,
767                     InitialLoadSet load)
768 {
769     TfAutoMallocTag2 tag("Usd", _StageTag(identifier));
770 
771     if (SdfLayerRefPtr layer = _CreateNewLayer(identifier))
772         return Open(layer, pathResolverContext, load);
773     return TfNullPtr;
774 }
775 
776 /* static */
777 UsdStageRefPtr
CreateNew(const std::string & identifier,const SdfLayerHandle & sessionLayer,const ArResolverContext & pathResolverContext,InitialLoadSet load)778 UsdStage::CreateNew(const std::string& identifier,
779                     const SdfLayerHandle& sessionLayer,
780                     const ArResolverContext& pathResolverContext,
781                     InitialLoadSet load)
782 {
783     TfAutoMallocTag2 tag("Usd", _StageTag(identifier));
784 
785     if (SdfLayerRefPtr layer = _CreateNewLayer(identifier))
786         return Open(layer, sessionLayer, pathResolverContext, load);
787     return TfNullPtr;
788 }
789 
790 /* static */
791 UsdStageRefPtr
CreateInMemory(InitialLoadSet load)792 UsdStage::CreateInMemory(InitialLoadSet load)
793 {
794     // Use usda file format if an identifier was not provided.
795     //
796     // In regards to "tmp.usda" below, SdfLayer::CreateAnonymous always
797     // prefixes the identifier with the layer's address in memory, so using the
798     // same identifier multiple times still produces unique layers.
799     return CreateInMemory("tmp.usda", load);
800 }
801 
802 /* static */
803 UsdStageRefPtr
CreateInMemory(const std::string & identifier,InitialLoadSet load)804 UsdStage::CreateInMemory(const std::string& identifier,
805                          InitialLoadSet load)
806 {
807     return Open(SdfLayer::CreateAnonymous(identifier), load);
808 }
809 
810 /* static */
811 UsdStageRefPtr
CreateInMemory(const std::string & identifier,const ArResolverContext & pathResolverContext,InitialLoadSet load)812 UsdStage::CreateInMemory(const std::string& identifier,
813                          const ArResolverContext& pathResolverContext,
814                          InitialLoadSet load)
815 {
816     // CreateAnonymous() will transform 'identifier', so don't bother
817     // using it as a tag
818     TfAutoMallocTag tag("Usd");
819 
820     return Open(SdfLayer::CreateAnonymous(identifier),
821                 pathResolverContext, load);
822 }
823 
824 /* static */
825 UsdStageRefPtr
CreateInMemory(const std::string & identifier,const SdfLayerHandle & sessionLayer,InitialLoadSet load)826 UsdStage::CreateInMemory(const std::string& identifier,
827                          const SdfLayerHandle &sessionLayer,
828                          InitialLoadSet load)
829 {
830     // CreateAnonymous() will transform 'identifier', so don't bother
831     // using it as a tag
832     TfAutoMallocTag tag("Usd");
833 
834     return Open(SdfLayer::CreateAnonymous(identifier),
835                 sessionLayer, load);
836 }
837 
838 /* static */
839 UsdStageRefPtr
CreateInMemory(const std::string & identifier,const SdfLayerHandle & sessionLayer,const ArResolverContext & pathResolverContext,InitialLoadSet load)840 UsdStage::CreateInMemory(const std::string& identifier,
841                          const SdfLayerHandle &sessionLayer,
842                          const ArResolverContext& pathResolverContext,
843                          InitialLoadSet load)
844 {
845     // CreateAnonymous() will transform 'identifier', so don't bother
846     // using it as a tag
847     TfAutoMallocTag tag("Usd");
848 
849     return Open(SdfLayer::CreateAnonymous(identifier),
850                 sessionLayer, pathResolverContext, load);
851 }
852 
853 static
854 SdfLayerRefPtr
_OpenLayer(const std::string & filePath,const ArResolverContext & resolverContext=ArResolverContext ())855 _OpenLayer(
856     const std::string &filePath,
857     const ArResolverContext &resolverContext = ArResolverContext())
858 {
859     boost::optional<ArResolverContextBinder> binder;
860     if (!resolverContext.IsEmpty())
861         binder = boost::in_place(resolverContext);
862 
863     SdfLayer::FileFormatArguments args;
864     args[SdfFileFormatTokens->TargetArg] =
865         UsdUsdFileFormatTokens->Target.GetString();
866 
867     return SdfLayer::FindOrOpen(filePath, args);
868 }
869 
870 /* static */
871 UsdStageRefPtr
Open(const std::string & filePath,InitialLoadSet load)872 UsdStage::Open(const std::string& filePath, InitialLoadSet load)
873 {
874     TfAutoMallocTag2 tag("Usd", _StageTag(filePath));
875 
876     SdfLayerRefPtr rootLayer = _OpenLayer(filePath);
877     if (!rootLayer) {
878         TF_RUNTIME_ERROR("Failed to open layer @%s@", filePath.c_str());
879         return TfNullPtr;
880     }
881     return Open(rootLayer, load);
882 }
883 
884 /* static */
885 UsdStageRefPtr
Open(const std::string & filePath,const ArResolverContext & pathResolverContext,InitialLoadSet load)886 UsdStage::Open(const std::string& filePath,
887                const ArResolverContext& pathResolverContext,
888                InitialLoadSet load)
889 {
890     TfAutoMallocTag2 tag("Usd", _StageTag(filePath));
891 
892     SdfLayerRefPtr rootLayer = _OpenLayer(filePath, pathResolverContext);
893     if (!rootLayer) {
894         TF_RUNTIME_ERROR("Failed to open layer @%s@", filePath.c_str());
895         return TfNullPtr;
896     }
897     return Open(rootLayer, pathResolverContext, load);
898 }
899 
900 /* static */
901 UsdStageRefPtr
OpenMasked(const std::string & filePath,const UsdStagePopulationMask & mask,InitialLoadSet load)902 UsdStage::OpenMasked(const std::string& filePath,
903                      const UsdStagePopulationMask &mask,
904                      InitialLoadSet load)
905 {
906     TfAutoMallocTag2 tag("Usd", _StageTag(filePath));
907 
908     SdfLayerRefPtr rootLayer = _OpenLayer(filePath);
909     if (!rootLayer) {
910         TF_RUNTIME_ERROR("Failed to open layer @%s@", filePath.c_str());
911         return TfNullPtr;
912     }
913     return OpenMasked(rootLayer, mask, load);
914 }
915 
916 /* static */
917 UsdStageRefPtr
OpenMasked(const std::string & filePath,const ArResolverContext & pathResolverContext,const UsdStagePopulationMask & mask,InitialLoadSet load)918 UsdStage::OpenMasked(const std::string& filePath,
919                      const ArResolverContext& pathResolverContext,
920                      const UsdStagePopulationMask &mask,
921                      InitialLoadSet load)
922 {
923     TfAutoMallocTag2 tag("Usd", _StageTag(filePath));
924 
925     SdfLayerRefPtr rootLayer = _OpenLayer(filePath, pathResolverContext);
926     if (!rootLayer) {
927         TF_RUNTIME_ERROR("Failed to open layer @%s@", filePath.c_str());
928         return TfNullPtr;
929     }
930     return OpenMasked(rootLayer, pathResolverContext, mask, load);
931 }
932 
933 class Usd_StageOpenRequest : public UsdStageCacheRequest
934 {
935 public:
Usd_StageOpenRequest(UsdStage::InitialLoadSet load,SdfLayerHandle const & rootLayer)936     Usd_StageOpenRequest(UsdStage::InitialLoadSet load,
937                          SdfLayerHandle const &rootLayer)
938         : _rootLayer(rootLayer)
939         , _initialLoadSet(load) {}
Usd_StageOpenRequest(UsdStage::InitialLoadSet load,SdfLayerHandle const & rootLayer,SdfLayerHandle const & sessionLayer)940     Usd_StageOpenRequest(UsdStage::InitialLoadSet load,
941                          SdfLayerHandle const &rootLayer,
942                          SdfLayerHandle const &sessionLayer)
943         : _rootLayer(rootLayer)
944         , _sessionLayer(sessionLayer)
945         , _initialLoadSet(load) {}
Usd_StageOpenRequest(UsdStage::InitialLoadSet load,SdfLayerHandle const & rootLayer,ArResolverContext const & pathResolverContext)946     Usd_StageOpenRequest(UsdStage::InitialLoadSet load,
947                          SdfLayerHandle const &rootLayer,
948                          ArResolverContext const &pathResolverContext)
949         : _rootLayer(rootLayer)
950         , _pathResolverContext(pathResolverContext)
951         , _initialLoadSet(load) {}
Usd_StageOpenRequest(UsdStage::InitialLoadSet load,SdfLayerHandle const & rootLayer,SdfLayerHandle const & sessionLayer,ArResolverContext const & pathResolverContext)952     Usd_StageOpenRequest(UsdStage::InitialLoadSet load,
953                          SdfLayerHandle const &rootLayer,
954                          SdfLayerHandle const &sessionLayer,
955                          ArResolverContext const &pathResolverContext)
956         : _rootLayer(rootLayer)
957         , _sessionLayer(sessionLayer)
958         , _pathResolverContext(pathResolverContext)
959         , _initialLoadSet(load) {}
960 
~Usd_StageOpenRequest()961     virtual ~Usd_StageOpenRequest() {}
IsSatisfiedBy(UsdStageRefPtr const & stage) const962     virtual bool IsSatisfiedBy(UsdStageRefPtr const &stage) const {
963         // Works if other stage's root layer matches and we either don't care
964         // about the session layer or it matches, and we either don't care about
965         // the path resolverContext or it matches.
966         return _rootLayer == stage->GetRootLayer() &&
967             (!_sessionLayer || (*_sessionLayer == stage->GetSessionLayer())) &&
968             (!_pathResolverContext || (*_pathResolverContext ==
969                                        stage->GetPathResolverContext()));
970     }
IsSatisfiedBy(UsdStageCacheRequest const & other) const971     virtual bool IsSatisfiedBy(UsdStageCacheRequest const &other) const {
972         auto req = dynamic_cast<Usd_StageOpenRequest const *>(&other);
973         if (!req)
974             return false;
975 
976         // Works if other's root layer matches and we either don't care about
977         // the session layer or it matches, and we either don't care about the
978         // path resolverContext or it matches.
979         return _rootLayer == req->_rootLayer &&
980             (!_sessionLayer || (_sessionLayer == req->_sessionLayer)) &&
981             (!_pathResolverContext || (_pathResolverContext ==
982                                        req->_pathResolverContext));
983     }
Manufacture()984     virtual UsdStageRefPtr Manufacture() {
985         return UsdStage::_InstantiateStage(
986             SdfLayerRefPtr(_rootLayer),
987             _sessionLayer ? SdfLayerRefPtr(*_sessionLayer) :
988             _CreateAnonymousSessionLayer(_rootLayer),
989             _pathResolverContext ? *_pathResolverContext :
990             _CreatePathResolverContext(_rootLayer),
991             UsdStagePopulationMask::All(),
992             _initialLoadSet);
993     }
994 
995 private:
996     SdfLayerHandle _rootLayer;
997     boost::optional<SdfLayerHandle> _sessionLayer;
998     boost::optional<ArResolverContext> _pathResolverContext;
999     UsdStage::InitialLoadSet _initialLoadSet;
1000 };
1001 
1002 /* static */
1003 template <class... Args>
1004 UsdStageRefPtr
_OpenImpl(InitialLoadSet load,Args const &...args)1005 UsdStage::_OpenImpl(InitialLoadSet load, Args const &... args)
1006 {
1007     // Try to find a matching stage in read-only caches.
1008     for (const UsdStageCache *cache:
1009              UsdStageCacheContext::_GetReadableCaches()) {
1010         if (UsdStageRefPtr stage = cache->FindOneMatching(args...))
1011             return stage;
1012     }
1013 
1014     // If none found, request the stage in all the writable caches.  If we
1015     // manufacture a stage, we'll publish it to all the writable caches, so
1016     // subsequent requests will get the same stage out.
1017     UsdStageRefPtr stage;
1018     auto writableCaches = UsdStageCacheContext::_GetWritableCaches();
1019     if (writableCaches.empty()) {
1020         stage = Usd_StageOpenRequest(load, args...).Manufacture();
1021     }
1022     else {
1023         for (UsdStageCache *cache: writableCaches) {
1024             auto r = cache->RequestStage(Usd_StageOpenRequest(load, args...));
1025             if (!stage)
1026                 stage = r.first;
1027             if (r.second) {
1028                 // We manufactured the stage -- we published it to all the other
1029                 // caches too, so nothing left to do.
1030                 break;
1031             }
1032         }
1033     }
1034     TF_VERIFY(stage);
1035     return stage;
1036 }
1037 
1038 /* static */
1039 UsdStageRefPtr
Open(const SdfLayerHandle & rootLayer,InitialLoadSet load)1040 UsdStage::Open(const SdfLayerHandle& rootLayer, InitialLoadSet load)
1041 {
1042     if (!rootLayer) {
1043         TF_CODING_ERROR("Invalid root layer");
1044         return TfNullPtr;
1045     }
1046 
1047     TF_DEBUG(USD_STAGE_OPEN)
1048         .Msg("UsdStage::Open(rootLayer=@%s@, load=%s)\n",
1049              rootLayer->GetIdentifier().c_str(),
1050              TfStringify(load).c_str());
1051 
1052     return _OpenImpl(load, rootLayer);
1053 }
1054 
1055 /* static */
1056 UsdStageRefPtr
Open(const SdfLayerHandle & rootLayer,const SdfLayerHandle & sessionLayer,InitialLoadSet load)1057 UsdStage::Open(const SdfLayerHandle& rootLayer,
1058                const SdfLayerHandle& sessionLayer,
1059                InitialLoadSet load)
1060 {
1061     if (!rootLayer) {
1062         TF_CODING_ERROR("Invalid root layer");
1063         return TfNullPtr;
1064     }
1065 
1066     TF_DEBUG(USD_STAGE_OPEN)
1067         .Msg("UsdStage::Open(rootLayer=@%s@, sessionLayer=@%s@, load=%s)\n",
1068              rootLayer->GetIdentifier().c_str(),
1069              sessionLayer ? sessionLayer->GetIdentifier().c_str() : "<null>",
1070              TfStringify(load).c_str());
1071 
1072     return _OpenImpl(load, rootLayer, sessionLayer);
1073 }
1074 
1075 /* static */
1076 UsdStageRefPtr
Open(const SdfLayerHandle & rootLayer,const ArResolverContext & pathResolverContext,InitialLoadSet load)1077 UsdStage::Open(const SdfLayerHandle& rootLayer,
1078                const ArResolverContext& pathResolverContext,
1079                InitialLoadSet load)
1080 {
1081     if (!rootLayer) {
1082         TF_CODING_ERROR("Invalid root layer");
1083         return TfNullPtr;
1084     }
1085 
1086     TF_DEBUG(USD_STAGE_OPEN)
1087         .Msg("UsdStage::Open(rootLayer=@%s@, pathResolverContext=%s, "
1088                             "load=%s)\n",
1089              rootLayer->GetIdentifier().c_str(),
1090              pathResolverContext.GetDebugString().c_str(),
1091              TfStringify(load).c_str());
1092 
1093     return _OpenImpl(load, rootLayer, pathResolverContext);
1094 }
1095 
1096 /* static */
1097 UsdStageRefPtr
Open(const SdfLayerHandle & rootLayer,const SdfLayerHandle & sessionLayer,const ArResolverContext & pathResolverContext,InitialLoadSet load)1098 UsdStage::Open(const SdfLayerHandle& rootLayer,
1099                const SdfLayerHandle& sessionLayer,
1100                const ArResolverContext& pathResolverContext,
1101                InitialLoadSet load)
1102 {
1103     if (!rootLayer) {
1104         TF_CODING_ERROR("Invalid root layer");
1105         return TfNullPtr;
1106     }
1107 
1108     TF_DEBUG(USD_STAGE_OPEN)
1109         .Msg("UsdStage::Open(rootLayer=@%s@, sessionLayer=@%s@, "
1110                              "pathResolverContext=%s, load=%s)\n",
1111              rootLayer->GetIdentifier().c_str(),
1112              sessionLayer ? sessionLayer->GetIdentifier().c_str() : "<null>",
1113              pathResolverContext.GetDebugString().c_str(),
1114              TfStringify(load).c_str());
1115 
1116     return _OpenImpl(load, rootLayer, sessionLayer, pathResolverContext);
1117 }
1118 
1119 ////////////////////////////////////////////////////////////////////////
1120 // masked opens.
1121 
1122 /* static */
1123 UsdStageRefPtr
OpenMasked(const SdfLayerHandle & rootLayer,const UsdStagePopulationMask & mask,InitialLoadSet load)1124 UsdStage::OpenMasked(const SdfLayerHandle& rootLayer,
1125                      const UsdStagePopulationMask &mask,
1126                      InitialLoadSet load)
1127 {
1128     if (!rootLayer) {
1129         TF_CODING_ERROR("Invalid root layer");
1130         return TfNullPtr;
1131     }
1132 
1133     TF_DEBUG(USD_STAGE_OPEN)
1134         .Msg("UsdStage::OpenMasked(rootLayer=@%s@, mask=%s, load=%s)\n",
1135              rootLayer->GetIdentifier().c_str(),
1136              TfStringify(mask).c_str(),
1137              TfStringify(load).c_str());
1138 
1139     return _InstantiateStage(SdfLayerRefPtr(rootLayer),
1140                              _CreateAnonymousSessionLayer(rootLayer),
1141                              _CreatePathResolverContext(rootLayer),
1142                              mask,
1143                              load);
1144 }
1145 
1146 /* static */
1147 UsdStageRefPtr
OpenMasked(const SdfLayerHandle & rootLayer,const SdfLayerHandle & sessionLayer,const UsdStagePopulationMask & mask,InitialLoadSet load)1148 UsdStage::OpenMasked(const SdfLayerHandle& rootLayer,
1149                      const SdfLayerHandle& sessionLayer,
1150                      const UsdStagePopulationMask &mask,
1151                      InitialLoadSet load)
1152 {
1153     if (!rootLayer) {
1154         TF_CODING_ERROR("Invalid root layer");
1155         return TfNullPtr;
1156     }
1157 
1158     TF_DEBUG(USD_STAGE_OPEN)
1159         .Msg("UsdStage::OpenMasked(rootLayer=@%s@, sessionLayer=@%s@, "
1160              "mask=%s, load=%s)\n",
1161              rootLayer->GetIdentifier().c_str(),
1162              sessionLayer ? sessionLayer->GetIdentifier().c_str() : "<null>",
1163              TfStringify(mask).c_str(),
1164              TfStringify(load).c_str());
1165 
1166     return _InstantiateStage(SdfLayerRefPtr(rootLayer),
1167                              SdfLayerRefPtr(sessionLayer),
1168                              _CreatePathResolverContext(rootLayer),
1169                              mask,
1170                              load);
1171 }
1172 
1173 /* static */
1174 UsdStageRefPtr
OpenMasked(const SdfLayerHandle & rootLayer,const ArResolverContext & pathResolverContext,const UsdStagePopulationMask & mask,InitialLoadSet load)1175 UsdStage::OpenMasked(const SdfLayerHandle& rootLayer,
1176                      const ArResolverContext& pathResolverContext,
1177                      const UsdStagePopulationMask &mask,
1178                      InitialLoadSet load)
1179 {
1180     if (!rootLayer) {
1181         TF_CODING_ERROR("Invalid root layer");
1182         return TfNullPtr;
1183     }
1184 
1185     TF_DEBUG(USD_STAGE_OPEN)
1186         .Msg("UsdStage::OpenMasked(rootLayer=@%s@, pathResolverContext=%s, "
1187              "mask=%s, load=%s)\n",
1188              rootLayer->GetIdentifier().c_str(),
1189              pathResolverContext.GetDebugString().c_str(),
1190              TfStringify(mask).c_str(),
1191              TfStringify(load).c_str());
1192 
1193     return _InstantiateStage(SdfLayerRefPtr(rootLayer),
1194                              _CreateAnonymousSessionLayer(rootLayer),
1195                              pathResolverContext,
1196                              mask,
1197                              load);
1198 }
1199 
1200 /* static */
1201 UsdStageRefPtr
OpenMasked(const SdfLayerHandle & rootLayer,const SdfLayerHandle & sessionLayer,const ArResolverContext & pathResolverContext,const UsdStagePopulationMask & mask,InitialLoadSet load)1202 UsdStage::OpenMasked(const SdfLayerHandle& rootLayer,
1203                      const SdfLayerHandle& sessionLayer,
1204                      const ArResolverContext& pathResolverContext,
1205                      const UsdStagePopulationMask &mask,
1206                      InitialLoadSet load)
1207 {
1208     if (!rootLayer) {
1209         TF_CODING_ERROR("Invalid root layer");
1210         return TfNullPtr;
1211     }
1212 
1213     TF_DEBUG(USD_STAGE_OPEN)
1214         .Msg("UsdStage::OpenMasked(rootLayer=@%s@, sessionLayer=@%s@, "
1215              "pathResolverContext=%s, mask=%s, load=%s)\n",
1216              rootLayer->GetIdentifier().c_str(),
1217              sessionLayer ? sessionLayer->GetIdentifier().c_str() : "<null>",
1218              pathResolverContext.GetDebugString().c_str(),
1219              TfStringify(mask).c_str(),
1220              TfStringify(load).c_str());
1221 
1222     return _InstantiateStage(SdfLayerRefPtr(rootLayer),
1223                              SdfLayerRefPtr(sessionLayer),
1224                              pathResolverContext,
1225                              mask,
1226                              load);
1227 }
1228 
1229 static inline SdfAttributeSpecHandle
_GetSchemaPropSpec(SdfAttributeSpec *,const UsdPrimDefinition & primDef,TfToken const & attrName)1230 _GetSchemaPropSpec(SdfAttributeSpec *,
1231                    const UsdPrimDefinition &primDef,
1232                    TfToken const &attrName)
1233 {
1234     return primDef.GetSchemaAttributeSpec(attrName);
1235 }
1236 
1237 static inline SdfRelationshipSpecHandle
_GetSchemaPropSpec(SdfRelationshipSpec *,const UsdPrimDefinition & primDef,TfToken const & attrName)1238 _GetSchemaPropSpec(SdfRelationshipSpec *,
1239                    const UsdPrimDefinition &primDef,
1240                    TfToken const &attrName)
1241 {
1242     return primDef.GetSchemaRelationshipSpec(attrName);
1243 }
1244 
1245 static inline SdfPropertySpecHandle
_GetSchemaPropSpec(SdfPropertySpec *,const UsdPrimDefinition & primDef,TfToken const & attrName)1246 _GetSchemaPropSpec(SdfPropertySpec *,
1247                    const UsdPrimDefinition &primDef,
1248                    TfToken const &attrName)
1249 {
1250     return primDef.GetSchemaPropertySpec(attrName);
1251 }
1252 
1253 template <class PropType>
1254 SdfHandle<PropType>
_GetSchemaPropertySpec(const UsdProperty & prop) const1255 UsdStage::_GetSchemaPropertySpec(const UsdProperty &prop) const
1256 {
1257     Usd_PrimDataHandle const &primData = prop._Prim();
1258     if (!primData)
1259         return TfNullPtr;
1260 
1261     // Consult the registry.
1262     return _GetSchemaPropSpec(static_cast<PropType *>(nullptr),
1263                               primData->GetPrimDefinition(), prop.GetName());
1264 }
1265 
1266 SdfPropertySpecHandle
_GetSchemaPropertySpec(const UsdProperty & prop) const1267 UsdStage::_GetSchemaPropertySpec(const UsdProperty &prop) const
1268 {
1269     return _GetSchemaPropertySpec<SdfPropertySpec>(prop);
1270 }
1271 
1272 SdfAttributeSpecHandle
_GetSchemaAttributeSpec(const UsdAttribute & attr) const1273 UsdStage::_GetSchemaAttributeSpec(const UsdAttribute &attr) const
1274 {
1275     return _GetSchemaPropertySpec<SdfAttributeSpec>(attr);
1276 }
1277 
1278 SdfRelationshipSpecHandle
_GetSchemaRelationshipSpec(const UsdRelationship & rel) const1279 UsdStage::_GetSchemaRelationshipSpec(const UsdRelationship &rel) const
1280 {
1281     return _GetSchemaPropertySpec<SdfRelationshipSpec>(rel);
1282 }
1283 
1284 bool
_ValidateEditPrim(const UsdPrim & prim,const char * operation) const1285 UsdStage::_ValidateEditPrim(const UsdPrim &prim, const char* operation) const
1286 {
1287     if (ARCH_UNLIKELY(prim.IsInPrototype())) {
1288         TF_CODING_ERROR("Cannot %s at path <%s>; "
1289                         "authoring to an instancing prototype is not allowed.",
1290                         operation, prim.GetPath().GetText());
1291         return false;
1292     }
1293 
1294     if (ARCH_UNLIKELY(prim.IsInstanceProxy())) {
1295         TF_CODING_ERROR("Cannot %s at path <%s>; "
1296                         "authoring to an instance proxy is not allowed.",
1297                         operation, prim.GetPath().GetText());
1298         return false;
1299     }
1300 
1301     return true;
1302 }
1303 
1304 bool
_ValidateEditPrimAtPath(const SdfPath & primPath,const char * operation) const1305 UsdStage::_ValidateEditPrimAtPath(const SdfPath &primPath,
1306                                   const char* operation) const
1307 {
1308     if (ARCH_UNLIKELY(Usd_InstanceCache::IsPathInPrototype(primPath))) {
1309         TF_CODING_ERROR("Cannot %s at path <%s>; "
1310                         "authoring to an instancing prototype is not allowed.",
1311                         operation, primPath.GetText());
1312         return false;
1313     }
1314 
1315     if (ARCH_UNLIKELY(_IsObjectDescendantOfInstance(primPath))) {
1316         TF_CODING_ERROR("Cannot %s at path <%s>; "
1317                         "authoring to an instance proxy is not allowed.",
1318                         operation, primPath.GetText());
1319         return false;
1320     }
1321 
1322     return true;
1323 }
1324 
1325 namespace {
1326 
1327 SdfPrimSpecHandle
_CreatePrimSpecAtEditTarget(const UsdEditTarget & editTarget,const SdfPath & path)1328 _CreatePrimSpecAtEditTarget(const UsdEditTarget &editTarget,
1329                             const SdfPath &path)
1330 {
1331     const SdfPath &targetPath = editTarget.MapToSpecPath(path);
1332     return targetPath.IsEmpty() ? SdfPrimSpecHandle() :
1333         SdfCreatePrimInLayer(editTarget.GetLayer(), targetPath);
1334 }
1335 
1336 }
1337 
1338 SdfPrimSpecHandle
_CreatePrimSpecForEditing(const UsdPrim & prim)1339 UsdStage::_CreatePrimSpecForEditing(const UsdPrim& prim)
1340 {
1341     if (ARCH_UNLIKELY(!_ValidateEditPrim(prim, "create prim spec"))) {
1342         return TfNullPtr;
1343     }
1344 
1345     return _CreatePrimSpecAtEditTarget(GetEditTarget(), prim.GetPath());
1346 }
1347 
1348 static SdfAttributeSpecHandle
_StampNewPropertySpec(const SdfPrimSpecHandle & primSpec,const TfToken & propName,const SdfAttributeSpecHandle & toCopy)1349 _StampNewPropertySpec(const SdfPrimSpecHandle &primSpec,
1350                       const TfToken &propName,
1351                       const SdfAttributeSpecHandle &toCopy)
1352 {
1353     return SdfAttributeSpec::New(
1354         primSpec, propName, toCopy->GetTypeName(),
1355         toCopy->GetVariability(), toCopy->IsCustom());
1356 }
1357 
1358 static SdfRelationshipSpecHandle
_StampNewPropertySpec(const SdfPrimSpecHandle & primSpec,const TfToken & propName,const SdfRelationshipSpecHandle & toCopy)1359 _StampNewPropertySpec(const SdfPrimSpecHandle &primSpec,
1360                       const TfToken &propName,
1361                       const SdfRelationshipSpecHandle &toCopy)
1362 {
1363     return SdfRelationshipSpec::New(
1364         primSpec, propName, toCopy->IsCustom(),
1365         toCopy->GetVariability());
1366 }
1367 
1368 static SdfPropertySpecHandle
_StampNewPropertySpec(const SdfPrimSpecHandle & primSpec,const TfToken & propName,const SdfPropertySpecHandle & toCopy)1369 _StampNewPropertySpec(const SdfPrimSpecHandle &primSpec,
1370                       const TfToken &propName,
1371                       const SdfPropertySpecHandle &toCopy)
1372 {
1373     // Type dispatch to correct property type.
1374     if (SdfAttributeSpecHandle attrSpec =
1375         TfDynamic_cast<SdfAttributeSpecHandle>(toCopy)) {
1376         return _StampNewPropertySpec(primSpec, propName, attrSpec);
1377     } else {
1378         return _StampNewPropertySpec(
1379             primSpec, propName, TfStatic_cast<SdfRelationshipSpecHandle>(toCopy));
1380     }
1381 }
1382 
1383 template <class PropType>
1384 SdfHandle<PropType>
_CreatePropertySpecForEditing(const UsdProperty & prop)1385 UsdStage::_CreatePropertySpecForEditing(const UsdProperty &prop)
1386 {
1387     UsdPrim prim = prop.GetPrim();
1388     if (ARCH_UNLIKELY(!_ValidateEditPrim(prim, "create property spec"))) {
1389         return TfNullPtr;
1390     }
1391 
1392     typedef SdfHandle<PropType> TypedSpecHandle;
1393 
1394     const UsdEditTarget &editTarget = GetEditTarget();
1395 
1396     const SdfPath &propPath = prop.GetPath();
1397     const TfToken &propName = prop.GetName();
1398 
1399     // Check to see if there already exists a property with this path at the
1400     // current EditTarget.
1401     if (SdfPropertySpecHandle propSpec =
1402         editTarget.GetPropertySpecForScenePath(propPath)) {
1403         // If it's of the correct type, we're done.  Otherwise this is an error:
1404         // attribute/relationship type mismatch.
1405         if (TypedSpecHandle spec = TfDynamic_cast<TypedSpecHandle>(propSpec))
1406             return spec;
1407 
1408         TF_RUNTIME_ERROR("Spec type mismatch.  Failed to create %s for <%s> at "
1409                          "<%s> in @%s@.  %s already at that location.",
1410                          ArchGetDemangled<PropType>().c_str(),
1411                          propPath.GetText(),
1412                          editTarget.MapToSpecPath(propPath).GetText(),
1413                          editTarget.GetLayer()->GetIdentifier().c_str(),
1414                          TfStringify(propSpec->GetSpecType()).c_str());
1415         return TfNullPtr;
1416     }
1417 
1418     // There is no property spec at the current EditTarget.  Look for a typed
1419     // spec whose metadata we can copy.  First check to see if there is a
1420     // builtin we can use.  Failing that, try to take the strongest authored
1421     // spec.
1422     TypedSpecHandle specToCopy;
1423 
1424     // Get definition, if any.
1425     specToCopy = _GetSchemaPropertySpec<PropType>(prop);
1426 
1427     if (!specToCopy) {
1428         // There is no definition available, either because the prim has no
1429         // known schema, or its schema has no definition for this property.  In
1430         // this case, we look to see if there's a strongest property spec.  If
1431         // so, we copy its required metadata.
1432         for (Usd_Resolver r(&prim.GetPrimIndex()); r.IsValid(); r.NextLayer()) {
1433             if (SdfPropertySpecHandle propSpec = r.GetLayer()->
1434                 GetPropertyAtPath(r.GetLocalPath().AppendProperty(propName))) {
1435                 if ((specToCopy = TfDynamic_cast<TypedSpecHandle>(propSpec)))
1436                     break;
1437                 // Type mismatch.
1438                 TF_RUNTIME_ERROR("Spec type mismatch.  Failed to create %s for "
1439                                  "<%s> at <%s> in @%s@.  Strongest existing "
1440                                  "spec, %s at <%s> in @%s@",
1441                                  ArchGetDemangled<PropType>().c_str(),
1442                                  propPath.GetText(),
1443                                  editTarget.MapToSpecPath(propPath).GetText(),
1444                                  editTarget.GetLayer()->GetIdentifier().c_str(),
1445                                  TfStringify(propSpec->GetSpecType()).c_str(),
1446                                  propSpec->GetPath().GetText(),
1447                                  propSpec->GetLayer()->GetIdentifier().c_str());
1448                 return TfNullPtr;
1449             }
1450         }
1451     }
1452 
1453     // If we have a spec to copy from, then we author an opinion at the edit
1454     // target.
1455     if (specToCopy) {
1456         SdfChangeBlock block;
1457         SdfPrimSpecHandle primSpec = _CreatePrimSpecForEditing(prim);
1458         if (TF_VERIFY(primSpec))
1459             return _StampNewPropertySpec(primSpec, propName, specToCopy);
1460     }
1461 
1462     // Otherwise, we fail to create a spec.
1463     return TfNullPtr;
1464 }
1465 
1466 SdfAttributeSpecHandle
_CreateAttributeSpecForEditing(const UsdAttribute & attr)1467 UsdStage::_CreateAttributeSpecForEditing(const UsdAttribute &attr)
1468 {
1469     return _CreatePropertySpecForEditing<SdfAttributeSpec>(attr);
1470 }
1471 
1472 SdfRelationshipSpecHandle
_CreateRelationshipSpecForEditing(const UsdRelationship & rel)1473 UsdStage::_CreateRelationshipSpecForEditing(const UsdRelationship &rel)
1474 {
1475     return _CreatePropertySpecForEditing<SdfRelationshipSpec>(rel);
1476 }
1477 
1478 SdfPropertySpecHandle
_CreatePropertySpecForEditing(const UsdProperty & prop)1479 UsdStage::_CreatePropertySpecForEditing(const UsdProperty &prop)
1480 {
1481     return _CreatePropertySpecForEditing<SdfPropertySpec>(prop);
1482 }
1483 
1484 bool
_SetMetadata(const UsdObject & object,const TfToken & key,const TfToken & keyPath,const VtValue & value)1485 UsdStage::_SetMetadata(const UsdObject &object,
1486                        const TfToken &key,
1487                        const TfToken &keyPath,
1488                        const VtValue &value)
1489 {
1490     // The VtValue may be holding a type that needs to be mapped across edit
1491     // targets.
1492     if (value.IsHolding<SdfTimeCode>()) {
1493         return _SetMetadata(object, key, keyPath,
1494                             value.UncheckedGet<SdfTimeCode>());
1495     } else if (value.IsHolding<VtArray<SdfTimeCode>>()) {
1496         return _SetMetadata(object, key, keyPath,
1497                             value.UncheckedGet<VtArray<SdfTimeCode>>());
1498     } else if (value.IsHolding<VtDictionary>()) {
1499         return _SetMetadata(object, key, keyPath,
1500                             value.UncheckedGet<VtDictionary>());
1501     } else if (value.IsHolding<SdfTimeSampleMap>()) {
1502         return _SetMetadata(object, key, keyPath,
1503                             value.UncheckedGet<SdfTimeSampleMap>());
1504     }
1505 
1506     return _SetMetadataImpl(object, key, keyPath, value);
1507 }
1508 
1509 // This function handles the inverse mapping of values to an edit target's layer
1510 // for value types that get resolved by layer offsets. It's templated by a set
1511 // value implementation function in order to abstract out this value mapping for
1512 // both attribute values and metadata.
1513 // Fn type is equivalent to:
1514 //     bool setValueImpl(const SdfAbstractDataConstValue &)
1515 template <typename T, typename Fn>
1516 static bool
_SetMappedValueForEditTarget(const T & newValue,const UsdEditTarget & editTarget,const Fn & setValueImpl)1517 _SetMappedValueForEditTarget(const T &newValue,
1518                              const UsdEditTarget &editTarget,
1519                              const Fn &setValueImpl)
1520 {
1521     const SdfLayerOffset &layerOffset =
1522         editTarget.GetMapFunction().GetTimeOffset();
1523     if (!layerOffset.IsIdentity()) {
1524         // Copy the value, apply the offset to the edit layer, and set it using
1525         // the provided set function.
1526         T targetValue = newValue;
1527         Usd_ApplyLayerOffsetToValue(&targetValue, layerOffset.GetInverse());
1528 
1529         SdfAbstractDataConstTypedValue<T> in(&targetValue);
1530         return setValueImpl(in);
1531     }
1532 
1533     SdfAbstractDataConstTypedValue<T> in(&newValue);
1534     return setValueImpl(in);
1535 }
1536 
1537 template <class T>
_SetEditTargetMappedMetadata(const UsdObject & obj,const TfToken & fieldName,const TfToken & keyPath,const T & newValue)1538 bool UsdStage::_SetEditTargetMappedMetadata(
1539     const UsdObject &obj, const TfToken& fieldName,
1540     const TfToken &keyPath, const T &newValue)
1541 {
1542     static_assert(_IsEditTargetMappable<T>::value,
1543                   "_SetEditTargetMappedMetadata can only be instantiated for "
1544                   "types that are edit target mappable.");
1545     return _SetMappedValueForEditTarget(
1546         newValue, GetEditTarget(),
1547         [this, &obj, &fieldName, &keyPath](const SdfAbstractDataConstValue &in)
1548         {
1549             return this->_SetMetadataImpl(obj, fieldName, keyPath, in);
1550         });
1551 }
1552 
1553 static const std::type_info &
_GetTypeInfo(const SdfAbstractDataConstValue & value)1554 _GetTypeInfo(const SdfAbstractDataConstValue &value)
1555 {
1556     return value.valueType;
1557 }
1558 
1559 static const std::type_info &
_GetTypeInfo(const VtValue & value)1560 _GetTypeInfo(const VtValue &value)
1561 {
1562     return value.IsEmpty() ? typeid(void) : value.GetTypeid();
1563 }
1564 
1565 template <class T>
1566 bool
_SetMetadataImpl(const UsdObject & obj,const TfToken & fieldName,const TfToken & keyPath,const T & newValue)1567 UsdStage::_SetMetadataImpl(const UsdObject &obj,
1568                            const TfToken &fieldName,
1569                            const TfToken &keyPath,
1570                            const T &newValue)
1571 {
1572     if (!SdfSchema::GetInstance().IsRegistered(fieldName)) {
1573         TF_CODING_ERROR("Unregistered metadata field: %s", fieldName.GetText());
1574         return false;
1575     }
1576 
1577     TfAutoMallocTag2 tag("Usd", _mallocTagID);
1578 
1579     SdfSpecHandle spec;
1580 
1581     if (obj.Is<UsdProperty>()) {
1582         spec = _CreatePropertySpecForEditing(obj.As<UsdProperty>());
1583     } else if (obj.Is<UsdPrim>()) {
1584         spec = _CreatePrimSpecForEditing(obj.As<UsdPrim>());
1585     } else {
1586         TF_CODING_ERROR("Cannot set metadata at path <%s> in layer @%s@; "
1587                         "a prim or property is required",
1588                         GetEditTarget().MapToSpecPath(obj.GetPath()).GetText(),
1589                         GetEditTarget().GetLayer()->GetIdentifier().c_str());
1590         return false;
1591     }
1592 
1593     if (!spec) {
1594         TF_CODING_ERROR("Cannot set metadata. Failed to create spec <%s> in "
1595                         "layer @%s@",
1596                         GetEditTarget().MapToSpecPath(obj.GetPath()).GetText(),
1597                         GetEditTarget().GetLayer()->GetIdentifier().c_str());
1598         return false;
1599     }
1600 
1601     const auto& schema = spec->GetSchema();
1602     const auto specType = spec->GetSpecType();
1603     if (!schema.IsValidFieldForSpec(fieldName, specType)) {
1604         TF_CODING_ERROR("Cannot set metadata. '%s' is not registered "
1605                         "as valid metadata for spec type %s.",
1606                         fieldName.GetText(),
1607                         TfStringify(specType).c_str());
1608         return false;
1609     }
1610 
1611     if (keyPath.IsEmpty()) {
1612         spec->GetLayer()->SetField(spec->GetPath(), fieldName, newValue);
1613     } else {
1614         spec->GetLayer()->SetFieldDictValueByKey(
1615             spec->GetPath(), fieldName, keyPath, newValue);
1616     }
1617     return true;
1618 }
1619 
1620 template <class T>
1621 bool
_SetEditTargetMappedValue(UsdTimeCode time,const UsdAttribute & attr,const T & newValue)1622 UsdStage::_SetEditTargetMappedValue(
1623     UsdTimeCode time, const UsdAttribute &attr, const T &newValue)
1624 {
1625     static_assert(_IsEditTargetMappable<T>::value,
1626                   "_SetEditTargetMappedValue can only be instantiated for "
1627                   "types that are edit target mappable.");
1628     return _SetMappedValueForEditTarget(newValue, GetEditTarget(),
1629         [this, &time, &attr](const SdfAbstractDataConstValue &in)
1630         {
1631             return this->_SetValueImpl(time, attr, in);
1632         });
1633 }
1634 
1635 // Default _SetValue implementation for most attribute value types that never
1636 // need to be mapped for an edit target.
1637 template <class T>
1638 typename std::enable_if<!UsdStage::_IsEditTargetMappable<T>::value, bool>::type
_SetValue(UsdTimeCode time,const UsdAttribute & attr,const T & newValue)1639 UsdStage::_SetValue(UsdTimeCode time, const UsdAttribute &attr,
1640                     const T &newValue)
1641 {
1642     SdfAbstractDataConstTypedValue<T> in(&newValue);
1643     return _SetValueImpl<SdfAbstractDataConstValue>(time, attr, in);
1644 }
1645 
1646 // Specializations for SdfTimeCode and its array type which may need to be
1647 // value mapped for edit targets.
1648 // Note that VtDictionary and SdfTimeSampleMap are value types that are time
1649 // mapped when setting metadata, but we don't include them for _SetValue as
1650 // they're not valid attribute value types.
1651 template <class T>
1652 typename std::enable_if<UsdStage::_IsEditTargetMappable<T>::value, bool>::type
_SetValue(UsdTimeCode time,const UsdAttribute & attr,const T & newValue)1653 UsdStage::_SetValue(UsdTimeCode time, const UsdAttribute &attr,
1654                     const T &newValue)
1655 {
1656     return _SetEditTargetMappedValue(time, attr, newValue);
1657 }
1658 
1659 bool
_SetValue(UsdTimeCode time,const UsdAttribute & attr,const VtValue & newValue)1660 UsdStage::_SetValue(
1661     UsdTimeCode time, const UsdAttribute &attr, const VtValue &newValue)
1662 {
1663     // May need to map the value if it's holding a time code type.
1664     if (newValue.IsHolding<SdfTimeCode>()) {
1665         return _SetValue(time, attr,
1666                          newValue.UncheckedGet<SdfTimeCode>());
1667     } else if (newValue.IsHolding<VtArray<SdfTimeCode>>()) {
1668         return _SetValue(time, attr,
1669                          newValue.UncheckedGet<VtArray<SdfTimeCode>>());
1670     }
1671     return _SetValueImpl(time, attr, newValue);
1672 }
1673 
1674 bool
_ClearValue(UsdTimeCode time,const UsdAttribute & attr)1675 UsdStage::_ClearValue(UsdTimeCode time, const UsdAttribute &attr)
1676 {
1677     if (ARCH_UNLIKELY(!_ValidateEditPrim(attr.GetPrim(), "clear attribute value"))) {
1678         return false;
1679     }
1680 
1681     if (time.IsDefault())
1682         return _ClearMetadata(attr, SdfFieldKeys->Default);
1683 
1684     const UsdEditTarget &editTarget = GetEditTarget();
1685     if (!editTarget.IsValid()) {
1686         TF_CODING_ERROR("EditTarget does not contain a valid layer.");
1687         return false;
1688     }
1689 
1690     const SdfLayerHandle &layer = editTarget.GetLayer();
1691     if (!layer->HasSpec(editTarget.MapToSpecPath(attr.GetPath()))) {
1692         return true;
1693     }
1694 
1695     SdfAttributeSpecHandle attrSpec = _CreateAttributeSpecForEditing(attr);
1696 
1697     if (!TF_VERIFY(attrSpec,
1698                    "Failed to get attribute spec <%s> in layer @%s@",
1699                    editTarget.MapToSpecPath(attr.GetPath()).GetText(),
1700                    editTarget.GetLayer()->GetIdentifier().c_str())) {
1701         return false;
1702     }
1703 
1704     const SdfLayerOffset stageToLayerOffset =
1705         editTarget.GetMapFunction().GetTimeOffset().GetInverse();
1706 
1707     const double layerTime = stageToLayerOffset * time.GetValue();
1708 
1709     attrSpec->GetLayer()->EraseTimeSample(attrSpec->GetPath(), layerTime);
1710 
1711     return true;
1712 }
1713 
1714 bool
_ClearMetadata(const UsdObject & obj,const TfToken & fieldName,const TfToken & keyPath)1715 UsdStage::_ClearMetadata(const UsdObject &obj, const TfToken& fieldName,
1716     const TfToken &keyPath)
1717 {
1718     if (ARCH_UNLIKELY(!_ValidateEditPrim(obj.GetPrim(), "clear metadata"))) {
1719         return false;
1720     }
1721 
1722     const UsdEditTarget &editTarget = GetEditTarget();
1723     if (!editTarget.IsValid()) {
1724         TF_CODING_ERROR("EditTarget does not contain a valid layer.");
1725         return false;
1726     }
1727 
1728     const SdfLayerHandle &layer = editTarget.GetLayer();
1729     if (!layer->HasSpec(editTarget.MapToSpecPath(obj.GetPath()))) {
1730         return true;
1731     }
1732 
1733     SdfSpecHandle spec;
1734     if (obj.Is<UsdProperty>())
1735         spec = _CreatePropertySpecForEditing(obj.As<UsdProperty>());
1736     else
1737         spec = _CreatePrimSpecForEditing(obj.As<UsdPrim>());
1738 
1739     if (!TF_VERIFY(spec,
1740                    "No spec at <%s> in layer @%s@",
1741                    editTarget.MapToSpecPath(obj.GetPath()).GetText(),
1742                    editTarget.GetLayer()->GetIdentifier().c_str())) {
1743         return false;
1744     }
1745 
1746     const auto& schema = spec->GetSchema();
1747     const auto specType = spec->GetSpecType();
1748     if (!schema.IsValidFieldForSpec(fieldName, specType)) {
1749         TF_CODING_ERROR("Cannot clear metadata. '%s' is not registered "
1750                         "as valid metadata for spec type %s.",
1751                         fieldName.GetText(),
1752                         TfStringify(specType).c_str());
1753         return false;
1754     }
1755 
1756     if (keyPath.IsEmpty()) {
1757         spec->GetLayer()->EraseField(spec->GetPath(), fieldName);
1758     } else {
1759         spec->GetLayer()->EraseFieldDictValueByKey(
1760             spec->GetPath(), fieldName, keyPath);
1761     }
1762     return true;
1763 }
1764 
1765 static
1766 bool
_IsPrivateFieldKey(const TfToken & fieldKey)1767 _IsPrivateFieldKey(const TfToken& fieldKey)
1768 {
1769     static TfHashSet<TfToken, TfToken::HashFunctor> ignoredKeys;
1770 
1771     // XXX -- Use this instead of an initializer list in case TfHashSet
1772     //        doesn't support initializer lists.  Should ensure that
1773     //        TfHashSet does support them.
1774     static std::once_flag once;
1775     std::call_once(once, [](){
1776         // Composition keys.
1777         ignoredKeys.insert(SdfFieldKeys->InheritPaths);
1778         ignoredKeys.insert(SdfFieldKeys->Payload);
1779         ignoredKeys.insert(SdfFieldKeys->References);
1780         ignoredKeys.insert(SdfFieldKeys->Specializes);
1781         ignoredKeys.insert(SdfFieldKeys->SubLayers);
1782         ignoredKeys.insert(SdfFieldKeys->SubLayerOffsets);
1783         ignoredKeys.insert(SdfFieldKeys->VariantSelection);
1784         ignoredKeys.insert(SdfFieldKeys->VariantSetNames);
1785         // Clip keys.
1786         {
1787             auto clipFields = UsdGetClipRelatedFields();
1788             ignoredKeys.insert(clipFields.begin(), clipFields.end());
1789         }
1790         // Value keys.
1791         ignoredKeys.insert(SdfFieldKeys->Default);
1792         ignoredKeys.insert(SdfFieldKeys->TimeSamples);
1793     });
1794 
1795     // First look-up the field in the exclude/ignore table.
1796     if (ignoredKeys.find(fieldKey) != ignoredKeys.end())
1797         return true;
1798 
1799     // Implicitly excluded fields (child containers & readonly metadata).
1800     SdfSchema const & schema = SdfSchema::GetInstance();
1801     SdfSchema::FieldDefinition const* field =
1802                                 schema.GetFieldDefinition(fieldKey);
1803     if (field && (field->IsReadOnly() || field->HoldsChildren()))
1804         return true;
1805 
1806     // The field is not private.
1807     return false;
1808 }
1809 
1810 UsdPrim
GetPseudoRoot() const1811 UsdStage::GetPseudoRoot() const
1812 {
1813     return UsdPrim(_pseudoRoot, SdfPath());
1814 }
1815 
1816 UsdPrim
GetDefaultPrim() const1817 UsdStage::GetDefaultPrim() const
1818 {
1819     TfToken name = GetRootLayer()->GetDefaultPrim();
1820     return SdfPath::IsValidIdentifier(name)
1821         ? GetPrimAtPath(SdfPath::AbsoluteRootPath().AppendChild(name))
1822         : UsdPrim();
1823 }
1824 
1825 void
SetDefaultPrim(const UsdPrim & prim)1826 UsdStage::SetDefaultPrim(const UsdPrim &prim)
1827 {
1828     GetRootLayer()->SetDefaultPrim(prim.GetName());
1829 }
1830 
1831 void
ClearDefaultPrim()1832 UsdStage::ClearDefaultPrim()
1833 {
1834     GetRootLayer()->ClearDefaultPrim();
1835 }
1836 
1837 bool
HasDefaultPrim() const1838 UsdStage::HasDefaultPrim() const
1839 {
1840     return GetRootLayer()->HasDefaultPrim();
1841 }
1842 
1843 UsdPrim
GetPrimAtPath(const SdfPath & path) const1844 UsdStage::GetPrimAtPath(const SdfPath &path) const
1845 {
1846     // Silently return an invalid UsdPrim if the given path is not an
1847     // absolute path to maintain existing behavior.
1848     if (!path.IsAbsolutePath()) {
1849         return UsdPrim();
1850     }
1851 
1852     // If this path points to a prim beneath an instance, return
1853     // an instance proxy that uses the prim data from the corresponding
1854     // prim in the prototype but appears to be a prim at the given path.
1855     Usd_PrimDataConstPtr primData = _GetPrimDataAtPathOrInPrototype(path);
1856     const SdfPath& proxyPrimPath =
1857         primData && primData->GetPath() != path ? path : SdfPath::EmptyPath();
1858     return UsdPrim(primData, proxyPrimPath);
1859 }
1860 
1861 UsdObject
GetObjectAtPath(const SdfPath & path) const1862 UsdStage::GetObjectAtPath(const SdfPath &path) const
1863 {
1864     // Maintain consistent behavior with GetPrimAtPath
1865     if (!path.IsAbsolutePath()) {
1866         return UsdObject();
1867     }
1868 
1869     const bool isPrimPath = path.IsPrimPath();
1870     const bool isPropPath = !isPrimPath && path.IsPropertyPath();
1871     if (!isPrimPath && !isPropPath) {
1872         return UsdObject();
1873     }
1874 
1875     // A valid prim must be found to return either a prim or prop
1876     if (isPrimPath) {
1877         return GetPrimAtPath(path);
1878     } else if (isPropPath) {
1879         if (auto prim = GetPrimAtPath(path.GetPrimPath())) {
1880             return prim.GetProperty(path.GetNameToken());
1881         }
1882     }
1883 
1884     return UsdObject();
1885 }
1886 
1887 UsdProperty
GetPropertyAtPath(const SdfPath & path) const1888 UsdStage::GetPropertyAtPath(const SdfPath &path) const
1889 {
1890     return GetObjectAtPath(path).As<UsdProperty>();
1891 }
1892 
1893 UsdAttribute
GetAttributeAtPath(const SdfPath & path) const1894 UsdStage::GetAttributeAtPath(const SdfPath &path) const
1895 {
1896     return GetObjectAtPath(path).As<UsdAttribute>();
1897 }
1898 
1899 UsdRelationship
GetRelationshipAtPath(const SdfPath & path) const1900 UsdStage::GetRelationshipAtPath(const SdfPath &path) const
1901 {
1902     return GetObjectAtPath(path).As<UsdRelationship>();
1903 }
1904 
1905 Usd_PrimDataConstPtr
_GetPrimDataAtPath(const SdfPath & path) const1906 UsdStage::_GetPrimDataAtPath(const SdfPath &path) const
1907 {
1908     tbb::spin_rw_mutex::scoped_lock lock;
1909     if (_primMapMutex)
1910         lock.acquire(*_primMapMutex, /*write=*/false);
1911     PathToNodeMap::const_iterator entry = _primMap.find(path);
1912     return entry != _primMap.end() ? entry->second.get() : nullptr;
1913 }
1914 
1915 Usd_PrimDataPtr
_GetPrimDataAtPath(const SdfPath & path)1916 UsdStage::_GetPrimDataAtPath(const SdfPath &path)
1917 {
1918     tbb::spin_rw_mutex::scoped_lock lock;
1919     if (_primMapMutex)
1920         lock.acquire(*_primMapMutex, /*write=*/false);
1921     PathToNodeMap::const_iterator entry = _primMap.find(path);
1922     return entry != _primMap.end() ? entry->second.get() : nullptr;
1923 }
1924 
1925 Usd_PrimDataConstPtr
_GetPrimDataAtPathOrInPrototype(const SdfPath & path) const1926 UsdStage::_GetPrimDataAtPathOrInPrototype(const SdfPath &path) const
1927 {
1928     Usd_PrimDataConstPtr primData = _GetPrimDataAtPath(path);
1929 
1930     // If no prim data exists at the given path, check if this
1931     // path is pointing to a prim beneath an instance. If so, we
1932     // need to return the prim data for the corresponding prim
1933     // in the prototype.
1934     if (!primData) {
1935         const SdfPath primInPrototypePath =
1936             _instanceCache->GetPathInPrototypeForInstancePath(path);
1937         if (!primInPrototypePath.IsEmpty()) {
1938             primData = _GetPrimDataAtPath(primInPrototypePath);
1939         }
1940     }
1941 
1942     return primData;
1943 }
1944 
1945 bool
_IsValidForUnload(const SdfPath & path) const1946 UsdStage::_IsValidForUnload(const SdfPath& path) const
1947 {
1948     if (!path.IsAbsolutePath()) {
1949         TF_CODING_ERROR("Attempted to load/unload a relative path <%s>",
1950                         path.GetText());
1951         return false;
1952     }
1953     if (_instanceCache->IsPathInPrototype(path)) {
1954         TF_CODING_ERROR("Attempted to load/unload a prototype path <%s>",
1955                         path.GetText());
1956         return false;
1957     }
1958     return true;
1959 }
1960 
1961 bool
_IsValidForLoad(const SdfPath & path) const1962 UsdStage::_IsValidForLoad(const SdfPath& path) const
1963 {
1964     if (!_IsValidForUnload(path)) {
1965         return false;
1966     }
1967 
1968     // XXX PERFORMANCE: could use HasPrimAtPath
1969     UsdPrim curPrim = GetPrimAtPath(path);
1970 
1971     if (!curPrim) {
1972         // Lets see if any ancestor exists, if so it's safe to attempt to load.
1973         SdfPath parentPath = path;
1974         while (parentPath != SdfPath::AbsoluteRootPath()) {
1975             if ((curPrim = GetPrimAtPath(parentPath))) {
1976                 break;
1977             }
1978             parentPath = parentPath.GetParentPath();
1979         }
1980 
1981         // We walked up to the absolute root without finding anything
1982         // report error.
1983         if (parentPath == SdfPath::AbsoluteRootPath()) {
1984             TF_RUNTIME_ERROR("Attempt to load a path <%s> which is not "
1985                              "present in the stage",
1986                     path.GetString().c_str());
1987             return false;
1988         }
1989     }
1990 
1991     if (!curPrim.IsActive()) {
1992         TF_CODING_ERROR("Attempt to load an inactive path <%s>",
1993                         path.GetString().c_str());
1994         return false;
1995     }
1996 
1997     if (curPrim.IsPrototype()) {
1998         TF_CODING_ERROR("Attempt to load instance prototype <%s>",
1999                         path.GetString().c_str());
2000         return false;
2001     }
2002 
2003     return true;
2004 }
2005 
2006 void
_DiscoverPayloads(const SdfPath & rootPath,UsdLoadPolicy policy,SdfPathSet * primIndexPaths,bool unloadedOnly,SdfPathSet * usdPrimPaths) const2007 UsdStage::_DiscoverPayloads(const SdfPath& rootPath,
2008                             UsdLoadPolicy policy,
2009                             SdfPathSet* primIndexPaths,
2010                             bool unloadedOnly,
2011                             SdfPathSet* usdPrimPaths) const
2012 {
2013     tbb::concurrent_vector<SdfPath> primIndexPathsVec;
2014     tbb::concurrent_vector<SdfPath> usdPrimPathsVec;
2015 
2016     auto addPrimPayload =
2017         [this, unloadedOnly, primIndexPaths, usdPrimPaths,
2018          &primIndexPathsVec, &usdPrimPathsVec]
2019         (UsdPrim const &prim) {
2020         // Inactive prims are never included in this query.  Prototypes are
2021         // also never included, since they aren't independently loadable.
2022         if (!prim.IsActive() || prim.IsPrototype())
2023             return;
2024 
2025         if (prim._GetSourcePrimIndex().HasAnyPayloads()) {
2026             SdfPath const &payloadIncludePath =
2027                 prim._GetSourcePrimIndex().GetPath();
2028             if (!unloadedOnly ||
2029                 !_cache->IsPayloadIncluded(payloadIncludePath)) {
2030                 if (primIndexPaths)
2031                     primIndexPathsVec.push_back(payloadIncludePath);
2032                 if (usdPrimPaths)
2033                     usdPrimPathsVec.push_back(prim.GetPath());
2034             }
2035         }
2036     };
2037 
2038     if (policy == UsdLoadWithDescendants) {
2039         if (UsdPrim root = GetPrimAtPath(rootPath)) {
2040             UsdPrimRange children = UsdPrimRange(
2041                 root, UsdTraverseInstanceProxies(UsdPrimAllPrimsPredicate));
2042             WorkParallelForEach(
2043                 children.begin(), children.end(), addPrimPayload);
2044         }
2045     } else {
2046         addPrimPayload(GetPrimAtPath(rootPath));
2047     }
2048 
2049     // Copy stuff out.
2050     if (primIndexPaths) {
2051         primIndexPaths->insert(
2052             primIndexPathsVec.begin(), primIndexPathsVec.end());
2053     }
2054     if (usdPrimPaths) {
2055         usdPrimPaths->insert(usdPrimPathsVec.begin(), usdPrimPathsVec.end());
2056     }
2057 }
2058 
2059 UsdPrim
Load(const SdfPath & path,UsdLoadPolicy policy)2060 UsdStage::Load(const SdfPath& path, UsdLoadPolicy policy)
2061 {
2062     SdfPathSet exclude, include;
2063     include.insert(path);
2064 
2065     // Update the load set; this will trigger recomposition and include any
2066     // recursive payloads needed.
2067     LoadAndUnload(include, exclude, policy);
2068 
2069     return GetPrimAtPath(path);
2070 }
2071 
2072 void
Unload(const SdfPath & path)2073 UsdStage::Unload(const SdfPath& path)
2074 {
2075     SdfPathSet include, exclude;
2076     exclude.insert(path);
2077 
2078     // Update the load set; this will trigger recomposition and include any
2079     // recursive payloads needed.
2080     LoadAndUnload(include, exclude);
2081 }
2082 
2083 void
LoadAndUnload(const SdfPathSet & loadSet,const SdfPathSet & unloadSet,UsdLoadPolicy policy)2084 UsdStage::LoadAndUnload(const SdfPathSet &loadSet,
2085                         const SdfPathSet &unloadSet,
2086                         UsdLoadPolicy policy)
2087 {
2088     TfAutoMallocTag2 tag("Usd", _mallocTagID);
2089 
2090     // Optimization: If either or both of the sets is empty then check the other
2091     // set to see if the load rules already produce the desired state.  If so
2092     // this is a noop and we can early-out.
2093     if (loadSet.empty() || unloadSet.empty()) {
2094         bool isNoOp = true;
2095         if (unloadSet.empty()) {
2096             // Check the loadSet to see if we're already in the desired state.
2097             for (SdfPath const &path: loadSet) {
2098                 if ((policy == UsdLoadWithDescendants &&
2099                      !_loadRules.IsLoadedWithAllDescendants(path)) ||
2100                     (policy == UsdLoadWithoutDescendants &&
2101                      !_loadRules.IsLoadedWithNoDescendants(path))) {
2102                     isNoOp = false;
2103                     break;
2104                 }
2105             }
2106         }
2107         else {
2108             // Check the unloadSet to see if we're already in the desired state.
2109             for (SdfPath const &path: unloadSet) {
2110                 if (_loadRules.GetEffectiveRuleForPath(path) !=
2111                     UsdStageLoadRules::NoneRule) {
2112                     isNoOp = false;
2113                     break;
2114                 }
2115             }
2116         }
2117         if (isNoOp) {
2118             // No changes in effective load state for given paths, early-out.
2119             return;
2120         }
2121     }
2122 
2123     SdfPathSet finalLoadSet, finalUnloadSet;
2124 
2125     for (auto const &path : loadSet) {
2126         if (!_IsValidForLoad(path)) {
2127             continue;
2128         }
2129         finalLoadSet.insert(path);
2130     }
2131 
2132     for (auto const &path: unloadSet) {
2133         if (!_IsValidForUnload(path)) {
2134             continue;
2135         }
2136         finalUnloadSet.insert(path);
2137     }
2138 
2139     _loadRules.LoadAndUnload(finalLoadSet, finalUnloadSet, policy);
2140 
2141     // Go through the finalLoadSet, and check ancestors -- if any are loaded,
2142     // include the most ancestral which was loaded last in the finalLoadSet.
2143     for (SdfPath const &p: finalLoadSet) {
2144         SdfPath curPath = p;
2145         while (true) {
2146             SdfPath parentPath = curPath.GetParentPath();
2147             if (parentPath.IsEmpty())
2148                 break;
2149             UsdPrim prim = GetPrimAtPath(parentPath);
2150             if (prim && prim.IsLoaded() && p != curPath) {
2151                 finalLoadSet.insert(curPath);
2152                 break;
2153             }
2154             curPath = parentPath;
2155         }
2156     }
2157 
2158     // Go through the loadSet and unloadSet, and find the most ancestral
2159     // instance path for each (or the path itself if no such path exists) and
2160     // treat them as significant changes.
2161     SdfPathVector recomposePaths;
2162     for (SdfPath const &p: finalLoadSet) {
2163         SdfPath instancePath = _instanceCache->GetMostAncestralInstancePath(p);
2164         recomposePaths.push_back(instancePath.IsEmpty() ? p : instancePath);
2165     }
2166     for (SdfPath const &p: finalUnloadSet) {
2167         SdfPath instancePath = _instanceCache->GetMostAncestralInstancePath(p);
2168         recomposePaths.push_back(instancePath.IsEmpty() ? p : instancePath);
2169     }
2170 
2171     // This leaves recomposePaths sorted.
2172     SdfPath::RemoveDescendentPaths(&recomposePaths);
2173 
2174     PcpChanges changes;
2175     for (SdfPath const &p: recomposePaths) {
2176         changes.DidChangeSignificantly(_cache.get(), p);
2177     }
2178 
2179     // Remove any included payloads that are descendant to recomposePaths.
2180     // We'll re-include everything we need during _Recompose via the inclusion
2181     // predicate.
2182     PcpCache::PayloadSet const &currentIncludes = _cache->GetIncludedPayloads();
2183     SdfPathSet currentIncludesAsSet(currentIncludes.begin(),
2184                                     currentIncludes.end());
2185     SdfPathSet payloadsToExclude;
2186     for (SdfPath const &p: recomposePaths) {
2187         auto range = SdfPathFindPrefixedRange(currentIncludesAsSet.begin(),
2188                                               currentIncludesAsSet.end(), p);
2189         payloadsToExclude.insert(range.first, range.second);
2190     }
2191     _cache->RequestPayloads(SdfPathSet(), payloadsToExclude, &changes);
2192 
2193     if (TfDebug::IsEnabled(USD_PAYLOADS)) {
2194         TF_DEBUG(USD_PAYLOADS).Msg(
2195             "UsdStage::LoadAndUnload()\n"
2196             "  finalLoadSet: %s\n"
2197             "  finalUnloadSet: %s\n"
2198             "  _loadRules: %s\n"
2199             "  payloadsToExclude: %s\n"
2200             "  recomposePaths: %s\n",
2201             TfStringify(finalLoadSet).c_str(),
2202             TfStringify(finalUnloadSet).c_str(),
2203             TfStringify(_loadRules).c_str(),
2204             TfStringify(payloadsToExclude).c_str(),
2205             TfStringify(recomposePaths).c_str());
2206     }
2207 
2208     // Recompose, given the resulting changes from Pcp.
2209     //
2210     // PERFORMANCE: Note that Pcp will always include the paths in
2211     // both sets as "significant changes" regardless of the actual changes
2212     // resulting from this request, this will trigger recomposition of UsdPrims
2213     // that potentially didn't change; it seems like we could do better.
2214     TF_DEBUG(USD_CHANGES).Msg("\nProcessing Load/Unload changes\n");
2215     _Recompose(changes);
2216 
2217     UsdStageWeakPtr self(this);
2218 
2219     UsdNotice::ObjectsChanged::_PathsToChangesMap resyncChanges, infoChanges;
2220     for (SdfPath const &p: recomposePaths) {
2221         resyncChanges[p];
2222     }
2223 
2224     UsdNotice::ObjectsChanged(self, &resyncChanges, &infoChanges).Send(self);
2225 
2226     UsdNotice::StageContentsChanged(self).Send(self);
2227 }
2228 
2229 SdfPathSet
GetLoadSet()2230 UsdStage::GetLoadSet()
2231 {
2232     SdfPathSet loadSet;
2233     for (const auto& primIndexPath : _cache->GetIncludedPayloads()) {
2234         // Get the path of the Usd prim using this prim index path.
2235         // This ensures we return the appropriate path if this prim index
2236         // is being used by a prim within a prototype.
2237         //
2238         // If there is no Usd prim using this prim index, we return the
2239         // prim index path anyway. This could happen if the ancestor of
2240         // a previously-loaded prim is deactivated, for instance.
2241         // Including this path in the returned set reflects what's loaded
2242         // in the underlying PcpCache and ensures users can still unload
2243         // the payloads for those prims by calling
2244         // LoadAndUnload([], GetLoadSet()).
2245         const SdfPath primPath =
2246             _GetPrimPathUsingPrimIndexAtPath(primIndexPath);
2247         if (primPath.IsEmpty()) {
2248             loadSet.insert(primIndexPath);
2249         }
2250         else {
2251             loadSet.insert(primPath);
2252         }
2253     }
2254 
2255     return loadSet;
2256 }
2257 
2258 SdfPathSet
FindLoadable(const SdfPath & rootPath)2259 UsdStage::FindLoadable(const SdfPath& rootPath)
2260 {
2261     SdfPath path = rootPath;
2262 
2263     SdfPathSet loadable;
2264     _DiscoverPayloads(path, UsdLoadWithDescendants, nullptr,
2265                       /* unloadedOnly = */ false, &loadable);
2266     return loadable;
2267 }
2268 
2269 void
SetLoadRules(UsdStageLoadRules const & rules)2270 UsdStage::SetLoadRules(UsdStageLoadRules const &rules)
2271 {
2272     // For now just set the rules and recompose everything.
2273     _loadRules = rules;
2274 
2275     PcpChanges changes;
2276     changes.DidChangeSignificantly(_cache.get(), SdfPath::AbsoluteRootPath());
2277     _Recompose(changes);
2278 
2279     // Notify.
2280     UsdStageWeakPtr self(this);
2281     UsdNotice::ObjectsChanged::_PathsToChangesMap resyncChanges, infoChanges;
2282     resyncChanges[SdfPath::AbsoluteRootPath()];
2283     UsdNotice::ObjectsChanged(self, &resyncChanges, &infoChanges).Send(self);
2284     UsdNotice::StageContentsChanged(self).Send(self);
2285 }
2286 
2287 void
SetPopulationMask(UsdStagePopulationMask const & mask)2288 UsdStage::SetPopulationMask(UsdStagePopulationMask const &mask)
2289 {
2290     // For now just set the mask and recompose everything.
2291     _populationMask = mask;
2292 
2293     PcpChanges changes;
2294     changes.DidChangeSignificantly(_cache.get(), SdfPath::AbsoluteRootPath());
2295     _Recompose(changes);
2296 
2297     // Notify.
2298     UsdStageWeakPtr self(this);
2299     UsdNotice::ObjectsChanged::_PathsToChangesMap resyncChanges, infoChanges;
2300     resyncChanges[SdfPath::AbsoluteRootPath()];
2301     UsdNotice::ObjectsChanged(self, &resyncChanges, &infoChanges).Send(self);
2302     UsdNotice::StageContentsChanged(self).Send(self);
2303 }
2304 
2305 void
ExpandPopulationMask(std::function<bool (UsdRelationship const &)> const & relPred,std::function<bool (UsdAttribute const &)> const & attrPred)2306 UsdStage::ExpandPopulationMask(
2307     std::function<bool (UsdRelationship const &)> const &relPred,
2308     std::function<bool (UsdAttribute const &)> const &attrPred)
2309 {
2310     if (GetPopulationMask().IncludesSubtree(SdfPath::AbsoluteRootPath()))
2311         return;
2312 
2313     // Walk everything, calling UsdPrim::FindAllRelationshipTargetPaths() and
2314     // include them in the mask.  If the mask changes, call SetPopulationMask()
2315     // and redo.  Continue until the mask ceases expansion.
2316     while (true) {
2317         auto root = GetPseudoRoot();
2318         SdfPathVector
2319             tgtPaths = root.FindAllRelationshipTargetPaths(relPred, false),
2320             connPaths = root.FindAllAttributeConnectionPaths(attrPred, false);
2321 
2322         tgtPaths.erase(remove_if(tgtPaths.begin(), tgtPaths.end(),
2323                                  [this](SdfPath const &path) {
2324                                      return _populationMask.Includes(path);
2325                                  }),
2326                        tgtPaths.end());
2327         connPaths.erase(remove_if(connPaths.begin(), connPaths.end(),
2328                                  [this](SdfPath const &path) {
2329                                      return _populationMask.Includes(path);
2330                                  }),
2331                        connPaths.end());
2332 
2333         if (tgtPaths.empty() && connPaths.empty())
2334             break;
2335 
2336         auto popMask = GetPopulationMask();
2337         for (auto const &path: tgtPaths) {
2338             popMask.Add(path.GetPrimPath());
2339         }
2340         for (auto const &path: connPaths) {
2341             popMask.Add(path.GetPrimPath());
2342         }
2343         SetPopulationMask(popMask);
2344     }
2345 }
2346 
2347 // ------------------------------------------------------------------------- //
2348 // Instancing
2349 // ------------------------------------------------------------------------- //
2350 
2351 vector<UsdPrim>
GetPrototypes() const2352 UsdStage::GetPrototypes() const
2353 {
2354     // Sort the instance prototype paths to provide a stable ordering for
2355     // this function.
2356     SdfPathVector prototypePaths = _instanceCache->GetAllPrototypes();
2357     std::sort(prototypePaths.begin(), prototypePaths.end());
2358 
2359     vector<UsdPrim> prototypePrims;
2360     for (const auto& path : prototypePaths) {
2361         UsdPrim p = GetPrimAtPath(path);
2362         if (TF_VERIFY(p, "Failed to find prim at prototype path <%s>.\n",
2363                       path.GetText())) {
2364             prototypePrims.push_back(p);
2365         }
2366     }
2367     return prototypePrims;
2368 }
2369 
2370 vector<UsdPrim>
_GetInstancesForPrototype(const UsdPrim & prototypePrim) const2371 UsdStage::_GetInstancesForPrototype(const UsdPrim& prototypePrim) const
2372 {
2373     if (!prototypePrim.IsPrototype()) {
2374         return {};
2375     }
2376 
2377     vector<UsdPrim> instances;
2378     SdfPathVector instancePaths =
2379         _instanceCache->GetInstancePrimIndexesForPrototype(
2380             prototypePrim.GetPath());
2381     instances.reserve(instancePaths.size());
2382     for (const SdfPath& instancePath : instancePaths) {
2383         Usd_PrimDataConstPtr primData =
2384             _GetPrimDataAtPathOrInPrototype(instancePath);
2385         instances.push_back(UsdPrim(primData, SdfPath::EmptyPath()));
2386     }
2387     return instances;
2388 }
2389 
2390 Usd_PrimDataConstPtr
_GetPrototypeForInstance(Usd_PrimDataConstPtr prim) const2391 UsdStage::_GetPrototypeForInstance(Usd_PrimDataConstPtr prim) const
2392 {
2393     if (!prim->IsInstance()) {
2394         return nullptr;
2395     }
2396 
2397     const SdfPath protoPath =
2398         _instanceCache->GetPrototypeForInstanceablePrimIndexPath(
2399             prim->GetPrimIndex().GetPath());
2400     return protoPath.IsEmpty() ? nullptr : _GetPrimDataAtPath(protoPath);
2401 }
2402 
2403 bool
_IsObjectDescendantOfInstance(const SdfPath & path) const2404 UsdStage::_IsObjectDescendantOfInstance(const SdfPath& path) const
2405 {
2406     // If the given path is a descendant of an instanceable
2407     // prim index, it would not be computed during composition unless
2408     // it is also serving as the source prim index for a prototype prim
2409     // on this stage.
2410     //
2411     // Check if we have any instancing in this stage to avoid unnecessary
2412     // path operations for performance.
2413     return (_instanceCache->GetNumPrototypes() > 0 &&
2414         _instanceCache->IsPathDescendantToAnInstance(
2415             path.GetAbsoluteRootOrPrimPath()));
2416 }
2417 
2418 SdfPath
_GetPrimPathUsingPrimIndexAtPath(const SdfPath & primIndexPath) const2419 UsdStage::_GetPrimPathUsingPrimIndexAtPath(const SdfPath& primIndexPath) const
2420 {
2421     SdfPath primPath;
2422 
2423     // In general, the path of a UsdPrim on a stage is the same as the
2424     // path of its prim index. However, this is not the case when
2425     // prims in prototypes are involved. In these cases, we need to use
2426     // the instance cache to map the prim index path to the prototype
2427     // prim on the stage.
2428     if (GetPrimAtPath(primIndexPath)) {
2429         primPath = primIndexPath;
2430     }
2431     else if (_instanceCache->GetNumPrototypes() != 0) {
2432         const vector<SdfPath> prototypesUsingPrimIndex =
2433             _instanceCache->GetPrimsInPrototypesUsingPrimIndexPath(
2434                 primIndexPath);
2435 
2436         for (const auto& pathInPrototype : prototypesUsingPrimIndex) {
2437             // If this path is a root prim path, it must be the path of a
2438             // prototype prim. This function wants to ignore prototype prims,
2439             // since they appear to have no prim index to the outside
2440             // consumer.
2441             //
2442             // However, if this is not a root prim path, it must be the
2443             // path of an prim nested inside a prototype, which we do want
2444             // to return. There will only ever be one of these, so we
2445             // can get this prim and break immediately.
2446             if (!pathInPrototype.IsRootPrimPath()) {
2447                 primPath = pathInPrototype;
2448                 break;
2449             }
2450         }
2451     }
2452 
2453     return primPath;
2454 }
2455 
2456 Usd_PrimDataPtr
_InstantiatePrim(const SdfPath & primPath)2457 UsdStage::_InstantiatePrim(const SdfPath &primPath)
2458 {
2459     TfAutoMallocTag tag("Usd_PrimData");
2460 
2461     // Instantiate new prim data instance.
2462     Usd_PrimDataPtr p = new Usd_PrimData(this, primPath);
2463     pair<PathToNodeMap::iterator, bool> result;
2464     std::pair<SdfPath, Usd_PrimDataPtr> payload(primPath, p);
2465     {
2466         tbb::spin_rw_mutex::scoped_lock lock;
2467         if (_primMapMutex)
2468             lock.acquire(*_primMapMutex);
2469         result = _primMap.insert(payload);
2470     }
2471 
2472     // Insert entry into the map -- should always succeed.
2473     TF_VERIFY(result.second, "Newly instantiated prim <%s> already present in "
2474               "_primMap", primPath.GetText());
2475     return p;
2476 }
2477 
2478 Usd_PrimDataPtr
_InstantiatePrototypePrim(const SdfPath & primPath)2479 UsdStage::_InstantiatePrototypePrim(const SdfPath &primPath)
2480 {
2481     // Prototype prims are parented beneath the pseudo-root,
2482     // but are *not* children of the pseudo-root. This ensures
2483     // that consumers never see prototype prims unless they are
2484     // explicitly asked for. So, we don't need to set the child
2485     // link here.
2486     Usd_PrimDataPtr prototypePrim = _InstantiatePrim(primPath);
2487     prototypePrim->_SetParentLink(_pseudoRoot);
2488     return prototypePrim;
2489 }
2490 
2491 namespace {
2492 // Less-than comparison for iterators that compares what they point to.
2493 struct _DerefIterLess {
2494     template <class Iter>
operator ()__anon7d3fbd5f1111::_DerefIterLess2495     bool operator()(const Iter &lhs, const Iter &rhs) const {
2496         return *lhs < *rhs;
2497     }
2498 };
2499 // Less-than comparison by prim name.
2500 struct _PrimNameLess {
2501     template <class PrimPtr>
operator ()__anon7d3fbd5f1111::_PrimNameLess2502     bool operator()(const PrimPtr &lhs, const PrimPtr &rhs) const {
2503         return lhs->GetName() < rhs->GetName();
2504     }
2505 };
2506 // Less-than comparison of second element in a pair.
2507 struct _SecondLess {
2508     template <class Pair>
operator ()__anon7d3fbd5f1111::_SecondLess2509     bool operator()(const Pair &lhs, const Pair &rhs) const {
2510         return lhs.second < rhs.second;
2511     }
2512 };
2513 }
2514 
2515 // This method has some subtle behavior to support minimal repopulation and
2516 // ideal allocation order.  See documentation for this method in the .h file for
2517 // important details regarding this method's behavior.
2518 void
_ComposeChildren(Usd_PrimDataPtr prim,UsdStagePopulationMask const * mask,bool recurse)2519 UsdStage::_ComposeChildren(Usd_PrimDataPtr prim,
2520                            UsdStagePopulationMask const *mask, bool recurse)
2521 {
2522     // If prim is deactivated, discard any existing children and return.
2523     if (!prim->IsActive()) {
2524         TF_DEBUG(USD_COMPOSITION).Msg("Inactive prim <%s>\n",
2525                                       prim->GetPath().GetText());
2526         _DestroyDescendents(prim);
2527         return;
2528     }
2529 
2530     // Instance prims do not directly expose any of their name children.
2531     // Discard any pre-existing children and add a task for composing
2532     // the instance's prototype's subtree if it's root uses this instance's
2533     // prim index as a source.
2534     if (prim->IsInstance()) {
2535         TF_DEBUG(USD_COMPOSITION).Msg("Instance prim <%s>\n",
2536                                       prim->GetPath().GetText());
2537         _DestroyDescendents(prim);
2538         return;
2539     }
2540 
2541     // Compose child names for this prim.
2542     TfTokenVector nameOrder;
2543     if (!TF_VERIFY(prim->_ComposePrimChildNames(&nameOrder)))
2544         return;
2545 
2546     // Filter nameOrder by the mask, if necessary.  If this subtree is
2547     // completely included, stop looking at the mask from here forward.
2548     if (mask) {
2549         // We always operate on the source prim index path here, not the prim
2550         // path since that would be something like /__Prototype_X/.. for prims
2551         // in prototypes.  Masks and load rules operate on the "uninstanced"
2552         // view of the world, and are included in instancing keys, so whichever
2553         // index we choose to be the source for a prototype must be included in
2554         // the stage-wide pop mask & load rules, and identically for all
2555         // instances that share a prototype.
2556         const SdfPath& sourceIndexPath = prim->GetSourcePrimIndex().GetPath();
2557         if (mask->IncludesSubtree(sourceIndexPath)) {
2558             mask = nullptr;
2559         } else {
2560             // Remove all names from nameOrder that aren't included in the mask.
2561             nameOrder.erase(
2562                 remove_if(nameOrder.begin(), nameOrder.end(),
2563                           [&sourceIndexPath, mask](TfToken const &nameTok) {
2564                               return !mask->Includes(
2565                                   sourceIndexPath.AppendChild(nameTok));
2566                           }), nameOrder.end());
2567         }
2568     }
2569 
2570     // If the prim has no children, simply destroy any existing child prims.
2571     if (nameOrder.empty()) {
2572         TF_DEBUG(USD_COMPOSITION).Msg("Children empty <%s>\n",
2573                                       prim->GetPath().GetText());
2574         _DestroyDescendents(prim);
2575         return;
2576     }
2577 
2578     // Find the first mismatch between the prim's current child prims and
2579     // the new list of child prims specified in nameOrder.
2580     Usd_PrimDataSiblingIterator
2581         begin = prim->_ChildrenBegin(),
2582         end = prim->_ChildrenEnd(),
2583         cur = begin;
2584     TfTokenVector::const_iterator
2585         curName = nameOrder.begin(),
2586         nameEnd = nameOrder.end();
2587     for (; cur != end && curName != nameEnd; ++cur, ++curName) {
2588         if ((*cur)->GetName() != *curName)
2589             break;
2590     }
2591 
2592     // The prims in [begin, cur) match the children specified in
2593     // [nameOrder.begin(), curName); recompose these child subtrees if needed.
2594     if (recurse) {
2595         for (Usd_PrimDataSiblingIterator it = begin; it != cur; ++it) {
2596             _ComposeChildSubtree(*it, prim, mask);
2597         }
2598     }
2599 
2600     // The prims in [cur, end) do not match the children specified in
2601     // [curName, nameEnd), so we need to process these trailing elements.
2602 
2603     // No trailing elements means children are unchanged.
2604     if (cur == end && curName == nameEnd) {
2605         TF_DEBUG(USD_COMPOSITION).Msg("Children same in same order <%s>\n",
2606                                       prim->GetPath().GetText());
2607         return;
2608     }
2609 
2610     // Trailing names only mean that children have been added to the end
2611     // of the prim's existing children. Note this includes the case where
2612     // the prim had no children previously.
2613     if (cur == end && curName != nameEnd) {
2614         const SdfPath& parentPath = prim->GetPath();
2615         Usd_PrimDataPtr head = nullptr, prev = nullptr, tail = nullptr;
2616         for (; curName != nameEnd; ++curName) {
2617             tail = _InstantiatePrim(parentPath.AppendChild(*curName));
2618             if (recurse) {
2619                 _ComposeChildSubtree(tail, prim, mask);
2620             }
2621             if (!prev) {
2622                 head = tail;
2623             }
2624             else {
2625                 prev->_SetSiblingLink(tail);
2626             }
2627             prev = tail;
2628         }
2629 
2630         if (cur == begin) {
2631             TF_DEBUG(USD_COMPOSITION).Msg("Children all new <%s>\n",
2632                                           prim->GetPath().GetText());
2633             TF_VERIFY(!prim->_firstChild);
2634             prim->_firstChild = head;
2635             tail->_SetParentLink(prim);
2636         }
2637         else {
2638             TF_DEBUG(USD_COMPOSITION).Msg("Children appended <%s>\n",
2639                                           prim->GetPath().GetText());
2640             Usd_PrimDataSiblingIterator lastChild = begin, next = begin;
2641             for (++next; next != cur; lastChild = next, ++next) { }
2642 
2643             (*lastChild)->_SetSiblingLink(head);
2644             tail->_SetParentLink(prim);
2645         }
2646         return;
2647     }
2648 
2649     // Trailing children only mean that children have been removed from
2650     // the end of the prim's existing children.
2651     if (cur != end && curName == nameEnd) {
2652         TF_DEBUG(USD_COMPOSITION).Msg("Children removed from end <%s>\n",
2653                                       prim->GetPath().GetText());
2654         for (Usd_PrimDataSiblingIterator it = cur; it != end; ) {
2655             // Make sure we advance to the next sibling before we destroy
2656             // the current child so we don't read from a deleted prim.
2657             _DestroyPrim(*it++);
2658         }
2659 
2660         if (cur == begin) {
2661             prim->_firstChild = nullptr;
2662         }
2663         else {
2664             Usd_PrimDataSiblingIterator lastChild = begin, next = begin;
2665             for (++next; next != cur; lastChild = next, ++next) { }
2666             (*lastChild)->_SetParentLink(prim);
2667         }
2668         return;
2669     }
2670 
2671     // Otherwise, both trailing children and names mean there was some
2672     // other change to the prim's list of children. Do the general form
2673     // of preserving preexisting children and ordering them according
2674     // to nameOrder.
2675     TF_DEBUG(USD_COMPOSITION).Msg(
2676         "Require general children recomposition <%s>\n",
2677         prim->GetPath().GetText());
2678 
2679     // Make a vector of iterators into nameOrder from [curName, nameEnd).
2680     typedef vector<TfTokenVector::const_iterator> TokenVectorIterVec;
2681     TokenVectorIterVec nameOrderIters(std::distance(curName, nameEnd));
2682     for (size_t i = 0, sz = nameOrderIters.size(); i != sz; ++i) {
2683         nameOrderIters[i] = curName + i;
2684     }
2685 
2686     // Sort the name order iterators *by name*.
2687     sort(nameOrderIters.begin(), nameOrderIters.end(), _DerefIterLess());
2688 
2689     // Make a vector of the existing prim children and sort them by name.
2690     vector<Usd_PrimDataPtr> oldChildren(cur, end);
2691     sort(oldChildren.begin(), oldChildren.end(), _PrimNameLess());
2692 
2693     vector<Usd_PrimDataPtr>::const_iterator
2694         oldChildIt = oldChildren.begin(),
2695         oldChildEnd = oldChildren.end();
2696 
2697     TokenVectorIterVec::const_iterator
2698         newNameItersIt = nameOrderIters.begin(),
2699         newNameItersEnd = nameOrderIters.end();
2700 
2701     // We build a vector of pairs of prims and the original name order
2702     // iterators.  This lets us re-sort by original order once we're finished.
2703     vector<pair<Usd_PrimDataPtr, TfTokenVector::const_iterator> >
2704         tempChildren;
2705     tempChildren.reserve(nameOrderIters.size());
2706 
2707     const SdfPath &parentPath = prim->GetPath();
2708 
2709     while (newNameItersIt != newNameItersEnd || oldChildIt != oldChildEnd) {
2710         // Walk through old children that no longer exist up to the current
2711         // potentially new name, removing them.
2712         while (oldChildIt != oldChildEnd &&
2713                (newNameItersIt == newNameItersEnd ||
2714                 (*oldChildIt)->GetName() < **newNameItersIt)) {
2715             TF_DEBUG(USD_COMPOSITION).Msg("Removing <%s>\n",
2716                                           (*oldChildIt)->GetPath().GetText());
2717             _DestroyPrim(*oldChildIt++);
2718         }
2719 
2720         // Walk through any matching children and preserve them.
2721         for (; newNameItersIt != newNameItersEnd &&
2722                  oldChildIt != oldChildEnd &&
2723                  **newNameItersIt == (*oldChildIt)->GetName();
2724              ++newNameItersIt, ++oldChildIt) {
2725             TF_DEBUG(USD_COMPOSITION).Msg("Preserving <%s>\n",
2726                                           (*oldChildIt)->GetPath().GetText());
2727             tempChildren.push_back(make_pair(*oldChildIt, *newNameItersIt));
2728             if (recurse) {
2729                 Usd_PrimDataPtr child = tempChildren.back().first;
2730                 _ComposeChildSubtree(child, prim, mask);
2731             }
2732         }
2733 
2734         // Walk newly-added names up to the next old name, adding them.
2735         for (; newNameItersIt != newNameItersEnd &&
2736                  (oldChildIt == oldChildEnd ||
2737                   **newNameItersIt < (*oldChildIt)->GetName());
2738              ++newNameItersIt) {
2739             SdfPath newChildPath = parentPath.AppendChild(**newNameItersIt);
2740             TF_DEBUG(USD_COMPOSITION).Msg("Creating new <%s>\n",
2741                                           newChildPath.GetText());
2742             tempChildren.push_back(
2743                 make_pair(_InstantiatePrim(newChildPath), *newNameItersIt));
2744             if (recurse) {
2745                 Usd_PrimDataPtr child = tempChildren.back().first;
2746                 _ComposeChildSubtree(child, prim, mask);
2747             }
2748         }
2749     }
2750 
2751     // tempChildren should never be empty at this point. If it were, it means
2752     // that the above loop would have only deleted existing children, but that
2753     // case is covered by optimization 4 above.
2754     if (!TF_VERIFY(!tempChildren.empty())) {
2755         return;
2756     }
2757 
2758     // Now all the new children are in lexicographical order by name, paired
2759     // with their name's iterator in the original name order.  Recover the
2760     // original order by sorting by the iterators natural order.
2761     sort(tempChildren.begin(), tempChildren.end(), _SecondLess());
2762 
2763     // Now all the new children are correctly ordered.  Set the
2764     // sibling and parent links to add them to the prim's children.
2765     for (size_t i = 0, e = tempChildren.size() - 1; i < e; ++i) {
2766         tempChildren[i].first->_SetSiblingLink(tempChildren[i+1].first);
2767     }
2768     tempChildren.back().first->_SetParentLink(prim);
2769 
2770     if (cur == begin) {
2771         prim->_firstChild = tempChildren.front().first;
2772     }
2773     else {
2774         Usd_PrimDataSiblingIterator lastChild = begin, next = begin;
2775         for (++next; next != cur; lastChild = next, ++next) { }
2776         (*lastChild)->_SetSiblingLink(tempChildren.front().first);
2777     }
2778 }
2779 
2780 void
_ComposeChildSubtree(Usd_PrimDataPtr prim,Usd_PrimDataConstPtr parent,UsdStagePopulationMask const * mask)2781 UsdStage::_ComposeChildSubtree(Usd_PrimDataPtr prim,
2782                                Usd_PrimDataConstPtr parent,
2783                                UsdStagePopulationMask const *mask)
2784 {
2785     if (parent->IsInPrototype()) {
2786         // If this UsdPrim is a child of an instance prototype, its
2787         // source prim index won't be at the same path as its stage path.
2788         // We need to construct the path from the parent's source index.
2789         const SdfPath sourcePrimIndexPath =
2790             parent->GetSourcePrimIndex().GetPath().AppendChild(prim->GetName());
2791         _ComposeSubtree(prim, parent, mask, sourcePrimIndexPath);
2792     }
2793     else {
2794         _ComposeSubtree(prim, parent, mask);
2795     }
2796 }
2797 
2798 void
_ReportPcpErrors(const PcpErrorVector & errors,const std::string & context) const2799 UsdStage::_ReportPcpErrors(const PcpErrorVector &errors,
2800                            const std::string &context) const
2801 {
2802     _ReportErrors(errors, std::vector<std::string>(), context);
2803 }
2804 
2805 // Report any errors.  It's important for error filtering that each
2806 // error be a single line. It's equally important that we provide
2807 // some clue to associating the errors to the originating stage
2808 // (it is caller's responsibility to ensure that any further required
2809 // context (e.g. prim path) be present in 'context' already).  We choose
2810 // a balance between total specificity (which would require identifying
2811 // both the session layer and ArResolverContext and be very long)
2812 // and brevity.  We can modulate this behavior with TfDebug if needed.
2813 // Finally, we use a mutex to ensure there is no interleaving of errors
2814 // from multiple threads.
2815 void
_ReportErrors(const PcpErrorVector & errors,const std::vector<std::string> & otherErrors,const std::string & context) const2816 UsdStage::_ReportErrors(const PcpErrorVector &errors,
2817                         const std::vector<std::string> &otherErrors,
2818                         const std::string &context) const
2819 {
2820     static std::mutex   errMutex;
2821 
2822     if (!errors.empty() || !otherErrors.empty()) {
2823         std::string  fullContext = TfStringPrintf("(%s on stage @%s@ <%p>)",
2824                                       context.c_str(),
2825                                       GetRootLayer()->GetIdentifier().c_str(),
2826                                       this);
2827         std::vector<std::string>  allErrors;
2828         allErrors.reserve(errors.size() + otherErrors.size());
2829 
2830         for (const auto& err : errors) {
2831             allErrors.push_back(TfStringPrintf("%s %s",
2832                                                err->ToString().c_str(),
2833                                                fullContext.c_str()));
2834         }
2835         for (const auto& err : otherErrors) {
2836             allErrors.push_back(TfStringPrintf("%s %s",
2837                                                err.c_str(),
2838                                                fullContext.c_str()));
2839         }
2840 
2841         {
2842             std::lock_guard<std::mutex>  lock(errMutex);
2843 
2844             for (const auto &err : allErrors){
2845                 TF_WARN(err);
2846             }
2847         }
2848     }
2849 }
2850 
2851 // Static prim type info cache
2852 static Usd_PrimTypeInfoCache &
_GetPrimTypeInfoCache()2853 _GetPrimTypeInfoCache()
2854 {
2855     static Usd_PrimTypeInfoCache cache;
2856     return cache;
2857 }
2858 
2859 // Iterate over a prim's specs until we get a non-empty, non-any-type typeName.
2860 static TfToken
_ComposeTypeName(const PcpPrimIndex * primIndex)2861 _ComposeTypeName(const PcpPrimIndex *primIndex)
2862 {
2863     for (Usd_Resolver res(primIndex); res.IsValid(); res.NextLayer()) {
2864         TfToken tok;
2865         if (res.GetLayer()->HasField(
2866                 res.GetLocalPath(), SdfFieldKeys->TypeName, &tok)) {
2867             if (!tok.IsEmpty() && tok != SdfTokens->AnyTypeToken)
2868                 return tok;
2869         }
2870     }
2871     return TfToken();
2872 }
2873 
2874 static void
_ComposeAuthoredAppliedSchemas(const PcpPrimIndex * primIndex,TfTokenVector * schemas)2875 _ComposeAuthoredAppliedSchemas(
2876     const PcpPrimIndex *primIndex, TfTokenVector *schemas)
2877 {
2878     // Collect all list op opinions for the API schemas field from strongest to
2879     // weakest. Then we apply them from weakest to strongest.
2880     std::vector<SdfTokenListOp> listOps;
2881 
2882     SdfTokenListOp listOp;
2883     for (Usd_Resolver res(primIndex); res.IsValid(); res.NextLayer()) {
2884         if (res.GetLayer()->HasField(
2885                 res.GetLocalPath(), UsdTokens->apiSchemas, &listOp)) {
2886             // Add the populated list op to the end of the list.
2887             listOps.emplace_back();
2888             listOps.back().Swap(listOp);
2889             // An explicit list op overwrites anything weaker so we can just
2890             // stop here if it's explicit.
2891             if (listOps.back().IsExplicit()) {
2892                 break;
2893             }
2894         }
2895     }
2896 
2897     // Apply the listops to our output in reverse order (weakest to strongest).
2898     std::for_each(listOps.crbegin(), listOps.crend(),
2899         [&schemas](const SdfTokenListOp& op) { op.ApplyOperations(schemas); });
2900 }
2901 
2902 void
_ComposeSubtreeInParallel(Usd_PrimDataPtr prim)2903 UsdStage::_ComposeSubtreeInParallel(Usd_PrimDataPtr prim)
2904 {
2905     _ComposeSubtreesInParallel(vector<Usd_PrimDataPtr>(1, prim));
2906 }
2907 
2908 void
_ComposeSubtreesInParallel(const vector<Usd_PrimDataPtr> & prims,const vector<SdfPath> * primIndexPaths)2909 UsdStage::_ComposeSubtreesInParallel(
2910     const vector<Usd_PrimDataPtr> &prims,
2911     const vector<SdfPath> *primIndexPaths)
2912 {
2913     TF_PY_ALLOW_THREADS_IN_SCOPE();
2914 
2915     // TF_DEBUG(USD_COMPOSITION).Msg("Composing Subtrees at: %s\n",
2916     //     TfStringify(
2917     //         [&prims]() {
2918     //             vector<SdfPath> paths;
2919     //             for (auto p : prims) { paths.push_back(p->GetPath()); }
2920     //             return paths;
2921     //         }()).c_str());
2922 
2923     TRACE_FUNCTION();
2924 
2925     // Begin a subtree composition in parallel.
2926     WorkWithScopedParallelism([this, &prims, &primIndexPaths]() {
2927             _primMapMutex = boost::in_place();
2928             _dispatcher = boost::in_place();
2929             // We populate the clip cache concurrently during composition, so we
2930             // need to enable concurrent population here.
2931             Usd_ClipCache::ConcurrentPopulationContext
2932                 clipConcurrentPopContext(*_clipCache);
2933             try {
2934                 for (size_t i = 0; i != prims.size(); ++i) {
2935                     Usd_PrimDataPtr p = prims[i];
2936                     _dispatcher->Run(
2937                         &UsdStage::_ComposeSubtreeImpl, this, p, p->GetParent(),
2938                         &_populationMask,
2939                         primIndexPaths ? (*primIndexPaths)[i] : p->GetPath());
2940                 }
2941             }
2942             catch (...) {
2943                 _dispatcher = boost::none;
2944                 _primMapMutex = boost::none;
2945                 throw;
2946             }
2947 
2948             _dispatcher = boost::none;
2949             _primMapMutex = boost::none;
2950         });
2951 }
2952 
2953 void
_ComposeSubtree(Usd_PrimDataPtr prim,Usd_PrimDataConstPtr parent,UsdStagePopulationMask const * mask,const SdfPath & primIndexPath)2954 UsdStage::_ComposeSubtree(
2955     Usd_PrimDataPtr prim, Usd_PrimDataConstPtr parent,
2956     UsdStagePopulationMask const *mask,
2957     const SdfPath& primIndexPath)
2958 {
2959     if (_dispatcher) {
2960         _dispatcher->Run(
2961             &UsdStage::_ComposeSubtreeImpl, this,
2962             prim, parent, mask, primIndexPath);
2963     } else {
2964         // TF_DEBUG(USD_COMPOSITION).Msg("Composing Subtree at <%s>\n",
2965         //                               prim->GetPath().GetText());
2966         // TRACE_FUNCTION();
2967         _ComposeSubtreeImpl(prim, parent, mask, primIndexPath);
2968     }
2969 }
2970 
2971 void
_ComposeSubtreeImpl(Usd_PrimDataPtr prim,Usd_PrimDataConstPtr parent,UsdStagePopulationMask const * mask,const SdfPath & inPrimIndexPath)2972 UsdStage::_ComposeSubtreeImpl(
2973     Usd_PrimDataPtr prim, Usd_PrimDataConstPtr parent,
2974     UsdStagePopulationMask const *mask,
2975     const SdfPath& inPrimIndexPath)
2976 {
2977     TfAutoMallocTag2 tag("Usd", _mallocTagID);
2978 
2979     const SdfPath primIndexPath =
2980         (inPrimIndexPath.IsEmpty() ? prim->GetPath() : inPrimIndexPath);
2981 
2982     // Find the prim's PcpPrimIndex. This should have already been
2983     // computed in a prior call to _ComposePrimIndexesInParallel.
2984     // Note that it's unsafe to call PcpCache::ComputePrimIndex here,
2985     // that method is not thread-safe unless the prim index happens
2986     // to have been computed already.
2987     prim->_primIndex = _GetPcpCache()->FindPrimIndex(primIndexPath);
2988     if (!TF_VERIFY(
2989             prim->_primIndex,
2990             "Prim index at <%s> not found in PcpCache for UsdStage %s",
2991             primIndexPath.GetText(), UsdDescribe(this).c_str())) {
2992         return;
2993     }
2994 
2995     parent = parent ? parent : prim->GetParent();
2996 
2997     // If this prim's parent is the pseudo-root and it has a different
2998     // path from its source prim index, it must represent a prototype prim.
2999     const bool isPrototypePrim =
3000         (parent == _pseudoRoot
3001          && prim->_primIndex->GetPath() != prim->GetPath());
3002 
3003     if (parent && !isPrototypePrim) {
3004         // Compose the type info full type ID for the prim which includes
3005         // the type name, applied schemas, and a possible mapped fallback type
3006         // if the stage specifies it.
3007         Usd_PrimTypeInfoCache::TypeId typeId(
3008             _ComposeTypeName(prim->_primIndex));
3009         _ComposeAuthoredAppliedSchemas(
3010             prim->_primIndex, &typeId.appliedAPISchemas);
3011         if (const TfToken *fallbackType = TfMapLookupPtr(
3012                 _invalidPrimTypeToFallbackMap, typeId.primTypeName)) {
3013             typeId.mappedTypeName = *fallbackType;
3014         }
3015 
3016         // Ask the type info cache for the type info for our type.
3017         prim->_primTypeInfo =
3018             _GetPrimTypeInfoCache().FindOrCreatePrimTypeInfo(std::move(typeId));
3019     } else {
3020         prim->_primTypeInfo = _GetPrimTypeInfoCache().GetEmptyPrimTypeInfo();
3021     }
3022 
3023     // Compose type info and flags for prim.
3024     prim->_ComposeAndCacheFlags(parent, isPrototypePrim);
3025 
3026     // Pre-compute clip information for this prim to avoid doing so
3027     // at value resolution time.
3028     if (prim->GetPath() != SdfPath::AbsoluteRootPath()) {
3029         bool primHasAuthoredClips = _clipCache->PopulateClipsForPrim(
3030             prim->GetPath(), prim->GetPrimIndex());
3031         prim->_SetMayHaveOpinionsInClips(
3032             primHasAuthoredClips || parent->MayHaveOpinionsInClips());
3033     } else {
3034         // When composing the pseudoroot we also determine any fallback type
3035         // mappings that the stage defines for type names that don't have a
3036         // valid schema. The possible mappings are defined in the root layer
3037         // metadata and are needed to compose type info for all the other prims,
3038         // thus why we do this here.
3039         _invalidPrimTypeToFallbackMap.clear();
3040         VtDictionary fallbackPrimTypes;
3041         if (GetMetadata(UsdTokens->fallbackPrimTypes, &fallbackPrimTypes)) {
3042             _GetPrimTypeInfoCache().ComputeInvalidPrimTypeToFallbackMap(
3043                 fallbackPrimTypes, &_invalidPrimTypeToFallbackMap);
3044         }
3045     }
3046 
3047     // Compose the set of children on this prim.
3048     _ComposeChildren(prim, mask, /*recurse=*/true);
3049 }
3050 
3051 void
_DestroyDescendents(Usd_PrimDataPtr prim)3052 UsdStage::_DestroyDescendents(Usd_PrimDataPtr prim)
3053 {
3054     // Recurse to children first.
3055     Usd_PrimDataSiblingIterator
3056         childIt = prim->_ChildrenBegin(), childEnd = prim->_ChildrenEnd();
3057     prim->_firstChild = nullptr;
3058     while (childIt != childEnd) {
3059         if (_dispatcher) {
3060             _dispatcher->Run(&UsdStage::_DestroyPrim, this, *childIt++);
3061         } else {
3062             _DestroyPrim(*childIt++);
3063         }
3064     }
3065 }
3066 
3067 void
_DestroyPrimsInParallel(const vector<SdfPath> & paths)3068 UsdStage::_DestroyPrimsInParallel(const vector<SdfPath>& paths)
3069 {
3070     TF_PY_ALLOW_THREADS_IN_SCOPE();
3071 
3072     TRACE_FUNCTION();
3073 
3074     TF_AXIOM(!_dispatcher && !_primMapMutex);
3075 
3076     WorkWithScopedParallelism([&]() {
3077             _primMapMutex = boost::in_place();
3078             _dispatcher = boost::in_place();
3079             for (const auto& path : paths) {
3080                 Usd_PrimDataPtr prim = _GetPrimDataAtPath(path);
3081                 // We *expect* every prim in paths to be valid as we iterate,
3082                 // but at one time had issues with deactivated prototype prims,
3083                 // so we preserve a guard for resiliency.  See
3084                 // testUsdBug141491.py
3085                 if (TF_VERIFY(prim)) {
3086                     _dispatcher->Run(&UsdStage::_DestroyPrim, this, prim);
3087                 }
3088             }
3089             _dispatcher = boost::none;
3090             _primMapMutex = boost::none;
3091         });
3092 }
3093 
3094 void
_DestroyPrim(Usd_PrimDataPtr prim)3095 UsdStage::_DestroyPrim(Usd_PrimDataPtr prim)
3096 {
3097     TF_DEBUG(USD_COMPOSITION).Msg(
3098         "Destroying <%s>\n", prim->GetPath().GetText());
3099 
3100     // Destroy descendents first.
3101     _DestroyDescendents(prim);
3102 
3103     // Set the prim's dead bit.
3104     prim->_MarkDead();
3105 
3106     // Remove from the map -- this prim should always be present.
3107 
3108     // XXX: We intentionally copy the prim's path to the local variable primPath
3109     // here.  If we don't, the erase() call ends up reading freed memory.  This
3110     // is because libstdc++'s hash_map's backing implementation implements
3111     // erase() as: find the first element with a matching key, erase it, then
3112     // walk subsequent bucket elements with matching keys and erase them.  This
3113     // might seem odd for hash_map since only one element can have the given
3114     // key, but it works this way since the backing implementation is shared
3115     // between hash_map and hash_multimap.
3116     //
3117     // This is a problem since prim->GetPath() returns a const reference to a
3118     // member variable, so once the first element (and only element) is erased
3119     // the reference is invalidated, but erase() may look at the path reference
3120     // again to do the key comparison for subsequent elements.  Copying the path
3121     // out to a local variable ensures it stays alive for the duration of
3122     // erase().
3123     //
3124     // NOTE: The above was true in gcc 4.4 but not in gcc 4.8, nor is it
3125     //       true in boost::unordered_map or std::unordered_map.
3126     if (!_isClosingStage) {
3127         SdfPath primPath = prim->GetPath();
3128         tbb::spin_rw_mutex::scoped_lock lock;
3129         const bool hasMutex = static_cast<bool>(_primMapMutex);
3130         if (hasMutex)
3131             lock.acquire(*_primMapMutex);
3132         bool erased = _primMap.erase(primPath);
3133         if (hasMutex)
3134             lock.release();
3135         TF_VERIFY(erased,
3136                   "Destroyed prim <%s> not present in stage's data structures",
3137                   prim->GetPath().GetString().c_str());
3138     }
3139 }
3140 
3141 void
Reload()3142 UsdStage::Reload()
3143 {
3144     TfAutoMallocTag2 tag("Usd", _mallocTagID);
3145 
3146     // This UsdStage may receive layer change notices due to layers being
3147     // reloaded below. However, we won't receive that notice for any layers
3148     // that we failed to load previously but are now loadable. For example,
3149     // if a prim had a reference to a non-existent layer, but then that
3150     // layer was created, the only indication of that would be a prim resync
3151     // in the PcpChanges object returned by Reload.
3152     //
3153     // We want to combine the stage changes from processing the layer changes
3154     // with the stage changes indicated in the PcpChanges returned by Reload
3155     // so that this stage only goes through one round of change processing
3156     // and notification. So, we create a _PendingChanges object that will
3157     // be filled in by _HandleLayersDidChange and the call to Reload, then
3158     // process all of that information in _ProcessPendingChanges().
3159     _PendingChanges localPendingChanges;
3160     _pendingChanges = &localPendingChanges;
3161 
3162     ArResolverScopedCache resolverCache;
3163 
3164 #if AR_VERSION > 1
3165     // Refresh the resolver to pick up changes that might have
3166     // affected asset resolution.
3167     ArGetResolver().RefreshContext(GetPathResolverContext());
3168 #endif
3169 
3170     // Reload layers in a change block to batch together change notices.
3171     {
3172         SdfChangeBlock block;
3173 
3174         // Reload layers that are reached via composition.
3175         PcpChanges& changes = _pendingChanges->pcpChanges;
3176         _cache->Reload(&changes);
3177 
3178         // Reload all clip layers that are opened.
3179         _clipCache->Reload();
3180     }
3181 
3182     // Process changes if they haven't already been processed in response
3183     // to layer change notices above. If they have already been processed,
3184     // _pendingChanges would have been reset to NULL.
3185     if (_pendingChanges == &localPendingChanges) {
3186         _ProcessPendingChanges();
3187     }
3188 }
3189 
3190 /*static*/
3191 bool
IsSupportedFile(const std::string & filePath)3192 UsdStage::IsSupportedFile(const std::string& filePath)
3193 {
3194     if (filePath.empty()) {
3195         TF_CODING_ERROR("Empty file path given");
3196         return false;
3197     }
3198 
3199     // grab the file's extension, and assert it to be valid
3200     std::string fileExtension = SdfFileFormat::GetFileExtension(filePath);
3201     if (fileExtension.empty()) {
3202         return false;
3203     }
3204 
3205     // if the extension is valid we'll get a non null FileFormatPtr
3206     return SdfFileFormat::FindByExtension(fileExtension,
3207                                           UsdUsdFileFormatTokens->Target);
3208 }
3209 
3210 namespace {
3211 
_SaveLayers(const SdfLayerHandleVector & layers)3212 void _SaveLayers(const SdfLayerHandleVector& layers)
3213 {
3214     for (const SdfLayerHandle& layer : layers) {
3215         if (!layer->IsDirty()) {
3216             continue;
3217         }
3218 
3219         if (layer->IsAnonymous()) {
3220             TF_WARN("Not saving @%s@ because it is an anonymous layer",
3221                     layer->GetIdentifier().c_str());
3222             continue;
3223         }
3224 
3225         // Sdf will emit errors if there are any problems with
3226         // saving the layer.
3227         layer->Save();
3228     }
3229 }
3230 
3231 }
3232 
3233 void
Save()3234 UsdStage::Save()
3235 {
3236     SdfLayerHandleVector layers = GetUsedLayers();
3237 
3238     const PcpLayerStackPtr localLayerStack = _GetPcpCache()->GetLayerStack();
3239     if (TF_VERIFY(localLayerStack)) {
3240         const SdfLayerHandleVector sessionLayers =
3241             localLayerStack->GetSessionLayers();
3242         const auto isSessionLayer =
3243             [&sessionLayers](const SdfLayerHandle& l) {
3244                 return std::find(
3245                     sessionLayers.begin(), sessionLayers.end(), l)
3246                     != sessionLayers.end();
3247             };
3248 
3249         layers.erase(std::remove_if(layers.begin(), layers.end(),
3250                                     isSessionLayer),
3251                      layers.end());
3252     }
3253 
3254     _SaveLayers(layers);
3255 }
3256 
3257 void
SaveSessionLayers()3258 UsdStage::SaveSessionLayers()
3259 {
3260     const PcpLayerStackPtr localLayerStack = _GetPcpCache()->GetLayerStack();
3261     if (TF_VERIFY(localLayerStack)) {
3262         _SaveLayers(localLayerStack->GetSessionLayers());
3263     }
3264 }
3265 
3266 void
WriteFallbackPrimTypes()3267 UsdStage::WriteFallbackPrimTypes()
3268 {
3269     // Mark that we're writing the fallback prim types from the schema registry
3270     // so that we can ignore changes to the fallbackPrimTypes metadata if we
3271     // end up writing it below. Otherwise we could end up rebuilding the entire
3272     // stage unnecessarily when this particular data shouldn't change any of
3273     // the prims' composition.
3274     TfScopedVar<bool> resetIsWriting(_isWritingFallbackPrimTypes, true);
3275 
3276     // Any fallback types for schema prim types will be defined in the schemas
3277     // themselves. The schema registry provides the fallback prim type
3278     // dictionary for us to write in the metadata
3279     const VtDictionary &schemaFallbackTypes =
3280         UsdSchemaRegistry::GetInstance().GetFallbackPrimTypes();
3281     if (!schemaFallbackTypes.empty()) {
3282         // The stage may already have metadata for fallback prim types, written
3283         // from this version of Usd, a different version of Usd, or possibly
3284         // direct user authoring of the metadata. We don't overwrite any
3285         // existing fallbacks; we only add entries for the types that don't have
3286         // fallbacks defined in the metadata yet.
3287         VtDictionary existingFallbackTypes;
3288         if (GetMetadata(UsdTokens->fallbackPrimTypes, &existingFallbackTypes)) {
3289             VtDictionaryOver(&existingFallbackTypes, schemaFallbackTypes);
3290             SetMetadata(UsdTokens->fallbackPrimTypes, existingFallbackTypes);
3291         } else {
3292             SetMetadata(UsdTokens->fallbackPrimTypes, schemaFallbackTypes);
3293         }
3294     }
3295 }
3296 
3297 std::pair<bool, UsdPrim>
_IsValidPathForCreatingPrim(const SdfPath & path) const3298 UsdStage::_IsValidPathForCreatingPrim(const SdfPath &path) const
3299 {
3300     std::pair<bool, UsdPrim> status = { false, UsdPrim() };
3301 
3302     // Path must be absolute.
3303     if (ARCH_UNLIKELY(!path.IsAbsolutePath())) {
3304         TF_CODING_ERROR("Path must be an absolute path: <%s>", path.GetText());
3305         return status;
3306     }
3307 
3308     // Path must be a prim path (or the absolute root path).
3309     if (ARCH_UNLIKELY(!path.IsAbsoluteRootOrPrimPath())) {
3310         TF_CODING_ERROR("Path must be a prim path: <%s>", path.GetText());
3311         return status;
3312     }
3313 
3314     // Path must not contain variant selections.
3315     if (ARCH_UNLIKELY(path.ContainsPrimVariantSelection())) {
3316         TF_CODING_ERROR("Path must not contain variant selections: <%s>",
3317                         path.GetText());
3318         return status;
3319     }
3320 
3321     const UsdPrim prim = GetPrimAtPath(path);
3322     if (ARCH_UNLIKELY(prim ? !_ValidateEditPrim(prim, "create prim")
3323                            : !_ValidateEditPrimAtPath(path, "create prim"))) {
3324         return status;
3325     }
3326 
3327     status = { true, prim };
3328     return status;
3329 }
3330 
3331 UsdPrim
OverridePrim(const SdfPath & path)3332 UsdStage::OverridePrim(const SdfPath &path)
3333 {
3334     // Special-case requests for the root.  It always succeeds and never does
3335     // authoring since the root cannot have PrimSpecs.
3336     if (path == SdfPath::AbsoluteRootPath())
3337         return GetPseudoRoot();
3338 
3339     // Validate path input.
3340     std::pair<bool, UsdPrim> status = _IsValidPathForCreatingPrim(path);
3341     if (!status.first) {
3342         return UsdPrim();
3343     }
3344 
3345     // Do the authoring, if any to do.
3346     if (!status.second) {
3347         {
3348             SdfChangeBlock block;
3349             TfErrorMark m;
3350             SdfPrimSpecHandle primSpec =
3351                 _CreatePrimSpecAtEditTarget(GetEditTarget(), path);
3352             // If spec creation failed, return.  Issue an error if a more
3353             // specific error wasn't already issued.
3354             if (!primSpec) {
3355                 if (m.IsClean())
3356                     TF_RUNTIME_ERROR("Failed to create PrimSpec for <%s>",
3357                                      path.GetText());
3358                 return UsdPrim();
3359             }
3360         }
3361 
3362         // Attempt to fetch the prim we tried to create.
3363         status.second = GetPrimAtPath(path);
3364     }
3365 
3366     return status.second;
3367 }
3368 
3369 UsdPrim
DefinePrim(const SdfPath & path,const TfToken & typeName)3370 UsdStage::DefinePrim(const SdfPath &path,
3371                      const TfToken &typeName)
3372 {
3373     // Validate path input.
3374     if (!_IsValidPathForCreatingPrim(path).first)
3375         return UsdPrim();
3376 
3377     return _DefinePrim(path, typeName);
3378 }
3379 
3380 UsdPrim
_DefinePrim(const SdfPath & path,const TfToken & typeName)3381 UsdStage::_DefinePrim(const SdfPath &path, const TfToken &typeName)
3382 {
3383     // Special-case requests for the root.  It always succeeds and never does
3384     // authoring since the root cannot have PrimSpecs.
3385     if (path == SdfPath::AbsoluteRootPath())
3386         return GetPseudoRoot();
3387 
3388     // Define all ancestors.
3389     if (!_DefinePrim(path.GetParentPath(), TfToken()))
3390         return UsdPrim();
3391 
3392     // Now author scene description for this prim.
3393     TfErrorMark m;
3394     UsdPrim prim = GetPrimAtPath(path);
3395     if (!prim || !prim.IsDefined() ||
3396         (!typeName.IsEmpty() && prim.GetTypeName() != typeName)) {
3397         {
3398             SdfChangeBlock block;
3399             SdfPrimSpecHandle primSpec =
3400                 _CreatePrimSpecAtEditTarget(GetEditTarget(), path);
3401             // If spec creation failed, return.  Issue an error if a more
3402             // specific error wasn't already issued.
3403             if (!primSpec) {
3404                 if (m.IsClean())
3405                     TF_RUNTIME_ERROR(
3406                         "Failed to create primSpec for <%s>", path.GetText());
3407                 return UsdPrim();
3408             }
3409 
3410             // Set specifier and typeName, if not empty.
3411             primSpec->SetSpecifier(SdfSpecifierDef);
3412             if (!typeName.IsEmpty())
3413                 primSpec->SetTypeName(typeName);
3414         }
3415         // Fetch prim if newly created.
3416         prim = prim ? prim : GetPrimAtPath(path);
3417     }
3418 
3419     // Issue an error if we were unable to define this prim and an error isn't
3420     // already issued.
3421     if ((!prim || !prim.IsDefined()) && m.IsClean())
3422         TF_RUNTIME_ERROR("Failed to define UsdPrim <%s>", path.GetText());
3423 
3424     return prim;
3425 }
3426 
3427 UsdPrim
CreateClassPrim(const SdfPath & path)3428 UsdStage::CreateClassPrim(const SdfPath &path)
3429 {
3430     // Classes must be created in local layers.
3431     if (_editTarget.GetMapFunction().IsIdentity() &&
3432         !HasLocalLayer(_editTarget.GetLayer())) {
3433         TF_CODING_ERROR("Must create classes in local LayerStack");
3434         return UsdPrim();
3435     }
3436 
3437     // Validate path input.
3438     const std::pair<bool, UsdPrim> status = _IsValidPathForCreatingPrim(path);
3439     if (!status.first) {
3440         return UsdPrim();
3441     }
3442 
3443     UsdPrim prim = status.second;
3444 
3445     // It's an error to try to transform a defined non-class into a class.
3446     if (prim && prim.IsDefined() &&
3447         prim.GetSpecifier() != SdfSpecifierClass) {
3448         TF_RUNTIME_ERROR("Non-class prim already exists at <%s>",
3449                          path.GetText());
3450         return UsdPrim();
3451     }
3452 
3453     // Stamp a class PrimSpec if need-be.
3454     if (!prim || !prim.IsAbstract()) {
3455         prim = _DefinePrim(path, TfToken());
3456         if (prim)
3457             prim.SetMetadata(SdfFieldKeys->Specifier, SdfSpecifierClass);
3458     }
3459     return prim;
3460 }
3461 
3462 bool
RemovePrim(const SdfPath & path)3463 UsdStage::RemovePrim(const SdfPath& path)
3464 {
3465     return _RemovePrim(path);
3466 }
3467 
3468 const UsdEditTarget &
GetEditTarget() const3469 UsdStage::GetEditTarget() const
3470 {
3471     return _editTarget;
3472 }
3473 
3474 UsdEditTarget
GetEditTargetForLocalLayer(size_t i)3475 UsdStage::GetEditTargetForLocalLayer(size_t i)
3476 {
3477     const SdfLayerRefPtrVector & layers = _cache->GetLayerStack()->GetLayers();
3478     if (i >= layers.size()) {
3479         TF_CODING_ERROR("Layer index %zu is out of range: only %zu entries in "
3480                         "layer stack", i, layers.size());
3481         return UsdEditTarget();
3482     }
3483     const SdfLayerOffset *layerOffset =
3484         _cache->GetLayerStack()->GetLayerOffsetForLayer(i);
3485     return UsdEditTarget(layers[i],
3486                          layerOffset ? *layerOffset : SdfLayerOffset() );
3487 }
3488 
3489 UsdEditTarget
GetEditTargetForLocalLayer(const SdfLayerHandle & layer)3490 UsdStage::GetEditTargetForLocalLayer(const SdfLayerHandle &layer)
3491 {
3492     const SdfLayerOffset *layerOffset =
3493         _cache->GetLayerStack()->GetLayerOffsetForLayer(layer);
3494     return UsdEditTarget(layer, layerOffset ? *layerOffset : SdfLayerOffset() );
3495 }
3496 
3497 bool
HasLocalLayer(const SdfLayerHandle & layer) const3498 UsdStage::HasLocalLayer(const SdfLayerHandle &layer) const
3499 {
3500     return _cache->GetLayerStack()->HasLayer(layer);
3501 }
3502 
3503 void
SetEditTarget(const UsdEditTarget & editTarget)3504 UsdStage::SetEditTarget(const UsdEditTarget &editTarget)
3505 {
3506     if (!editTarget.IsValid()){
3507         TF_CODING_ERROR("Attempt to set an invalid UsdEditTarget as current");
3508         return;
3509     }
3510     // Do some extra error checking if the EditTarget specifies a local layer.
3511     if (editTarget.GetMapFunction().IsIdentity() &&
3512         !HasLocalLayer(editTarget.GetLayer())) {
3513         TF_CODING_ERROR("Layer @%s@ is not in the local LayerStack rooted "
3514                         "at @%s@",
3515                         editTarget.GetLayer()->GetIdentifier().c_str(),
3516                         GetRootLayer()->GetIdentifier().c_str());
3517         return;
3518     }
3519 
3520     // If different from current, set EditTarget and notify.
3521     if (editTarget != _editTarget) {
3522         _editTarget = editTarget;
3523         UsdStageWeakPtr self(this);
3524         UsdNotice::StageEditTargetChanged(self).Send(self);
3525     }
3526 }
3527 
3528 SdfLayerHandle
GetRootLayer() const3529 UsdStage::GetRootLayer() const
3530 {
3531     return _rootLayer;
3532 }
3533 
3534 ArResolverContext
GetPathResolverContext() const3535 UsdStage::GetPathResolverContext() const
3536 {
3537     if (!TF_VERIFY(_GetPcpCache())) {
3538         static ArResolverContext empty;
3539         return empty;
3540     }
3541     return _GetPcpCache()->GetLayerStackIdentifier().pathResolverContext;
3542 }
3543 
3544 SdfLayerHandleVector
GetLayerStack(bool includeSessionLayers) const3545 UsdStage::GetLayerStack(bool includeSessionLayers) const
3546 {
3547     SdfLayerHandleVector result;
3548 
3549     // Pcp's API lets us get either the whole stack or just the session layer
3550     // stack.  We get the whole stack and either copy the whole thing to Handles
3551     // or only the portion starting at the root layer to the end.
3552 
3553     if (PcpLayerStackPtr layerStack = _cache->GetLayerStack()) {
3554         const SdfLayerRefPtrVector &layers = layerStack->GetLayers();
3555 
3556         // Copy everything if sublayers requested, otherwise copy from the root
3557         // layer to the end.
3558         SdfLayerRefPtrVector::const_iterator copyBegin =
3559             includeSessionLayers ? layers.begin() :
3560             find(layers.begin(), layers.end(), GetRootLayer());
3561 
3562         TF_VERIFY(copyBegin != layers.end(),
3563                   "Root layer @%s@ not in LayerStack",
3564                   GetRootLayer()->GetIdentifier().c_str());
3565 
3566         result.assign(copyBegin, layers.end());
3567     }
3568 
3569     return result;
3570 }
3571 
3572 SdfLayerHandleVector
GetUsedLayers(bool includeClipLayers) const3573 UsdStage::GetUsedLayers(bool includeClipLayers) const
3574 {
3575     if (!_cache)
3576         return SdfLayerHandleVector();
3577 
3578     SdfLayerHandleSet usedLayers = _cache->GetUsedLayers();
3579 
3580     if (includeClipLayers && _clipCache){
3581         SdfLayerHandleSet clipLayers = _clipCache->GetUsedLayers();
3582         if (!clipLayers.empty()){
3583             usedLayers.insert(clipLayers.begin(), clipLayers.end());
3584         }
3585     }
3586 
3587     return SdfLayerHandleVector(usedLayers.begin(), usedLayers.end());
3588 }
3589 
3590 
3591 SdfLayerHandle
GetSessionLayer() const3592 UsdStage::GetSessionLayer() const
3593 {
3594     return _sessionLayer;
3595 }
3596 
3597 void
MuteLayer(const std::string & layerIdentifier)3598 UsdStage::MuteLayer(const std::string &layerIdentifier)
3599 {
3600     MuteAndUnmuteLayers({layerIdentifier}, {});
3601 }
3602 
3603 void
UnmuteLayer(const std::string & layerIdentifier)3604 UsdStage::UnmuteLayer(const std::string &layerIdentifier)
3605 {
3606     MuteAndUnmuteLayers({}, {layerIdentifier});
3607 }
3608 
3609 void
MuteAndUnmuteLayers(const std::vector<std::string> & muteLayers,const std::vector<std::string> & unmuteLayers)3610 UsdStage::MuteAndUnmuteLayers(const std::vector<std::string> &muteLayers,
3611                               const std::vector<std::string> &unmuteLayers)
3612 {
3613     TfAutoMallocTag2 tag("Usd", _mallocTagID);
3614 
3615     PcpChanges changes;
3616     std::vector<std::string> newMutedLayers, newUnMutedLayers;
3617     _cache->RequestLayerMuting(muteLayers, unmuteLayers, &changes,
3618             &newMutedLayers, &newUnMutedLayers);
3619 
3620     UsdStageWeakPtr self(this);
3621 
3622     // Notify for layer muting/unmuting
3623     if (!newMutedLayers.empty() || !newUnMutedLayers.empty()) {
3624         UsdNotice::LayerMutingChanged(self, newMutedLayers, newUnMutedLayers)
3625             .Send(self);
3626     }
3627 
3628     if (changes.IsEmpty()) {
3629         return;
3630     }
3631 
3632     using _PathsToChangesMap = UsdNotice::ObjectsChanged::_PathsToChangesMap;
3633     _PathsToChangesMap resyncChanges, infoChanges;
3634     _Recompose(changes, &resyncChanges);
3635 
3636     UsdNotice::ObjectsChanged(self, &resyncChanges, &infoChanges)
3637         .Send(self);
3638     UsdNotice::StageContentsChanged(self).Send(self);
3639 }
3640 
3641 const std::vector<std::string>&
GetMutedLayers() const3642 UsdStage::GetMutedLayers() const
3643 {
3644     return _cache->GetMutedLayers();
3645 }
3646 
3647 bool
IsLayerMuted(const std::string & layerIdentifier) const3648 UsdStage::IsLayerMuted(const std::string& layerIdentifier) const
3649 {
3650     return _cache->IsLayerMuted(layerIdentifier);
3651 }
3652 
3653 UsdPrimRange
Traverse()3654 UsdStage::Traverse()
3655 {
3656     return UsdPrimRange::Stage(UsdStagePtr(this));
3657 }
3658 
3659 UsdPrimRange
Traverse(const Usd_PrimFlagsPredicate & predicate)3660 UsdStage::Traverse(const Usd_PrimFlagsPredicate &predicate)
3661 {
3662     return UsdPrimRange::Stage(UsdStagePtr(this), predicate);
3663 }
3664 
3665 UsdPrimRange
TraverseAll()3666 UsdStage::TraverseAll()
3667 {
3668     return UsdPrimRange::Stage(UsdStagePtr(this), UsdPrimAllPrimsPredicate);
3669 }
3670 
3671 bool
_RemovePrim(const SdfPath & path)3672 UsdStage::_RemovePrim(const SdfPath& path)
3673 {
3674     SdfPrimSpecHandle spec = _GetPrimSpec(path);
3675     if (!spec) {
3676         return false;
3677     }
3678 
3679     SdfPrimSpecHandle parent = spec->GetRealNameParent();
3680     if (!parent) {
3681         return false;
3682     }
3683 
3684     return parent->RemoveNameChild(spec);
3685 }
3686 
3687 bool
_RemoveProperty(const SdfPath & path)3688 UsdStage::_RemoveProperty(const SdfPath &path)
3689 {
3690     SdfPropertySpecHandle propHandle =
3691         GetEditTarget().GetPropertySpecForScenePath(path);
3692 
3693     if (!propHandle) {
3694         return false;
3695     }
3696 
3697     // dynamic cast needed because of protected copyctor
3698     // safe to assume a prim owner because we are in UsdPrim
3699     SdfPrimSpecHandle parent
3700         = TfDynamic_cast<SdfPrimSpecHandle>(propHandle->GetOwner());
3701 
3702     if (!TF_VERIFY(parent, "Prop has no parent")) {
3703         return false;
3704     }
3705 
3706     parent->RemoveProperty(propHandle);
3707     return true;
3708 }
3709 
3710 template <class... Values>
3711 static void
_AddToChangedPaths(SdfPathVector * paths,const SdfPath & p,const Values &...data)3712 _AddToChangedPaths(SdfPathVector *paths, const SdfPath& p,
3713                    const Values&... data)
3714 {
3715     paths->push_back(p);
3716 }
3717 
3718 template <class ChangedPaths, class... Values>
3719 static void
_AddToChangedPaths(ChangedPaths * paths,const SdfPath & p,const Values &...data)3720 _AddToChangedPaths(ChangedPaths *paths, const SdfPath& p, const Values&... data)
3721 {
3722     (*paths)[p].emplace_back(data...);
3723 }
3724 
3725 static std::string
_Stringify(const SdfPathVector & paths)3726 _Stringify(const SdfPathVector& paths)
3727 {
3728     return TfStringify(paths);
3729 }
3730 
3731 template <class ChangedPaths>
3732 static std::string
_Stringify(const ChangedPaths & paths)3733 _Stringify(const ChangedPaths& paths)
3734 {
3735     return _Stringify(SdfPathVector(
3736         make_transform_iterator(paths.begin(), TfGet<0>()),
3737         make_transform_iterator(paths.end(), TfGet<0>())));
3738 }
3739 
3740 // Add paths in the given cache that depend on the given path in the given
3741 // layer to changedPaths. If ChangedPaths is a map of paths to list of
3742 // objects, will construct an object using the given extraData
3743 // and append to the back of the list for each dependent path. If
3744 // ChangedPaths is a vector, each dependent path will be appended to
3745 // the vector and extraData is ignored.
3746 template <class ChangedPaths, class... ExtraData>
3747 static void
_AddAffectedStagePaths(const SdfLayerHandle & layer,const SdfPath & path,const PcpCache & cache,ChangedPaths * changedPaths,const ExtraData &...extraData)3748 _AddAffectedStagePaths(const SdfLayerHandle &layer, const SdfPath &path,
3749                        const PcpCache &cache,
3750                        ChangedPaths *changedPaths,
3751                        const ExtraData&... extraData)
3752 {
3753     // We include virtual dependencies so that we can process
3754     // changes like adding missing defaultPrim metadata.
3755     const PcpDependencyFlags depTypes =
3756         PcpDependencyTypeDirect
3757         | PcpDependencyTypeAncestral
3758         | PcpDependencyTypeNonVirtual
3759         | PcpDependencyTypeVirtual;
3760 
3761     // Do not filter dependencies against the indexes cached in PcpCache,
3762     // because Usd does not cache PcpPropertyIndex entries.
3763     const bool filterForExistingCachesOnly = false;
3764 
3765     // If this site is in the cache's layerStack, we always add it here.
3766     // We do this instead of including PcpDependencyTypeRoot in depTypes
3767     // because we do not want to include root deps on those sites, just
3768     // the other kinds of inbound deps.
3769     if (cache.GetLayerStack()->HasLayer(layer)) {
3770         const SdfPath depPath = path.StripAllVariantSelections();
3771         _AddToChangedPaths(changedPaths, depPath, extraData...);
3772     }
3773 
3774     for (const PcpDependency& dep:
3775          cache.FindSiteDependencies(layer, path, depTypes,
3776                                     /* recurseOnSite */ true,
3777                                     /* recurseOnIndex */ false,
3778                                     filterForExistingCachesOnly)) {
3779         _AddToChangedPaths(changedPaths, dep.indexPath, extraData...);
3780     }
3781 
3782     TF_DEBUG(USD_CHANGES).Msg(
3783         "Adding paths that use <%s> in layer @%s@: %s\n",
3784         path.GetText(),
3785         layer->GetIdentifier().c_str(),
3786         _Stringify(*changedPaths).c_str());
3787 }
3788 
3789 // Removes all elements from changedPaths whose paths are prefixed
3790 // by other elements.
3791 template <class ChangedPaths>
3792 static void
_RemoveDescendentEntries(ChangedPaths * changedPaths)3793 _RemoveDescendentEntries(ChangedPaths *changedPaths)
3794 {
3795     for (auto it = changedPaths->begin(); it != changedPaths->end(); ) {
3796         auto prefixedIt = it;
3797         ++prefixedIt;
3798 
3799         auto prefixedEndIt = prefixedIt;
3800         for (; prefixedEndIt != changedPaths->end()
3801                && prefixedEndIt->first.HasPrefix(it->first); ++prefixedEndIt)
3802             { }
3803 
3804         changedPaths->erase(prefixedIt, prefixedEndIt);
3805         ++it;
3806     }
3807 }
3808 
3809 // Removes all elements from weaker whose paths are prefixed by other
3810 // elements in stronger. If elements with the same path exist in both
3811 // weaker and stronger, merges those elements into stronger and removes
3812 // the element from weaker. Assumes that stronger has no elements
3813 // whose paths are prefixed by other elements in stronger.
3814 template <class ChangedPaths>
3815 static void
_MergeAndRemoveDescendentEntries(ChangedPaths * stronger,ChangedPaths * weaker)3816 _MergeAndRemoveDescendentEntries(ChangedPaths *stronger, ChangedPaths *weaker)
3817 {
3818     // We may be removing entries from weaker, and depending on the
3819     // concrete type of ChangedPaths that may invalidate iterators. So don't
3820     // cache the end iterator here.
3821     auto weakIt = weaker->begin();
3822 
3823     auto strongIt = stronger->begin();
3824     const auto strongEndIt = stronger->end();
3825 
3826     while (strongIt != strongEndIt && weakIt != weaker->end()) {
3827         if (weakIt->first < strongIt->first) {
3828             // If the current element in weaker is less than the current element
3829             // in stronger, it cannot be prefixed, so retain it.
3830             ++weakIt;
3831         } else if (weakIt->first == strongIt->first) {
3832             // If the same path exists in both weaker and stronger, merge the
3833             // weaker entry into stronger, then remove it from weaker.
3834             strongIt->second.insert(strongIt->second.end(),
3835                 weakIt->second.begin(), weakIt->second.end());
3836             weakIt = weaker->erase(weakIt);
3837         } else if (weakIt->first.HasPrefix(strongIt->first)) {
3838             // Otherwise if this element in weaker is prefixed by the current
3839             // element in stronger, discard it.
3840             //
3841             // Note that if stronger was allowed to have elements that were
3842             // prefixed by other elements in stronger, this would not be
3843             // correct, since stronger could have an exact match for this
3844             // path, which we'd need to merge.
3845             weakIt = weaker->erase(weakIt);
3846         } else {
3847             // Otherwise advance to the next element in stronger.
3848             ++strongIt;
3849         }
3850     }
3851 }
3852 
3853 void
_HandleLayersDidChange(const SdfNotice::LayersDidChangeSentPerLayer & n)3854 UsdStage::_HandleLayersDidChange(
3855     const SdfNotice::LayersDidChangeSentPerLayer &n)
3856 {
3857     TfAutoMallocTag2 tag("Usd", _mallocTagID);
3858 
3859     // Ignore if this is not the round of changes we're looking for.
3860     size_t serial = n.GetSerialNumber();
3861     if (serial == _lastChangeSerialNumber)
3862         return;
3863 
3864     if (ARCH_UNLIKELY(serial < _lastChangeSerialNumber)) {
3865         // If we receive a change from an earlier round of change processing
3866         // than one we've already seen, there must be a violation of the Usd
3867         // threading model -- concurrent edits to layers that apply to a single
3868         // stage are disallowed.
3869         TF_CODING_ERROR("Detected usd threading violation.  Concurrent changes "
3870                         "to layer(s) composed in stage %p rooted at @%s@.  "
3871                         "(serial=%zu, lastSerial=%zu).",
3872                         this, GetRootLayer()->GetIdentifier().c_str(),
3873                         serial, _lastChangeSerialNumber);
3874         return;
3875     }
3876 
3877     _lastChangeSerialNumber = serial;
3878 
3879     TF_DEBUG(USD_CHANGES).Msg(
3880         "\nHandleLayersDidChange received (%s)\n", UsdDescribe(this).c_str());
3881 
3882     // If a function up the call stack has set up _PendingChanges, merge in
3883     // all of the information from layer changes so it can be processed later.
3884     // Otherwise, fill in our own _PendingChanges and process it at the end
3885     // of this function.
3886     _PendingChanges localPendingChanges;
3887     if (!_pendingChanges) {
3888         _pendingChanges = &localPendingChanges;
3889     }
3890 
3891     // Keep track of paths to USD objects that need to be recomposed or
3892     // have otherwise changed.
3893     using _PathsToChangesMap = UsdNotice::ObjectsChanged::_PathsToChangesMap;
3894     _PathsToChangesMap& recomposeChanges = _pendingChanges->recomposeChanges;
3895     _PathsToChangesMap& otherResyncChanges = _pendingChanges->otherResyncChanges;
3896     _PathsToChangesMap& otherInfoChanges = _pendingChanges->otherInfoChanges;
3897 
3898     SdfPathVector changedActivePaths;
3899 
3900     // A fallback prim types change occurs when the fallbackPrimTypes metadata
3901     // changes on the root or session layer.
3902     // Note that we never process these changes while writing the schema
3903     // defined prim type fallbacks to the stage metadata via
3904     // WriteFallbackPrimTypes. Since the function can only write fallbacks for
3905     // recognized schema types and does not overwrite existing fallback entries,
3906     // it creates no effective changes to the composed prims. So, we have to
3907     // ignore this layer metadata change to avoid unnecessarily recomposing
3908     // the whole stage.
3909     auto _IsFallbackPrimTypesChange =
3910         [this](const SdfLayerHandle &layer, const SdfPath &sdfPath,
3911                const TfToken &infoKey)
3912     {
3913         return infoKey == UsdTokens->fallbackPrimTypes &&
3914                !this->_isWritingFallbackPrimTypes &&
3915                sdfPath == SdfPath::AbsoluteRootPath() &&
3916                (layer == this->GetRootLayer() ||
3917                 layer == this->GetSessionLayer());
3918     };
3919 
3920     // Add dependent paths for any PrimSpecs whose fields have changed that may
3921     // affect cached prim information.
3922     for(const auto& layerAndChangelist : n.GetChangeListVec()) {
3923         // If this layer does not pertain to us, skip.
3924         const SdfLayerHandle &layer = layerAndChangelist.first;
3925         if (_cache->FindAllLayerStacksUsingLayer(layer).empty()) {
3926             continue;
3927         }
3928 
3929         // Loop over the changes in this layer, and determine what parts of the
3930         // usd stage are affected by them.
3931         for (const auto& entryList : layerAndChangelist.second.GetEntryList()) {
3932 
3933             // This path is the path in the layer that was modified -- in
3934             // general it's not the same as a path to an object on a usd stage.
3935             // Instead, it's the path to the changed part of a layer, which may
3936             // affect zero or more objects on the usd stage, depending on
3937             // reference structures, active state, etc.  We have to map these
3938             // paths to those objects on the stage that are affected.
3939             const SdfPath &sdfPath = entryList.first;
3940             const SdfChangeList::Entry &entry = entryList.second;
3941 
3942             // Skip target paths entirely -- we do not create target objects in
3943             // USD.
3944             if (sdfPath.IsTargetPath())
3945                 continue;
3946 
3947             TF_DEBUG(USD_CHANGES).Msg(
3948                 "<%s> in @%s@ changed.\n",
3949                 sdfPath.GetText(),
3950                 layer->GetIdentifier().c_str());
3951 
3952             bool willRecompose = false;
3953             if (sdfPath == SdfPath::AbsoluteRootPath() ||
3954                 sdfPath.IsPrimOrPrimVariantSelectionPath()) {
3955 
3956                 bool didChangeActive = false;
3957                 for (const auto& info : entry.infoChanged) {
3958                     if (info.first == SdfFieldKeys->Active) {
3959                         TF_DEBUG(USD_CHANGES).Msg(
3960                             "Changed field: %s\n", info.first.GetText());
3961                         didChangeActive = true;
3962                         break;
3963                     }
3964                 }
3965 
3966                 if (didChangeActive || entry.flags.didReorderChildren) {
3967                     willRecompose = true;
3968                 } else {
3969                     for (const auto& info : entry.infoChanged) {
3970                         const auto& infoKey = info.first;
3971                         if (infoKey == SdfFieldKeys->Kind ||
3972                             infoKey == SdfFieldKeys->TypeName ||
3973                             infoKey == SdfFieldKeys->Specifier ||
3974                             infoKey == UsdTokens->apiSchemas ||
3975 
3976                             // XXX: Could be more specific when recomposing due
3977                             //      to clip changes. E.g., only update the clip
3978                             //      resolver and bits on each prim.
3979                             UsdIsClipRelatedField(infoKey) ||
3980                             // Fallback prim type changes may potentially only
3981                             // affect a small number or prims, but this type of
3982                             // change should be so rare that it's not really
3983                             // worth parsing the minimal set of prims to
3984                             // recompose.
3985                             _IsFallbackPrimTypesChange(layer, sdfPath, infoKey)) {
3986 
3987                             TF_DEBUG(USD_CHANGES).Msg(
3988                                 "Changed field: %s\n", infoKey.GetText());
3989 
3990                             willRecompose = true;
3991                             break;
3992                         }
3993                     }
3994                 }
3995 
3996                 if (willRecompose) {
3997                     _AddAffectedStagePaths(layer, sdfPath,
3998                                            *_cache, &recomposeChanges, &entry);
3999                 }
4000                 if (didChangeActive) {
4001                     _AddAffectedStagePaths(layer, sdfPath,
4002                                            *_cache, &changedActivePaths);
4003                 }
4004             }
4005             else {
4006                 willRecompose = sdfPath.IsPropertyPath() &&
4007                     (entry.flags.didAddPropertyWithOnlyRequiredFields ||
4008                      entry.flags.didAddProperty ||
4009                      entry.flags.didRemovePropertyWithOnlyRequiredFields ||
4010                      entry.flags.didRemoveProperty);
4011 
4012                 if (willRecompose) {
4013                     _AddAffectedStagePaths(
4014                         layer, sdfPath, *_cache, &otherResyncChanges, &entry);
4015                 }
4016             }
4017 
4018             // If we're not going to recompose this path, record the dependent
4019             // scene paths separately so we can notify clients about the
4020             // changes.
4021             if (!willRecompose) {
4022                 _AddAffectedStagePaths(layer, sdfPath,
4023                                   *_cache, &otherInfoChanges, &entry);
4024             }
4025         }
4026     }
4027 
4028     // Now we have collected the affected paths in UsdStage namespace in
4029     // recomposeChanges, otherResyncChanges, otherInfoChanges and
4030     // changedActivePaths.  Push changes through Pcp to determine further
4031     // invalidation based on composition metadata (reference, inherits, variant
4032     // selections, etc).
4033 
4034     PcpChanges& changes = _pendingChanges->pcpChanges;
4035     const PcpCache *cache = _cache.get();
4036     changes.DidChange(
4037         TfSpan<const PcpCache*>(&cache, 1), n.GetChangeListVec());
4038 
4039     // Pcp does not consider activation changes to be significant since
4040     // it doesn't look at activation during composition. However, UsdStage
4041     // needs to do so, since it elides children of deactivated prims.
4042     // This ensures that prim indexes for these prims are ejected from
4043     // the PcpCache.
4044     for (const SdfPath& p : changedActivePaths) {
4045         changes.DidChangeSignificantly(_cache.get(), p);
4046     }
4047 
4048     // Normally we'd call _ProcessPendingChanges only if _pendingChanges
4049     // pointed to localPendingChanges. If it didn't, it would mean that an
4050     // upstream caller initialized _pendingChanges and that caller would be
4051     // expected to call _ProcessPendingChanges itself.
4052     //
4053     // However, the _PathsToChangesMap objects in _pendingChanges may hold
4054     // raw pointers to entries stored in the notice, so we must process these
4055     // changes immediately while the notice is still alive.
4056     _ProcessPendingChanges();
4057 }
4058 
4059 void
_ProcessPendingChanges()4060 UsdStage::_ProcessPendingChanges()
4061 {
4062     if (!TF_VERIFY(_pendingChanges)) {
4063         return;
4064     }
4065 
4066     TF_DEBUG(USD_CHANGES).Msg(
4067         "\nProcessPendingChanges (%s)\n", UsdDescribe(this).c_str());
4068 
4069     PcpChanges& changes = _pendingChanges->pcpChanges;
4070 
4071     using _PathsToChangesMap = UsdNotice::ObjectsChanged::_PathsToChangesMap;
4072     _PathsToChangesMap& recomposeChanges = _pendingChanges->recomposeChanges;
4073     _PathsToChangesMap& otherResyncChanges=_pendingChanges->otherResyncChanges;
4074     _PathsToChangesMap& otherInfoChanges = _pendingChanges->otherInfoChanges;
4075 
4076     _Recompose(changes, &recomposeChanges);
4077 
4078     if (_pendingChanges->notifyPseudoRootResync) {
4079         recomposeChanges.clear();
4080         recomposeChanges[SdfPath::AbsoluteRootPath()];
4081 
4082         otherResyncChanges.clear();
4083         otherInfoChanges.clear();
4084     }
4085     else {
4086         // Filter out all changes to objects beneath instances and remap
4087         // them to the corresponding object in the instance's prototype. Do this
4088         // after _Recompose so that the instancing cache is up-to-date.
4089         auto remapChangesToPrototypes = [this](_PathsToChangesMap* changes) {
4090             std::vector<_PathsToChangesMap::value_type> prototypeChanges;
4091             for (auto it = changes->begin(); it != changes->end(); ) {
4092                 if (_IsObjectDescendantOfInstance(it->first)) {
4093                     const SdfPath primIndexPath =
4094                         it->first.GetAbsoluteRootOrPrimPath();
4095                     for (const SdfPath& pathInPrototype :
4096                          _instanceCache->GetPrimsInPrototypesUsingPrimIndexPath(
4097                              primIndexPath)) {
4098                         prototypeChanges.emplace_back(
4099                             it->first.ReplacePrefix(
4100                                 primIndexPath, pathInPrototype),
4101                             it->second);
4102                     }
4103                     it = changes->erase(it);
4104                     continue;
4105                 }
4106                 ++it;
4107             }
4108 
4109             for (const auto& entry : prototypeChanges) {
4110                 auto& value = (*changes)[entry.first];
4111                 value.insert(
4112                     value.end(), entry.second.begin(), entry.second.end());
4113             }
4114         };
4115 
4116         remapChangesToPrototypes(&recomposeChanges);
4117         remapChangesToPrototypes(&otherResyncChanges);
4118         remapChangesToPrototypes(&otherInfoChanges);
4119 
4120         // Add in all other paths that are marked as resynced.
4121         if (recomposeChanges.empty()) {
4122             recomposeChanges.swap(otherResyncChanges);
4123         }
4124         else {
4125             _RemoveDescendentEntries(&recomposeChanges);
4126             _MergeAndRemoveDescendentEntries(
4127                 &recomposeChanges, &otherResyncChanges);
4128             for (auto& entry : otherResyncChanges) {
4129                 recomposeChanges[entry.first] = std::move(entry.second);
4130             }
4131         }
4132 
4133         // Collect the paths in otherChangedPaths that aren't under paths that
4134         // were recomposed.  If the pseudo-root had been recomposed, we can
4135         // just clear out otherChangedPaths since everything was recomposed.
4136         if (!recomposeChanges.empty() &&
4137             recomposeChanges.begin()->first == SdfPath::AbsoluteRootPath()) {
4138             // If the pseudo-root is present, it should be the only path in the
4139             // changes.
4140             TF_VERIFY(recomposeChanges.size() == 1);
4141             otherInfoChanges.clear();
4142         }
4143 
4144         // Now we want to remove all elements of otherInfoChanges that are
4145         // prefixed by elements in recomposeChanges or beneath instances.
4146         _MergeAndRemoveDescendentEntries(&recomposeChanges, &otherInfoChanges);
4147     }
4148 
4149     // Reset _pendingChanges before sending notices so that any changes to
4150     // this stage that happen in response to the notices are handled
4151     // properly. The object that _pendingChanges referred to should remain
4152     // alive, so the references we took above are still valid.
4153     _pendingChanges = nullptr;
4154 
4155     if (!recomposeChanges.empty() || !otherInfoChanges.empty()) {
4156         UsdStageWeakPtr self(this);
4157 
4158         // Notify about changed objects.
4159         UsdNotice::ObjectsChanged(
4160             self, &recomposeChanges, &otherInfoChanges).Send(self);
4161 
4162         // Receivers can now refresh their caches... or just dirty them
4163         UsdNotice::StageContentsChanged(self).Send(self);
4164     }
4165 }
4166 
4167 void
_HandleResolverDidChange(const ArNotice::ResolverChanged & n)4168 UsdStage::_HandleResolverDidChange(
4169     const ArNotice::ResolverChanged& n)
4170 {
4171 #if AR_VERSION == 1
4172     return;
4173 #endif
4174 
4175     // A ResolverChanged notice that affects our resolver context means that
4176     // any asset paths that have been resolved on this stage may now resolve
4177     // to a different resolved path. This includes asset paths that were
4178     // resolved during composition and asset path-valued attributes.
4179     //
4180     // Handling this notice correctly must be done downstream of Sdf, since
4181     // asset paths have to be re-resolved under the contexts they were
4182     // originally resolved with. Sdf does not have the information needed to do
4183     // this, since it only tracks the context a layer was originally opened
4184     // with and not any other contexts.
4185     //
4186     // For example: let's say we have stage A that opens a layer with asset path
4187     // L, then we create stage B with a different context that also references
4188     // L. If L happens to resolve to the same file under B's context, then A and
4189     // B will share that layer.  However, at the Sdf level that layer only knows
4190     // about A's context since that's what it was opened under. If we get a
4191     // ResolverChanged notice that affects stage B, we need to re-resolve L
4192     // under stage B's context to determine if anything needs to change.
4193     if (!n.AffectsContext(GetPathResolverContext())) {
4194         return;
4195     }
4196 
4197     TF_DEBUG(USD_CHANGES).Msg(
4198         "\nHandleResolverDidChange received (%s)\n", UsdDescribe(this).c_str());
4199 
4200     // Merge stage changes computed in this function with other pending changes
4201     // or start up our own pending changes batch so we can process them at the
4202     // end of the function.
4203     _PendingChanges localPendingChanges;
4204     if (!_pendingChanges) {
4205         _pendingChanges = &localPendingChanges;
4206     }
4207 
4208     // Inform Pcp of the change to the resolver to determine prims that
4209     // may need to be resynced. Pcp will re-resolve asset paths for all prim
4210     // indexes to see if any now refer to a different resolved path and
4211     // indicate that resyncs are necessary for those prims.
4212     PcpChanges& changes = _pendingChanges->pcpChanges;
4213     changes.DidChangeAssetResolver(_GetPcpCache());
4214 
4215     // Asset-path valued attributes on this stage may be invalidated.
4216     // We don't want to incur the expense of scanning the entire stage
4217     // to see if any such attributes exist so we conservatively notify
4218     // clients that the pseudo-root has resynced, even though we may
4219     // only be recomposing a subset of the stage.
4220     _pendingChanges->notifyPseudoRootResync = true;
4221 
4222     // Process pending changes if we are the originators of the batch.
4223     if (_pendingChanges == &localPendingChanges) {
4224         _ProcessPendingChanges();
4225     }
4226 }
4227 
4228 void
_Recompose(const PcpChanges & changes)4229 UsdStage::_Recompose(const PcpChanges &changes)
4230 {
4231     using _PathsToChangesMap = UsdNotice::ObjectsChanged::_PathsToChangesMap;
4232     _Recompose(changes, (_PathsToChangesMap*)nullptr);
4233 }
4234 
4235 template <class T>
4236 void
_Recompose(const PcpChanges & changes,T * initialPathsToRecompose)4237 UsdStage::_Recompose(const PcpChanges &changes,
4238                      T *initialPathsToRecompose)
4239 {
4240     T newPathsToRecompose;
4241     T *pathsToRecompose = initialPathsToRecompose ?
4242         initialPathsToRecompose : &newPathsToRecompose;
4243 
4244     // Note: Calling changes.Apply() will result in recomputation of
4245     // pcpPrimIndexes for changed prims, these get updated on the respective
4246     // prims during _ComposeSubtreeImpl call. Using these outdated primIndexes
4247     // can result in undefined behavior
4248     changes.Apply();
4249 
4250     // Process layer stack changes.
4251     //
4252     // Pcp recomputes layer stacks immediately upon the call to
4253     // PcpChanges::Apply, which causes composition errors that occur
4254     // during this process to not be reported in _ComposePrimIndexesInParallel.
4255     // Walk through all modified layer stacks and report their errors here.
4256     const PcpChanges::LayerStackChanges &layerStackChanges =
4257         changes.GetLayerStackChanges();
4258 
4259     for (const auto& layerStackChange : layerStackChanges) {
4260         const PcpLayerStackPtr& layerStack = layerStackChange.first;
4261         const PcpErrorVector& errors = layerStack->GetLocalErrors();
4262         if (!errors.empty()) {
4263             _ReportPcpErrors(errors, "Recomposing stage");
4264         }
4265     }
4266 
4267     // Process composed prim changes.
4268     const PcpChanges::CacheChanges &cacheChanges = changes.GetCacheChanges();
4269     if (!cacheChanges.empty()) {
4270         const PcpCacheChanges &ourChanges = cacheChanges.begin()->second;
4271 
4272         for (const auto& path : ourChanges.didChangeSignificantly) {
4273             (*pathsToRecompose)[path];
4274             TF_DEBUG(USD_CHANGES).Msg("Did Change Significantly: %s\n",
4275                                       path.GetText());
4276         }
4277 
4278         for (const auto& path : ourChanges.didChangePrims) {
4279             (*pathsToRecompose)[path];
4280             TF_DEBUG(USD_CHANGES).Msg("Did Change Prim: %s\n", path.GetText());
4281         }
4282 
4283     } else {
4284         TF_DEBUG(USD_CHANGES).Msg("No cache changes\n");
4285     }
4286 
4287     _RecomposePrims(pathsToRecompose);
4288 
4289     // Update layer change notice listeners if changes may affect
4290     // the set of used layers. This is potentially expensive which is why we
4291     // try to make sure the changes require it.
4292     _RegisterPerLayerNotices();
4293 }
4294 
4295 template <class T>
4296 void
_RecomposePrims(T * pathsToRecompose)4297 UsdStage::_RecomposePrims(T *pathsToRecompose)
4298 {
4299     if (pathsToRecompose->empty()) {
4300         TF_DEBUG(USD_CHANGES).Msg("Nothing to recompose in cache changes\n");
4301         return;
4302     }
4303 
4304     // Prune descendant paths.
4305     _RemoveDescendentEntries(pathsToRecompose);
4306 
4307     // Invalidate the clip cache, but keep the clips alive for the duration
4308     // of recomposition in the (likely) case that clip data hasn't changed
4309     // and the underlying clip layer can be reused.
4310     Usd_ClipCache::Lifeboat clipLifeboat(*_clipCache);
4311     for (const auto& entry : *pathsToRecompose) {
4312         _clipCache->InvalidateClipsForPrim(entry.first);
4313     }
4314 
4315     // Ask Pcp to compute all the prim indexes in parallel, stopping at
4316     // stuff that's not active.
4317     SdfPathVector primPathsToRecompose;
4318     primPathsToRecompose.reserve(pathsToRecompose->size());
4319     for (const auto& entry : *pathsToRecompose) {
4320         const SdfPath& path = entry.first;
4321         if (!path.IsAbsoluteRootOrPrimPath() ||
4322             path.ContainsPrimVariantSelection()) {
4323             continue;
4324         }
4325 
4326         // Instance prims don't expose any name children, so we don't
4327         // need to recompose any prim index beneath instance prim
4328         // indexes *unless* they are being used as the source index
4329         // for a prototype.
4330         if (_instanceCache->IsPathDescendantToAnInstance(path)) {
4331             const bool primIndexUsedByPrototype =
4332                 _instanceCache->PrototypeUsesPrimIndexPath(path);
4333             if (!primIndexUsedByPrototype) {
4334                 TF_DEBUG(USD_CHANGES).Msg(
4335                     "Ignoring elided prim <%s>\n", path.GetText());
4336                 continue;
4337             }
4338         }
4339 
4340         // Unregister all instances beneath the given path. This
4341         // allows us to determine which instance prim indexes are
4342         // no longer present and make the appropriate instance
4343         // changes during prim index composition below.
4344         _instanceCache->UnregisterInstancePrimIndexesUnder(path);
4345 
4346         primPathsToRecompose.push_back(path);
4347     }
4348 
4349     ArResolverScopedCache resolverCache;
4350     Usd_InstanceChanges instanceChanges;
4351     _ComposePrimIndexesInParallel(
4352         primPathsToRecompose, "recomposing stage", &instanceChanges);
4353 
4354     // Determine what instance prototype prims on this stage need to
4355     // be recomposed due to instance prim index changes.
4356     typedef TfHashMap<SdfPath, SdfPath, SdfPath::Hash> _PrototypeToPrimIndexMap;
4357     _PrototypeToPrimIndexMap prototypeToPrimIndexMap;
4358 
4359     const bool pathsContainsAbsRoot =
4360         pathsToRecompose->begin()->first == SdfPath::AbsoluteRootPath();
4361 
4362     //If AbsoluteRootPath is present then that should be the only entry!
4363     TF_VERIFY(!pathsContainsAbsRoot || pathsToRecompose->size() == 1);
4364 
4365     const size_t origNumPathsToRecompose = pathsToRecompose->size();
4366     for (const auto& entry : *pathsToRecompose) {
4367         const SdfPath& path = entry.first;
4368         // Add corresponding inPrototypePaths for any instance or proxy paths in
4369         // pathsToRecompose
4370         for (const SdfPath& inPrototypePath :
4371                  _instanceCache->GetPrimsInPrototypesUsingPrimIndexPath(path)) {
4372             prototypeToPrimIndexMap[inPrototypePath] = path;
4373             (*pathsToRecompose)[inPrototypePath];
4374         }
4375         // Add any unchanged prototypes whose instances are descendents of paths
4376         // in pathsToRecompose
4377         for (const std::pair<SdfPath, SdfPath>& prototypeSourceIndexPair:
4378                 _instanceCache->GetPrototypesUsingPrimIndexPathOrDescendents(
4379                     path))
4380         {
4381             const SdfPath& prototypePath = prototypeSourceIndexPair.first;
4382             const SdfPath& sourceIndexPath = prototypeSourceIndexPair.second;
4383             prototypeToPrimIndexMap[prototypePath] = sourceIndexPath;
4384             (*pathsToRecompose)[prototypePath];
4385         }
4386     }
4387 
4388     // Add new prototypes paths to pathsToRecompose
4389     for (size_t i = 0; i != instanceChanges.newPrototypePrims.size(); ++i) {
4390         prototypeToPrimIndexMap[instanceChanges.newPrototypePrims[i]] =
4391             instanceChanges.newPrototypePrimIndexes[i];
4392         (*pathsToRecompose)[instanceChanges.newPrototypePrims[i]];
4393     }
4394 
4395     // Add changed prototypes paths to pathsToRecompose
4396     for (size_t i = 0; i != instanceChanges.changedPrototypePrims.size(); ++i) {
4397         prototypeToPrimIndexMap[instanceChanges.changedPrototypePrims[i]] =
4398             instanceChanges.changedPrototypePrimIndexes[i];
4399         (*pathsToRecompose)[instanceChanges.changedPrototypePrims[i]];
4400     }
4401 
4402     // If pseudoRoot is present in pathsToRecompose, then the only other prims
4403     // in pathsToRecompose can be prototype prims (added above), in which case
4404     // we do not want to remove these prototypes. If not we need to make sure
4405     // any descendents of prototypes are removed if corresponding prototype is
4406     // present
4407     if (!pathsContainsAbsRoot &&
4408             pathsToRecompose->size() != origNumPathsToRecompose) {
4409         _RemoveDescendentEntries(pathsToRecompose);
4410     }
4411 
4412     // XXX: If the call chain here ever starts composing prims in parallel,
4413     // we'll have to add a Usd_ClipCache::ConcurrentPopulationContext object
4414     // around this.
4415     std::vector<Usd_PrimDataPtr> subtreesToRecompose;
4416     _ComputeSubtreesToRecompose(
4417         make_transform_iterator(pathsToRecompose->begin(), TfGet<0>()),
4418         make_transform_iterator(pathsToRecompose->end(), TfGet<0>()),
4419         &subtreesToRecompose);
4420 
4421     // Recompose subtrees.
4422     if (prototypeToPrimIndexMap.empty()) {
4423         _ComposeSubtreesInParallel(subtreesToRecompose);
4424     }
4425     else {
4426 
4427         SdfPathVector primIndexPathsForSubtrees;
4428         primIndexPathsForSubtrees.reserve(subtreesToRecompose.size());
4429         for (const auto& prim : subtreesToRecompose) {
4430             primIndexPathsForSubtrees.push_back(TfMapLookupByValue(
4431                 prototypeToPrimIndexMap, prim->GetPath(), prim->GetPath()));
4432         }
4433         _ComposeSubtreesInParallel(
4434             subtreesToRecompose, &primIndexPathsForSubtrees);
4435     }
4436 
4437     // Destroy dead prototype subtrees, making sure to record them in
4438     // paths to recompose for notifications.
4439     for (const SdfPath& p : instanceChanges.deadPrototypePrims) {
4440         (*pathsToRecompose)[p];
4441     }
4442     _DestroyPrimsInParallel(instanceChanges.deadPrototypePrims);
4443 }
4444 
4445 
4446 template <class Iter>
4447 void
_ComputeSubtreesToRecompose(Iter i,Iter end,std::vector<Usd_PrimDataPtr> * subtreesToRecompose)4448 UsdStage::_ComputeSubtreesToRecompose(
4449     Iter i, Iter end,
4450     std::vector<Usd_PrimDataPtr>* subtreesToRecompose)
4451 {
4452     // XXX: If this function ever winds up composing prims in parallel, callers
4453     // will have to ensure that a Usd_ClipCache::ConcurrentPopulationContext
4454     // object is alive during the call.
4455 
4456     subtreesToRecompose->reserve(
4457         subtreesToRecompose->size() + std::distance(i, end));
4458 
4459     while (i != end) {
4460         TF_DEBUG(USD_CHANGES).Msg("Recomposing: %s\n", i->GetText());
4461         // TODO: refactor into shared method
4462         // We only care about recomposing prim-like things
4463         // so avoid recomposing anything else.
4464         if (!i->IsAbsoluteRootOrPrimPath() ||
4465             i->ContainsPrimVariantSelection()) {
4466             TF_DEBUG(USD_CHANGES).Msg("Skipping non-prim: %s\n",
4467                                       i->GetText());
4468             ++i;
4469             continue;
4470         }
4471 
4472         // Add prototypes to list of subtrees to recompose and instantiate any
4473         // new prototype not present in the primMap from before
4474         if (_instanceCache->IsPrototypePath(*i)) {
4475             PathToNodeMap::const_iterator itr = _primMap.find(*i);
4476             Usd_PrimDataPtr prototypePrim;
4477             if (itr != _primMap.end()) {
4478                 // should be a changed prototype if already in the primMap
4479                 prototypePrim = itr->second.get();
4480             } else {
4481                 // newPrototype should be absent from the primMap, instantiate
4482                 // these now to be added to subtreesToRecompose
4483                 prototypePrim = _InstantiatePrototypePrim(*i);
4484             }
4485             subtreesToRecompose->push_back(prototypePrim);
4486             ++i;
4487             continue;
4488         }
4489 
4490         // Collect all non-prototype prims (including descendants of prototypes)
4491         // to be added to subtreesToRecompute
4492         SdfPath const &parentPath = i->GetParentPath();
4493         PathToNodeMap::const_iterator parentIt = _primMap.find(parentPath);
4494         if (parentIt != _primMap.end()) {
4495 
4496             // Since our input range contains no descendant paths, siblings
4497             // must appear consecutively.  We want to process all siblings that
4498             // have changed together in order to only recompose the parent's
4499             // list of children once.  We scan forward while the paths share a
4500             // parent to find the range of siblings.
4501 
4502             // Recompose parent's list of children.
4503             auto parent = parentIt->second.get();
4504             _ComposeChildren(
4505                 parent, parent->IsInPrototype() ? nullptr : &_populationMask,
4506                 /*recurse=*/false);
4507 
4508             // Recompose the subtree for each affected sibling.
4509             do {
4510                 PathToNodeMap::const_iterator primIt = _primMap.find(*i);
4511                 if (primIt != _primMap.end()) {
4512                     subtreesToRecompose->push_back(primIt->second.get());
4513                 } else if (_instanceCache->IsPrototypePath(*i)) {
4514                     // If this path is a prototype path and is not present in
4515                     // the primMap, then this must be a new prototype added
4516                     // during this processing, instantiate and add it.
4517                     Usd_PrimDataPtr protoPrim = _InstantiatePrototypePrim(*i);
4518                     subtreesToRecompose->push_back(protoPrim);
4519                 }
4520                 ++i;
4521             } while (i != end && i->GetParentPath() == parentPath);
4522         } else if (parentPath.IsEmpty()) {
4523             // This is the pseudo root, so we need to blow and rebuild
4524             // everything.
4525             subtreesToRecompose->push_back(_pseudoRoot);
4526             ++i;
4527         } else {
4528             ++i;
4529         }
4530     }
4531 }
4532 
4533 struct UsdStage::_IncludePayloadsPredicate
4534 {
_IncludePayloadsPredicateUsdStage::_IncludePayloadsPredicate4535     explicit _IncludePayloadsPredicate(UsdStage const *stage)
4536         : _stage(stage) {}
4537 
operator ()UsdStage::_IncludePayloadsPredicate4538     bool operator()(SdfPath const &primIndexPath) const {
4539         // Apply the stage's load rules to this primIndexPath.  This works
4540         // correctly with instancing, because load rules are included in
4541         // instancing keys.
4542         return _stage->_loadRules.IsLoaded(primIndexPath);
4543     }
4544 
4545     UsdStage const *_stage;
4546 };
4547 
4548 void
_ComposePrimIndexesInParallel(const std::vector<SdfPath> & primIndexPaths,const std::string & context,Usd_InstanceChanges * instanceChanges)4549 UsdStage::_ComposePrimIndexesInParallel(
4550     const std::vector<SdfPath>& primIndexPaths,
4551     const std::string& context,
4552     Usd_InstanceChanges* instanceChanges)
4553 {
4554     if (TfDebug::IsEnabled(USD_COMPOSITION)) {
4555         // Ensure not too much spew if primIndexPaths is big.
4556         constexpr size_t maxPaths = 16;
4557         std::vector<SdfPath> dbgPaths(
4558             primIndexPaths.begin(),
4559             primIndexPaths.begin() + std::min(maxPaths, primIndexPaths.size()));
4560         string msg = TfStringPrintf(
4561             "Composing prim indexes: %s%s\n",
4562             TfStringify(dbgPaths).c_str(), primIndexPaths.size() > maxPaths ?
4563             TfStringPrintf(
4564                 " (and %zu more)", primIndexPaths.size() - maxPaths).c_str() :
4565             "");
4566         TF_DEBUG(USD_COMPOSITION).Msg("%s", msg.c_str());
4567     }
4568 
4569     // We only want to compute prim indexes included by the stage's
4570     // population mask. As an optimization, if all prims are included the
4571     // name children predicate doesn't need to consider the mask at all.
4572     static auto allMask = UsdStagePopulationMask::All();
4573     const UsdStagePopulationMask* mask =
4574         _populationMask == allMask ? nullptr : &_populationMask;
4575 
4576     // Ask Pcp to compute all the prim indexes in parallel, stopping at
4577     // prim indexes that won't be used by the stage.
4578     PcpErrorVector errs;
4579 
4580     _cache->ComputePrimIndexesInParallel(
4581         primIndexPaths, &errs,
4582         _NameChildrenPred(mask, &_loadRules, _instanceCache.get()),
4583         _IncludePayloadsPredicate(this),
4584         "Usd", _mallocTagID);
4585 
4586     if (!errs.empty()) {
4587         _ReportPcpErrors(errs, context);
4588     }
4589 
4590     // Process instancing changes due to new or changed instanceable
4591     // prim indexes discovered during composition.
4592     Usd_InstanceChanges changes;
4593     _instanceCache->ProcessChanges(&changes);
4594 
4595     if (instanceChanges) {
4596         instanceChanges->AppendChanges(changes);
4597     }
4598 
4599     // After processing changes, we may discover that some prototype prims
4600     // need to change their source prim index. This may be because their
4601     // previous source prim index was destroyed or was no longer an
4602     // instance. Compose the new source prim indexes.
4603     if (!changes.changedPrototypePrims.empty()) {
4604         _ComposePrimIndexesInParallel(
4605             changes.changedPrototypePrimIndexes, context, instanceChanges);
4606     }
4607 }
4608 
4609 void
_RegisterPerLayerNotices()4610 UsdStage::_RegisterPerLayerNotices()
4611 {
4612     // The goal is to update _layersAndNoticeKeys so it reflects the current
4613     // cache's set of used layers (from GetUsedLayers()).  We want to avoid
4614     // thrashing the TfNotice registrations since we expect that usually only a
4615     // relatively small subset of used layers will change, if any.
4616     //
4617     // We walk both the current _layersAndNoticeKeys and the cache's
4618     // GetUsedLayers, and incrementally update, TfNotice::Revoke()ing any layers
4619     // we no longer use, TfNotice::Register()ing for new layers we didn't use
4620     // previously, and leaving alone those layers that remain.  The linear walk
4621     // works because the PcpCache::GetUsedLayers() returns a std::set, so we
4622     // always retain things in a stable order.
4623 
4624     // Check to see if the set of used layers hasn't changed, and skip all this
4625     // if so.
4626     size_t currentUsedLayersRevision = _cache->GetUsedLayersRevision();
4627     if (_usedLayersRevision &&
4628         _usedLayersRevision == currentUsedLayersRevision) {
4629         return;
4630     }
4631 
4632     SdfLayerHandleSet usedLayers = _cache->GetUsedLayers();
4633     _usedLayersRevision = currentUsedLayersRevision;
4634 
4635     SdfLayerHandleSet::const_iterator
4636         usedLayersIter = usedLayers.begin(),
4637         usedLayersEnd = usedLayers.end();
4638 
4639     _LayerAndNoticeKeyVec::iterator
4640         layerAndKeyIter = _layersAndNoticeKeys.begin(),
4641         layerAndKeyEnd = _layersAndNoticeKeys.end();
4642 
4643     // We'll build a new vector and swap it into place at the end.  We can
4644     // preallocate space upfront since we know the resulting size will be
4645     // exactly the size of usedLayers.
4646     _LayerAndNoticeKeyVec newLayersAndNoticeKeys;
4647     newLayersAndNoticeKeys.reserve(usedLayers.size());
4648 
4649     UsdStagePtr self(this);
4650 
4651     while (usedLayersIter != usedLayersEnd ||
4652            layerAndKeyIter != layerAndKeyEnd) {
4653 
4654         // There are three cases to consider: a newly added layer, a layer no
4655         // longer used, or a layer that we used before and continue to use.
4656         if (layerAndKeyIter == layerAndKeyEnd ||
4657             (usedLayersIter != usedLayersEnd  &&
4658              *usedLayersIter < layerAndKeyIter->first)) {
4659             // This is a newly added layer.  Register for the notice and add it.
4660             newLayersAndNoticeKeys.push_back(
4661                 make_pair(*usedLayersIter,
4662                           TfNotice::Register(
4663                               self, &UsdStage::_HandleLayersDidChange,
4664                               *usedLayersIter)));
4665             ++usedLayersIter;
4666         } else if (usedLayersIter == usedLayersEnd    ||
4667                    (layerAndKeyIter != layerAndKeyEnd &&
4668                     layerAndKeyIter->first < *usedLayersIter)) {
4669             // This is a layer we no longer use, unregister and skip over.
4670             TfNotice::Revoke(layerAndKeyIter->second);
4671             ++layerAndKeyIter;
4672         } else {
4673             // This is a layer we had before and still have, just copy it over.
4674             newLayersAndNoticeKeys.push_back(*layerAndKeyIter);
4675             ++layerAndKeyIter, ++usedLayersIter;
4676         }
4677     }
4678 
4679     // Swap new set into place.
4680     _layersAndNoticeKeys.swap(newLayersAndNoticeKeys);
4681 }
4682 
4683 void
_RegisterResolverChangeNotice()4684 UsdStage::_RegisterResolverChangeNotice()
4685 {
4686     _resolverChangeKey = TfNotice::Register(
4687         TfCreateWeakPtr(this), &UsdStage::_HandleResolverDidChange);
4688 }
4689 
4690 SdfPrimSpecHandle
_GetPrimSpec(const SdfPath & path)4691 UsdStage::_GetPrimSpec(const SdfPath& path)
4692 {
4693     return GetEditTarget().GetPrimSpecForScenePath(path);
4694 }
4695 
4696 SdfSpecType
_GetDefiningSpecType(Usd_PrimDataConstPtr primData,const TfToken & propName) const4697 UsdStage::_GetDefiningSpecType(Usd_PrimDataConstPtr primData,
4698                                const TfToken& propName) const
4699 {
4700     if (!TF_VERIFY(primData) || !TF_VERIFY(!propName.IsEmpty()))
4701         return SdfSpecTypeUnknown;
4702 
4703     // Check for a spec type in the definition registry, in case this is a
4704     // builtin property.
4705     const UsdPrimDefinition &primDef = primData->GetPrimDefinition();
4706     SdfSpecType specType = primDef.GetSpecType(propName);
4707     if (specType != SdfSpecTypeUnknown)
4708         return specType;
4709 
4710     // Otherwise look for the strongest authored property spec.
4711     Usd_Resolver res(&primData->GetPrimIndex(), /*skipEmptyNodes=*/true);
4712     SdfPath curPath;
4713     bool curPathValid = false;
4714     while (res.IsValid()) {
4715         const SdfLayerRefPtr& layer = res.GetLayer();
4716         if (layer->HasSpec(res.GetLocalPath())) {
4717             if (!curPathValid) {
4718                 curPath = res.GetLocalPath().AppendProperty(propName);
4719                 curPathValid = true;
4720             }
4721             specType = layer->GetSpecType(curPath);
4722             if (specType != SdfSpecTypeUnknown)
4723                 return specType;
4724         }
4725         if (res.NextLayer())
4726             curPathValid = false;
4727     }
4728 
4729     // Unknown.
4730     return SdfSpecTypeUnknown;
4731 }
4732 
4733 // ------------------------------------------------------------------------- //
4734 // Flatten & Export Utilities
4735 // ------------------------------------------------------------------------- //
4736 
4737 class Usd_FlattenAccess
4738 {
4739 public:
4740 
GetAllMetadataForFlatten(const UsdObject & obj,UsdMetadataValueMap * resultMap)4741     static void GetAllMetadataForFlatten(
4742         const UsdObject &obj, UsdMetadataValueMap* resultMap)
4743     {
4744         // Get the resolved metadata with any asset paths anchored.
4745         obj.GetStage()->_GetAllMetadata(
4746             obj, /* useFallbacks = */ false, resultMap,
4747             /* anchorAssetPathsOnly = */ true);
4748     }
4749 
ResolveValueForFlatten(UsdTimeCode time,const UsdAttribute & attr,const SdfLayerOffset & timeOffset,VtValue * value)4750     static void ResolveValueForFlatten(
4751         UsdTimeCode time, const UsdAttribute& attr,
4752         const SdfLayerOffset &timeOffset, VtValue* value)
4753     {
4754         // Asset path values are anchored for flatten operations
4755         attr.GetStage()->_MakeResolvedAssetPathsValue(
4756             time, attr, value, /* anchorAssetPathsOnly = */ true);
4757         // Time based values are adjusted by layer offset when flattened to a
4758         // layer affected by an offset.
4759         if (!timeOffset.IsIdentity()) {
4760             Usd_ApplyLayerOffsetToValue(value, timeOffset);
4761         }
4762 
4763     }
4764 
MakeTimeSampleMapForFlatten(const UsdAttribute & attr,const SdfLayerOffset & offset,SdfTimeSampleMap * out)4765     static bool MakeTimeSampleMapForFlatten(
4766         const UsdAttribute &attr, const SdfLayerOffset& offset,
4767         SdfTimeSampleMap *out)
4768     {
4769         UsdAttributeQuery attrQuery(attr);
4770 
4771         std::vector<double> timeSamples;
4772         if (attrQuery.GetTimeSamples(&timeSamples)) {
4773             for (const auto& timeSample : timeSamples) {
4774                 VtValue value;
4775                 if (attrQuery.Get(&value, timeSample)) {
4776                     Usd_FlattenAccess::ResolveValueForFlatten(
4777                         timeSample, attr, offset, &value);
4778                     (*out)[offset * timeSample].Swap(value);
4779                 }
4780                 else {
4781                     (*out)[offset * timeSample] = VtValue(SdfValueBlock());
4782                 }
4783             }
4784             return true;
4785         }
4786         return false;
4787     }
4788 
4789 };
4790 
4791 namespace {
4792 
4793 // Map from path to replacement for remapping target paths during flattening.
4794 using _PathRemapping = std::map<SdfPath, SdfPath>;
4795 
4796 // Apply path remappings to a list of target paths.
4797 void
_RemapTargetPaths(SdfPathVector * targetPaths,const _PathRemapping & pathRemapping)4798 _RemapTargetPaths(SdfPathVector* targetPaths,
4799                   const _PathRemapping& pathRemapping)
4800 {
4801     if (pathRemapping.empty()) {
4802         return;
4803     }
4804 
4805     for (SdfPath& p : *targetPaths) {
4806         auto it = SdfPathFindLongestPrefix(pathRemapping, p);
4807         if (it != pathRemapping.end()) {
4808             p = p.ReplacePrefix(it->first, it->second);
4809         }
4810     }
4811 }
4812 
4813 // Remove any paths to prototype prims or descendants from given target paths
4814 // for srcProp. Issues a warning if any paths were removed.
4815 void
_RemovePrototypeTargetPaths(const UsdProperty & srcProp,SdfPathVector * targetPaths)4816 _RemovePrototypeTargetPaths(const UsdProperty& srcProp,
4817                          SdfPathVector* targetPaths)
4818 {
4819     auto removeIt = std::remove_if(
4820         targetPaths->begin(), targetPaths->end(),
4821         Usd_InstanceCache::IsPathInPrototype);
4822     if (removeIt == targetPaths->end()) {
4823         return;
4824     }
4825 
4826     TF_WARN(
4827         "Some %s paths from <%s> could not be flattened because "
4828         "they targeted objects within an instancing prototype.",
4829         srcProp.Is<UsdAttribute>() ?
4830             "attribute connection" : "relationship target",
4831         srcProp.GetPath().GetText());
4832 
4833     targetPaths->erase(removeIt, targetPaths->end());
4834 }
4835 
4836 // We want to give generated prototypes in the flattened stage
4837 // reserved(using '__' as a prefix), unclashing paths, however,
4838 // we don't want to use the '__Prototype' paths which have special
4839 // meaning to UsdStage. So we create a mapping between our generated
4840 // 'Flattened_Prototype'-style paths and the '__Prototype' paths.
4841 _PathRemapping
_GenerateFlattenedPrototypePath(const std::vector<UsdPrim> & prototypes)4842 _GenerateFlattenedPrototypePath(const std::vector<UsdPrim>& prototypes)
4843 {
4844     size_t primPrototypeId = 1;
4845 
4846     const auto generatePathName = [&primPrototypeId]() {
4847         return SdfPath(TfStringPrintf("/Flattened_Prototype_%lu",
4848                                       primPrototypeId++));
4849     };
4850 
4851     _PathRemapping prototypeToFlattened;
4852 
4853     for (auto const& prototypePrim : prototypes) {
4854         SdfPath flattenedPrototypePath;
4855         const auto prototypePrimPath = prototypePrim.GetPath();
4856 
4857         auto prototypePathLookup = prototypeToFlattened.find(prototypePrimPath);
4858         if (prototypePathLookup == prototypeToFlattened.end()) {
4859             // We want to ensure that we don't clash with user
4860             // prims in the unlikely even they named it Flatten_xxx
4861             flattenedPrototypePath = generatePathName();
4862             const auto stage = prototypePrim.GetStage();
4863             while (stage->GetPrimAtPath(flattenedPrototypePath)) {
4864                 flattenedPrototypePath = generatePathName();
4865             }
4866             prototypeToFlattened.emplace(
4867                 prototypePrimPath, flattenedPrototypePath);
4868         } else {
4869             flattenedPrototypePath = prototypePathLookup->second;
4870         }
4871     }
4872 
4873     return prototypeToFlattened;
4874 }
4875 
4876 void
_CopyMetadata(const SdfSpecHandle & dest,const UsdMetadataValueMap & metadata)4877 _CopyMetadata(const SdfSpecHandle& dest, const UsdMetadataValueMap& metadata)
4878 {
4879     // Copy each key/value into the Sdf spec.
4880     TfErrorMark m;
4881     vector<string> msgs;
4882     for (auto const& tokVal : metadata) {
4883         dest->SetInfo(tokVal.first, tokVal.second);
4884         if (!m.IsClean()) {
4885             msgs.clear();
4886             for (auto i = m.GetBegin(); i != m.GetEnd(); ++i) {
4887                 msgs.push_back(i->GetCommentary());
4888             }
4889             m.Clear();
4890             TF_WARN("Failed copying metadata: %s", TfStringJoin(msgs).c_str());
4891         }
4892     }
4893 }
4894 
4895 void
_CopyAuthoredMetadata(const UsdObject & source,const SdfSpecHandle & dest)4896 _CopyAuthoredMetadata(const UsdObject &source, const SdfSpecHandle& dest)
4897 {
4898     // GetAllMetadata returns all non-private metadata fields (it excludes
4899     // composition arcs and values), which is exactly what we want here.
4900     UsdMetadataValueMap metadata;
4901     Usd_FlattenAccess::GetAllMetadataForFlatten(source, &metadata);
4902 
4903     _CopyMetadata(dest, metadata);
4904 }
4905 
4906 void
_CopyProperty(const UsdProperty & prop,const SdfPrimSpecHandle & dest,const TfToken & destName,const _PathRemapping & pathRemapping,const SdfLayerOffset & timeOffset)4907 _CopyProperty(const UsdProperty &prop,
4908               const SdfPrimSpecHandle &dest, const TfToken &destName,
4909               const _PathRemapping &pathRemapping,
4910               const SdfLayerOffset &timeOffset)
4911 {
4912     if (prop.Is<UsdAttribute>()) {
4913         UsdAttribute attr = prop.As<UsdAttribute>();
4914 
4915         if (!attr.GetTypeName()){
4916             TF_WARN("Attribute <%s> has unknown value type. "
4917                     "It will be omitted from the flattened result.",
4918                     attr.GetPath().GetText());
4919             return;
4920         }
4921 
4922         SdfAttributeSpecHandle sdfAttr = dest->GetAttributes()[destName];
4923         if (!sdfAttr) {
4924             sdfAttr = SdfAttributeSpec::New(dest, destName, attr.GetTypeName());
4925         }
4926 
4927         _CopyAuthoredMetadata(attr, sdfAttr);
4928 
4929         // Copy the default & time samples, if present. We get the
4930         // correct timeSamples/default value resolution here because
4931         // GetBracketingTimeSamples sets hasSamples=false when the
4932         // default value is stronger.
4933 
4934         double lower = 0.0, upper = 0.0;
4935         bool hasSamples = false;
4936         if (attr.GetBracketingTimeSamples(
4937             0.0, &lower, &upper, &hasSamples) && hasSamples) {
4938             SdfTimeSampleMap ts;
4939             if (Usd_FlattenAccess::MakeTimeSampleMapForFlatten(
4940                     attr, timeOffset, &ts)) {
4941                 sdfAttr->SetInfo(SdfFieldKeys->TimeSamples, VtValue::Take(ts));
4942             }
4943         }
4944         if (attr.HasAuthoredMetadata(SdfFieldKeys->Default)) {
4945             VtValue defaultValue;
4946             if (attr.Get(&defaultValue)) {
4947                 Usd_FlattenAccess::ResolveValueForFlatten(
4948                     UsdTimeCode::Default(), attr, timeOffset, &defaultValue);
4949             }
4950             else {
4951                 defaultValue = SdfValueBlock();
4952             }
4953             sdfAttr->SetInfo(SdfFieldKeys->Default, defaultValue);
4954         }
4955         SdfPathVector sources;
4956         attr.GetConnections(&sources);
4957         if (!sources.empty()) {
4958             _RemapTargetPaths(&sources, pathRemapping);
4959             _RemovePrototypeTargetPaths(prop, &sources);
4960             sdfAttr->GetConnectionPathList().GetExplicitItems() = sources;
4961         }
4962      }
4963      else if (prop.Is<UsdRelationship>()) {
4964          UsdRelationship rel = prop.As<UsdRelationship>();
4965          // NOTE: custom = true by default for relationship, but the
4966          // SdfSchema fallback is false, so we must set it explicitly
4967          // here. The situation is similar for variability.
4968          SdfRelationshipSpecHandle sdfRel = dest->GetRelationships()[destName];
4969          if (!sdfRel){
4970              sdfRel = SdfRelationshipSpec::New(
4971                  dest, destName, /*custom*/ false, SdfVariabilityVarying);
4972          }
4973 
4974          _CopyAuthoredMetadata(rel, sdfRel);
4975 
4976          SdfPathVector targets;
4977          rel.GetTargets(&targets);
4978          if (!targets.empty()) {
4979              _RemapTargetPaths(&targets, pathRemapping);
4980              _RemovePrototypeTargetPaths(prop, &targets);
4981              sdfRel->GetTargetPathList().GetExplicitItems() = targets;
4982          }
4983      }
4984 }
4985 
4986 void
_CopyPrim(const UsdPrim & usdPrim,const SdfLayerHandle & layer,const SdfPath & path,const _PathRemapping & prototypeToFlattened)4987 _CopyPrim(const UsdPrim &usdPrim,
4988           const SdfLayerHandle &layer, const SdfPath &path,
4989           const _PathRemapping &prototypeToFlattened)
4990 {
4991     SdfPrimSpecHandle newPrim;
4992 
4993     if (!usdPrim.IsActive()) {
4994         return;
4995     }
4996 
4997     if (usdPrim.GetPath() == SdfPath::AbsoluteRootPath()) {
4998         newPrim = layer->GetPseudoRoot();
4999     } else {
5000         // Note that the true value for spec will be populated in _CopyMetadata
5001         newPrim = SdfPrimSpec::New(layer->GetPrimAtPath(path.GetParentPath()),
5002                                    path.GetName(), SdfSpecifierOver,
5003                                    usdPrim.GetTypeName());
5004     }
5005 
5006     if (usdPrim.IsInstance()) {
5007         const auto flattenedPrototypePath =
5008             prototypeToFlattened.at(usdPrim.GetPrototype().GetPath());
5009 
5010         // Author an internal reference to our flattened prototype prim
5011         newPrim->GetReferenceList().Add(SdfReference(std::string(),
5012                                         flattenedPrototypePath));
5013     }
5014 
5015     _CopyAuthoredMetadata(usdPrim, newPrim);
5016 
5017     // In the case of flattening clips, we may have builtin attributes which
5018     // aren't declared in the static scene topology, but may have a value
5019     // in some clips that we want to relay into the flattened result.
5020     // XXX: This should be removed if we fix GetProperties()
5021     // and GetAuthoredProperties to consider clips.
5022     auto hasValue = [](const UsdProperty& prop){
5023         return prop.Is<UsdAttribute>()
5024                && prop.As<UsdAttribute>().HasAuthoredValue();
5025     };
5026 
5027     for (auto const &prop : usdPrim.GetProperties()) {
5028         if (prop.IsAuthored() || hasValue(prop)) {
5029             _CopyProperty(prop, newPrim, prop.GetName(), prototypeToFlattened,
5030                           SdfLayerOffset());
5031         }
5032     }
5033 }
5034 
5035 void
_CopyPrototypePrim(const UsdPrim & prototypePrim,const SdfLayerHandle & destinationLayer,const _PathRemapping & prototypeToFlattened)5036 _CopyPrototypePrim(const UsdPrim &prototypePrim,
5037                    const SdfLayerHandle &destinationLayer,
5038                    const _PathRemapping &prototypeToFlattened)
5039 {
5040     const auto& flattenedPrototypePath
5041         = prototypeToFlattened.at(prototypePrim.GetPath());
5042 
5043     for (UsdPrim child: UsdPrimRange::AllPrims(prototypePrim)) {
5044         // We need to update the child path to use the Flatten name.
5045         const auto flattenedChildPath = child.GetPath().ReplacePrefix(
5046             prototypePrim.GetPath(), flattenedPrototypePath);
5047 
5048         _CopyPrim(child, destinationLayer, flattenedChildPath,
5049                   prototypeToFlattened);
5050     }
5051 }
5052 
5053 bool
_IsPrivateFallbackFieldKey(const TfToken & fieldKey)5054 _IsPrivateFallbackFieldKey(const TfToken& fieldKey)
5055 {
5056     // Consider documentation and comment fallbacks as private; these are
5057     // primarily for schema authors and are not expected to be authored
5058     // in flattened results.
5059     if (fieldKey == SdfFieldKeys->Documentation ||
5060         fieldKey == SdfFieldKeys->Comment) {
5061         return true;
5062     }
5063 
5064     // Consider default value fallback as non-private, since we do write out
5065     // default values during flattening.
5066     if (fieldKey == SdfFieldKeys->Default) {
5067         return false;
5068     }
5069 
5070     return _IsPrivateFieldKey(fieldKey);
5071 }
5072 
5073 bool
_HasAuthoredValue(const TfToken & fieldKey,const SdfPropertySpecHandleVector & propStack)5074 _HasAuthoredValue(const TfToken& fieldKey,
5075                   const SdfPropertySpecHandleVector& propStack)
5076 {
5077     return std::any_of(
5078         propStack.begin(), propStack.end(),
5079         [&fieldKey](const SdfPropertySpecHandle& spec) {
5080             return spec->HasInfo(fieldKey);
5081         });
5082 }
5083 
5084 void
_CopyFallbacks(const SdfPropertySpecHandle & srcPropDef,const SdfPropertySpecHandle & dstPropDef,const SdfPropertySpecHandle & dstPropSpec,const SdfPropertySpecHandleVector & dstPropStack)5085 _CopyFallbacks(const SdfPropertySpecHandle &srcPropDef,
5086                const SdfPropertySpecHandle &dstPropDef,
5087                const SdfPropertySpecHandle &dstPropSpec,
5088                const SdfPropertySpecHandleVector &dstPropStack)
5089 {
5090     if (!srcPropDef) {
5091         return;
5092     }
5093 
5094     std::vector<TfToken> fallbackFields = srcPropDef->ListFields();
5095     fallbackFields.erase(
5096         std::remove_if(fallbackFields.begin(), fallbackFields.end(),
5097                        _IsPrivateFallbackFieldKey),
5098         fallbackFields.end());
5099 
5100     UsdMetadataValueMap fallbacks;
5101     for (const auto& fieldName : fallbackFields) {
5102         // If the property spec already has a value for this field,
5103         // don't overwrite it with the fallback.
5104         if (dstPropSpec->HasField(fieldName)) {
5105             continue;
5106         }
5107 
5108         // If we're flattening over a builtin property and the
5109         // fallback for that property matches the source fallback
5110         // and there isn't an authored value that's overriding that
5111         // fallback, we don't need to write the fallback.
5112         VtValue fallbackVal = srcPropDef->GetField(fieldName);
5113         if (dstPropDef && dstPropDef->GetField(fieldName) == fallbackVal &&
5114             !_HasAuthoredValue(fieldName, dstPropStack)) {
5115                 continue;
5116         }
5117 
5118         fallbacks[fieldName].Swap(fallbackVal);
5119     }
5120 
5121     _CopyMetadata(dstPropSpec, fallbacks);
5122 }
5123 
5124 } // end anonymous namespace
5125 
5126 bool
ExportToString(std::string * result,bool addSourceFileComment) const5127 UsdStage::ExportToString(std::string *result, bool addSourceFileComment) const
5128 {
5129     SdfLayerRefPtr flatLayer = Flatten(addSourceFileComment);
5130     return flatLayer->ExportToString(result);
5131 }
5132 
5133 bool
Export(const std::string & newFileName,bool addSourceFileComment,const SdfLayer::FileFormatArguments & args) const5134 UsdStage::Export(const std::string & newFileName, bool addSourceFileComment,
5135                  const SdfLayer::FileFormatArguments &args) const
5136 {
5137     SdfLayerRefPtr flatLayer = Flatten(addSourceFileComment);
5138     return flatLayer->Export(newFileName, /* comment = */ std::string(), args);
5139 }
5140 
5141 SdfLayerRefPtr
Flatten(bool addSourceFileComment) const5142 UsdStage::Flatten(bool addSourceFileComment) const
5143 {
5144     TRACE_FUNCTION();
5145 
5146     SdfLayerHandle rootLayer = GetRootLayer();
5147     SdfLayerRefPtr flatLayer = SdfLayer::CreateAnonymous(".usda");
5148 
5149     if (!TF_VERIFY(rootLayer)) {
5150         return TfNullPtr;
5151     }
5152 
5153     if (!TF_VERIFY(flatLayer)) {
5154         return TfNullPtr;
5155     }
5156 
5157     // Preemptively populate our mapping. This allows us to populate
5158     // nested instances in the destination layer much more simply.
5159     const auto prototypeToFlattened =
5160         _GenerateFlattenedPrototypePath(GetPrototypes());
5161 
5162     // We author the prototype overs first to produce simpler
5163     // assets which have them grouped at the top of the file.
5164     for (auto const& prototype : GetPrototypes()) {
5165         _CopyPrototypePrim(prototype, flatLayer, prototypeToFlattened);
5166     }
5167 
5168     for (UsdPrim prim: UsdPrimRange::AllPrims(GetPseudoRoot())) {
5169         _CopyPrim(prim, flatLayer, prim.GetPath(), prototypeToFlattened);
5170     }
5171 
5172     if (addSourceFileComment) {
5173         std::string doc = flatLayer->GetDocumentation();
5174 
5175         if (!doc.empty()) {
5176             doc.append("\n\n");
5177         }
5178 
5179         doc.append(TfStringPrintf("Generated from Composed Stage "
5180                                   "of root layer %s\n",
5181                                   GetRootLayer()->GetRealPath().c_str()));
5182 
5183         flatLayer->SetDocumentation(doc);
5184     }
5185 
5186     return flatLayer;
5187 }
5188 
5189 UsdProperty
_FlattenProperty(const UsdProperty & srcProp,const UsdPrim & dstParent,const TfToken & dstName)5190 UsdStage::_FlattenProperty(const UsdProperty &srcProp,
5191                            const UsdPrim &dstParent, const TfToken &dstName)
5192 {
5193     if (!srcProp) {
5194         TF_CODING_ERROR("Cannot flatten invalid property <%s>",
5195                         UsdDescribe(srcProp).c_str());
5196         return UsdProperty();
5197     }
5198 
5199     if (!dstParent) {
5200         TF_CODING_ERROR("Cannot flatten property <%s> to invalid %s",
5201                         UsdDescribe(srcProp).c_str(),
5202                         UsdDescribe(dstParent).c_str());
5203         return UsdProperty();
5204     }
5205 
5206     // Keep track of the pre-existing property stack for the destination
5207     // property if any -- we use this later to determine if we need to
5208     // stamp out the fallback values from the source property.
5209     SdfPropertySpecHandleVector dstPropStack;
5210     if (UsdProperty dstProp = dstParent.GetProperty(dstName)) {
5211         if ((srcProp.Is<UsdAttribute>() && !dstProp.Is<UsdAttribute>()) ||
5212             (srcProp.Is<UsdRelationship>() && !dstProp.Is<UsdRelationship>())) {
5213             TF_CODING_ERROR("Cannot flatten %s to %s because they are "
5214                             "different property types",
5215                             UsdDescribe(srcProp).c_str(),
5216                             UsdDescribe(dstProp).c_str());
5217             return UsdProperty();
5218         }
5219 
5220         dstPropStack = dstProp.GetPropertyStack();
5221     }
5222 
5223     UsdProperty dstProp;
5224     {
5225         SdfChangeBlock block;
5226 
5227         // Use the edit target from the destination prim's stage, since it may
5228         // be different from this stage
5229         SdfPrimSpecHandle primSpec =
5230             dstParent.GetStage()->_CreatePrimSpecForEditing(dstParent);
5231         if (!primSpec) {
5232             // _CreatePrimSpecForEditing will have already issued any
5233             // coding errors, so just bail out.
5234             return UsdProperty();
5235         }
5236 
5237         if (SdfPropertySpecHandle dstPropSpec =
5238                 primSpec->GetProperties()[dstName]) {
5239             // Ignore the pre-existing property spec when determining
5240             // whether to stamp out fallback values.
5241             dstPropStack.erase(
5242                 std::remove(dstPropStack.begin(), dstPropStack.end(),
5243                             dstPropSpec),
5244                 dstPropStack.end());
5245 
5246             // Clear out the existing property spec unless we're flattening
5247             // over the source property. In that case, we don't want to
5248             // remove the property spec because its authored opinions should
5249             // be considered when flattening. This won't leave behind any
5250             // unwanted opinions since we'll be overwriting all of the
5251             // destination property spec's fields anyway in this case.
5252             const bool flatteningToSelf =
5253                 srcProp.GetPrim() == dstParent && srcProp.GetName() == dstName;
5254             if (!flatteningToSelf) {
5255                 primSpec->RemoveProperty(dstPropSpec);
5256             }
5257         }
5258 
5259         // Set up a path remapping so that attribute connections or
5260         // relationships targeting an object beneath the old parent prim
5261         // now target objects beneath the new parent prim.
5262         _PathRemapping remapping;
5263         if (srcProp.GetPrim() != dstParent) {
5264             remapping[srcProp.GetPrimPath()] = dstParent.GetPath();
5265         }
5266 
5267         // Apply offsets that affect the edit target to flattened time
5268         // samples to ensure they resolve to the expected value.
5269         // Use the edit target from the destination prim's stage, since it may
5270         // be different from this stage.
5271         const SdfLayerOffset stageToLayerOffset =
5272             dstParent.GetStage()->GetEditTarget().GetMapFunction().
5273             GetTimeOffset().GetInverse();
5274 
5275         // Copy authored property values and metadata.
5276         _CopyProperty(srcProp, primSpec, dstName, remapping, stageToLayerOffset);
5277         SdfPropertySpecHandle dstPropSpec =
5278             primSpec->GetProperties().get(dstName);
5279         if (!dstPropSpec) {
5280             return UsdProperty();
5281         }
5282 
5283         dstProp = dstParent.GetProperty(dstName);
5284 
5285         // Copy fallback property values and metadata if needed.
5286         _CopyFallbacks(
5287             _GetSchemaPropertySpec(srcProp),
5288             _GetSchemaPropertySpec(dstProp),
5289             dstPropSpec, dstPropStack);
5290     }
5291 
5292     return dstProp;
5293 }
5294 
5295 const PcpPrimIndex*
_GetPcpPrimIndex(const SdfPath & primPath) const5296 UsdStage::_GetPcpPrimIndex(const SdfPath& primPath) const
5297 {
5298     return _cache->FindPrimIndex(primPath);
5299 }
5300 
5301 // ========================================================================== //
5302 //                               VALUE RESOLUTION                             //
5303 // ========================================================================== //
5304 
5305 //
5306 // Helper template function for determining type names from arbitrary pointer
5307 // types, which may include SdfAbstractDataValue and VtValue.
5308 //
5309 static const std::type_info &
_GetTypeid(const SdfAbstractDataValue * val)5310 _GetTypeid(const SdfAbstractDataValue *val) { return val->valueType; }
5311 
5312 static const std::type_info &
_GetTypeid(const VtValue * val)5313 _GetTypeid(const VtValue *val) { return val->GetTypeid(); }
5314 
5315 template <class T, class Holder>
_IsHolding(const Holder & holder)5316 static bool _IsHolding(const Holder &holder) {
5317     return TfSafeTypeCompare(typeid(T), _GetTypeid(holder));
5318 }
5319 
5320 template <class T>
_UncheckedGet(const SdfAbstractDataValue * val)5321 static const T &_UncheckedGet(const SdfAbstractDataValue *val) {
5322     return *static_cast<T const *>(val->value);
5323 }
5324 template <class T>
_UncheckedGet(const VtValue * val)5325 static const T &_UncheckedGet(const VtValue *val) {
5326     return val->UncheckedGet<T>();
5327 }
5328 
5329 template <class T>
_UncheckedSwap(SdfAbstractDataValue * dv,T & val)5330 void _UncheckedSwap(SdfAbstractDataValue *dv, T& val) {
5331     using namespace std;
5332     swap(*static_cast<T*>(dv->value), val);
5333 }
5334 template <class T>
_UncheckedSwap(VtValue * value,T & val)5335 void _UncheckedSwap(VtValue *value, T& val) {
5336     value->UncheckedSwap(val);
5337 }
5338 
5339 namespace {
5340 
5341 // Helper for lazily computing and caching the layer to stage offset for the
5342 // value resolution functions below. This allows to only resolve the layer
5343 // offset once we've determined that a value is holding a type that can be
5344 // resolved layer offsets while caching this computation for types that may
5345 // use it multiple times (e.g. SdfTimeCodeMap and VtDictionary)
5346 struct LayerOffsetAccess
5347 {
5348 public:
LayerOffsetAccess__anon7d3fbd5f1e11::LayerOffsetAccess5349     LayerOffsetAccess(const PcpNodeRef &node, const SdfLayerHandle &layer)
5350         : _node(node), _layer(layer), _hasLayerOffset(false) {}
5351 
Get__anon7d3fbd5f1e11::LayerOffsetAccess5352     const SdfLayerOffset & Get() const {
5353         // Compute once and cache.
5354         if (!_hasLayerOffset){
5355             _hasLayerOffset = true;
5356             _layerOffset = _GetLayerToStageOffset(_node, _layer);
5357         }
5358         return _layerOffset;
5359     }
5360 
5361 private:
5362     // Private helper meant to be transient so store references to inputs.
5363     const PcpNodeRef _node;
5364     const SdfLayerHandle _layer;
5365 
5366     mutable SdfLayerOffset _layerOffset;
5367     mutable bool _hasLayerOffset;
5368 };
5369 }; // end anonymous namespace
5370 
5371 static void
_ResolveAssetPath(SdfAssetPath * v,const ArResolverContext & context,const SdfLayerRefPtr & layer,bool anchorAssetPathsOnly)5372 _ResolveAssetPath(SdfAssetPath *v,
5373                   const ArResolverContext &context,
5374                   const SdfLayerRefPtr &layer,
5375                   bool anchorAssetPathsOnly)
5376 {
5377     _MakeResolvedAssetPathsImpl(
5378         layer, context, v, 1,  anchorAssetPathsOnly);
5379 }
5380 
5381 static void
_ResolveAssetPath(VtArray<SdfAssetPath> * v,const ArResolverContext & context,const SdfLayerRefPtr & layer,bool anchorAssetPathsOnly)5382 _ResolveAssetPath(VtArray<SdfAssetPath> *v,
5383                   const ArResolverContext &context,
5384                   const SdfLayerRefPtr &layer,
5385                   bool anchorAssetPathsOnly)
5386 {
5387     _MakeResolvedAssetPathsImpl(
5388         layer, context, v->data(), v->size(),  anchorAssetPathsOnly);
5389 }
5390 
5391 template <class T, class Storage>
5392 static void
_UncheckedResolveAssetPath(Storage storage,const ArResolverContext & context,const SdfLayerRefPtr & layer,bool anchorAssetPathsOnly)5393 _UncheckedResolveAssetPath(Storage storage,
5394                            const ArResolverContext &context,
5395                            const SdfLayerRefPtr &layer,
5396                            bool anchorAssetPathsOnly)
5397 {
5398     T v;
5399     _UncheckedSwap(storage, v);
5400     _ResolveAssetPath(&v, context, layer, anchorAssetPathsOnly);
5401     _UncheckedSwap(storage, v);
5402 }
5403 
5404 template <class T, class Storage>
5405 static bool
_TryResolveAssetPath(Storage storage,const ArResolverContext & context,const SdfLayerRefPtr & layer,bool anchorAssetPathsOnly)5406 _TryResolveAssetPath(Storage storage,
5407                      const ArResolverContext &context,
5408                      const SdfLayerRefPtr &layer,
5409                      bool anchorAssetPathsOnly)
5410 {
5411     if (_IsHolding<T>(storage)) {
5412         _UncheckedResolveAssetPath<T>(
5413             storage, context, layer, anchorAssetPathsOnly);
5414         return true;
5415     }
5416     return false;
5417 }
5418 
5419 // Tries to resolve the asset path in storage if it's holding an asset path
5420 // type. Returns true if the value is holding an asset path type.
5421 template <class Storage>
5422 static bool
_TryResolveAssetPaths(Storage storage,const ArResolverContext & context,const SdfLayerRefPtr & layer,bool anchorAssetPathsOnly)5423 _TryResolveAssetPaths(Storage storage,
5424                       const ArResolverContext &context,
5425                       const SdfLayerRefPtr &layer,
5426                       bool anchorAssetPathsOnly)
5427 {
5428     return
5429         _TryResolveAssetPath<SdfAssetPath>(
5430             storage, context, layer, anchorAssetPathsOnly) ||
5431         _TryResolveAssetPath<VtArray<SdfAssetPath>>(
5432             storage, context, layer, anchorAssetPathsOnly);
5433 }
5434 
5435 template <class T, class Storage>
5436 static void
_UncheckedApplyLayerOffsetToValue(Storage storage,const SdfLayerOffset & offset)5437 _UncheckedApplyLayerOffsetToValue(Storage storage,
5438                                   const SdfLayerOffset &offset)
5439 {
5440     if (!offset.IsIdentity()) {
5441         T v;
5442         _UncheckedSwap(storage, v);
5443         Usd_ApplyLayerOffsetToValue(&v, offset);
5444         _UncheckedSwap(storage, v);
5445     }
5446 }
5447 
5448 // Tries to apply the layer offset to the value in storage if its holding the
5449 // templated class type. Returns true if the value is holding the specified
5450 // type.
5451 template <class T, class Storage>
5452 static bool
_TryApplyLayerOffsetToValue(Storage storage,const LayerOffsetAccess & offsetAccess)5453 _TryApplyLayerOffsetToValue(Storage storage,
5454                             const LayerOffsetAccess &offsetAccess)
5455 {
5456     if (_IsHolding<T>(storage)) {
5457         const SdfLayerOffset &offset = offsetAccess.Get();
5458         _UncheckedApplyLayerOffsetToValue<T>(storage, offset);
5459         return true;
5460     }
5461     return false;
5462 }
5463 
5464 // Tries to resolve the time code(s) in storage with the layer offset if it's
5465 // holding an time code type. Returns true if the value is holding a time code
5466 // type.
5467 template <class Storage>
5468 static bool
_TryResolveTimeCodes(Storage storage,const LayerOffsetAccess & offsetAccess)5469 _TryResolveTimeCodes(Storage storage, const LayerOffsetAccess &offsetAccess)
5470 {
5471     return
5472         _TryApplyLayerOffsetToValue<SdfTimeCode>(storage, offsetAccess) ||
5473         _TryApplyLayerOffsetToValue<VtArray<SdfTimeCode>>(storage, offsetAccess);
5474 }
5475 
5476 // If the given dictionary contains any resolvable values, fills in those values
5477 // with their resolved paths.
5478 static void
_ResolveValuesInDictionary(const SdfLayerRefPtr & anchor,const ArResolverContext & context,const LayerOffsetAccess * offsetAccess,VtDictionary * dict,bool anchorAssetPathsOnly)5479 _ResolveValuesInDictionary(const SdfLayerRefPtr &anchor,
5480                            const ArResolverContext &context,
5481                            const LayerOffsetAccess *offsetAccess,
5482                            VtDictionary *dict,
5483                            bool anchorAssetPathsOnly)
5484 {
5485     // If there is no layer offset, don't bother with resolving time codes and
5486     // just resolve asset paths.
5487     if (offsetAccess) {
5488         Usd_ResolveValuesInDictionary(dict,
5489             [&anchor, &context, &offsetAccess, &anchorAssetPathsOnly]
5490                 (VtValue *value)
5491             {
5492                 _TryResolveAssetPaths(
5493                     value, context, anchor, anchorAssetPathsOnly) ||
5494                 _TryResolveTimeCodes(value, *offsetAccess);
5495             });
5496     } else {
5497         Usd_ResolveValuesInDictionary(dict,
5498             [&anchor, &context, &anchorAssetPathsOnly](VtValue *value)
5499             {
5500                 _TryResolveAssetPaths(
5501                     value, context, anchor, anchorAssetPathsOnly);
5502             });
5503     }
5504 }
5505 
5506 // Tries to resolve all the resolvable values contained within a VtDictionary in
5507 // storage. Returns true if the value is holding a VtDictionary.
5508 template <class Storage>
5509 static bool
_TryResolveValuesInDictionary(Storage storage,const SdfLayerRefPtr & anchor,const ArResolverContext & context,const LayerOffsetAccess * offsetAccess,bool anchorAssetPathsOnly)5510 _TryResolveValuesInDictionary(Storage storage,
5511                               const SdfLayerRefPtr &anchor,
5512                               const ArResolverContext &context,
5513                               const LayerOffsetAccess *offsetAccess,
5514                               bool anchorAssetPathsOnly)
5515 {
5516     if (_IsHolding<VtDictionary>(storage)) {
5517         VtDictionary resolvedDict;
5518         _UncheckedSwap(storage, resolvedDict);
5519         _ResolveValuesInDictionary(
5520             anchor, context, offsetAccess, &resolvedDict, anchorAssetPathsOnly);
5521         _UncheckedSwap(storage, resolvedDict);
5522         return true;
5523     }
5524     return false;
5525 }
5526 
5527 
5528 namespace {
5529 
5530 // Non-virtual value composer base class. Helps provide shared functionality
5531 // amongst the different derived value composer classed. The derived classes
5532 // must all implement a ConsumeAuthored and ConsumeUsdFallback function.
5533 template <class Storage>
5534 struct ValueComposerBase
5535 {
5536     static const bool ProducesValue = true;
5537 
GetHeldTypeid__anon7d3fbd5f2111::ValueComposerBase5538     const std::type_info& GetHeldTypeid() const { return _GetTypeid(_value); }
IsDone__anon7d3fbd5f2111::ValueComposerBase5539     bool IsDone() const { return _done; }
5540 
5541     template <class ValueType>
ConsumeExplicitValue__anon7d3fbd5f2111::ValueComposerBase5542     void ConsumeExplicitValue(ValueType type)
5543     {
5544         Usd_SetValue(_value, type);
5545         _done = true;
5546     }
5547 
5548 protected:
5549     // Protected constructor.
ValueComposerBase__anon7d3fbd5f2111::ValueComposerBase5550     explicit ValueComposerBase(Storage s, bool anchorAssetPathsOnly = false)
5551         : _value(s), _done(false), _anchorAssetPathsOnly(anchorAssetPathsOnly)
5552         {}
5553 
5554     // Gets the value from the layer spec.
_GetValue__anon7d3fbd5f2111::ValueComposerBase5555     bool _GetValue(const SdfLayerRefPtr &layer,
5556                    const SdfPath &specPath,
5557                    const TfToken &fieldName,
5558                    const TfToken &keyPath)
5559     {
5560         return keyPath.IsEmpty() ?
5561             layer->HasField(specPath, fieldName, _value) :
5562             layer->HasFieldDictKey(specPath, fieldName, keyPath, _value);
5563     }
5564 
5565     // Gets the fallback value for the property
_GetFallbackValue__anon7d3fbd5f2111::ValueComposerBase5566     bool _GetFallbackValue(const UsdPrimDefinition &primDef,
5567                            const TfToken &propName,
5568                            const TfToken &fieldName,
5569                            const TfToken &keyPath)
5570     {
5571         // Try to read fallback value.
5572         return Usd_GetFallbackValue(
5573             primDef, propName, fieldName, keyPath, _value);
5574     }
5575 
5576     // Consumes an authored dictionary value and merges it into the current
5577     // strongest dictionary value.
_ConsumeAndMergeAuthoredDictionary__anon7d3fbd5f2111::ValueComposerBase5578     bool _ConsumeAndMergeAuthoredDictionary(const PcpNodeRef &node,
5579                                             const SdfLayerRefPtr &layer,
5580                                             const SdfPath &specPath,
5581                                             const TfToken &fieldName,
5582                                             const TfToken &keyPath)
5583     {
5584         // Copy to the side since we'll have to merge if the next opinion
5585         // is also a dictionary.
5586         VtDictionary tmpDict = _UncheckedGet<VtDictionary>(_value);
5587 
5588         // Try to read value from scene description.
5589         if (_GetValue(layer, specPath, fieldName, keyPath)) {
5590             const ArResolverContext &context =
5591                 node.GetLayerStack()->GetIdentifier().pathResolverContext;
5592             // Create a layer offset accessor so we don't compute the layer
5593             // offset unless one of the resolve functions actually needs it.
5594             LayerOffsetAccess layerOffsetAccess(node, layer);
5595 
5596             // Try resolving the values in the dictionary.
5597             if (_TryResolveValuesInDictionary(
5598                     _value, layer, context, &layerOffsetAccess,
5599                     _anchorAssetPathsOnly)) {
5600                 // Merge the resolved dictionary.
5601                 VtDictionaryOverRecursive(
5602                     &tmpDict, _UncheckedGet<VtDictionary>(_value));
5603                 _UncheckedSwap(_value, tmpDict);
5604             }
5605             return true;
5606         }
5607         return false;
5608     }
5609 
5610     // Consumes the fallback dictionary value and merges it into the current
5611     // dictionary value.
_ConsumeAndMergeFallbackDictionary__anon7d3fbd5f2111::ValueComposerBase5612     void _ConsumeAndMergeFallbackDictionary(
5613         const UsdPrimDefinition &primDef,
5614         const TfToken &propName,
5615         const TfToken &fieldName,
5616         const TfToken &keyPath)
5617     {
5618         // Copy to the side since we'll have to merge if the next opinion is
5619         // also a dictionary.
5620         VtDictionary tmpDict = _UncheckedGet<VtDictionary>(_value);
5621 
5622         // Try to read fallback value.
5623         if(_GetFallbackValue(primDef, propName, fieldName, keyPath)) {
5624             // Always done after reading the fallback value.
5625             _done = true;
5626             if (_IsHolding<VtDictionary>(_value)) {
5627                 // Merge dictionaries: _value is weaker, tmpDict stronger.
5628                 VtDictionaryOverRecursive(&tmpDict,
5629                                           _UncheckedGet<VtDictionary>(_value));
5630                 _UncheckedSwap(_value, tmpDict);
5631             }
5632         }
5633     }
5634 
5635     Storage _value;
5636     bool _done;
5637     bool _anchorAssetPathsOnly;
5638 };
5639 
5640 // Value composer for a type erased VtValue. This will check the type
5641 // of the stored value and do the appropriate value composition for the type.
5642 struct UntypedValueComposer : public ValueComposerBase<VtValue *>
5643 {
5644     using Base = ValueComposerBase<VtValue *>;
5645 
UntypedValueComposer__anon7d3fbd5f2111::UntypedValueComposer5646     explicit UntypedValueComposer(
5647         VtValue *s, bool anchorAssetPathsOnly = false)
5648         : Base(s, anchorAssetPathsOnly) {}
5649 
ConsumeAuthored__anon7d3fbd5f2111::UntypedValueComposer5650     bool ConsumeAuthored(const PcpNodeRef &node,
5651                          const SdfLayerRefPtr &layer,
5652                          const SdfPath &specPath,
5653                          const TfToken &fieldName,
5654                          const TfToken &keyPath)
5655     {
5656         if (_IsHoldingDictionary()) {
5657             // Handle special value-type composition: dictionaries merge atop
5658             // each other.
5659             return this->_ConsumeAndMergeAuthoredDictionary(
5660                 node, layer, specPath, fieldName, keyPath);
5661         } else {
5662             // Try to read value from scene description and resolve it if needed
5663             // if the value is found.
5664             if (this->_GetValue(layer, specPath, fieldName, keyPath)) {
5665                 // We're done if we got value and it's not a dictionary. For
5666                 // dictionaries we'll continue to merge in weaker dictionaries.
5667                 if (!_IsHoldingDictionary()) {
5668                     this->_done = true;
5669                 }
5670                 _ResolveValue(node, layer);
5671                 return true;
5672             }
5673             return false;
5674         }
5675     }
5676 
ConsumeUsdFallback__anon7d3fbd5f2111::UntypedValueComposer5677     void ConsumeUsdFallback(const UsdPrimDefinition &primDef,
5678                             const TfToken &propName,
5679                             const TfToken &fieldName,
5680                             const TfToken &keyPath)
5681     {
5682         if (_IsHoldingDictionary()) {
5683             // Handle special value-type composition: fallback dictionaries
5684             // are merged into the current dictionary value..
5685             this->_ConsumeAndMergeFallbackDictionary(
5686                 primDef, propName, fieldName, keyPath);
5687         } else {
5688             // Try to read fallback value. Fallbacks are not resolved.
5689             this->_done = this->_GetFallbackValue(
5690                 primDef, propName, fieldName, keyPath);
5691         }
5692     }
5693 
5694 protected:
_IsHoldingDictionary__anon7d3fbd5f2111::UntypedValueComposer5695     bool _IsHoldingDictionary() const {
5696         return _IsHolding<VtDictionary>(this->_value);
5697     }
5698 
_ResolveValue__anon7d3fbd5f2111::UntypedValueComposer5699     void _ResolveValue(const PcpNodeRef &node, const SdfLayerRefPtr &layer)
5700     {
5701         const ArResolverContext &context =
5702             node.GetLayerStack()->GetIdentifier().pathResolverContext;
5703         // Create a layer offset accessor so we don't compute the layer
5704         // offset unless one of the resolve functions actually needs it.
5705         LayerOffsetAccess layerOffsetAccess(node, layer);
5706 
5707         // Since we don't know the type, we have to try to resolve the
5708         // consumed value for all the types that require additional
5709         // value resolution.
5710 
5711         // Try resolving the value as a dictionary first. Note that even though
5712         // we have a special case in ConsumeAuthored for when the value is
5713         // holding a dictionary, we still have to check for dictionary values
5714         // here to the cover the case when the storage container starts as an
5715         // empty VtValue.
5716         if (_TryResolveValuesInDictionary(
5717                 this->_value, layer, context, &layerOffsetAccess,
5718                 this->_anchorAssetPathsOnly)) {
5719         } else {
5720             // Otherwise try resolving each of the the other resolvable
5721             // types.
5722             _TryApplyLayerOffsetToValue<SdfTimeSampleMap>(
5723                 this->_value, layerOffsetAccess) ||
5724             _TryResolveAssetPaths(
5725                 this->_value, context, layer, this->_anchorAssetPathsOnly) ||
5726             _TryResolveTimeCodes(this->_value, layerOffsetAccess);
5727         }
5728     }
5729 };
5730 
5731 // Strongest value composer for a SdfAbstractDataValue holding a type we know
5732 // does not need type specific value resolution. The data value is type erased
5733 // since this composer only needs to get the strongest value. For value types
5734 // with, type specific value resolution, the TypeSpecficValueComposer must be
5735 // used instead to get a correctly resolved value.
5736 struct StrongestValueComposer : public ValueComposerBase<SdfAbstractDataValue *>
5737 {
5738     using Base = ValueComposerBase<SdfAbstractDataValue *>;
5739 
StrongestValueComposer__anon7d3fbd5f2111::StrongestValueComposer5740     explicit StrongestValueComposer(SdfAbstractDataValue *s)
5741         : Base(s, /* anchorAssetPathsOnly = */ false) {}
5742 
5743 
ConsumeAuthored__anon7d3fbd5f2111::StrongestValueComposer5744     bool ConsumeAuthored(const PcpNodeRef &node,
5745                          const SdfLayerRefPtr &layer,
5746                          const SdfPath &specPath,
5747                          const TfToken &fieldName,
5748                          const TfToken &keyPath)
5749     {
5750         // Try to read value from scene description, we're done if the value
5751         // is found.
5752         if (this->_GetValue(layer, specPath, fieldName, keyPath)) {
5753             this->_done = true;
5754             return true;
5755         }
5756         return false;
5757     }
5758 
ConsumeUsdFallback__anon7d3fbd5f2111::StrongestValueComposer5759     void ConsumeUsdFallback(const UsdPrimDefinition &primDef,
5760                             const TfToken &propName,
5761                             const TfToken &fieldName,
5762                             const TfToken &keyPath)
5763     {
5764         this->_done = this->_GetFallbackValue(
5765             primDef, propName, fieldName, keyPath);
5766     }
5767 };
5768 
5769 // Value composer for a storage container whose type requires type specific
5770 // value resolution. If this composer is used for a type that does not have
5771 // type specific value resolution then this is equivalent to using a
5772 // StrongestValueComposer. For types that have type specific value resolution,
5773 // this is specialized to perform the appropriate resolution.
5774 template <class T>
5775 struct TypeSpecificValueComposer :
5776     public ValueComposerBase<SdfAbstractDataValue *>
5777 {
5778     using Base = ValueComposerBase<SdfAbstractDataValue *>;
5779     friend Base;
5780 
TypeSpecificValueComposer__anon7d3fbd5f2111::TypeSpecificValueComposer5781     explicit TypeSpecificValueComposer(SdfAbstractDataTypedValue<T> *s)
5782         : Base(s, /*anchorAssetPathsOnly = */ false) {}
5783 
ConsumeAuthored__anon7d3fbd5f2111::TypeSpecificValueComposer5784     bool ConsumeAuthored(const PcpNodeRef &node,
5785                          const SdfLayerRefPtr &layer,
5786                          const SdfPath &specPath,
5787                          const TfToken &fieldName,
5788                          const TfToken &keyPath)
5789     {
5790         // Try to read value from scene description and resolve it if needed
5791         // if the value is found.
5792         if (this->_GetValue(layer, specPath, fieldName, keyPath)) {
5793             // We're done if we got value and it's not a dictionary. For
5794             // dictionaries we'll continue to merge in weaker dictionaries.
5795             this->_done = true;
5796             _ResolveValue(node, layer);
5797             return true;
5798         }
5799         return false;
5800     }
5801 
ConsumeUsdFallback__anon7d3fbd5f2111::TypeSpecificValueComposer5802     void ConsumeUsdFallback(const UsdPrimDefinition &primDef,
5803                             const TfToken &propName,
5804                             const TfToken &fieldName,
5805                             const TfToken &keyPath)
5806     {
5807         this->_done = this->_GetFallbackValue(
5808             primDef, propName, fieldName, keyPath);
5809     }
5810 
5811 protected:
5812     // Implementation for the base class.
_ResolveValue__anon7d3fbd5f2111::TypeSpecificValueComposer5813     void _ResolveValue(const PcpNodeRef &node,
5814                        const SdfLayerRefPtr &layer)
5815     {
5816         // The default for almost all types is to do no extra value resolution.
5817         // The few types that require resolution must either specialize this
5818         // method or reimplement ConsumeAuthored and delete this method.
5819         static_assert(!UsdStage::_HasTypeSpecificResolution<T>::value,
5820                       "Value types that have type specific value resolution "
5821                       "must either specialize _ResolveValue or delete it and "
5822                       "reimplement ConsumeAuthored");
5823     }
5824 };
5825 
5826 // Specializations of _ResolveValue for type specific value resolution types.
5827 // Note that we can assume that _value always holds the template value type so
5828 // there is no value type checking.
5829 // We may, however, want to skip these resolves when _value.isValueBlock is true
5830 template <>
5831 void
_ResolveValue(const PcpNodeRef & node,const SdfLayerRefPtr & layer)5832 TypeSpecificValueComposer<SdfAssetPath>::_ResolveValue(
5833     const PcpNodeRef &node,
5834     const SdfLayerRefPtr &layer)
5835 {
5836     const ArResolverContext &context =
5837         node.GetLayerStack()->GetIdentifier().pathResolverContext;
5838     _UncheckedResolveAssetPath<SdfAssetPath>(
5839         _value, context, layer, /*anchorAssetPathsOnly = */ false);
5840 }
5841 
5842 template <>
5843 void
_ResolveValue(const PcpNodeRef & node,const SdfLayerRefPtr & layer)5844 TypeSpecificValueComposer<VtArray<SdfAssetPath>>::_ResolveValue(
5845     const PcpNodeRef &node,
5846     const SdfLayerRefPtr &layer)
5847 {
5848     const ArResolverContext &context =
5849         node.GetLayerStack()->GetIdentifier().pathResolverContext;
5850     _UncheckedResolveAssetPath<VtArray<SdfAssetPath>>(
5851         _value, context, layer, /*anchorAssetPathsOnly = */ false);
5852 }
5853 
5854 template <>
5855 void
_ResolveValue(const PcpNodeRef & node,const SdfLayerRefPtr & layer)5856 TypeSpecificValueComposer<SdfTimeCode>::_ResolveValue(
5857     const PcpNodeRef &node,
5858     const SdfLayerRefPtr &layer)
5859 {
5860     SdfLayerOffset offset = _GetLayerToStageOffset(node, layer);
5861     _UncheckedApplyLayerOffsetToValue<SdfTimeCode>(_value, offset);
5862 }
5863 
5864 template <>
5865 void
_ResolveValue(const PcpNodeRef & node,const SdfLayerRefPtr & layer)5866 TypeSpecificValueComposer<VtArray<SdfTimeCode>>::_ResolveValue(
5867     const PcpNodeRef &node,
5868     const SdfLayerRefPtr &layer)
5869 {
5870     SdfLayerOffset offset = _GetLayerToStageOffset(node, layer);
5871     _UncheckedApplyLayerOffsetToValue<VtArray<SdfTimeCode>>(_value, offset);
5872 }
5873 
5874 template <>
5875 void
_ResolveValue(const PcpNodeRef & node,const SdfLayerRefPtr & layer)5876 TypeSpecificValueComposer<SdfTimeSampleMap>::_ResolveValue(
5877     const PcpNodeRef &node,
5878     const SdfLayerRefPtr &layer)
5879 {
5880     SdfLayerOffset offset = _GetLayerToStageOffset(node, layer);
5881     _UncheckedApplyLayerOffsetToValue<SdfTimeSampleMap>(_value, offset);
5882 }
5883 
5884 // The TypeSpecificValueComposer for VtDictionary has additional specialization
5885 // for consuming values as it merges in weaker values unlike most types that
5886 // only consume the strongest value.
5887 template <>
5888 bool
ConsumeAuthored(const PcpNodeRef & node,const SdfLayerRefPtr & layer,const SdfPath & specPath,const TfToken & fieldName,const TfToken & keyPath)5889 TypeSpecificValueComposer<VtDictionary>::ConsumeAuthored(
5890     const PcpNodeRef &node,
5891     const SdfLayerRefPtr &layer,
5892     const SdfPath &specPath,
5893     const TfToken &fieldName,
5894     const TfToken &keyPath)
5895 {
5896     // Handle special value-type composition: dictionaries merge atop
5897     // each other.
5898     return this->_ConsumeAndMergeAuthoredDictionary(
5899         node, layer, specPath, fieldName, keyPath);
5900 }
5901 
5902 template <>
5903 void
ConsumeUsdFallback(const UsdPrimDefinition & primDef,const TfToken & propName,const TfToken & fieldName,const TfToken & keyPath)5904 TypeSpecificValueComposer<VtDictionary>::ConsumeUsdFallback(
5905     const UsdPrimDefinition &primDef,
5906     const TfToken &propName,
5907     const TfToken &fieldName,
5908     const TfToken &keyPath)
5909 {
5910     // Handle special value-type composition: fallback dictionaries
5911     // are merged into the current dictionary value..
5912     _ConsumeAndMergeFallbackDictionary(
5913         primDef, propName, fieldName, keyPath);
5914 }
5915 
5916 template <>
5917 void
5918 TypeSpecificValueComposer<VtDictionary>::_ResolveValue(
5919     const PcpNodeRef &, const SdfLayerRefPtr &) = delete;
5920 
5921 
5922 struct ExistenceComposer
5923 {
5924     static const bool ProducesValue = false;
5925 
ExistenceComposer__anon7d3fbd5f2111::ExistenceComposer5926     ExistenceComposer() : _done(false), _strongestLayer(nullptr) {}
ExistenceComposer__anon7d3fbd5f2111::ExistenceComposer5927     explicit ExistenceComposer(SdfLayerRefPtr *strongestLayer)
5928         : _done(false), _strongestLayer(strongestLayer) {}
5929 
GetHeldTypeid__anon7d3fbd5f2111::ExistenceComposer5930     const std::type_info& GetHeldTypeid() const { return typeid(void); }
IsDone__anon7d3fbd5f2111::ExistenceComposer5931     bool IsDone() const { return _done; }
ConsumeAuthored__anon7d3fbd5f2111::ExistenceComposer5932     bool ConsumeAuthored(const PcpNodeRef &node,
5933                          const SdfLayerRefPtr &layer,
5934                          const SdfPath &specPath,
5935                          const TfToken &fieldName,
5936                          const TfToken &keyPath,
5937                          const SdfLayerOffset & = SdfLayerOffset()) {
5938         _done = keyPath.IsEmpty() ?
5939             layer->HasField(specPath, fieldName,
5940                             static_cast<VtValue *>(nullptr)) :
5941             layer->HasFieldDictKey(specPath, fieldName, keyPath,
5942                                    static_cast<VtValue*>(nullptr));
5943         if (_done && _strongestLayer)
5944             *_strongestLayer = layer;
5945         return _done;
5946     }
ConsumeUsdFallback__anon7d3fbd5f2111::ExistenceComposer5947     void ConsumeUsdFallback(const UsdPrimDefinition &primDef,
5948                             const TfToken &propName,
5949                             const TfToken &fieldName,
5950                             const TfToken &keyPath) {
5951         _done = Usd_GetFallbackValue(primDef, propName, fieldName, keyPath,
5952                                      static_cast<VtValue *>(nullptr));
5953         if (_strongestLayer)
5954             *_strongestLayer = TfNullPtr;
5955     }
5956     template <class ValueType>
ConsumeExplicitValue__anon7d3fbd5f2111::ExistenceComposer5957     void ConsumeExplicitValue(ValueType type) {
5958         _done = true;
5959     }
5960 
5961 protected:
5962     bool _done;
5963     SdfLayerRefPtr *_strongestLayer;
5964 };
5965 
5966 }
5967 
5968 template <class T>
5969 bool
_SetValueImpl(UsdTimeCode time,const UsdAttribute & attr,const T & newValue)5970 UsdStage::_SetValueImpl(
5971     UsdTimeCode time, const UsdAttribute &attr, const T& newValue)
5972 {
5973     // if we are setting a value block, we don't want type checking
5974     if (!Usd_ValueContainsBlock(&newValue)) {
5975         // Do a type check.  Obtain typeName.
5976         TfToken typeName;
5977         SdfAbstractDataTypedValue<TfToken> abstrToken(&typeName);
5978         TypeSpecificValueComposer<TfToken> composer(&abstrToken);
5979         _GetMetadataImpl(attr, SdfFieldKeys->TypeName, TfToken(),
5980                          /*useFallbacks=*/true, &composer);
5981 
5982         if (typeName.IsEmpty()) {
5983                 TF_RUNTIME_ERROR("Empty typeName for <%s>",
5984                                  attr.GetPath().GetText());
5985             return false;
5986         }
5987         // Ensure this typeName is known to our schema.
5988         TfType valType = SdfSchema::GetInstance().FindType(typeName).GetType();
5989         if (valType.IsUnknown()) {
5990             TF_RUNTIME_ERROR("Unknown typename for <%s>: '%s'",
5991                              typeName.GetText(), attr.GetPath().GetText());
5992             return false;
5993         }
5994         // Check that the passed value is the expected type.
5995         if (!TfSafeTypeCompare(_GetTypeInfo(newValue), valType.GetTypeid())) {
5996             TF_CODING_ERROR("Type mismatch for <%s>: expected '%s', got '%s'",
5997                             attr.GetPath().GetText(),
5998                             ArchGetDemangled(valType.GetTypeid()).c_str(),
5999                             ArchGetDemangled(_GetTypeInfo(newValue)).c_str());
6000             return false;
6001         }
6002 
6003         // Check variability, but only if the appropriate debug flag is
6004         // enabled. Variability is a statement of intent but doesn't control
6005         // behavior, so we only want to perform this validation when it is
6006         // requested.
6007         if (TfDebug::IsEnabled(USD_VALIDATE_VARIABILITY) &&
6008             time != UsdTimeCode::Default() &&
6009             _GetVariability(attr) == SdfVariabilityUniform) {
6010             TF_DEBUG(USD_VALIDATE_VARIABILITY)
6011                 .Msg("Warning: authoring time sample value on "
6012                      "uniform attribute <%s> at time %.3f\n",
6013                      UsdDescribe(attr).c_str(), time.GetValue());
6014         }
6015     }
6016 
6017     SdfAttributeSpecHandle attrSpec = _CreateAttributeSpecForEditing(attr);
6018 
6019     if (!attrSpec) {
6020         TF_RUNTIME_ERROR(
6021             "Cannot set attribute value.  Failed to create "
6022             "attribute spec <%s> in layer @%s@",
6023             GetEditTarget().MapToSpecPath(attr.GetPath()).GetText(),
6024             GetEditTarget().GetLayer()->GetIdentifier().c_str());
6025         return false;
6026     }
6027 
6028     if (time.IsDefault()) {
6029         attrSpec->GetLayer()->SetField(attrSpec->GetPath(),
6030                                        SdfFieldKeys->Default,
6031                                        newValue);
6032     } else {
6033         // XXX: should this loft the underlying values up when
6034         // authoring over a weaker layer?
6035 
6036         // XXX: this won't be correct if we are trying to edit
6037         // across two different reference arcs -- which may have
6038         // different time offsets.  perhaps we need the map function
6039         // to track a time offset for each path?
6040         const SdfLayerOffset stageToLayerOffset =
6041             GetEditTarget().GetMapFunction().GetTimeOffset().GetInverse();
6042 
6043         double localTime = stageToLayerOffset * time.GetValue();
6044 
6045         attrSpec->GetLayer()->SetTimeSample(
6046             attrSpec->GetPath(),
6047             localTime,
6048             newValue);
6049     }
6050 
6051     return true;
6052 }
6053 
6054 // --------------------------------------------------------------------- //
6055 // Helpers for Metadata Resolution
6056 // --------------------------------------------------------------------- //
6057 
6058 template <class Composer>
6059 static bool
_GetFallbackMetadataImpl(Usd_PrimDataConstPtr primData,const TfToken & propName,const TfToken & fieldName,const TfToken & keyPath,Composer * composer)6060 _GetFallbackMetadataImpl(Usd_PrimDataConstPtr primData,
6061                          const TfToken& propName,
6062                          const TfToken &fieldName,
6063                          const TfToken &keyPath,
6064                          Composer *composer)
6065 {
6066     // Look for a fallback value in the definition.
6067     // NOTE: This code is performance critical.
6068     composer->ConsumeUsdFallback(
6069         primData->GetPrimDefinition(), propName, fieldName, keyPath);
6070     return composer->IsDone();
6071 }
6072 
6073 template <class Composer>
6074 static bool
_ComposeGeneralMetadataImpl(Usd_PrimDataConstPtr primData,const TfToken & propName,const TfToken & fieldName,const TfToken & keyPath,bool useFallbacks,Usd_Resolver * res,Composer * composer)6075 _ComposeGeneralMetadataImpl(Usd_PrimDataConstPtr primData,
6076                             const TfToken& propName,
6077                             const TfToken& fieldName,
6078                             const TfToken& keyPath,
6079                             bool useFallbacks,
6080                             Usd_Resolver* res,
6081                             Composer *composer)
6082 {
6083     // Main resolution loop.
6084     SdfPath specPath = res->GetLocalPath(propName);
6085     bool gotOpinion = false;
6086 
6087     for (bool isNewNode = false; res->IsValid(); isNewNode = res->NextLayer()) {
6088         if (isNewNode) {
6089             specPath = res->GetLocalPath(propName);
6090         }
6091 
6092         // Consume an authored opinion here, if one exists.
6093         gotOpinion |= composer->ConsumeAuthored(
6094             res->GetNode(), res->GetLayer(), specPath, fieldName, keyPath);
6095 
6096         if (composer->IsDone()) {
6097             return true;
6098         }
6099     }
6100 
6101     if (useFallbacks) {
6102         _GetFallbackMetadataImpl(
6103             primData, propName, fieldName, keyPath, composer);
6104     }
6105 
6106     return gotOpinion || composer->IsDone();
6107 }
6108 
6109 // Special composing for just the pseudoroot. The pseudoroot only composes
6110 // metadata opinions on the absolute root path from the session and root layers.
6111 // Note that the pseudoroot itself doesn't provide fallbacks.
6112 // Returns true if an opinion was found.
6113 template <class Composer>
6114 static bool
_ComposePseudoRootMetadataImpl(Usd_PrimDataConstPtr primData,const TfToken & fieldName,const TfToken & keyPath,const SdfLayerRefPtr & rootLayer,const SdfLayerRefPtr & sessionLayer,Composer * composer)6115 _ComposePseudoRootMetadataImpl(Usd_PrimDataConstPtr primData,
6116                                const TfToken& fieldName,
6117                                const TfToken& keyPath,
6118                                const SdfLayerRefPtr &rootLayer,
6119                                const SdfLayerRefPtr &sessionLayer,
6120                                Composer *composer)
6121 {
6122     const SdfPath &specPath = SdfPath::AbsoluteRootPath();
6123     bool gotOpinion = false;
6124 
6125     PcpNodeRef node = primData->GetPrimIndex().GetRootNode();
6126 
6127     // If we a have a session layer and it isn't muted, we try to consume its
6128     // opinion first. The session layer will be the first layer in the
6129     // layer stack unless it is muted.
6130     if (sessionLayer &&
6131         node.GetLayerStack()->GetLayers().front() == sessionLayer) {
6132         // Consume an authored opinion here, if one exists.
6133         gotOpinion = composer->ConsumeAuthored(
6134             node, sessionLayer, specPath, fieldName, keyPath);
6135         if (composer->IsDone()) {
6136             return true;
6137         }
6138     }
6139 
6140     // Consume an authored opinion from the root layer (which cannot be muted).
6141     gotOpinion |= composer->ConsumeAuthored(
6142         node, rootLayer, specPath, fieldName, keyPath);
6143 
6144     // Return whether we got an opinion from either layer.
6145     return gotOpinion;
6146 }
6147 
6148 // --------------------------------------------------------------------- //
6149 // Specialized Metadata Resolution
6150 // --------------------------------------------------------------------- //
6151 
6152 template <class Composer>
6153 static bool
6154 _GetPrimSpecifierImpl(Usd_PrimDataConstPtr primData,
6155                       bool useFallbacks, Composer *composer);
6156 
6157 SdfSpecifier
_GetSpecifier(Usd_PrimDataConstPtr primData)6158 UsdStage::_GetSpecifier(Usd_PrimDataConstPtr primData)
6159 {
6160     SdfSpecifier result = SdfSpecifierOver;
6161     SdfAbstractDataTypedValue<SdfSpecifier> resultVal(&result);
6162     TypeSpecificValueComposer<SdfSpecifier> composer(&resultVal);
6163     _GetPrimSpecifierImpl(primData, /* useFallbacks = */ true, &composer);
6164     return result;
6165 }
6166 
6167 template <class Composer>
6168 static bool
_GetPrimKindImpl(Usd_PrimDataConstPtr primData,bool useFallbacks,Composer * composer)6169 _GetPrimKindImpl(Usd_PrimDataConstPtr primData,
6170                  bool useFallbacks, Composer *composer)
6171 {
6172     Usd_Resolver resolver(&primData->GetPrimIndex());
6173     return _ComposeGeneralMetadataImpl(
6174         primData, TfToken(), SdfFieldKeys->Kind, TfToken(), useFallbacks,
6175         &resolver, composer);
6176 }
6177 
6178 TfToken
_GetKind(Usd_PrimDataConstPtr primData)6179 UsdStage::_GetKind(Usd_PrimDataConstPtr primData)
6180 {
6181     TfToken kind;
6182     SdfAbstractDataTypedValue<TfToken> resultValue(&kind);
6183     TypeSpecificValueComposer<TfToken> composer(&resultValue);
6184 
6185     // We don't allow fallbacks for kind.
6186     _GetPrimKindImpl(primData, /* useFallbacks = */ false, &composer);
6187     return kind;
6188 }
6189 
6190 template <class Composer>
6191 static bool
_GetPrimActiveImpl(Usd_PrimDataConstPtr primData,bool useFallbacks,Composer * composer)6192 _GetPrimActiveImpl(Usd_PrimDataConstPtr primData,
6193                    bool useFallbacks, Composer *composer)
6194 {
6195     Usd_Resolver resolver(&primData->GetPrimIndex());
6196     return _ComposeGeneralMetadataImpl(
6197         primData, TfToken(), SdfFieldKeys->Active, TfToken(), useFallbacks,
6198         &resolver, composer);
6199 }
6200 
6201 bool
_IsActive(Usd_PrimDataConstPtr primData)6202 UsdStage::_IsActive(Usd_PrimDataConstPtr primData)
6203 {
6204     bool active = true;
6205     SdfAbstractDataTypedValue<bool> resultValue(&active);
6206     TypeSpecificValueComposer<bool> composer(&resultValue);
6207 
6208     // We don't allow fallbacks for active.
6209     _GetPrimActiveImpl(primData, /* useFallbacks = */ false, &composer);
6210     return active;
6211 }
6212 
6213 bool
_IsCustom(const UsdProperty & prop) const6214 UsdStage::_IsCustom(const UsdProperty &prop) const
6215 {
6216     // Custom is composed as true if there is no property definition and it is
6217     // true anywhere in the stack of opinions.
6218 
6219     if (_GetSchemaPropertySpec(prop))
6220         return false;
6221 
6222     const TfToken &propName = prop.GetName();
6223 
6224     TF_REVERSE_FOR_ALL(itr, prop.GetPrim().GetPrimIndex().GetNodeRange()) {
6225 
6226         if (itr->IsInert() || !itr->HasSpecs()) {
6227             continue;
6228         }
6229 
6230         SdfPath specPath = itr->GetPath().AppendProperty(propName);
6231         TF_REVERSE_FOR_ALL(layerIt, itr->GetLayerStack()->GetLayers()) {
6232             bool result = false;
6233             if ((*layerIt)->HasField(specPath, SdfFieldKeys->Custom, &result)
6234                 && result) {
6235                 return true;
6236             }
6237         }
6238     }
6239 
6240     return SdfSchema::GetInstance().GetFieldDefinition(
6241         SdfFieldKeys->Custom)->GetFallbackValue().Get<bool>();
6242 }
6243 
6244 SdfVariability
6245 UsdStage
_GetVariability(const UsdProperty & prop) const6246 ::_GetVariability(const UsdProperty &prop) const
6247 {
6248     // The composed variability is the taken from the weakest opinion in the
6249     // stack, unless this is a built-in attribute, in which case the definition
6250     // wins.
6251 
6252     if (prop.Is<UsdAttribute>()) {
6253         UsdAttribute attr = prop.As<UsdAttribute>();
6254         // Check definition.
6255         if (SdfAttributeSpecHandle attrDef = _GetSchemaAttributeSpec(attr)) {
6256             return attrDef->GetVariability();
6257         }
6258 
6259         // Check authored scene description.
6260         const TfToken &attrName = attr.GetName();
6261         TF_REVERSE_FOR_ALL(itr, attr.GetPrim().GetPrimIndex().GetNodeRange()) {
6262             if (itr->IsInert() || !itr->HasSpecs())
6263                 continue;
6264 
6265             SdfPath specPath = itr->GetPath().AppendProperty(attrName);
6266             TF_REVERSE_FOR_ALL(layerIt, itr->GetLayerStack()->GetLayers()) {
6267                 SdfVariability result;
6268                 if ((*layerIt)->HasField(
6269                         specPath, SdfFieldKeys->Variability, &result)) {
6270                     return result;
6271                 }
6272             }
6273         }
6274     }
6275 
6276     // Fall back to schema.
6277     return SdfSchema::GetInstance().GetFieldDefinition(
6278         SdfFieldKeys->Variability)->GetFallbackValue().Get<SdfVariability>();
6279 }
6280 
6281 // --------------------------------------------------------------------- //
6282 // Metadata Resolution
6283 // --------------------------------------------------------------------- //
6284 
6285 // Populates the time sample map with the resolved values for the given
6286 // attribute and returns true if time samples exist, false otherwise.
6287 static bool
_GetTimeSampleMap(const UsdAttribute & attr,SdfTimeSampleMap * out)6288 _GetTimeSampleMap(const UsdAttribute &attr, SdfTimeSampleMap *out)
6289 {
6290     UsdAttributeQuery attrQuery(attr);
6291 
6292     std::vector<double> timeSamples;
6293     if (attrQuery.GetTimeSamples(&timeSamples)) {
6294         for (const auto& timeSample : timeSamples) {
6295             VtValue value;
6296             if (attrQuery.Get(&value, timeSample)) {
6297                 (*out)[timeSample].Swap(value);
6298             } else {
6299                 (*out)[timeSample] = VtValue(SdfValueBlock());
6300             }
6301         }
6302         return true;
6303     }
6304     return false;
6305 }
6306 
6307 bool
_GetMetadata(const UsdObject & obj,const TfToken & fieldName,const TfToken & keyPath,bool useFallbacks,VtValue * result) const6308 UsdStage::_GetMetadata(const UsdObject &obj, const TfToken &fieldName,
6309                        const TfToken &keyPath, bool useFallbacks,
6310                        VtValue* result) const
6311 {
6312     TRACE_FUNCTION();
6313 
6314     // XXX: HORRIBLE HACK.  Special-case timeSamples for now, since its
6315     // resulting value is a complicated function influenced by "model clips",
6316     // not a single value from scene description or fallbacks.  We special-case
6317     // it upfront here, since the Composer mechanism cannot deal with it.  We'd
6318     // like to consider remove "attribute value" fields from the set of stuff
6319     // that Usd considers to be "metadata", in which case we can remove this.
6320     if (obj.Is<UsdAttribute>()) {
6321         if (fieldName == SdfFieldKeys->TimeSamples) {
6322             SdfTimeSampleMap timeSamples;
6323             if (_GetTimeSampleMap(obj.As<UsdAttribute>(), &timeSamples)) {
6324                 *result = timeSamples;
6325                 return true;
6326             }
6327             return false;
6328         }
6329     }
6330 
6331     UntypedValueComposer composer(result);
6332     return _GetMetadataImpl(obj, fieldName, keyPath, useFallbacks, &composer);
6333 }
6334 
6335 bool
_GetStrongestResolvedMetadata(const UsdObject & obj,const TfToken & fieldName,const TfToken & keyPath,bool useFallbacks,SdfAbstractDataValue * result) const6336 UsdStage::_GetStrongestResolvedMetadata(const UsdObject &obj,
6337                                         const TfToken& fieldName,
6338                                         const TfToken &keyPath,
6339                                         bool useFallbacks,
6340                                         SdfAbstractDataValue* result) const
6341 {
6342     StrongestValueComposer composer(result);
6343     return _GetMetadataImpl(obj, fieldName, keyPath, useFallbacks, &composer);
6344 }
6345 
6346 template <class T>
6347 bool
_GetTypeSpecificResolvedMetadata(const UsdObject & obj,const TfToken & fieldName,const TfToken & keyPath,bool useFallbacks,T * result) const6348 UsdStage::_GetTypeSpecificResolvedMetadata(const UsdObject &obj,
6349                                            const TfToken& fieldName,
6350                                            const TfToken &keyPath,
6351                                            bool useFallbacks,
6352                                            T* result) const
6353 {
6354     SdfAbstractDataTypedValue<T> out(result);
6355     TypeSpecificValueComposer<T> composer(&out);
6356     return _GetMetadataImpl(obj, fieldName, keyPath, useFallbacks, &composer);
6357 }
6358 
6359 // This specialization for SdfTimeSampleMap is still required because of the
6360 // attribute time samples hack.
6361 template <>
6362 bool
_GetTypeSpecificResolvedMetadata(const UsdObject & obj,const TfToken & fieldName,const TfToken & keyPath,bool useFallbacks,SdfTimeSampleMap * result) const6363 UsdStage::_GetTypeSpecificResolvedMetadata(const UsdObject &obj,
6364                                            const TfToken& fieldName,
6365                                            const TfToken &keyPath,
6366                                            bool useFallbacks,
6367                                            SdfTimeSampleMap* result) const
6368 {
6369     TRACE_FUNCTION();
6370 
6371     // XXX: HORRIBLE HACK.  Special-case timeSamples for now, since its
6372     // resulting value is a complicated function influenced by "model clips",
6373     // not a single value from scene description or fallbacks.  We special-case
6374     // it upfront here, since the Composer mechanism cannot deal with it.  We'd
6375     // like to consider remove "attribute value" fields from the set of stuff
6376     // that Usd considers to be "metadata", in which case we can remove this.
6377     if (obj.Is<UsdAttribute>()) {
6378         if (fieldName == SdfFieldKeys->TimeSamples) {
6379             return _GetTimeSampleMap(obj.As<UsdAttribute>(), result);
6380         }
6381     }
6382 
6383     SdfAbstractDataTypedValue<SdfTimeSampleMap> out(result);
6384     TypeSpecificValueComposer<SdfTimeSampleMap> composer(&out);
6385     return _GetMetadataImpl(obj, fieldName, keyPath, useFallbacks, &composer);
6386 }
6387 
6388 template <class Composer>
6389 void
_GetAttrTypeImpl(const UsdAttribute & attr,const TfToken & fieldName,bool useFallbacks,Composer * composer) const6390 UsdStage::_GetAttrTypeImpl(const UsdAttribute &attr,
6391                            const TfToken &fieldName,
6392                            bool useFallbacks,
6393                            Composer *composer) const
6394 {
6395     TRACE_FUNCTION();
6396     composer->ConsumeUsdFallback(
6397         attr._Prim()->GetPrimDefinition(),
6398         attr.GetName(), fieldName, TfToken());
6399     if (composer->IsDone()) {
6400         return;
6401     }
6402 
6403     // Fall back to general metadata composition.
6404     _GetGeneralMetadataImpl(attr, fieldName, TfToken(), useFallbacks, composer);
6405 }
6406 
6407 template <class Composer>
6408 void
_GetAttrVariabilityImpl(const UsdAttribute & attr,bool useFallbacks,Composer * composer) const6409 UsdStage::_GetAttrVariabilityImpl(const UsdAttribute &attr, bool useFallbacks,
6410                                   Composer *composer) const
6411 {
6412     TRACE_FUNCTION();
6413     composer->ConsumeUsdFallback(
6414         attr._Prim()->GetPrimDefinition(),
6415         attr.GetName(), SdfFieldKeys->Variability, TfToken());
6416     if (composer->IsDone()) {
6417         return;
6418     }
6419 
6420     // Otherwise variability is determined by the *weakest* authored opinion.
6421     // Walk authored scene description in reverse order.
6422     const TfToken &attrName = attr.GetName();
6423     TF_REVERSE_FOR_ALL(itr, attr.GetPrim().GetPrimIndex().GetNodeRange()) {
6424         if (itr->IsInert() || !itr->HasSpecs())
6425             continue;
6426         SdfPath specPath = itr->GetPath().AppendProperty(attrName);
6427         TF_REVERSE_FOR_ALL(layerIt, itr->GetLayerStack()->GetLayers()) {
6428             composer->ConsumeAuthored(
6429                 *itr, *layerIt, specPath, SdfFieldKeys->Variability, TfToken());
6430             if (composer->IsDone())
6431                 return;
6432         }
6433     }
6434 }
6435 
6436 template <class Composer>
6437 void
_GetPropCustomImpl(const UsdProperty & prop,bool useFallbacks,Composer * composer) const6438 UsdStage::_GetPropCustomImpl(const UsdProperty &prop, bool useFallbacks,
6439                              Composer *composer) const
6440 {
6441     TRACE_FUNCTION();
6442     // Custom is composed as true if there is no property definition and it is
6443     // true anywhere in the stack of opinions.
6444     if (_GetSchemaPropertySpec(prop)) {
6445         composer->ConsumeUsdFallback(
6446             prop._Prim()->GetPrimDefinition(),
6447             prop.GetName(),
6448             SdfFieldKeys->Custom, TfToken());
6449         return;
6450     }
6451 
6452     const TfToken &propName = prop.GetName();
6453 
6454     TF_REVERSE_FOR_ALL(itr, prop.GetPrim().GetPrimIndex().GetNodeRange()) {
6455         if (itr->IsInert() || !itr->HasSpecs())
6456             continue;
6457 
6458         SdfPath specPath = itr->GetPath().AppendProperty(propName);
6459         TF_REVERSE_FOR_ALL(layerIt, itr->GetLayerStack()->GetLayers()) {
6460             composer->ConsumeAuthored(
6461                 *itr, *layerIt, specPath, SdfFieldKeys->Custom, TfToken());
6462             if (composer->IsDone())
6463                 return;
6464         }
6465     }
6466 }
6467 
6468 template <class Composer>
6469 static void
_GetPrimTypeNameImpl(Usd_PrimDataConstPtr primData,bool useFallbacks,Composer * composer)6470 _GetPrimTypeNameImpl(Usd_PrimDataConstPtr primData,
6471                      bool useFallbacks, Composer *composer)
6472 {
6473     TRACE_FUNCTION();
6474     for (Usd_Resolver res(&primData->GetPrimIndex());
6475          res.IsValid(); res.NextLayer()) {
6476         TfToken tok;
6477         if (res.GetLayer()->HasField(
6478                 res.GetLocalPath(), SdfFieldKeys->TypeName, &tok)) {
6479             if (!tok.IsEmpty() && tok != SdfTokens->AnyTypeToken) {
6480                 composer->ConsumeAuthored(
6481                     res.GetNode(), res.GetLayer(), res.GetLocalPath(),
6482                     SdfFieldKeys->TypeName, TfToken());
6483                 if (composer->IsDone())
6484                     return;
6485             }
6486         }
6487     }
6488 }
6489 
6490 template <class Composer>
6491 static bool
_GetPrimSpecifierImpl(Usd_PrimDataConstPtr primData,bool useFallbacks,Composer * composer)6492 _GetPrimSpecifierImpl(Usd_PrimDataConstPtr primData,
6493                       bool useFallbacks, Composer *composer)
6494 {
6495     // The pseudo-root and instance prototype prims are always defined -- see
6496     // Usd_PrimData for details. Since the fallback for specifier is 'over', we
6497     // have to handle these prims specially here.
6498     if (primData->GetPath().IsAbsoluteRootPath() || primData->IsPrototype()) {
6499         composer->ConsumeExplicitValue(SdfSpecifierDef);
6500         return true;
6501     }
6502 
6503     TRACE_FUNCTION();
6504     // Compose specifier.  The result is not given by simple strength order.  A
6505     // defining specifier is always stronger than a non-defining specifier.
6506     // Also, perhaps surprisingly, a class specifier due to a direct inherit is
6507     // weaker than any other defining specifier.  This handles cases like the
6508     // following:
6509     //
6510     // -- root.file -----------------------------------------------------------
6511     //   class "C" {}
6512     //   over "A" (references = @other.file@</B>) {}
6513     //
6514     // -- other.file ----------------------------------------------------------
6515     //   class "C" {}
6516     //   def "B" (inherits = </C>) {}
6517     //
6518     // Here /A references /B in other.file, and /B inherits class /C.
6519     // The strength order of specifiers for /A from strong-to-weak is:
6520     //
6521     // 1. 'over'  (from /A)
6522     // 2. 'class' (from /C in root)
6523     // 3. 'def'   (from /B)
6524     // 4. 'class' (from /C in other)
6525     //
6526     // If we were to pick the strongest defining specifier, /A would be a class.
6527     // But that's wrong: /A should be a 'def'.  Inheriting a class should not
6528     // make the instance a class.  Classness should not be inherited.  Treating
6529     // 'class' specifiers due to direct inherits as weaker than all other
6530     // defining specifiers avoids this problem.
6531 
6532     // These are ordered so stronger strengths are numerically larger.
6533     enum _SpecifierStrength {
6534         _SpecifierStrengthNonDefining,
6535         _SpecifierStrengthDirectlyInheritedClass,
6536         _SpecifierStrengthDefining
6537     };
6538 
6539     boost::optional<SdfSpecifier> specifier;
6540     _SpecifierStrength strength = _SpecifierStrengthNonDefining;
6541 
6542     // Iterate over all prims, strongest to weakest.
6543     SdfSpecifier curSpecifier = SdfSpecifierOver;
6544 
6545     Usd_Resolver::Position specPos;
6546 
6547     const PcpPrimIndex &primIndex = primData->GetPrimIndex();
6548     for (Usd_Resolver res(&primIndex); res.IsValid(); res.NextLayer()) {
6549         // Get specifier and its strength from this prim.
6550         _SpecifierStrength curStrength = _SpecifierStrengthDefining;
6551         if (res.GetLayer()->HasField(
6552                 res.GetLocalPath(), SdfFieldKeys->Specifier, &curSpecifier)) {
6553             specPos = res.GetPosition();
6554 
6555             if (SdfIsDefiningSpecifier(curSpecifier)) {
6556                 // Compute strength.
6557                 if (curSpecifier == SdfSpecifierClass) {
6558                     // See if this excerpt is due to direct inherits.  Walk up
6559                     // the excerpt tree looking for a direct inherit.  If we
6560                     // find one set the strength and stop.
6561                     for (PcpNodeRef node = res.GetNode();
6562                          node; node = node.GetParentNode()) {
6563 
6564                         if (PcpIsInheritArc(node.GetArcType()) &&
6565                             !node.IsDueToAncestor()) {
6566                             curStrength =
6567                                 _SpecifierStrengthDirectlyInheritedClass;
6568                             break;
6569                         }
6570                     }
6571 
6572                 }
6573             }
6574             else {
6575                 // Strength is _SpecifierStrengthNonDefining and can't be
6576                 // stronger than the current strength so there's no need to do
6577                 // the check below.
6578                 continue;
6579             }
6580         }
6581         else {
6582             // Variant PrimSpecs don't have a specifier field, continue looking
6583             // for a specifier.
6584             continue;
6585         }
6586 
6587         // Use the specifier if it's stronger.
6588         if (curStrength > strength) {
6589             specifier = curSpecifier;
6590             strength = curStrength;
6591 
6592             // We can stop as soon as we find a specifier with the strongest
6593             // strength.
6594             if (strength == _SpecifierStrengthDefining)
6595                 break;
6596         }
6597     }
6598 
6599     // Verify we found *something*.  We should never have PrimData without at
6600     // least one PrimSpec, and 'specifier' is required, so it must be present.
6601     if (TF_VERIFY(specPos.GetLayer(), "No PrimSpecs for '%s'",
6602                   primData->GetPath().GetText())) {
6603         // Let the composer see the deciding opinion.
6604         composer->ConsumeAuthored(
6605             specPos.GetNode(), specPos.GetLayer(),
6606             specPos.GetLocalPath(),
6607             SdfFieldKeys->Specifier, TfToken());
6608     }
6609     return true;
6610 }
6611 
6612 template <class ListOpType, class Composer>
6613 static bool
_GetListOpMetadataImpl(Usd_PrimDataConstPtr primData,const TfToken & propName,const TfToken & fieldName,bool useFallbacks,Usd_Resolver * res,Composer * composer)6614 _GetListOpMetadataImpl(Usd_PrimDataConstPtr primData,
6615                        const TfToken &propName,
6616                        const TfToken &fieldName,
6617                        bool useFallbacks,
6618                        Usd_Resolver *res,
6619                        Composer *composer)
6620 {
6621     // Collect all list op opinions for this field.
6622     std::vector<ListOpType> listOps;
6623 
6624     SdfPath specPath = res->GetLocalPath(propName);
6625 
6626     for (bool isNewNode = false; res->IsValid(); isNewNode = res->NextLayer()) {
6627         if (isNewNode)
6628             specPath = res->GetLocalPath(propName);
6629 
6630         // Consume an authored opinion here, if one exists.
6631         ListOpType op;
6632         if (res->GetLayer()->HasField(specPath, fieldName, &op)) {
6633             listOps.emplace_back(op);
6634         }
6635     }
6636 
6637     if (useFallbacks) {
6638         ListOpType fallbackListOp;
6639         SdfAbstractDataTypedValue<ListOpType> out(&fallbackListOp);
6640         TypeSpecificValueComposer<ListOpType> composer(&out);
6641         if (_GetFallbackMetadataImpl(
6642                 primData, propName, fieldName, TfToken(), &composer)) {
6643             listOps.emplace_back(fallbackListOp);
6644         }
6645     }
6646 
6647     // Bake the result of applying the list ops into a single explicit
6648     // list op.
6649     if (!listOps.empty()) {
6650         typename ListOpType::ItemVector items;
6651         std::for_each(
6652             listOps.crbegin(), listOps.crend(),
6653             [&items](const ListOpType& op) { op.ApplyOperations(&items); });
6654 
6655         ListOpType bakedListOp;
6656         bakedListOp.SetExplicitItems(std::move(items));
6657         composer->ConsumeExplicitValue(bakedListOp);
6658         return true;
6659     }
6660 
6661     return false;
6662 }
6663 
6664 template <class Composer>
6665 bool
_GetSpecialPropMetadataImpl(const UsdObject & obj,const TfToken & fieldName,const TfToken & keyPath,bool useFallbacks,Composer * composer) const6666 UsdStage::_GetSpecialPropMetadataImpl(const UsdObject &obj,
6667                                       const TfToken &fieldName,
6668                                       const TfToken &keyPath,
6669                                       bool useFallbacks,
6670                                       Composer *composer) const
6671 {
6672     // Dispatch to special-case composition rules based on type and field.
6673     // Return true if the given field was handled, false otherwise.
6674     if (obj.Is<UsdAttribute>()) {
6675         if (fieldName == SdfFieldKeys->TypeName) {
6676             _GetAttrTypeImpl(
6677                 obj.As<UsdAttribute>(), fieldName, useFallbacks, composer);
6678             return true;
6679         } else if (fieldName == SdfFieldKeys->Variability) {
6680             _GetAttrVariabilityImpl(
6681                 obj.As<UsdAttribute>(), useFallbacks, composer);
6682             return true;
6683         }
6684     }
6685     if (fieldName == SdfFieldKeys->Custom) {
6686         _GetPropCustomImpl(obj.As<UsdProperty>(), useFallbacks, composer);
6687         return true;
6688     }
6689     return false;
6690 }
6691 
6692 template <class Composer>
6693 static bool
_GetSpecialPrimMetadataImpl(Usd_PrimDataConstPtr primData,const TfToken & fieldName,const TfToken & keyPath,bool useFallbacks,Composer * composer)6694 _GetSpecialPrimMetadataImpl(Usd_PrimDataConstPtr primData,
6695                             const TfToken &fieldName,
6696                             const TfToken &keyPath,
6697                             bool useFallbacks,
6698                             Composer *composer)
6699 {
6700     // Dispatch to special-case composition rules based on type and field.
6701     // Return true if the given field was handled, false otherwise.
6702     if (fieldName == SdfFieldKeys->TypeName) {
6703         _GetPrimTypeNameImpl(primData, useFallbacks, composer);
6704         return true;
6705     } else if (fieldName == SdfFieldKeys->Specifier) {
6706         _GetPrimSpecifierImpl(primData, useFallbacks, composer);
6707         return true;
6708     } else if (fieldName == SdfFieldKeys->Kind) {
6709         // XXX: We do not not respect fallback kind values during
6710         // Usd_PrimData composition (see _GetKind), but we do allow
6711         // fallback values here to maintain existing behavior. However,
6712         // we may want to force the useFallbacks flag to false here for
6713         // consistency.
6714         _GetPrimKindImpl(primData, useFallbacks, composer);
6715         return true;
6716     } else if (fieldName == SdfFieldKeys->Active) {
6717         // XXX: See comment in the handling of 'kind' re: fallback values.
6718         _GetPrimActiveImpl(primData, useFallbacks, composer);
6719         return true;
6720     }
6721 
6722     return false;
6723 }
6724 
6725 template <class Composer>
6726 bool
_GetMetadataImpl(const UsdObject & obj,const TfToken & fieldName,const TfToken & keyPath,bool useFallbacks,Composer * composer) const6727 UsdStage::_GetMetadataImpl(
6728     const UsdObject &obj,
6729     const TfToken& fieldName,
6730     const TfToken& keyPath,
6731     bool useFallbacks,
6732     Composer *composer) const
6733 {
6734     // XXX: references, inherit paths, variant selection currently unhandled.
6735     TfErrorMark m;
6736 
6737     // Handle special cases.
6738     if (obj.Is<UsdProperty>()) {
6739         if (_GetSpecialPropMetadataImpl(
6740                 obj, fieldName, keyPath, useFallbacks, composer)) {
6741             return composer->IsDone() && m.IsClean();
6742         }
6743     } else if (obj.Is<UsdPrim>()) {
6744         // If the prim is the pseudo root, we have a special metadata
6745         // composition to perform as the pseudoroot only composes metadata
6746         // opinions from the session layer and root layer.
6747         if (obj._Prim()->IsPseudoRoot()) {
6748             // Note that this function returns true if an opinion was found so
6749             // we don't need to check composer->IsDone(). IsDone will always
6750             // return false for dictionary metadata on the pseudo root since
6751             // we don't have fallbacks.
6752             return _ComposePseudoRootMetadataImpl(
6753                 get_pointer(obj._Prim()), fieldName, keyPath,
6754                 _rootLayer, _sessionLayer, composer) && m.IsClean();
6755         } else if (_GetSpecialPrimMetadataImpl(
6756             get_pointer(obj._Prim()), fieldName, keyPath, useFallbacks,
6757             composer)) {
6758             return composer->IsDone() && m.IsClean();
6759         }
6760     }
6761 
6762     return _GetGeneralMetadataImpl(
6763         obj, fieldName, keyPath, useFallbacks, composer) && m.IsClean();
6764 }
6765 
6766 template <class Composer>
6767 bool
_GetGeneralMetadataImpl(const UsdObject & obj,const TfToken & fieldName,const TfToken & keyPath,bool useFallbacks,Composer * composer) const6768 UsdStage::_GetGeneralMetadataImpl(const UsdObject &obj,
6769                                   const TfToken& fieldName,
6770                                   const TfToken& keyPath,
6771                                   bool useFallbacks,
6772                                   Composer *composer) const
6773 {
6774     const Usd_PrimDataConstPtr primData = get_pointer(obj._Prim());
6775 
6776     static TfToken empty;
6777     const TfToken &propName = obj.Is<UsdProperty>() ? obj.GetName() : empty;
6778 
6779     Usd_Resolver resolver(&primData->GetPrimIndex());
6780     if (!_ComposeGeneralMetadataImpl(
6781             primData, propName, fieldName, keyPath, useFallbacks, &resolver,
6782             composer)) {
6783         return false;
6784     }
6785 
6786     if (Composer::ProducesValue) {
6787         // If the metadata value produced by the composer is a type that
6788         // requires specific composition behavior, dispatch to the appropriate
6789         // helper. Pass along the same resolver so that the helper can start
6790         // from where _ComposeGeneralMetadataImpl found the first metadata
6791         // value.
6792         const std::type_info& valueTypeId(composer->GetHeldTypeid());
6793         if (valueTypeId == typeid(SdfIntListOp)) {
6794             return _GetListOpMetadataImpl<SdfIntListOp>(
6795                 primData, propName, fieldName, useFallbacks, &resolver,
6796                 composer);
6797         }
6798         else if (valueTypeId == typeid(SdfInt64ListOp)) {
6799             return _GetListOpMetadataImpl<SdfInt64ListOp>(
6800                 primData, propName, fieldName, useFallbacks, &resolver,
6801                 composer);
6802         }
6803         else if (valueTypeId == typeid(SdfUIntListOp)) {
6804             return _GetListOpMetadataImpl<SdfUIntListOp>(
6805                 primData, propName, fieldName, useFallbacks, &resolver,
6806                 composer);
6807         }
6808         else if (valueTypeId == typeid(SdfUInt64ListOp)) {
6809             return _GetListOpMetadataImpl<SdfUInt64ListOp>(
6810                 primData, propName, fieldName, useFallbacks, &resolver,
6811                 composer);
6812         }
6813         else if (valueTypeId == typeid(SdfStringListOp)) {
6814             return _GetListOpMetadataImpl<SdfStringListOp>(
6815                 primData, propName, fieldName, useFallbacks, &resolver,
6816                 composer);
6817         }
6818         else if (valueTypeId == typeid(SdfTokenListOp)) {
6819             return _GetListOpMetadataImpl<SdfTokenListOp>(
6820                 primData, propName, fieldName, useFallbacks, &resolver,
6821                 composer);
6822         }
6823     }
6824 
6825     return true;
6826 }
6827 
6828 bool
_HasMetadata(const UsdObject & obj,const TfToken & fieldName,const TfToken & keyPath,bool useFallbacks) const6829 UsdStage::_HasMetadata(const UsdObject &obj, const TfToken& fieldName,
6830                        const TfToken &keyPath, bool useFallbacks) const
6831 {
6832     ExistenceComposer composer;
6833     _GetMetadataImpl(obj, fieldName, keyPath, useFallbacks, &composer);
6834     return composer.IsDone();
6835 }
6836 
6837 static
6838 SdfSpecType
_ListMetadataFieldsImpl(Usd_PrimDataConstPtr primData,const TfToken & propName,bool useFallbacks,TfTokenVector * result)6839 _ListMetadataFieldsImpl(Usd_PrimDataConstPtr primData,
6840                         const TfToken &propName,
6841                         bool useFallbacks,
6842                         TfTokenVector *result)
6843 {
6844     TRACE_FUNCTION();
6845 
6846     Usd_Resolver res(&primData->GetPrimIndex());
6847     SdfPath specPath = res.GetLocalPath(propName);
6848     PcpNodeRef lastNode = res.GetNode();
6849     SdfSpecType specType = SdfSpecTypeUnknown;
6850 
6851     const UsdPrimDefinition &primDef = primData->GetPrimDefinition();
6852 
6853     // If this is a builtin property, determine specType from the definition.
6854     if (!propName.IsEmpty()) {
6855         specType = primDef.GetSpecType(propName);
6856     }
6857 
6858     // Insert authored fields, discovering spec type along the way.
6859     for (; res.IsValid(); res.NextLayer()) {
6860         if (res.GetNode() != lastNode) {
6861             lastNode = res.GetNode();
6862             specPath = res.GetLocalPath(propName);
6863         }
6864         const SdfLayerRefPtr& layer = res.GetLayer();
6865         if (specType == SdfSpecTypeUnknown)
6866             specType = layer->GetSpecType(specPath);
6867 
6868         for (const auto& fieldName : layer->ListFields(specPath)) {
6869             if (!_IsPrivateFieldKey(fieldName))
6870                 result->push_back(fieldName);
6871         }
6872     }
6873 
6874     // If including fallbacks, add any defined metadata fields from the prim
6875     // definition for the property (or the prim if the prop name is empty).
6876     if (useFallbacks) {
6877         const TfTokenVector fallbackFields = propName.IsEmpty() ?
6878             primDef.ListMetadataFields() :
6879             primDef.ListPropertyMetadataFields(propName);
6880         result->insert(result->end(),
6881                        fallbackFields.begin(), fallbackFields.end());
6882     }
6883 
6884     return specType;
6885 }
6886 
6887 static
6888 SdfSpecType
_ListPseudoRootMetadataFieldsImpl(Usd_PrimDataConstPtr primData,const SdfLayerRefPtr & rootLayer,const SdfLayerRefPtr & sessionLayer,TfTokenVector * result)6889 _ListPseudoRootMetadataFieldsImpl(Usd_PrimDataConstPtr primData,
6890                                   const SdfLayerRefPtr &rootLayer,
6891                                   const SdfLayerRefPtr &sessionLayer,
6892                                   TfTokenVector *result)
6893 {
6894     TRACE_FUNCTION();
6895 
6896     const SdfPath &specPath = SdfPath::AbsoluteRootPath();
6897     PcpNodeRef node = primData->GetPrimIndex().GetRootNode();
6898 
6899     // If we a have a session layer and it isn't muted, get its authored layer
6900     // metadata fields. The session layer will be the first layer in the
6901     // layer stack unless it is muted.
6902     if (sessionLayer &&
6903         node.GetLayerStack()->GetLayers().front() == sessionLayer) {
6904         for (const auto& fieldName : sessionLayer->ListFields(specPath)) {
6905             if (!_IsPrivateFieldKey(fieldName)) {
6906                 result->push_back(fieldName);
6907             }
6908         }
6909     }
6910 
6911     // Get all authored layer metadata fields from the root layer (which can't
6912     // be muted).
6913     for (const auto& fieldName : rootLayer->ListFields(specPath)) {
6914         if (!_IsPrivateFieldKey(fieldName)) {
6915             result->push_back(fieldName);
6916         }
6917     }
6918 
6919     return SdfSpecTypePseudoRoot;
6920 }
6921 
6922 TfTokenVector
_ListMetadataFields(const UsdObject & obj,bool useFallbacks) const6923 UsdStage::_ListMetadataFields(const UsdObject &obj, bool useFallbacks) const
6924 {
6925     TRACE_FUNCTION();
6926 
6927     TfTokenVector result;
6928 
6929     SdfSpecType specType = SdfSpecTypeUnknown;
6930     Usd_PrimDataConstPtr primData = get_pointer(obj._Prim());
6931     if (obj.Is<UsdProperty>()) {
6932         // List metadata fields for property
6933         specType = _ListMetadataFieldsImpl(
6934             primData, obj.GetName(), useFallbacks, &result);
6935     } else if (obj._Prim()->IsPseudoRoot()) {
6936         // Custom implementation for listing metadata for the pseudo root.
6937         specType = _ListPseudoRootMetadataFieldsImpl(
6938             primData, _rootLayer, _sessionLayer, &result);
6939     } else {
6940         // List metadata fields for non pseudo root prims.
6941         specType = _ListMetadataFieldsImpl(
6942             primData, TfToken(), useFallbacks, &result);
6943     }
6944 
6945     // Insert required fields for spec type.
6946     const SdfSchema::SpecDefinition* specDef = nullptr;
6947     specDef = SdfSchema::GetInstance().GetSpecDefinition(specType);
6948     if (specDef) {
6949         for (const auto& fieldName : specDef->GetRequiredFields()) {
6950             if (!_IsPrivateFieldKey(fieldName))
6951                 result.push_back(fieldName);
6952         }
6953     }
6954 
6955     // Sort & remove duplicate fields.
6956     std::sort(result.begin(), result.end(), TfDictionaryLessThan());
6957     result.erase(std::unique(result.begin(), result.end()), result.end());
6958 
6959     return result;
6960 }
6961 
6962 void
_GetAllMetadata(const UsdObject & obj,bool useFallbacks,UsdMetadataValueMap * resultMap,bool anchorAssetPathsOnly) const6963 UsdStage::_GetAllMetadata(const UsdObject &obj,
6964                           bool useFallbacks,
6965                           UsdMetadataValueMap* resultMap,
6966                           bool anchorAssetPathsOnly) const
6967 {
6968     TRACE_FUNCTION();
6969 
6970     UsdMetadataValueMap &result = *resultMap;
6971 
6972     TfTokenVector fieldNames = _ListMetadataFields(obj, useFallbacks);
6973     for (const auto& fieldName : fieldNames) {
6974         VtValue val;
6975         UntypedValueComposer composer(&val, anchorAssetPathsOnly);
6976         _GetMetadataImpl(obj, fieldName, TfToken(), useFallbacks, &composer);
6977         result[fieldName] = val;
6978     }
6979 }
6980 
6981 // --------------------------------------------------------------------- //
6982 // Default & TimeSample Resolution
6983 // --------------------------------------------------------------------- //
6984 
6985 static bool
_ClipsApplyToLayerStackSite(const Usd_ClipSetRefPtr & clips,const PcpLayerStackPtr & layerStack,const SdfPath & primPathInLayerStack)6986 _ClipsApplyToLayerStackSite(
6987     const Usd_ClipSetRefPtr& clips,
6988     const PcpLayerStackPtr& layerStack, const SdfPath& primPathInLayerStack)
6989 {
6990     return (layerStack == clips->sourceLayerStack
6991             && primPathInLayerStack.HasPrefix(clips->sourcePrimPath));
6992 }
6993 
6994 static bool
_ClipsApplyToNode(const Usd_ClipSetRefPtr & clips,const PcpNodeRef & node)6995 _ClipsApplyToNode(
6996     const Usd_ClipSetRefPtr& clips,
6997     const PcpNodeRef& node)
6998 {
6999     return (node.GetLayerStack() == clips->sourceLayerStack
7000             && node.GetPath().HasPrefix(clips->sourcePrimPath));
7001 }
7002 
7003 static bool
_ClipsContainValueForAttribute(const Usd_ClipSetRefPtr & clips,const SdfPath & attrSpecPath)7004 _ClipsContainValueForAttribute(
7005     const Usd_ClipSetRefPtr& clips,
7006     const SdfPath& attrSpecPath)
7007 {
7008     // Only look for samples in clips for attributes that are
7009     // marked as varying in the clip manifest (if one is present).
7010     // This gives users a way to indicate that an attribute will
7011     // never have samples in a clip, which can help performance.
7012     //
7013     // We normally do not consider variability during value
7014     // resolution to avoid the cost of composing variability on
7015     // each value fetch. We can use it here because we're only
7016     // fetching it from a single layer, which should be cheap.
7017     // This is also convenient for users, since it allows them
7018     // to reuse assets that may have both uniform and varying
7019     // attributes as manifests.
7020     if (clips->manifestClip) {
7021         SdfVariability attrVariability = SdfVariabilityUniform;
7022         if (clips->manifestClip->HasField(
7023                 attrSpecPath, SdfFieldKeys->Variability, &attrVariability)
7024             && attrVariability == SdfVariabilityVarying) {
7025             return true;
7026         }
7027     }
7028     return false;
7029 }
7030 
7031 static
7032 const std::vector<Usd_ClipSetRefPtr>
_GetClipsThatApplyToNode(const std::vector<Usd_ClipSetRefPtr> & clipsAffectingPrim,const PcpNodeRef & node,const SdfPath & specPath)7033 _GetClipsThatApplyToNode(
7034     const std::vector<Usd_ClipSetRefPtr>& clipsAffectingPrim,
7035     const PcpNodeRef& node,
7036     const SdfPath& specPath)
7037 {
7038     std::vector<Usd_ClipSetRefPtr> relevantClips;
7039 
7040     for (const auto& localClips : clipsAffectingPrim) {
7041         if (_ClipsApplyToNode(localClips, node)
7042             && _ClipsContainValueForAttribute(localClips, specPath)) {
7043             relevantClips.push_back(localClips);
7044         }
7045     }
7046 
7047     return relevantClips;
7048 }
7049 
7050 static bool
_HasTimeSamples(const SdfLayerRefPtr & source,const SdfPath & specPath,const double * time=nullptr,double * lower=nullptr,double * upper=nullptr)7051 _HasTimeSamples(const SdfLayerRefPtr& source,
7052                 const SdfPath& specPath,
7053                 const double* time = nullptr,
7054                 double* lower = nullptr, double* upper = nullptr)
7055 {
7056     if (time) {
7057         // If caller wants bracketing time samples as well, we can just use
7058         // GetBracketingTimeSamplesForPath. If no samples exist, this should
7059         // return false.
7060         return source->GetBracketingTimeSamplesForPath(
7061             specPath, *time, lower, upper);
7062     }
7063 
7064     return source->GetNumTimeSamplesForPath(specPath) > 0;
7065 }
7066 
7067 static bool
_HasTimeSamples(const Usd_ClipSetRefPtr & sourceClips,const SdfPath & specPath,const double * time=nullptr,double * lower=nullptr,double * upper=nullptr)7068 _HasTimeSamples(const Usd_ClipSetRefPtr& sourceClips,
7069                 const SdfPath& specPath,
7070                 const double* time = nullptr,
7071                 double* lower = nullptr, double* upper = nullptr)
7072 {
7073     // Bail out immediately if this clip set does not contain values
7074     // for this attribute.
7075     if (!_ClipsContainValueForAttribute(sourceClips, specPath)) {
7076         return false;
7077     }
7078 
7079     if (time) {
7080         return sourceClips->GetBracketingTimeSamplesForPath(
7081             specPath, *time, lower, upper);
7082     }
7083 
7084     // Since this clip set has declared it contains values for this
7085     // attribute, we always return true.
7086     return true;
7087 }
7088 
7089 // Helper for getting the fully resolved value from an attribute generically
7090 // for all value types for use by _GetValue and _GetValueForResolveInfo.
7091 template <class T>
7092 struct Usd_AttrGetValueHelper {
7093 
7094 public:
7095     // Get the value at time for the attribute. The getValueImpl function is
7096     // templated for sharing of this functionality between _GetValue and
7097     // _GetValueForResolveInfo.
7098     template <class Fn>
GetValueUsd_AttrGetValueHelper7099     static bool GetValue(const UsdStage &stage, UsdTimeCode time,
7100                          const UsdAttribute &attr, T* result,
7101                          const Fn &getValueImpl)
7102     {
7103         // Special case if time is default: we can grab the value from the
7104         // metadata. This value will be fully resolved already.
7105         if (time.IsDefault()) {
7106             SdfAbstractDataTypedValue<T> out(result);
7107             TypeSpecificValueComposer<T> composer(&out);
7108             bool valueFound = stage._GetMetadataImpl(
7109                 attr, SdfFieldKeys->Default, TfToken(),
7110                 /*useFallbacks=*/true, &composer);
7111 
7112             return valueFound &&
7113                 (!Usd_ClearValueIfBlocked<SdfAbstractDataValue>(&out));
7114         }
7115 
7116         return _GetResolvedValue(stage, time, attr, result, getValueImpl);
7117     }
7118 
7119 private:
7120     // Metafunction for selecting the appropriate interpolation object if the
7121     // given value type supports linear interpolation.
7122     struct _SelectInterpolator
7123         : public boost::mpl::if_c<
7124               UsdLinearInterpolationTraits<T>::isSupported,
7125               Usd_LinearInterpolator<T>,
7126               Usd_HeldInterpolator<T> > { };
7127 
7128     // Gets the attribute value from the implementation with appropriate
7129     // interpolation. In the case of value types that have type specific value
7130     // resolution (like SdfAssetPath and SdfTimeCode), the value returned from
7131     // from this is NOT fully resolved yet.
7132     template <class Fn>
_GetValueFromImplUsd_AttrGetValueHelper7133     static bool _GetValueFromImpl(const UsdStage &stage,
7134                                   UsdTimeCode time, const UsdAttribute &attr,
7135                                   T* result, const Fn &getValueImpl)
7136     {
7137         SdfAbstractDataTypedValue<T> out(result);
7138 
7139         if (stage._interpolationType == UsdInterpolationTypeLinear) {
7140             typedef typename _SelectInterpolator::type _Interpolator;
7141             _Interpolator interpolator(result);
7142             return getValueImpl(stage, time, attr, &interpolator, &out);
7143         };
7144 
7145         Usd_HeldInterpolator<T> interpolator(result);
7146         return getValueImpl(stage, time, attr, &interpolator, &out);
7147     }
7148 
7149     // Gets the fully resolved value for the attribute.
7150     template <class Fn>
_GetResolvedValueUsd_AttrGetValueHelper7151     static bool _GetResolvedValue(const UsdStage &stage,
7152                                   UsdTimeCode time, const UsdAttribute &attr,
7153                                   T* result, const Fn &getValueImpl)
7154     {
7155         if (_GetValueFromImpl(stage, time, attr, result, getValueImpl)) {
7156             // Do the the type specific value resolution on the result. For
7157             // most types _ResolveValue does nothing.
7158             _ResolveValue(stage, time, attr, result);
7159             return true;
7160         }
7161         return false;
7162     }
7163 
7164     // Performs type specific value resolution.
_ResolveValueUsd_AttrGetValueHelper7165     static void _ResolveValue(
7166         const UsdStage &stage, UsdTimeCode time, const UsdAttribute &attr,
7167         T* result)
7168     {
7169         // Do nothing for types without type specific value resolution.
7170         static_assert(!UsdStage::_HasTypeSpecificResolution<T>::value,
7171                       "Value types with type specific value resolution must "
7172                       "specialize Usd_AttrGetValueHelper::_ResolveValue");
7173     }
7174 };
7175 
7176 // Specializations implementing _ResolveValue for types with type specific
7177 // value resolution.
7178 template <>
_ResolveValue(const UsdStage & stage,UsdTimeCode time,const UsdAttribute & attr,SdfAssetPath * result)7179 void Usd_AttrGetValueHelper<SdfAssetPath>::_ResolveValue(
7180     const UsdStage &stage, UsdTimeCode time, const UsdAttribute &attr,
7181     SdfAssetPath* result)
7182 {
7183     stage._MakeResolvedAssetPaths(time, attr, result, 1);
7184 }
7185 
7186 template <>
_ResolveValue(const UsdStage & stage,UsdTimeCode time,const UsdAttribute & attr,VtArray<SdfAssetPath> * result)7187 void Usd_AttrGetValueHelper<VtArray<SdfAssetPath>>::_ResolveValue(
7188     const UsdStage &stage, UsdTimeCode time, const UsdAttribute &attr,
7189     VtArray<SdfAssetPath>* result)
7190 {
7191     stage._MakeResolvedAssetPaths(time, attr, result->data(), result->size());
7192 }
7193 
7194 template <>
_ResolveValue(const UsdStage & stage,UsdTimeCode time,const UsdAttribute & attr,SdfTimeCode * result)7195 void Usd_AttrGetValueHelper<SdfTimeCode>::_ResolveValue(
7196     const UsdStage &stage, UsdTimeCode time, const UsdAttribute &attr,
7197     SdfTimeCode* result)
7198 {
7199     stage._MakeResolvedTimeCodes(time, attr, result, 1);
7200 }
7201 
7202 template <>
_ResolveValue(const UsdStage & stage,UsdTimeCode time,const UsdAttribute & attr,VtArray<SdfTimeCode> * result)7203 void Usd_AttrGetValueHelper<VtArray<SdfTimeCode>>::_ResolveValue(
7204     const UsdStage &stage, UsdTimeCode time, const UsdAttribute &attr,
7205     VtArray<SdfTimeCode>* result)
7206 {
7207     stage._MakeResolvedTimeCodes(time, attr, result->data(), result->size());
7208 }
7209 
7210 // Attribute value getter for type erased VtValue.
7211 struct Usd_AttrGetUntypedValueHelper {
7212     template <class Fn>
GetValueUsd_AttrGetUntypedValueHelper7213     static bool GetValue(const UsdStage &stage, UsdTimeCode time,
7214                          const UsdAttribute &attr, VtValue* result,
7215                          const Fn &getValueImpl)
7216     {
7217         // Special case if time is default: we can grab the value from the
7218         // metadata. This value will be fully resolved already because
7219         // _GetMetadata returns fully resolved values.
7220         if (time.IsDefault()) {
7221             bool valueFound = stage._GetMetadata(
7222                 attr, SdfFieldKeys->Default, TfToken(),
7223                 /*useFallbacks=*/true, result);
7224             return valueFound && (!Usd_ClearValueIfBlocked(result));
7225         }
7226 
7227         Usd_UntypedInterpolator interpolator(attr, result);
7228         if (getValueImpl(stage, time, attr, &interpolator, result)) {
7229             if (result) {
7230                 // Always run the resolve functions for value types that need
7231                 // it.
7232                 stage._MakeResolvedAttributeValue(time, attr, result);
7233             }
7234             return true;
7235         }
7236         return false;
7237     }
7238 };
7239 
7240 bool
_GetValue(UsdTimeCode time,const UsdAttribute & attr,VtValue * result) const7241 UsdStage::_GetValue(UsdTimeCode time, const UsdAttribute &attr,
7242                     VtValue* result) const
7243 {
7244     auto getValueImpl = [](const UsdStage &stage,
7245                            UsdTimeCode time, const UsdAttribute &attr,
7246                            Usd_InterpolatorBase* interpolator,
7247                            VtValue* value)
7248     {
7249         return stage._GetValueImpl(time, attr, interpolator, value);
7250     };
7251 
7252     return Usd_AttrGetUntypedValueHelper::GetValue(
7253         *this, time, attr, result, getValueImpl);
7254 }
7255 
7256 template <class T>
7257 bool
_GetValue(UsdTimeCode time,const UsdAttribute & attr,T * result) const7258 UsdStage::_GetValue(UsdTimeCode time, const UsdAttribute &attr,
7259                     T* result) const
7260 {
7261     auto getValueImpl = [](const UsdStage &stage,
7262                            UsdTimeCode time, const UsdAttribute &attr,
7263                            Usd_InterpolatorBase* interpolator,
7264                            SdfAbstractDataValue* value)
7265     {
7266         return stage._GetValueImpl(time, attr, interpolator, value);
7267     };
7268 
7269     return Usd_AttrGetValueHelper<T>::GetValue(
7270         *this, time, attr, result, getValueImpl);
7271 }
7272 
7273 class UsdStage_ResolveInfoAccess
7274 {
7275 public:
7276     template <class T>
_GetTimeSampleValue(UsdTimeCode time,const UsdAttribute & attr,const UsdResolveInfo & info,const double * lowerHint,const double * upperHint,Usd_InterpolatorBase * interpolator,T * result)7277     static bool _GetTimeSampleValue(
7278         UsdTimeCode time, const UsdAttribute& attr,
7279         const UsdResolveInfo &info,
7280         const double *lowerHint, const double *upperHint,
7281         Usd_InterpolatorBase *interpolator,
7282         T *result)
7283     {
7284         const SdfPath specPath =
7285             info._primPathInLayerStack.AppendProperty(attr.GetName());
7286         const SdfLayerHandle& layer = info._layer;
7287         const double localTime =
7288             info._layerToStageOffset.GetInverse() * time.GetValue();
7289 
7290         double upper = 0.0;
7291         double lower = 0.0;
7292 
7293         if (lowerHint && upperHint) {
7294             lower = *lowerHint;
7295             upper = *upperHint;
7296         }
7297         else {
7298             if (!TF_VERIFY(layer->GetBracketingTimeSamplesForPath(
7299                                specPath, localTime, &lower, &upper),
7300                            "No bracketing time samples for "
7301                            "%s on <%s> for time %g between %g and %g",
7302                            layer->GetIdentifier().c_str(),
7303                            specPath.GetText(),
7304                            localTime, lower, upper)) {
7305                 return false;
7306             }
7307         }
7308 
7309         TF_DEBUG(USD_VALUE_RESOLUTION).Msg(
7310             "RESOLVE: reading field %s:%s from @%s@, "
7311             "with requested time = %.3f (local time = %.3f) "
7312             "reading from sample %.3f \n",
7313             specPath.GetText(),
7314             SdfFieldKeys->TimeSamples.GetText(),
7315             layer->GetIdentifier().c_str(),
7316             time.GetValue(),
7317             localTime,
7318             lower);
7319 
7320         return Usd_GetOrInterpolateValue(
7321             layer, specPath, localTime, lower, upper, interpolator, result);
7322     }
7323 
7324     template <class T>
_GetClipValue(UsdTimeCode time,const UsdAttribute & attr,const UsdResolveInfo & info,const Usd_ClipSetRefPtr & clipSet,const double * lowerHint,const double * upperHint,Usd_InterpolatorBase * interpolator,T * result)7325     static bool _GetClipValue(
7326         UsdTimeCode time, const UsdAttribute& attr,
7327         const UsdResolveInfo &info,
7328         const Usd_ClipSetRefPtr &clipSet,
7329         const double *lowerHint, const double *upperHint,
7330         Usd_InterpolatorBase *interpolator,
7331         T *result)
7332     {
7333         const SdfPath specPath =
7334             info._primPathInLayerStack.AppendProperty(attr.GetName());
7335 
7336         // Note that we do not apply layer offsets to the time.
7337         // Because clip metadata may be authored in different
7338         // layers in the LayerStack, each with their own
7339         // layer offsets, it is simpler to bake the effects of
7340         // those offsets into Usd_Clip.
7341         const double localTime = time.GetValue();
7342         double upper = 0.0;
7343         double lower = 0.0;
7344 
7345         if (lowerHint && upperHint) {
7346             lower = *lowerHint;
7347             upper = *upperHint;
7348         }
7349         else {
7350             _HasTimeSamples(clipSet, specPath, &localTime, &lower, &upper);
7351         }
7352 
7353         TF_DEBUG(USD_VALUE_RESOLUTION).Msg(
7354             "RESOLVE: reading field %s:%s from clip set %s, "
7355             "with requested time = %.3f "
7356             "reading from sample %.3f \n",
7357             specPath.GetText(),
7358             SdfFieldKeys->TimeSamples.GetText(),
7359             clipSet->name.c_str(),
7360             localTime,
7361             lower);
7362 
7363         return Usd_GetOrInterpolateValue(
7364             clipSet, specPath, localTime, lower, upper, interpolator, result);
7365     }
7366 };
7367 
7368 // Helper structure populated by _GetResolveInfo and _ResolveInfoResolver
7369 // with extra information accumulated in the process. This allows clients to
7370 // avoid redoing work.
7371 template <class T>
7372 struct UsdStage::_ExtraResolveInfo
7373 {
7374     // If the resolve info source is UsdResolveInfoSourceTimeSamples or
7375     // UsdResolveInfoSourceValueClips and an explicit time is given to
7376     // _GetResolveInfo, this will be the lower and upper bracketing time
7377     // samples for that time.
7378     double lowerSample = 0;
7379     double upperSample = 0;
7380 
7381     // If the resolve info source is UsdResolveInfoSourceDefault or
7382     // UsdResolveInfoSourceFallback and this is non-null, the default
7383     // or fallback value will be copied to the object this pointer refers to.
7384     T* defaultOrFallbackValue = nullptr;
7385 
7386     // If the resolve info source is UsdResolveInfoSourceValueClips this will
7387     // be the Usd_ClipSet containing values for the attribute.
7388     Usd_ClipSetRefPtr clipSet;
7389 };
7390 
7391 SdfLayerRefPtr
_GetLayerWithStrongestValue(UsdTimeCode time,const UsdAttribute & attr) const7392 UsdStage::_GetLayerWithStrongestValue(
7393     UsdTimeCode time, const UsdAttribute &attr) const
7394 {
7395     SdfLayerRefPtr resultLayer;
7396     if (time.IsDefault()) {
7397         ExistenceComposer getLayerComposer(&resultLayer);
7398         _GetMetadataImpl(attr, SdfFieldKeys->Default,
7399                          TfToken(), /*useFallbacks=*/false, &getLayerComposer);
7400     } else {
7401         UsdResolveInfo resolveInfo;
7402         _ExtraResolveInfo<SdfAbstractDataValue> extraResolveInfo;
7403 
7404         _GetResolveInfo(attr, &resolveInfo, &time, &extraResolveInfo);
7405 
7406         if (resolveInfo._source == UsdResolveInfoSourceTimeSamples ||
7407             resolveInfo._source == UsdResolveInfoSourceDefault) {
7408             resultLayer = resolveInfo._layer;
7409         }
7410         else if (resolveInfo._source == UsdResolveInfoSourceValueClips) {
7411             const Usd_ClipSetRefPtr& clipSet = extraResolveInfo.clipSet;
7412             const Usd_ClipRefPtr& activeClip =
7413                 clipSet->GetActiveClip(time.GetValue());
7414             const SdfPath specPath =
7415                 resolveInfo._primPathInLayerStack.AppendProperty(attr.GetName());
7416 
7417             // If the active clip has authored time samples, the value will
7418             // come from it (or at least be interpolated from it) so use that
7419             // clip's layer. Otherwise the value will come from the manifest.
7420             resultLayer = activeClip->HasAuthoredTimeSamples(specPath) ?
7421                 activeClip->GetLayer() : clipSet->manifestClip->GetLayer();
7422         }
7423     }
7424     return resultLayer;
7425 }
7426 
7427 template <class T>
7428 bool
_GetValueImpl(UsdTimeCode time,const UsdAttribute & attr,Usd_InterpolatorBase * interpolator,T * result) const7429 UsdStage::_GetValueImpl(UsdTimeCode time, const UsdAttribute &attr,
7430                         Usd_InterpolatorBase* interpolator,
7431                         T *result) const
7432 {
7433     UsdResolveInfo resolveInfo;
7434     _ExtraResolveInfo<T> extraResolveInfo;
7435     extraResolveInfo.defaultOrFallbackValue = result;
7436 
7437     TfErrorMark m;
7438     _GetResolveInfo(attr, &resolveInfo, &time, &extraResolveInfo);
7439 
7440     if (resolveInfo._source == UsdResolveInfoSourceTimeSamples) {
7441         return UsdStage_ResolveInfoAccess::_GetTimeSampleValue(
7442             time, attr, resolveInfo,
7443             &extraResolveInfo.lowerSample, &extraResolveInfo.upperSample,
7444             interpolator, result);
7445     }
7446     else if (resolveInfo._source == UsdResolveInfoSourceValueClips) {
7447         return UsdStage_ResolveInfoAccess::_GetClipValue(
7448             time, attr, resolveInfo,
7449             extraResolveInfo.clipSet,
7450             &extraResolveInfo.lowerSample, &extraResolveInfo.upperSample,
7451             interpolator, result);
7452     }
7453     else if (resolveInfo._source == UsdResolveInfoSourceDefault ||
7454              resolveInfo._source == UsdResolveInfoSourceFallback) {
7455         // Nothing to do here -- the call to _GetResolveInfo will have
7456         // filled in the result with the default value.
7457         return m.IsClean();
7458     }
7459 
7460     return false;
7461 }
7462 
7463 // Our property stack resolver never indicates for resolution to stop
7464 // as we need to gather all relevant property specs in the LayerStack
7465 struct UsdStage::_PropertyStackResolver {
7466     SdfPropertySpecHandleVector propertyStack;
7467 
ProcessFallbackUsdStage::_PropertyStackResolver7468     bool ProcessFallback() { return false; }
7469 
7470     bool
ProcessLayerUsdStage::_PropertyStackResolver7471     ProcessLayer(const size_t layerStackPosition,
7472                  const SdfPath& specPath,
7473                  const PcpNodeRef& node,
7474                  const double *time)
7475     {
7476         const auto layer
7477             = node.GetLayerStack()->GetLayers()[layerStackPosition];
7478         const auto propertySpec = layer->GetPropertyAtPath(specPath);
7479         if (propertySpec) {
7480             propertyStack.push_back(propertySpec);
7481         }
7482 
7483         return false;
7484     }
7485 
7486     bool
ProcessClipsUsdStage::_PropertyStackResolver7487     ProcessClips(const Usd_ClipSetRefPtr& clipSet,
7488                  const SdfPath& specPath,
7489                  const PcpNodeRef& node,
7490                  const double* time)
7491     {
7492         // Look through clips to see if they have a time sample for
7493         // this attribute. If a time is given, examine just the clips
7494         // that are active at that time.
7495         double lowerSample = 0.0, upperSample = 0.0;
7496 
7497         if (_HasTimeSamples(
7498                 clipSet, specPath, time, &lowerSample, &upperSample)) {
7499 
7500             const Usd_ClipRefPtr& activeClip = clipSet->GetActiveClip(*time);
7501 
7502             // If the active clip has authored time samples, the value will
7503             // come from it (or at least be interpolated from it) so use the
7504             // property spec from that clip. Otherwise the value will come
7505             // from the manifest.
7506             const Usd_ClipRefPtr& sourceClip =
7507                 activeClip->HasAuthoredTimeSamples(specPath) ?
7508                 activeClip : clipSet->manifestClip;
7509 
7510             if (!TF_VERIFY(sourceClip)) {
7511                 return false;
7512             }
7513 
7514             if (const auto propertySpec =
7515                     sourceClip->GetPropertyAtPath(specPath)) {
7516                 propertyStack.push_back(propertySpec);
7517             }
7518         }
7519 
7520         return false;
7521     }
7522 };
7523 
7524 SdfPropertySpecHandleVector
_GetPropertyStack(const UsdProperty & prop,UsdTimeCode time) const7525 UsdStage::_GetPropertyStack(const UsdProperty &prop,
7526                             UsdTimeCode time) const
7527 {
7528     _PropertyStackResolver resolver;
7529     _GetResolvedValueImpl(prop, &resolver, &time);
7530     return resolver.propertyStack;
7531 }
7532 
7533 // A 'Resolver' for filling UsdResolveInfo.
7534 template <typename T>
7535 struct UsdStage::_ResolveInfoResolver
7536 {
_ResolveInfoResolverUsdStage::_ResolveInfoResolver7537     explicit _ResolveInfoResolver(const UsdAttribute& attr,
7538                                  UsdResolveInfo* resolveInfo,
7539                                  UsdStage::_ExtraResolveInfo<T>* extraInfo)
7540     :   _attr(attr),
7541         _resolveInfo(resolveInfo),
7542         _extraInfo(extraInfo)
7543     {
7544     }
7545 
7546     bool
ProcessFallbackUsdStage::_ResolveInfoResolver7547     ProcessFallback()
7548     {
7549         if (const bool hasFallback =
7550                 _attr._Prim()->GetPrimDefinition().GetAttributeFallbackValue(
7551                     _attr.GetName(), _extraInfo->defaultOrFallbackValue)) {
7552             _resolveInfo->_source = UsdResolveInfoSourceFallback;
7553             return true;
7554         }
7555 
7556         // No values at all.
7557         _resolveInfo->_source = UsdResolveInfoSourceNone;
7558         return true;
7559     }
7560 
7561     bool
ProcessLayerUsdStage::_ResolveInfoResolver7562     ProcessLayer(const size_t layerStackPosition,
7563                  const SdfPath& specPath,
7564                  const PcpNodeRef& node,
7565                  const double *time)
7566     {
7567         const PcpLayerStackRefPtr& nodeLayers = node.GetLayerStack();
7568         const SdfLayerRefPtrVector& layerStack = nodeLayers->GetLayers();
7569         const SdfLayerOffset layerToStageOffset =
7570             _GetLayerToStageOffset(node, layerStack[layerStackPosition]);
7571         const SdfLayerRefPtr& layer = layerStack[layerStackPosition];
7572         boost::optional<double> localTime;
7573         if (time) {
7574             localTime = layerToStageOffset.GetInverse() * (*time);
7575         }
7576 
7577         if (_HasTimeSamples(layer, specPath, localTime.get_ptr(),
7578                             &_extraInfo->lowerSample,
7579                             &_extraInfo->upperSample)) {
7580             _resolveInfo->_source = UsdResolveInfoSourceTimeSamples;
7581         }
7582         else {
7583             Usd_DefaultValueResult defValue = Usd_HasDefault(
7584                 layer, specPath, _extraInfo->defaultOrFallbackValue);
7585             if (defValue == Usd_DefaultValueResult::Found) {
7586                 _resolveInfo->_source = UsdResolveInfoSourceDefault;
7587             }
7588             else if (defValue == Usd_DefaultValueResult::Blocked) {
7589                 _resolveInfo->_valueIsBlocked = true;
7590                 return ProcessFallback();
7591             }
7592         }
7593 
7594         if (_resolveInfo->_source != UsdResolveInfoSourceNone) {
7595             _resolveInfo->_layerStack = nodeLayers;
7596             _resolveInfo->_layer = layer;
7597             _resolveInfo->_primPathInLayerStack = node.GetPath();
7598             _resolveInfo->_layerToStageOffset = layerToStageOffset;
7599             _resolveInfo->_node = node;
7600             return true;
7601         }
7602 
7603         return false;
7604     }
7605 
7606     bool
ProcessClipsUsdStage::_ResolveInfoResolver7607     ProcessClips(const Usd_ClipSetRefPtr& clipSet,
7608                  const SdfPath& specPath,
7609                  const PcpNodeRef& node,
7610                  const double* time)
7611     {
7612         if (!_HasTimeSamples(
7613                 clipSet, specPath, time,
7614                 &_extraInfo->lowerSample, &_extraInfo->upperSample)) {
7615             return false;
7616         }
7617 
7618         _extraInfo->clipSet = clipSet;
7619 
7620         _resolveInfo->_source = UsdResolveInfoSourceValueClips;
7621         _resolveInfo->_layerStack = node.GetLayerStack();
7622         _resolveInfo->_primPathInLayerStack = node.GetPath();
7623         _resolveInfo->_node = node;
7624 
7625         return true;
7626     }
7627 
7628 private:
7629     const UsdAttribute& _attr;
7630     UsdResolveInfo* _resolveInfo;
7631     UsdStage::_ExtraResolveInfo<T>* _extraInfo;
7632 };
7633 
7634 template <class T>
7635 void
_GetResolveInfo(const UsdAttribute & attr,UsdResolveInfo * resolveInfo,const UsdTimeCode * time,_ExtraResolveInfo<T> * extraInfo) const7636 UsdStage::_GetResolveInfo(const UsdAttribute &attr,
7637                           UsdResolveInfo *resolveInfo,
7638                           const UsdTimeCode *time,
7639                           _ExtraResolveInfo<T> *extraInfo) const
7640 {
7641     _ExtraResolveInfo<T> localExtraInfo;
7642     if (!extraInfo) {
7643         extraInfo = &localExtraInfo;
7644     }
7645 
7646     _ResolveInfoResolver<T> resolver(attr, resolveInfo, extraInfo);
7647     _GetResolvedValueImpl(attr, &resolver, time);
7648 
7649     if (TfDebug::IsEnabled(USD_VALIDATE_VARIABILITY) &&
7650         (resolveInfo->_source == UsdResolveInfoSourceTimeSamples ||
7651          resolveInfo->_source == UsdResolveInfoSourceValueClips) &&
7652         _GetVariability(attr) == SdfVariabilityUniform) {
7653 
7654         TF_DEBUG(USD_VALIDATE_VARIABILITY)
7655             .Msg("Warning: detected time sample value on "
7656                  "uniform attribute <%s>\n",
7657                  UsdDescribe(attr).c_str());
7658     }
7659 }
7660 
7661 // This function takes a Resolver object, which is used to process opinions
7662 // in strength order. Resolvers must implement three functions:
7663 //
7664 //       ProcessLayer()
7665 //       ProcessClips()
7666 //       ProcessFallback()
7667 //
7668 // Each of these functions is required to return true, to indicate that
7669 // iteration of opinions should stop, and false otherwise.
7670 template <class Resolver>
7671 void
_GetResolvedValueImpl(const UsdProperty & prop,Resolver * resolver,const UsdTimeCode * time) const7672 UsdStage::_GetResolvedValueImpl(const UsdProperty &prop,
7673                                 Resolver *resolver,
7674                                 const UsdTimeCode *time) const
7675 {
7676     auto primHandle = prop._Prim();
7677     boost::optional<double> localTime;
7678     if (time && !time->IsDefault()) {
7679         localTime = time->GetValue();
7680     }
7681 
7682     // Retrieve all clips that may contribute time samples for this
7683     // attribute at the given time. Clips never contribute default
7684     // values.
7685     const std::vector<Usd_ClipSetRefPtr>* clipsAffectingPrim = nullptr;
7686     if (primHandle->MayHaveOpinionsInClips()
7687         && (!time || !time->IsDefault())) {
7688         clipsAffectingPrim =
7689             &(_clipCache->GetClipsForPrim(primHandle->GetPath()));
7690     }
7691 
7692     // Clips may contribute opinions at nodes where no specs for the attribute
7693     // exist in the node's LayerStack. So, if we have any clips, tell
7694     // Usd_Resolver that we want to iterate over 'empty' nodes as well.
7695     const bool skipEmptyNodes = (bool)(!clipsAffectingPrim);
7696 
7697     for (Usd_Resolver res(&primHandle->GetPrimIndex(), skipEmptyNodes);
7698          res.IsValid(); res.NextNode()) {
7699 
7700         const PcpNodeRef& node = res.GetNode();
7701         const bool nodeHasSpecs = node.HasSpecs();
7702         if (!nodeHasSpecs && !clipsAffectingPrim) {
7703             continue;
7704         }
7705 
7706         const SdfPath specPath = node.GetPath().AppendProperty(prop.GetName());
7707         const SdfLayerRefPtrVector& layerStack
7708             = node.GetLayerStack()->GetLayers();
7709         boost::optional<std::vector<Usd_ClipSetRefPtr>> clips;
7710         for (size_t i = 0, e = layerStack.size(); i < e; ++i) {
7711             if (nodeHasSpecs) {
7712                 if (resolver->ProcessLayer(i, specPath, node,
7713                                            localTime.get_ptr())) {
7714                     return;
7715                 }
7716             }
7717 
7718             if (clipsAffectingPrim){
7719                 if (!clips) {
7720                     clips = _GetClipsThatApplyToNode(*clipsAffectingPrim,
7721                                                      node, specPath);
7722                     // If we don't have specs on this node and clips don't
7723                     // apply we can mode onto the next node.
7724                     if (!nodeHasSpecs && clips->empty()) {
7725                         break;
7726                     }
7727                 }
7728 
7729                 // gcc 4.8 incorrectly detects boost::optional as uninitialized.
7730                 // See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47679
7731                 ARCH_PRAGMA_PUSH
7732                 ARCH_PRAGMA_MAYBE_UNINITIALIZED
7733 
7734                 for (const Usd_ClipSetRefPtr& clipSet : *clips) {
7735                     // We only care about clips that were introduced at this
7736                     // position within the LayerStack.
7737                     if (clipSet->sourceLayerIndex != i) {
7738                         continue;
7739                     }
7740 
7741                     // Look through clips to see if they have a time sample for
7742                     // this attribute. If a time is given, examine just the clips
7743                     // that are active at that time.
7744                     if (resolver->ProcessClips(
7745                             clipSet, specPath, node, localTime.get_ptr())) {
7746                         return;
7747                     }
7748                 }
7749 
7750                 ARCH_PRAGMA_POP
7751             }
7752         }
7753     }
7754 
7755     resolver->ProcessFallback();
7756 }
7757 
7758 void
_GetResolveInfo(const UsdAttribute & attr,UsdResolveInfo * resolveInfo,const UsdTimeCode * time) const7759 UsdStage::_GetResolveInfo(const UsdAttribute &attr,
7760                           UsdResolveInfo *resolveInfo,
7761                           const UsdTimeCode *time) const
7762 {
7763     _GetResolveInfo<SdfAbstractDataValue>(attr, resolveInfo, time);
7764 }
7765 
7766 template <class T>
7767 bool
_GetValueFromResolveInfoImpl(const UsdResolveInfo & info,UsdTimeCode time,const UsdAttribute & attr,Usd_InterpolatorBase * interpolator,T * result) const7768 UsdStage::_GetValueFromResolveInfoImpl(const UsdResolveInfo &info,
7769                                        UsdTimeCode time, const UsdAttribute &attr,
7770                                        Usd_InterpolatorBase* interpolator,
7771                                        T* result) const
7772 {
7773     if (info._source == UsdResolveInfoSourceTimeSamples) {
7774         return UsdStage_ResolveInfoAccess::_GetTimeSampleValue(
7775             time, attr, info, nullptr, nullptr, interpolator, result);
7776     }
7777     else if (info._source == UsdResolveInfoSourceDefault) {
7778         const SdfPath specPath =
7779             info._primPathInLayerStack.AppendProperty(attr.GetName());
7780         const SdfLayerHandle& layer = info._layer;
7781 
7782         TF_DEBUG(USD_VALUE_RESOLUTION).Msg(
7783             "RESOLVE: reading field %s:%s from @%s@, with t = %.3f"
7784             " as default\n",
7785             specPath.GetText(),
7786             SdfFieldKeys->TimeSamples.GetText(),
7787             layer->GetIdentifier().c_str(),
7788             time.GetValue());
7789 
7790         return TF_VERIFY(
7791             layer->HasField(specPath, SdfFieldKeys->Default, result));
7792     }
7793     else if (info._source == UsdResolveInfoSourceValueClips) {
7794         const SdfPath specPath =
7795             info._primPathInLayerStack.AppendProperty(attr.GetName());
7796 
7797         const UsdPrim prim = attr.GetPrim();
7798         const std::vector<Usd_ClipSetRefPtr>& clipsAffectingPrim =
7799             _clipCache->GetClipsForPrim(prim.GetPath());
7800 
7801         for (const auto& clipSet : clipsAffectingPrim) {
7802             if (!_ClipsApplyToLayerStackSite(
7803                     clipSet, info._layerStack, info._primPathInLayerStack)
7804                 || !_ClipsContainValueForAttribute(clipSet, specPath)) {
7805                 continue;
7806             }
7807 
7808             return UsdStage_ResolveInfoAccess::_GetClipValue(
7809                 time, attr, info, clipSet, nullptr, nullptr,
7810                 interpolator, result);
7811         }
7812     }
7813     else if (info._source == UsdResolveInfoSourceFallback) {
7814         // Get the fallback value.
7815         return attr._Prim()->GetPrimDefinition().GetAttributeFallbackValue(
7816                 attr.GetName(), result);
7817     }
7818 
7819     return false;
7820 }
7821 
7822 bool
_GetValueFromResolveInfo(const UsdResolveInfo & info,UsdTimeCode time,const UsdAttribute & attr,VtValue * result) const7823 UsdStage::_GetValueFromResolveInfo(const UsdResolveInfo &info,
7824                                    UsdTimeCode time, const UsdAttribute &attr,
7825                                    VtValue* result) const
7826 {
7827     auto getValueImpl = [&info](const UsdStage &stage,
7828                                 UsdTimeCode time, const UsdAttribute &attr,
7829                                 Usd_InterpolatorBase* interpolator,
7830                                 VtValue* value)
7831     {
7832         return stage._GetValueFromResolveInfoImpl(
7833             info, time, attr, interpolator, value);
7834     };
7835 
7836     return Usd_AttrGetUntypedValueHelper::GetValue(
7837         *this, time, attr, result, getValueImpl);
7838 }
7839 
7840 template <class T>
7841 bool
_GetValueFromResolveInfo(const UsdResolveInfo & info,UsdTimeCode time,const UsdAttribute & attr,T * result) const7842 UsdStage::_GetValueFromResolveInfo(const UsdResolveInfo &info,
7843                                    UsdTimeCode time, const UsdAttribute &attr,
7844                                    T* result) const
7845 {
7846     auto getValueImpl = [&info](const UsdStage &stage,
7847                                 UsdTimeCode time, const UsdAttribute &attr,
7848                                 Usd_InterpolatorBase* interpolator,
7849                                 SdfAbstractDataValue* value)
7850     {
7851         return stage._GetValueFromResolveInfoImpl(
7852             info, time, attr, interpolator, value);
7853     };
7854 
7855     return Usd_AttrGetValueHelper<T>::GetValue(
7856         *this, time, attr, result, getValueImpl);
7857 }
7858 
7859 // --------------------------------------------------------------------- //
7860 // Specialized Time Sample I/O
7861 // --------------------------------------------------------------------- //
7862 
7863 bool
_GetTimeSamplesInInterval(const UsdAttribute & attr,const GfInterval & interval,std::vector<double> * times) const7864 UsdStage::_GetTimeSamplesInInterval(const UsdAttribute& attr,
7865                                     const GfInterval& interval,
7866                                     std::vector<double>* times) const
7867 {
7868     UsdResolveInfo info;
7869     _GetResolveInfo(attr, &info);
7870     return _GetTimeSamplesInIntervalFromResolveInfo(info, attr, interval, times);
7871 }
7872 
7873 bool
_GetTimeSamplesInIntervalFromResolveInfo(const UsdResolveInfo & info,const UsdAttribute & attr,const GfInterval & interval,std::vector<double> * times) const7874 UsdStage::_GetTimeSamplesInIntervalFromResolveInfo(
7875     const UsdResolveInfo &info,
7876     const UsdAttribute &attr,
7877     const GfInterval& interval,
7878     std::vector<double>* times) const
7879 {
7880     // An empty requested interval would result in in empty times
7881     // vector so avoid computing any of the contained samples
7882     if (interval.IsEmpty()) {
7883         return true;
7884     }
7885 
7886     // This is the lowest-level site for guaranteeing that all GetTimeSample
7887     // queries clear out the return vector
7888     times->clear();
7889     const auto copySamplesInInterval = [](const std::set<double>& samples,
7890                                           vector<double>* target,
7891                                           const GfInterval& interval)
7892     {
7893         std::set<double>::iterator samplesBegin, samplesEnd;
7894 
7895         if (interval.IsMinOpen()) {
7896             samplesBegin = std::upper_bound(samples.begin(),
7897                                             samples.end(),
7898                                             interval.GetMin());
7899         } else {
7900             samplesBegin = std::lower_bound(samples.begin(),
7901                                             samples.end(),
7902                                             interval.GetMin());
7903         }
7904 
7905         if (interval.IsMaxOpen()) {
7906             samplesEnd = std::lower_bound(samplesBegin,
7907                                           samples.end(),
7908                                           interval.GetMax());
7909         } else {
7910             samplesEnd = std::upper_bound(samplesBegin,
7911                                           samples.end(),
7912                                           interval.GetMax());
7913         }
7914 
7915         target->insert(target->end(), samplesBegin, samplesEnd);
7916     };
7917 
7918     if (info._source == UsdResolveInfoSourceTimeSamples) {
7919         const SdfPath specPath =
7920             info._primPathInLayerStack.AppendProperty(attr.GetName());
7921         const SdfLayerHandle& layer = info._layer;
7922 
7923         const std::set<double> samples =
7924             layer->ListTimeSamplesForPath(specPath);
7925         if (!samples.empty()) {
7926             if (info._layerToStageOffset.IsIdentity()) {
7927                 // The layer offset is identity, so we can use the interval
7928                 // directly, and do not need to remap the sample times.
7929                 copySamplesInInterval(samples, times, interval);
7930             } else {
7931                 // Map the interval (expressed in stage time) to layer time.
7932                 const SdfLayerOffset stageToLayer =
7933                     info._layerToStageOffset.GetInverse();
7934                 const GfInterval layerInterval =
7935                     interval * stageToLayer.GetScale()
7936                     + stageToLayer.GetOffset();
7937                 copySamplesInInterval(samples, times, layerInterval);
7938                 // Map the layer sample times to stage times.
7939                 for (auto &time : *times) {
7940                     time = info._layerToStageOffset * time;
7941                 }
7942             }
7943         }
7944 
7945         return true;
7946     }
7947     else if (info._source == UsdResolveInfoSourceValueClips) {
7948         const UsdPrim prim = attr.GetPrim();
7949 
7950         // See comments in _GetValueImpl regarding clips.
7951         const std::vector<Usd_ClipSetRefPtr>& clipsAffectingPrim =
7952             _clipCache->GetClipsForPrim(prim.GetPath());
7953 
7954         const SdfPath specPath =
7955             info._primPathInLayerStack.AppendProperty(attr.GetName());
7956 
7957         // Loop through all the clips that apply to this node and
7958         // combine all the time samples that are provided.
7959         for (const auto& clipSet : clipsAffectingPrim) {
7960             if (!_ClipsApplyToLayerStackSite(
7961                     clipSet, info._layerStack, info._primPathInLayerStack)
7962                 || !_ClipsContainValueForAttribute(clipSet, specPath)) {
7963                 continue;
7964             }
7965 
7966             // See comments in _GetValueImpl regarding layer
7967             // offsets and why they're not applied here.
7968             const std::set<double> samples =
7969                 clipSet->ListTimeSamplesForPath(specPath);
7970             copySamplesInInterval(samples, times, interval);;
7971             return true;
7972         }
7973     }
7974 
7975     return true;
7976 }
7977 
7978 size_t
_GetNumTimeSamples(const UsdAttribute & attr) const7979 UsdStage::_GetNumTimeSamples(const UsdAttribute &attr) const
7980 {
7981     UsdResolveInfo info;
7982     _GetResolveInfo(attr, &info);
7983     return _GetNumTimeSamplesFromResolveInfo(info, attr);
7984 
7985 }
7986 
7987 size_t
_GetNumTimeSamplesFromResolveInfo(const UsdResolveInfo & info,const UsdAttribute & attr) const7988 UsdStage::_GetNumTimeSamplesFromResolveInfo(const UsdResolveInfo &info,
7989                                             const UsdAttribute &attr) const
7990 {
7991     if (info._source == UsdResolveInfoSourceTimeSamples) {
7992         const SdfPath specPath =
7993             info._primPathInLayerStack.AppendProperty(attr.GetName());
7994         const SdfLayerHandle& layer = info._layer;
7995 
7996         return layer->GetNumTimeSamplesForPath(specPath);
7997     }
7998     else if (info._source == UsdResolveInfoSourceValueClips) {
7999         // XXX: optimization
8000         //
8001         // We don't have an efficient way of getting the number of time
8002         // samples from all the clips involved. To avoid code duplication,
8003         // simply get all the time samples and return the size here.
8004         //
8005         // This is good motivation for why we really need the ability to
8006         // ask the question of whether there is more than one sample directly.
8007         //
8008         std::vector<double> timesFromAllClips;
8009         _GetTimeSamplesInIntervalFromResolveInfo(info, attr,
8010             GfInterval::GetFullInterval(), &timesFromAllClips);
8011         return timesFromAllClips.size();
8012     }
8013 
8014     return 0;
8015 }
8016 
8017 bool
_GetBracketingTimeSamples(const UsdAttribute & attr,double desiredTime,bool requireAuthored,double * lower,double * upper,bool * hasSamples) const8018 UsdStage::_GetBracketingTimeSamples(const UsdAttribute &attr,
8019                                     double desiredTime,
8020                                     bool requireAuthored,
8021                                     double* lower,
8022                                     double* upper,
8023                                     bool* hasSamples) const
8024 {
8025     const UsdTimeCode time(desiredTime);
8026 
8027     UsdResolveInfo resolveInfo;
8028     _ExtraResolveInfo<SdfAbstractDataValue> extraInfo;
8029 
8030     _GetResolveInfo<SdfAbstractDataValue>(
8031         attr, &resolveInfo, &time, &extraInfo);
8032 
8033     if (resolveInfo._source == UsdResolveInfoSourceTimeSamples) {
8034         // In the time samples case, we bail out early to avoid another
8035         // call to SdfLayer::GetBracketingTimeSamples. _GetResolveInfo will
8036         // already have filled in the lower and upper samples with the
8037         // results of that function at the desired time.
8038         *lower = extraInfo.lowerSample;
8039         *upper = extraInfo.upperSample;
8040 
8041         const SdfLayerOffset offset = resolveInfo._layerToStageOffset;
8042         if (!offset.IsIdentity()) {
8043             *lower = offset * (*lower);
8044             *upper = offset * (*upper);
8045         }
8046 
8047         *hasSamples = true;
8048         return true;
8049     }
8050     else if (resolveInfo._source == UsdResolveInfoSourceValueClips) {
8051         *lower = extraInfo.lowerSample;
8052         *upper = extraInfo.upperSample;
8053         *hasSamples = true;
8054         return true;
8055     }
8056 
8057     return _GetBracketingTimeSamplesFromResolveInfo(
8058         resolveInfo, attr, desiredTime, requireAuthored, lower, upper,
8059         hasSamples);
8060 }
8061 
8062 bool
_GetBracketingTimeSamplesFromResolveInfo(const UsdResolveInfo & info,const UsdAttribute & attr,double desiredTime,bool requireAuthored,double * lower,double * upper,bool * hasSamples) const8063 UsdStage::_GetBracketingTimeSamplesFromResolveInfo(const UsdResolveInfo &info,
8064                                                    const UsdAttribute &attr,
8065                                                    double desiredTime,
8066                                                    bool requireAuthored,
8067                                                    double* lower,
8068                                                    double* upper,
8069                                                    bool* hasSamples) const
8070 {
8071     if (info._source == UsdResolveInfoSourceTimeSamples) {
8072         const SdfPath specPath =
8073             info._primPathInLayerStack.AppendProperty(attr.GetName());
8074         const SdfLayerHandle& layer = info._layer;
8075         const double layerTime =
8076             info._layerToStageOffset.GetInverse() * desiredTime;
8077 
8078         if (layer->GetBracketingTimeSamplesForPath(
8079                 specPath, layerTime, lower, upper)) {
8080 
8081             if (!info._layerToStageOffset.IsIdentity()) {
8082                 *lower = info._layerToStageOffset * (*lower);
8083                 *upper = info._layerToStageOffset * (*upper);
8084             }
8085 
8086             *hasSamples = true;
8087             return true;
8088         }
8089     }
8090     else if (info._source == UsdResolveInfoSourceDefault) {
8091         *hasSamples = false;
8092         return true;
8093     }
8094     else if (info._source == UsdResolveInfoSourceValueClips) {
8095         const SdfPath specPath =
8096             info._primPathInLayerStack.AppendProperty(attr.GetName());
8097 
8098         const UsdPrim prim = attr.GetPrim();
8099 
8100         // See comments in _GetValueImpl regarding clips.
8101         const std::vector<Usd_ClipSetRefPtr>& clipsAffectingPrim =
8102             _clipCache->GetClipsForPrim(prim.GetPath());
8103 
8104         for (const auto& clipSet : clipsAffectingPrim) {
8105             if (!_ClipsApplyToLayerStackSite(
8106                     clipSet, info._layerStack, info._primPathInLayerStack)
8107                 || !_ClipsContainValueForAttribute(clipSet, specPath)) {
8108                 continue;
8109             }
8110 
8111             if (clipSet->GetBracketingTimeSamplesForPath(
8112                     specPath, desiredTime, lower, upper)) {
8113                 *hasSamples = true;
8114                 return true;
8115             }
8116         }
8117     }
8118     else if (info._source == UsdResolveInfoSourceFallback) {
8119         // At this point, no authored value was found, so if the client only
8120         // wants authored values, we can exit.
8121         *hasSamples = false;
8122         if (requireAuthored)
8123             return false;
8124 
8125         // Check for a registered fallback.
8126         if (SdfAttributeSpecHandle attrDef = _GetSchemaAttributeSpec(attr)) {
8127             if (attrDef->HasDefaultValue()) {
8128                 *hasSamples = false;
8129                 return true;
8130             }
8131         }
8132     }
8133 
8134     // No authored value, no fallback.
8135     return false;
8136 }
8137 
8138 static bool
_ValueFromClipsMightBeTimeVarying(const Usd_ClipSetRefPtr & clipSet,const SdfPath & attrSpecPath)8139 _ValueFromClipsMightBeTimeVarying(const Usd_ClipSetRefPtr &clipSet,
8140                                   const SdfPath &attrSpecPath)
8141 {
8142     // If there is only one clip active over all time and it has more than one
8143     // time sample for the attribute, it might be time varying. Otherwise the
8144     // attribute's value must be constant over all time.
8145     if (clipSet->valueClips.size() == 1) {
8146         const size_t numTimeSamples =
8147             clipSet->valueClips.front()->GetNumTimeSamplesForPath(attrSpecPath);
8148         return numTimeSamples > 1;
8149     }
8150 
8151     // Since there are multiple clips active across all time, we can't say
8152     // for certain whether there are multiple time samples without
8153     // potentially opening every clip. So, we have to report that the value
8154     // might be time varying.
8155     return true;
8156 }
8157 
8158 bool
_ValueMightBeTimeVarying(const UsdAttribute & attr) const8159 UsdStage::_ValueMightBeTimeVarying(const UsdAttribute &attr) const
8160 {
8161     UsdResolveInfo info;
8162     _ExtraResolveInfo<SdfAbstractDataValue> extraInfo;
8163     _GetResolveInfo(attr, &info, nullptr, &extraInfo);
8164 
8165     if (info._source == UsdResolveInfoSourceValueClips) {
8166         // See comment in _ValueMightBeTimeVaryingFromResolveInfo.
8167         const SdfPath specPath =
8168             info._primPathInLayerStack.AppendProperty(attr.GetName());
8169         return _ValueFromClipsMightBeTimeVarying(extraInfo.clipSet, specPath);
8170     }
8171 
8172     return _ValueMightBeTimeVaryingFromResolveInfo(info, attr);
8173 }
8174 
8175 bool
_ValueMightBeTimeVaryingFromResolveInfo(const UsdResolveInfo & info,const UsdAttribute & attr) const8176 UsdStage::_ValueMightBeTimeVaryingFromResolveInfo(const UsdResolveInfo &info,
8177                                                   const UsdAttribute &attr) const
8178 {
8179     if (info._source == UsdResolveInfoSourceValueClips) {
8180         // Do a specialized check for value clips instead of falling through
8181         // to calling _GetNumTimeSamplesFromResolveInfo, which requires opening
8182         // every clip to get the total time sample count.
8183         const SdfPath specPath =
8184             info._primPathInLayerStack.AppendProperty(attr.GetName());
8185 
8186         const std::vector<Usd_ClipSetRefPtr>& clipsAffectingPrim =
8187             _clipCache->GetClipsForPrim(attr.GetPrim().GetPath());
8188         for (const auto& clipSet : clipsAffectingPrim) {
8189             if (!_ClipsApplyToLayerStackSite(
8190                     clipSet, info._layerStack, info._primPathInLayerStack)) {
8191                 continue;
8192             }
8193 
8194             if (_HasTimeSamples(clipSet, specPath)) {
8195                 return _ValueFromClipsMightBeTimeVarying(clipSet, specPath);
8196             }
8197         }
8198 
8199         return false;
8200     }
8201 
8202     return _GetNumTimeSamplesFromResolveInfo(info, attr) > 1;
8203 }
8204 
8205 bool
GetMetadata(const TfToken & key,VtValue * value) const8206 UsdStage::GetMetadata(const TfToken &key, VtValue *value) const
8207 {
8208     if (!value){
8209         TF_CODING_ERROR(
8210             "Null out-param 'value' for UsdStage::GetMetadata(\"%s\")",
8211             key.GetText());
8212         return false;
8213 
8214     }
8215     const SdfSchema &schema = SdfSchema::GetInstance();
8216 
8217     if (!schema.IsValidFieldForSpec(key, SdfSpecTypePseudoRoot)){
8218         return false;
8219     }
8220 
8221     if (!GetPseudoRoot().GetMetadata(key, value)) {
8222         *value = SdfSchema::GetInstance().GetFallback(key);
8223     } else if (value->IsHolding<VtDictionary>()){
8224         const VtDictionary &fallback = SdfSchema::GetInstance().GetFallback(key).Get<VtDictionary>();
8225 
8226         VtDictionary dict;
8227         value->UncheckedSwap<VtDictionary>(dict);
8228         VtDictionaryOverRecursive(&dict, fallback);
8229         value->UncheckedSwap<VtDictionary>(dict);
8230     }
8231     return true;
8232 }
8233 
8234 bool
HasMetadata(const TfToken & key) const8235 UsdStage::HasMetadata(const TfToken &key) const
8236 {
8237     const SdfSchema &schema = SdfSchema::GetInstance();
8238 
8239     if (!schema.IsValidFieldForSpec(key, SdfSpecTypePseudoRoot))
8240         return false;
8241 
8242     return (GetPseudoRoot().HasAuthoredMetadata(key) ||
8243             !schema.GetFallback(key).IsEmpty());
8244 }
8245 
8246 bool
HasAuthoredMetadata(const TfToken & key) const8247 UsdStage::HasAuthoredMetadata(const TfToken& key) const
8248 {
8249     const SdfSchema &schema = SdfSchema::GetInstance();
8250 
8251     if (!schema.IsValidFieldForSpec(key, SdfSpecTypePseudoRoot))
8252         return false;
8253 
8254     return GetPseudoRoot().HasAuthoredMetadata(key);
8255 }
8256 
8257 static
8258 void
_SetLayerFieldOrDictKey(const SdfLayerHandle & layer,const TfToken & key,const TfToken & keyPath,const VtValue & val)8259 _SetLayerFieldOrDictKey(const SdfLayerHandle &layer, const TfToken &key,
8260                         const TfToken &keyPath, const VtValue &val)
8261 {
8262     if (keyPath.IsEmpty()) {
8263         layer->SetField(SdfPath::AbsoluteRootPath(), key, val);
8264     } else {
8265         layer->SetFieldDictValueByKey(SdfPath::AbsoluteRootPath(),
8266                                       key, keyPath, val);
8267     }
8268 }
8269 
8270 static
8271 void
_ClearLayerFieldOrDictKey(const SdfLayerHandle & layer,const TfToken & key,const TfToken & keyPath)8272 _ClearLayerFieldOrDictKey(const SdfLayerHandle &layer, const TfToken &key,
8273                           const TfToken &keyPath)
8274 {
8275     if (keyPath.IsEmpty()) {
8276         layer->EraseField(SdfPath::AbsoluteRootPath(), key);
8277     } else {
8278         layer->EraseFieldDictValueByKey(SdfPath::AbsoluteRootPath(),
8279                                         key, keyPath);
8280     }
8281 }
8282 
8283 static
8284 bool
_SetStageMetadataOrDictKey(const UsdStage & stage,const TfToken & key,const TfToken & keyPath,const VtValue & val)8285 _SetStageMetadataOrDictKey(const UsdStage &stage, const TfToken &key,
8286                            const TfToken &keyPath, const VtValue &val)
8287 {
8288     SdfLayerHandle rootLayer = stage.GetRootLayer();
8289     SdfLayerHandle sessionLayer = stage.GetSessionLayer();
8290     const SdfSchema &schema = SdfSchema::GetInstance();
8291 
8292     if (!schema.IsValidFieldForSpec(key, SdfSpecTypePseudoRoot)) {
8293         TF_CODING_ERROR("Metadata '%s' is not registered as valid Layer "
8294                         "metadata, and cannot be set on UsdStage %s.",
8295                         key.GetText(),
8296                         rootLayer->GetIdentifier().c_str());
8297         return false;
8298     }
8299 
8300     const SdfLayerHandle &editTargetLayer = stage.GetEditTarget().GetLayer();
8301     if (editTargetLayer == rootLayer || editTargetLayer == sessionLayer) {
8302         _SetLayerFieldOrDictKey(editTargetLayer, key, keyPath, val);
8303     } else {
8304         TF_CODING_ERROR("Cannot set layer metadata '%s' in current edit "
8305                         "target \"%s\", as it is not the root layer or "
8306                         "session layer of stage \"%s\".",
8307                         key.GetText(),
8308                         editTargetLayer->GetIdentifier().c_str(),
8309                         rootLayer->GetIdentifier().c_str());
8310         return false;
8311     }
8312 
8313     return true;
8314 }
8315 
8316 bool
SetMetadata(const TfToken & key,const VtValue & value) const8317 UsdStage::SetMetadata(const TfToken &key, const VtValue &value) const
8318 {
8319     return _SetStageMetadataOrDictKey(*this, key, TfToken(), value);
8320 }
8321 
8322 
8323 static
8324 bool
_ClearStageMetadataOrDictKey(const UsdStage & stage,const TfToken & key,const TfToken & keyPath)8325 _ClearStageMetadataOrDictKey(const UsdStage &stage, const TfToken &key,
8326                         const TfToken &keyPath)
8327 {
8328     SdfLayerHandle rootLayer = stage.GetRootLayer();
8329     SdfLayerHandle sessionLayer = stage.GetSessionLayer();
8330     const SdfSchema &schema = SdfSchema::GetInstance();
8331 
8332     if (!schema.IsValidFieldForSpec(key, SdfSpecTypePseudoRoot)) {
8333         TF_CODING_ERROR("Metadata '%s' is not registered as valid Layer "
8334                         "metadata, and cannot be cleared on UsdStage %s.",
8335                         key.GetText(),
8336                         rootLayer->GetIdentifier().c_str());
8337         return false;
8338     }
8339 
8340     const SdfLayerHandle &editTargetLayer = stage.GetEditTarget().GetLayer();
8341     if (editTargetLayer == rootLayer || editTargetLayer == sessionLayer) {
8342         _ClearLayerFieldOrDictKey(editTargetLayer, key, keyPath);
8343     } else {
8344         TF_CODING_ERROR("Cannot clear layer metadata '%s' in current edit "
8345                         "target \"%s\", as it is not the root layer or "
8346                         "session layer of stage \"%s\".",
8347                         key.GetText(),
8348                         editTargetLayer->GetIdentifier().c_str(),
8349                         rootLayer->GetIdentifier().c_str());
8350         return false;
8351     }
8352 
8353     return true;
8354 }
8355 
8356 bool
ClearMetadata(const TfToken & key) const8357 UsdStage::ClearMetadata(const TfToken &key) const
8358 {
8359     return _ClearStageMetadataOrDictKey(*this, key, TfToken());
8360 }
8361 
8362 bool
GetMetadataByDictKey(const TfToken & key,const TfToken & keyPath,VtValue * value) const8363 UsdStage::GetMetadataByDictKey(const TfToken& key, const TfToken &keyPath,
8364                                VtValue *value) const
8365 {
8366     if (keyPath.IsEmpty())
8367         return false;
8368 
8369     if (!value){
8370         TF_CODING_ERROR(
8371             "Null out-param 'value' for UsdStage::GetMetadataByDictKey"
8372             "(\"%s\", \"%s\")",
8373             key.GetText(), keyPath.GetText());
8374         return false;
8375 
8376     }
8377     const SdfSchema &schema = SdfSchema::GetInstance();
8378 
8379     if (!schema.IsValidFieldForSpec(key, SdfSpecTypePseudoRoot))
8380         return false;
8381 
8382     if (!GetPseudoRoot().GetMetadataByDictKey(key, keyPath, value)) {
8383         const VtValue &fallback =  SdfSchema::GetInstance().GetFallback(key);
8384         if (!fallback.IsEmpty()){
8385             const VtValue *elt = fallback.Get<VtDictionary>().
8386                 GetValueAtPath(keyPath);
8387             if (elt){
8388                 *value = *elt;
8389                 return true;
8390             }
8391         }
8392         return false;
8393     }
8394     else if (value->IsHolding<VtDictionary>()){
8395         const VtDictionary &fallback = SdfSchema::GetInstance().GetFallback(key).Get<VtDictionary>();
8396         const VtValue *elt = fallback.GetValueAtPath(keyPath);
8397         if (elt && elt->IsHolding<VtDictionary>()){
8398             VtDictionary dict;
8399             value->UncheckedSwap<VtDictionary>(dict);
8400             VtDictionaryOverRecursive(&dict, elt->UncheckedGet<VtDictionary>());
8401             value->UncheckedSwap<VtDictionary>(dict);
8402         }
8403    }
8404 
8405     return true;
8406 }
8407 
8408 bool
HasMetadataDictKey(const TfToken & key,const TfToken & keyPath) const8409 UsdStage::HasMetadataDictKey(const TfToken& key, const TfToken &keyPath) const
8410 {
8411     const SdfSchema &schema = SdfSchema::GetInstance();
8412 
8413     if (keyPath.IsEmpty() ||
8414         !schema.IsValidFieldForSpec(key, SdfSpecTypePseudoRoot))
8415         return false;
8416 
8417     if (GetPseudoRoot().HasAuthoredMetadataDictKey(key, keyPath)) {
8418         return true;
8419     }
8420 
8421     const VtValue &fallback =  schema.GetFallback(key);
8422 
8423     return ((!fallback.IsEmpty()) &&
8424             (fallback.Get<VtDictionary>().GetValueAtPath(keyPath) != nullptr));
8425 }
8426 
8427 bool
HasAuthoredMetadataDictKey(const TfToken & key,const TfToken & keyPath) const8428 UsdStage::HasAuthoredMetadataDictKey(
8429     const TfToken& key, const TfToken &keyPath) const
8430 {
8431     if (keyPath.IsEmpty())
8432         return false;
8433 
8434     return GetPseudoRoot().HasAuthoredMetadataDictKey(key, keyPath);
8435 }
8436 
8437 bool
SetMetadataByDictKey(const TfToken & key,const TfToken & keyPath,const VtValue & value) const8438 UsdStage::SetMetadataByDictKey(
8439     const TfToken& key, const TfToken &keyPath, const VtValue& value) const
8440 {
8441     if (keyPath.IsEmpty())
8442         return false;
8443 
8444     return _SetStageMetadataOrDictKey(*this, key, keyPath, value);
8445 }
8446 
8447 bool
ClearMetadataByDictKey(const TfToken & key,const TfToken & keyPath) const8448 UsdStage::ClearMetadataByDictKey(
8449         const TfToken& key, const TfToken& keyPath) const
8450 {
8451     if (keyPath.IsEmpty())
8452         return false;
8453 
8454     return _ClearStageMetadataOrDictKey(*this, key, keyPath);
8455 }
8456 
8457 ///////////////////////////////////////////////////////////////////////////////
8458 // XXX(Frame->Time): backwards compatibility
8459 // Temporary helper functions to support backwards compatibility.
8460 ///////////////////////////////////////////////////////////////////////////////
8461 
8462 static
8463 bool
_HasStartFrame(const SdfLayerConstHandle & layer)8464 _HasStartFrame(const SdfLayerConstHandle &layer)
8465 {
8466     return layer->GetPseudoRoot()->HasInfo(SdfFieldKeys->StartFrame);
8467 }
8468 
8469 static
8470 bool
_HasEndFrame(const SdfLayerConstHandle & layer)8471 _HasEndFrame(const SdfLayerConstHandle &layer)
8472 {
8473     return layer->GetPseudoRoot()->HasInfo(SdfFieldKeys->EndFrame);
8474 }
8475 
8476 static
8477 double
_GetStartFrame(const SdfLayerConstHandle & layer)8478 _GetStartFrame(const SdfLayerConstHandle &layer)
8479 {
8480     VtValue startFrame = layer->GetPseudoRoot()->GetInfo(SdfFieldKeys->StartFrame);
8481     if (startFrame.IsHolding<double>())
8482         return startFrame.UncheckedGet<double>();
8483     return 0.0;
8484 }
8485 
8486 static
8487 double
_GetEndFrame(const SdfLayerConstHandle & layer)8488 _GetEndFrame(const SdfLayerConstHandle &layer)
8489 {
8490     VtValue endFrame = layer->GetPseudoRoot()->GetInfo(SdfFieldKeys->EndFrame);
8491     if (endFrame.IsHolding<double>())
8492         return endFrame.UncheckedGet<double>();
8493     return 0.0;
8494 }
8495 
8496 //////////////////////////////////////////////////////////////////////////////
8497 
8498 // XXX bug/123508 - Once we can remove backwards compatibility with
8499 // startFrame/endFrame, these methods can become as simple as those for
8500 // TimeCodesPerSecond and FramesPerSecond
8501 double
GetStartTimeCode() const8502 UsdStage::GetStartTimeCode() const
8503 {
8504     // Look for 'startTimeCode' first. If it is not available, then look for
8505     // the deprecated field 'startFrame'.
8506     const SdfLayerConstHandle sessionLayer = GetSessionLayer();
8507     if (sessionLayer) {
8508         if (sessionLayer->HasStartTimeCode())
8509             return sessionLayer->GetStartTimeCode();
8510         else if (_HasStartFrame(sessionLayer))
8511             return _GetStartFrame(sessionLayer);
8512     }
8513 
8514     if (GetRootLayer()->HasStartTimeCode())
8515         return GetRootLayer()->GetStartTimeCode();
8516     return _GetStartFrame(GetRootLayer());
8517 }
8518 
8519 void
SetStartTimeCode(double startTime)8520 UsdStage::SetStartTimeCode(double startTime)
8521 {
8522     SetMetadata(SdfFieldKeys->StartTimeCode, startTime);
8523 }
8524 
8525 double
GetEndTimeCode() const8526 UsdStage::GetEndTimeCode() const
8527 {
8528     // Look for 'endTimeCode' first. If it is not available, then look for
8529     // the deprecated field 'startFrame'.
8530     const SdfLayerConstHandle sessionLayer = GetSessionLayer();
8531     if (sessionLayer) {
8532         if (sessionLayer->HasEndTimeCode())
8533             return sessionLayer->GetEndTimeCode();
8534         else if (_HasEndFrame(sessionLayer))
8535             return _GetEndFrame(sessionLayer);
8536     }
8537 
8538     if (GetRootLayer()->HasEndTimeCode())
8539         return GetRootLayer()->GetEndTimeCode();
8540     return _GetEndFrame(GetRootLayer());
8541 }
8542 
8543 void
SetEndTimeCode(double endTime)8544 UsdStage::SetEndTimeCode(double endTime)
8545 {
8546     SetMetadata(SdfFieldKeys->EndTimeCode, endTime);
8547 }
8548 
8549 bool
HasAuthoredTimeCodeRange() const8550 UsdStage::HasAuthoredTimeCodeRange() const
8551 {
8552     SdfLayerHandle rootLayer = GetRootLayer();
8553     SdfLayerHandle sessionLayer = GetSessionLayer();
8554 
8555     return (sessionLayer &&
8556             ((sessionLayer->HasStartTimeCode() && sessionLayer->HasEndTimeCode()) ||
8557              (_HasStartFrame(sessionLayer) && _HasEndFrame(sessionLayer)))) ||
8558            (rootLayer &&
8559             ((rootLayer->HasStartTimeCode() && rootLayer->HasEndTimeCode()) ||
8560              (_HasStartFrame(rootLayer) && _HasEndFrame(rootLayer))));
8561 }
8562 
8563 double
GetTimeCodesPerSecond() const8564 UsdStage::GetTimeCodesPerSecond() const
8565 {
8566     // PcpLayerStack computes timeCodesPerSecond for its map function layer
8567     // offsets. The root layer stack will always have the stage's fully
8568     // computed timeCodesPerSecond value accounting for the unique interaction
8569     // between the root and session layer.
8570     const PcpLayerStackPtr localLayerStack = _GetPcpCache()->GetLayerStack();
8571     return localLayerStack->GetTimeCodesPerSecond();
8572 }
8573 
8574 void
SetTimeCodesPerSecond(double timeCodesPerSecond) const8575 UsdStage::SetTimeCodesPerSecond(double timeCodesPerSecond) const
8576 {
8577     SetMetadata(SdfFieldKeys->TimeCodesPerSecond, timeCodesPerSecond);
8578 }
8579 
8580 double
GetFramesPerSecond() const8581 UsdStage::GetFramesPerSecond() const
8582 {
8583     // We expect the SdfSchema to provide a fallback, so simply:
8584     double result = 0;
8585     GetMetadata(SdfFieldKeys->FramesPerSecond, &result);
8586     return result;
8587 }
8588 
8589 void
SetFramesPerSecond(double framesPerSecond) const8590 UsdStage::SetFramesPerSecond(double framesPerSecond) const
8591 {
8592     SetMetadata(SdfFieldKeys->FramesPerSecond, framesPerSecond);
8593 }
8594 
8595 void
SetColorConfiguration(const SdfAssetPath & colorConfig) const8596 UsdStage::SetColorConfiguration(const SdfAssetPath &colorConfig) const
8597 {
8598     SetMetadata(SdfFieldKeys->ColorConfiguration, colorConfig);
8599 }
8600 
8601 SdfAssetPath
GetColorConfiguration() const8602 UsdStage::GetColorConfiguration() const
8603 {
8604     SdfAssetPath colorConfig;
8605     GetMetadata(SdfFieldKeys->ColorConfiguration, &colorConfig);
8606 
8607     return colorConfig.GetAssetPath().empty() ?
8608         _colorConfigurationFallbacks->first : colorConfig;
8609 }
8610 
8611 void
SetColorManagementSystem(const TfToken & cms) const8612 UsdStage::SetColorManagementSystem(const TfToken &cms) const
8613 {
8614     SetMetadata(SdfFieldKeys->ColorManagementSystem, cms);
8615 }
8616 
8617 TfToken
GetColorManagementSystem() const8618 UsdStage::GetColorManagementSystem() const
8619 {
8620     TfToken cms;
8621     GetMetadata(SdfFieldKeys->ColorManagementSystem, &cms);
8622 
8623     return cms.IsEmpty() ? _colorConfigurationFallbacks->second : cms;
8624 }
8625 
8626 /* static */
8627 void
GetColorConfigFallbacks(SdfAssetPath * colorConfiguration,TfToken * colorManagementSystem)8628 UsdStage::GetColorConfigFallbacks(
8629     SdfAssetPath *colorConfiguration,
8630     TfToken *colorManagementSystem)
8631 {
8632     if (colorConfiguration) {
8633         *colorConfiguration = _colorConfigurationFallbacks->first;
8634     }
8635     if (colorManagementSystem) {
8636         *colorManagementSystem = _colorConfigurationFallbacks->second;
8637     }
8638 }
8639 
8640 /* static */
8641 void
SetColorConfigFallbacks(const SdfAssetPath & colorConfiguration,const TfToken & colorManagementSystem)8642 UsdStage::SetColorConfigFallbacks(
8643     const SdfAssetPath &colorConfiguration,
8644     const TfToken &colorManagementSystem)
8645 {
8646     if (!colorConfiguration.GetAssetPath().empty())
8647         _colorConfigurationFallbacks->first = colorConfiguration;
8648     if (!colorManagementSystem.IsEmpty())
8649         _colorConfigurationFallbacks->second = colorManagementSystem;
8650 }
8651 
8652 std::string
ResolveIdentifierToEditTarget(std::string const & identifier) const8653 UsdStage::ResolveIdentifierToEditTarget(std::string const &identifier) const
8654 {
8655     const SdfLayerHandle &anchor = _editTarget.GetLayer();
8656 
8657     // This check finds anonymous layers, which we consider to always resolve
8658     if (SdfLayer::IsAnonymousLayerIdentifier(identifier)) {
8659         if (SdfLayerHandle lyr = SdfLayer::Find(identifier)){
8660             TF_DEBUG(USD_PATH_RESOLUTION).Msg(
8661                 "Resolved identifier %s because it was anonymous\n",
8662                 identifier.c_str());
8663             return identifier;
8664         }
8665         else {
8666             TF_DEBUG(USD_PATH_RESOLUTION).Msg(
8667                 "Resolved identifier %s to \"\" because it was anonymous but "
8668                 "no layer is open with that identifier\n",
8669                 identifier.c_str());
8670             return std::string();
8671         }
8672     }
8673 
8674     ArResolverContextBinder binder(GetPathResolverContext());
8675 
8676     // Handles non-relative paths also
8677     const std::string resolved =
8678         _ResolveAssetPathRelativeToLayer(anchor, identifier);
8679     TF_DEBUG(USD_PATH_RESOLUTION).Msg("Resolved identifier \"%s\" against layer "
8680                                       "@%s@ to: \"%s\"\n",
8681                                       identifier.c_str(),
8682                                       anchor->GetIdentifier().c_str(),
8683                                       resolved.c_str());
8684     return resolved;
8685 }
8686 
8687 void
SetInterpolationType(UsdInterpolationType interpolationType)8688 UsdStage::SetInterpolationType(UsdInterpolationType interpolationType)
8689 {
8690     if (_interpolationType != interpolationType) {
8691         _interpolationType = interpolationType;
8692 
8693         // Notify, as interpolated attributes values have likely changed.
8694         UsdStageWeakPtr self(this);
8695         UsdNotice::ObjectsChanged::_PathsToChangesMap resyncChanges, infoChanges;
8696         resyncChanges[SdfPath::AbsoluteRootPath()];
8697         UsdNotice::ObjectsChanged(self, &resyncChanges, &infoChanges).Send(self);
8698         UsdNotice::StageContentsChanged(self).Send(self);
8699     }
8700 }
8701 
8702 UsdInterpolationType
GetInterpolationType() const8703 UsdStage::GetInterpolationType() const
8704 {
8705     return _interpolationType;
8706 }
8707 
UsdDescribe(const UsdStage * stage)8708 std::string UsdDescribe(const UsdStage *stage) {
8709     if (!stage) {
8710         return "null stage";
8711     } else {
8712         return TfStringPrintf(
8713             "stage with rootLayer @%s@%s",
8714             stage->GetRootLayer()->GetIdentifier().c_str(),
8715             (stage->GetSessionLayer() ? TfStringPrintf(
8716                 ", sessionLayer @%s@", stage->GetSessionLayer()->
8717                 GetIdentifier().c_str()).c_str() : ""));
8718     }
8719 }
8720 
UsdDescribe(const UsdStage & stage)8721 std::string UsdDescribe(const UsdStage &stage) {
8722     return UsdDescribe(&stage);
8723 }
8724 
UsdDescribe(const UsdStagePtr & stage)8725 std::string UsdDescribe(const UsdStagePtr &stage) {
8726     return UsdDescribe(get_pointer(stage));
8727 }
8728 
UsdDescribe(const UsdStageRefPtr & stage)8729 std::string UsdDescribe(const UsdStageRefPtr &stage) {
8730     return UsdDescribe(get_pointer(stage));
8731 }
8732 
8733 // Explicitly instantiate templated getters and setters for all Sdf value
8734 // types.
8735 #define _INSTANTIATE_GET(r, unused, elem)                               \
8736     template bool UsdStage::_GetValue(                                  \
8737         UsdTimeCode, const UsdAttribute&,                               \
8738         SDF_VALUE_CPP_TYPE(elem)*) const;                               \
8739     template bool UsdStage::_GetValue(                                  \
8740         UsdTimeCode, const UsdAttribute&,                               \
8741         SDF_VALUE_CPP_ARRAY_TYPE(elem)*) const;                         \
8742                                                                         \
8743     template bool UsdStage::_GetValueFromResolveInfo(                   \
8744         const UsdResolveInfo&, UsdTimeCode, const UsdAttribute&,        \
8745         SDF_VALUE_CPP_TYPE(elem)*) const;                               \
8746     template bool UsdStage::_GetValueFromResolveInfo(                   \
8747         const UsdResolveInfo&, UsdTimeCode, const UsdAttribute&,        \
8748         SDF_VALUE_CPP_ARRAY_TYPE(elem)*) const;                         \
8749                                                                         \
8750     template bool UsdStage::_SetValue(                                  \
8751         UsdTimeCode, const UsdAttribute&,                               \
8752         const SDF_VALUE_CPP_TYPE(elem)&);                               \
8753     template bool UsdStage::_SetValue(                                  \
8754         UsdTimeCode, const UsdAttribute&,                               \
8755         const SDF_VALUE_CPP_ARRAY_TYPE(elem)&);
8756 
8757 BOOST_PP_SEQ_FOR_EACH(_INSTANTIATE_GET, ~, SDF_VALUE_TYPES)
8758 #undef _INSTANTIATE_GET
8759 
8760 // In addition to the Sdf value types, _SetValue can also be called with an
8761 // SdfValueBlock.
8762 template bool UsdStage::_SetValue(
8763     UsdTimeCode, const UsdAttribute&, const SdfValueBlock &);
8764 
8765 // Explicitly instantiate the templated _SetEditTargetMappedMetadata and
8766 // _GetTypeSpecificResolvedMetadata functions for the types that support each.
8767 // The types instantiated here must match the types whose value is true for
8768 // _HasTypeSpecificResolution<T> and _IsEditTargetMappable<T>.
8769 #define INSTANTIATE_SET_MAPPED_METADATA(elem)                               \
8770     template USD_API bool UsdStage::_SetEditTargetMappedMetadata(           \
8771         const UsdObject &, const TfToken&, const TfToken &, const elem &);
8772 
8773 #define INSTANTIATE_GET_TYPE_RESOLVED_METADATA(elem)                                 \
8774     template USD_API bool UsdStage::_GetTypeSpecificResolvedMetadata(                       \
8775         const UsdObject &, const TfToken&, const TfToken &, bool, elem *) const;
8776 
8777 #define INSTANTIATE_GET_TYPE_RESOLVED_AND_SET_MAPPED_METADATA(elem)  \
8778     INSTANTIATE_GET_TYPE_RESOLVED_METADATA(elem);                    \
8779     INSTANTIATE_SET_MAPPED_METADATA(elem);
8780 
8781 INSTANTIATE_GET_TYPE_RESOLVED_METADATA(SdfAssetPath);
8782 INSTANTIATE_GET_TYPE_RESOLVED_METADATA(VtArray<SdfAssetPath>);
8783 INSTANTIATE_GET_TYPE_RESOLVED_AND_SET_MAPPED_METADATA(SdfTimeCode);
8784 INSTANTIATE_GET_TYPE_RESOLVED_AND_SET_MAPPED_METADATA(VtArray<SdfTimeCode>);
8785 // Do not explicitly instantiate _GetTypeSpecificResolvedMetadata for
8786 // SdfTimeSampleMap because we provide a specialization instead.
8787 INSTANTIATE_SET_MAPPED_METADATA(SdfTimeSampleMap);
8788 INSTANTIATE_GET_TYPE_RESOLVED_AND_SET_MAPPED_METADATA(VtDictionary);
8789 
8790 #undef INSTANTIATE_GET_TYPE_RESOLVED_AND_SET_MAPPED_METADATA
8791 #undef INSTANTIATE_GET_TYPE_RESOLVED_METADATA
8792 #undef INSTANTIATE_SET_MAPPED_METADATA
8793 
8794 // Make sure both versions of _SetMetadataImpl are instantiated as they are
8795 // directly called from UsdObject.
8796 template USD_API bool UsdStage::_SetMetadataImpl(
8797     const UsdObject &, const TfToken &, const TfToken &,
8798     const VtValue &);
8799 template USD_API bool UsdStage::_SetMetadataImpl(
8800     const UsdObject &, const TfToken &, const TfToken &,
8801     const SdfAbstractDataConstValue &);
8802 
8803 PXR_NAMESPACE_CLOSE_SCOPE
8804 
8805