Skip to content

Commit 829f11e

Browse files
matthewcpppixar-oss
authored andcommitted
This change fixes a coding error that is triggered when performing a sublayer operation on a layer whose file format is a package. The current implementation which generates fine grained change lists makes use of an anonymous layer to compute a diff against. It is an error to create such a layer with a package file format. To workaround this limitation with the current implementation, we send packages down the "big bang" invalidation path.
(Internal change: 2355629)
1 parent b213500 commit 829f11e

File tree

4 files changed

+119
-0
lines changed

4 files changed

+119
-0
lines changed

pxr/usd/pcp/changes.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "pxr/usd/pcp/pathTranslation.h"
1919
#include "pxr/usd/pcp/utils.h"
2020
#include "pxr/usd/sdf/changeList.h"
21+
#include "pxr/usd/sdf/fileFormat.h"
2122
#include "pxr/usd/sdf/layer.h"
2223
#include "pxr/usd/ar/resolverContextBinder.h"
2324
#include "pxr/base/tf/envSetting.h"
@@ -1555,6 +1556,7 @@ PcpChanges::_DidMuteLayer(
15551556
if (!TfGetEnvSetting(PCP_ENABLE_MINIMAL_CHANGES_FOR_LAYER_OPERATIONS) ||
15561557
!mutedLayer ||
15571558
mutedLayer->IsEmpty() ||
1559+
mutedLayer->GetFileFormat()->IsPackage() ||
15581560
Pcp_LayerMightHaveRelocates(cache, mutedLayer))
15591561
{
15601562
_DidChangeSublayerAndLayerStacks(
@@ -1614,6 +1616,7 @@ PcpChanges::_DidUnmuteLayer(
16141616
if (!TfGetEnvSetting(PCP_ENABLE_MINIMAL_CHANGES_FOR_LAYER_OPERATIONS) ||
16151617
!unmutedLayer ||
16161618
unmutedLayer->IsEmpty() ||
1619+
unmutedLayer->GetFileFormat()->IsPackage() ||
16171620
Pcp_LayerMightHaveRelocates(cache, unmutedLayer))
16181621
{
16191622
_DidChangeSublayerAndLayerStacks(
@@ -2238,6 +2241,7 @@ PcpChanges::_DidAddOrRemoveSublayer(
22382241
PCP_ENABLE_MINIMAL_CHANGES_FOR_LAYER_OPERATIONS) ||
22392242
!sublayer ||
22402243
sublayer->IsEmpty() ||
2244+
sublayer->GetFileFormat()->IsPackage() ||
22412245
Pcp_LayerMightHaveRelocates(cache, sublayer))
22422246
{
22432247
bool isSignificant = false;

pxr/usd/usd/CMakeLists.txt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,7 @@ pxr_test_scripts(
227227
testenv/testUsdNamespaceEditorTargetPathFixup.py
228228
testenv/testUsdNotices.py
229229
testenv/testUsdObjectsChangedNotices.py
230+
testenv/testUsdObjectsChangedNoticesSublayerOps.py
230231
testenv/testUsdOpaqueAttributes.py
231232
testenv/testUsdPathExpressionAttrs.py
232233
testenv/testUsdPayloads.py
@@ -621,6 +622,11 @@ pxr_install_test_dir(
621622
DEST testUsdNamespaceEditorTargetPathFixup
622623
)
623624

625+
pxr_install_test_dir(
626+
SRC testenv/testUsdObjectsChangedNoticesSublayerOps
627+
DEST testUsdObjectsChangedNoticesSublayerOps
628+
)
629+
624630
pxr_install_test_dir(
625631
SRC testenv/testUsdPrims.testenv
626632
DEST testUsdPrims
@@ -1202,6 +1208,12 @@ pxr_register_test(testUsdObjectsChangedNotices
12021208
EXPECTED_RETURN_CODE 0
12031209
)
12041210

1211+
pxr_register_test(testUsdObjectsChangedNoticesSublayerOps
1212+
PYTHON
1213+
COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testUsdObjectsChangedNoticesSublayerOps"
1214+
EXPECTED_RETURN_CODE 0
1215+
)
1216+
12051217
pxr_register_test(testUsdNamespaceEditor
12061218
PYTHON
12071219
COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testUsdNamespaceEditor"
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
#!/pxrpythonsubst
2+
#
3+
# Copyright 2025 Pixar
4+
#
5+
# Licensed under the terms set forth in the LICENSE.txt file available at
6+
# https://openusd.org/license.
7+
8+
9+
import unittest
10+
from pxr import Kind, Sdf, Tf, Usd
11+
12+
class TestUsdObjectsChangedNoticesSublayerOps(unittest.TestCase):
13+
def _listenForNotices(self, stage):
14+
# Each ObjectsChanged notice is converted to a dictionary and appended
15+
# to self._notices.
16+
self._notices = []
17+
self._noticeKey = Tf.Notice.Register(
18+
Usd.Notice.ObjectsChanged,
19+
self._onObjectsChanged,
20+
stage)
21+
22+
def _onObjectsChanged(self, notice, sender):
23+
asDict = {}
24+
resynced = notice.GetResyncedPaths()
25+
changedInfoOnly = notice.GetChangedInfoOnlyPaths()
26+
resolvedAssetPathsResynced = notice.GetResolvedAssetPathsResyncedPaths()
27+
if resynced:
28+
asDict['Resynced'] = {
29+
str(path): notice.GetChangedFields(path)
30+
for path in resynced
31+
}
32+
if changedInfoOnly:
33+
asDict['ChangedInfoOnly'] = {
34+
str(path): notice.GetChangedFields(path)
35+
for path in changedInfoOnly
36+
}
37+
if resolvedAssetPathsResynced:
38+
asDict['ResolvedAssetPathsResynced'] = {
39+
str(path): notice.GetChangedFields(path)
40+
for path in resolvedAssetPathsResynced
41+
}
42+
self._notices.append(asDict)
43+
44+
def test_InsertPackageSublayer(self):
45+
stage = Usd.Stage.CreateInMemory()
46+
self._listenForNotices(stage)
47+
stage.GetRootLayer().subLayerPaths = ["./package.usdz"]
48+
self.assertEqual(len(self._notices), 1)
49+
self.assertDictEqual(self._notices[0], {
50+
'Resynced': {
51+
'/': []
52+
}
53+
})
54+
55+
def test_RemovePackageSublayer(self):
56+
root = Sdf.Layer.CreateAnonymous('root.usda')
57+
root.ImportFromString("""#usda 1.0
58+
(
59+
subLayers = [@./package.usdz@]
60+
)
61+
""")
62+
stage = Usd.Stage.Open(root)
63+
self._listenForNotices(stage)
64+
stage.GetRootLayer().subLayerPaths = []
65+
self.assertEqual(len(self._notices), 1)
66+
self.assertDictEqual(self._notices[0], {
67+
'Resynced': {
68+
'/': []
69+
}
70+
})
71+
72+
def test_MutePackageSublayer(self):
73+
root = Sdf.Layer.CreateAnonymous('root.usda')
74+
root.ImportFromString("""#usda 1.0
75+
(
76+
subLayers = [@./package.usdz@]
77+
)
78+
""")
79+
stage = Usd.Stage.Open(root)
80+
self._listenForNotices(stage)
81+
stage.MuteLayer('./package.usdz')
82+
self.assertEqual(len(self._notices), 1)
83+
self.assertDictEqual(self._notices[0], {
84+
'Resynced': {
85+
'/': []
86+
}
87+
})
88+
89+
def test_UnmutePackageSublayer(self):
90+
stage = Usd.Stage.CreateInMemory()
91+
stage.MuteLayer('./package.usdz')
92+
stage.GetRootLayer().subLayerPaths = ["./package.usdz"]
93+
self._listenForNotices(stage)
94+
stage.UnmuteLayer('./package.usdz')
95+
self.assertEqual(len(self._notices), 1)
96+
self.assertDictEqual(self._notices[0], {
97+
'Resynced': {
98+
'/': []
99+
}
100+
})
101+
102+
if __name__ == "__main__":
103+
unittest.main()
Binary file not shown.

0 commit comments

Comments
 (0)