Skip to content

Commit

Permalink
Merge pull request #3432 from Autodesk/bailp/EMSUSD-749/lost-edit-as-…
Browse files Browse the repository at this point in the history
…maya

EMSUSD-749 fix how stages are updated when saved
  • Loading branch information
seando-adsk authored Nov 3, 2023
2 parents 3969bb5 + e9959c5 commit fd9ab59
Show file tree
Hide file tree
Showing 9 changed files with 87 additions and 31 deletions.
1 change: 1 addition & 0 deletions lib/mayaUsd/commands/abstractLayerEditorWindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ class MAYAUSD_CORE_PUBLIC AbstractLayerEditorWindow
virtual void printLayer() = 0;
virtual void clearLayer() = 0;
virtual void selectPrimsWithSpec() = 0;
virtual void updateLayerModel() = 0;

virtual void selectProxyShape(const char* shapePath) = 0;
};
Expand Down
18 changes: 18 additions & 0 deletions lib/mayaUsd/nodes/layerManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
//
#include "layerManager.h"

#include <mayaUsd/commands/abstractLayerEditorWindow.h>
#include <mayaUsd/listeners/notice.h>
#include <mayaUsd/listeners/proxyShapeNotice.h>
#include <mayaUsd/nodes/proxyShapeBase.h>
Expand Down Expand Up @@ -254,6 +255,7 @@ class LayerDatabase : public TfWeakBase
void clearProxies();
bool hasDirtyLayer() const;
void refreshProxiesToSave();
void updateLayerManagers();

std::map<std::string, SdfLayerRefPtr> _idToLayer;
TfNotice::Key _onStageSetKey;
Expand Down Expand Up @@ -439,6 +441,21 @@ void LayerDatabase::clearProxies()
_internalProxiesToSave.clear();
}

void LayerDatabase::updateLayerManagers()
{
auto creator = MayaUsd::AbstractLayerEditorCreator::instance();
if (!creator)
return;

for (const std::string& panelName : creator->getAllPanelNames()) {
AbstractLayerEditorWindow* window = creator->getWindow(panelName.c_str());
if (!window)
continue;

window->updateLayerModel();
}
}

bool LayerDatabase::hasDirtyLayer() const
{
for (const auto& info : _proxiesToSave) {
Expand Down Expand Up @@ -646,6 +663,7 @@ bool LayerDatabase::saveUsd(bool isExport)
}

clearProxies();
updateLayerManagers();
return (MayaUsd::kCompleted == result);
}

Expand Down
61 changes: 38 additions & 23 deletions lib/mayaUsd/nodes/proxyShapeBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -820,19 +820,25 @@ MStatus MayaUsdProxyShapeBase::computeInStageDataCached(MDataBlock& dataBlock)

bool isIncomingStage = false;

// Compute the load set for the stage.
MDataHandle loadPayloadsHandle = dataBlock.inputValue(loadPayloadsAttr, &retValue);
CHECK_MSTATUS_AND_RETURN_IT(retValue);

UsdStage::InitialLoadSet loadSet = loadPayloadsHandle.asBool()
? UsdStage::InitialLoadSet::LoadAll
: UsdStage::InitialLoadSet::LoadNone;

// If there is a dynamic attribute containing the exact load rules
// for payload, start by loading nothing. The correct payload will
// be loaded by the load rules.
if (hasLoadRulesAttribute(*this))
loadSet = UsdStage::InitialLoadSet::LoadNone;
// Note: we explicitly always load no payload initially and will load them
// later on if requested. The reason is that there are other code elsewhere
// that updates the stages. Those functions must find the same existing stages.
// Somewhat unfortunately, the OpenUSD API to open a stage only finds an existing
// stage if *all* parameters passed to open the stage match, including the initial
// load set. In order to be consistent everywhere, we must always pass in the same
// initial load set. Given that not loading payloads is the "lightest" version,
// that is what we request.
//
// Furthermore, for any statge that had its payload loaded or unloaded by the user
// we keep the detailed load and unload state of all prims, so we would use the
// load-none mode anyway and apply the detailed rules afterward, and this is
// probably the common case for stages that actually contain payloads.
//
// TODO: in the future, we need to provide a stage (and layer) internal manager
// that would stand between MayaUSD and OpenUSD and manage stages and layers
// and deal with consistent Open and other considerations, like updating stages
// and layers when anonymous layers are saved to disk.
const UsdStage::InitialLoadSet loadSet = UsdStage::InitialLoadSet::LoadNone;

// If inData has an incoming connection, then use it. Otherwise generate stage from the filepath
if (!inDataHandle.data().isNull()) {
Expand Down Expand Up @@ -966,16 +972,9 @@ MStatus MayaUsdProxyShapeBase::computeInStageDataCached(MDataBlock& dataBlock)
// then UsdStage::Open will create the in-memory session layer for us,
// just as we want.
if (sessionLayer) {
sharedUsdStage = UsdStage::Open(
rootLayer,
sessionLayer,
ArGetResolver().CreateDefaultContextForAsset(fileString),
loadSet);
sharedUsdStage = UsdStage::Open(rootLayer, sessionLayer, loadSet);
} else {
sharedUsdStage = UsdStage::Open(
rootLayer,
ArGetResolver().CreateDefaultContextForAsset(fileString),
loadSet);
sharedUsdStage = UsdStage::Open(rootLayer, loadSet);
}

sharedUsdStage->SetEditTarget(
Expand Down Expand Up @@ -1072,8 +1071,24 @@ MStatus MayaUsdProxyShapeBase::computeInStageDataCached(MDataBlock& dataBlock)
}

if (finalUsdStage) {
// Compute the load set for the stage.
MDataHandle loadPayloadsHandle = dataBlock.inputValue(loadPayloadsAttr, &retValue);
CHECK_MSTATUS_AND_RETURN_IT(retValue);

// Apply the payload rules based on either the saved payload rules
// dynamic attribute containing the exact load rules for payload,
// or the load-payload attribute.
if (hasLoadRulesAttribute(*this)) {
copyLoadRulesFromAttribute(*this, *finalUsdStage);
} else {
if (loadPayloadsHandle.asBool()) {
finalUsdStage->Load(SdfPath("/"), UsdLoadPolicy::UsdLoadWithDescendants);
} else {
finalUsdStage->Unload(SdfPath("/"));
}
}

primPath = finalUsdStage->GetPseudoRoot().GetPath();
copyLoadRulesFromAttribute(*this, *finalUsdStage);
copyLayerMutingFromAttribute(*this, *finalUsdStage);
if (!_targetLayer)
_targetLayer = getTargetLayerFromAttribute(*this, *finalUsdStage);
Expand Down
3 changes: 3 additions & 0 deletions lib/mayaUsd/utils/utilSerialization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,9 @@ void updateAllCachedStageWithLayer(SdfLayerRefPtr originalLayer, const std::stri
std::vector<UsdStageRefPtr> stages = cache.FindAllMatching(originalLayer);
for (const auto& stage : stages) {
auto sessionLayer = stage->GetSessionLayer();
// Note: See comments in lib\mayaUsd\nodes\proxyShapeBase.cpp, in the
// function computeInStageDataCached() about requirements about
// matching UsdStage::Open() arguments to find a stage.
auto newStage = UsdStage::UsdStage::Open(
newLayer, sessionLayer, UsdStage::InitialLoadSet::LoadNone);
newStage->SetLoadRules(stage->GetLoadRules());
Expand Down
2 changes: 2 additions & 0 deletions lib/usd/ui/layerEditor/mayaLayerEditorWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,8 @@ void MayaLayerEditorWindow::addAnonymousSublayer()
treeView()->callMethodOnSelection(name, &LayerTreeItem::addAnonymousSublayer);
}

void MayaLayerEditorWindow::updateLayerModel() { _sessionState.refreshCurrentStageEntry(); }

void MayaLayerEditorWindow::addParentLayer()
{
QString name = "Add Parent Layer";
Expand Down
1 change: 1 addition & 0 deletions lib/usd/ui/layerEditor/mayaLayerEditorWindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ class MayaLayerEditorWindow
void printLayer() override;
void clearLayer() override;
void selectPrimsWithSpec() override;
void updateLayerModel() override;

void selectProxyShape(const char* shapePath) override;

Expand Down
15 changes: 12 additions & 3 deletions lib/usd/ui/layerEditor/mayaSessionState.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -184,11 +184,15 @@ void MayaSessionState::unregisterNotifications()
TfNotice::Revoke(_stageResetNoticeKey);
}

void MayaSessionState::mayaUsdStageReset(const MayaUsdProxyStageSetNotice& notice)
void MayaSessionState::refreshCurrentStageEntry()
{
refreshStageEntry(_currentStageEntry._proxyShapePath);
}

void MayaSessionState::refreshStageEntry(std::string const& proxyShapePath)
{
auto shapePath = notice.GetShapePath();
StageEntry entry;
if (getStageEntry(&entry, shapePath.c_str())) {
if (getStageEntry(&entry, proxyShapePath.c_str())) {
if (entry._proxyShapePath == _currentStageEntry._proxyShapePath) {
QTimer::singleShot(0, this, [this, entry]() {
mayaUsdStageResetCBOnIdle(entry);
Expand All @@ -200,6 +204,11 @@ void MayaSessionState::mayaUsdStageReset(const MayaUsdProxyStageSetNotice& notic
}
}

void MayaSessionState::mayaUsdStageReset(const MayaUsdProxyStageSetNotice& notice)
{
refreshStageEntry(notice.GetShapePath());
}

void MayaSessionState::mayaUsdStageResetCBOnIdle(StageEntry const& entry)
{
Q_EMIT stageResetSignal(entry);
Expand Down
3 changes: 3 additions & 0 deletions lib/usd/ui/layerEditor/mayaSessionState.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@ class MayaSessionState
// in this case, the stage needs to be re-created on the new file
void rootLayerPathChanged(std::string const& in_path) override;

void refreshCurrentStageEntry();
void refreshStageEntry(std::string const& proxyShapePath);

std::string proxyShapePath() { return _currentStageEntry._proxyShapePath; }

Q_SIGNALS:
Expand Down
14 changes: 9 additions & 5 deletions test/lib/mayaUsd/nodes/testProxyShapeBase.py
Original file line number Diff line number Diff line change
Expand Up @@ -630,9 +630,11 @@ def testShareStageLoadRules(self):
proxyShapePath = proxyShapes[0]
stage = mayaUsd.lib.GetPrim(proxyShapePath).GetStage()

# check that the stage has no load rules
# check that the stage has a single load rule to laod everything.
loadRules = stage.GetLoadRules()
self.assertEqual(len(loadRules.GetRules()), 0)
self.assertEqual(len(loadRules.GetRules()), 1)
self.assertEqual(loadRules.GetRules()[0][0], "/")
self.assertEqual(loadRules.GetRules()[0][1], loadRules.AllRule)

# add a new rule to unload the room
cmd = contextOps.doOpCmd(['Unload'])
Expand All @@ -642,9 +644,11 @@ def testShareStageLoadRules(self):
# check that the expected load rules are on the stage.
def check_load_rules(stage):
loadRules = stage.GetLoadRules()
self.assertEqual(len(loadRules.GetRules()), 1)
self.assertEqual(loadRules.GetRules()[0][0], "/Room_set")
self.assertEqual(loadRules.GetRules()[0][1], loadRules.NoneRule)
self.assertEqual(len(loadRules.GetRules()), 2)
self.assertEqual(loadRules.GetRules()[0][0], "/")
self.assertEqual(loadRules.GetRules()[0][1], loadRules.AllRule)
self.assertEqual(loadRules.GetRules()[1][0], "/Room_set")
self.assertEqual(loadRules.GetRules()[1][1], loadRules.NoneRule)

check_load_rules(stage)

Expand Down

0 comments on commit fd9ab59

Please sign in to comment.