-
Notifications
You must be signed in to change notification settings - Fork 201
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
MAYA-123361 fix unshared stage toggling and loading #2410
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -651,7 +651,9 @@ MStatus MayaUsdProxyShapeBase::computeInStageDataCached(MDataBlock& dataBlock) | |
} | ||
|
||
// Normal context computation | ||
UsdStageRefPtr usdStage; | ||
UsdStageRefPtr sharedUsdStage; | ||
UsdStageRefPtr unsharedUsdStage; | ||
UsdStageRefPtr finalUsdStage; | ||
SdfPath primPath; | ||
|
||
MDataHandle inDataHandle = dataBlock.inputValue(inStageDataAttr, &retValue); | ||
|
@@ -711,7 +713,7 @@ MStatus MayaUsdProxyShapeBase::computeInStageDataCached(MDataBlock& dataBlock) | |
if (!inDataHandle.data().isNull()) { | ||
MayaUsdStageData* inStageData | ||
= dynamic_cast<MayaUsdStageData*>(inDataHandle.asPluginData()); | ||
usdStage = inStageData->stage; | ||
sharedUsdStage = inStageData->stage; | ||
primPath = inStageData->primPath; | ||
isIncomingStage = true; | ||
} else { | ||
|
@@ -721,7 +723,7 @@ MStatus MayaUsdProxyShapeBase::computeInStageDataCached(MDataBlock& dataBlock) | |
const auto cacheId = UsdStageCache::Id::FromLongInt(cacheIdNum); | ||
const auto stageCached = cacheId.IsValid() && UsdUtilsStageCache::Get().Contains(cacheId); | ||
if (stageCached) { | ||
usdStage = UsdUtilsStageCache::Get().Find(cacheId); | ||
sharedUsdStage = UsdUtilsStageCache::Get().Find(cacheId); | ||
isIncomingStage = true; | ||
} else { | ||
// | ||
|
@@ -778,14 +780,19 @@ MStatus MayaUsdProxyShapeBase::computeInStageDataCached(MDataBlock& dataBlock) | |
// UsdStage. See https://github.com/Autodesk/maya-usd/issues/528 for | ||
// more information. | ||
UsdStageCacheContext ctx( | ||
UsdMayaStageCache::Get(loadSet == UsdStage::InitialLoadSet::LoadAll)); | ||
UsdMayaStageCache::Get(loadSet, UsdMayaStageCache::ShareMode::Shared)); | ||
|
||
SdfLayerRefPtr rootLayer | ||
= sharableStage ? computeRootLayer(dataBlock, fileString) : nullptr; | ||
if (nullptr == rootLayer) | ||
rootLayer = SdfLayer::FindOrOpen(fileString); | ||
|
||
if (rootLayer) { | ||
// Note: computeSessionLayer will find a session layer *only* if the | ||
// Maya scene had been saved and thus serialized the session | ||
// layer. Otherwise it returns null which will mean to use | ||
// whatever session layer happens to be associated with the | ||
// stage we potentially find in the stage cache. | ||
SdfLayerRefPtr sessionLayer = computeSessionLayer(dataBlock); | ||
|
||
MProfilingScope profilingScope( | ||
|
@@ -798,34 +805,47 @@ MStatus MayaUsdProxyShapeBase::computeInStageDataCached(MDataBlock& dataBlock) | |
= MGlobal::optionVarIntValue(kSessionLayerOptionVarName) == 1; | ||
targetSession = targetSession || !rootLayer->PermissionToEdit(); | ||
|
||
if (sessionLayer || targetSession) { | ||
if (!sessionLayer) | ||
sessionLayer = SdfLayer::CreateAnonymous(); | ||
usdStage = UsdStage::Open( | ||
// Note: UsdStage::Open has the peculiar design that it will return | ||
// any previously open stage that happen to match its arguments, | ||
// all its arguments, but only those arguments. | ||
// | ||
// So *not* passing in a session layer will find any stage that | ||
// has the given root layer. That is why it is important *not* to | ||
// pass the session layer if the session layer is null. Otherwise | ||
// the cache would try find a stage *without* a session layer. | ||
// | ||
// So, not passing the (null) session layer is how a newly-created | ||
// shared stage with the same root layer will find the correct stage | ||
// with the existing session layer. | ||
// | ||
// If the stage is not in the cache and no session layer is passed | ||
// 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); | ||
} else { | ||
usdStage = UsdStage::Open( | ||
sharedUsdStage = UsdStage::Open( | ||
rootLayer, | ||
ArGetResolver().CreateDefaultContextForAsset(fileString), | ||
loadSet); | ||
} | ||
if (sessionLayer && targetSession) { | ||
usdStage->SetEditTarget(sessionLayer); | ||
} else { | ||
usdStage->SetEditTarget(usdStage->GetRootLayer()); | ||
} | ||
|
||
sharedUsdStage->SetEditTarget( | ||
targetSession ? sharedUsdStage->GetSessionLayer() | ||
: sharedUsdStage->GetRootLayer()); | ||
} else { | ||
// Create a new stage in memory with an anonymous root layer. | ||
usdStage = UsdStage::CreateInMemory(kAnonymousLayerName, loadSet); | ||
sharedUsdStage = UsdStage::CreateInMemory(kAnonymousLayerName, loadSet); | ||
} | ||
} | ||
} | ||
} | ||
|
||
if (!usdStage) { | ||
if (!sharedUsdStage) { | ||
return MS::kFailure; | ||
} | ||
|
||
|
@@ -838,7 +858,7 @@ MStatus MayaUsdProxyShapeBase::computeInStageDataCached(MDataBlock& dataBlock) | |
CHECK_MSTATUS_AND_RETURN_IT(retValue); | ||
|
||
if (isIncomingStage) { | ||
std::vector<std::string> incomingLayers { usdStage->GetRootLayer()->GetIdentifier() }; | ||
std::vector<std::string> incomingLayers { sharedUsdStage->GetRootLayer()->GetIdentifier() }; | ||
_incomingLayers = UsdMayaUtil::getAllSublayers(incomingLayers, true); | ||
} else { | ||
_incomingLayers.clear(); | ||
|
@@ -859,10 +879,11 @@ MStatus MayaUsdProxyShapeBase::computeInStageDataCached(MDataBlock& dataBlock) | |
} | ||
} | ||
} | ||
finalUsdStage = sharedUsdStage; | ||
} | ||
// Own the stage | ||
else { | ||
SdfLayerRefPtr inRootLayer = usdStage->GetRootLayer(); | ||
SdfLayerRefPtr inRootLayer = sharedUsdStage->GetRootLayer(); | ||
|
||
if (!_unsharedStageRootLayer) { | ||
_unsharedStageRootLayer = SdfLayer::CreateAnonymous(kUnsharedStageLayerName); | ||
|
@@ -903,16 +924,18 @@ MStatus MayaUsdProxyShapeBase::computeInStageDataCached(MDataBlock& dataBlock) | |
newReferencedLayers, _unsharedStageRootLayer, MayaUsdMetadata->ReferencedLayers); | ||
} | ||
|
||
usdStage = UsdStage::UsdStage::Open(_unsharedStageRootLayer, loadSet); | ||
unsharedUsdStage = getUnsharedStage(loadSet); | ||
finalUsdStage = unsharedUsdStage; | ||
} | ||
|
||
if (usdStage) { | ||
primPath = usdStage->GetPseudoRoot().GetPath(); | ||
copyLoadRulesFromAttribute(thisMObject(), *usdStage); | ||
if (finalUsdStage) { | ||
primPath = finalUsdStage->GetPseudoRoot().GetPath(); | ||
copyLoadRulesFromAttribute(thisMObject(), *finalUsdStage); | ||
updateShareMode(sharedUsdStage, unsharedUsdStage, loadSet); | ||
} | ||
|
||
// Set the outUsdStageData | ||
stageData->stage = usdStage; | ||
stageData->stage = finalUsdStage; | ||
stageData->primPath = primPath; | ||
|
||
// Set the data on the output plug | ||
|
@@ -925,6 +948,83 @@ MStatus MayaUsdProxyShapeBase::computeInStageDataCached(MDataBlock& dataBlock) | |
return MS::kSuccess; | ||
} | ||
|
||
UsdStageRefPtr MayaUsdProxyShapeBase::getUnsharedStage(UsdStage::InitialLoadSet loadSet) | ||
{ | ||
// The unshared stages are *also* kept in a stage cache so that we can find them | ||
// again when proxy shape attribute change. For example, if the 'loadPayloads' | ||
// attribute change, we want to find the same unshared stage, we don't want to lose | ||
// edits, in particular in its session layer. | ||
// | ||
// We also need to be able to find them when switching a stage between non-shared | ||
// and shared, so that we can transfer the content of the session layer. | ||
// | ||
// Fortunately, the USD stage cache matches stages using *all* arguments provided. | ||
// So if the unshared session layer is unique to this proxy shape, there is no | ||
// chance of finding it by accident from another proxy shape. | ||
UsdStageCacheContext ctx( | ||
UsdMayaStageCache::Get(loadSet, UsdMayaStageCache::ShareMode::Unshared)); | ||
|
||
if (!_unsharedStageSessionLayer) | ||
_unsharedStageSessionLayer = SdfLayer::CreateAnonymous(); | ||
|
||
return UsdStage::UsdStage::Open(_unsharedStageRootLayer, _unsharedStageSessionLayer, loadSet); | ||
} | ||
|
||
void MayaUsdProxyShapeBase::updateShareMode( | ||
const UsdStageRefPtr& sharedUsdStage, | ||
const UsdStageRefPtr& unsharedUsdStage, | ||
UsdStage::InitialLoadSet loadSet) | ||
{ | ||
// Based on the previous shared mode and current shared mode of the stage, | ||
// transfer the content of the session layer from one to the other as needed. | ||
const auto shareMode = isShareableStage() ? ShareMode::Shared : ShareMode::Unshared; | ||
if (shareMode == _previousShareMode) | ||
return; | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. On thing I was not sure of: do I need to reset the previous share mode in some cases? For example, if the user edits the filename, would we need to reset the flag? Where and when, through what mechanism would that be done? I did not see that any other member variable get reset in these cases, so I did not do anything about it for this flag. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Resetting the share mode on file (i.e. root layer) change is an interesting question. I think you'll need to follow up with Design here so that we can schedule some time for this. |
||
// Only transfer the session content if the previous mode was known | ||
// or if the current mode is unshared, as the session layer content | ||
// is put in the shared stage when loaded from disk in a Maya scene. | ||
// | ||
// IOW: | ||
// Shared -> Unshared : copy | ||
// Unshared -> Shared : copy | ||
// Unknown -> Unshared : copy | ||
// | ||
// Shared -> Shared : content already in place, pruned above | ||
// Unshared -> Unshared : content already in place, pruned above | ||
// Unknown -> Shared : content already in place | ||
// | ||
// X -> Unknown : impossible since the new mode is always known | ||
if (_previousShareMode != ShareMode::Unknown || shareMode == ShareMode::Unshared) | ||
transferSessionLayer(shareMode, sharedUsdStage, unsharedUsdStage, loadSet); | ||
|
||
_previousShareMode = shareMode; | ||
} | ||
|
||
void MayaUsdProxyShapeBase::transferSessionLayer( | ||
ShareMode currentMode, | ||
const UsdStageRefPtr& sharedUsdStage, | ||
const UsdStageRefPtr& unsharedUsdStage, | ||
UsdStage::InitialLoadSet loadSet) | ||
{ | ||
// When flipping to shared from unshared, the unshared set was not loaded. | ||
// Load it now to be able to transfer the session layer content. | ||
UsdStageRefPtr validUnsharedUsdStage | ||
= unsharedUsdStage ? unsharedUsdStage : getUnsharedStage(loadSet); | ||
|
||
SdfLayerHandle sharedSession = sharedUsdStage->GetSessionLayer(); | ||
SdfLayerHandle unsharedSession = validUnsharedUsdStage->GetSessionLayer(); | ||
|
||
if (!sharedSession || !unsharedSession) | ||
return; | ||
|
||
if (currentMode == ShareMode::Shared) { | ||
sharedSession->TransferContent(unsharedSession); | ||
} else { | ||
unsharedSession->TransferContent(sharedSession); | ||
} | ||
} | ||
|
||
MStatus MayaUsdProxyShapeBase::computeOutStageData(MDataBlock& dataBlock) | ||
{ | ||
MProfilingScope computeOutStageDatacomputeOutStageData( | ||
|
@@ -1618,6 +1718,8 @@ MayaUsdProxyShapeBase::MayaUsdProxyShapeBase( | |
const bool useLoadRulesHandling) | ||
: MPxSurfaceShape() | ||
, _isUfeSelectionEnabled(enableUfeSelection) | ||
, _previousShareMode(ShareMode::Unknown) | ||
, _unsharedStageSessionLayer(nullptr) | ||
, _unsharedStageRootLayer(nullptr) | ||
, _unsharedStageRootSublayers() | ||
, _incomingLayers() | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When targeting the session layer without a named session layer loaded from Maya scene, it would create a new session layer. This would prevent reusing a previously shared stage. Target session vs stage sharing are orthogonal. I looked at the original github issue and PR and the goal was to be able to target the session, with no discussion about affecting stage sharing.
I think the code was unwittingly written to have that side effect, so I fixed it.