Skip to content

EMSUSD-3880 Optimizes Multi-stage loading performance#4660

Merged
seando-adsk merged 2 commits into
devfrom
azharia/EMSUSD-3880/Performance-Optimization-Many-Stages-Loading
Jul 7, 2026
Merged

EMSUSD-3880 Optimizes Multi-stage loading performance#4660
seando-adsk merged 2 commits into
devfrom
azharia/EMSUSD-3880/Performance-Optimization-Many-Stages-Loading

Conversation

@AramAzhari-adsk

@AramAzhari-adsk AramAzhari-adsk commented Jul 3, 2026

Copy link
Copy Markdown
Collaborator

EMSUSD-3880 Optimizes Multi-stage loading performance

While the Layer Editor is open, loading many USD stages at once was O(N^2): each per-stage notification (stage set, current-stage change, proxy add/remove, selection change) triggered a full model rebuild, combo-box rebuild, or a full-DAG-scan allStages() lookup — once per stage. This coalesces those reactions and removes the per-stage scans, all within the Layer Editor.

Changes:

  • LayerTreeModel::sessionStageChanged now defers through the coalesced rebuildModelOnIdle instead of rebuilding synchronously on every stage
    change; the lock-state refresh is preserved by threading it through the idle rebuild (rebuildModelOnIdle now takes a refreshLockState arg
    alongside dev's dataChanged arg).
  • StageSelectorWidget::updateFromSessionState is now coalesced: a burst of stageListChangedSignal notifications collapses into a single combo rebuild (last requested selection wins). LayerTreeView::updateFromSessionState is likewise coalesced into a single refresh per event-loop turn.
  • Replaced the allStages() (full Maya DAG scan) index lookups in selectionChanged / sessionStageChanged / stageRenamed / stageReset with a local combo lookup by id (comboIndexById), since the combo already holds the stage entries. Removed the now-unused getEntryIndexById helpers.

Impact (500-stage bulk load, Layer Editor open): ~44s -> ~12s (~3.5x);
Layer-Editor self-time ~31s -> ~65ms. The remaining cost is core UsdStageMap / ProxyShapeHandler quadratic work, independent of the Layer Editor, tracked separately.

pierrebai-adsk
pierrebai-adsk previously approved these changes Jul 3, 2026

@pierrebai-adsk pierrebai-adsk left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work!

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR optimizes Layer Editor responsiveness during bulk USD stage loads by coalescing high-frequency session notifications and removing repeated full-DAG scans, reducing per-stage UI rebuild work to at most once per event-loop turn.

Changes:

  • Coalesces StageSelectorWidget::updateFromSessionState so bursts of stageListChangedSignal trigger a single dropdown rebuild (last requested selection wins).
  • Coalesces LayerTreeView::updateFromSessionState so stage list bursts trigger a single cached-state refresh per event-loop turn.
  • Replaces repeated SessionState::allStages() (full Maya DAG scan) lookups in stage selection handlers with a local combo-box id lookup (comboIndexById).

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated no comments.

Show a summary per file
File Description
lib/usd/ui/layerEditor/stageSelectorWidget.h Adds coalescing state and an idle-coalesced update method to reduce per-stage UI rebuilds.
lib/usd/ui/layerEditor/stageSelectorWidget.cpp Implements idle coalescing and replaces DAG-scan lookups with combo-based id lookup.
lib/usd/ui/layerEditor/layerTreeView.h Adds an idle-coalesced refresh method and pending flag for stage-list bursts.
lib/usd/ui/layerEditor/layerTreeView.cpp Implements idle coalescing for stage-list refreshes to avoid per-stage full rescans.
lib/usd/ui/layerEditor/layerTreeModel.h Extends idle rebuild API to accumulate lock-state refresh requests.
lib/usd/ui/layerEditor/layerTreeModel.cpp Coalesces rebuild requests and threads lock-state refresh through the idle rebuild path.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.


if (it != stages.end()) {
return std::distance(stages.begin(), it);
for (int i = 0, count = dropDown->count(); i < count; ++i) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to guard against input dropDown == nullptr?

@AramAzhari-adsk AramAzhari-adsk Jul 6, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good suggestion. It seems that dropdown is only created in a constructor once and never reset (not even in the destructor). So at all the callers' location the dropDown is guaranteed non-null for the widget's entire lifetime.

I could still add this if it's blocking this PR, or take a note and improve it later.

   if (!dropDown)
        return -1;

@seando-adsk seando-adsk left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good work - thanks.

@AramAzhari-adsk AramAzhari-adsk added the ready-for-merge Development process is finished, PR is ready for merge label Jul 6, 2026
@seando-adsk seando-adsk added the core Related to core library label Jul 7, 2026
@seando-adsk seando-adsk merged commit 062aecd into dev Jul 7, 2026
12 checks passed
@seando-adsk seando-adsk deleted the azharia/EMSUSD-3880/Performance-Optimization-Many-Stages-Loading branch July 7, 2026 19:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

core Related to core library ready-for-merge Development process is finished, PR is ready for merge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants