diff --git a/backends/imgui_impl_metal.h b/backends/imgui_impl_metal.h index 702d754ad..cc3f29cc7 100644 --- a/backends/imgui_impl_metal.h +++ b/backends/imgui_impl_metal.h @@ -32,7 +32,7 @@ IMGUI_IMPL_API bool ImGui_ImplMetal_Init(id device); IMGUI_IMPL_API void ImGui_ImplMetal_Shutdown(); IMGUI_IMPL_API void ImGui_ImplMetal_NewFrame(MTLRenderPassDescriptor* renderPassDescriptor); -IMGUI_IMPL_API void ImGui_ImplMetal_RenderDrawData(ImDrawData* drawData, +IMGUI_IMPL_API void ImGui_ImplMetal_RenderDrawData(ImDrawData* draw_data, id commandBuffer, id commandEncoder); @@ -40,14 +40,8 @@ IMGUI_IMPL_API void ImGui_ImplMetal_RenderDrawData(ImDrawData* drawData, IMGUI_IMPL_API bool ImGui_ImplMetal_CreateDeviceObjects(id device); IMGUI_IMPL_API void ImGui_ImplMetal_DestroyDeviceObjects(); -// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = nullptr to handle this manually. -IMGUI_IMPL_API void ImGui_ImplMetal_UpdateTexture(ImTextureData* tex); - #endif -// (Optional) Multi-viewport: enable vsync (CAMetalLayer.displaySyncEnabled) on secondary viewport windows. Default: disabled. macOS only. -IMGUI_IMPL_API void ImGui_ImplMetal_SetDisplaySyncEnabled(bool enabled); - //----------------------------------------------------------------------------- // C++ API //----------------------------------------------------------------------------- @@ -71,12 +65,19 @@ IMGUI_IMPL_API void ImGui_ImplMetal_RenderDrawData(ImDrawData* draw_data, IMGUI_IMPL_API bool ImGui_ImplMetal_CreateDeviceObjects(MTL::Device* device); IMGUI_IMPL_API void ImGui_ImplMetal_DestroyDeviceObjects(); -// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = nullptr to handle this manually. -IMGUI_IMPL_API void ImGui_ImplMetal_UpdateTexture(ImTextureData* tex); - #endif #endif +//----------------------------------------------------------------------------- +// Shared +//----------------------------------------------------------------------------- + +// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = nullptr to handle this manually. +IMGUI_IMPL_API void ImGui_ImplMetal_UpdateTexture(ImTextureData* tex); + +// (Advanced) Multi-viewport: enable vsync (CAMetalLayer.displaySyncEnabled) on secondary viewport windows. Default: disabled. macOS only. +IMGUI_IMPL_API void ImGui_ImplMetal_SetDisplaySyncEnabled(bool enabled); + //----------------------------------------------------------------------------- #endif // #ifndef IMGUI_DISABLE diff --git a/backends/imgui_impl_metal.mm b/backends/imgui_impl_metal.mm index 30459462d..0061207e0 100644 --- a/backends/imgui_impl_metal.mm +++ b/backends/imgui_impl_metal.mm @@ -568,11 +568,12 @@ static void ImGui_ImplMetal_SetWindowSize(ImGuiViewport* viewport, ImVec2 size) static void ImGui_ImplMetal_RenderWindow(ImGuiViewport* viewport, void*) { + ImGui_ImplMetal_Data* bd = ImGui_ImplMetal_GetBackendData(); ImGuiViewportDataMetal* data = (ImGuiViewportDataMetal*)viewport->RendererUserData; #if TARGET_OS_OSX - ImGui_ImplMetal_Data* bd = ImGui_ImplMetal_GetBackendData(); data->MetalLayer.displaySyncEnabled = bd->DisplaySyncEnabled; // Present without vsync by default + void* handle = viewport->PlatformHandleRaw ? viewport->PlatformHandleRaw : viewport->PlatformHandle; NSWindow* window = (__bridge NSWindow*)handle; @@ -591,6 +592,8 @@ static void ImGui_ImplMetal_RenderWindow(ImGuiViewport* viewport, void*) CGSize want_size = MakeScaledSize(window.contentView.bounds.size, fb_scale); if (!CGSizeEqualToSize(data->MetalLayer.drawableSize, want_size)) data->MetalLayer.drawableSize = want_size; +#else + IM_UNUSED(bd); #endif id drawable = [data->MetalLayer nextDrawable]; diff --git a/backends/imgui_impl_metal4.h b/backends/imgui_impl_metal4.h index 61f797fae..4e4fc43bc 100644 --- a/backends/imgui_impl_metal4.h +++ b/backends/imgui_impl_metal4.h @@ -40,7 +40,7 @@ IMGUI_IMPL_API void ImGui_ImplMetal4_Shutdown(); // frameInFlightIndex must match the slot you use to index your own per-frame-in-flight resources // (e.g. the same index used to pick your command buffer/allocator), and must be < framesInFlight passed to Init(). IMGUI_IMPL_API void ImGui_ImplMetal4_NewFrame(MTL4RenderPassDescriptor* renderPassDescriptor, int frameInFlightIndex); -IMGUI_IMPL_API void ImGui_ImplMetal4_RenderDrawData(ImDrawData* drawData, +IMGUI_IMPL_API void ImGui_ImplMetal4_RenderDrawData(ImDrawData* draw_data, id commandBuffer, id commandEncoder); @@ -48,9 +48,6 @@ IMGUI_IMPL_API void ImGui_ImplMetal4_RenderDrawData(ImDrawData* drawData, IMGUI_IMPL_API bool ImGui_ImplMetal4_CreateDeviceObjects(id device); IMGUI_IMPL_API void ImGui_ImplMetal4_DestroyDeviceObjects(); -// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = nullptr to handle this manually. -IMGUI_IMPL_API void ImGui_ImplMetal4_UpdateTexture(ImTextureData* tex); - #endif //----------------------------------------------------------------------------- @@ -79,12 +76,19 @@ IMGUI_IMPL_API void ImGui_ImplMetal4_RenderDrawData(ImDrawData* draw_data, IMGUI_IMPL_API bool ImGui_ImplMetal4_CreateDeviceObjects(MTL::Device* device); IMGUI_IMPL_API void ImGui_ImplMetal4_DestroyDeviceObjects(); -// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = nullptr to handle this manually. -IMGUI_IMPL_API void ImGui_ImplMetal4_UpdateTexture(ImTextureData* tex); - #endif #endif +//----------------------------------------------------------------------------- +// Shared +//----------------------------------------------------------------------------- + +// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = nullptr to handle this manually. +IMGUI_IMPL_API void ImGui_ImplMetal4_UpdateTexture(ImTextureData* tex); + +// (Advanced) Multi-viewport: enable vsync (CAMetalLayer.displaySyncEnabled) on secondary viewport windows. Default: disabled. macOS only. +IMGUI_IMPL_API void ImGui_ImplMetal4_SetDisplaySyncEnabled(bool enabled); + //----------------------------------------------------------------------------- #endif // #ifndef IMGUI_DISABLE diff --git a/backends/imgui_impl_metal4.mm b/backends/imgui_impl_metal4.mm index 6c9603afc..4486f442a 100644 --- a/backends/imgui_impl_metal4.mm +++ b/backends/imgui_impl_metal4.mm @@ -21,6 +21,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2026-11-05: [Docking] Present secondary viewport windows without vsync by default, matching other backends. Added ImGui_ImplMetal_SetDisplaySyncEnabled(). (#9501, #9608) // 2026-10-06: Added support for render passes with multiple color attachments: we render to the first one and leave the others untouched. (#9574) // 2026-09-07: Round framebuffer dimensions to the nearest integer instead of truncating them. (#9538, 9515, #8628) // 2026-08-06: Metal 4: fixed resizing windows losing framebuffer scale. (#6828, #8856) @@ -109,8 +110,9 @@ struct ImGui_ImplMetal4_Data { MetalContext* SharedMetalContext; id RenderCommandEncoder; + bool DisplaySyncEnabled; - ImGui_ImplMetal4_Data() { memset((void*)this, 0, sizeof(*this)); } + ImGui_ImplMetal4_Data() { memset((void*)this, 0, sizeof(*this)); } }; static ImGui_ImplMetal4_Data* ImGui_ImplMetal4_GetBackendData() { return ImGui::GetCurrentContext() ? (ImGui_ImplMetal4_Data*)ImGui::GetIO().BackendRendererUserData : nullptr; } @@ -825,6 +827,13 @@ struct ImGuiViewportDataMetal bool FirstFrame = true; }; +void ImGui_ImplMetal4_SetDisplaySyncEnabled(bool enabled) +{ + ImGui_ImplMetal4_Data* bd = ImGui_ImplMetal4_GetBackendData(); + IM_ASSERT(bd != nullptr && "Context or backend not initialized! Did you call ImGui_ImplMetal4_Init()?"); + bd->DisplaySyncEnabled = enabled; +} + static void ImGui_ImplMetal_CreateWindow(ImGuiViewport* viewport) { ImGui_ImplMetal4_Data* bd = ImGui_ImplMetal4_GetBackendData(); @@ -874,9 +883,12 @@ static void ImGui_ImplMetal_SetWindowSize(ImGuiViewport* viewport, ImVec2 size) static void ImGui_ImplMetal_RenderWindow(ImGuiViewport* viewport, void*) { + ImGui_ImplMetal4_Data* bd = ImGui_ImplMetal4_GetBackendData(); ImGuiViewportDataMetal* data = (ImGuiViewportDataMetal*)viewport->RendererUserData; #if TARGET_OS_OSX + data->MetalLayer.displaySyncEnabled = bd->DisplaySyncEnabled; // Present without vsync by default + void* handle = viewport->PlatformHandleRaw ? viewport->PlatformHandleRaw : viewport->PlatformHandle; NSWindow* window = (__bridge NSWindow*)handle; @@ -907,7 +919,6 @@ static void ImGui_ImplMetal_RenderWindow(ImGuiViewport* viewport, void*) if ((viewport->Flags & ImGuiViewportFlags_NoRendererClear) == 0) renderPassDescriptor.colorAttachments[0].loadAction = MTLLoadActionClear; - ImGui_ImplMetal4_Data* bd = ImGui_ImplMetal4_GetBackendData(); id commandBuffer = [bd->SharedMetalContext.device newCommandBuffer]; [commandBuffer beginCommandBufferWithAllocator:bd->SharedMetalContext.commandAllocators[bd->SharedMetalContext.currentFrameSlot]]; diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index d333576d2..31dc01125 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -114,7 +114,7 @@ Docking+Viewports Branch: - Win32: make windows appear with `::SetWindowPos()` w/ `SWP_NOOWNERZORDER` instead of unparenting + `ShowWindow()`. Fixes missing taskbar icon for newly appearing windows that are parented and use `ImGuiViewportFlags_NoFocusOnAppearing`. (#7354, #8669) - - Metal: present secondary viewport windows without vsync by default, matching other + - Metal, Metal4: present secondary viewport windows without vsync by default, matching other backends. Added `ImGui_ImplMetal_SetDisplaySyncEnabled()`. (#9501, #9608) [@lailoken]