From 73a6610e810ab6209c7c8f0dec2209c72581235b Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 17 Jun 2026 15:00:20 +0200 Subject: [PATCH] Backends: OpenGL3: Expose selected render state in ImGui_ImplOpenGL3_RenderState, allowing to dynamically select between use of glBindSampler() and glTexParameter(). (#9378) --- backends/imgui_impl_opengl3.cpp | 74 ++++++++++++++++++++++++++------- backends/imgui_impl_opengl3.h | 13 ++++++ docs/CHANGELOG.txt | 2 + 3 files changed, 73 insertions(+), 16 deletions(-) diff --git a/backends/imgui_impl_opengl3.cpp b/backends/imgui_impl_opengl3.cpp index b3d32426a..1f96c6fe8 100644 --- a/backends/imgui_impl_opengl3.cpp +++ b/backends/imgui_impl_opengl3.cpp @@ -23,7 +23,8 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2026-06-23: OpenGL: GLSL version detection assume GLSL 410 when GL context is 4.1. Fixes an issue running on macOS with Wine. (#9427, #6577) +// 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) // 2026-04-23: OpenGL: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState, DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest. (#9378) // (Breaking): this change prioritize using glBindSampler() when available, which would override glTexParameter() settings you may have set on custom textures. // 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) @@ -255,8 +256,6 @@ struct ImGui_ImplOpenGL3_Data bool HasBindSampler; bool HasClipOrigin; bool UseBufferSubData; - bool UseTexParameterToSetSampler; - GLuint NextSampler; // Used if !HasBindSampler && UseTexParameterToSetSampler. #ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER GLuint TexSamplers[2]; // Used if HasBindSimpler. (0=linear, 1=nearest) #endif @@ -332,7 +331,7 @@ void ImGui_ImplOpenGL3_NewFrame() IM_ASSERT(0 && "ImGui_ImplOpenGL3_CreateDeviceObjects() failed!"); } -static void ImGui_ImplOpenGL3_SetupRenderState(ImDrawData* draw_data, int fb_width, int fb_height, GLuint vertex_array_object) +static void ImGui_ImplOpenGL3_SetupRenderState(ImDrawData* draw_data, ImGui_ImplOpenGL3_RenderState* render_state, int fb_width, int fb_height, GLuint vertex_array_object) { ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData(); @@ -386,8 +385,11 @@ static void ImGui_ImplOpenGL3_SetupRenderState(ImDrawData* draw_data, int fb_wid glUniformMatrix4fv(bd->AttribLocationProjMtx, 1, GL_FALSE, &ortho_projection[0][0]); #ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER - if (bd->HasBindSampler) - glBindSampler(0, bd->TexSamplers[0]); // We use combined texture/sampler state. Applications using GL 3.3 and GL ES 3.0 may set that otherwise. + if (render_state->UseBindSampler) + { + render_state->CurrentSampler = bd->TexSamplers[0]; + glBindSampler(0, render_state->CurrentSampler); // We use combined texture/sampler state. Applications using GL 3.3 and GL ES 3.0 may set that otherwise. + } #endif (void)vertex_array_object; @@ -408,13 +410,42 @@ static void ImGui_ImplOpenGL3_SetupRenderState(ImDrawData* draw_data, int fb_wid // Draw callbacks static void ImGui_ImplOpenGL3_DrawCallback_ResetRenderState(const ImDrawList*, const ImDrawCmd*) {} // Intentionally empty. Used as an identifier for rendering loop to call its code. Simpler to implement this way. +static void ImGui_ImplOpenGL3_DrawCallback_SetSamplerLinear(const ImDrawList*, const ImDrawCmd*) +{ + ImGui_ImplOpenGL3_RenderState* render_state = ImGui_ImplOpenGL3_GetRenderState(); #ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER -static void ImGui_ImplOpenGL3_DrawCallback_SetSamplerLinear(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData(); if (bd->HasBindSampler) { glBindSampler(0, bd->TexSamplers[0]); } else { bd->UseTexParameterToSetSampler = true; bd->NextSampler = GL_LINEAR; } } -static void ImGui_ImplOpenGL3_DrawCallback_SetSamplerNearest(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData(); if (bd->HasBindSampler) { glBindSampler(0, bd->TexSamplers[1]); } else { bd->UseTexParameterToSetSampler = true; bd->NextSampler = GL_NEAREST; } } -#else -static void ImGui_ImplOpenGL3_DrawCallback_SetSamplerLinear(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData(); bd->UseTexParameterToSetSampler = true; bd->NextSampler = GL_LINEAR; } -static void ImGui_ImplOpenGL3_DrawCallback_SetSamplerNearest(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData(); bd->UseTexParameterToSetSampler = true; bd->NextSampler = GL_NEAREST; } + ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData(); + if (bd->HasBindSampler) + { + render_state->CurrentSampler = bd->TexSamplers[0]; + render_state->UseTexParameterFilter = false; + glBindSampler(0, render_state->CurrentSampler); + } + else #endif + { + render_state->UseTexParameterFilter = true; + render_state->CurrentTexParameterFilter = GL_LINEAR; + } +} +static void ImGui_ImplOpenGL3_DrawCallback_SetSamplerNearest(const ImDrawList*, const ImDrawCmd*) +{ + ImGui_ImplOpenGL3_RenderState* render_state = ImGui_ImplOpenGL3_GetRenderState(); +#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER + ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData(); + if (bd->HasBindSampler) + { + render_state->CurrentSampler = bd->TexSamplers[1]; + render_state->UseTexParameterFilter = false; + glBindSampler(0, render_state->CurrentSampler); + } + else +#endif + { + render_state->UseTexParameterFilter = true; + render_state->CurrentTexParameterFilter = GL_NEAREST; + } +} // OpenGL3 Render function. // Note that this implementation is little overcomplicated because we are saving/setting up/restoring every OpenGL state explicitly. @@ -484,7 +515,17 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data) #ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY GL_CALL(glGenVertexArrays(1, &vertex_array_object)); #endif - ImGui_ImplOpenGL3_SetupRenderState(draw_data, fb_width, fb_height, vertex_array_object); + + // Setup render state structure (for callbacks and custom texture bindings) + ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); + ImGui_ImplOpenGL3_RenderState render_state; + render_state.UseBindSampler = bd->HasBindSampler; + render_state.UseTexParameterFilter = false; + render_state.CurrentSampler = 0; + render_state.CurrentTexParameterFilter = 0; + platform_io.Renderer_RenderState = &render_state; + + ImGui_ImplOpenGL3_SetupRenderState(draw_data, &render_state, fb_width, fb_height, vertex_array_object); // Will project scissor/clipping rectangles into framebuffer space ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports @@ -531,7 +572,7 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data) { // User callback, registered via ImDrawList::AddCallback() if (pcmd->UserCallback == ImGui_ImplOpenGL3_DrawCallback_ResetRenderState) - ImGui_ImplOpenGL3_SetupRenderState(draw_data, fb_width, fb_height, vertex_array_object); + ImGui_ImplOpenGL3_SetupRenderState(draw_data, &render_state, fb_width, fb_height, vertex_array_object); else pcmd->UserCallback(draw_list, pcmd); } @@ -551,10 +592,10 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data) // Emulate sampler change (even though it is technically part of texture data) // As a sort of hack/workaround, we only start writing using glTexParameter() if sampler is ever changed explicitly. - if (!bd->HasBindSampler && bd->UseTexParameterToSetSampler) + if (render_state.UseTexParameterFilter) { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, bd->NextSampler); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, bd->NextSampler); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, render_state.CurrentTexParameterFilter); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, render_state.CurrentTexParameterFilter); } #ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET @@ -566,6 +607,7 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data) } } } + platform_io.Renderer_RenderState = nullptr; // Destroy the temporary VAO #ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY diff --git a/backends/imgui_impl_opengl3.h b/backends/imgui_impl_opengl3.h index aabe04b07..a93804213 100644 --- a/backends/imgui_impl_opengl3.h +++ b/backends/imgui_impl_opengl3.h @@ -65,4 +65,17 @@ IMGUI_IMPL_API void ImGui_ImplOpenGL3_UpdateTexture(ImTextureData* tex); #endif +// [BETA] Selected render state data shared with callbacks. +// This is temporarily stored in GetPlatformIO().Renderer_RenderState during the ImGui_ImplOpenGL3_RenderDrawData() call. +// (Please open an issue if you feel you need access to more data) +struct ImGui_ImplOpenGL3_RenderState +{ + bool UseBindSampler; + bool UseTexParameterFilter; + unsigned int CurrentSampler; // (GLuint) Used if UseBindSampler == true, otherwise always 0 + unsigned int CurrentTexParameterFilter; // (GLuint) Used if UseTexParameterToSetSampler == true +}; + +static inline ImGui_ImplOpenGL3_RenderState* ImGui_ImplOpenGL3_GetRenderState() { return (ImGui_ImplOpenGL3_RenderState*)ImGui::GetPlatformIO().Renderer_RenderState; } + #endif // #ifndef IMGUI_DISABLE diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index dde360912..b962a1352 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -86,6 +86,8 @@ Other Changes: - OpenGL3: - GLSL version detection assume GLSL 410 when GL context is 4.1. Fixes an issue running on macOS with Wine. [#9427, #6577) [@perminovVS] + - Expose selected render state in ImGui_ImplOpenGL3_RenderState, allowing to + dynamically select between use of glBindSampler() and glTexParameter(). (#9378) - Win32: - Uses `SetProcessDpiAwarenessContext()` instead of `SetThreadDpiAwarenessContext()` when available, fixing OpenGL DPI scaling issues as e.g. NVIDIA drivers tends