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 /// \file Changes.cpp
25 
26 #include "pxr/pxr.h"
27 #include "pxr/usd/pcp/changes.h"
28 #include "pxr/usd/pcp/cache.h"
29 #include "pxr/usd/pcp/debugCodes.h"
30 #include "pxr/usd/pcp/dependencies.h"
31 #include "pxr/usd/pcp/instancing.h"
32 #include "pxr/usd/pcp/layerStack.h"
33 #include "pxr/usd/pcp/layerStackRegistry.h"
34 #include "pxr/usd/pcp/pathTranslation.h"
35 #include "pxr/usd/pcp/utils.h"
36 #include "pxr/usd/sdf/changeList.h"
37 #include "pxr/usd/sdf/layer.h"
38 #include "pxr/usd/ar/resolverContextBinder.h"
39 #include "pxr/base/trace/trace.h"
40 
41 PXR_NAMESPACE_OPEN_SCOPE
42 
43 static
44 void
Pcp_SubsumeDescendants(SdfPathSet * pathSet)45 Pcp_SubsumeDescendants(SdfPathSet* pathSet)
46 {
47     SdfPathSet::iterator prefixIt = pathSet->begin(), end = pathSet->end();
48     while (prefixIt != end) {
49         // Find the range of paths under path *prefixIt.
50         SdfPathSet::iterator first = prefixIt;
51         SdfPathSet::iterator last  = ++first;
52         while (last != end && last->HasPrefix(*prefixIt)) {
53             ++last;
54         }
55 
56         // Remove the range.
57         pathSet->erase(first, last);
58 
59         // Next path is not under previous path.
60         prefixIt = last;
61     }
62 }
63 
64 void
Pcp_SubsumeDescendants(SdfPathSet * pathSet,const SdfPath & prefix)65 Pcp_SubsumeDescendants(SdfPathSet* pathSet, const SdfPath& prefix)
66 {
67     // Start at first path in pathSet that is prefix or greater.
68     SdfPathSet::iterator first = pathSet->lower_bound(prefix);
69 
70     // Scan for next path in pathSet that does not have prefix as a prefix.
71     SdfPathSet::iterator last = first;
72     SdfPathSet::iterator end = pathSet->end();
73     while (last != end && last->HasPrefix(prefix)) {
74         ++last;
75     }
76 
77     // Erase the paths in the range.
78     pathSet->erase(first, last);
79 }
80 
PcpLifeboat()81 PcpLifeboat::PcpLifeboat()
82 {
83     // Do nothing
84 }
85 
~PcpLifeboat()86 PcpLifeboat::~PcpLifeboat()
87 {
88     // Do nothing
89 }
90 
91 void
Retain(const SdfLayerRefPtr & layer)92 PcpLifeboat::Retain(const SdfLayerRefPtr& layer)
93 {
94     _layers.insert(layer);
95 }
96 
97 void
Retain(const PcpLayerStackRefPtr & layerStack)98 PcpLifeboat::Retain(const PcpLayerStackRefPtr& layerStack)
99 {
100     _layerStacks.insert(layerStack);
101 }
102 
103 const std::set<PcpLayerStackRefPtr>&
GetLayerStacks() const104 PcpLifeboat::GetLayerStacks() const
105 {
106     return _layerStacks;
107 }
108 
109 void
Swap(PcpLifeboat & other)110 PcpLifeboat::Swap(PcpLifeboat& other)
111 {
112     std::swap(_layers, other._layers);
113     std::swap(_layerStacks, other._layerStacks);
114 }
115 
PcpChanges()116 PcpChanges::PcpChanges()
117 {
118     // Do nothing
119 }
120 
~PcpChanges()121 PcpChanges::~PcpChanges()
122 {
123     // Do nothing
124 }
125 
126 #define PCP_APPEND_DEBUG(...)                       \
127     if (!debugSummary) ; else                    \
128         *debugSummary += TfStringPrintf(__VA_ARGS__)
129 
130 enum Pcp_ChangesLayerStackChange {
131     Pcp_ChangesLayerStackChangeNone,
132     Pcp_ChangesLayerStackChangeSignificant,
133     Pcp_ChangesLayerStackChangeMaybeSignificant
134 };
135 
136 static
137 Pcp_ChangesLayerStackChange
Pcp_EntryRequiresLayerStackChange(const SdfChangeList::Entry & entry)138 Pcp_EntryRequiresLayerStackChange(const SdfChangeList::Entry& entry)
139 {
140     // If a layer's content was entirely replaced, we must blow layer stacks.
141     if (entry.flags.didReplaceContent) {
142         return Pcp_ChangesLayerStackChangeSignificant;
143     }
144 
145     // XXX: This only requires blowing the layer stacks using this
146     //      identifier that haven't also been updated to use the new
147     //      identifier.
148     if (entry.flags.didChangeIdentifier) {
149         return Pcp_ChangesLayerStackChangeSignificant;
150     }
151 
152     // Order of layers in layer stack probably changed.
153     // XXX: Don't return true if these changes don't affect the
154     //      layer tree order.
155     for (auto const &p: entry.infoChanged) {
156         if (p.first == SdfFieldKeys->Owner ||
157             p.first == SdfFieldKeys->SessionOwner ||
158             p.first == SdfFieldKeys->HasOwnedSubLayers) {
159             return Pcp_ChangesLayerStackChangeSignificant;
160         }
161     }
162 
163     // Layer was added or removed.
164     TF_FOR_ALL(i, entry.subLayerChanges) {
165         if (i->second == SdfChangeList::SubLayerAdded ||
166             i->second == SdfChangeList::SubLayerRemoved) {
167             // Whether the change is significant depends on whether any
168             // added/removed layer is significant.  To check that we need
169             // the help of each cache using this layer.
170             return Pcp_ChangesLayerStackChangeMaybeSignificant;
171         }
172     }
173 
174     return Pcp_ChangesLayerStackChangeNone;
175 }
176 
177 static
178 bool
Pcp_EntryRequiresLayerStackOffsetsChange(const SdfLayerHandle & layer,const SdfChangeList::Entry & entry,bool * rootLayerStacksMayNeedTcpsRecompute)179 Pcp_EntryRequiresLayerStackOffsetsChange(
180     const SdfLayerHandle &layer,
181     const SdfChangeList::Entry& entry,
182     bool *rootLayerStacksMayNeedTcpsRecompute)
183 {
184     // Check any changes to actual sublayer offsets.
185     for (const auto &it : entry.subLayerChanges) {
186         if (it.second == SdfChangeList::SubLayerOffset) {
187             return true;
188         }
189     }
190 
191     // Check if the TCPS metadata field changed. Note that this encapsulates
192     // both changes to timeCodesPerSecond and framesPerSecond as the
193     // SdfChangeManager will send a send a FPS change as a change to TCPS as
194     // well when the FPS is relevant as a fallback for an unspecified TCPS.
195     auto it = entry.FindInfoChange(SdfFieldKeys->TimeCodesPerSecond);
196     if (it != entry.infoChanged.end()) {
197         // The old and new values in the entry already account for the
198         // "computed TCPS" when the FPS is used as a fallback. So we still have
199         // to check if the computed TCPS changed.
200         //
201         // We also have to account here for the case where both the FPS and
202         // TCPS are unspecified, either before or after the change, as the old
203         // or new entry value will be empty which is equivalent to specifying
204         // the TCPS fallback value from the SdfSchema.
205         const VtValue &oldComputedTcps = it->second.first;
206         const VtValue &newComputedTcps = it->second.second;
207         auto _MatchesFallback = [&layer](const VtValue &val) {
208             return layer->GetSchema().GetFallback(
209                 SdfFieldKeys->TimeCodesPerSecond) == val;
210         };
211 
212         // If the old and new TCPS values are the same, this indicates that
213         // either the old or new TCPS field is actually unauthored and is
214         // falling back to an authored FPS value. This is not a computed TCPS
215         // change for the layer itself and doesn't directly affect the offset
216         // for the layer relative to other layers.
217         //
218         // However, if this layer is the session or root layer of a cache's
219         // root layer stack, this change could still have an effect on the
220         // computed overall TCPS of that layer stack. That's why we still flag
221         // this change so we can check for this case after layer changes are
222         // processed.
223         //
224         // XXX: Note this requires an interpretation of the change information
225         // coming out of Sdf involving knowledge of specific implementation
226         // details of Sdf change management. Ideally Sdf should provide a
227         // notification differentiation between "authored TCPS" changed vs
228         // "computed TCPS" changed.
229         if (oldComputedTcps == newComputedTcps) {
230             if (rootLayerStacksMayNeedTcpsRecompute) {
231                 *rootLayerStacksMayNeedTcpsRecompute = true;
232             }
233             return false;
234         }
235 
236         // If either old or new value is empty, and the other value matches the
237         // fallback, then we don't have an effective TCPS change.
238         if ((oldComputedTcps.IsEmpty() && _MatchesFallback(newComputedTcps)) ||
239             (newComputedTcps.IsEmpty() && _MatchesFallback(oldComputedTcps))) {
240             return false;
241         }
242         return true;
243     }
244 
245     return false;
246 }
247 
248 static
249 bool
Pcp_EntryRequiresPrimIndexChange(const SdfChangeList::Entry & entry)250 Pcp_EntryRequiresPrimIndexChange(const SdfChangeList::Entry& entry)
251 {
252     // Inherits, specializes, reference or variants changed.
253     if (entry.flags.didChangePrimInheritPaths ||
254         entry.flags.didChangePrimSpecializes  ||
255         entry.flags.didChangePrimReferences   ||
256         entry.flags.didChangePrimVariantSets) {
257         return true;
258     }
259 
260     // Payload, permission or variant selection changed.
261     // XXX: We don't require a prim graph change if:
262     //        we add/remove an unrequested payload;
263     //        permissions change doesn't add/remove any specs
264     //            that themselves require prim graph changes;
265     //        variant selection was invalid and is still invalid.
266     for (auto const &p: entry.infoChanged) {
267         if (p.first == SdfFieldKeys->Payload ||
268             p.first == SdfFieldKeys->Permission ||
269             p.first == SdfFieldKeys->VariantSelection ||
270             p.first == SdfFieldKeys->Instanceable) {
271             return true;
272         }
273     }
274 
275     return false;
276 }
277 
278 enum {
279     Pcp_EntryChangeSpecsAddInert        = 1,
280     Pcp_EntryChangeSpecsRemoveInert     = 2,
281     Pcp_EntryChangeSpecsAddNonInert     = 4,
282     Pcp_EntryChangeSpecsRemoveNonInert  = 8,
283     Pcp_EntryChangeSpecsTargets         = 16,
284     Pcp_EntryChangeSpecsConnections     = 32,
285     Pcp_EntryChangeSpecsAdd =
286         Pcp_EntryChangeSpecsAddInert |
287         Pcp_EntryChangeSpecsAddNonInert,
288     Pcp_EntryChangeSpecsRemove =
289         Pcp_EntryChangeSpecsRemoveInert |
290         Pcp_EntryChangeSpecsRemoveNonInert,
291     Pcp_EntryChangeSpecsInert =
292         Pcp_EntryChangeSpecsAddInert |
293         Pcp_EntryChangeSpecsRemoveInert,
294     Pcp_EntryChangeSpecsNonInert =
295         Pcp_EntryChangeSpecsAddNonInert |
296         Pcp_EntryChangeSpecsRemoveNonInert
297 };
298 
299 static int
Pcp_EntryRequiresPrimSpecsChange(const SdfChangeList::Entry & entry)300 Pcp_EntryRequiresPrimSpecsChange(const SdfChangeList::Entry& entry)
301 {
302     int result = 0;
303 
304     result |= entry.flags.didAddInertPrim
305               ? Pcp_EntryChangeSpecsAddInert      : 0;
306     result |= entry.flags.didRemoveInertPrim
307              ? Pcp_EntryChangeSpecsRemoveInert    : 0;
308     result |= entry.flags.didAddNonInertPrim
309              ? Pcp_EntryChangeSpecsAddNonInert    : 0;
310     result |= entry.flags.didRemoveNonInertPrim
311              ? Pcp_EntryChangeSpecsRemoveNonInert : 0;
312 
313     return result;
314 }
315 
316 static int
Pcp_EntryRequiresPropertySpecsChange(const SdfChangeList::Entry & entry)317 Pcp_EntryRequiresPropertySpecsChange(const SdfChangeList::Entry& entry)
318 {
319     int result = 0;
320 
321     result |= entry.flags.didAddPropertyWithOnlyRequiredFields
322               ? Pcp_EntryChangeSpecsAddInert      : 0;
323     result |= entry.flags.didRemovePropertyWithOnlyRequiredFields
324              ? Pcp_EntryChangeSpecsRemoveInert    : 0;
325     result |= entry.flags.didAddProperty
326              ? Pcp_EntryChangeSpecsAddNonInert    : 0;
327     result |= entry.flags.didRemoveProperty
328              ? Pcp_EntryChangeSpecsRemoveNonInert : 0;
329 
330     if (entry.flags.didChangeRelationshipTargets) {
331         result |= Pcp_EntryChangeSpecsTargets;
332     }
333     if (entry.flags.didChangeAttributeConnection) {
334         result |= Pcp_EntryChangeSpecsConnections;
335     }
336 
337     return result;
338 }
339 
340 static bool
Pcp_EntryRequiresPropertyIndexChange(const SdfChangeList::Entry & entry)341 Pcp_EntryRequiresPropertyIndexChange(const SdfChangeList::Entry& entry)
342 {
343     for (auto const &p: entry.infoChanged) {
344         if (p.first == SdfFieldKeys->Permission) {
345             return true;
346         }
347     }
348     return false;
349 }
350 
351 // Returns true if any changed info field in the changelist entry is a
352 // field that may be an input used to compute file format arguments for a
353 // dynamic file format used by a prim index in the cache. This is a minimal
354 // filtering by field name only, ignoring all other context.
355 static bool
Pcp_ChangeMayAffectDynamicFileFormatArguments(const PcpCache * cache,const SdfChangeList::Entry & entry,std::string * debugSummary)356 Pcp_ChangeMayAffectDynamicFileFormatArguments(
357     const PcpCache* cache,
358     const SdfChangeList::Entry& entry,
359     std::string* debugSummary)
360 {
361     // Early out if the cache has no dynamic file format dependencies.
362     if (cache->HasAnyDynamicFileFormatArgumentDependencies()) {
363         for (const auto& change : entry.infoChanged) {
364             if (cache->IsPossibleDynamicFileFormatArgumentField(change.first)) {
365                 PCP_APPEND_DEBUG("  Info change for field '%s' may affect "
366                                  "dynamic file format arguments\n",
367                                  change.first.GetText());
368                 return true;
369             }
370         }
371     }
372 
373     return false;
374 }
375 
376 static bool
Pcp_PrimSpecOrDescendantHasRelocates(const SdfLayerHandle & layer,const SdfPath & primPath)377 Pcp_PrimSpecOrDescendantHasRelocates(const SdfLayerHandle& layer,
378                                      const SdfPath& primPath)
379 {
380     TRACE_FUNCTION();
381 
382     if (layer->HasField(primPath, SdfFieldKeys->Relocates)) {
383         return true;
384     }
385 
386     TfTokenVector primChildNames;
387     if (layer->HasField(primPath, SdfChildrenKeys->PrimChildren,
388                         &primChildNames)) {
389         for (const TfToken& name : primChildNames) {
390             if (Pcp_PrimSpecOrDescendantHasRelocates(
391                     layer, primPath.AppendChild(name))) {
392                 return true;
393             }
394         }
395     }
396 
397     return false;
398 }
399 
400 // Returns true if any of the info changed in the change list affects the file
401 // format arguments of for a dynamic file format under the prim index at path.
402 static bool
Pcp_DoesInfoChangeAffectFileFormatArguments(PcpCache const * cache,const SdfPath & primIndexPath,const SdfChangeList::Entry & changes,std::string * debugSummary)403 Pcp_DoesInfoChangeAffectFileFormatArguments(
404     PcpCache const *cache, const SdfPath& primIndexPath,
405     const SdfChangeList::Entry &changes,
406     std::string *debugSummary)
407 {
408     PCP_APPEND_DEBUG(
409         "Pcp_DoesInfoChangeAffectFileFormatArguments %s:%s?\n",
410         cache->GetLayerStackIdentifier().rootLayer->GetIdentifier().c_str(),
411         primIndexPath.GetText());
412 
413     // Get the cached  dynamic file format dependency data for the prim index.
414     // This will exist if the prim index exists and has any direct arcs that
415     // used a dynamic file format.
416     const PcpDynamicFileFormatDependencyData &depData =
417         cache->GetDynamicFileFormatArgumentDependencyData(primIndexPath);
418     if (depData.IsEmpty()) {
419         PCP_APPEND_DEBUG("  Prim index has no dynamic file format dependencies\n");
420         return false;
421     }
422 
423     // For each info field ask the dependency data if the change can affect
424     // the file format args of any node in the prim index graph.
425     for (const auto& change : changes.infoChanged) {
426         const bool isRelevantChange =
427             depData.CanFieldChangeAffectFileFormatArguments(
428                 change.first, change.second.first, change.second.second);
429         PCP_APPEND_DEBUG("  Field '%s' change: %s -> %s "
430                          "%s relevant for prim index path '%s'\n",
431                          change.first.GetText(),
432                          TfStringify(change.second.first).c_str(),
433                          TfStringify(change.second.second).c_str(),
434                          isRelevantChange ? "IS" : "is NOT",
435                          primIndexPath.GetText());
436         if (isRelevantChange) {
437             return true;
438         }
439     }
440 
441     return false;
442 }
443 
444 // DepFunc is a function type void (const PcpDependency &)
445 template <typename DepFunc>
446 static void
Pcp_DidChangeDependents(const PcpCache * cache,const SdfLayerHandle & layer,const SdfPath & path,bool processPrimDescendants,bool onlyExistingDependentPaths,const DepFunc & processDependencyFunc,std::string * debugSummary)447 Pcp_DidChangeDependents(
448     const PcpCache* cache,
449     const SdfLayerHandle& layer,
450     const SdfPath& path,
451     bool processPrimDescendants,
452     bool onlyExistingDependentPaths,
453     const DepFunc &processDependencyFunc,
454     std::string* debugSummary)
455 {
456     // Don't want to put a trace here, as this function can get called many
457     // times during change processing.
458     // TRACE_FUNCTION();
459 
460     // We don't recurse on site for property paths, only prim paths if
461     // necessary.
462     const bool recurseOnSite =
463         processPrimDescendants &&
464         (path == SdfPath::AbsoluteRootPath()  ||
465          path.IsPrimOrPrimVariantSelectionPath());
466     PcpDependencyVector deps = cache->FindSiteDependencies(
467         layer, path, PcpDependencyTypeAnyIncludingVirtual, recurseOnSite,
468         /* recurseOnIndex */ false,
469         /* filter */ onlyExistingDependentPaths);
470 
471     PCP_APPEND_DEBUG(
472         "   Resync following in @%s@ %s due to Sdf site @%s@<%s>%s:\n",
473         cache->GetLayerStackIdentifier()
474         .rootLayer->GetIdentifier().c_str(),
475         recurseOnSite ?
476         "recurse on prim descendants" :
477         "do not recurse on prim descendants",
478         layer->GetIdentifier().c_str(), path.GetText(),
479         onlyExistingDependentPaths ?
480         " (restricted to existing caches)" :
481         " (not restricted to existing caches)");
482 
483     // Run the process function on each found dependency.
484     for (const auto& dep: deps) {
485         PCP_APPEND_DEBUG(
486             "    <%s> depends on <%s>\n",
487             dep.indexPath.GetText(),
488             dep.sitePath.GetText());
489 
490         processDependencyFunc(dep);
491     }
492 
493     PCP_APPEND_DEBUG("   Resync end\n");
494 }
495 
496 void
DidChange(const TfSpan<const PcpCache * > & caches,const SdfLayerChangeListVec & changes)497 PcpChanges::DidChange(const TfSpan<const PcpCache*>& caches,
498                       const SdfLayerChangeListVec& changes)
499 {
500     // LayerStack changes
501     static const int LayerStackLayersChange       = 1;
502     static const int LayerStackOffsetsChange      = 2;
503     static const int LayerStackRelocatesChange    = 4;
504     static const int LayerStackSignificantChange  = 8;
505     static const int LayerStackResolvedPathChange = 16;
506     typedef int LayerStackChangeBitmask;
507     typedef std::map<PcpLayerStackPtr, LayerStackChangeBitmask>
508         LayerStackChangeMap;
509 
510     // Path changes
511     static const int PathChangeSimple      = 1;
512     static const int PathChangeTargets     = 2;
513     static const int PathChangeConnections = 4;
514     typedef int PathChangeBitmask;
515     typedef std::map<SdfPath, PathChangeBitmask,
516                      SdfPath::FastLessThan> PathChangeMap;
517     typedef PathChangeMap::value_type PathChangeValue;
518 
519     // Spec changes
520     typedef int SpecChangeBitmask;
521     typedef std::map<SdfPath, SpecChangeBitmask,
522                      SdfPath::FastLessThan> SpecChangesTypes;
523 
524     // Payload decorator changes
525     typedef std::pair<const PcpCache*, SdfPath> CacheAndLayerPathPair;
526     typedef std::vector<CacheAndLayerPathPair> CacheAndLayerPathPairVector;
527 
528     TRACE_FUNCTION();
529 
530     SdfPathSet pathsWithSignificantChanges;
531     PathChangeMap pathsWithSpecChanges;
532     SpecChangesTypes pathsWithSpecChangesTypes;
533     SdfPathSet pathsWithRelocatesChanges;
534     SdfPathVector oldPaths, newPaths;
535     SdfPathSet fallbackToAncestorPaths;
536 
537     CacheAndLayerPathPairVector fieldForFileFormatArgumentsChanges;
538 
539     // As we process each layer below, we'll look for changes that
540     // affect entire layer stacks, then process those in one pass
541     // at the end.
542     LayerStackChangeMap layerStackChangesMap;
543 
544     // Change debugging.
545     std::string summary;
546     std::string* debugSummary = TfDebug::IsEnabled(PCP_CHANGES) ? &summary : 0;
547 
548     PCP_APPEND_DEBUG("  Caches:\n");
549     for (const PcpCache* cache: caches) {
550         PCP_APPEND_DEBUG("    %s\n",
551                  TfStringify(cache->GetLayerStack()->GetIdentifier()).c_str());
552     }
553 
554     const bool allCachesInUsdMode = std::all_of(
555         caches.begin(), caches.end(),
556         [](const PcpCache* cache) { return cache->IsUsd(); });
557 
558     // Process all changes, first looping over all layers.
559     for (auto const &i: changes) {
560         const SdfLayerHandle& layer     = i.first;
561         const SdfChangeList& changeList = i.second;
562 
563         // PcpCaches in USD mode only cache prim indexes, so they only
564         // care about prim changes. We can do a pre-scan of the entries
565         // and bail early if none of the changes are for prims, skipping
566         // over unnecessary work.
567         if (allCachesInUsdMode) {
568             using _Entries = SdfChangeList::EntryList;
569 
570             const _Entries& entries = changeList.GetEntryList();
571             const bool hasPrimChanges = std::find_if(
572                 entries.begin(), entries.end(),
573                 [](const _Entries::value_type& entry) {
574                     return !entry.first.ContainsPropertyElements();
575                 }) != entries.end();
576 
577             if (!hasPrimChanges) {
578                 PCP_APPEND_DEBUG(
579                     "  Layer @%s@ changed:  skipping non-prim changes\n",
580                     layer->GetIdentifier().c_str());
581                 continue;
582             }
583         }
584 
585         // Find every layer stack in every cache that includes 'layer'.
586         // If there aren't any such layer stacks, we can ignore this change.
587         typedef std::pair<const PcpCache*, PcpLayerStackPtrVector>
588             CacheLayerStacks;
589         typedef std::vector<CacheLayerStacks> CacheLayerStacksVector;
590 
591         CacheLayerStacksVector cacheLayerStacks;
592         for (auto cache : caches) {
593             PcpLayerStackPtrVector stacks =
594                 cache->FindAllLayerStacksUsingLayer(layer);
595             if (!stacks.empty()) {
596                 cacheLayerStacks.emplace_back(cache, std::move(stacks));
597             }
598         }
599         if (cacheLayerStacks.empty()) {
600             PCP_APPEND_DEBUG("  Layer @%s@ changed:  unused\n",
601                              layer->GetIdentifier().c_str());
602             continue;
603         }
604 
605         PCP_APPEND_DEBUG("  Changes to layer %s:\n%s",
606                          layer->GetIdentifier().c_str(),
607                          TfStringify(changeList).c_str());
608 
609         // Reset state.
610         LayerStackChangeBitmask layerStackChangeMask = 0;
611         bool rootLayerStacksMayNeedTcpsRecompute = false;
612         pathsWithSignificantChanges.clear();
613         pathsWithSpecChanges.clear();
614         pathsWithSpecChangesTypes.clear();
615         pathsWithRelocatesChanges.clear();
616         oldPaths.clear();
617         newPaths.clear();
618         fallbackToAncestorPaths.clear();
619         fieldForFileFormatArgumentsChanges.clear();
620 
621         // Loop over each entry on the layer.
622         for (auto const &j: changeList.GetEntryList()) {
623             const SdfPath& path = j.first;
624             const SdfChangeList::Entry& entry = j.second;
625 
626             // Figure out for which paths we must fallback to an ancestor.
627             // These are the paths where a prim/property was added or
628             // removed and any descendant.
629             //
630             // When adding the first spec for a prim or property, there
631             // won't be any dependencies for that object yet, but we still
632             // need to figure out the locations that will be affected by
633             // the addition of this new object. Hence the need to fallback
634             // to an ancestor to synthesize dependencies.
635             //
636             // When removing a prim or property spec, the fallback ancestor
637             // is usually not needed because there should already be
638             // dependencies registered for that object. However, in the case
639             // where an object is renamed then removed in a single change
640             // block, we will need the fallback ancestor because the
641             // dependencies at the renamed path will not have been registered
642             // yet. The fallback ancestor code won't be run in the usual
643             // case anyway, so it's safe to just always set up the fallback
644             // ancestor path.
645             const bool fallbackToParent =
646                 entry.flags.didAddInertPrim                             ||
647                 entry.flags.didRemoveInertPrim                          ||
648                 entry.flags.didAddNonInertPrim                          ||
649                 entry.flags.didRemoveNonInertPrim                       ||
650                 entry.flags.didAddProperty                              ||
651                 entry.flags.didRemoveProperty                           ||
652                 entry.flags.didAddPropertyWithOnlyRequiredFields        ||
653                 entry.flags.didRemovePropertyWithOnlyRequiredFields;
654 
655             if (fallbackToParent) {
656                 fallbackToAncestorPaths.insert(path);
657             }
658 
659             if (path == SdfPath::AbsoluteRootPath()) {
660                 if (entry.flags.didReplaceContent) {
661                     pathsWithSignificantChanges.insert(path);
662                 }
663 
664                 // Treat a change to DefaultPrim as a resync
665                 // of that root prim path.
666                 auto i = entry.FindInfoChange(SdfFieldKeys->DefaultPrim);
667                 if (i != entry.infoChanged.end()) {
668                     // old value.
669                     TfToken token = i->second.first.GetWithDefault<TfToken>();
670                     pathsWithSignificantChanges.insert(
671                         SdfPath::IsValidIdentifier(token)
672                         ? SdfPath::AbsoluteRootPath().AppendChild(token)
673                         : SdfPath::AbsoluteRootPath());
674                     // new value.
675                     token = i->second.second.GetWithDefault<TfToken>();
676                     pathsWithSignificantChanges.insert(
677                         SdfPath::IsValidIdentifier(token)
678                         ? SdfPath::AbsoluteRootPath().AppendChild(token)
679                         : SdfPath::AbsoluteRootPath());
680                 }
681 
682                 // Handle changes that require blowing the layer stack.
683                 switch (Pcp_EntryRequiresLayerStackChange(entry)) {
684                 case Pcp_ChangesLayerStackChangeMaybeSignificant:
685                     layerStackChangeMask |= LayerStackLayersChange;
686                     for (auto const &k: entry.subLayerChanges) {
687                         if (k.second == SdfChangeList::SubLayerAdded ||
688                             k.second == SdfChangeList::SubLayerRemoved) {
689                             const std::string& sublayerPath = k.first;
690                             const _SublayerChangeType sublayerChange =
691                                 k.second == SdfChangeList::SubLayerAdded ?
692                                 _SublayerAdded : _SublayerRemoved;
693 
694                             for (auto const &i: cacheLayerStacks) {
695                                 bool significant = false;
696                                 const SdfLayerRefPtr sublayer =
697                                     _LoadSublayerForChange(i.first,
698                                                            layer,
699                                                            sublayerPath,
700                                                            sublayerChange);
701 
702                                 PCP_APPEND_DEBUG(
703                                     "  Layer @%s@ changed sublayers\n",
704                                     layer ?
705                                     layer->GetIdentifier().c_str() : "invalid");
706 
707                                 _DidChangeSublayer(i.first /* cache */,
708                                                    i.second /* stack */,
709                                                    sublayerPath,
710                                                    sublayer,
711                                                    sublayerChange,
712                                                    debugSummary,
713                                                    &significant);
714                                 if (significant) {
715                                     layerStackChangeMask |=
716                                         LayerStackSignificantChange;
717                                 }
718                             }
719                         }
720                     }
721                     break;
722 
723                 case Pcp_ChangesLayerStackChangeSignificant:
724                     // Must blow everything
725                     layerStackChangeMask |= LayerStackLayersChange |
726                                             LayerStackSignificantChange;
727                     pathsWithSignificantChanges.insert(path);
728                     PCP_APPEND_DEBUG("  Layer @%s@ changed:  significant\n",
729                                      layer->GetIdentifier().c_str());
730                     break;
731 
732                 case Pcp_ChangesLayerStackChangeNone:
733                     // Layer stack is okay.   Handle changes that require
734                     // blowing the layer stack offsets.
735                     if (Pcp_EntryRequiresLayerStackOffsetsChange(layer, entry,
736                             &rootLayerStacksMayNeedTcpsRecompute)) {
737                         layerStackChangeMask |= LayerStackOffsetsChange;
738 
739                         // Layer offsets are folded into the map functions
740                         // for arcs that originate from a layer. So, when
741                         // offsets authored in a layer change, all indexes
742                         // that depend on that layer must be significantly
743                         // resync'd to regenerate those functions.
744                         //
745                         // XXX: If this becomes a performance issue, we could
746                         //      potentially apply the same incremental updating
747                         //      that's currently done for relocates.
748                         pathsWithSignificantChanges.insert(path);
749                         PCP_APPEND_DEBUG("  Layer @%s@ changed:  "
750                                          "layer offsets (significant)\n",
751                                          layer->GetIdentifier().c_str());
752                     }
753                     break;
754                 }
755 
756                 if (entry.flags.didChangeResolvedPath) {
757                     layerStackChangeMask |= LayerStackResolvedPathChange;
758                 }
759             }
760 
761             // Handle changes that require a prim graph change.
762             else if (path.IsPrimOrPrimVariantSelectionPath()) {
763                 if (entry.flags.didRename) {
764                     // XXX: We don't have enough info to determine if
765                     //      the changes so far are a rename in layer
766                     //      stack space.  Renames in Sd are only renames
767                     //      in a Pcp layer stack if all specs in the
768                     //      layer stack were renamed the same way (for
769                     //      and given old path, new path pair).  But we
770                     //      don't know which layer stacks to check and
771                     //      which caches they belong to.  For example,
772                     //      if we rename in a referenced layer stack we
773                     //      don't know here what caches are referencing
774                     //      that layer stack.
775                     //
776                     //      In the future we'll probably avoid this
777                     //      problem altogether by requiring clients to
778                     //      do namespace edits through Csd if they want
779                     //      efficient handling.  Csd will be able to
780                     //      tell its PcpChanges object about the
781                     //      renames directly and we won't do *any*
782                     //      *handling of renames in this method.
783                     //
784                     //      For now we'll just treat renames as resyncs.
785                     oldPaths.push_back(entry.oldPath);
786                     newPaths.push_back(path);
787                     PCP_APPEND_DEBUG("  Renamed @%s@<%s> to <%s>\n",
788                                      layer->GetIdentifier().c_str(),
789                                      entry.oldPath.GetText(), path.GetText());
790                 }
791                 if (int specChanges = Pcp_EntryRequiresPrimSpecsChange(entry)) {
792                     pathsWithSpecChangesTypes[path] |= specChanges;
793                 }
794                 if (Pcp_EntryRequiresPrimIndexChange(entry)) {
795                     pathsWithSignificantChanges.insert(path);
796                 }
797                 else {
798                     for (const auto& c : cacheLayerStacks) {
799                         const PcpCache* cache = c.first;
800                         // Gather info changes that may affect dynamic file
801                         // format arguments so we can check dependents on
802                         // these changes later.
803                         if (Pcp_ChangeMayAffectDynamicFileFormatArguments(
804                                 cache, entry, debugSummary)) {
805                             PCP_APPEND_DEBUG(
806                                 "  Info change on @%s@<%s> may affect file "
807                                 "format arguments in cache '%s'\n",
808                                 layer->GetIdentifier().c_str(),
809                                 path.GetText(),
810                                 cache->GetLayerStackIdentifier().rootLayer
811                                     ->GetIdentifier().c_str());
812 
813                             fieldForFileFormatArgumentsChanges.push_back(
814                                 CacheAndLayerPathPair(cache, path));
815                         }
816                     }
817                 }
818 
819                 if (entry.HasInfoChange(SdfFieldKeys->Relocates)) {
820                     layerStackChangeMask |= LayerStackRelocatesChange;
821                 }
822             }
823             else if (!allCachesInUsdMode) {
824                 // See comment above regarding PcpCaches in USD mode.
825                 // We also check for USD mode here to ensure we don't
826                 // process any non-prim changes if the changelist had
827                 // a mix of prim and non-prim changes.
828                 if (path.IsPropertyPath()) {
829                     if (entry.flags.didRename) {
830                         // XXX: See the comment above regarding renaming
831                         //      prims.
832                         oldPaths.push_back(entry.oldPath);
833                         newPaths.push_back(path);
834                         PCP_APPEND_DEBUG("  Renamed @%s@<%s> to <%s>\n",
835                                          layer->GetIdentifier().c_str(),
836                                          entry.oldPath.GetText(),path.GetText());
837                     }
838                     if (int specChanges =
839                             Pcp_EntryRequiresPropertySpecsChange(entry)) {
840                         pathsWithSpecChangesTypes[path] |= specChanges;
841                     }
842                     if (Pcp_EntryRequiresPropertyIndexChange(entry)) {
843                         pathsWithSignificantChanges.insert(path);
844                     }
845                 }
846                 else if (path.IsTargetPath()) {
847                     if (entry.flags.didAddTarget) {
848                         pathsWithSpecChangesTypes[path] |=
849                             Pcp_EntryChangeSpecsAddInert;
850                     }
851                     if (entry.flags.didRemoveTarget) {
852                         pathsWithSpecChangesTypes[path] |=
853                             Pcp_EntryChangeSpecsRemoveInert;
854                     }
855                 }
856             }
857         } // end for all entries in changelist
858 
859         // If we processed a change that may affect the TCPS of root layer
860         // stacks, we check that here.
861         if (rootLayerStacksMayNeedTcpsRecompute) {
862             for (const auto &i : cacheLayerStacks) {
863                 const PcpCache *cache = i.first;
864                 // We only need to check the root layer stacks of caches
865                 // using this layer.
866                 if (const PcpLayerStackPtr& layerStack =
867                         cache->GetLayerStack()) {
868                     // If the layer stack will need to recompute its TCPS
869                     // because this layer changed, then mark that layer stack
870                     // will have its layer offsets change.
871                     if (Pcp_NeedToRecomputeLayerStackTimeCodesPerSecond(
872                             layerStack, layer)) {
873                         PCP_APPEND_DEBUG("  Layer @%s@ changed:  "
874                                          "root layer stack TCPS (significant)\n",
875                                          layer->GetIdentifier().c_str());
876                         layerStackChangesMap[layerStack] |=
877                             LayerStackOffsetsChange;
878                         // This is a significant change to all prim indexes.
879                         DidChangeSignificantly(cache, SdfPath::AbsoluteRootPath());
880                     }
881                 }
882             }
883         }
884 
885         // Push layer stack changes to all layer stacks using this layer.
886         if (layerStackChangeMask != 0) {
887             for (auto const &i: cacheLayerStacks) {
888                 for (auto const &layerStack: i.second) {
889                     layerStackChangesMap[layerStack] |= layerStackChangeMask;
890                 }
891             }
892         }
893 
894         // Handle spec changes.  What we do depends on what changes happened
895         // and the cache at each path.
896         //
897         //  Prim:
898         //     Add/remove inert     -- insignificant change (*)
899         //     Add/remove non-inert -- significant change
900         //
901         //  Property:
902         //     Add/remove inert     -- insignificant change
903         //     Add/remove non-inert -- significant change
904         //
905         // (*) We may be adding the first prim spec or removing the last prim
906         // spec from a composed prim in this case.  We'll check for this in
907         // DidChangeSpecs and upgrade to a significant change if we discover
908         // this is the case.
909         //
910         // Note that in the below code, the order of the if statements does
911         // matter, as a spec could be added, then removed (for example) within
912         // the same change.
913         for (const auto& value : pathsWithSpecChangesTypes) {
914             const SdfPath& path = value.first;
915             if (path.IsPrimOrPrimVariantSelectionPath()) {
916                 if (value.second & Pcp_EntryChangeSpecsNonInert) {
917                     pathsWithSignificantChanges.insert(path);
918                 }
919                 else if (value.second & Pcp_EntryChangeSpecsInert) {
920                     pathsWithSpecChanges[path] |= PathChangeSimple;
921                 }
922             }
923             else {
924                 if (value.second & Pcp_EntryChangeSpecsNonInert) {
925                     pathsWithSignificantChanges.insert(path);
926                 }
927                 else if (value.second & Pcp_EntryChangeSpecsInert) {
928                     pathsWithSpecChanges[path] |= PathChangeSimple;
929                 }
930 
931                 if (value.second & Pcp_EntryChangeSpecsTargets) {
932                     pathsWithSpecChanges[path] |= PathChangeTargets;
933                 }
934                 if (value.second & Pcp_EntryChangeSpecsConnections) {
935                     pathsWithSpecChanges[path] |= PathChangeConnections;
936                 }
937             }
938         }
939 
940         // For every path we've found on this layer that has a
941         // significant change, find all paths in the cache that use the
942         // spec at (layer, path) and mark them as affected.
943         for (const auto& path : pathsWithSignificantChanges) {
944             const bool onlyExistingDependentPaths =
945                 fallbackToAncestorPaths.count(path) == 0;
946             for (auto cache : caches) {
947                 // For significant changes to a prim (as opposed to property),
948                 // we need to process its dependencies as well as dependencies
949                 // on descendants of that prim.
950                 //
951                 // This is needed to accommodate relocates, specifically the
952                 // case where a descendant of the changed prim was relocated out
953                 // from beneath it. In this case, dependencies on that
954                 // descendant will be in a different branch of namespace than
955                 // the dependencies on the changed prim. We need to mark both
956                 // sets of dependencies as being changed.
957                 //
958                 // We don't need to do this for significant property changes as
959                 // properties can't be individually relocated.
960                 Pcp_DidChangeDependents(
961                     cache, layer, path, /*processPrimDescendants*/ true,
962                     onlyExistingDependentPaths,
963                     [this, &cache](const PcpDependency &dep) {
964                         DidChangeSignificantly(cache, dep.indexPath);
965                     },
966                     debugSummary);
967             }
968         }
969 
970         // For every (layer, path) site we've found that has a change
971         // to a field that a prim index that generates dynamic file format
972         // arguments cares about, find all paths in the cache that depend on
973         // that site and register a significant change if the file format says
974         // the field change affects how it generates arguments.
975         for (const auto& p : fieldForFileFormatArgumentsChanges) {
976             const bool onlyExistingDependentPaths =
977                 fallbackToAncestorPaths.count(p.second) == 0;
978 
979             const PcpCache* cache = p.first;
980             const SdfPath &changedPath = p.second;
981 
982             SdfChangeList::Entry const &changes =
983                 changeList.GetEntry(changedPath);
984             // We need to recurse on prim descendants for dynamic file format
985             // argument changes. This is to catch the case where there's
986             // a reference to a subroot prim who has an ancestor with a dynamic
987             // file format dependency. Changes that affect the ancestor may
988             // affect the descendant prim's prim index but that dependency will
989             // be stored with the descendant as the ancestor prim index is not
990             // itself cached when it is only used to compute subroot references.
991             Pcp_DidChangeDependents(
992                 cache, layer, p.second, /*processPrimDescendants*/ true,
993                 onlyExistingDependentPaths,
994                 [this, &cache, &changes, &debugSummary](
995                     const PcpDependency &dep) {
996                     if (Pcp_DoesInfoChangeAffectFileFormatArguments(
997                             cache, dep.indexPath, changes, debugSummary)) {
998                         DidChangeSignificantly(cache, dep.indexPath);
999                     }
1000                 },
1001                 debugSummary);
1002         }
1003 
1004         // For every non-inert prim spec that has been added to this layer,
1005         // check if it or any of its descendant prim specs contains relocates.
1006         // If so, all dependent layer stacks need to recompute its cached
1007         // relocates. We can skip this if all caches are in USD mode, since
1008         // relocates are disabled for those caches.
1009         if (!allCachesInUsdMode) {
1010             for (const auto& value : pathsWithSpecChangesTypes) {
1011                 const SdfPath& path = value.first;
1012                 if (!path.IsPrimOrPrimVariantSelectionPath() ||
1013                     !(value.second & Pcp_EntryChangeSpecsAddNonInert)) {
1014                     continue;
1015                 }
1016 
1017                 if (Pcp_PrimSpecOrDescendantHasRelocates(layer, path)) {
1018                     for (const CacheLayerStacks &i: cacheLayerStacks) {
1019                         if (i.first->IsUsd()) {
1020                             // No relocations in usd mode
1021                             continue;
1022                         }
1023                         for (const PcpLayerStackPtr &layerStack: i.second) {
1024                             layerStackChangesMap[layerStack]
1025                                 |= LayerStackRelocatesChange;
1026                         }
1027                     }
1028                     break;
1029                 }
1030             }
1031         }
1032 
1033         // For every path we've found that has a significant change,
1034         // check layer stacks that have discovered relocations that
1035         // could be affected by that change. We can skip this if all caches
1036         // are in USD mode, since relocates are disabled for those caches.
1037         if (!pathsWithSignificantChanges.empty() && !allCachesInUsdMode) {
1038             // If this scope turns out to be expensive, we should look
1039             // at switching PcpLayerStack's _relocatesPrimPaths from
1040             // a std::vector to a path set.  _AddRelocateEditsForLayerStack
1041             // also does a traversal and might see a similar benefit.
1042             TRACE_SCOPE("PcpChanges::DidChange -- Checking layer stack "
1043                         "relocations against significant prim resyncs");
1044 
1045             for(const CacheLayerStacks &i: cacheLayerStacks) {
1046                 if (i.first->IsUsd()) {
1047                     // No relocations in usd mode
1048                     continue;
1049                 }
1050                 for(const PcpLayerStackPtr &layerStack: i.second) {
1051                     const SdfPathVector& reloPaths =
1052                         layerStack->GetPathsToPrimsWithRelocates();
1053                     if (reloPaths.empty()) {
1054                         continue;
1055                     }
1056                     for(const SdfPath &changedPath:
1057                         pathsWithSignificantChanges) {
1058                         for(const SdfPath &reloPath: reloPaths) {
1059                             if (reloPath.HasPrefix(changedPath)) {
1060                                 layerStackChangesMap[layerStack]
1061                                     |= LayerStackRelocatesChange;
1062                                 goto doneWithLayerStack;
1063                             }
1064                         }
1065                     }
1066                     doneWithLayerStack:
1067                     ;
1068                 }
1069             }
1070         }
1071 
1072         // For every path we've found on this layer that maybe requires
1073         // rebuilding the property stack based on parent dependencies, find
1074         // all paths in the cache that use the spec at (layer,path).  If
1075         // there aren't any then find all paths in the cache that use the
1076         // parent.  In either case mark the found paths as needing their
1077         // property spec stacks blown.
1078         for (const auto& value : pathsWithSpecChanges) {
1079             const SdfPath& path        = value.first;
1080             PathChangeBitmask changes = value.second;
1081 
1082             for (auto cache : caches) {
1083                 Pcp_DidChangeDependents(
1084                     cache, layer, path, /*processPrimDescendants*/ false,
1085                     /*filter*/ false,
1086                     [this, &changes, &cache, &layer](const PcpDependency &dep) {
1087                         // If the changes for this path include something other
1088                         // than target changes, they must be spec changes.
1089                         if (changes & ~(PathChangeTargets |
1090                                         PathChangeConnections)) {
1091                             DidChangeSpecs(cache, dep.indexPath, layer,
1092                                            dep.sitePath);
1093                         }
1094                         if (changes & PathChangeTargets) {
1095                             DidChangeTargets(cache, dep.indexPath,
1096                                 PcpCacheChanges::TargetTypeRelationshipTarget);
1097                         }
1098                         if (changes & PathChangeConnections) {
1099                             DidChangeTargets(cache, dep.indexPath,
1100                                 PcpCacheChanges::TargetTypeConnection);
1101                         }
1102                     },
1103                     debugSummary);
1104             }
1105         }
1106 
1107         // For every path we've found on this layer that was namespace
1108         // edited, find all paths in the cache that map to the path and
1109         // the corresponding new path.  Save these internally for later
1110         // comparison to edits added through DidChangePaths().
1111         if (!oldPaths.empty()) {
1112             SdfPathVector depPaths;
1113 
1114             for (auto cache : caches) {
1115                 _PathEditMap& renameChanges = _GetRenameChanges(cache);
1116 
1117                 // Do every path.
1118                 for (size_t i = 0, n = oldPaths.size(); i != n; ++i) {
1119                     const SdfPath& oldPath = oldPaths[i];
1120                     const SdfPath& newPath = newPaths[i];
1121                     // Do every path dependent on the new path.  We might
1122                     // have an object at the new path and we're replacing
1123                     // it with the object at the old path.  So we must
1124                     // act as if we're deleting the object at the new path.
1125                     if (!newPath.IsEmpty()) {
1126                         PcpDependencyVector deps =
1127                             cache->FindSiteDependencies(
1128                                 layer, newPath,
1129                                 PcpDependencyTypeAnyNonVirtual,
1130                                 /* recurseOnSite */ false,
1131                                 /* recurseOnIndex */ false,
1132                                 /* filter */ true
1133                             );
1134                         for (const auto &dep: deps) {
1135                             renameChanges[dep.indexPath] = SdfPath();
1136                         }
1137                     }
1138 
1139                     // Do every path dependent on the old path.
1140                     PcpDependencyVector deps =
1141                         cache->FindSiteDependencies(
1142                             layer, oldPath,
1143                             PcpDependencyTypeAnyNonVirtual,
1144                             /* recurseOnSite */ false,
1145                             /* recurseOnIndex */ false,
1146                             /* filter */ true
1147                         );
1148                     for (const auto &dep: deps) {
1149                         SdfPath newIndexPath;
1150                         // If this isn't a delete then translate newPath
1151                         if (!newPath.IsEmpty()) {
1152                             newIndexPath =
1153                                 dep.mapFunc.MapSourceToTarget(newPath);
1154                         }
1155                         renameChanges[dep.indexPath] = newIndexPath;
1156                         PCP_APPEND_DEBUG("  renameChanges <%s> to <%s>\n",
1157                              dep.indexPath.GetText(),
1158                              newIndexPath.GetText());
1159                     }
1160                 }
1161             }
1162         }
1163     } // end for all layers in changelist map
1164 
1165     // Process layer stack changes.  This will handle both blowing
1166     // caches (as needed) for the layer stack contents and offsets,
1167     // as well as analyzing relocation changes in the layer stack.
1168     for (const auto& entry : layerStackChangesMap) {
1169         const PcpLayerStackPtr& layerStack = entry.first;
1170         LayerStackChangeBitmask layerStackChanges = entry.second;
1171 
1172         if (layerStackChanges & LayerStackResolvedPathChange) {
1173             const bool needToRecompute =
1174                 Pcp_NeedToRecomputeDueToAssetPathChange(layerStack);
1175 
1176             _DidChangeLayerStackResolvedPath(
1177                 caches, layerStack, needToRecompute, debugSummary);
1178             if (needToRecompute) {
1179                 layerStackChanges |= LayerStackLayersChange |
1180                                      LayerStackSignificantChange;
1181             }
1182         }
1183 
1184         if (layerStackChanges & LayerStackRelocatesChange) {
1185             _DidChangeLayerStackRelocations(caches, layerStack, debugSummary);
1186         }
1187 
1188         _DidChangeLayerStack(
1189             caches,
1190             layerStack,
1191             layerStackChanges & LayerStackLayersChange,
1192             layerStackChanges & LayerStackOffsetsChange,
1193             layerStackChanges & LayerStackSignificantChange);
1194     }
1195 
1196     if (debugSummary && !debugSummary->empty()) {
1197         TfDebug::Helper().Msg("PcpChanges::DidChange\n%s",
1198                               debugSummary->c_str());
1199     }
1200 }
1201 
1202 void
DidMuteLayer(const PcpCache * cache,const std::string & layerId)1203 PcpChanges::DidMuteLayer(
1204     const PcpCache* cache,
1205     const std::string& layerId)
1206 {
1207     // Change debugging.
1208     std::string summary;
1209     std::string* debugSummary = TfDebug::IsEnabled(PCP_CHANGES) ? &summary : 0;
1210 
1211     const SdfLayerRefPtr mutedLayer =
1212         _LoadSublayerForChange(cache, layerId, _SublayerRemoved);
1213     const PcpLayerStackPtrVector& layerStacks =
1214         cache->FindAllLayerStacksUsingLayer(mutedLayer);
1215 
1216     PCP_APPEND_DEBUG("  Did mute layer @%s@\n", layerId.c_str());
1217 
1218     if (!layerStacks.empty()) {
1219         _DidChangeSublayerAndLayerStacks(
1220             cache, layerStacks, layerId, mutedLayer, _SublayerRemoved,
1221             debugSummary);
1222     }
1223 
1224     if (debugSummary && !debugSummary->empty()) {
1225         TfDebug::Helper().Msg("PcpChanges::DidMuteLayer\n%s",
1226                               debugSummary->c_str());
1227     }
1228 }
1229 
1230 void
DidUnmuteLayer(const PcpCache * cache,const std::string & layerId)1231 PcpChanges::DidUnmuteLayer(
1232     const PcpCache* cache,
1233     const std::string& layerId)
1234 {
1235     // Change debugging.
1236     std::string summary;
1237     std::string* debugSummary = TfDebug::IsEnabled(PCP_CHANGES) ? &summary : 0;
1238 
1239     const SdfLayerRefPtr unmutedLayer =
1240         _LoadSublayerForChange(cache, layerId, _SublayerAdded);
1241     const PcpLayerStackPtrVector& layerStacks =
1242         cache->_layerStackCache->FindAllUsingMutedLayer(layerId);
1243 
1244     PCP_APPEND_DEBUG("  Did unmute layer @%s@\n", layerId.c_str());
1245 
1246     if (!layerStacks.empty()) {
1247         _DidChangeSublayerAndLayerStacks(
1248             cache, layerStacks, layerId, unmutedLayer, _SublayerAdded,
1249             debugSummary);
1250     }
1251 
1252     if (debugSummary && !debugSummary->empty()) {
1253         TfDebug::Helper().Msg("PcpChanges::DidUnmuteLayer\n%s",
1254                               debugSummary->c_str());
1255     }
1256 }
1257 
1258 void
DidMaybeFixSublayer(const PcpCache * cache,const SdfLayerHandle & layer,const std::string & sublayerPath)1259 PcpChanges::DidMaybeFixSublayer(
1260     const PcpCache* cache,
1261     const SdfLayerHandle& layer,
1262     const std::string& sublayerPath)
1263 {
1264     // Change debugging.
1265     std::string summary;
1266     std::string* debugSummary = TfDebug::IsEnabled(PCP_CHANGES) ? &summary : 0;
1267 
1268     // See if the sublayer is now readable.  If so mark the layer stacks
1269     // using the sublayer's parent (and thus the sublayer) as dirty, and also
1270     // all of the prims in cache that are using any prim from any of those
1271     // layer stacks.
1272     const SdfLayerRefPtr sublayer =
1273         _LoadSublayerForChange(cache, layer, sublayerPath, _SublayerAdded);
1274     const PcpLayerStackPtrVector& layerStacks =
1275         cache->FindAllLayerStacksUsingLayer(layer);
1276 
1277     PCP_APPEND_DEBUG(
1278         "  Layer @%s@ changed sublayer @%s@\n",
1279         layer ? layer->GetIdentifier().c_str() : "invalid",
1280         sublayerPath.c_str());
1281 
1282     _DidChangeSublayerAndLayerStacks(
1283         cache, layerStacks, sublayerPath, sublayer, _SublayerAdded,
1284         debugSummary);
1285 
1286     if (debugSummary && !debugSummary->empty()) {
1287         TfDebug::Helper().Msg("PcpChanges::DidMaybeFixSublayer\n%s",
1288                               debugSummary->c_str());
1289     }
1290 }
1291 
1292 void
_DidChangeSublayerAndLayerStacks(const PcpCache * cache,const PcpLayerStackPtrVector & layerStacks,const std::string & sublayerPath,const SdfLayerHandle & sublayer,_SublayerChangeType sublayerChange,std::string * debugSummary)1293 PcpChanges::_DidChangeSublayerAndLayerStacks(
1294     const PcpCache* cache,
1295     const PcpLayerStackPtrVector& layerStacks,
1296     const std::string& sublayerPath,
1297     const SdfLayerHandle& sublayer,
1298     _SublayerChangeType sublayerChange,
1299     std::string* debugSummary)
1300 {
1301     static const bool requiresLayerStackChange        = true;
1302     static const bool requiresLayerStackOffsetsChange = false;
1303     bool requiresSignificantChange = false;
1304 
1305     _DidChangeSublayer(cache, layerStacks,
1306                        sublayerPath, sublayer, sublayerChange,
1307                        debugSummary, &requiresSignificantChange);
1308 
1309     if (sublayer) {
1310         // Layer was loaded.  The layer stacks are changed.
1311         TF_FOR_ALL(layerStack, layerStacks) {
1312             _DidChangeLayerStack(TfSpan<const PcpCache*>(&cache, 1),
1313                                  *layerStack,
1314                                  requiresLayerStackChange,
1315                                  requiresLayerStackOffsetsChange,
1316                                  requiresSignificantChange);
1317         }
1318     }
1319 }
1320 
1321 void
DidMaybeFixAsset(const PcpCache * cache,const PcpSite & site,const SdfLayerHandle & srcLayer,const std::string & assetPath)1322 PcpChanges::DidMaybeFixAsset(
1323     const PcpCache* cache,
1324     const PcpSite& site,
1325     const SdfLayerHandle& srcLayer,
1326     const std::string& assetPath)
1327 {
1328     // Get the site's layer stack and make sure it's valid.
1329     PcpLayerStackPtr layerStack =
1330         cache->FindLayerStack(site.layerStackIdentifier);
1331     if (!layerStack) {
1332         return;
1333     }
1334 
1335     // Change debugging.
1336     std::string summary;
1337     std::string* debugSummary = TfDebug::IsEnabled(PCP_CHANGES) ? &summary : 0;
1338 
1339     // Load the layer.
1340     TfErrorMark m;
1341     SdfLayerRefPtr layer = SdfLayer::FindOrOpenRelativeToLayer(
1342         srcLayer, assetPath);
1343     m.Clear();
1344 
1345     PCP_APPEND_DEBUG("  Asset @%s@ %s\n",
1346                      assetPath.c_str(),
1347                      layer ? (layer->IsEmpty() ? "insignificant"
1348                                                : "significant")
1349                            : "invalid");
1350 
1351     if (layer) {
1352         // Hold layer to avoid reparsing.
1353         _lifeboat.Retain(layer);
1354 
1355         // Mark prims using site as changed.
1356         PCP_APPEND_DEBUG(
1357             "Resync following in @%s@ significantly due to "
1358             "loading asset used by @%s@<%s>:\n",
1359             cache->GetLayerStackIdentifier().rootLayer->
1360                  GetIdentifier().c_str(),
1361             layerStack->GetIdentifier().rootLayer->
1362                  GetIdentifier().c_str(), site.path.GetText());
1363         if (layerStack == cache->GetLayerStack()) {
1364             PCP_APPEND_DEBUG("    <%s>\n", site.path.GetText());
1365             DidChangeSignificantly(cache, site.path);
1366         }
1367         PcpDependencyVector deps =
1368             cache->FindSiteDependencies(layerStack, site.path,
1369                                         PcpDependencyTypeAnyIncludingVirtual,
1370                                         /* recurseOnSite */ true,
1371                                         /* recurseOnIndex */ true,
1372                                         /* filter */ true);
1373         for(const auto &dep: deps) {
1374             PCP_APPEND_DEBUG("    <%s>\n", dep.indexPath.GetText());
1375             DidChangeSignificantly(cache, dep.indexPath);
1376         }
1377     }
1378 
1379     if (debugSummary && !debugSummary->empty()) {
1380         TfDebug::Helper().Msg("PcpChanges::DidMaybeFixAsset\n%s",
1381                               debugSummary->c_str());
1382     }
1383 }
1384 
1385 void
DidChangeLayers(const PcpCache * cache)1386 PcpChanges::DidChangeLayers(const PcpCache* cache)
1387 {
1388     TF_DEBUG(PCP_CHANGES).Msg("PcpChanges::DidChangeLayers: @%s@\n",
1389                               cache->GetLayerStackIdentifier().rootLayer->
1390                                   GetIdentifier().c_str());
1391 
1392     PcpLayerStackChanges& changes = _GetLayerStackChanges(cache);
1393     if (!changes.didChangeLayers) {
1394         changes.didChangeLayers       = true;
1395         changes.didChangeLayerOffsets = false;
1396     }
1397 }
1398 
1399 void
DidChangeLayerOffsets(const PcpCache * cache)1400 PcpChanges::DidChangeLayerOffsets(const PcpCache* cache)
1401 {
1402     PcpLayerStackChanges& changes = _GetLayerStackChanges(cache);
1403     if (!changes.didChangeLayers) {
1404         changes.didChangeLayerOffsets = true;
1405     }
1406 }
1407 
1408 void
DidChangeSignificantly(const PcpCache * cache,const SdfPath & path)1409 PcpChanges::DidChangeSignificantly(const PcpCache* cache, const SdfPath& path)
1410 {
1411     _GetCacheChanges(cache).didChangeSignificantly.insert(path);
1412 }
1413 
1414 static bool
_NoLongerHasAnySpecs(const PcpPrimIndex & primIndex)1415 _NoLongerHasAnySpecs(const PcpPrimIndex& primIndex)
1416 {
1417     for (const PcpNodeRef &node: primIndex.GetNodeRange()) {
1418         if (PcpComposeSiteHasPrimSpecs(node)) {
1419             return false;
1420         }
1421     }
1422     return true;
1423 }
1424 
1425 void
DidChangeSpecs(const PcpCache * cache,const SdfPath & path,const SdfLayerHandle & changedLayer,const SdfPath & changedPath)1426 PcpChanges::DidChangeSpecs(
1427     const PcpCache* cache, const SdfPath& path,
1428     const SdfLayerHandle& changedLayer, const SdfPath& changedPath)
1429 {
1430     if (path.IsPrimPath()) {
1431         TF_VERIFY(changedPath.IsPrimOrPrimVariantSelectionPath());
1432         const bool primWasAdded = changedLayer->HasSpec(changedPath);
1433         const bool primWasRemoved = !primWasAdded;
1434 
1435         const PcpPrimIndex* primIndex = cache->FindPrimIndex(path);
1436         if (primIndex && primIndex->HasSpecs()) {
1437             // If the inert spec removed was the last spec in this prim index,
1438             // the composed prim no longer exists, so mark it as a significant
1439             // change.
1440             if (primWasRemoved && _NoLongerHasAnySpecs(*primIndex)) {
1441                 DidChangeSignificantly(cache, path);
1442                 return;
1443             }
1444 
1445             const PcpNodeRef nodeForChangedSpec =
1446                 primIndex->GetNodeProvidingSpec(changedLayer, changedPath);
1447             if (nodeForChangedSpec) {
1448                 // If this prim index is instanceable, the addition or removal
1449                 // of an inert spec could affect whether this node is considered
1450                 // instanceable, which would change the prim index's instancing
1451                 // key. Mark it as a significant change if this is the case.
1452                 //
1453                 // Note that we don't handle the case where the node for this
1454                 // spec can't be found, because it should never happen. This is
1455                 // because instanceable nodes cannot be ancestral nodes, and
1456                 // non-ancestral nodes are never culled/removed from the graph,
1457                 // so we should always be able to find them.
1458                 //
1459                 // See Pcp_ChildNodeIsInstanceable and _NodeCanBeCulled.
1460                 if (primIndex->IsInstanceable() &&
1461                     Pcp_ChildNodeInstanceableChanged(nodeForChangedSpec)) {
1462                     DidChangeSignificantly(cache, path);
1463                     return;
1464                 }
1465             }
1466             else if (primWasAdded) {
1467                 // If we're adding an inert prim spec, it may correspond to a
1468                 // node that was culled in the prim index at path. If so, we
1469                 // need to rebuild that index to pick up the new node. We don't
1470                 // need to rebuild the indexes for namespace descendants because
1471                 // those should not be affected.
1472                 _GetCacheChanges(cache).didChangePrims.insert(path);
1473                 return;
1474             }
1475         }
1476         else {
1477             // If no prim index was found for this path, we assume that if we're
1478             // adding an inert spec, it's the first one for this composed prim,
1479             // so mark it as a significant change.
1480             if (primWasAdded) {
1481                 DidChangeSignificantly(cache, path);
1482                 return;
1483             }
1484         }
1485     }
1486 
1487     DidChangeSpecStack(cache, path);
1488 }
1489 
1490 void
DidChangeSpecStack(const PcpCache * cache,const SdfPath & path)1491 PcpChanges::DidChangeSpecStack(const PcpCache* cache, const SdfPath& path)
1492 {
1493     _GetCacheChanges(cache).didChangeSpecs.insert(path);
1494 }
1495 
1496 void
DidChangeTargets(const PcpCache * cache,const SdfPath & path,PcpCacheChanges::TargetType targetType)1497 PcpChanges::DidChangeTargets(const PcpCache* cache, const SdfPath& path,
1498                              PcpCacheChanges::TargetType targetType)
1499 {
1500     _GetCacheChanges(cache).didChangeTargets[path] |= targetType;
1501 }
1502 
1503 void
DidChangeRelocates(const PcpCache * cache,const SdfPath & path)1504 PcpChanges::DidChangeRelocates(const PcpCache* cache, const SdfPath& path)
1505 {
1506     // XXX For now we resync the prim entirely.  This is both because
1507     // we do not yet have a way to incrementally update the mappings,
1508     // as well as to ensure that we provide a change entry that will
1509     // cause Csd to pull on the cache and keep its contents alive.
1510     _GetCacheChanges(cache).didChangeSignificantly.insert(path);
1511 }
1512 
1513 void
DidChangePaths(const PcpCache * cache,const SdfPath & oldPath,const SdfPath & newPath)1514 PcpChanges::DidChangePaths(
1515     const PcpCache* cache,
1516     const SdfPath& oldPath,
1517     const SdfPath& newPath)
1518 {
1519     TF_DEBUG(PCP_CHANGES).Msg("PcpChanges::DidChangePaths: @%s@<%s> to <%s>\n",
1520                               cache->GetLayerStackIdentifier().rootLayer->
1521                                   GetIdentifier().c_str(),
1522                               oldPath.GetText(), newPath.GetText());
1523 
1524     // Changes are ordered. A chain of A -> B; B -> C is different than a
1525     // parallel move B -> C; A -> B
1526     _GetCacheChanges(cache).didChangePath.emplace_back(oldPath, newPath);
1527 }
1528 
1529 void
DidDestroyCache(const PcpCache * cache)1530 PcpChanges::DidDestroyCache(const PcpCache* cache)
1531 {
1532     _cacheChanges.erase(const_cast<PcpCache*>(cache));
1533     _renameChanges.erase(const_cast<PcpCache*>(cache));
1534 
1535     // Note that a layer stack in _layerStackChanges may be expired.  We
1536     // just leave it there and let clients and Apply() check for expired
1537     // layer stacks.
1538 }
1539 
1540 void
DidChangeAssetResolver(const PcpCache * cache)1541 PcpChanges::DidChangeAssetResolver(const PcpCache* cache)
1542 {
1543     TF_DEBUG(PCP_CHANGES).Msg(
1544         "PcpChanges::DidChangeAssetResolver\n");
1545 
1546     // Change debugging.
1547     std::string summary;
1548     std::string* debugSummary = TfDebug::IsEnabled(PCP_CHANGES) ? &summary : 0;
1549 
1550     const ArResolverContextBinder binder(
1551         cache->GetLayerStackIdentifier().pathResolverContext);
1552 
1553     cache->ForEachPrimIndex(
1554         [this, cache, debugSummary](const PcpPrimIndex& primIndex) {
1555             if (Pcp_NeedToRecomputeDueToAssetPathChange(primIndex)) {
1556                 DidChangeSignificantly(cache, primIndex.GetPath());
1557                 PCP_APPEND_DEBUG("    %s\n", primIndex.GetPath().GetText());
1558             }
1559         }
1560     );
1561 
1562     cache->ForEachLayerStack(
1563         [this, &cache, debugSummary](const PcpLayerStackPtr& layerStack) {
1564             // This matches logic in _DidChange when processing changes
1565             // to a layer's resolved path.
1566             if (Pcp_NeedToRecomputeDueToAssetPathChange(layerStack)) {
1567                 _DidChangeLayerStack(
1568                     TfSpan<const PcpCache*>(&cache, 1), layerStack,
1569                     /* requiresLayerStackChange = */ true,
1570                     /* requiresLayerStackOffsetChange = */ false,
1571                     /* requiresSignificantChange = */ true);
1572             }
1573         }
1574     );
1575 
1576     if (debugSummary && !debugSummary->empty()) {
1577         TfDebug::Helper().Msg(
1578             "   Resync following in @%s@ significant due to layer "
1579             "resolved path change:\n%s",
1580             cache->GetLayerStackIdentifier().rootLayer->
1581                 GetIdentifier().c_str(),
1582             debugSummary->c_str());
1583     }
1584 }
1585 
1586 void
Swap(PcpChanges & other)1587 PcpChanges::Swap(PcpChanges& other)
1588 {
1589     std::swap(_layerStackChanges, other._layerStackChanges);
1590     std::swap(_cacheChanges, other._cacheChanges);
1591     std::swap(_renameChanges, other._renameChanges);
1592     _lifeboat.Swap(other._lifeboat);
1593 }
1594 
1595 bool
IsEmpty() const1596 PcpChanges::IsEmpty() const
1597 {
1598     return _layerStackChanges.empty() &&
1599            _cacheChanges.empty()      &&
1600            _renameChanges.empty();
1601 }
1602 
1603 const PcpChanges::LayerStackChanges&
GetLayerStackChanges() const1604 PcpChanges::GetLayerStackChanges() const
1605 {
1606     return _layerStackChanges;
1607 }
1608 
1609 const PcpChanges::CacheChanges&
GetCacheChanges() const1610 PcpChanges::GetCacheChanges() const
1611 {
1612     // NOTE: This is potentially expensive even if we've already done
1613     //       it.  In the expected use pattern we only call this method
1614     //       once, so it shouldn't be a problem.
1615     _Optimize();
1616 
1617     return _cacheChanges;
1618 }
1619 
1620 const PcpLifeboat&
GetLifeboat() const1621 PcpChanges::GetLifeboat() const
1622 {
1623     return _lifeboat;
1624 }
1625 
1626 void
Apply() const1627 PcpChanges::Apply() const
1628 {
1629     // NOTE: This is potentially expensive even if we've already done
1630     //       it.  In the expected use pattern we only call this method
1631     //       once, so it shouldn't be a problem.
1632     _Optimize();
1633 
1634     // Apply layer changes first.
1635     TF_FOR_ALL(i, _layerStackChanges) {
1636         if (i->first) {
1637             i->first->Apply(i->second, &_lifeboat);
1638         }
1639     }
1640 
1641     // Now apply cache changes.
1642     TF_FOR_ALL(i, _cacheChanges) {
1643         i->first->Apply(i->second, &_lifeboat);
1644     }
1645 }
1646 
1647 PcpLayerStackChanges&
_GetLayerStackChanges(const PcpCache * cache)1648 PcpChanges::_GetLayerStackChanges(const PcpCache* cache)
1649 {
1650     return _layerStackChanges[cache->GetLayerStack()];
1651 }
1652 
1653 PcpLayerStackChanges&
_GetLayerStackChanges(const PcpLayerStackPtr & layerStack)1654 PcpChanges::_GetLayerStackChanges(const PcpLayerStackPtr& layerStack)
1655 {
1656     return _layerStackChanges[layerStack];
1657 }
1658 
1659 PcpCacheChanges&
_GetCacheChanges(const PcpCache * cache)1660 PcpChanges::_GetCacheChanges(const PcpCache* cache)
1661 {
1662     return _cacheChanges[const_cast<PcpCache*>(cache)];
1663 }
1664 
1665 PcpChanges::_PathEditMap&
_GetRenameChanges(const PcpCache * cache)1666 PcpChanges::_GetRenameChanges(const PcpCache* cache)
1667 {
1668     return _renameChanges[const_cast<PcpCache*>(cache)];
1669 }
1670 
1671 void
_Optimize() const1672 PcpChanges::_Optimize() const
1673 {
1674     const_cast<PcpChanges*>(this)->_Optimize();
1675 }
1676 
1677 void
_Optimize()1678 PcpChanges::_Optimize()
1679 {
1680     TF_FOR_ALL(i, _renameChanges) {
1681         _OptimizePathChanges(i->first, &_cacheChanges[i->first], &i->second);
1682     }
1683 
1684     // This must be called after _OptimizePathChanges().
1685     TF_FOR_ALL(i, _cacheChanges) {
1686         _Optimize(&i->second);
1687     }
1688 }
1689 
1690 void
_Optimize(PcpCacheChanges * changes)1691 PcpChanges::_Optimize(PcpCacheChanges* changes)
1692 {
1693     // Subsume changes implied by ancestors.
1694     Pcp_SubsumeDescendants(&changes->didChangeSignificantly);
1695 
1696     // Subsume changes implied by prim graph changes.
1697     TF_FOR_ALL(i, changes->didChangeSignificantly) {
1698         Pcp_SubsumeDescendants(&changes->didChangePrims, *i);
1699         Pcp_SubsumeDescendants(&changes->didChangeSpecs, *i);
1700         Pcp_SubsumeDescendants(&changes->_didChangeSpecsInternal, *i);
1701     }
1702 
1703     // Subsume spec changes for prims whose indexes will be rebuilt.
1704     TF_FOR_ALL(i, changes->didChangePrims) {
1705         changes->didChangeSpecs.erase(*i);
1706         changes->_didChangeSpecsInternal.erase(*i);
1707     }
1708 
1709     // Subsume spec changes that don't change the contents of the stack
1710     // changes against those that may change the contents.
1711     TF_FOR_ALL(i, changes->didChangeSpecs) {
1712         changes->_didChangeSpecsInternal.erase(*i);
1713     }
1714 
1715     // XXX: Do we subsume name changes?
1716 }
1717 
1718 void
_OptimizePathChanges(const PcpCache * cache,PcpCacheChanges * changes,const _PathEditMap * pathChanges)1719 PcpChanges::_OptimizePathChanges(
1720     const PcpCache* cache,
1721     PcpCacheChanges* changes,
1722     const _PathEditMap* pathChanges)
1723 {
1724     // XXX: DidChangePaths handles rename chains. I.e. A renamed to B
1725     //      then renamed to C. pathChanges is a map but we may need to handle
1726     //      one oldPath appearing multiple times in didChangePath, e.g.
1727     //      A -> B -> C and D -> B -> E, where B appears in two chains.
1728 
1729     // Copy the path changes and discard any that are also in
1730     // changes->didChangePath.
1731     _PathEditMap sdOnly(*pathChanges);
1732     for (const auto &pathPair : changes->didChangePath) {
1733         auto it = sdOnly.find(pathPair.first);
1734         // Note that we check for exact matches of mapping oldPath to newPath.
1735         if (it != sdOnly.end() && it->second == pathPair.second) {
1736             sdOnly.erase(it);
1737         }
1738     }
1739 
1740     std::string summary;
1741     std::string* debugSummary = TfDebug::IsEnabled(PCP_CHANGES) ? &summary : 0;
1742 
1743     // sdOnly now has the path changes that Sd told us about but
1744     // DidChangePaths() did not.  We must assume the worst.
1745     for (const auto& change : sdOnly) {
1746         const SdfPath& oldPath = change.first;
1747         const SdfPath& newPath = change.second;
1748 
1749         PCP_APPEND_DEBUG("  Sd only path change @%s@<%s> to <%s>\n",
1750                          cache->GetLayerStackIdentifier().rootLayer->
1751                              GetIdentifier().c_str(),
1752                          oldPath.GetText(), newPath.GetText());
1753         changes->didChangeSignificantly.insert(oldPath);
1754         if (!newPath.IsEmpty()) {
1755             changes->didChangeSignificantly.insert(newPath);
1756         }
1757     }
1758 
1759     if (debugSummary && !debugSummary->empty()) {
1760         TfDebug::Helper().Msg("PcpChanges::_Optimize:\n%s",
1761                               debugSummary->c_str());
1762     }
1763 }
1764 
1765 SdfLayerRefPtr
_LoadSublayerForChange(const PcpCache * cache,const std::string & sublayerPath,_SublayerChangeType sublayerChange) const1766 PcpChanges::_LoadSublayerForChange(
1767     const PcpCache* cache,
1768     const std::string& sublayerPath,
1769     _SublayerChangeType sublayerChange) const
1770 {
1771     // Bind the resolver context.
1772     const ArResolverContextBinder binder(
1773         cache->GetLayerStackIdentifier().pathResolverContext);
1774 
1775     // Load the layer.
1776     SdfLayerRefPtr sublayer;
1777 
1778     const SdfLayer::FileFormatArguments sublayerArgs =
1779         Pcp_GetArgumentsForFileFormatTarget(
1780             sublayerPath, cache->GetFileFormatTarget());
1781 
1782     if (sublayerChange == _SublayerAdded) {
1783         sublayer = SdfLayer::FindOrOpen(sublayerPath, sublayerArgs);
1784     }
1785     else {
1786         sublayer = SdfLayer::Find(sublayerPath, sublayerArgs);
1787     }
1788 
1789     return sublayer;
1790 }
1791 
1792 SdfLayerRefPtr
_LoadSublayerForChange(const PcpCache * cache,const SdfLayerHandle & layer,const std::string & sublayerPath,_SublayerChangeType sublayerChange) const1793 PcpChanges::_LoadSublayerForChange(
1794     const PcpCache* cache,
1795     const SdfLayerHandle& layer,
1796     const std::string& sublayerPath,
1797     _SublayerChangeType sublayerChange) const
1798 {
1799     if (!layer) {
1800         return SdfLayerRefPtr();
1801     }
1802 
1803     // Bind the resolver context.
1804     const ArResolverContextBinder binder(
1805         cache->GetLayerStackIdentifier().pathResolverContext);
1806 
1807     // Load the layer.
1808     SdfLayerRefPtr sublayer;
1809 
1810     const SdfLayer::FileFormatArguments sublayerArgs =
1811         Pcp_GetArgumentsForFileFormatTarget(
1812             sublayerPath, cache->GetFileFormatTarget());
1813 
1814     // Note the possible conversions from SdfLayerHandle to SdfLayerRefPtr below.
1815     if (SdfLayer::IsAnonymousLayerIdentifier(sublayerPath)) {
1816         sublayer = SdfLayer::Find(sublayerPath, sublayerArgs);
1817     }
1818     else {
1819         // Don't bother trying to open a sublayer if we're removing it;
1820         // either it's already opened in the system and we'll find it, or
1821         // it's invalid, which we'll deal with below.
1822         if (sublayerChange == _SublayerAdded) {
1823             TfErrorMark m;
1824             sublayer = SdfLayer::FindOrOpenRelativeToLayer(
1825                 layer, sublayerPath, sublayerArgs);
1826             m.Clear();
1827         }
1828         else {
1829             sublayer = SdfLayer::FindRelativeToLayer(
1830                 layer, sublayerPath, sublayerArgs);
1831         }
1832     }
1833 
1834     return sublayer;
1835 }
1836 
1837 void
_DidChangeSublayer(const PcpCache * cache,const PcpLayerStackPtrVector & layerStacks,const std::string & sublayerPath,const SdfLayerHandle & sublayer,_SublayerChangeType sublayerChange,std::string * debugSummary,bool * significant)1838 PcpChanges::_DidChangeSublayer(
1839     const PcpCache* cache,
1840     const PcpLayerStackPtrVector& layerStacks,
1841     const std::string& sublayerPath,
1842     const SdfLayerHandle& sublayer,
1843     _SublayerChangeType sublayerChange,
1844     std::string* debugSummary,
1845     bool *significant)
1846 {
1847     *significant = (sublayer && !sublayer->IsEmpty());
1848 
1849     PCP_APPEND_DEBUG("  %s sublayer @%s@ %s\n",
1850                      sublayer ? (*significant ? "significant"
1851                                               : "insignificant")
1852                               : "invalid",
1853                      sublayerPath.c_str(),
1854                      sublayerChange == _SublayerAdded ? "added" : "removed");
1855 
1856     if (!sublayer || (!*significant && cache->IsUsd())) {
1857         // If the added or removed sublayer is invalid, or if it is
1858         // insignificant and this cache is a USD cache, then it has no effect on
1859         // composed results so we don't need to register any changes.
1860         return;
1861     }
1862 
1863     // Keep the layer alive to avoid reparsing.
1864     _lifeboat.Retain(sublayer);
1865 
1866     // Register change entries for affected paths.
1867     //
1868     // For significant sublayer changes, the sublayer may have introduced
1869     // new prims with new arcs, requiring prim and property indexes to be
1870     // recomputed. So, register significant changes for every prim path
1871     // in the cache that uses any path in any of the layer stacks that
1872     // included layer.  Only bother doing this for prims, since the
1873     // properties will be implicitly invalidated by significant
1874     // prim resyncs.
1875     //
1876     // For insignificant sublayer changes, the only prim that's really
1877     // affected is the pseudo-root. However, we still need to rebuild the
1878     // prim stacks for every prim that uses an affected layer stack. This
1879     // is because PcpPrimIndex's prim stack stores indices into the layer
1880     // stack that may need to be adjusted due to the addition or removal of
1881     // a layer from that stack.
1882     //
1883     // We rely on the caller to provide the affected layer stacks for
1884     // us because some changes introduce new dependencies that wouldn't
1885     // have been registered yet using the normal means -- such as unmuting
1886     // a sublayer.
1887 
1888     bool anyFound = false;
1889     TF_FOR_ALL(layerStack, layerStacks) {
1890         PcpDependencyVector deps = cache->FindSiteDependencies(
1891             *layerStack,
1892             SdfPath::AbsoluteRootPath(),
1893             PcpDependencyTypeAnyIncludingVirtual,
1894             /* recurseOnSite */ true,
1895             /* recurseOnIndex */ true,
1896             /* filter */ true);
1897         for (const auto &dep: deps) {
1898             if (!dep.indexPath.IsAbsoluteRootOrPrimPath()) {
1899                 // Filter to only prims; see comment above re: properties.
1900                 continue;
1901             }
1902             if (!anyFound) {
1903                 PCP_APPEND_DEBUG(
1904                     "  %s following in @%s@ due to "
1905                     "%s reload in sublayer @%s@:\n",
1906                     *significant ? "Resync" : "Spec changes",
1907                     cache->GetLayerStackIdentifier().rootLayer->
1908                          GetIdentifier().c_str(),
1909                     *significant ? "significant" : "insignificant",
1910                     sublayer->GetIdentifier().c_str());
1911                 anyFound = true;
1912             }
1913             PCP_APPEND_DEBUG("    <%s>\n", dep.indexPath.GetText());
1914             if (*significant) {
1915                 DidChangeSignificantly(cache, dep.indexPath);
1916             } else {
1917                 _DidChangeSpecStackInternal(cache, dep.indexPath);
1918             }
1919         }
1920     }
1921 }
1922 
1923 void
_DidChangeLayerStack(const TfSpan<const PcpCache * > & caches,const PcpLayerStackPtr & layerStack,bool requiresLayerStackChange,bool requiresLayerStackOffsetsChange,bool requiresSignificantChange)1924 PcpChanges::_DidChangeLayerStack(
1925     const TfSpan<const PcpCache*>& caches,
1926     const PcpLayerStackPtr& layerStack,
1927     bool requiresLayerStackChange,
1928     bool requiresLayerStackOffsetsChange,
1929     bool requiresSignificantChange)
1930 {
1931     PcpLayerStackChanges& changes = _GetLayerStackChanges(layerStack);
1932     changes.didChangeLayers        |= requiresLayerStackChange;
1933     changes.didChangeLayerOffsets  |= requiresLayerStackOffsetsChange;
1934     changes.didChangeSignificantly |= requiresSignificantChange;
1935 
1936     // didChangeLayers subsumes didChangeLayerOffsets.
1937     if (changes.didChangeLayers) {
1938         changes.didChangeLayerOffsets = false;
1939     }
1940 
1941     if (requiresLayerStackChange || requiresSignificantChange) {
1942         for (const PcpCache *cache: caches) {
1943             if (cache->UsesLayerStack(layerStack)) {
1944                 _GetCacheChanges(cache).didMaybeChangeLayers = true;
1945             }
1946         }
1947     }
1948 }
1949 
1950 static void
_DeterminePathsAffectedByRelocationChanges(const SdfRelocatesMap & oldMap,const SdfRelocatesMap & newMap,SdfPathSet * affectedPaths)1951 _DeterminePathsAffectedByRelocationChanges( const SdfRelocatesMap & oldMap,
1952                                             const SdfRelocatesMap & newMap,
1953                                             SdfPathSet *affectedPaths )
1954 {
1955     TF_FOR_ALL(path, oldMap) {
1956         SdfRelocatesMap::const_iterator i = newMap.find(path->first);
1957         if (i == newMap.end() || i->second != path->second) {
1958             // This entry in oldMap does not exist in newMap, or
1959             // newMap relocates this to a different path.
1960             // Record the affected paths.
1961             affectedPaths->insert(path->first);
1962             affectedPaths->insert(path->second);
1963             if (i != newMap.end()) {
1964                 affectedPaths->insert(i->second);
1965             }
1966         }
1967     }
1968     TF_FOR_ALL(path, newMap) {
1969         SdfRelocatesMap::const_iterator i = oldMap.find(path->first);
1970         if (i == oldMap.end() || i->second != path->second) {
1971             // This entry in newMap does not exist in oldMap, or
1972             // oldMap relocated this to a different path.
1973             // Record the affected paths.
1974             affectedPaths->insert(path->first);
1975             affectedPaths->insert(path->second);
1976             if (i != oldMap.end()) {
1977                 affectedPaths->insert(i->second);
1978             }
1979         }
1980     }
1981 }
1982 
1983 // Handle changes to relocations.  This requires:
1984 // 1. rebuilding the composed relocation tables in layer stacks
1985 // 2. blowing PrimIndex caches affected by relocations
1986 // 3. rebuilding MapFunction values that consumed those relocations
1987 void
_DidChangeLayerStackRelocations(const TfSpan<const PcpCache * > & caches,const PcpLayerStackPtr & layerStack,std::string * debugSummary)1988 PcpChanges::_DidChangeLayerStackRelocations(
1989     const TfSpan<const PcpCache*>& caches,
1990     const PcpLayerStackPtr & layerStack,
1991     std::string* debugSummary)
1992 {
1993     PcpLayerStackChanges& changes = _GetLayerStackChanges(layerStack);
1994 
1995     if (changes.didChangeRelocates) {
1996         // There might be multiple relocation changes in a given
1997         // layer stack, but we only need to process them once.
1998         return;
1999     }
2000 
2001     changes.didChangeRelocates = true;
2002 
2003     // Rebuild this layer stack's composed relocations.
2004     // Store the result in the PcpLayerStackChanges so they can
2005     // be committed when the changes are applied.
2006     Pcp_ComputeRelocationsForLayerStack(
2007         layerStack->GetLayers(),
2008         &changes.newRelocatesSourceToTarget,
2009         &changes.newRelocatesTargetToSource,
2010         &changes.newIncrementalRelocatesSourceToTarget,
2011         &changes.newIncrementalRelocatesTargetToSource,
2012         &changes.newRelocatesPrimPaths);
2013 
2014     // Compare the old and new relocations to determine which
2015     // paths (in this layer stack) are affected.
2016     _DeterminePathsAffectedByRelocationChanges(
2017         layerStack->GetRelocatesSourceToTarget(),
2018         changes.newRelocatesSourceToTarget,
2019         &changes.pathsAffectedByRelocationChanges);
2020 
2021     // Resync affected prims.
2022     // Use dependencies to find affected caches.
2023     if (!changes.pathsAffectedByRelocationChanges.empty()) {
2024         PCP_APPEND_DEBUG("  Relocation change in %s affects:\n",
2025                          TfStringify(layerStack).c_str());
2026     }
2027     for (const PcpCache* cache: caches) {
2028         // Find the equivalent layer stack in this cache.
2029         PcpLayerStackPtr equivLayerStack =
2030             cache->FindLayerStack(layerStack->GetIdentifier());
2031         if (!equivLayerStack) {
2032             continue;
2033         }
2034 
2035         SdfPathSet depPathSet;
2036         for (const SdfPath& path : changes.pathsAffectedByRelocationChanges) {
2037             PCP_APPEND_DEBUG("    <%s>\n", path.GetText());
2038 
2039             PcpDependencyVector deps =
2040                 cache->FindSiteDependencies(
2041                     equivLayerStack, path,
2042                     PcpDependencyTypeAnyIncludingVirtual,
2043                     /* recurseOnSite */ true,
2044                     /* recurseOnIndex */ true,
2045                     /* filterForExistingCachesOnly */ false);
2046             for (const auto &dep: deps) {
2047                 depPathSet.insert(dep.indexPath);
2048             }
2049         }
2050 
2051         if (!depPathSet.empty()) {
2052             PCP_APPEND_DEBUG("  and dependent paths in %s\n",
2053                              TfStringify(layerStack).c_str());
2054         }
2055         for (const SdfPath& depPath : depPathSet) {
2056             PCP_APPEND_DEBUG("      <%s>\n", depPath.GetText());
2057             DidChangeSignificantly(cache, depPath);
2058         }
2059     }
2060 }
2061 
2062 void
_DidChangeLayerStackResolvedPath(const TfSpan<const PcpCache * > & caches,const PcpLayerStackPtr & layerStack,bool requiresLayerStackChange,std::string * debugSummary)2063 PcpChanges::_DidChangeLayerStackResolvedPath(
2064     const TfSpan<const PcpCache*>& caches,
2065     const PcpLayerStackPtr& layerStack,
2066     bool requiresLayerStackChange,
2067     std::string* debugSummary)
2068 {
2069     const ArResolverContextBinder binder(
2070         layerStack->GetIdentifier().pathResolverContext);
2071 
2072     for (const PcpCache* cache : caches) {
2073         PcpDependencyVector deps;
2074 
2075         if (requiresLayerStackChange) {
2076             // If layerStack needs to be recomputed, any prim index that depends
2077             // on any site in layerStack must be resynced since recomputing the
2078             // layer stack may cause new opinions to be added or removed.
2079             deps = cache->FindSiteDependencies(
2080                 layerStack, SdfPath::AbsoluteRootPath(),
2081                 PcpDependencyTypeAnyIncludingVirtual,
2082                 /* recurseOnSite */ true,
2083                 /* recurseOnIndex */ false,
2084                 /* filterForExisting */ true);
2085         }
2086         else {
2087             // If layerStack does not need to be recomputed, it's still possible
2088             // that prim indexes that use sites in layerStack need to be
2089             // resynced because they have references to asset paths that now
2090             // resolve to different assets. For example, if the resolved path
2091             // for layer A in layerStack changed, any asset paths in that layer
2092             // that were relative to layer A may now resolve differently.
2093             //
2094             // So, we grab all prim indexes that depend on any site in the layer
2095             // stack, and all of the descendants of those prim indexes, and
2096             // mark them as needing a resync if we detect the above.
2097             deps = cache->FindSiteDependencies(
2098                 layerStack, SdfPath::AbsoluteRootPath(),
2099                 PcpDependencyTypeAnyIncludingVirtual,
2100                 /* recurseOnSite */ true,
2101                 /* recurseOnIndex */ true,
2102                 /* filterForExisting */ true);
2103 
2104             auto noResyncNeeded = [cache](const PcpDependency& dep) {
2105                 if (!dep.indexPath.IsPrimPath()) {
2106                     return true;
2107                 }
2108                 const PcpPrimIndex* primIndex =
2109                     cache->FindPrimIndex(dep.indexPath);
2110                 return (TF_VERIFY(primIndex) &&
2111                         !Pcp_NeedToRecomputeDueToAssetPathChange(*primIndex));
2112             };
2113 
2114             deps.erase(
2115                 std::remove_if(deps.begin(), deps.end(), noResyncNeeded),
2116                 deps.end());
2117         }
2118 
2119         if (deps.empty()) {
2120             continue;
2121         }
2122 
2123         PCP_APPEND_DEBUG(
2124             "   Resync following in @%s@ significant due to layer "
2125             "resolved path change:\n",
2126             cache->GetLayerStackIdentifier().rootLayer->
2127                 GetIdentifier().c_str());
2128 
2129         for (const PcpDependency& dep : deps) {
2130             PCP_APPEND_DEBUG("    <%s>\n", dep.indexPath.GetText());
2131             DidChangeSignificantly(cache, dep.indexPath);
2132         }
2133     }
2134 }
2135 
2136 void
_DidChangeSpecStackInternal(const PcpCache * cache,const SdfPath & path)2137 PcpChanges::_DidChangeSpecStackInternal(
2138     const PcpCache* cache, const SdfPath& path)
2139 {
2140     _GetCacheChanges(cache)._didChangeSpecsInternal.insert(path);
2141 }
2142 
2143 PXR_NAMESPACE_CLOSE_SCOPE
2144