Skip to content

Metal: no way to control vsync (displaySyncEnabled) on secondary viewport windows (API proposal) #9501

Description

@lailoken

Version/Branch of Dear ImGui:

1.93.0 WIP, docking branch

Back-ends:

imgui_impl_metal.mm

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:

My Issue/Question:

XXX (please provide as much context as possible)

Screenshots/Video:

Description:

The application owns the main viewport's CAMetalLayer and can set displaySyncEnabled on it directly, but the layers for secondary viewport windows are created inside the backend (ImGui_ImplMetal_CreateWindow) with the default (vsync on), and ImGuiViewportDataMetal is file-private behind viewport->RendererUserData, so there is no supported way to reach them.

An application that runs unsynced (with its own frame pacing) gets clamped by each vsynced secondary present; with several viewport windows across displays the presents serialize and the whole UI drops toward refresh-rate/N.

Proposal:

// Set CAMetalLayer.displaySyncEnabled for secondary viewport windows created by the backend.
// macOS only: no-op on other Apple platforms.
IMGUI_IMPL_API void ImGui_ImplMetal_SetDisplaySyncEnabled(bool enabled);

Implementation I'm running: the flag lives in ImGui_ImplMetal_Data (per-context, default true = CAMetalLayer's default); the setter applies it to existing secondary viewport layers and Renderer_CreateWindow applies it to new ones:

void ImGui_ImplMetal_SetDisplaySyncEnabled(bool enabled)
{
    ImGui_ImplMetal_Data* bd = ImGui_ImplMetal_GetBackendData();
    IM_ASSERT(bd != nullptr && "Context or backend not initialized! Did you call ImGui_ImplMetal_Init()?");
    bd->DisplaySyncEnabled = enabled;
#if TARGET_OS_OSX
    ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
    for (int i = 1; i < platform_io.Viewports.Size; i++)
        if (ImGuiViewportDataMetal* data = (ImGuiViewportDataMetal*)platform_io.Viewports[i]->RendererUserData)
            data->MetalLayer.displaySyncEnabled = enabled;
#endif
}

plus in ImGui_ImplMetal_CreateWindow():

#if TARGET_OS_OSX
    layer.displaySyncEnabled = bd->DisplaySyncEnabled;
#endif

If you'd rather see a generic per-viewport or ImGuiPlatformIO-level vsync toggle (the same limitation exists in other backends' swap-interval handling; related discussion in #1542 / #9078), I'm open to either shape.

Minimal, Complete and Verifiable Example code:

No response

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions