Skip to content

Commit

Permalink
EMSUSD-1722 fix node origin detection
Browse files Browse the repository at this point in the history
- Pass the proxy node to the layer manager so it can determine which
  layer manager corresponds to the proxy node.
- We keep track of the association with a new proxy shape
  attribute that contains the UUID of the layer manager node so that we
  can lookup the node when needed to find the layer manager.
- Fix a crash in MayaSessionState when the proxy shape has been deleted
  before the on-idle callback is run.
- This can happen in scripts that creates scene, a stage and clear the
  scene in one go, before an on-idle callback is run.
- Make the test more similar to the script in the ticket.

Note: originally, I tried to use an attribute plug connection, but we're
not allowed to connect or disconnect plugs during DG evaluation and that
was preventing us from updating the layer manager connection in the
proxy shape.
  • Loading branch information
pierrebai-adsk committed Oct 31, 2024
1 parent 8a634e0 commit f17afcc
Show file tree
Hide file tree
Showing 8 changed files with 230 additions and 120 deletions.
96 changes: 61 additions & 35 deletions lib/mayaUsd/nodes/layerManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -114,20 +114,23 @@ MStatus disconnectCompoundArrayPlug(MPlug arrayPlug)
return dgmod.doIt();
}

/// @brief Verify if the given node is either from the given reference, if that is not null,
/// or from the main Maya scene if the reference is null.
/// @brief Verify if the given node is from a reference.
static bool
isNodeFromDesiredOrigin(const MFnReference* fromReference, const MFnDependencyNode& node)
isNodeFromDesiredOrigin(const MFnDependencyNode& node, MayaUsdProxyShapeBase* forProxyShape)
{
if (fromReference) {
return fromReference->containsNodeExactly(node.object());
} else {
return !node.isFromReferencedFile();
}
const bool proxyIsFromReference
= (forProxyShape && MFnDependencyNode(forProxyShape->thisMObject()).isFromReferencedFile());
return node.isFromReferencedFile() == proxyIsFromReference;
}

MayaUsd::LayerManager* findNode(const MFnReference* fromReference = nullptr)
MayaUsd::LayerManager* findNode(MayaUsdProxyShapeBase* forProxyShape)
{
if (forProxyShape) {
if (MayaUsd::LayerManager* layerManager = forProxyShape->getLayerManager()) {
return layerManager;
}
}

// Check for cached layer manager before searching
MFnDependencyNode fn;
if (layerManagerHandle.isValid() && layerManagerHandle.isAlive()) {
Expand All @@ -143,7 +146,7 @@ MayaUsd::LayerManager* findNode(const MFnReference* fromReference = nullptr)
MObject mobj = iter.item();
fn.setObject(mobj);
if (fn.typeId() == MayaUsd::LayerManager::typeId) {
if (isNodeFromDesiredOrigin(fromReference, fn)) {
if (isNodeFromDesiredOrigin(fn, forProxyShape)) {
layerManagerHandle = mobj;
return static_cast<MayaUsd::LayerManager*>(fn.userNode());
}
Expand All @@ -152,9 +155,9 @@ MayaUsd::LayerManager* findNode(const MFnReference* fromReference = nullptr)
return nullptr;
}

MayaUsd::LayerManager* findOrCreateNode(const MFnReference* fromReference = nullptr)
MayaUsd::LayerManager* findOrCreateNode(MayaUsdProxyShapeBase* forProxyShape)
{
MayaUsd::LayerManager* lm = findNode(fromReference);
MayaUsd::LayerManager* lm = findNode(forProxyShape);
if (!lm) {
MDGModifier& modifier = MayaUsd::MDGModifierUndoItem::create("Node find or creation");
MObject manager = modifier.createNode(MayaUsd::LayerManager::typeId);
Expand Down Expand Up @@ -230,10 +233,12 @@ class LayerDatabase : public TfWeakBase
static void prepareForExportCheck(bool*, void*);
static void prepareForWriteCheck(bool*, bool);
static void cleanupForWrite();
static void loadLayersPostRead(const MFnReference* fromReference = nullptr);
static void loadLayersPostRead(MayaUsdProxyShapeBase* forProxyShape);
static void cleanUpNewScene(void*);
static void clearManagerNode(MayaUsd::LayerManager* lm);
static void removeManagerNode(MayaUsd::LayerManager* lm = nullptr);
static void removeManagerNode(
MayaUsd::LayerManager* lm = nullptr,
MayaUsdProxyShapeBase* forProxyShape = nullptr);

bool getProxiesToSave(bool isExport, bool* hasAnyProxy);
bool saveInteractionRequired();
Expand All @@ -249,7 +254,7 @@ class LayerDatabase : public TfWeakBase
std::string getSelectedStage() const;

bool saveLayerManagerSelectedStage();
bool loadLayerManagerSelectedStage();
bool loadLayerManagerSelectedStage(MayaUsdProxyShapeBase* forProxyShape);

SdfLayerHandle findLayer(std::string identifier) const;

Expand Down Expand Up @@ -506,8 +511,11 @@ void LayerDatabase::prepareForWriteCheck(bool* retCode, bool isExport)
*retCode = true;
}

// Note: for now we only save USD change made in stage in the main
// Maya scene. We don't save changes made to stages in Maya
// references.
if (!hasAnyProxy)
removeManagerNode(nullptr);
removeManagerNode(nullptr, nullptr);
}

void LayerDatabase::cleanupForWrite()
Expand Down Expand Up @@ -666,7 +674,10 @@ std::string LayerDatabase::getSelectedStage() const { return _selectedStage; }

bool LayerDatabase::saveLayerManagerSelectedStage()
{
MayaUsd::LayerManager* lm = findOrCreateNode();
// Note: for now we only save USD change made in stage in the main
// Maya scene. We don't save changes made to stages in Maya
// references.
MayaUsd::LayerManager* lm = findOrCreateNode(nullptr);
if (!lm)
return false;

Expand All @@ -691,9 +702,9 @@ bool LayerDatabase::saveLayerManagerSelectedStage()
return true;
}

bool LayerDatabase::loadLayerManagerSelectedStage()
bool LayerDatabase::loadLayerManagerSelectedStage(MayaUsdProxyShapeBase* forProxyShape)
{
MayaUsd::LayerManager* lm = findNode();
MayaUsd::LayerManager* lm = findNode(forProxyShape);
if (!lm)
return false;

Expand Down Expand Up @@ -852,6 +863,8 @@ SaveStageToMayaResult saveStageToMayaFile(
if (!pShape)
return result;

pShape->setLayerManager(nullptr);

std::unordered_set<std::string> localLayerIds;

// Save session layer and its sublayers
Expand Down Expand Up @@ -902,14 +915,19 @@ SaveStageToMayaResult saveStageToMayaFile(
stage->GetRootLayer()->GetIdentifier());
}

pShape->setLayerManager(lm);

result._saveSuceeded = true;
return result;
}

SaveStageToMayaResult saveStageToMayaFile(const MObject& proxyNode, UsdStageRefPtr stage)
{
// Note: for now we only save USD change made in stage in the main
// Maya scene. We don't save changes made to stages in Maya
// references.
SaveStageToMayaResult result;
MayaUsd::LayerManager* lm = findOrCreateNode();
MayaUsd::LayerManager* lm = findOrCreateNode(nullptr);
if (!lm)
return result;

Expand All @@ -930,7 +948,10 @@ SaveStageToMayaResult saveStageToMayaFile(const MObject& proxyNode, UsdStageRefP

BatchSaveResult LayerDatabase::saveUsdToMayaFile()
{
MayaUsd::LayerManager* lm = findOrCreateNode();
// Note: for now we only save USD change made in stage in the main
// Maya scene. We don't save changes made to stages in Maya
// references.
MayaUsd::LayerManager* lm = findOrCreateNode(nullptr);
if (!lm) {
return MayaUsd::kNotHandled;
}
Expand Down Expand Up @@ -1077,7 +1098,10 @@ void LayerDatabase::convertAnonymousLayers(

void LayerDatabase::saveUsdLayerToMayaFile(SdfLayerRefPtr layer, bool asAnonymous)
{
MayaUsd::LayerManager* lm = findOrCreateNode();
// Note: for now we only save USD change made in stage in the main
// Maya scene. We don't save changes made to stages in Maya
// references.
MayaUsd::LayerManager* lm = findOrCreateNode(nullptr);
if (!lm)
return;

Expand All @@ -1094,9 +1118,9 @@ void LayerDatabase::saveUsdLayerToMayaFile(SdfLayerRefPtr layer, bool asAnonymou
dataBlock.setClean(lm->layers);
}

void LayerDatabase::loadLayersPostRead(const MFnReference* fromReference)
void LayerDatabase::loadLayersPostRead(MayaUsdProxyShapeBase* forProxyShape)
{
MayaUsd::LayerManager* lm = findNode(fromReference);
MayaUsd::LayerManager* lm = findNode(forProxyShape);
if (!lm)
return;

Expand Down Expand Up @@ -1127,7 +1151,7 @@ void LayerDatabase::loadLayersPostRead(const MFnReference* fromReference)
identifierVal = idPlug.asString(MDGContext::fsNormal, &status).asChar();
if (identifierVal.empty()) {
MGlobal::displayError(
MString("Error - plug ") + idPlug.partialName(true) + "had empty identifier");
MString("Error - plug ") + idPlug.partialName(true) + " had empty identifier");
continue;
}

Expand Down Expand Up @@ -1209,10 +1233,10 @@ void LayerDatabase::loadLayersPostRead(const MFnReference* fromReference)
}
}

LayerDatabase::instance().loadLayerManagerSelectedStage();
LayerDatabase::instance().loadLayerManagerSelectedStage(forProxyShape);

if (!_isSavingMayaFile)
removeManagerNode(lm);
removeManagerNode(lm, forProxyShape);

for (auto it = createdLayers.begin(); it != createdLayers.end(); ++it) {
SdfLayerHandle lh = (*it);
Expand Down Expand Up @@ -1332,10 +1356,12 @@ void LayerDatabase::clearManagerNode(MayaUsd::LayerManager* lm)
dataBlock.setClean(lm->layers);
}

void LayerDatabase::removeManagerNode(MayaUsd::LayerManager* lm)
void LayerDatabase::removeManagerNode(
MayaUsd::LayerManager* lm,
MayaUsdProxyShapeBase* forProxyShape)
{
if (!lm) {
lm = findNode();
lm = findNode(forProxyShape);
}
if (!lm) {
return;
Expand Down Expand Up @@ -1485,21 +1511,21 @@ LayerManager::LayerManager()
LayerManager::~LayerManager() { }

/* static */
SdfLayerHandle LayerManager::findLayer(std::string identifier, const MFnReference* fromReference)
SdfLayerHandle LayerManager::findLayer(std::string identifier, MayaUsdProxyShapeBase* forProxyShape)
{
std::lock_guard<std::recursive_mutex> lock(findNodeMutex);

LayerDatabase::loadLayersPostRead(fromReference);
LayerDatabase::loadLayersPostRead(forProxyShape);

return LayerDatabase::instance().findLayer(identifier);
}

/* static */
LayerManager::LayerNameMap LayerManager::getLayerNameMap(const MFnReference* fromReference)
LayerManager::LayerNameMap LayerManager::getLayerNameMap(MayaUsdProxyShapeBase* forProxyShape)
{
std::lock_guard<std::recursive_mutex> lock(findNodeMutex);

LayerDatabase::loadLayersPostRead(fromReference);
LayerDatabase::loadLayersPostRead(forProxyShape);

return LayerDatabase::instance().getLayerNameMap();
}
Expand Down Expand Up @@ -1528,9 +1554,9 @@ void LayerManager::setSelectedStage(const std::string& stage)
}

/* static */
std::string LayerManager::getSelectedStage()
std::string LayerManager::getSelectedStage(MayaUsdProxyShapeBase* forProxyShape)
{
LayerDatabase::loadLayersPostRead();
LayerDatabase::loadLayersPostRead(forProxyShape);
return LayerDatabase::instance().getSelectedStage();
}

Expand Down
7 changes: 4 additions & 3 deletions lib/mayaUsd/nodes/layerManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#define MAYA_USD_LAYER_MANAGER

#include <mayaUsd/base/api.h>
#include <mayaUsd/nodes/proxyShapeBase.h>

#include <pxr/base/tf/notice.h>
#include <pxr/pxr.h>
Expand Down Expand Up @@ -122,18 +123,18 @@ class MAYAUSD_CORE_PUBLIC LayerManager : public MPxNode
//! \brief set the stage that is currently selected in the layer manager.
static void setSelectedStage(const std::string& stage);
//! \brief get the stage that should be selected in the layer manager.
static std::string getSelectedStage();
static std::string getSelectedStage(PXR_NS::MayaUsdProxyShapeBase* forProxyShape);

/*! \brief Supported Proxy Shapes should call this to possibly retrieve their Root and Session
layers before calling Sdf::FindOrOpen. If a handle is found and returned then it will be the
recreated layer, and all sublayers, with edits from a previous Maya session and should be
used to initialize the Proxy Shape in a call to UsdStage::Open().
*/
static SdfLayerHandle
findLayer(std::string identifier, const MFnReference* fromReference = nullptr);
findLayer(std::string identifier, PXR_NS::MayaUsdProxyShapeBase* forProxyShape);

using LayerNameMap = std::map<std::string, std::string>;
static LayerNameMap getLayerNameMap(const MFnReference* fromReference = nullptr);
static LayerNameMap getLayerNameMap(PXR_NS::MayaUsdProxyShapeBase* forProxyShape);

//! \brief returns true if the layer manager is currently saving files.
static bool isSaving();
Expand Down
Loading

0 comments on commit f17afcc

Please sign in to comment.