From e3927dc004a05f4cc7b4ebe5f1fe204efbbb4f29 Mon Sep 17 00:00:00 2001 From: Turtle Dove Date: Wed, 15 Jul 2026 07:58:39 -0500 Subject: [PATCH] Backends: OpenGL2/3: Backup and restore GL_UNPACK state in UpdateTexture() (#9473, #8802) --- backends/imgui_impl_opengl2.cpp | 11 +++++++++++ backends/imgui_impl_opengl3.cpp | 20 +++++++++++++++++++- 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/backends/imgui_impl_opengl2.cpp b/backends/imgui_impl_opengl2.cpp index 6cbaaac77..23afa1d33 100644 --- a/backends/imgui_impl_opengl2.cpp +++ b/backends/imgui_impl_opengl2.cpp @@ -30,6 +30,7 @@ // 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) // 2025-09-18: Call platform_io.ClearRendererHandlers() on shutdown. // 2025-07-15: OpenGL: Set GL_UNPACK_ALIGNMENT to 1 before updating textures. (#8802) +// 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) // 2025-06-11: OpenGL: Added support for ImGuiBackendFlags_RendererHasTextures, for dynamic font atlas. Removed ImGui_ImplOpenGL2_CreateFontsTexture() and ImGui_ImplOpenGL2_DestroyFontsTexture(). // 2024-10-07: OpenGL: Changed default texture sampler to Clamp instead of Repeat/Wrap. // 2024-06-28: OpenGL: ImGui_ImplOpenGL2_NewFrame() recreates font texture if it has been destroyed by ImGui_ImplOpenGL2_DestroyFontsTexture(). (#7748) @@ -262,6 +263,12 @@ void ImGui_ImplOpenGL2_RenderDrawData(ImDrawData* draw_data) void ImGui_ImplOpenGL2_UpdateTexture(ImTextureData* tex) { + // Backup GL_UNPACK state that we modify, restore on exit. + // This prevents corrupting the caller's pixel store state when ImGui + // creates or updates textures mid-frame. (#8802, #9473) + GLint last_unpack_row_length = 0; GL_CALL(glGetIntegerv(GL_UNPACK_ROW_LENGTH, &last_unpack_row_length)); + GLint last_unpack_alignment = 0; GL_CALL(glGetIntegerv(GL_UNPACK_ALIGNMENT, &last_unpack_alignment)); + if (tex->Status == ImTextureStatus_WantCreate) { // Create and upload new texture to graphics system @@ -318,6 +325,10 @@ void ImGui_ImplOpenGL2_UpdateTexture(ImTextureData* tex) tex->SetTexID(ImTextureID_Invalid); tex->SetStatus(ImTextureStatus_Destroyed); } + + // Restore GL_UNPACK state + GL_CALL(glPixelStorei(GL_UNPACK_ROW_LENGTH, last_unpack_row_length)); + GL_CALL(glPixelStorei(GL_UNPACK_ALIGNMENT, last_unpack_alignment)); } bool ImGui_ImplOpenGL2_CreateDeviceObjects() diff --git a/backends/imgui_impl_opengl3.cpp b/backends/imgui_impl_opengl3.cpp index 1f96c6fe8..8e21a3a5f 100644 --- a/backends/imgui_impl_opengl3.cpp +++ b/backends/imgui_impl_opengl3.cpp @@ -32,6 +32,7 @@ // 2025-09-18: Call platform_io.ClearRendererHandlers() on shutdown. // 2025-07-22: OpenGL: Add and call embedded loader shutdown during ImGui_ImplOpenGL3_Shutdown() to facilitate multiple init/shutdown cycles in same process. (#8792) // 2025-07-15: OpenGL: Set GL_UNPACK_ALIGNMENT to 1 before updating textures (#8802) + restore non-WebGL/ES update path that doesn't require a CPU-side copy. +// 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) // 2025-06-11: OpenGL: Added support for ImGuiBackendFlags_RendererHasTextures, for dynamic font atlas. Removed ImGui_ImplOpenGL3_CreateFontsTexture() and ImGui_ImplOpenGL3_DestroyFontsTexture(). // 2025-06-04: OpenGL: Made GLES 3.20 contexts not access GL_CONTEXT_PROFILE_MASK nor GL_PRIMITIVE_RESTART. (#8664) // 2025-02-18: OpenGL: Lazily reinitialize embedded GL loader for when calling backend from e.g. other DLL boundaries. (#8406) @@ -666,7 +667,16 @@ static void ImGui_ImplOpenGL3_DestroyTexture(ImTextureData* tex) void ImGui_ImplOpenGL3_UpdateTexture(ImTextureData* tex) { - // FIXME: Consider backing up and restoring + // Backup GL_UNPACK state that we modify, restore on exit. + // This prevents corrupting the caller's pixel store state when ImGui + // creates or updates textures mid-frame. (#8802, #9473) +#ifdef GL_UNPACK_ROW_LENGTH + GLint last_unpack_row_length = 0; GL_CALL(glGetIntegerv(GL_UNPACK_ROW_LENGTH, &last_unpack_row_length)); +#endif +#ifdef GL_UNPACK_ALIGNMENT + GLint last_unpack_alignment = 0; GL_CALL(glGetIntegerv(GL_UNPACK_ALIGNMENT, &last_unpack_alignment)); +#endif + if (tex->Status == ImTextureStatus_WantCreate || tex->Status == ImTextureStatus_WantUpdates) { #ifdef GL_UNPACK_ROW_LENGTH // Not on WebGL/ES @@ -738,6 +748,14 @@ void ImGui_ImplOpenGL3_UpdateTexture(ImTextureData* tex) } else if (tex->Status == ImTextureStatus_WantDestroy && tex->UnusedFrames > 0) ImGui_ImplOpenGL3_DestroyTexture(tex); + + // Restore GL_UNPACK state +#ifdef GL_UNPACK_ROW_LENGTH + GL_CALL(glPixelStorei(GL_UNPACK_ROW_LENGTH, last_unpack_row_length)); +#endif +#ifdef GL_UNPACK_ALIGNMENT + GL_CALL(glPixelStorei(GL_UNPACK_ALIGNMENT, last_unpack_alignment)); +#endif } // If you get an error please report on github. You may try different GL context version or GLSL version. See GL<>GLSL version table at the top of this file.