Skip to content

Metal: secondary viewport windows freeze during live resize on macOS #9500

Description

@lailoken

Version/Branch of Dear ImGui:

1.93.0 WIP, docking branch

Back-ends:

imgui_impl_metal.mm + imgui_impl_sdl2.cpp (backend-agnostic on the platform side)

Compiler, OS:

macOS

Full config/build information:

// (Copy from the next line. Keep the ``` markers for formatting.)

Dear ImGui 1.92.9 WIP (19285)
--------------------------------
sizeof(size_t): 8, sizeof(ImDrawIdx): 4, sizeof(ImDrawVert): 20
define: __cplusplus=202002
define: __APPLE__
define: __GNUC__=4
define: __clang_version__=21.0.0 (clang-2100.1.1.101)
define: IMGUI_HAS_VIEWPORT
define: IMGUI_HAS_DOCK
define: NDEBUG
IM_ASSERT: runs expression: KO. expand size: KO (MAYBE DISABLED?!) (?)
--------------------------------
io.BackendPlatformName: imgui_impl_sdl2 (2.32.70, 2.32.70) (cocoa)
io.BackendRendererName: imgui_impl_metal
io.ConfigFlags: 0x00000481
 NavEnableKeyboard
 DockingEnable
 ViewportsEnable
io.ConfigDpiScaleFonts
io.ConfigDpiScaleViewports
io.ConfigViewportsNoAutoMerge
io.ConfigViewportsNoDefaultParent
io.ConfigDockingWithShift
io.ConfigNavCaptureKeyboard
io.ConfigInputTextCursorBlink
io.ConfigWindowsResizeFromEdges
io.ConfigMemoryCompactTimer = 60.0
io.BackendFlags: 0x00000C1E
 HasMouseCursors
 HasSetMousePos
 PlatformHasViewports
 RendererHasVtxOffset
 RendererHasTextures
 RendererHasViewports
--------------------------------
io.Fonts: 5 fonts, Flags: 0x00000004, TexSize: 512,256
io.Fonts->FontLoaderName: stb_truetype
io.DisplaySize: 1.00,1.00
io.DisplayFramebufferScale: 1.00,1.00
--------------------------------
style.WindowPadding: 8.00,8.00
style.WindowBorderSize: 0.00
style.FramePadding: 4.00,3.00
style.FrameRounding: 0.00
style.FrameBorderSize: 1.00
style.ItemSpacing: 6.00,3.00
style.ItemInnerSpacing: 4.00,2.00

Details:

Description:

With multi-viewports enabled, dragging the border of a secondary viewport window shows frozen, detached contents; the drawable stops tracking the window until the mouse is released.

Cause: during AppKit live resize, Core Animation only composites drawables that are presented synchronously inside the current CATransaction. ImGui_ImplMetal_RenderWindow() presents asynchronously (presentDrawable: + commit), which happens outside the transaction, so AppKit keeps compositing the stale layer contents.

Steps to reproduce:

Run any Metal multi-viewport example on macOS, drag a window out of the main viewport, then resize it by its border.

Fix (Apple's documented pattern for Metal live resize):

In ImGui_ImplMetal_RenderWindow(), set presentsWithTransaction while in live resize and present synchronously:

#if TARGET_OS_OSX
    // During live resize, Core Animation only composites drawables presented synchronously within
    // the current transaction; an asynchronous presentDrawable: leaves the window contents frozen.
    bool in_live_resize = window.inLiveResize;
    data->MetalLayer.presentsWithTransaction = in_live_resize;
#endif

    ...encode and render as before...

#if TARGET_OS_OSX
    if (in_live_resize)
    {
        [commandBuffer commit];
        [commandBuffer waitUntilScheduled];
        [drawable present];
    }
    else
#endif
    {
        [commandBuffer presentDrawable:drawable];
        [commandBuffer commit];
    }

The waitUntilScheduled stall only occurs during live resize; the normal path is unchanged. Reference: CAMetalLayer.presentsWithTransaction documentation.

This pairs with the drawable-size fixes discussed in #6828 / #8856 (same function).

Screenshots/Video:

No response

Minimal, Complete and Verifiable Example code:

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions