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