diff --git a/lib/mayaHydra/hydraExtensions/sceneIndex/mhMayaUsdProxyShapeSceneIndex.cpp b/lib/mayaHydra/hydraExtensions/sceneIndex/mhMayaUsdProxyShapeSceneIndex.cpp index c4be986ac..5687af687 100644 --- a/lib/mayaHydra/hydraExtensions/sceneIndex/mhMayaUsdProxyShapeSceneIndex.cpp +++ b/lib/mayaHydra/hydraExtensions/sceneIndex/mhMayaUsdProxyShapeSceneIndex.cpp @@ -100,7 +100,22 @@ void MayaUsdProxyShapeSceneIndex::_StageInvalidate(const MAYAUSDAPI_NS::ProxySta { _usdImagingStageSceneIndex->SetStage(nullptr); _populated = false; - Populate(); + // Simply mark populate as dirty and do not call + // Populate(); + // here. Doing so is incorrect for two reasons: + // - _StageInvalidate() is a callback called during Maya invalidation. + // Populate() calls MayaUsdProxyShapeBase::getUsdStage(), which calls + // MayaUsdProxyShapeBase::compute(), which should not be done during + // dirty propagation. + // - Calling getUsdStage() through Populate() creates an invalidate + // callback dependency between _StageInvalidate() and + // the mayaUsd plugin MayaStagesSubject::onStageInvalidate(). During + // getUsdStage(), MayaStagesSubject::setupListeners() is called, and it + // depends on MayaStagesSubject::onStageInvalidate() being called first, + // otherwise setupListeners() and therefore getUsdStage() will fail. + // + // Invalidate callbacks should not have dependencies on one another --- + // it should be possible to call them in random order. } void MayaUsdProxyShapeSceneIndex::_ObjectsChanged( diff --git a/test/lib/mayaUsd/render/mayaToHydra/cpp/testUsdStageFromFile.py b/test/lib/mayaUsd/render/mayaToHydra/cpp/testUsdStageFromFile.py index 12744232e..15787e279 100644 --- a/test/lib/mayaUsd/render/mayaToHydra/cpp/testUsdStageFromFile.py +++ b/test/lib/mayaUsd/render/mayaToHydra/cpp/testUsdStageFromFile.py @@ -17,6 +17,7 @@ import fixturesUtils import mtohUtils import usdUtils +import mayaUsd import testUtils from testUtils import PluginLoaded @@ -51,11 +52,24 @@ def test_UsdStageFromFile(self): cmds.setAttr('cubeShape.filePath', usdScenePath, type="string") + cmds.refresh() + populateCallsPost = cmds.mayaHydraInstruments("MayaUsdProxyShapeSceneIndex:NbPopulateCalls", q=True) self.assertEqual(populateCallsPre+1, populateCallsPost) cmds.mayaHydraCppTest(self.CONE_PATH, f="TestHydraPrim.fromAppPath") + def test_getStage(self): + + # Any file will do. + usdScenePath = testUtils.getTestScene('testUsdNativeInstances', 'instancedCubeHierarchies.usda') + + proxyShapePathStr = usdUtils.createStageFromFile(usdScenePath) + + stage = mayaUsd.lib.GetPrim(proxyShapePathStr).GetStage() + + self.assertIsNotNone(stage) + if __name__ == '__main__': fixturesUtils.runTests(globals())