From 4898533613abc4412601fdb87f775f8c399701fe Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 7 Sep 2026 12:47:03 +0200 Subject: [PATCH] Backends: DX10, DX11, DX12, Metal/4, OpenGL2/3, SDLGPU3, Vulkan: round framebuffer dimensions instead of truncating. (#9538, #9515, #8628) --- backends/imgui_impl_dx10.cpp | 5 +++-- backends/imgui_impl_dx11.cpp | 4 ++-- backends/imgui_impl_dx12.cpp | 5 +++-- backends/imgui_impl_metal.mm | 9 +++++---- backends/imgui_impl_metal4.mm | 9 +++++---- backends/imgui_impl_opengl2.cpp | 5 +++-- backends/imgui_impl_opengl3.cpp | 5 +++-- backends/imgui_impl_sdlgpu3.cpp | 9 +++++---- backends/imgui_impl_vulkan.cpp | 5 +++-- examples/example_apple_opengl2/main.mm | 4 ++-- examples/example_apple_opengl3/main.mm | 4 ++-- 11 files changed, 36 insertions(+), 28 deletions(-) diff --git a/backends/imgui_impl_dx10.cpp b/backends/imgui_impl_dx10.cpp index 35378612d..7cf062cc7 100644 --- a/backends/imgui_impl_dx10.cpp +++ b/backends/imgui_impl_dx10.cpp @@ -16,6 +16,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2026-09-07: Round framebuffer dimensions to the nearest integer instead of truncating them. (#9538, 9515, #8628) // 2026-04-23: DirectX10: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState, DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest. Obsoleting samplers from ImGui_ImplDX10_RenderState. (#9378) // 2026-01-19: DirectX10: Added 'SamplerNearest' in ImGui_ImplDX10_RenderState. Renamed 'SamplerDefault' to 'SamplerLinear'. // 2025-09-18: Call platform_io.ClearRendererHandlers() on shutdown. @@ -106,8 +107,8 @@ static void ImGui_ImplDX10_SetupRenderState(ImDrawData* draw_data, ID3D10Device* // Setup viewport D3D10_VIEWPORT vp = {}; - vp.Width = (UINT)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x); - vp.Height = (UINT)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y); + vp.Width = (UINT)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x + 0.5f); + vp.Height = (UINT)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y + 0.5f); vp.MinDepth = 0.0f; vp.MaxDepth = 1.0f; vp.TopLeftX = vp.TopLeftY = 0; diff --git a/backends/imgui_impl_dx11.cpp b/backends/imgui_impl_dx11.cpp index 73f722a08..a15f1ab25 100644 --- a/backends/imgui_impl_dx11.cpp +++ b/backends/imgui_impl_dx11.cpp @@ -110,8 +110,8 @@ static void ImGui_ImplDX11_SetupRenderState(const ImDrawData* draw_data, ID3D11D // Setup viewport D3D11_VIEWPORT vp = {}; - vp.Width = draw_data->DisplaySize.x * draw_data->FramebufferScale.x; - vp.Height = draw_data->DisplaySize.y * draw_data->FramebufferScale.y; + vp.Width = (float)(int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x + 0.5f); + vp.Height = (float)(int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y + 0.5f); vp.MinDepth = 0.0f; vp.MaxDepth = 1.0f; vp.TopLeftX = vp.TopLeftY = 0; diff --git a/backends/imgui_impl_dx12.cpp b/backends/imgui_impl_dx12.cpp index 04516eefd..811600b66 100644 --- a/backends/imgui_impl_dx12.cpp +++ b/backends/imgui_impl_dx12.cpp @@ -20,6 +20,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2026-09-07: Round framebuffer dimensions to the nearest integer instead of truncating them. (#9538, 9515, #8628) // 2026-08-05: DirectX12: *BREAKING CHANGE* Removed support for legacy `ImGui_ImplDX12_Init()` signature obsoleted in 1.91.6 (2024-11-15) because it needed to forcefully disable support for ImGuiBackendFlags_RendererHasTextures. (#9487) // 2026-04-23: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState, DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest. (#9378) // 2025-10-11: DirectX12: Reuse texture upload buffer and grow it only when necessary. (#9002) @@ -183,8 +184,8 @@ static void ImGui_ImplDX12_SetupRenderState(ImDrawData* draw_data, ID3D12Graphic // Setup viewport D3D12_VIEWPORT vp = {}; - vp.Width = draw_data->DisplaySize.x * draw_data->FramebufferScale.x; - vp.Height = draw_data->DisplaySize.y * draw_data->FramebufferScale.y; + vp.Width = (float)(int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x + 0.5f); + vp.Height = (float)(int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y + 0.5f); vp.MinDepth = 0.0f; vp.MaxDepth = 1.0f; vp.TopLeftX = vp.TopLeftY = 0.0f; diff --git a/backends/imgui_impl_metal.mm b/backends/imgui_impl_metal.mm index 1c0660628..55b33de14 100644 --- a/backends/imgui_impl_metal.mm +++ b/backends/imgui_impl_metal.mm @@ -16,6 +16,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2026-09-07: Round framebuffer dimensions to the nearest integer instead of truncating them. (#9538, 9515, #8628) // 2026-04-28: Added support for standard draw callbacks (in platform_io): DrawCallback_SetSamplerLinear and DrawCallback_SetSamplerNearest. (#9378, #9381) // 2026-04-23: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState (others are not yet supported). (#9378) // 2026-04-14: Metal: use a dedicated bufferCacheLock to avoid crashing when bufferCache is replaced by a new object while being used for @synchronize(). (#9367) @@ -163,8 +164,8 @@ static void ImGui_ImplMetal_SetupRenderState(ImDrawData* draw_data, idDisplaySize.x * draw_data->FramebufferScale.x), - .height = (double)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y), + .width = (double)(int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x + 0.5f), + .height = (double)(int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y + 0.5f), .znear = 0.0, .zfar = 1.0 }; @@ -203,8 +204,8 @@ void ImGui_ImplMetal_RenderDrawData(ImDrawData* draw_data, id MetalContext* ctx = bd->SharedMetalContext; // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates) - int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x); - int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y); + int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x + 0.5f); + int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y + 0.5f); if (fb_width <= 0 || fb_height <= 0 || draw_data->CmdLists.Size == 0) return; diff --git a/backends/imgui_impl_metal4.mm b/backends/imgui_impl_metal4.mm index 2866ed1e2..73f8c5905 100644 --- a/backends/imgui_impl_metal4.mm +++ b/backends/imgui_impl_metal4.mm @@ -19,6 +19,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2026-09-07: Round framebuffer dimensions to the nearest integer instead of truncating them. (#9538, 9515, #8628) // 2026-07-07: Metal 4: Added metal-cpp support. (#9461) // 2026-07-02: Metal 4: Added new Metal 4 backend implementation. (#9458) @@ -162,8 +163,8 @@ static void ImGui_ImplMetal4_SetupRenderState(ImDrawData* draw_data, idDisplaySize.x * draw_data->FramebufferScale.x), - .height = (double)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y), + .width = (double)(int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x + 0.5f), + .height = (double)(int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y + 0.5f), .znear = 0.0, .zfar = 1.0 }; @@ -203,8 +204,8 @@ void ImGui_ImplMetal4_RenderDrawData(ImDrawData* draw_data, idSharedMetalContext; // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates) - int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x); - int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y); + int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x + 0.5f); + int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y + 0.5f); if (fb_width <= 0 || fb_height <= 0 || draw_data->CmdLists.Size == 0) return; diff --git a/backends/imgui_impl_opengl2.cpp b/backends/imgui_impl_opengl2.cpp index e6d195533..8fe9d489f 100644 --- a/backends/imgui_impl_opengl2.cpp +++ b/backends/imgui_impl_opengl2.cpp @@ -26,6 +26,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2026-09-07: Round framebuffer dimensions to the nearest integer instead of truncating them. (#9538, 9515, #8628) // 2026-07-15: OpenGL: Backup and restore GL_UNPACK_ROW_LENGTH and GL_UNPACK_ALIGNMENT in UpdateTexture() to avoid corrupting caller GL state. (#8802, #9473) // 2026-04-23: OpenGL: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState, DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest. (#9378) // 2026-03-12: OpenGL: Fixed invalid assert in ImGui_ImplOpenGL3_UpdateTexture() if ImTextureID_Invalid is defined to be != 0, which became the default since 2026-03-12. (#9295) @@ -168,8 +169,8 @@ void ImGui_ImplOpenGL2_RenderDrawData(ImDrawData* draw_data) { // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates) ImGui_ImplOpenGL2_Data* bd = ImGui_ImplOpenGL2_GetBackendData(); - int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x); - int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y); + int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x + 0.5f); + int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y + 0.5f); if (fb_width == 0 || fb_height == 0) return; diff --git a/backends/imgui_impl_opengl3.cpp b/backends/imgui_impl_opengl3.cpp index e917fd36b..6d3e2751f 100644 --- a/backends/imgui_impl_opengl3.cpp +++ b/backends/imgui_impl_opengl3.cpp @@ -23,6 +23,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2026-09-07: Round framebuffer dimensions to the nearest integer instead of truncating them. (#9538, 9515, #8628) // 2026-07-15: OpenGL: Backup and restore GL_UNPACK_ROW_LENGTH and GL_UNPACK_ALIGNMENT in UpdateTexture() to avoid corrupting caller GL state. (#8802, #9473) // 2026-06-17: OpenGL: Expose selected render state in ImGui_ImplOpenGL3_RenderState, Allowing to dynamically select between use of glBindSampler() and glTexParameter(). You can access in 'void* platform_io.Renderer_RenderState' during rendering. // 2026-06-03: OpenGL: GLSL version detection assume GLSL 410 when GL context is 4.1. Fixes an issue running on macOS with Wine. (#9427, #6577) @@ -455,8 +456,8 @@ static void ImGui_ImplOpenGL3_DrawCallback_SetSamplerNearest(const ImDrawList*, void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data) { // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates) - int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x); - int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y); + int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x + 0.5f); + int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y + 0.5f); if (fb_width <= 0 || fb_height <= 0) return; diff --git a/backends/imgui_impl_sdlgpu3.cpp b/backends/imgui_impl_sdlgpu3.cpp index 9328b0a32..2a73f1b05 100644 --- a/backends/imgui_impl_sdlgpu3.cpp +++ b/backends/imgui_impl_sdlgpu3.cpp @@ -22,6 +22,7 @@ // Calling the function is MANDATORY, otherwise the ImGui will not upload neither the vertex nor the index buffer for the GPU. See imgui_impl_sdlgpu3.cpp for more info. // CHANGELOG +// 2026-09-07: Round framebuffer dimensions to the nearest integer instead of truncating them. (#9538, 9515, #8628) // 2026-04-23: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState, DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest. Obsoleting samplers from ImGui_ImplSDLGPU3_RenderState. (#9378) // 2026-03-19: Fixed issue in ImGui_ImplSDLGPU3_DestroyTexture() if ImTextureID_Invalid is defined to be != 0, which became the default since 2026-03-12. (#9295, #9310) // 2026-02-25: Removed unnecessary call to SDL_WaitForGPUIdle when releasing vertex/index buffers. (#9262) @@ -163,8 +164,8 @@ static void CreateOrResizeBuffers(SDL_GPUBuffer** buffer, SDL_GPUTransferBuffer* void ImGui_ImplSDLGPU3_PrepareDrawData(ImDrawData* draw_data, SDL_GPUCommandBuffer* command_buffer) { // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates) - int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x); - int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y); + int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x + 0.5f); + int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y + 0.5f); if (fb_width <= 0 || fb_height <= 0 || draw_data->TotalVtxCount <= 0) return; @@ -229,8 +230,8 @@ static void ImGui_ImplSDLGPU3_DrawCallback_SetSamplerNearest(const ImDrawList*, void ImGui_ImplSDLGPU3_RenderDrawData(ImDrawData* draw_data, SDL_GPUCommandBuffer* command_buffer, SDL_GPURenderPass* render_pass, SDL_GPUGraphicsPipeline* pipeline) { // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates) - int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x); - int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y); + int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x + 0.5f); + int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y + 0.5f); if (fb_width <= 0 || fb_height <= 0) return; diff --git a/backends/imgui_impl_vulkan.cpp b/backends/imgui_impl_vulkan.cpp index 0e172bfb8..795c87a1a 100644 --- a/backends/imgui_impl_vulkan.cpp +++ b/backends/imgui_impl_vulkan.cpp @@ -27,6 +27,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2026-09-07: Round framebuffer dimensions to the nearest integer instead of truncating them. (#9538, 9515, #8628) // 2026-09-03: Added for support for multiple Vulkan contexts with custom loaders. (#6616) // 2026-04-23: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState, DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest. (#9378) // 2026-04-22: *BREAKING CHANGE* redesigned to use separate ImageView + Sampler instead of Combined Image Sampler. This change allows us to facilitate changing samplers, in line with other backends. @@ -587,8 +588,8 @@ void ImGui_ImplVulkan_DrawCallback_SetSamplerCustom(const ImDrawList*, const ImD void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer command_buffer, VkPipeline pipeline) { // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates) - int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x); - int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y); + int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x + 0.5f); + int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y + 0.5f); if (fb_width <= 0 || fb_height <= 0) return; diff --git a/examples/example_apple_opengl2/main.mm b/examples/example_apple_opengl2/main.mm index 65c169089..7cdc38f20 100644 --- a/examples/example_apple_opengl2/main.mm +++ b/examples/example_apple_opengl2/main.mm @@ -131,8 +131,8 @@ ImDrawData* draw_data = ImGui::GetDrawData(); [[self openGLContext] makeCurrentContext]; - GLsizei width = (GLsizei)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x); - GLsizei height = (GLsizei)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y); + GLsizei width = (GLsizei)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x + 0.5f); + GLsizei height = (GLsizei)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y + 0.5f); glViewport(0, 0, width, height); glClearColor(clear_color.x * clear_color.w, clear_color.y * clear_color.w, clear_color.z * clear_color.w, clear_color.w); glClear(GL_COLOR_BUFFER_BIT); diff --git a/examples/example_apple_opengl3/main.mm b/examples/example_apple_opengl3/main.mm index 1541d5d07..241aa1332 100644 --- a/examples/example_apple_opengl3/main.mm +++ b/examples/example_apple_opengl3/main.mm @@ -131,8 +131,8 @@ ImDrawData* draw_data = ImGui::GetDrawData(); [[self openGLContext] makeCurrentContext]; - GLsizei width = (GLsizei)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x); - GLsizei height = (GLsizei)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y); + GLsizei width = (GLsizei)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x + 0.5f); + GLsizei height = (GLsizei)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y + 0.5f); glViewport(0, 0, width, height); glClearColor(clear_color.x * clear_color.w, clear_color.y * clear_color.w, clear_color.z * clear_color.w, clear_color.w); glClear(GL_COLOR_BUFFER_BIT);