Skip to content

Commit 27d821d

Browse files
deboisjclaude
andcommitted
Merge remote-tracking branch 'upstream/dev' into deboisj/unify_layer_editor_review
# Conflicts: # lib/usd/ui/CMakeLists.txt # lib/usd/ui/layerEditor/mayaCommandHook.cpp # lib/usd/ui/renderSetup/renderSetupWindowCmd.cpp KBuYmLgYNrFpAfTMkewbc CKMXQPPtE40icSdsp8GsAmou8z/TdcXkVrx3JD5N4CxgT81ekwYQX5TvwCxQymhd fMGynH4JkKWCg5FK//rsu623du4u9XiTzOQrdsIGT7AMGotqm1qubXInvR+HKARo gxtSQ6mQf+CSGznSNbJlvy8aXq1tfH8fJv28nOXmMXSaq6cXq79lcF6tmS/VMylx pAi5CcIDsXH9rlbsyaKQjtgR30DyaFcu8xoIrQZ19oLk0AmvwGXMhjBVLxs7nKPY jxwJCaPIsEJKxebk5kGRocwFCDs5C+a3eT4I4NW5cOZRd4jzh9KuZ38VuO5BY/GN e7WSA+dxP67xP05w6EYjjdt1qrfe9Ko9jlTb506ptYTBm7Ewz+6roCz40QW7wo1X 2ddj3B6oU3p0vIQVxTT8WhIXhrB/cccMMqaTEBt6YuiczLFCHuYzAOj1znAqnzrL XZWw2OaS9OkyBE0DnOd4czNnzSyx/vSBPo5Xo/QPi0fiVdOdNI/bdTC2NW+E6QTJ rMUPY1vf/KZPRV8l306V =2bZ3 -----END PGP SIGNATURE----- Merge pull request #4655 from Autodesk/bailp/EMSUSD-3823/layer-display-refresh EMSUSD-3823 fix layer content refresh`ImportChaser` pluginsis no…both unchanged. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> 8 <noreply@anthropic.com> <noreply@anthropic.com> opic.com>
2 parents f2bf551 + 10f7cf1 commit 27d821d

28 files changed

Lines changed: 548 additions & 121 deletions

lib/mayaUsd/commands/Readme.md

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -87,18 +87,27 @@ pipeline-specific operations and/or early prototyping of features that might
8787
otherwise not make sense to be part of the mainline codebase.
8888

8989
Chasers are registered with a particular name and can be passed argument
90-
name/value pairs in an invocation of `mayaUSDImport`. There is no "plugin
91-
discovery" method here – the developer/user is responsible for making sure the
92-
chaser is registered via a call to the convenience macro
93-
`USDMAYA_DEFINE_IMPORT_CHASER_FACTORY(name, ctx)`, where `name` is the name of
94-
the chaser being created. Unlike export chasers, import chasers also have the
95-
ability to define `Undo` and `Redo` methods in order to allow the
90+
name/value pairs in an invocation of `mayaUSDImport`. The chaser is registered
91+
via a call to the convenience macro `USDMAYA_DEFINE_IMPORT_CHASER_FACTORY(name,
92+
ctx)`, where `name` is the name of the chaser being created. Import chaser
93+
plugins can be discovered and loaded automatically by declaring the
94+
`UsdMaya:ImportChaserPlugin` metadata in their `plugInfo.json`:
95+
96+
```json
97+
"Info": {
98+
"UsdMaya": {
99+
"ImportChaserPlugin": {}
100+
}
101+
}
102+
```
103+
104+
Unlike export chasers, import chasers also have the ability to define `Undo` and
105+
`Redo` methods in order to allow the
96106
`mayaUSDImport` command to remain compliant with the Maya undo stack. It's not
97107
necessary to compile your chaser plugin together with `mayaUsdPlugin` in order
98108
to work; you can create a completely separate maya DLL that contains the
99109
business logic of your chaser code, and just call the aforementioned
100-
`USDMAYA_DEFINE_IMPORT_CHASER_FACTORY` to register it, as long as the
101-
`mayaUsdPlugin` DLL is loaded first.
110+
`USDMAYA_DEFINE_IMPORT_CHASER_FACTORY` to register it.
102111

103112
A sample import chaser, `infoImportChaser.cpp`, is provided to give an example
104113
of how to write an import chaser. All it does is read any custom layer data in
@@ -399,9 +408,17 @@ implement prim post-processing that executes immediately after prims
399408
are written (and/or after animation is written to a prim in time-based
400409
exports). Chasers are registered with a particular name and can be
401410
passed argument name/value pairs in an invocation of a concrete
402-
`MayaUSDExportCommand` command. There is no "plugin discovery" method
403-
here – the developer/user is responsible for making sure the chaser is
404-
registered.
411+
`MayaUSDExportCommand` command. Export chaser plugins can be discovered
412+
and loaded automatically by declaring the `UsdMaya:ExportChaserPlugin`
413+
metadata in their `plugInfo.json`:
414+
415+
```json
416+
"Info": {
417+
"UsdMaya": {
418+
"ExportChaserPlugin": {}
419+
}
420+
}
421+
```
405422
406423
For example the pxr plug-in provides one such chaser plugin called
407424
`AlembicChaser` to try to make integrating USD into Alembic-heavy

lib/mayaUsd/fileio/chaser/exportChaserRegistry.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,9 @@ bool UsdMayaExportChaserRegistry::RegisterFactory(
6767
UsdMayaExportChaserRefPtr
6868
UsdMayaExportChaserRegistry::Create(const std::string& name, const FactoryContext& context) const
6969
{
70+
UsdMaya_RegistryHelper::LoadExportChaserPlugins();
7071
TfRegistryManager::GetInstance().SubscribeTo<UsdMayaExportChaserRegistry>();
72+
7173
if (UsdMayaExportChaserRegistry::FactoryFn fn = _factoryRegistry[name]) {
7274
return TfCreateRefPtr(fn(context));
7375
} else {

lib/mayaUsd/fileio/chaser/importChaserRegistry.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,9 @@ bool UsdMayaImportChaserRegistry::RegisterFactory(const char* name, FactoryFn fn
8080
UsdMayaImportChaserRefPtr
8181
UsdMayaImportChaserRegistry::Create(const char* name, const FactoryContext& context) const
8282
{
83+
UsdMaya_RegistryHelper::LoadImportChaserPlugins();
8384
TfRegistryManager::GetInstance().SubscribeTo<UsdMayaImportChaserRegistry>();
85+
8486
if (UsdMayaImportChaserRegistry::FactoryFn fn = _factoryImportRegistry[name]) {
8587
return TfCreateRefPtr(fn(context));
8688
} else {

lib/mayaUsd/fileio/registryHelper.cpp

Lines changed: 56 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ TF_DEFINE_PRIVATE_TOKENS(
4242
(UsdMaya)
4343
(ShadingModePlugin)
4444
(JobContextPlugin)
45+
(ImportChaserPlugin)
46+
(ExportChaserPlugin)
4547
);
4648
// clang-format on
4749

@@ -140,6 +142,42 @@ static bool _HasMayaPlugin(
140142
return true;
141143
}
142144

145+
static void _FindAndLoadUsdMayaPlugins(const TfToken& pluginKey)
146+
{
147+
const std::vector<TfToken> scope { _tokens->UsdMaya, pluginKey };
148+
149+
for (const auto& plug : PlugRegistry::GetInstance().GetAllPlugins()) {
150+
std::string mayaPlugin;
151+
if (_HasMayaPlugin(plug, scope, &mayaPlugin)) {
152+
if (!mayaPlugin.empty()) {
153+
TF_DEBUG(PXRUSDMAYA_REGISTRY)
154+
.Msg(
155+
"Found %s %s: Loading via Maya API %s.\n",
156+
pluginKey.GetText(),
157+
plug->GetName().c_str(),
158+
mayaPlugin.c_str());
159+
std::string loadPluginCmd
160+
= TfStringPrintf("loadPlugin -quiet %s", mayaPlugin.c_str());
161+
if (MGlobal::executeCommand(loadPluginCmd.c_str())) {
162+
// Need to ensure Python script modules are loaded
163+
// properly for this library (Maya's loadPlugin will not
164+
// load script modules like TfDlopen would).
165+
TfScriptModuleLoader::GetInstance().LoadModules();
166+
} else {
167+
TF_CODING_ERROR("Unable to load mayaplugin %s\n", mayaPlugin.c_str());
168+
}
169+
} else {
170+
TF_DEBUG(PXRUSDMAYA_REGISTRY)
171+
.Msg(
172+
"Found %s %s: Loading via USD API.\n",
173+
pluginKey.GetText(),
174+
plug->GetName().c_str());
175+
plug->Load();
176+
}
177+
}
178+
}
179+
}
180+
143181
/* static */
144182
std::string _PluginDictScopeToDebugString(const std::vector<TfToken>& scope)
145183
{
@@ -202,81 +240,29 @@ void UsdMaya_RegistryHelper::FindAndLoadMayaPlug(
202240
/* static */
203241
void UsdMaya_RegistryHelper::LoadShadingModePlugins()
204242
{
205-
static std::once_flag _shadingModesLoaded;
206-
static std::vector<TfToken> scope = { _tokens->UsdMaya, _tokens->ShadingModePlugin };
207-
std::call_once(_shadingModesLoaded, []() {
208-
PlugPluginPtrVector plugins = PlugRegistry::GetInstance().GetAllPlugins();
209-
std::string mayaPlugin;
210-
TF_FOR_ALL(plugIter, plugins)
211-
{
212-
PlugPluginPtr plug = *plugIter;
213-
if (_HasMayaPlugin(plug, scope, &mayaPlugin)) {
214-
if (!mayaPlugin.empty()) {
215-
TF_DEBUG(PXRUSDMAYA_REGISTRY)
216-
.Msg(
217-
"Found shading mode plugin %s: Loading via Maya API %s.\n",
218-
plug->GetName().c_str(),
219-
mayaPlugin.c_str());
220-
std::string loadPluginCmd
221-
= TfStringPrintf("loadPlugin -quiet %s", mayaPlugin.c_str());
222-
if (MGlobal::executeCommand(loadPluginCmd.c_str())) {
223-
// Need to ensure Python script modules are loaded
224-
// properly for this library (Maya's loadPlugin will not
225-
// load script modules like TfDlopen would).
226-
TfScriptModuleLoader::GetInstance().LoadModules();
227-
} else {
228-
TF_CODING_ERROR("Unable to load mayaplugin %s\n", mayaPlugin.c_str());
229-
}
230-
} else {
231-
TF_DEBUG(PXRUSDMAYA_REGISTRY)
232-
.Msg(
233-
"Found shading mode plugin %s: Loading via USD API.\n",
234-
plug->GetName().c_str());
235-
plug->Load();
236-
}
237-
}
238-
}
239-
});
243+
static std::once_flag _loaded;
244+
std::call_once(_loaded, []() { _FindAndLoadUsdMayaPlugins(_tokens->ShadingModePlugin); });
240245
}
241246

242247
/* static */
243248
void UsdMaya_RegistryHelper::LoadJobContextPlugins()
244249
{
245-
static std::once_flag _jobContextsLoaded;
246-
static std::vector<TfToken> scope = { _tokens->UsdMaya, _tokens->JobContextPlugin };
247-
std::call_once(_jobContextsLoaded, []() {
248-
PlugPluginPtrVector plugins = PlugRegistry::GetInstance().GetAllPlugins();
249-
std::string mayaPlugin;
250-
TF_FOR_ALL(plugIter, plugins)
251-
{
252-
PlugPluginPtr plug = *plugIter;
253-
if (_HasMayaPlugin(plug, scope, &mayaPlugin)) {
254-
if (!mayaPlugin.empty()) {
255-
TF_DEBUG(PXRUSDMAYA_REGISTRY)
256-
.Msg(
257-
"Found job context plugin %s: Loading via Maya API %s.\n",
258-
plug->GetName().c_str(),
259-
mayaPlugin.c_str());
260-
std::string loadPluginCmd
261-
= TfStringPrintf("loadPlugin -quiet %s", mayaPlugin.c_str());
262-
if (MGlobal::executeCommand(loadPluginCmd.c_str())) {
263-
// Need to ensure Python script modules are loaded
264-
// properly for this library (Maya's loadPlugin will not
265-
// load script modules like TfDlopen would).
266-
TfScriptModuleLoader::GetInstance().LoadModules();
267-
} else {
268-
TF_CODING_ERROR("Unable to load mayaplugin %s\n", mayaPlugin.c_str());
269-
}
270-
} else {
271-
TF_DEBUG(PXRUSDMAYA_REGISTRY)
272-
.Msg(
273-
"Found job context plugin %s: Loading via USD API.\n",
274-
plug->GetName().c_str());
275-
plug->Load();
276-
}
277-
}
278-
}
279-
});
250+
static std::once_flag _loaded;
251+
std::call_once(_loaded, []() { _FindAndLoadUsdMayaPlugins(_tokens->JobContextPlugin); });
252+
}
253+
254+
/* static */
255+
void UsdMaya_RegistryHelper::LoadImportChaserPlugins()
256+
{
257+
static std::once_flag _loaded;
258+
std::call_once(_loaded, []() { _FindAndLoadUsdMayaPlugins(_tokens->ImportChaserPlugin); });
259+
}
260+
261+
/* static */
262+
void UsdMaya_RegistryHelper::LoadExportChaserPlugins()
263+
{
264+
static std::once_flag _loaded;
265+
std::call_once(_loaded, []() { _FindAndLoadUsdMayaPlugins(_tokens->ExportChaserPlugin); });
280266
}
281267

282268
/* static */

lib/mayaUsd/fileio/registryHelper.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,30 @@ struct UsdMaya_RegistryHelper
7474
/// usdMaya will try to load the "mayaPlugin" when job contexts are first accessed.
7575
static void LoadJobContextPlugins();
7676

77+
/// Searches the plugInfos and looks for ImportChaserPlugin.
78+
///
79+
/// "UsdMaya" : {
80+
/// "ImportChaserPlugin" : {
81+
/// "mayaPlugin" : "myImportChaserPlugin"
82+
/// }
83+
/// }
84+
///
85+
/// At that scope, it expects an optional "mayaPlugin" key.
86+
/// usdMaya will try to load the plugin when import chasers are first accessed.
87+
static void LoadImportChaserPlugins();
88+
89+
/// Searches the plugInfos and looks for ExportChaserPlugin.
90+
///
91+
/// "UsdMaya" : {
92+
/// "ExportChaserPlugin" : {
93+
/// "mayaPlugin" : "myExportChaserPlugin"
94+
/// }
95+
/// }
96+
///
97+
/// At that scope, it expects an optional "mayaPlugin" key.
98+
/// usdMaya will try to load the plugin when export chasers are first accessed.
99+
static void LoadExportChaserPlugins();
100+
77101
/// Searches the plugInfos for metadata dictionaries at the given \p scope,
78102
/// and composes them together.
79103
/// The scope are the nested keys to search through in the plugInfo (for

lib/usd/ui/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ endif()
122122
# -----------------------------------------------------------------------------
123123
set(HEADERS
124124
api.h
125+
undoChunkUtils.h
125126
)
126127

127128
mayaUsd_promoteHeaderList(

lib/usd/ui/debugTools/CompositionEditorCmd.cpp

Lines changed: 3 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
#include <mayaUsd/ufe/Utils.h>
1919
#include <mayaUsd/undo/MayaUsdUndoBlock.h>
20+
#include <mayaUsdUI/ui/undoChunkUtils.h>
2021

2122
#include <usdUfe/undo/UsdUndoManager.h>
2223

@@ -62,31 +63,6 @@ constexpr auto kReloadFlagLong = "-reload";
6263

6364
const MString WORKSPACE_CONTROL_NAME = "mayaUsdCompositionEditor";
6465

65-
// RAII guard that opens a named Maya undo chunk
66-
class UndoChunkContext
67-
{
68-
private:
69-
// Maya's undo chunk names cannot contain spaces (the name is split at the
70-
// first space), so replace them with underscores before quoting.
71-
MString cleanChunkName(const std::string& label)
72-
{
73-
std::string name = label.empty() ? "USD Composition Edit" : label;
74-
std::replace(name.begin(), name.end(), ' ', '_');
75-
return MString("\"") + name.c_str() + "\"";
76-
}
77-
78-
public:
79-
explicit UndoChunkContext(const std::string& label)
80-
{
81-
MGlobal::executeCommand(
82-
MString("undoInfo -openChunk -chunkName ") + cleanChunkName(label), false, false);
83-
}
84-
~UndoChunkContext() { MGlobal::executeCommand("undoInfo -closeChunk", false, false); }
85-
86-
UndoChunkContext(const UndoChunkContext&) = delete;
87-
UndoChunkContext& operator=(const UndoChunkContext&) = delete;
88-
};
89-
9066
QPointer<Adsk::UsdDebug::CompositionEditorWidget> g_compositionEditorWidget;
9167
Ufe::Observer::Ptr g_selectionObserver;
9268

@@ -167,8 +143,8 @@ class MayaCompositionEditorHost : public Adsk::UsdDebug::ApplicationHost
167143
UsdUfe::UsdUndoManager::instance().trackLayerStates(layer);
168144
}
169145

170-
UndoChunkContext undoChunk(editLabel);
171-
MayaUsdUndoBlock undoBlock;
146+
MayaUsdUI::UndoChunkGuard undoChunk(editLabel);
147+
MayaUsdUndoBlock undoBlock;
172148
return edit();
173149
}
174150

lib/usd/ui/layerEditor/layerEditorWidget.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,13 @@ QLayout* LayerEditorWidget::setupLayout_toolbar()
145145
this,
146146
&LayerEditorWidget::onLazyUpdateLayerContents);
147147

148+
// update layer contents widget on selected layer data change
149+
connect(
150+
_treeView->layerTreeModel(),
151+
&LayerTreeModel::selectedLayerDataChangedSignal,
152+
this,
153+
&LayerEditorWidget::onLazyUpdateLayerContents);
154+
148155
_buttons._loadLayer = addHIGButton(
149156
":/UsdLayerEditor/import_layer",
150157
StringResources::getAsQString(StringResources::kLoadExistingLayer),

lib/usd/ui/layerEditor/layerTreeModel.cpp

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -294,11 +294,12 @@ void LayerTreeModel::setSessionState(SessionState* in_sessionState)
294294
this,
295295
&LayerTreeModel::autoHideSessionLayerChanged);
296296

297-
rebuildModelOnIdle();
297+
rebuildModelOnIdle(true);
298298
}
299299

300-
void LayerTreeModel::rebuildModelOnIdle()
300+
void LayerTreeModel::rebuildModelOnIdle(bool dataChanged)
301301
{
302+
_selectedLayerDataChanged |= dataChanged;
302303
if (!_rebuildOnIdlePending) {
303304
_rebuildOnIdlePending = true;
304305
QTimer::singleShot(0, this, [this]() {
@@ -313,6 +314,11 @@ void LayerTreeModel::rebuildModel(bool refreshLockState /*= false*/)
313314
_rebuildOnIdlePending = false;
314315
_lastAskedAnonLayerNameSinceRebuild = 0;
315316

317+
if (_selectedLayerDataChanged) {
318+
Q_EMIT selectedLayerDataChangedSignal();
319+
_selectedLayerDataChanged = false;
320+
}
321+
316322
if (!_sessionState->isValid()) {
317323
if (rowCount() > 0) {
318324
// Note: clear() calls beginResetModel and endResetModel for us.
@@ -472,7 +478,7 @@ void LayerTreeModel::usd_layerChanged(SdfNotice::LayersDidChangeSentPerLayer con
472478
{
473479
// experienced crashes in python prototype For now, rebuild everything
474480
if (!_blockUsdNotices)
475-
rebuildModelOnIdle();
481+
rebuildModelOnIdle(true);
476482
}
477483

478484
// notification from USD

lib/usd/ui/layerEditor/layerTreeModel.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ class LayerTreeModel
124124

125125
Q_SIGNALS:
126126
void selectLayerSignal(const QModelIndex&);
127+
void selectedLayerDataChangedSignal();
127128

128129
protected:
129130
// slots
@@ -149,8 +150,9 @@ class LayerTreeModel
149150

150151
mutable int _lastAskedAnonLayerNameSinceRebuild = 0;
151152

152-
void rebuildModelOnIdle();
153+
void rebuildModelOnIdle(bool dataChanged = false);
153154
bool _rebuildOnIdlePending = false;
155+
bool _selectedLayerDataChanged = false;
154156
void rebuildModel(bool refreshLockState = false);
155157

156158
void updateTargetLayer(InRebuildModel inRebuild);

0 commit comments

Comments
 (0)