Skip to content

fix: defer UV rebuild on import to prevent UI freeze - #763

Merged
fernandotonon merged 2 commits into
masterfrom
fix/model-import-uv-editor-freeze
Jun 27, 2026
Merged

fix: defer UV rebuild on import to prevent UI freeze#763
fernandotonon merged 2 commits into
masterfrom
fix/model-import-uv-editor-freeze

Conversation

@fernandotonon

@fernandotonon fernandotonon commented Jun 27, 2026

Copy link
Copy Markdown
Owner

Summary

Fixes UI freezes when importing meshes (especially large/skinned FBX assets).

  • UV Editor (UV: Slice B — UV component selection (vertex/edge/face) #460 follow-up): UVEditorController was rebuilding the full HalfEdge/island cache + QVariantList triangle payload on every entityCreated / selectOne during import (each sub-entity auto-selects). Now skips rebuilds while the UV Editor dock is hidden, debounces (75ms) when open, and indexes vertices→triangles for edit-mode context islands.
  • Startup/import latency: Lazy-load hidden dock QML (UV Editor, Asset Browser, AI Chat, Dope Sheet, Curve Editor), defer Asset Browser directory scan + LLMManager init, and stop re-applying custom palette via setPalette() after QML widgets exist.

Test plan

  • UnitTests --gtest_filter="UVEditorControllerTest.*" — 16/16 pass
  • Import a large animated FBX — viewport stays responsive with UV Editor closed
  • Open UV Editor after import — layout + context islands populate correctly
  • Custom palette users — menu checkbox still reflects saved theme, no startup repaint stall

Made with Cursor

Summary by CodeRabbit

  • New Features

    • The UV Editor now updates more efficiently in the background and resumes automatically when opened.
    • Several panels and tools now load only when needed, improving startup and display responsiveness.
  • Bug Fixes

    • Hidden UV Editor panels no longer trigger unnecessary rebuilds or updates.
    • Theme changes now avoid extra UI work, helping prevent freezes.
    • Docked views are more reliable when shown or activated.

UVEditorController was rebuilding the full HalfEdge/island cache on every
entityCreated + selectOne during import, freezing the UI on large meshes.
Skip rebuilds while the UV Editor is closed, debounce when open, and add
vertex→triangle indices for edit-mode context islands.

Also lazy-load hidden dock QML (UV Editor, Asset Browser, AI Chat, Dope
Sheet, Curve Editor), defer Asset Browser directory scan and LLMManager
init, and stop re-applying custom palette after QML widgets exist.

Co-authored-by: Cursor <cursoragent@cursor.com>
@coderabbitai

coderabbitai Bot commented Jun 27, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@fernandotonon, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 37 minutes and 21 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits.

🚦 How do rate limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a17c4f6d-6cfd-4a37-a835-2522b4dd0d55

📥 Commits

Reviewing files that changed from the base of the PR and between b0443d1 and 6634066.

📒 Files selected for processing (3)
  • src/UVEditorController.cpp
  • src/UVEditorController_test.cpp
  • src/mainwindow.cpp
📝 Walkthrough

Walkthrough

The PR adds deferred refresh handling and cached UV selection lookups in UVEditorController, updates the UV editor tests, and changes MainWindow to lazily load dock QML and defer LLMManager startup.

Changes

UV editor refresh and context lookup

Layer / File(s) Summary
Deferred refresh gating and panel state
src/UVEditorController.h, src/UVEditorController.cpp, src/UVEditorController_test.cpp
UVEditorController adds panel-active state, timer-driven refresh scheduling, and a hidden-panel test that checks rebuilds stay deferred until the panel is reactivated.
Cached context-island lookup
src/UVEditorController.cpp, src/UVEditorController_test.cpp
buildFromEntity() builds global triangle/vertex caches, updateContextIslandsFromEdit() uses them for island lookup, and the edit-selection test now activates the panel before asserting highlight behavior.

Main window lazy dock startup

Layer / File(s) Summary
Lazy-QML helpers and startup initialization
src/mainwindow.cpp
Adds helper functions for marking and initializing lazy QQuickWidget docks, syncs theme action checked states from QSettings, and defers LLMManager::instance() with QTimer::singleShot(0, ...).
Dock activation paths
src/mainwindow.cpp
Converts AI Chat, Asset Browser, Dope Sheet, Curve Editor, and UV Editor docks to lazy QML loading, initializes them on show or visibility changes, and calls ensureLazyDockQml(...) from showBottomToolDock(...) and chat entry points.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • fernandotonon/QtMeshEditor#455: Also changes dock reveal and lazy QML initialization paths in src/mainwindow.cpp, including showBottomToolDock(...).
  • fernandotonon/QtMeshEditor#759: Directly related to the UVEditorController panel/controller pipeline that this PR extends with deferred refresh behavior.
  • fernandotonon/QtMeshEditor#760: Also modifies UVEditorController’s edit-selection context island computation and the related triangle/vertex mapping.

Poem

I’m a rabbit with a timer, hop-hoppity bright,
Lazy docks wake softly in the moonlit night.
🐇 QML naps, then opens with a wink,
And UV islands pop into place in a blink.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 9.09% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: deferring UV rebuilds to avoid UI freezes.
Description check ✅ Passed The description covers the summary, key technical changes, and test plan, so it is mostly complete despite missing template headings.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/model-import-uv-editor-freeze

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/mainwindow.cpp`:
- Around line 1152-1157: The AI Chat open paths in MainWindow are missing a
ui.action breadcrumb for user-facing navigation. Update both entrypoints that
open the chat (the aiChatButton clicked lambda and the other AI Chat action path
referenced in MainWindow) to call SentryReporter::addBreadcrumb with category
ui.action and a message indicating the chat was opened before showing/raising
m_chatDock, so both routes are consistently tracked.
- Around line 882-892: The `AssetBrowserController::importMeshRequested` signal
hookup in `MainWindow` was moved into the `m_assetBrowserDock` visibilityChanged
lambda, which makes the import handler register too late and can drop
`openFile()` requests before the dock is shown. Move the connect/disconnect
logic for `importMeshRequested` back into the startup/initialization path of
`MainWindow` so the signal is always wired eagerly, and keep only
`ensureLazyDockQml(m_assetBrowserDock)` inside the visibilityChanged handler.
- Around line 255-271: The theme menu check state is reading only the “palette”
setting, which can diverge from the actual theme chosen by
ThemeManager::applySavedThemeFromSettings(). Update the logic in the mainwindow
sync block to follow the same precedence as ThemeManager, using
“appearanceTheme” first and falling back to “palette” only when appropriate,
while still keeping the QAction state updates in sync for ui->actionLight,
ui->actionDark, and ui->actionCustom.

In `@src/UVEditorController_test.cpp`:
- Around line 198-208: The test in UVEditorController should not assume the
singleton starts with an empty mesh cache, since UVEditorController::instance()
may already retain mesh state from earlier tests. Update the setup so the test
explicitly establishes a known state before asserting hasMesh(), and remove the
extra ctrl->refresh() after ctrl->setPanelActive(true) so the test verifies that
setPanelActive(true) itself flushes any deferred refresh. Use the existing
UVEditorController methods and meshDataChanged spy to keep the assertions
focused on the panel activation behavior.

In `@src/UVEditorController.cpp`:
- Around line 68-86: The refresh queue in UVEditorController is not cleared when
the panel becomes inactive, so a previously started m_refreshTimer can still
fire and trigger refresh/rebuildMeshCache while hidden. Update
setPanelActive(bool) to stop any pending timer when active becomes false, and
keep scheduleRefresh() using m_refreshPending only for deferred refreshes; use
the existing m_refreshTimer, m_refreshPending, and refresh() flow to locate the
fix.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b7566518-969e-4782-8c82-28fff33b30de

📥 Commits

Reviewing files that changed from the base of the PR and between 65bc246 and b0443d1.

📒 Files selected for processing (5)
  • src/AssetBrowserController.cpp
  • src/UVEditorController.cpp
  • src/UVEditorController.h
  • src/UVEditorController_test.cpp
  • src/mainwindow.cpp

Comment thread src/mainwindow.cpp
Comment thread src/mainwindow.cpp Outdated
Comment thread src/mainwindow.cpp
Comment thread src/UVEditorController_test.cpp
Comment thread src/UVEditorController.cpp

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b0443d1d0b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/mainwindow.cpp
UVEditorController::instance()->setPanelActive(vis);
if (vis) {
ensureLazyDockQml(m_uvEditorDock);
UVEditorController::instance()->refresh();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Avoid rebuilding the UV cache twice when reopening

When the UV editor was previously opened and then hidden during an import/selection change, scheduleRefresh() leaves m_refreshPending set; the call to setPanelActive(true) just above this line consumes that pending state by calling refresh(), and then this unconditional refresh() immediately rebuilds the same mesh cache a second time. For large meshes this doubles the UI-thread work exactly when the user opens the UV Editor after an import, so skip this call when activation has already flushed a pending refresh or move the refresh responsibility to one place.

Useful? React with 👍 / 👎.

…cancel

Match ThemeManager settings precedence for palette menu checkboxes, keep
importMeshRequested wired at startup (lazy QML only), stop debounce timer
when UV Editor hides, add AI Chat breadcrumbs, and tighten hidden-panel test.

Co-authored-by: Cursor <cursoragent@cursor.com>
@sonarqubecloud

Copy link
Copy Markdown

@fernandotonon

Copy link
Copy Markdown
Owner Author

Addressed CodeRabbit review in 6634066:

Comment Fix
Theme menu out of sync with ThemeManager precedence Checkbox sync now uses the same appearanceTheme / palette / custom resolution as ThemeManager::applySavedThemeFromSettings() (still no second setPalette() call)
Asset Browser importMeshRequested dropped before dock shown Signal wiring restored at startup; only QML setSource stays lazy on visibility
UV debounce timer fires after dock hidden setPanelActive(false) stops the timer and marks refresh pending
AI Chat open paths missing breadcrumbs Added ui.action breadcrumbs on toolbar + menu entry points
Hidden-panel test order-dependent Fresh controller instance; assert setPanelActive(true) flushes pending refresh without explicit refresh()

Latest CI run (28274082203) is green.

@fernandotonon
fernandotonon merged commit f20f82f into master Jun 27, 2026
21 checks passed
@fernandotonon
fernandotonon deleted the fix/model-import-uv-editor-freeze branch June 27, 2026 02:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant