Backends: Metal, Metal4: amend 1876296 for Metal4 backend. (#9501, #9608)

This commit is contained in:
ocornut 2026-11-05 11:28:19 +01:00
parent 1876296f42
commit 1f3ee75ee4
5 changed files with 40 additions and 21 deletions

View File

@ -32,7 +32,7 @@
IMGUI_IMPL_API bool ImGui_ImplMetal_Init(id<MTLDevice> 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<MTLCommandBuffer> commandBuffer,
id<MTLRenderCommandEncoder> commandEncoder);
@ -40,14 +40,8 @@ IMGUI_IMPL_API void ImGui_ImplMetal_RenderDrawData(ImDrawData* drawData,
IMGUI_IMPL_API bool ImGui_ImplMetal_CreateDeviceObjects(id<MTLDevice> 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

View File

@ -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 <CAMetalDrawable> drawable = [data->MetalLayer nextDrawable];

View File

@ -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<MTL4CommandBuffer> commandBuffer,
id<MTL4RenderCommandEncoder> commandEncoder);
@ -48,9 +48,6 @@ IMGUI_IMPL_API void ImGui_ImplMetal4_RenderDrawData(ImDrawData* drawData,
IMGUI_IMPL_API bool ImGui_ImplMetal4_CreateDeviceObjects(id<MTLDevice> 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

View File

@ -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<MTL4RenderCommandEncoder> 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 <MTL4CommandBuffer> commandBuffer = [bd->SharedMetalContext.device newCommandBuffer];
[commandBuffer beginCommandBufferWithAllocator:bd->SharedMetalContext.commandAllocators[bd->SharedMetalContext.currentFrameSlot]];

View File

@ -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]