Our application owns the main viewport's CAMetalLayer and can set displaySyncEnabled on it, but the secondary viewport layers are created by the backend and always have vsync on, which throttles the frames when the app runs with vsync off.
ImGui_ImplMetal_SetDisplaySyncEnabled(bool) stores the settings (default to true, so no behaviour change), applies it to existing secondary viewport layers, and ImGui_ImplMetal_CreateWindow() applies it to new ones. The main viewport is left to the app. macOS only; no-op elsewhere.
Tested on macOS with SDL2 + Metal, multi-viewports.
Fixes #9501
Activity
5NB: if the option was configurable it is simpler we write to layer.displaySyncEnabled in ImGui_ImplMetal_RenderWindow().
Agreed, simpler is better. I've updated the PR to just set displaySyncEnabled = NO on secondary viewport layers and dropped the API. The main viewport's layer stays app-owned, so an app that wants vsync still gets its pacing from there.
Small follow-up: testing the "always off" version in our app showed it can't be unconditional. We run multi-viewport with the main viewport hidden (it never presents), so the secondary viewports' vsync was our only frame pacing. With it forced off, the app ran unpaced.
So I went with your second suggestion: vsync on secondary viewports is now off by default (matching other backends), and ImGui_ImplMetal_SetDisplaySyncEnabled(bool) just stores a flag that ImGui_ImplMetal_RenderWindow() writes to layer.displaySyncEnabled each frame. Apps that pace via a presenting main viewport don't need to call anything.
Other backends tends to avoid vsync for secondary viewports, so I would suggest we could first simply disable this all together by default?
I generally agree in #9501 that it would be nice to provide a backend-agnostic option through I worry it may be difficult to express all associated subtleties.