Resolved multiple issues with fix 2600
Device Contexts are no longer maintained for the application lifetime.
::GetDC() is now never called when using DirectX backend.
Removed lambda callback and brought WGL function loading into
conformance with XInput DLL loading.
diff --git a/backends/imgui_impl_opengl3.cpp b/backends/imgui_impl_opengl3.cpp
index b603fff..877f25b 100644
--- a/backends/imgui_impl_opengl3.cpp
+++ b/backends/imgui_impl_opengl3.cpp
@@ -917,6 +917,11 @@
static void ImGui_ImplOpenGL3_RenderWindow(ImGuiViewport* viewport, void*)
{
+ ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
+
+ if (platform_io.Platform_PushOglContext)
+ platform_io.Platform_PushOglContext(viewport);
+
if (!(viewport->Flags & ImGuiViewportFlags_NoRendererClear))
{
ImVec4 clear_color = ImVec4(0.0f, 0.0f, 0.0f, 1.0f);
@@ -924,6 +929,9 @@
glClear(GL_COLOR_BUFFER_BIT);
}
ImGui_ImplOpenGL3_RenderDrawData(viewport->DrawData);
+
+ if (platform_io.Platform_PopOglContext)
+ platform_io.Platform_PopOglContext(viewport);
}
static void ImGui_ImplOpenGL3_InitPlatformInterface()
diff --git a/backends/imgui_impl_win32.cpp b/backends/imgui_impl_win32.cpp
index 0e452c2..bce3fa7 100644
--- a/backends/imgui_impl_win32.cpp
+++ b/backends/imgui_impl_win32.cpp
@@ -25,12 +25,12 @@
#include <dwmapi.h>
// Stuff for loading WGL functions explicitly
-#include <cstdlib> // atexit()
-static HMODULE libgl;
-HGLRC (WINAPI* _wglCreateContext)(HDC);
-BOOL (WINAPI* _wglDeleteContext)(HGLRC);
-BOOL (WINAPI* _wglMakeCurrent)(HDC, HGLRC);
-BOOL (WINAPI* _wglShareLists)(HGLRC, HGLRC);
+static HGLRC (WINAPI* _wglCreateContext)(HDC);
+static BOOL (WINAPI* _wglDeleteContext)(HGLRC);
+static BOOL (WINAPI* _wglMakeCurrent)(HDC, HGLRC);
+static BOOL (WINAPI* _wglShareLists)(HGLRC, HGLRC);
+static HGLRC (WINAPI* _wglGetCurrentContext)(VOID);
+static HDC (WINAPI* _wglGetCurrentDC)(VOID);
// Configuration flags to add in your imconfig.h file:
//#define IMGUI_IMPL_WIN32_DISABLE_GAMEPAD // Disable gamepad support. This was meaningful before <1.81 but we now load XInput dynamically so the option is now less relevant.
@@ -103,8 +103,7 @@
struct ImGui_ImplWin32_Data
{
HWND hWnd;
- HDC Hdc;
- HGLRC HgLrc;
+ HGLRC OpenGlContext;
HWND MouseHwnd;
int MouseTrackedArea; // 0: not tracked, 1: client are, 2: non-client area
int MouseButtonsDown;
@@ -113,6 +112,11 @@
ImGuiMouseCursor LastMouseCursor;
bool WantUpdateMonitors;
+ // OpenGL
+ HMODULE OglDLL;
+ HDC stashedDeviceContext;
+ HGLRC stashedOpenGlContext;
+
#ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
bool HasGamepad;
bool WantUpdateHasGamepad;
@@ -134,7 +138,12 @@
}
// Functions
-bool ImGui_ImplWin32_Init(void* hwnd, void* hglrc)
+bool ImGui_ImplWin32_Init(void* hwnd)
+{
+ return ImGui_ImplWin32_InitForOpenGL(hwnd, NULL);
+}
+
+bool ImGui_ImplWin32_InitForOpenGL(void* hwnd, void* hglrc)
{
ImGuiIO& io = ImGui::GetIO();
IM_ASSERT(io.BackendPlatformUserData == nullptr && "Already initialized a platform backend!");
@@ -145,25 +154,6 @@
if (!::QueryPerformanceCounter((LARGE_INTEGER*)&perf_counter))
return false;
- // Load WGL symbols explicitly
- // This is needed to allow compilation if and when non-OpenGL APIs are used with Win32.
- // The function pointer names are preceded with an underscore ("_") to prevent duplicate
- // symbols in projects where OpenGL32.dll is linked implicitly.
- if (hglrc)
- {
- libgl = LoadLibraryA("opengl32.dll");
- IM_ASSERT(libgl);
- _wglCreateContext = (HGLRC(WINAPI*)(HDC))GetProcAddress(libgl, "wglCreateContext");
- _wglDeleteContext = (BOOL(WINAPI*)(HGLRC))GetProcAddress(libgl, "wglDeleteContext");
- _wglMakeCurrent = (BOOL(WINAPI*)(HDC, HGLRC))GetProcAddress(libgl, "wglMakeCurrent");
- _wglShareLists = (BOOL(WINAPI*)(HGLRC, HGLRC))GetProcAddress(libgl, "wglShareLists");
- IM_ASSERT(_wglCreateContext);
- IM_ASSERT(_wglDeleteContext);
- IM_ASSERT(_wglMakeCurrent);
- IM_ASSERT(_wglShareLists);
- atexit([](){ FreeLibrary(libgl); });
- }
-
// Setup backend capabilities flags
ImGui_ImplWin32_Data* bd = IM_NEW(ImGui_ImplWin32_Data)();
io.BackendPlatformUserData = (void*)bd;
@@ -174,8 +164,7 @@
io.BackendFlags |= ImGuiBackendFlags_HasMouseHoveredViewport; // We can call io.AddMouseViewportEvent() with correct data (optional)
bd->hWnd = (HWND)hwnd;
- bd->Hdc = GetDC(bd->hWnd);
- bd->HgLrc = (HGLRC)hglrc; // OpenGL
+ bd->OpenGlContext = (HGLRC)hglrc;
bd->WantUpdateMonitors = true;
bd->TicksPerSecond = perf_frequency;
bd->Time = perf_counter;
@@ -187,6 +176,28 @@
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
ImGui_ImplWin32_InitPlatformInterface();
+ // Dynamically load WGL symbols
+ // This is needed to allow compilation if and when non-OpenGL APIs are used with Win32.
+ // The function pointer names are preceded with an underscore ("_") to prevent duplicate
+ // symbols in projects where OpenGL32.dll is linked implicitly.
+ if (hglrc && !(bd->OglDLL))
+ {
+ bd->OglDLL = ::LoadLibraryA("opengl32.dll");
+ IM_ASSERT(bd->OglDLL);
+ _wglCreateContext = (HGLRC(WINAPI*)(HDC))GetProcAddress(bd->OglDLL, "wglCreateContext");
+ _wglDeleteContext = (BOOL(WINAPI*)(HGLRC))GetProcAddress(bd->OglDLL, "wglDeleteContext");
+ _wglMakeCurrent = (BOOL(WINAPI*)(HDC, HGLRC))GetProcAddress(bd->OglDLL, "wglMakeCurrent");
+ _wglShareLists = (BOOL(WINAPI*)(HGLRC, HGLRC))GetProcAddress(bd->OglDLL, "wglShareLists");
+ _wglGetCurrentContext = (HGLRC(WINAPI*)(VOID))GetProcAddress(bd->OglDLL, "wglGetCurrentContext");
+ _wglGetCurrentDC = (HDC(WINAPI*)(VOID))GetProcAddress(bd->OglDLL, "wglGetCurrentDC");
+ IM_ASSERT(_wglCreateContext);
+ IM_ASSERT(_wglDeleteContext);
+ IM_ASSERT(_wglMakeCurrent);
+ IM_ASSERT(_wglShareLists);
+ IM_ASSERT(_wglGetCurrentContext);
+ IM_ASSERT(_wglGetCurrentDC);
+ }
+
// Dynamically load XInput library
#ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
bd->WantUpdateHasGamepad = true;
@@ -219,6 +230,10 @@
ImGui_ImplWin32_ShutdownPlatformInterface();
+ // Unload OpenGL library
+ if (bd->OglDLL)
+ ::FreeLibrary(bd->OglDLL);
+
// Unload XInput library
#ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
if (bd->XInputDLL)
@@ -930,8 +945,7 @@
{
HWND Hwnd;
bool HwndOwned;
- HDC Hdc;
- HGLRC HgLrc;
+ HGLRC OpenGlContext;
DWORD DwStyle;
DWORD DwExStyle;
@@ -939,8 +953,7 @@
{
Hwnd = nullptr;
HwndOwned = false;
- Hdc = nullptr;
- HgLrc = nullptr;
+ OpenGlContext = nullptr;
DwStyle = 0;
DwExStyle = 0;
}
@@ -983,27 +996,39 @@
rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, // Window area
parent_window, nullptr, ::GetModuleHandle(nullptr), nullptr); // Parent window, Menu, Instance, Param
vd->HwndOwned = true;
- vd->Hdc = GetDC(vd->Hwnd);
viewport->PlatformRequestResize = false;
viewport->PlatformHandle = viewport->PlatformHandleRaw = vd->Hwnd;
ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData();
- if (bd->HgLrc) // OpenGL
+ if (bd->OpenGlContext)
{
+ HDC previousDC = _wglGetCurrentDC();
+ HGLRC previousRC = _wglGetCurrentContext();
+ HDC newDC = ::GetDC(vd->Hwnd);
+
// Use the main window's pixel format
- int pf = GetPixelFormat(bd->Hdc);
+ int pf;
PIXELFORMATDESCRIPTOR pfd;
- DescribePixelFormat(bd->Hdc, pf, sizeof(pfd), &pfd);
- SetPixelFormat(vd->Hdc, pf, &pfd);
+ if (previousDC)
+ {
+ pf = ::GetPixelFormat(previousDC);
+ ::DescribePixelFormat(previousDC, pf, sizeof(pfd), &pfd);
+ }
+ else
+ {
+ HDC mainDC = ::GetDC(bd->hWnd);
+ pf = ::GetPixelFormat(mainDC);
+ ::DescribePixelFormat(mainDC, pf, sizeof(pfd), &pfd);
+ ::ReleaseDC(bd->hWnd, mainDC);
+ }
+ ::SetPixelFormat(newDC, pf, &pfd);
// Create OpenGL context and share main context's lists with it
- vd->HgLrc = _wglCreateContext(vd->Hdc);
- _wglMakeCurrent(vd->Hdc, vd->HgLrc);
- _wglShareLists(bd->HgLrc, vd->HgLrc);
-
- // Present window
- ImGui_ImplWin32_SetWindowFocus(viewport);
- ImGui_ImplWin32_ShowWindow(viewport);
+ vd->OpenGlContext = _wglCreateContext(newDC);
+ _wglMakeCurrent(newDC, vd->OpenGlContext);
+ _wglShareLists(bd->OpenGlContext, vd->OpenGlContext);
+ _wglMakeCurrent(previousDC, previousRC);
+ ::ReleaseDC(vd->Hwnd, newDC);
}
}
@@ -1020,8 +1045,8 @@
}
if (vd->Hwnd && vd->HwndOwned)
{
- if (vd->HgLrc)
- _wglDeleteContext(vd->HgLrc);
+ if (vd->OpenGlContext)
+ _wglDeleteContext(vd->OpenGlContext);
::DestroyWindow(vd->Hwnd);
}
@@ -1184,19 +1209,37 @@
#endif
}
-static void ImGui_ImplWin32_OGL_RenderWindow(ImGuiViewport* viewport, void*)
+static void ImGui_ImplWin32_PushOglContext(ImGuiViewport* viewport)
{
+ ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData();
ImGui_ImplWin32_ViewportData* vd = (ImGui_ImplWin32_ViewportData*)viewport->PlatformUserData;
- IM_ASSERT(vd->HgLrc); // ImGui_ImplWin32_OGL_RenderWindow() is only registered if API is OpenGL
- _wglMakeCurrent(vd->Hdc, vd->HgLrc);
+ IM_ASSERT(vd->OpenGlContext); // ImGui_ImplWin32_PushOglContext() is only registered if API is OpenGL
+
+ bd->stashedDeviceContext = _wglGetCurrentDC();
+ bd->stashedOpenGlContext = _wglGetCurrentContext();
+ _wglMakeCurrent(::GetDC(vd->Hwnd), vd->OpenGlContext);
+}
+
+static void ImGui_ImplWin32_PopOglContext(ImGuiViewport* viewport)
+{
+ ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData();
+ ImGui_ImplWin32_ViewportData* vd = (ImGui_ImplWin32_ViewportData*)viewport->PlatformUserData;
+ IM_ASSERT(vd->OpenGlContext); // ImGui_ImplWin32_PopOglContext() is only registered if API is OpenGL
+
+ IM_ASSERT(_wglGetCurrentContext() == vd->OpenGlContext);
+ HDC vd_dc = _wglGetCurrentDC();
+ _wglMakeCurrent(bd->stashedDeviceContext, bd->stashedOpenGlContext);
+ ::ReleaseDC(vd->Hwnd, vd_dc);
}
static void ImGui_ImplWin32_OGL_SwapBuffers(ImGuiViewport* viewport, void*)
{
ImGui_ImplWin32_ViewportData* vd = (ImGui_ImplWin32_ViewportData*)viewport->PlatformUserData;
- IM_ASSERT(vd->HgLrc); // ImGui_ImplWin32_OGL_SwapBuffers() is only registered if API is OpenGL
- _wglMakeCurrent(vd->Hdc, vd->HgLrc);
- SwapBuffers(vd->Hdc);
+ IM_ASSERT(vd->OpenGlContext); // ImGui_ImplWin32_OGL_SwapBuffers() is only registered if API is OpenGL
+
+ ImGui_ImplWin32_PushOglContext(viewport);
+ ::SwapBuffers(_wglGetCurrentDC());
+ ImGui_ImplWin32_PopOglContext(viewport);
}
static LRESULT CALLBACK ImGui_ImplWin32_WndProcHandler_PlatformWindow(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
@@ -1276,9 +1319,10 @@
platform_io.Platform_OnChangedViewport = ImGui_ImplWin32_OnChangedViewport; // FIXME-DPI
ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData();
- if (bd->HgLrc) // OpenGL
+ if (bd->OpenGlContext) // OpenGL
{
- platform_io.Platform_RenderWindow = ImGui_ImplWin32_OGL_RenderWindow;
+ platform_io.Platform_PushOglContext = ImGui_ImplWin32_PushOglContext;
+ platform_io.Platform_PopOglContext = ImGui_ImplWin32_PopOglContext;
platform_io.Platform_SwapBuffers = ImGui_ImplWin32_OGL_SwapBuffers;
}
@@ -1288,8 +1332,7 @@
ImGui_ImplWin32_ViewportData* vd = IM_NEW(ImGui_ImplWin32_ViewportData)();
vd->Hwnd = bd->hWnd;
vd->HwndOwned = false;
- vd->Hdc = bd->Hdc;
- vd->HgLrc = bd->HgLrc; // OpenGL
+ vd->OpenGlContext = bd->OpenGlContext;
main_viewport->PlatformUserData = vd;
main_viewport->PlatformHandle = (void*)bd->hWnd;
}
diff --git a/backends/imgui_impl_win32.h b/backends/imgui_impl_win32.h
index 8ca0cb7..b01f6e0 100644
--- a/backends/imgui_impl_win32.h
+++ b/backends/imgui_impl_win32.h
@@ -17,7 +17,8 @@
#pragma once
#include "imgui.h" // IMGUI_IMPL_API
-IMGUI_IMPL_API bool ImGui_ImplWin32_Init(void* hwnd, void* hglrc = NULL);
+IMGUI_IMPL_API bool ImGui_ImplWin32_Init(void* hwnd);
+IMGUI_IMPL_API bool ImGui_ImplWin32_InitForOpenGL(void* hwnd, void* hglrc);
IMGUI_IMPL_API void ImGui_ImplWin32_Shutdown();
IMGUI_IMPL_API void ImGui_ImplWin32_NewFrame();
diff --git a/imgui.h b/imgui.h
index 2910bd6..ab8fa5e 100644
--- a/imgui.h
+++ b/imgui.h
@@ -3220,6 +3220,8 @@
float (*Platform_GetWindowDpiScale)(ImGuiViewport* vp); // N . . . . // (Optional) [BETA] FIXME-DPI: DPI handling: Return DPI scale for this viewport. 1.0f = 96 DPI.
void (*Platform_OnChangedViewport)(ImGuiViewport* vp); // . F . . . // (Optional) [BETA] FIXME-DPI: DPI handling: Called during Begin() every time the viewport we are outputting into changes, so backend has a chance to swap fonts to adjust style.
int (*Platform_CreateVkSurface)(ImGuiViewport* vp, ImU64 vk_inst, const void* vk_allocators, ImU64* out_vk_surface); // (Optional) For a Vulkan Renderer to call into Platform code (since the surface creation needs to tie them both).
+ void (*Platform_PushOglContext)(ImGuiViewport* vp); // . . . R . // (Optional) For an OpenGL Renderer to make a platform window's rendering context current for rendering
+ void (*Platform_PopOglContext)(ImGuiViewport* vp); // . . . R . // (Optional) For an OpenGL Renderer to revert to the previous rendering context after rendering a platform window
// (Optional) Renderer functions (e.g. DirectX, OpenGL, Vulkan)
void (*Renderer_CreateWindow)(ImGuiViewport* vp); // . . U . . // Create swap chain, frame buffers etc. (called after Platform_CreateWindow)