From 4cec3a0467af9cd068d85363d1a7ceaddc3b68e0 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 29 Jun 2021 16:42:13 +0200 Subject: [PATCH] Backends: support for multiple imgui context with little testing (#586, #1851, #2004, #3012, #3934, #4141) I believe more renderer backends should work. GLFW/Win32/SDL/Vulkan probably have many issues. --- backends/imgui_impl_dx10.cpp | 10 +++++----- backends/imgui_impl_dx11.cpp | 10 +++++----- backends/imgui_impl_dx12.cpp | 10 +++++----- backends/imgui_impl_dx9.cpp | 10 +++++----- backends/imgui_impl_glfw.cpp | 12 +++++++----- backends/imgui_impl_opengl2.cpp | 10 +++++----- backends/imgui_impl_opengl3.cpp | 10 +++++----- backends/imgui_impl_sdl.cpp | 14 ++++++++------ backends/imgui_impl_vulkan.cpp | 11 ++++++----- backends/imgui_impl_win32.cpp | 12 +++++++----- docs/CHANGELOG.txt | 7 +++++-- 11 files changed, 63 insertions(+), 53 deletions(-) diff --git a/backends/imgui_impl_dx10.cpp b/backends/imgui_impl_dx10.cpp index 760f36f0..19de9692 100644 --- a/backends/imgui_impl_dx10.cpp +++ b/backends/imgui_impl_dx10.cpp @@ -62,11 +62,11 @@ struct ImGui_ImplDX10_Data ImGui_ImplDX10_Data() { memset(this, 0, sizeof(*this)); VertexBufferSize = 5000; IndexBufferSize = 10000; } }; -// Wrapping access to backend data (to facilitate multiple-contexts stored in io.BackendPlatformUserData) -static ImGui_ImplDX10_Data* g_Data; -static ImGui_ImplDX10_Data* ImGui_ImplDX10_CreateBackendData() { IM_ASSERT(g_Data == NULL); g_Data = IM_NEW(ImGui_ImplDX10_Data); return g_Data; } -static ImGui_ImplDX10_Data* ImGui_ImplDX10_GetBackendData() { return ImGui::GetCurrentContext() != NULL ? g_Data : NULL; } -static void ImGui_ImplDX10_DestroyBackendData() { IM_DELETE(g_Data); g_Data = NULL; } +// Backend data stored in io.BackendRendererUserData to allow support for multiple Dear ImGui contexts +// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts. +static ImGui_ImplDX10_Data* ImGui_ImplDX10_CreateBackendData() { return IM_NEW(ImGui_ImplDX10_Data)(); } +static ImGui_ImplDX10_Data* ImGui_ImplDX10_GetBackendData() { return (ImGui_ImplDX10_Data*)ImGui::GetIO().BackendRendererUserData; } +static void ImGui_ImplDX10_DestroyBackendData() { IM_DELETE(ImGui_ImplDX10_GetBackendData()); } struct VERTEX_CONSTANT_BUFFER { diff --git a/backends/imgui_impl_dx11.cpp b/backends/imgui_impl_dx11.cpp index 867fb7ac..a5f9f217 100644 --- a/backends/imgui_impl_dx11.cpp +++ b/backends/imgui_impl_dx11.cpp @@ -63,11 +63,11 @@ struct ImGui_ImplDX11_Data ImGui_ImplDX11_Data() { memset(this, 0, sizeof(*this)); VertexBufferSize = 5000; IndexBufferSize = 10000; } }; -// Wrapping access to backend data (to facilitate multiple-contexts stored in io.BackendPlatformUserData) -static ImGui_ImplDX11_Data* g_Data; -static ImGui_ImplDX11_Data* ImGui_ImplDX11_CreateBackendData() { IM_ASSERT(g_Data == NULL); g_Data = IM_NEW(ImGui_ImplDX11_Data); return g_Data; } -static ImGui_ImplDX11_Data* ImGui_ImplDX11_GetBackendData() { return ImGui::GetCurrentContext() != NULL ? g_Data : NULL; } -static void ImGui_ImplDX11_DestroyBackendData() { IM_DELETE(g_Data); g_Data = NULL; } +// Backend data stored in io.BackendRendererUserData to allow support for multiple Dear ImGui contexts +// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts. +static ImGui_ImplDX11_Data* ImGui_ImplDX11_CreateBackendData() { return IM_NEW(ImGui_ImplDX11_Data)(); } +static ImGui_ImplDX11_Data* ImGui_ImplDX11_GetBackendData() { return (ImGui_ImplDX11_Data*)ImGui::GetIO().BackendRendererUserData; } +static void ImGui_ImplDX11_DestroyBackendData() { IM_DELETE(ImGui_ImplDX11_GetBackendData()); } struct VERTEX_CONSTANT_BUFFER { diff --git a/backends/imgui_impl_dx12.cpp b/backends/imgui_impl_dx12.cpp index c7dcca11..079c515c 100644 --- a/backends/imgui_impl_dx12.cpp +++ b/backends/imgui_impl_dx12.cpp @@ -74,11 +74,11 @@ struct ImGui_ImplDX12_Data ImGui_ImplDX12_Data() { memset(this, 0, sizeof(*this)); frameIndex = UINT_MAX; } }; -// Wrapping access to backend data (to facilitate multiple-contexts stored in io.BackendPlatformUserData) -static ImGui_ImplDX12_Data* g_Data; -static ImGui_ImplDX12_Data* ImGui_ImplDX12_CreateBackendData() { IM_ASSERT(g_Data == NULL); g_Data = IM_NEW(ImGui_ImplDX12_Data); return g_Data; } -static ImGui_ImplDX12_Data* ImGui_ImplDX12_GetBackendData() { return ImGui::GetCurrentContext() != NULL ? g_Data : NULL; } -static void ImGui_ImplDX12_DestroyBackendData() { IM_DELETE(g_Data); g_Data = NULL; } +// Backend data stored in io.BackendRendererUserData to allow support for multiple Dear ImGui contexts +// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts. +static ImGui_ImplDX12_Data* ImGui_ImplDX12_CreateBackendData() { return IM_NEW(ImGui_ImplDX12_Data)(); } +static ImGui_ImplDX12_Data* ImGui_ImplDX12_GetBackendData() { return (ImGui_ImplDX12_Data*)ImGui::GetIO().BackendRendererUserData; } +static void ImGui_ImplDX12_DestroyBackendData() { IM_DELETE(ImGui_ImplDX12_GetBackendData()); } template static void SafeRelease(T*& res) diff --git a/backends/imgui_impl_dx9.cpp b/backends/imgui_impl_dx9.cpp index a2d426db..07c35ea1 100644 --- a/backends/imgui_impl_dx9.cpp +++ b/backends/imgui_impl_dx9.cpp @@ -49,11 +49,11 @@ struct ImGui_ImplDX9_Data ImGui_ImplDX9_Data() { memset(this, 0, sizeof(*this)); VertexBufferSize = 5000; IndexBufferSize = 10000; } }; -// Wrapping access to backend data (to facilitate multiple-contexts stored in io.BackendPlatformUserData) -static ImGui_ImplDX9_Data* g_Data; -static ImGui_ImplDX9_Data* ImGui_ImplDX9_CreateBackendData() { IM_ASSERT(g_Data == NULL); g_Data = IM_NEW(ImGui_ImplDX9_Data); return g_Data; } -static ImGui_ImplDX9_Data* ImGui_ImplDX9_GetBackendData() { return ImGui::GetCurrentContext() != NULL ? g_Data : NULL; } -static void ImGui_ImplDX9_DestroyBackendData() { IM_DELETE(g_Data); g_Data = NULL; } +// Backend data stored in io.BackendRendererUserData to allow support for multiple Dear ImGui contexts +// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts. +static ImGui_ImplDX9_Data* ImGui_ImplDX9_CreateBackendData() { return IM_NEW(ImGui_ImplDX9_Data)(); } +static ImGui_ImplDX9_Data* ImGui_ImplDX9_GetBackendData() { return (ImGui_ImplDX9_Data*)ImGui::GetIO().BackendRendererUserData; } +static void ImGui_ImplDX9_DestroyBackendData() { IM_DELETE(ImGui_ImplDX9_GetBackendData()); } struct CUSTOMVERTEX { diff --git a/backends/imgui_impl_glfw.cpp b/backends/imgui_impl_glfw.cpp index 07b61dfb..cc3c58fc 100644 --- a/backends/imgui_impl_glfw.cpp +++ b/backends/imgui_impl_glfw.cpp @@ -86,11 +86,13 @@ struct ImGui_ImplGlfw_Data ImGui_ImplGlfw_Data() { memset(this, 0, sizeof(*this)); } }; -// Wrapping access to backend data (to facilitate multiple-contexts stored in io.BackendPlatformUserData) -static ImGui_ImplGlfw_Data* g_Data; -static ImGui_ImplGlfw_Data* ImGui_ImplGlfw_CreateBackendData() { IM_ASSERT(g_Data == NULL); g_Data = IM_NEW(ImGui_ImplGlfw_Data); return g_Data; } -static ImGui_ImplGlfw_Data* ImGui_ImplGlfw_GetBackendData() { return ImGui::GetCurrentContext() != NULL ? g_Data : NULL; } -static void ImGui_ImplGlfw_DestroyBackendData() { IM_DELETE(g_Data); g_Data = NULL; } +// Backend data stored in io.BackendPlatformUserData to allow support for multiple Dear ImGui contexts +// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts. +// FIXME: multi-context support is not well tested and probably dysfunctional in this backend. +// FIXME: some shared resources (mouse cursor shape, gamepad) are mishandled when using multi-context. +static ImGui_ImplGlfw_Data* ImGui_ImplGlfw_CreateBackendData() { return IM_NEW(ImGui_ImplGlfw_Data)(); } +static ImGui_ImplGlfw_Data* ImGui_ImplGlfw_GetBackendData() { return (ImGui_ImplGlfw_Data*)ImGui::GetIO().BackendPlatformUserData; } +static void ImGui_ImplGlfw_DestroyBackendData() { IM_DELETE(ImGui_ImplGlfw_GetBackendData()); } // Functions static const char* ImGui_ImplGlfw_GetClipboardText(void* user_data) diff --git a/backends/imgui_impl_opengl2.cpp b/backends/imgui_impl_opengl2.cpp index e45c0423..5a39edfa 100644 --- a/backends/imgui_impl_opengl2.cpp +++ b/backends/imgui_impl_opengl2.cpp @@ -63,11 +63,11 @@ struct ImGui_ImplOpenGL2_Data ImGui_ImplOpenGL2_Data() { memset(this, 0, sizeof(*this)); } }; -// Wrapping access to backend data (to facilitate multiple-contexts stored in io.BackendPlatformUserData) -static ImGui_ImplOpenGL2_Data* g_Data; -static ImGui_ImplOpenGL2_Data* ImGui_ImplOpenGL2_CreateBackendData() { IM_ASSERT(g_Data == NULL); g_Data = IM_NEW(ImGui_ImplOpenGL2_Data); return g_Data; } -static ImGui_ImplOpenGL2_Data* ImGui_ImplOpenGL2_GetBackendData() { return ImGui::GetCurrentContext() != NULL ? g_Data : NULL; } -static void ImGui_ImplOpenGL2_DestroyBackendData() { IM_DELETE(g_Data); g_Data = NULL; } +// Backend data stored in io.BackendRendererUserData to allow support for multiple Dear ImGui contexts +// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts. +static ImGui_ImplOpenGL2_Data* ImGui_ImplOpenGL2_CreateBackendData() { return IM_NEW(ImGui_ImplOpenGL2_Data)(); } +static ImGui_ImplOpenGL2_Data* ImGui_ImplOpenGL2_GetBackendData() { return (ImGui_ImplOpenGL2_Data*)ImGui::GetIO().BackendRendererUserData; } +static void ImGui_ImplOpenGL2_DestroyBackendData() { IM_DELETE(ImGui_ImplOpenGL2_GetBackendData()); } // Functions bool ImGui_ImplOpenGL2_Init() diff --git a/backends/imgui_impl_opengl3.cpp b/backends/imgui_impl_opengl3.cpp index ee0fd6f2..2204b333 100644 --- a/backends/imgui_impl_opengl3.cpp +++ b/backends/imgui_impl_opengl3.cpp @@ -189,11 +189,11 @@ struct ImGui_ImplOpenGL3_Data ImGui_ImplOpenGL3_Data() { memset(this, 0, sizeof(*this)); } }; -// Wrapping access to backend data (to facilitate multiple-contexts stored in io.BackendPlatformUserData) -static ImGui_ImplOpenGL3_Data* g_Data; -static ImGui_ImplOpenGL3_Data* ImGui_ImplOpenGL3_CreateBackendData() { IM_ASSERT(g_Data == NULL); g_Data = IM_NEW(ImGui_ImplOpenGL3_Data); return g_Data; } -static ImGui_ImplOpenGL3_Data* ImGui_ImplOpenGL3_GetBackendData() { IM_ASSERT(ImGui::GetCurrentContext() != NULL); return g_Data; } -static void ImGui_ImplOpenGL3_DestroyBackendData() { IM_DELETE(g_Data); g_Data = NULL; } +// Backend data stored in io.BackendRendererUserData to allow support for multiple Dear ImGui contexts +// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts. +static ImGui_ImplOpenGL3_Data* ImGui_ImplOpenGL3_CreateBackendData() { return IM_NEW(ImGui_ImplOpenGL3_Data)(); } +static ImGui_ImplOpenGL3_Data* ImGui_ImplOpenGL3_GetBackendData() { return (ImGui_ImplOpenGL3_Data*)ImGui::GetIO().BackendRendererUserData; } +static void ImGui_ImplOpenGL3_DestroyBackendData() { IM_DELETE(ImGui_ImplOpenGL3_GetBackendData()); } // Functions bool ImGui_ImplOpenGL3_Init(const char* glsl_version) diff --git a/backends/imgui_impl_sdl.cpp b/backends/imgui_impl_sdl.cpp index 9392216f..c7c28e04 100644 --- a/backends/imgui_impl_sdl.cpp +++ b/backends/imgui_impl_sdl.cpp @@ -69,14 +69,16 @@ struct ImGui_ImplSDL2_Data char* ClipboardTextData; bool MouseCanUseGlobalState; - ImGui_ImplSDL2_Data() { memset(this, 0, sizeof(*this)); } + ImGui_ImplSDL2_Data() { memset(this, 0, sizeof(*this)); } }; -// Wrapping access to backend data data (to facilitate multiple-contexts stored in io.BackendPlatformUserData) -static ImGui_ImplSDL2_Data* g_Data; -static ImGui_ImplSDL2_Data* ImGui_ImplSDL2_CreateBackendData() { IM_ASSERT(g_Data == NULL); g_Data = IM_NEW(ImGui_ImplSDL2_Data); return g_Data; } -static ImGui_ImplSDL2_Data* ImGui_ImplSDL2_GetBackendData() { return ImGui::GetCurrentContext() != NULL ? g_Data : NULL; } -static void ImGui_ImplSDL2_DestroyBackendData() { IM_DELETE(g_Data); g_Data = NULL; } +// Backend data stored in io.BackendPlatformUserData to allow support for multiple Dear ImGui contexts +// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts. +// FIXME: multi-context support is not well tested and probably dysfunctional in this backend. +// FIXME: some shared resources (mouse cursor shape, gamepad) are mishandled when using multi-context. +static ImGui_ImplSDL2_Data* ImGui_ImplSDL2_CreateBackendData() { return IM_NEW(ImGui_ImplSDL2_Data)(); } +static ImGui_ImplSDL2_Data* ImGui_ImplSDL2_GetBackendData() { return (ImGui_ImplSDL2_Data*)ImGui::GetIO().BackendPlatformUserData; } +static void ImGui_ImplSDL2_DestroyBackendData() { IM_DELETE(ImGui_ImplSDL2_GetBackendData()); } // Functions static const char* ImGui_ImplSDL2_GetClipboardText(void*) diff --git a/backends/imgui_impl_vulkan.cpp b/backends/imgui_impl_vulkan.cpp index f5d63b24..5f2a192d 100644 --- a/backends/imgui_impl_vulkan.cpp +++ b/backends/imgui_impl_vulkan.cpp @@ -110,11 +110,12 @@ struct ImGui_ImplVulkan_Data } }; -// Wrapping access to backend data (to facilitate multiple-contexts stored in io.BackendPlatformUserData) -static ImGui_ImplVulkan_Data* g_Data; -static ImGui_ImplVulkan_Data* ImGui_ImplVulkan_CreateBackendData() { IM_ASSERT(g_Data == NULL); g_Data = IM_NEW(ImGui_ImplVulkan_Data); return g_Data; } -static ImGui_ImplVulkan_Data* ImGui_ImplVulkan_GetBackendData() { return ImGui::GetCurrentContext() ? g_Data : NULL; } -static void ImGui_ImplVulkan_DestroyBackendData() { IM_DELETE(g_Data); g_Data = NULL; } +// Backend data stored in io.BackendRendererUserData to allow support for multiple Dear ImGui contexts +// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts. +// FIXME: multi-context support is not tested and probably dysfunctional in this backend. +static ImGui_ImplVulkan_Data* ImGui_ImplVulkan_CreateBackendData() { return IM_NEW(ImGui_ImplVulkan_Data)(); } +static ImGui_ImplVulkan_Data* ImGui_ImplVulkan_GetBackendData() { return (ImGui_ImplVulkan_Data*)ImGui::GetIO().BackendRendererUserData; } +static void ImGui_ImplVulkan_DestroyBackendData() { IM_DELETE(ImGui_ImplVulkan_GetBackendData()); } // Forward Declarations bool ImGui_ImplVulkan_CreateDeviceObjects(); diff --git a/backends/imgui_impl_win32.cpp b/backends/imgui_impl_win32.cpp index edd6635a..09d12708 100644 --- a/backends/imgui_impl_win32.cpp +++ b/backends/imgui_impl_win32.cpp @@ -82,11 +82,13 @@ struct ImGui_ImplWin32_Data ImGui_ImplWin32_Data() { memset(this, 0, sizeof(*this)); } }; -// Wrapping access to backend data (to facilitate multiple-contexts stored in io.BackendPlatformUserData) -static ImGui_ImplWin32_Data* g_Data; -static ImGui_ImplWin32_Data* ImGui_ImplWin32_CreateBackendData() { IM_ASSERT(g_Data == NULL); g_Data = IM_NEW(ImGui_ImplWin32_Data); return g_Data; } -static ImGui_ImplWin32_Data* ImGui_ImplWin32_GetBackendData() { return ImGui::GetCurrentContext() ? g_Data : NULL; } -static void ImGui_ImplWin32_DestroyBackendData() { IM_DELETE(g_Data); g_Data = NULL; } +// Backend data stored in io.BackendPlatformUserData to allow support for multiple Dear ImGui contexts +// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts. +// FIXME: multi-context support is not well tested and probably dysfunctional in this backend. +// FIXME: some shared resources (mouse cursor shape, gamepad) are mishandled when using multi-context. +static ImGui_ImplWin32_Data* ImGui_ImplWin32_CreateBackendData() { return IM_NEW(ImGui_ImplWin32_Data)(); } +static ImGui_ImplWin32_Data* ImGui_ImplWin32_GetBackendData() { return (ImGui_ImplWin32_Data*)ImGui::GetIO().BackendPlatformUserData; } +static void ImGui_ImplWin32_DestroyBackendData() { IM_DELETE(ImGui_ImplWin32_GetBackendData()); } // Functions bool ImGui_ImplWin32_Init(void* hwnd) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 995307e2..aeb6dd4b 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -55,8 +55,11 @@ Other Changes: - Demo: Fixed requirement in 1.83 to link with imgui_demo.cpp if IMGUI_DISABLE_METRICS_WINDOW is not set. (#4171) Normally the right way to disable compiling the demo is to set IMGUI_DISABLE_DEMO_WINDOWS, but we want to avoid implying that the file is required. -- Backends: Reorganized most backends (Win32, SDL, GLFW, OpenGL2/3, DX9/10/11/12, Vulkan, Allegro) to pull data - from a single structure to facilitate usage with multiple-contexts. (#586, #1851, #2004, #3012, #3934, #4141) +- Backends: Reorganized most backends (Win32, SDL, GLFW, OpenGL2/3, DX9/10/11/12, Vulkan, Allegro) to pull their + data from a single structure stored inside the main Dear ImGui context. This facilitate/allow usage of standard + backends with multiple-contexts BUT is only partially tested and not well supported. It is generally advised to + instead use the multi-viewports feature of docking branch where a single Dear ImGui context can be used accross + multiple windows. (#586, #1851, #2004, #3012, #3934, #4141) - Backends: Win32: Rework to handle certains Windows 8.1/10 features without a manifest. (#4200, #4191) - ImGui_ImplWin32_GetDpiScaleForMonitor() will handle per-monitor DPI on Windows 10 without a manifest. - ImGui_ImplWin32_EnableDpiAwareness() will call SetProcessDpiAwareness() fallback on Windows 8.1 without a manifest.