From fdfc42ed8ccf90e6b03dfccffaac509ee1aa729e Mon Sep 17 00:00:00 2001 From: ouczbs Date: Mon, 23 Dec 2024 17:44:32 +0800 Subject: [PATCH] remove imgui --- engine/3rdparty/xmake.lua | 3 +- .../editor/panel/asset_preview_panel.h | 6 +- .../editor/window/editor_main_window.h | 7 +- engine/include/engine/api.h | 1 - .../asset/impl/resource_system_impl.inl | 2 +- .../asset/{module.h => asset_module.h} | 0 .../src/{module.cpp => asset_module.cpp} | 2 +- .../render/3rdparty/imgui/imgui_impl_sdl2.cpp | 1206 ---------- .../render/3rdparty/imgui/imgui_impl_sdl2.h | 50 - .../engine/render/impl/editor_system_impl.inl | 14 - .../engine/render/impl/renderapi_impl.inl | 2 +- .../engine/render/impl/window_impl.inl | 4 +- .../render/include/render/editor_system.h | 53 - .../render/{module.h => render_module.h} | 0 .../engine/render/include/render/window.h | 2 +- .../engine/render/src/graph/frame_graph.cpp | 4 +- .../src/{module.cpp => render_module.cpp} | 2 +- engine/modules/engine/render/xmake.lua | 5 +- .../modules/engine/ui/include/ui/ui_module.h | 11 + engine/modules/engine/ui/src/ui_module.cpp | 34 + engine/modules/engine/ui/xmake.lua | 5 + .../include/imgui/imgui_impl_vulkan.cpp | 1960 ----------------- .../vulkan/include/imgui/imgui_impl_vulkan.h | 211 -- .../render/vulkan/include/vkn/vulkan_api.h | 2 +- .../vulkan/include/vkn/vulkan_imgui_editor.h | 25 - .../include/vkn/{module.h => vulkan_module.h} | 3 +- .../render/vulkan/include/vkn/vulkan_window.h | 5 +- .../modules/render/vulkan/src/vulkan_api.cpp | 4 +- .../render/vulkan/src/vulkan_imgui_editor.cpp | 185 -- .../src/{module.cpp => vulkan_module.cpp} | 14 +- .../render/vulkan/src/vulkan_window.cpp | 7 +- engine/modules/render/vulkan/xmake.lua | 2 +- engine/modules/xmake.lua | 4 +- engine/src/editor/editor.cpp | 16 +- .../src/editor/panel/asset_preview_panel.cpp | 28 - engine/src/editor/panel/menu_bar_panel.cpp | 25 - .../src/editor/window/editor_main_window.cpp | 19 - engine/src/engine/api.cpp | 1 + engine/src/engine/plugin.cpp | 8 +- engine/xmake.lua | 3 +- engine/xmake/rule_plugin/xmake.lua | 14 +- game/zworld/src/zworld.cpp | 34 +- game/zworld/src/zworld.h | 3 +- 43 files changed, 120 insertions(+), 3866 deletions(-) rename engine/modules/engine/asset/include/asset/{module.h => asset_module.h} (100%) rename engine/modules/engine/asset/src/{module.cpp => asset_module.cpp} (90%) delete mode 100644 engine/modules/engine/render/3rdparty/imgui/imgui_impl_sdl2.cpp delete mode 100644 engine/modules/engine/render/3rdparty/imgui/imgui_impl_sdl2.h delete mode 100644 engine/modules/engine/render/impl/editor_system_impl.inl delete mode 100644 engine/modules/engine/render/include/render/editor_system.h rename engine/modules/engine/render/include/render/{module.h => render_module.h} (100%) rename engine/modules/engine/render/src/{module.cpp => render_module.cpp} (85%) create mode 100644 engine/modules/engine/ui/include/ui/ui_module.h create mode 100644 engine/modules/engine/ui/src/ui_module.cpp create mode 100644 engine/modules/engine/ui/xmake.lua delete mode 100644 engine/modules/render/vulkan/include/imgui/imgui_impl_vulkan.cpp delete mode 100644 engine/modules/render/vulkan/include/imgui/imgui_impl_vulkan.h delete mode 100644 engine/modules/render/vulkan/include/vkn/vulkan_imgui_editor.h rename engine/modules/render/vulkan/include/vkn/{module.h => vulkan_module.h} (70%) delete mode 100644 engine/modules/render/vulkan/src/vulkan_imgui_editor.cpp rename engine/modules/render/vulkan/src/{module.cpp => vulkan_module.cpp} (61%) delete mode 100644 engine/src/editor/panel/asset_preview_panel.cpp delete mode 100644 engine/src/editor/panel/menu_bar_panel.cpp delete mode 100644 engine/src/editor/window/editor_main_window.cpp diff --git a/engine/3rdparty/xmake.lua b/engine/3rdparty/xmake.lua index 54e6c24..1b9be27 100644 --- a/engine/3rdparty/xmake.lua +++ b/engine/3rdparty/xmake.lua @@ -1,5 +1,6 @@ add_requires("spdlog", "vulkansdk","shaderc","spirv","spirv-cross") add_requires("mimalloc", {configs = {shared = true, debug = true, copy = true}}) -add_requires("imgui",{configs = {shared = true, debug = true, copy = true}}) +--add_requires("imgui",{configs = {shared = true, debug = true, copy = true}}) +add_requires("noesis",{configs = {shared = true, copy = true}}) add_requires("libsdl",{configs = {shared = true}}) includes("*/xmake.lua") \ No newline at end of file diff --git a/engine/include/editor/panel/asset_preview_panel.h b/engine/include/editor/panel/asset_preview_panel.h index 5a47440..7167916 100644 --- a/engine/include/editor/panel/asset_preview_panel.h +++ b/engine/include/editor/panel/asset_preview_panel.h @@ -1,8 +1,4 @@ #pragma once -#include "render/editor_system.h" namespace api { - class AssetPreviewPanel : public EditorPanel{ - public: - void DrawPanel(FrameGraph& graph, RenderEditorContext& context) override; - }; + } \ No newline at end of file diff --git a/engine/include/editor/window/editor_main_window.h b/engine/include/editor/window/editor_main_window.h index 098a319..7167916 100644 --- a/engine/include/editor/window/editor_main_window.h +++ b/engine/include/editor/window/editor_main_window.h @@ -1,9 +1,4 @@ #pragma once -#include "render/editor_system.h" namespace api { - class EditorMainWindow : public EditorWindow { - public: - EditorMainWindow(); - void Draw(FrameGraph& graph, RenderEditorContext& context) override; - }; + } \ No newline at end of file diff --git a/engine/include/engine/api.h b/engine/include/engine/api.h index dff51e5..13a8933 100644 --- a/engine/include/engine/api.h +++ b/engine/include/engine/api.h @@ -1,2 +1 @@ -#include "asset/module.h" #include "module/module_manager.h" \ No newline at end of file diff --git a/engine/modules/engine/asset/impl/resource_system_impl.inl b/engine/modules/engine/asset/impl/resource_system_impl.inl index dd5f88c..c4569d4 100644 --- a/engine/modules/engine/asset/impl/resource_system_impl.inl +++ b/engine/modules/engine/asset/impl/resource_system_impl.inl @@ -1,4 +1,4 @@ -#include "asset/module.h" +#include "asset/asset_module.h" #include "asset/resource_system.h" #include "os/file_manager.h" #include "os/file_handle.h" diff --git a/engine/modules/engine/asset/include/asset/module.h b/engine/modules/engine/asset/include/asset/asset_module.h similarity index 100% rename from engine/modules/engine/asset/include/asset/module.h rename to engine/modules/engine/asset/include/asset/asset_module.h diff --git a/engine/modules/engine/asset/src/module.cpp b/engine/modules/engine/asset/src/asset_module.cpp similarity index 90% rename from engine/modules/engine/asset/src/module.cpp rename to engine/modules/engine/asset/src/asset_module.cpp index 16c766d..09e757c 100644 --- a/engine/modules/engine/asset/src/module.cpp +++ b/engine/modules/engine/asset/src/asset_module.cpp @@ -1,4 +1,4 @@ -#include "asset/module.h" +#include "asset/asset_module.h" #include "asset/resource_system.h" #include "asset/asset_loader.h" #include "archive/pch.h" diff --git a/engine/modules/engine/render/3rdparty/imgui/imgui_impl_sdl2.cpp b/engine/modules/engine/render/3rdparty/imgui/imgui_impl_sdl2.cpp deleted file mode 100644 index 2e5af0e..0000000 --- a/engine/modules/engine/render/3rdparty/imgui/imgui_impl_sdl2.cpp +++ /dev/null @@ -1,1206 +0,0 @@ -// dear imgui: Platform Backend for SDL2 -// This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..) -// (Info: SDL2 is a cross-platform general purpose library for handling windows, inputs, graphics context creation, etc.) -// (Prefer SDL 2.0.5+ for full feature support.) - -// Implemented features: -// [X] Platform: Clipboard support. -// [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen. -// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy SDL_SCANCODE_* values are obsolete since 1.87 and not supported since 1.91.5] -// [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. -// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. -// [X] Platform: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'. -// Issues: -// [ ] Platform: Multi-viewport: Minimized windows seems to break mouse wheel events (at least under Windows). -// [ ] Platform: Multi-viewport: ParentViewportID not honored, and so io.ConfigViewportsNoDefaultParent has no effect (minor). -// [x] Platform: Basic IME support. App needs to call 'SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1");' before SDL_CreateWindow()!. - -// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. -// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. -// Learn about Dear ImGui: -// - FAQ https://dearimgui.com/faq -// - Getting Started https://dearimgui.com/getting-started -// - Documentation https://dearimgui.com/docs (same as your local docs/ folder). -// - Introduction, links and more at the top of imgui.cpp - -// CHANGELOG -// (minor and older changes stripped away, please see git history for details) -// 2024-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. -// 2024-10-24: Emscripten: from SDL 2.30.9, SDL_EVENT_MOUSE_WHEEL event doesn't require dividing by 100.0f. -// 2024-09-09: use SDL_Vulkan_GetDrawableSize() when available. (#7967, #3190) -// 2024-08-22: moved some OS/backend related function pointers from ImGuiIO to ImGuiPlatformIO: -// - io.GetClipboardTextFn -> platform_io.Platform_GetClipboardTextFn -// - io.SetClipboardTextFn -> platform_io.Platform_SetClipboardTextFn -// - io.PlatformOpenInShellFn -> platform_io.Platform_OpenInShellFn -// - io.PlatformSetImeDataFn -> platform_io.Platform_SetImeDataFn -// 2024-08-19: Storing SDL's Uint32 WindowID inside ImGuiViewport::PlatformHandle instead of SDL_Window*. -// 2024-08-19: ImGui_ImplSDL2_ProcessEvent() now ignores events intended for other SDL windows. (#7853) -// 2024-07-02: Emscripten: Added io.PlatformOpenInShellFn() handler for Emscripten versions. -// 2024-07-02: Update for io.SetPlatformImeDataFn() -> io.PlatformSetImeDataFn() renaming in main library. -// 2024-02-14: Inputs: Handle gamepad disconnection. Added ImGui_ImplSDL2_SetGamepadMode(). -// 2023-10-05: Inputs: Added support for extra ImGuiKey values: F13 to F24 function keys, app back/forward keys. -// 2023-04-06: Inputs: Avoid calling SDL_StartTextInput()/SDL_StopTextInput() as they don't only pertain to IME. It's unclear exactly what their relation is to IME. (#6306) -// 2023-04-04: Inputs: Added support for io.AddMouseSourceEvent() to discriminate ImGuiMouseSource_Mouse/ImGuiMouseSource_TouchScreen. (#2702) -// 2023-02-23: Accept SDL_GetPerformanceCounter() not returning a monotonically increasing value. (#6189, #6114, #3644) -// 2023-02-07: Implement IME handler (io.SetPlatformImeDataFn will call SDL_SetTextInputRect()/SDL_StartTextInput()). -// 2023-02-07: *BREAKING CHANGE* Renamed this backend file from imgui_impl_sdl.cpp/.h to imgui_impl_sdl2.cpp/.h in prevision for the future release of SDL3. -// 2023-02-02: Avoid calling SDL_SetCursor() when cursor has not changed, as the function is surprisingly costly on Mac with latest SDL (may be fixed in next SDL version). -// 2023-02-02: Added support for SDL 2.0.18+ preciseX/preciseY mouse wheel data for smooth scrolling + Scaling X value on Emscripten (bug?). (#4019, #6096) -// 2023-02-02: Removed SDL_MOUSEWHEEL value clamping, as values seem correct in latest Emscripten. (#4019) -// 2023-02-01: Flipping SDL_MOUSEWHEEL 'wheel.x' value to match other backends and offer consistent horizontal scrolling direction. (#4019, #6096, #1463) -// 2022-10-11: Using 'nullptr' instead of 'NULL' as per our switch to C++11. -// 2022-09-26: Inputs: Disable SDL 2.0.22 new "auto capture" (SDL_HINT_MOUSE_AUTO_CAPTURE) which prevents drag and drop across windows for multi-viewport support + don't capture when drag and dropping. (#5710) -// 2022-09-26: Inputs: Renamed ImGuiKey_ModXXX introduced in 1.87 to ImGuiMod_XXX (old names still supported). -// 2022-03-22: Inputs: Fix mouse position issues when dragging outside of boundaries. SDL_CaptureMouse() erroneously still gives out LEAVE events when hovering OS decorations. -// 2022-03-22: Inputs: Added support for extra mouse buttons (SDL_BUTTON_X1/SDL_BUTTON_X2). -// 2022-02-04: Added SDL_Renderer* parameter to ImGui_ImplSDL2_InitForSDLRenderer(), so we can use SDL_GetRendererOutputSize() instead of SDL_GL_GetDrawableSize() when bound to a SDL_Renderer. -// 2022-01-26: Inputs: replaced short-lived io.AddKeyModsEvent() (added two weeks ago) with io.AddKeyEvent() using ImGuiKey_ModXXX flags. Sorry for the confusion. -// 2021-01-20: Inputs: calling new io.AddKeyAnalogEvent() for gamepad support, instead of writing directly to io.NavInputs[]. -// 2022-01-17: Inputs: calling new io.AddMousePosEvent(), io.AddMouseButtonEvent(), io.AddMouseWheelEvent() API (1.87+). -// 2022-01-17: Inputs: always update key mods next and before key event (not in NewFrame) to fix input queue with very low framerates. -// 2022-01-12: Update mouse inputs using SDL_MOUSEMOTION/SDL_WINDOWEVENT_LEAVE + fallback to provide it when focused but not hovered/captured. More standard and will allow us to pass it to future input queue API. -// 2022-01-12: Maintain our own copy of MouseButtonsDown mask instead of using ImGui::IsAnyMouseDown() which will be obsoleted. -// 2022-01-10: Inputs: calling new io.AddKeyEvent(), io.AddKeyModsEvent() + io.SetKeyEventNativeData() API (1.87+). Support for full ImGuiKey range. -// 2021-08-17: Calling io.AddFocusEvent() on SDL_WINDOWEVENT_FOCUS_GAINED/SDL_WINDOWEVENT_FOCUS_LOST. -// 2021-07-29: Inputs: MousePos is correctly reported when the host platform window is hovered but not focused (using SDL_GetMouseFocus() + SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, requires SDL 2.0.5+) -// 2021-06:29: *BREAKING CHANGE* Removed 'SDL_Window* window' parameter to ImGui_ImplSDL2_NewFrame() which was unnecessary. -// 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX). -// 2021-03-22: Rework global mouse pos availability check listing supported platforms explicitly, effectively fixing mouse access on Raspberry Pi. (#2837, #3950) -// 2020-05-25: Misc: Report a zero display-size when window is minimized, to be consistent with other backends. -// 2020-02-20: Inputs: Fixed mapping for ImGuiKey_KeyPadEnter (using SDL_SCANCODE_KP_ENTER instead of SDL_SCANCODE_RETURN2). -// 2019-12-17: Inputs: On Wayland, use SDL_GetMouseState (because there is no global mouse state). -// 2019-12-05: Inputs: Added support for ImGuiMouseCursor_NotAllowed mouse cursor. -// 2019-07-21: Inputs: Added mapping for ImGuiKey_KeyPadEnter. -// 2019-04-23: Inputs: Added support for SDL_GameController (if ImGuiConfigFlags_NavEnableGamepad is set by user application). -// 2019-03-12: Misc: Preserve DisplayFramebufferScale when main window is minimized. -// 2018-12-21: Inputs: Workaround for Android/iOS which don't seem to handle focus related calls. -// 2018-11-30: Misc: Setting up io.BackendPlatformName so it can be displayed in the About Window. -// 2018-11-14: Changed the signature of ImGui_ImplSDL2_ProcessEvent() to take a 'const SDL_Event*'. -// 2018-08-01: Inputs: Workaround for Emscripten which doesn't seem to handle focus related calls. -// 2018-06-29: Inputs: Added support for the ImGuiMouseCursor_Hand cursor. -// 2018-06-08: Misc: Extracted imgui_impl_sdl.cpp/.h away from the old combined SDL2+OpenGL/Vulkan examples. -// 2018-06-08: Misc: ImGui_ImplSDL2_InitForOpenGL() now takes a SDL_GLContext parameter. -// 2018-05-09: Misc: Fixed clipboard paste memory leak (we didn't call SDL_FreeMemory on the data returned by SDL_GetClipboardText). -// 2018-03-20: Misc: Setup io.BackendFlags ImGuiBackendFlags_HasMouseCursors flag + honor ImGuiConfigFlags_NoMouseCursorChange flag. -// 2018-02-16: Inputs: Added support for mouse cursors, honoring ImGui::GetMouseCursor() value. -// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves. -// 2018-02-06: Inputs: Added mapping for ImGuiKey_Space. -// 2018-02-05: Misc: Using SDL_GetPerformanceCounter() instead of SDL_GetTicks() to be able to handle very high framerate (1000+ FPS). -// 2018-02-05: Inputs: Keyboard mapping is using scancodes everywhere instead of a confusing mixture of keycodes and scancodes. -// 2018-01-20: Inputs: Added Horizontal Mouse Wheel support. -// 2018-01-19: Inputs: When available (SDL 2.0.4+) using SDL_CaptureMouse() to retrieve coordinates outside of client area when dragging. Otherwise (SDL 2.0.3 and before) testing for SDL_WINDOW_INPUT_FOCUS instead of SDL_WINDOW_MOUSE_FOCUS. -// 2018-01-18: Inputs: Added mapping for ImGuiKey_Insert. -// 2017-08-25: Inputs: MousePos set to -FLT_MAX,-FLT_MAX when mouse is unavailable/missing (instead of -1,-1). -// 2016-10-15: Misc: Added a void* user_data parameter to Clipboard function handlers. - -#include "imgui.h" -#ifndef IMGUI_DISABLE -#include "imgui_impl_sdl2.h" - -// Clang warnings with -Weverything -#if defined(__clang__) -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wimplicit-int-float-conversion" // warning: implicit conversion from 'xxx' to 'float' may lose precision -#endif - -// SDL -// (the multi-viewports feature requires SDL features supported from SDL 2.0.4+. SDL 2.0.5+ is highly recommended) -#include -#include -#ifdef __APPLE__ -#include -#endif -#ifdef __EMSCRIPTEN__ -#include -#endif - -#if SDL_VERSION_ATLEAST(2,0,4) && !defined(__EMSCRIPTEN__) && !defined(__ANDROID__) && !(defined(__APPLE__) && TARGET_OS_IOS) && !defined(__amigaos4__) -#define SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE 1 -#else -#define SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE 0 -#endif -#define SDL_HAS_WINDOW_ALPHA SDL_VERSION_ATLEAST(2,0,5) -#define SDL_HAS_ALWAYS_ON_TOP SDL_VERSION_ATLEAST(2,0,5) -#define SDL_HAS_USABLE_DISPLAY_BOUNDS SDL_VERSION_ATLEAST(2,0,5) -#define SDL_HAS_PER_MONITOR_DPI SDL_VERSION_ATLEAST(2,0,4) -#define SDL_HAS_VULKAN SDL_VERSION_ATLEAST(2,0,6) -#define SDL_HAS_DISPLAY_EVENT SDL_VERSION_ATLEAST(2,0,9) -#define SDL_HAS_SHOW_WINDOW_ACTIVATION_HINT SDL_VERSION_ATLEAST(2,0,18) -#if SDL_HAS_VULKAN -#include -#else -static const Uint32 SDL_WINDOW_VULKAN = 0x10000000; -#endif - -// SDL Data -struct ImGui_ImplSDL2_Data -{ - SDL_Window* Window; - Uint32 WindowID; - SDL_Renderer* Renderer; - Uint64 Time; - char* ClipboardTextData; - bool UseVulkan; - bool WantUpdateMonitors; - - // Mouse handling - Uint32 MouseWindowID; - int MouseButtonsDown; - SDL_Cursor* MouseCursors[ImGuiMouseCursor_COUNT]; - SDL_Cursor* MouseLastCursor; - int MouseLastLeaveFrame; - bool MouseCanUseGlobalState; - bool MouseCanReportHoveredViewport; // This is hard to use/unreliable on SDL so we'll set ImGuiBackendFlags_HasMouseHoveredViewport dynamically based on state. - - // Gamepad handling - ImVector Gamepads; - ImGui_ImplSDL2_GamepadMode GamepadMode; - bool WantUpdateGamepadsList; - - ImGui_ImplSDL2_Data() { memset((void*)this, 0, sizeof(*this)); } -}; - -// 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_GetBackendData() -{ - return ImGui::GetCurrentContext() ? (ImGui_ImplSDL2_Data*)ImGui::GetIO().BackendPlatformUserData : nullptr; -} - -// Forward Declarations -static void ImGui_ImplSDL2_UpdateMonitors(); -static void ImGui_ImplSDL2_InitMultiViewportSupport(SDL_Window* window, void* sdl_gl_context); -static void ImGui_ImplSDL2_ShutdownMultiViewportSupport(); - -// Functions -static const char* ImGui_ImplSDL2_GetClipboardText(ImGuiContext*) -{ - ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData(); - if (bd->ClipboardTextData) - SDL_free(bd->ClipboardTextData); - bd->ClipboardTextData = SDL_GetClipboardText(); - return bd->ClipboardTextData; -} - -static void ImGui_ImplSDL2_SetClipboardText(ImGuiContext*, const char* text) -{ - SDL_SetClipboardText(text); -} - -// Note: native IME will only display if user calls SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1") _before_ SDL_CreateWindow(). -static void ImGui_ImplSDL2_PlatformSetImeData(ImGuiContext*, ImGuiViewport* viewport, ImGuiPlatformImeData* data) -{ - if (data->WantVisible) - { - SDL_Rect r; - r.x = (int)(data->InputPos.x - viewport->Pos.x); - r.y = (int)(data->InputPos.y - viewport->Pos.y + data->InputLineHeight); - r.w = 1; - r.h = (int)data->InputLineHeight; - SDL_SetTextInputRect(&r); - } -} - -// Not static to allow third-party code to use that if they want to (but undocumented) -ImGuiKey ImGui_ImplSDL2_KeyEventToImGuiKey(SDL_Keycode keycode, SDL_Scancode scancode); -ImGuiKey ImGui_ImplSDL2_KeyEventToImGuiKey(SDL_Keycode keycode, SDL_Scancode scancode) -{ - IM_UNUSED(scancode); - switch (keycode) - { - case SDLK_TAB: return ImGuiKey_Tab; - case SDLK_LEFT: return ImGuiKey_LeftArrow; - case SDLK_RIGHT: return ImGuiKey_RightArrow; - case SDLK_UP: return ImGuiKey_UpArrow; - case SDLK_DOWN: return ImGuiKey_DownArrow; - case SDLK_PAGEUP: return ImGuiKey_PageUp; - case SDLK_PAGEDOWN: return ImGuiKey_PageDown; - case SDLK_HOME: return ImGuiKey_Home; - case SDLK_END: return ImGuiKey_End; - case SDLK_INSERT: return ImGuiKey_Insert; - case SDLK_DELETE: return ImGuiKey_Delete; - case SDLK_BACKSPACE: return ImGuiKey_Backspace; - case SDLK_SPACE: return ImGuiKey_Space; - case SDLK_RETURN: return ImGuiKey_Enter; - case SDLK_ESCAPE: return ImGuiKey_Escape; - case SDLK_QUOTE: return ImGuiKey_Apostrophe; - case SDLK_COMMA: return ImGuiKey_Comma; - case SDLK_MINUS: return ImGuiKey_Minus; - case SDLK_PERIOD: return ImGuiKey_Period; - case SDLK_SLASH: return ImGuiKey_Slash; - case SDLK_SEMICOLON: return ImGuiKey_Semicolon; - case SDLK_EQUALS: return ImGuiKey_Equal; - case SDLK_LEFTBRACKET: return ImGuiKey_LeftBracket; - case SDLK_BACKSLASH: return ImGuiKey_Backslash; - case SDLK_RIGHTBRACKET: return ImGuiKey_RightBracket; - case SDLK_BACKQUOTE: return ImGuiKey_GraveAccent; - case SDLK_CAPSLOCK: return ImGuiKey_CapsLock; - case SDLK_SCROLLLOCK: return ImGuiKey_ScrollLock; - case SDLK_NUMLOCKCLEAR: return ImGuiKey_NumLock; - case SDLK_PRINTSCREEN: return ImGuiKey_PrintScreen; - case SDLK_PAUSE: return ImGuiKey_Pause; - case SDLK_KP_0: return ImGuiKey_Keypad0; - case SDLK_KP_1: return ImGuiKey_Keypad1; - case SDLK_KP_2: return ImGuiKey_Keypad2; - case SDLK_KP_3: return ImGuiKey_Keypad3; - case SDLK_KP_4: return ImGuiKey_Keypad4; - case SDLK_KP_5: return ImGuiKey_Keypad5; - case SDLK_KP_6: return ImGuiKey_Keypad6; - case SDLK_KP_7: return ImGuiKey_Keypad7; - case SDLK_KP_8: return ImGuiKey_Keypad8; - case SDLK_KP_9: return ImGuiKey_Keypad9; - case SDLK_KP_PERIOD: return ImGuiKey_KeypadDecimal; - case SDLK_KP_DIVIDE: return ImGuiKey_KeypadDivide; - case SDLK_KP_MULTIPLY: return ImGuiKey_KeypadMultiply; - case SDLK_KP_MINUS: return ImGuiKey_KeypadSubtract; - case SDLK_KP_PLUS: return ImGuiKey_KeypadAdd; - case SDLK_KP_ENTER: return ImGuiKey_KeypadEnter; - case SDLK_KP_EQUALS: return ImGuiKey_KeypadEqual; - case SDLK_LCTRL: return ImGuiKey_LeftCtrl; - case SDLK_LSHIFT: return ImGuiKey_LeftShift; - case SDLK_LALT: return ImGuiKey_LeftAlt; - case SDLK_LGUI: return ImGuiKey_LeftSuper; - case SDLK_RCTRL: return ImGuiKey_RightCtrl; - case SDLK_RSHIFT: return ImGuiKey_RightShift; - case SDLK_RALT: return ImGuiKey_RightAlt; - case SDLK_RGUI: return ImGuiKey_RightSuper; - case SDLK_APPLICATION: return ImGuiKey_Menu; - case SDLK_0: return ImGuiKey_0; - case SDLK_1: return ImGuiKey_1; - case SDLK_2: return ImGuiKey_2; - case SDLK_3: return ImGuiKey_3; - case SDLK_4: return ImGuiKey_4; - case SDLK_5: return ImGuiKey_5; - case SDLK_6: return ImGuiKey_6; - case SDLK_7: return ImGuiKey_7; - case SDLK_8: return ImGuiKey_8; - case SDLK_9: return ImGuiKey_9; - case SDLK_a: return ImGuiKey_A; - case SDLK_b: return ImGuiKey_B; - case SDLK_c: return ImGuiKey_C; - case SDLK_d: return ImGuiKey_D; - case SDLK_e: return ImGuiKey_E; - case SDLK_f: return ImGuiKey_F; - case SDLK_g: return ImGuiKey_G; - case SDLK_h: return ImGuiKey_H; - case SDLK_i: return ImGuiKey_I; - case SDLK_j: return ImGuiKey_J; - case SDLK_k: return ImGuiKey_K; - case SDLK_l: return ImGuiKey_L; - case SDLK_m: return ImGuiKey_M; - case SDLK_n: return ImGuiKey_N; - case SDLK_o: return ImGuiKey_O; - case SDLK_p: return ImGuiKey_P; - case SDLK_q: return ImGuiKey_Q; - case SDLK_r: return ImGuiKey_R; - case SDLK_s: return ImGuiKey_S; - case SDLK_t: return ImGuiKey_T; - case SDLK_u: return ImGuiKey_U; - case SDLK_v: return ImGuiKey_V; - case SDLK_w: return ImGuiKey_W; - case SDLK_x: return ImGuiKey_X; - case SDLK_y: return ImGuiKey_Y; - case SDLK_z: return ImGuiKey_Z; - case SDLK_F1: return ImGuiKey_F1; - case SDLK_F2: return ImGuiKey_F2; - case SDLK_F3: return ImGuiKey_F3; - case SDLK_F4: return ImGuiKey_F4; - case SDLK_F5: return ImGuiKey_F5; - case SDLK_F6: return ImGuiKey_F6; - case SDLK_F7: return ImGuiKey_F7; - case SDLK_F8: return ImGuiKey_F8; - case SDLK_F9: return ImGuiKey_F9; - case SDLK_F10: return ImGuiKey_F10; - case SDLK_F11: return ImGuiKey_F11; - case SDLK_F12: return ImGuiKey_F12; - case SDLK_F13: return ImGuiKey_F13; - case SDLK_F14: return ImGuiKey_F14; - case SDLK_F15: return ImGuiKey_F15; - case SDLK_F16: return ImGuiKey_F16; - case SDLK_F17: return ImGuiKey_F17; - case SDLK_F18: return ImGuiKey_F18; - case SDLK_F19: return ImGuiKey_F19; - case SDLK_F20: return ImGuiKey_F20; - case SDLK_F21: return ImGuiKey_F21; - case SDLK_F22: return ImGuiKey_F22; - case SDLK_F23: return ImGuiKey_F23; - case SDLK_F24: return ImGuiKey_F24; - case SDLK_AC_BACK: return ImGuiKey_AppBack; - case SDLK_AC_FORWARD: return ImGuiKey_AppForward; - default: break; - } - return ImGuiKey_None; -} - -static void ImGui_ImplSDL2_UpdateKeyModifiers(SDL_Keymod sdl_key_mods) -{ - ImGuiIO& io = ImGui::GetIO(); - io.AddKeyEvent(ImGuiMod_Ctrl, (sdl_key_mods & KMOD_CTRL) != 0); - io.AddKeyEvent(ImGuiMod_Shift, (sdl_key_mods & KMOD_SHIFT) != 0); - io.AddKeyEvent(ImGuiMod_Alt, (sdl_key_mods & KMOD_ALT) != 0); - io.AddKeyEvent(ImGuiMod_Super, (sdl_key_mods & KMOD_GUI) != 0); -} - -static ImGuiViewport* ImGui_ImplSDL2_GetViewportForWindowID(Uint32 window_id) -{ - return ImGui::FindViewportByPlatformHandle((void*)(intptr_t)window_id); -} - -// You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs. -// - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application, or clear/overwrite your copy of the mouse data. -// - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application, or clear/overwrite your copy of the keyboard data. -// Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags. -bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event) -{ - ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData(); - IM_ASSERT(bd != nullptr && "Context or backend not initialized! Did you call ImGui_ImplSDL2_Init()?"); - ImGuiIO& io = ImGui::GetIO(); - - switch (event->type) - { - case SDL_MOUSEMOTION: - { - if (ImGui_ImplSDL2_GetViewportForWindowID(event->motion.windowID) == NULL) - return false; - ImVec2 mouse_pos((float)event->motion.x, (float)event->motion.y); - if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) - { - int window_x, window_y; - SDL_GetWindowPosition(SDL_GetWindowFromID(event->motion.windowID), &window_x, &window_y); - mouse_pos.x += window_x; - mouse_pos.y += window_y; - } - io.AddMouseSourceEvent(event->motion.which == SDL_TOUCH_MOUSEID ? ImGuiMouseSource_TouchScreen : ImGuiMouseSource_Mouse); - io.AddMousePosEvent(mouse_pos.x, mouse_pos.y); - return true; - } - case SDL_MOUSEWHEEL: - { - if (ImGui_ImplSDL2_GetViewportForWindowID(event->wheel.windowID) == NULL) - return false; - //IMGUI_DEBUG_LOG("wheel %.2f %.2f, precise %.2f %.2f\n", (float)event->wheel.x, (float)event->wheel.y, event->wheel.preciseX, event->wheel.preciseY); -#if SDL_VERSION_ATLEAST(2,0,18) // If this fails to compile on Emscripten: update to latest Emscripten! - float wheel_x = -event->wheel.preciseX; - float wheel_y = event->wheel.preciseY; -#else - float wheel_x = -(float)event->wheel.x; - float wheel_y = (float)event->wheel.y; -#endif -#if defined(__EMSCRIPTEN__) && !SDL_VERSION_ATLEAST(2,31,0) - wheel_x /= 100.0f; -#endif - io.AddMouseSourceEvent(event->wheel.which == SDL_TOUCH_MOUSEID ? ImGuiMouseSource_TouchScreen : ImGuiMouseSource_Mouse); - io.AddMouseWheelEvent(wheel_x, wheel_y); - return true; - } - case SDL_MOUSEBUTTONDOWN: - case SDL_MOUSEBUTTONUP: - { - if (ImGui_ImplSDL2_GetViewportForWindowID(event->button.windowID) == NULL) - return false; - int mouse_button = -1; - if (event->button.button == SDL_BUTTON_LEFT) { mouse_button = 0; } - if (event->button.button == SDL_BUTTON_RIGHT) { mouse_button = 1; } - if (event->button.button == SDL_BUTTON_MIDDLE) { mouse_button = 2; } - if (event->button.button == SDL_BUTTON_X1) { mouse_button = 3; } - if (event->button.button == SDL_BUTTON_X2) { mouse_button = 4; } - if (mouse_button == -1) - break; - io.AddMouseSourceEvent(event->button.which == SDL_TOUCH_MOUSEID ? ImGuiMouseSource_TouchScreen : ImGuiMouseSource_Mouse); - io.AddMouseButtonEvent(mouse_button, (event->type == SDL_MOUSEBUTTONDOWN)); - bd->MouseButtonsDown = (event->type == SDL_MOUSEBUTTONDOWN) ? (bd->MouseButtonsDown | (1 << mouse_button)) : (bd->MouseButtonsDown & ~(1 << mouse_button)); - return true; - } - case SDL_TEXTINPUT: - { - if (ImGui_ImplSDL2_GetViewportForWindowID(event->text.windowID) == NULL) - return false; - io.AddInputCharactersUTF8(event->text.text); - return true; - } - case SDL_KEYDOWN: - case SDL_KEYUP: - { - if (ImGui_ImplSDL2_GetViewportForWindowID(event->key.windowID) == NULL) - return false; - ImGui_ImplSDL2_UpdateKeyModifiers((SDL_Keymod)event->key.keysym.mod); - ImGuiKey key = ImGui_ImplSDL2_KeyEventToImGuiKey(event->key.keysym.sym, event->key.keysym.scancode); - io.AddKeyEvent(key, (event->type == SDL_KEYDOWN)); - io.SetKeyEventNativeData(key, event->key.keysym.sym, event->key.keysym.scancode, event->key.keysym.scancode); // To support legacy indexing (<1.87 user code). Legacy backend uses SDLK_*** as indices to IsKeyXXX() functions. - return true; - } -#if SDL_HAS_DISPLAY_EVENT - case SDL_DISPLAYEVENT: - { - // 2.0.26 has SDL_DISPLAYEVENT_CONNECTED/SDL_DISPLAYEVENT_DISCONNECTED/SDL_DISPLAYEVENT_ORIENTATION, - // so change of DPI/Scaling are not reflected in this event. (SDL3 has it) - bd->WantUpdateMonitors = true; - return true; - } -#endif - case SDL_WINDOWEVENT: - { - ImGuiViewport* viewport = ImGui_ImplSDL2_GetViewportForWindowID(event->window.windowID); - if (viewport == NULL) - return false; - - // - When capturing mouse, SDL will send a bunch of conflicting LEAVE/ENTER event on every mouse move, but the final ENTER tends to be right. - // - However we won't get a correct LEAVE event for a captured window. - // - In some cases, when detaching a window from main viewport SDL may send SDL_WINDOWEVENT_ENTER one frame too late, - // causing SDL_WINDOWEVENT_LEAVE on previous frame to interrupt drag operation by clear mouse position. This is why - // we delay process the SDL_WINDOWEVENT_LEAVE events by one frame. See issue #5012 for details. - Uint8 window_event = event->window.event; - if (window_event == SDL_WINDOWEVENT_ENTER) - { - bd->MouseWindowID = event->window.windowID; - bd->MouseLastLeaveFrame = 0; - } - if (window_event == SDL_WINDOWEVENT_LEAVE) - bd->MouseLastLeaveFrame = ImGui::GetFrameCount() + 1; - if (window_event == SDL_WINDOWEVENT_FOCUS_GAINED) - io.AddFocusEvent(true); - else if (window_event == SDL_WINDOWEVENT_FOCUS_LOST) - io.AddFocusEvent(false); - else if (window_event == SDL_WINDOWEVENT_CLOSE) - viewport->PlatformRequestClose = true; - else if (window_event == SDL_WINDOWEVENT_MOVED) - viewport->PlatformRequestMove = true; - else if (window_event == SDL_WINDOWEVENT_RESIZED) - viewport->PlatformRequestResize = true; - return true; - } - case SDL_CONTROLLERDEVICEADDED: - case SDL_CONTROLLERDEVICEREMOVED: - { - bd->WantUpdateGamepadsList = true; - return true; - } - } - return false; -} - -#ifdef __EMSCRIPTEN__ -EM_JS(void, ImGui_ImplSDL2_EmscriptenOpenURL, (char const* url), { url = url ? UTF8ToString(url) : null; if (url) window.open(url, '_blank'); }); -#endif - -static bool ImGui_ImplSDL2_Init(SDL_Window* window, SDL_Renderer* renderer, void* sdl_gl_context) -{ - ImGuiIO& io = ImGui::GetIO(); - IMGUI_CHECKVERSION(); - IM_ASSERT(io.BackendPlatformUserData == nullptr && "Already initialized a platform backend!"); - - // Check and store if we are on a SDL backend that supports global mouse position - // ("wayland" and "rpi" don't support it, but we chose to use a white-list instead of a black-list) - bool mouse_can_use_global_state = false; -#if SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE - const char* sdl_backend = SDL_GetCurrentVideoDriver(); - const char* global_mouse_whitelist[] = { "windows", "cocoa", "x11", "DIVE", "VMAN" }; - for (int n = 0; n < IM_ARRAYSIZE(global_mouse_whitelist); n++) - if (strncmp(sdl_backend, global_mouse_whitelist[n], strlen(global_mouse_whitelist[n])) == 0) - mouse_can_use_global_state = true; -#endif - - // Setup backend capabilities flags - ImGui_ImplSDL2_Data* bd = IM_NEW(ImGui_ImplSDL2_Data)(); - io.BackendPlatformUserData = (void*)bd; - io.BackendPlatformName = "imgui_impl_sdl2"; - io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional) - io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used) - if (mouse_can_use_global_state) - io.BackendFlags |= ImGuiBackendFlags_PlatformHasViewports; // We can create multi-viewports on the Platform side (optional) - - bd->Window = window; - bd->WindowID = SDL_GetWindowID(window); - bd->Renderer = renderer; - - // SDL on Linux/OSX doesn't report events for unfocused windows (see https://github.com/ocornut/imgui/issues/4960) - // We will use 'MouseCanReportHoveredViewport' to set 'ImGuiBackendFlags_HasMouseHoveredViewport' dynamically each frame. - bd->MouseCanUseGlobalState = mouse_can_use_global_state; -#ifndef __APPLE__ - bd->MouseCanReportHoveredViewport = bd->MouseCanUseGlobalState; -#else - bd->MouseCanReportHoveredViewport = false; -#endif - - ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); - platform_io.Platform_SetClipboardTextFn = ImGui_ImplSDL2_SetClipboardText; - platform_io.Platform_GetClipboardTextFn = ImGui_ImplSDL2_GetClipboardText; - platform_io.Platform_ClipboardUserData = nullptr; - platform_io.Platform_SetImeDataFn = ImGui_ImplSDL2_PlatformSetImeData; -#ifdef __EMSCRIPTEN__ - platform_io.Platform_OpenInShellFn = [](ImGuiContext*, const char* url) { ImGui_ImplSDL2_EmscriptenOpenURL(url); return true; }; -#endif - - // Update monitor a first time during init - ImGui_ImplSDL2_UpdateMonitors(); - - // Gamepad handling - bd->GamepadMode = ImGui_ImplSDL2_GamepadMode_AutoFirst; - bd->WantUpdateGamepadsList = true; - - // Load mouse cursors - bd->MouseCursors[ImGuiMouseCursor_Arrow] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_ARROW); - bd->MouseCursors[ImGuiMouseCursor_TextInput] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_IBEAM); - bd->MouseCursors[ImGuiMouseCursor_ResizeAll] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEALL); - bd->MouseCursors[ImGuiMouseCursor_ResizeNS] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENS); - bd->MouseCursors[ImGuiMouseCursor_ResizeEW] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEWE); - bd->MouseCursors[ImGuiMouseCursor_ResizeNESW] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENESW); - bd->MouseCursors[ImGuiMouseCursor_ResizeNWSE] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENWSE); - bd->MouseCursors[ImGuiMouseCursor_Hand] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_HAND); - bd->MouseCursors[ImGuiMouseCursor_NotAllowed] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_NO); - - // Set platform dependent data in viewport - // Our mouse update function expect PlatformHandle to be filled for the main viewport - ImGuiViewport* main_viewport = ImGui::GetMainViewport(); - main_viewport->PlatformHandle = (void*)(intptr_t)bd->WindowID; - main_viewport->PlatformHandleRaw = nullptr; - SDL_SysWMinfo info; - SDL_VERSION(&info.version); - if (SDL_GetWindowWMInfo(window, &info)) - { -#if defined(SDL_VIDEO_DRIVER_WINDOWS) - main_viewport->PlatformHandleRaw = (void*)info.info.win.window; -#elif defined(__APPLE__) && defined(SDL_VIDEO_DRIVER_COCOA) - main_viewport->PlatformHandleRaw = (void*)info.info.cocoa.window; -#endif - } - - // From 2.0.5: Set SDL hint to receive mouse click events on window focus, otherwise SDL doesn't emit the event. - // Without this, when clicking to gain focus, our widgets wouldn't activate even though they showed as hovered. - // (This is unfortunately a global SDL setting, so enabling it might have a side-effect on your application. - // It is unlikely to make a difference, but if your app absolutely needs to ignore the initial on-focus click: - // you can ignore SDL_MOUSEBUTTONDOWN events coming right after a SDL_WINDOWEVENT_FOCUS_GAINED) -#ifdef SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH - SDL_SetHint(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, "1"); -#endif - - // From 2.0.18: Enable native IME. - // IMPORTANT: This is used at the time of SDL_CreateWindow() so this will only affects secondary windows, if any. - // For the main window to be affected, your application needs to call this manually before calling SDL_CreateWindow(). -#ifdef SDL_HINT_IME_SHOW_UI - SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1"); -#endif - - // From 2.0.22: Disable auto-capture, this is preventing drag and drop across multiple windows (see #5710) -#ifdef SDL_HINT_MOUSE_AUTO_CAPTURE - SDL_SetHint(SDL_HINT_MOUSE_AUTO_CAPTURE, "0"); -#endif - - // We need SDL_CaptureMouse(), SDL_GetGlobalMouseState() from SDL 2.0.4+ to support multiple viewports. - // We left the call to ImGui_ImplSDL2_InitMultiViewportSupport() outside of #ifdef to avoid unused-function warnings. - if (io.BackendFlags & ImGuiBackendFlags_PlatformHasViewports) - ImGui_ImplSDL2_InitMultiViewportSupport(window, sdl_gl_context); - - return true; -} - -bool ImGui_ImplSDL2_InitForOpenGL(SDL_Window* window, void* sdl_gl_context) -{ - return ImGui_ImplSDL2_Init(window, nullptr, sdl_gl_context); -} - -bool ImGui_ImplSDL2_InitForVulkan(SDL_Window* window) -{ -#if !SDL_HAS_VULKAN - IM_ASSERT(0 && "Unsupported"); -#endif - if (!ImGui_ImplSDL2_Init(window, nullptr, nullptr)) - return false; - ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData(); - bd->UseVulkan = true; - return true; -} - -bool ImGui_ImplSDL2_InitForD3D(SDL_Window* window) -{ -#if !defined(_WIN32) - IM_ASSERT(0 && "Unsupported"); -#endif - return ImGui_ImplSDL2_Init(window, nullptr, nullptr); -} - -bool ImGui_ImplSDL2_InitForMetal(SDL_Window* window) -{ - return ImGui_ImplSDL2_Init(window, nullptr, nullptr); -} - -bool ImGui_ImplSDL2_InitForSDLRenderer(SDL_Window* window, SDL_Renderer* renderer) -{ - return ImGui_ImplSDL2_Init(window, renderer, nullptr); -} - -bool ImGui_ImplSDL2_InitForOther(SDL_Window* window) -{ - return ImGui_ImplSDL2_Init(window, nullptr, nullptr); -} - -static void ImGui_ImplSDL2_CloseGamepads(); - -void ImGui_ImplSDL2_Shutdown() -{ - ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData(); - IM_ASSERT(bd != nullptr && "No platform backend to shutdown, or already shutdown?"); - ImGuiIO& io = ImGui::GetIO(); - - ImGui_ImplSDL2_ShutdownMultiViewportSupport(); - - if (bd->ClipboardTextData) - SDL_free(bd->ClipboardTextData); - for (ImGuiMouseCursor cursor_n = 0; cursor_n < ImGuiMouseCursor_COUNT; cursor_n++) - SDL_FreeCursor(bd->MouseCursors[cursor_n]); - ImGui_ImplSDL2_CloseGamepads(); - - io.BackendPlatformName = nullptr; - io.BackendPlatformUserData = nullptr; - io.BackendFlags &= ~(ImGuiBackendFlags_HasMouseCursors | ImGuiBackendFlags_HasSetMousePos | ImGuiBackendFlags_HasGamepad | ImGuiBackendFlags_PlatformHasViewports | ImGuiBackendFlags_HasMouseHoveredViewport); - IM_DELETE(bd); -} - -// This code is incredibly messy because some of the functions we need for full viewport support are not available in SDL < 2.0.4. -static void ImGui_ImplSDL2_UpdateMouseData() -{ - ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData(); - ImGuiIO& io = ImGui::GetIO(); - - // We forward mouse input when hovered or captured (via SDL_MOUSEMOTION) or when focused (below) -#if SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE - // SDL_CaptureMouse() let the OS know e.g. that our imgui drag outside the SDL window boundaries shouldn't e.g. trigger other operations outside - SDL_CaptureMouse((bd->MouseButtonsDown != 0) ? SDL_TRUE : SDL_FALSE); - SDL_Window* focused_window = SDL_GetKeyboardFocus(); - const bool is_app_focused = (focused_window && (bd->Window == focused_window || ImGui_ImplSDL2_GetViewportForWindowID(SDL_GetWindowID(focused_window)) != NULL)); -#else - SDL_Window* focused_window = bd->Window; - const bool is_app_focused = (SDL_GetWindowFlags(bd->Window) & SDL_WINDOW_INPUT_FOCUS) != 0; // SDL 2.0.3 and non-windowed systems: single-viewport only -#endif - - if (is_app_focused) - { - // (Optional) Set OS mouse position from Dear ImGui if requested (rarely used, only when io.ConfigNavMoveSetMousePos is enabled by user) - if (io.WantSetMousePos) - { -#if SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE - if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) - SDL_WarpMouseGlobal((int)io.MousePos.x, (int)io.MousePos.y); - else -#endif - SDL_WarpMouseInWindow(bd->Window, (int)io.MousePos.x, (int)io.MousePos.y); - } - - // (Optional) Fallback to provide mouse position when focused (SDL_MOUSEMOTION already provides this when hovered or captured) - if (bd->MouseCanUseGlobalState && bd->MouseButtonsDown == 0) - { - // Single-viewport mode: mouse position in client window coordinates (io.MousePos is (0,0) when the mouse is on the upper-left corner of the app window) - // Multi-viewport mode: mouse position in OS absolute coordinates (io.MousePos is (0,0) when the mouse is on the upper-left of the primary monitor) - int mouse_x, mouse_y, window_x, window_y; - SDL_GetGlobalMouseState(&mouse_x, &mouse_y); - if (!(io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)) - { - SDL_GetWindowPosition(focused_window, &window_x, &window_y); - mouse_x -= window_x; - mouse_y -= window_y; - } - io.AddMousePosEvent((float)mouse_x, (float)mouse_y); - } - } - - // (Optional) When using multiple viewports: call io.AddMouseViewportEvent() with the viewport the OS mouse cursor is hovering. - // If ImGuiBackendFlags_HasMouseHoveredViewport is not set by the backend, Dear imGui will ignore this field and infer the information using its flawed heuristic. - // - [!] SDL backend does NOT correctly ignore viewports with the _NoInputs flag. - // Some backend are not able to handle that correctly. If a backend report an hovered viewport that has the _NoInputs flag (e.g. when dragging a window - // for docking, the viewport has the _NoInputs flag in order to allow us to find the viewport under), then Dear ImGui is forced to ignore the value reported - // by the backend, and use its flawed heuristic to guess the viewport behind. - // - [X] SDL backend correctly reports this regardless of another viewport behind focused and dragged from (we need this to find a useful drag and drop target). - if (io.BackendFlags & ImGuiBackendFlags_HasMouseHoveredViewport) - { - ImGuiID mouse_viewport_id = 0; - if (ImGuiViewport* mouse_viewport = ImGui_ImplSDL2_GetViewportForWindowID(bd->MouseWindowID)) - mouse_viewport_id = mouse_viewport->ID; - io.AddMouseViewportEvent(mouse_viewport_id); - } -} - -static void ImGui_ImplSDL2_UpdateMouseCursor() -{ - ImGuiIO& io = ImGui::GetIO(); - if (io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange) - return; - ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData(); - - ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor(); - if (io.MouseDrawCursor || imgui_cursor == ImGuiMouseCursor_None) - { - // Hide OS mouse cursor if imgui is drawing it or if it wants no cursor - SDL_ShowCursor(SDL_FALSE); - } - else - { - // Show OS mouse cursor - SDL_Cursor* expected_cursor = bd->MouseCursors[imgui_cursor] ? bd->MouseCursors[imgui_cursor] : bd->MouseCursors[ImGuiMouseCursor_Arrow]; - if (bd->MouseLastCursor != expected_cursor) - { - SDL_SetCursor(expected_cursor); // SDL function doesn't have an early out (see #6113) - bd->MouseLastCursor = expected_cursor; - } - SDL_ShowCursor(SDL_TRUE); - } -} - -static void ImGui_ImplSDL2_CloseGamepads() -{ - ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData(); - if (bd->GamepadMode != ImGui_ImplSDL2_GamepadMode_Manual) - for (SDL_GameController* gamepad : bd->Gamepads) - SDL_GameControllerClose(gamepad); - bd->Gamepads.resize(0); -} - -void ImGui_ImplSDL2_SetGamepadMode(ImGui_ImplSDL2_GamepadMode mode, struct _SDL_GameController** manual_gamepads_array, int manual_gamepads_count) -{ - ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData(); - ImGui_ImplSDL2_CloseGamepads(); - if (mode == ImGui_ImplSDL2_GamepadMode_Manual) - { - IM_ASSERT(manual_gamepads_array != nullptr && manual_gamepads_count > 0); - for (int n = 0; n < manual_gamepads_count; n++) - bd->Gamepads.push_back(manual_gamepads_array[n]); - } - else - { - IM_ASSERT(manual_gamepads_array == nullptr && manual_gamepads_count <= 0); - bd->WantUpdateGamepadsList = true; - } - bd->GamepadMode = mode; -} - -static void ImGui_ImplSDL2_UpdateGamepadButton(ImGui_ImplSDL2_Data* bd, ImGuiIO& io, ImGuiKey key, SDL_GameControllerButton button_no) -{ - bool merged_value = false; - for (SDL_GameController* gamepad : bd->Gamepads) - merged_value |= SDL_GameControllerGetButton(gamepad, button_no) != 0; - io.AddKeyEvent(key, merged_value); -} - -static inline float Saturate(float v) { return v < 0.0f ? 0.0f : v > 1.0f ? 1.0f : v; } -static void ImGui_ImplSDL2_UpdateGamepadAnalog(ImGui_ImplSDL2_Data* bd, ImGuiIO& io, ImGuiKey key, SDL_GameControllerAxis axis_no, float v0, float v1) -{ - float merged_value = 0.0f; - for (SDL_GameController* gamepad : bd->Gamepads) - { - float vn = Saturate((float)(SDL_GameControllerGetAxis(gamepad, axis_no) - v0) / (float)(v1 - v0)); - if (merged_value < vn) - merged_value = vn; - } - io.AddKeyAnalogEvent(key, merged_value > 0.1f, merged_value); -} - -static void ImGui_ImplSDL2_UpdateGamepads() -{ - ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData(); - ImGuiIO& io = ImGui::GetIO(); - - // Update list of controller(s) to use - if (bd->WantUpdateGamepadsList && bd->GamepadMode != ImGui_ImplSDL2_GamepadMode_Manual) - { - ImGui_ImplSDL2_CloseGamepads(); - int joystick_count = SDL_NumJoysticks(); - for (int n = 0; n < joystick_count; n++) - if (SDL_IsGameController(n)) - if (SDL_GameController* gamepad = SDL_GameControllerOpen(n)) - { - bd->Gamepads.push_back(gamepad); - if (bd->GamepadMode == ImGui_ImplSDL2_GamepadMode_AutoFirst) - break; - } - bd->WantUpdateGamepadsList = false; - } - - // FIXME: Technically feeding gamepad shouldn't depend on this now that they are regular inputs. - if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0) - return; - io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad; - if (bd->Gamepads.Size == 0) - return; - io.BackendFlags |= ImGuiBackendFlags_HasGamepad; - - // Update gamepad inputs - const int thumb_dead_zone = 8000; // SDL_gamecontroller.h suggests using this value. - ImGui_ImplSDL2_UpdateGamepadButton(bd, io, ImGuiKey_GamepadStart, SDL_CONTROLLER_BUTTON_START); - ImGui_ImplSDL2_UpdateGamepadButton(bd, io, ImGuiKey_GamepadBack, SDL_CONTROLLER_BUTTON_BACK); - ImGui_ImplSDL2_UpdateGamepadButton(bd, io, ImGuiKey_GamepadFaceLeft, SDL_CONTROLLER_BUTTON_X); // Xbox X, PS Square - ImGui_ImplSDL2_UpdateGamepadButton(bd, io, ImGuiKey_GamepadFaceRight, SDL_CONTROLLER_BUTTON_B); // Xbox B, PS Circle - ImGui_ImplSDL2_UpdateGamepadButton(bd, io, ImGuiKey_GamepadFaceUp, SDL_CONTROLLER_BUTTON_Y); // Xbox Y, PS Triangle - ImGui_ImplSDL2_UpdateGamepadButton(bd, io, ImGuiKey_GamepadFaceDown, SDL_CONTROLLER_BUTTON_A); // Xbox A, PS Cross - ImGui_ImplSDL2_UpdateGamepadButton(bd, io, ImGuiKey_GamepadDpadLeft, SDL_CONTROLLER_BUTTON_DPAD_LEFT); - ImGui_ImplSDL2_UpdateGamepadButton(bd, io, ImGuiKey_GamepadDpadRight, SDL_CONTROLLER_BUTTON_DPAD_RIGHT); - ImGui_ImplSDL2_UpdateGamepadButton(bd, io, ImGuiKey_GamepadDpadUp, SDL_CONTROLLER_BUTTON_DPAD_UP); - ImGui_ImplSDL2_UpdateGamepadButton(bd, io, ImGuiKey_GamepadDpadDown, SDL_CONTROLLER_BUTTON_DPAD_DOWN); - ImGui_ImplSDL2_UpdateGamepadButton(bd, io, ImGuiKey_GamepadL1, SDL_CONTROLLER_BUTTON_LEFTSHOULDER); - ImGui_ImplSDL2_UpdateGamepadButton(bd, io, ImGuiKey_GamepadR1, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER); - ImGui_ImplSDL2_UpdateGamepadAnalog(bd, io, ImGuiKey_GamepadL2, SDL_CONTROLLER_AXIS_TRIGGERLEFT, 0.0f, 32767); - ImGui_ImplSDL2_UpdateGamepadAnalog(bd, io, ImGuiKey_GamepadR2, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, 0.0f, 32767); - ImGui_ImplSDL2_UpdateGamepadButton(bd, io, ImGuiKey_GamepadL3, SDL_CONTROLLER_BUTTON_LEFTSTICK); - ImGui_ImplSDL2_UpdateGamepadButton(bd, io, ImGuiKey_GamepadR3, SDL_CONTROLLER_BUTTON_RIGHTSTICK); - ImGui_ImplSDL2_UpdateGamepadAnalog(bd, io, ImGuiKey_GamepadLStickLeft, SDL_CONTROLLER_AXIS_LEFTX, -thumb_dead_zone, -32768); - ImGui_ImplSDL2_UpdateGamepadAnalog(bd, io, ImGuiKey_GamepadLStickRight, SDL_CONTROLLER_AXIS_LEFTX, +thumb_dead_zone, +32767); - ImGui_ImplSDL2_UpdateGamepadAnalog(bd, io, ImGuiKey_GamepadLStickUp, SDL_CONTROLLER_AXIS_LEFTY, -thumb_dead_zone, -32768); - ImGui_ImplSDL2_UpdateGamepadAnalog(bd, io, ImGuiKey_GamepadLStickDown, SDL_CONTROLLER_AXIS_LEFTY, +thumb_dead_zone, +32767); - ImGui_ImplSDL2_UpdateGamepadAnalog(bd, io, ImGuiKey_GamepadRStickLeft, SDL_CONTROLLER_AXIS_RIGHTX, -thumb_dead_zone, -32768); - ImGui_ImplSDL2_UpdateGamepadAnalog(bd, io, ImGuiKey_GamepadRStickRight, SDL_CONTROLLER_AXIS_RIGHTX, +thumb_dead_zone, +32767); - ImGui_ImplSDL2_UpdateGamepadAnalog(bd, io, ImGuiKey_GamepadRStickUp, SDL_CONTROLLER_AXIS_RIGHTY, -thumb_dead_zone, -32768); - ImGui_ImplSDL2_UpdateGamepadAnalog(bd, io, ImGuiKey_GamepadRStickDown, SDL_CONTROLLER_AXIS_RIGHTY, +thumb_dead_zone, +32767); -} - -// FIXME: Note that doesn't update with DPI/Scaling change only as SDL2 doesn't have an event for it (SDL3 has). -static void ImGui_ImplSDL2_UpdateMonitors() -{ - ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData(); - ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); - platform_io.Monitors.resize(0); - bd->WantUpdateMonitors = false; - int display_count = SDL_GetNumVideoDisplays(); - for (int n = 0; n < display_count; n++) - { - // Warning: the validity of monitor DPI information on Windows depends on the application DPI awareness settings, which generally needs to be set in the manifest or at runtime. - ImGuiPlatformMonitor monitor; - SDL_Rect r; - SDL_GetDisplayBounds(n, &r); - monitor.MainPos = monitor.WorkPos = ImVec2((float)r.x, (float)r.y); - monitor.MainSize = monitor.WorkSize = ImVec2((float)r.w, (float)r.h); -#if SDL_HAS_USABLE_DISPLAY_BOUNDS - SDL_GetDisplayUsableBounds(n, &r); - monitor.WorkPos = ImVec2((float)r.x, (float)r.y); - monitor.WorkSize = ImVec2((float)r.w, (float)r.h); -#endif -#if SDL_HAS_PER_MONITOR_DPI - // FIXME-VIEWPORT: On MacOS SDL reports actual monitor DPI scale, ignoring OS configuration. We may want to set - // DpiScale to cocoa_window.backingScaleFactor here. - float dpi = 0.0f; - if (!SDL_GetDisplayDPI(n, &dpi, nullptr, nullptr)) - { - if (dpi <= 0.0f) - continue; // Some accessibility applications are declaring virtual monitors with a DPI of 0, see #7902. - monitor.DpiScale = dpi / 96.0f; - } -#endif - monitor.PlatformHandle = (void*)(intptr_t)n; - platform_io.Monitors.push_back(monitor); - } -} - -void ImGui_ImplSDL2_NewFrame() -{ - ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData(); - IM_ASSERT(bd != nullptr && "Context or backend not initialized! Did you call ImGui_ImplSDL2_Init()?"); - ImGuiIO& io = ImGui::GetIO(); - - // Setup display size (every frame to accommodate for window resizing) - int w, h; - int display_w, display_h; - SDL_GetWindowSize(bd->Window, &w, &h); - if (SDL_GetWindowFlags(bd->Window) & SDL_WINDOW_MINIMIZED) - w = h = 0; - if (bd->Renderer != nullptr) - SDL_GetRendererOutputSize(bd->Renderer, &display_w, &display_h); -#if SDL_HAS_VULKAN - else if (SDL_GetWindowFlags(bd->Window) & SDL_WINDOW_VULKAN) - SDL_Vulkan_GetDrawableSize(bd->Window, &display_w, &display_h); -#endif - else - SDL_GL_GetDrawableSize(bd->Window, &display_w, &display_h); - io.DisplaySize = ImVec2((float)w, (float)h); - if (w > 0 && h > 0) - io.DisplayFramebufferScale = ImVec2((float)display_w / w, (float)display_h / h); - - // Update monitors - if (bd->WantUpdateMonitors) - ImGui_ImplSDL2_UpdateMonitors(); - - // Setup time step (we don't use SDL_GetTicks() because it is using millisecond resolution) - // (Accept SDL_GetPerformanceCounter() not returning a monotonically increasing value. Happens in VMs and Emscripten, see #6189, #6114, #3644) - static Uint64 frequency = SDL_GetPerformanceFrequency(); - Uint64 current_time = SDL_GetPerformanceCounter(); - if (current_time <= bd->Time) - current_time = bd->Time + 1; - io.DeltaTime = bd->Time > 0 ? (float)((double)(current_time - bd->Time) / frequency) : (float)(1.0f / 60.0f); - bd->Time = current_time; - - if (bd->MouseLastLeaveFrame && bd->MouseLastLeaveFrame >= ImGui::GetFrameCount() && bd->MouseButtonsDown == 0) - { - bd->MouseWindowID = 0; - bd->MouseLastLeaveFrame = 0; - io.AddMousePosEvent(-FLT_MAX, -FLT_MAX); - } - - // Our io.AddMouseViewportEvent() calls will only be valid when not capturing. - // Technically speaking testing for 'bd->MouseButtonsDown == 0' would be more rigorous, but testing for payload reduces noise and potential side-effects. - if (bd->MouseCanReportHoveredViewport && ImGui::GetDragDropPayload() == nullptr) - io.BackendFlags |= ImGuiBackendFlags_HasMouseHoveredViewport; - else - io.BackendFlags &= ~ImGuiBackendFlags_HasMouseHoveredViewport; - - ImGui_ImplSDL2_UpdateMouseData(); - ImGui_ImplSDL2_UpdateMouseCursor(); - - // Update game controllers (if enabled and available) - ImGui_ImplSDL2_UpdateGamepads(); -} - -//-------------------------------------------------------------------------------------------------------- -// MULTI-VIEWPORT / PLATFORM INTERFACE SUPPORT -// This is an _advanced_ and _optional_ feature, allowing the backend to create and handle multiple viewports simultaneously. -// If you are new to dear imgui or creating a new binding for dear imgui, it is recommended that you completely ignore this section first.. -//-------------------------------------------------------------------------------------------------------- - -// Helper structure we store in the void* RendererUserData field of each ImGuiViewport to easily retrieve our backend data. -struct ImGui_ImplSDL2_ViewportData -{ - SDL_Window* Window; - Uint32 WindowID; - bool WindowOwned; - SDL_GLContext GLContext; - - ImGui_ImplSDL2_ViewportData() { Window = nullptr; WindowID = 0; WindowOwned = false; GLContext = nullptr; } - ~ImGui_ImplSDL2_ViewportData() { IM_ASSERT(Window == nullptr && GLContext == nullptr); } -}; - -static void ImGui_ImplSDL2_CreateWindow(ImGuiViewport* viewport) -{ - ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData(); - ImGui_ImplSDL2_ViewportData* vd = IM_NEW(ImGui_ImplSDL2_ViewportData)(); - viewport->PlatformUserData = vd; - - ImGuiViewport* main_viewport = ImGui::GetMainViewport(); - ImGui_ImplSDL2_ViewportData* main_viewport_data = (ImGui_ImplSDL2_ViewportData*)main_viewport->PlatformUserData; - - // Share GL resources with main context - bool use_opengl = (main_viewport_data->GLContext != nullptr); - SDL_GLContext backup_context = nullptr; - if (use_opengl) - { - backup_context = SDL_GL_GetCurrentContext(); - SDL_GL_SetAttribute(SDL_GL_SHARE_WITH_CURRENT_CONTEXT, 1); - SDL_GL_MakeCurrent(main_viewport_data->Window, main_viewport_data->GLContext); - } - - Uint32 sdl_flags = 0; - sdl_flags |= use_opengl ? SDL_WINDOW_OPENGL : (bd->UseVulkan ? SDL_WINDOW_VULKAN : 0); - sdl_flags |= SDL_GetWindowFlags(bd->Window) & SDL_WINDOW_ALLOW_HIGHDPI; - sdl_flags |= SDL_WINDOW_HIDDEN; - sdl_flags |= (viewport->Flags & ImGuiViewportFlags_NoDecoration) ? SDL_WINDOW_BORDERLESS : 0; - sdl_flags |= (viewport->Flags & ImGuiViewportFlags_NoDecoration) ? 0 : SDL_WINDOW_RESIZABLE; -#if !defined(_WIN32) - // See SDL hack in ImGui_ImplSDL2_ShowWindow(). - sdl_flags |= (viewport->Flags & ImGuiViewportFlags_NoTaskBarIcon) ? SDL_WINDOW_SKIP_TASKBAR : 0; -#endif -#if SDL_HAS_ALWAYS_ON_TOP - sdl_flags |= (viewport->Flags & ImGuiViewportFlags_TopMost) ? SDL_WINDOW_ALWAYS_ON_TOP : 0; -#endif - vd->Window = SDL_CreateWindow("No Title Yet", (int)viewport->Pos.x, (int)viewport->Pos.y, (int)viewport->Size.x, (int)viewport->Size.y, sdl_flags); - vd->WindowOwned = true; - if (use_opengl) - { - vd->GLContext = SDL_GL_CreateContext(vd->Window); - SDL_GL_SetSwapInterval(0); - } - if (use_opengl && backup_context) - SDL_GL_MakeCurrent(vd->Window, backup_context); - - viewport->PlatformHandle = (void*)(intptr_t)SDL_GetWindowID(vd->Window); - viewport->PlatformHandleRaw = nullptr; - SDL_SysWMinfo info; - SDL_VERSION(&info.version); - if (SDL_GetWindowWMInfo(vd->Window, &info)) - { -#if defined(SDL_VIDEO_DRIVER_WINDOWS) - viewport->PlatformHandleRaw = info.info.win.window; -#elif defined(__APPLE__) && defined(SDL_VIDEO_DRIVER_COCOA) - viewport->PlatformHandleRaw = (void*)info.info.cocoa.window; -#endif - } -} - -static void ImGui_ImplSDL2_DestroyWindow(ImGuiViewport* viewport) -{ - if (ImGui_ImplSDL2_ViewportData* vd = (ImGui_ImplSDL2_ViewportData*)viewport->PlatformUserData) - { - if (vd->GLContext && vd->WindowOwned) - SDL_GL_DeleteContext(vd->GLContext); - if (vd->Window && vd->WindowOwned) - SDL_DestroyWindow(vd->Window); - vd->GLContext = nullptr; - vd->Window = nullptr; - IM_DELETE(vd); - } - viewport->PlatformUserData = viewport->PlatformHandle = nullptr; -} - -static void ImGui_ImplSDL2_ShowWindow(ImGuiViewport* viewport) -{ - ImGui_ImplSDL2_ViewportData* vd = (ImGui_ImplSDL2_ViewportData*)viewport->PlatformUserData; -#if defined(_WIN32) && !(defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP || WINAPI_FAMILY == WINAPI_FAMILY_GAMES)) - HWND hwnd = (HWND)viewport->PlatformHandleRaw; - - // SDL hack: Hide icon from task bar - // Note: SDL 2.0.6+ has a SDL_WINDOW_SKIP_TASKBAR flag which is supported under Windows but the way it create the window breaks our seamless transition. - if (viewport->Flags & ImGuiViewportFlags_NoTaskBarIcon) - { - LONG ex_style = ::GetWindowLong(hwnd, GWL_EXSTYLE); - ex_style &= ~WS_EX_APPWINDOW; - ex_style |= WS_EX_TOOLWINDOW; - ::SetWindowLong(hwnd, GWL_EXSTYLE, ex_style); - } -#endif - -#if SDL_HAS_SHOW_WINDOW_ACTIVATION_HINT - SDL_SetHint(SDL_HINT_WINDOW_NO_ACTIVATION_WHEN_SHOWN, (viewport->Flags & ImGuiViewportFlags_NoFocusOnAppearing) ? "1" : "0"); -#elif defined(_WIN32) - // SDL hack: SDL always activate/focus windows :/ - if (viewport->Flags & ImGuiViewportFlags_NoFocusOnAppearing) - { - ::ShowWindow(hwnd, SW_SHOWNA); - return; - } -#endif - SDL_ShowWindow(vd->Window); -} - -static ImVec2 ImGui_ImplSDL2_GetWindowPos(ImGuiViewport* viewport) -{ - ImGui_ImplSDL2_ViewportData* vd = (ImGui_ImplSDL2_ViewportData*)viewport->PlatformUserData; - int x = 0, y = 0; - SDL_GetWindowPosition(vd->Window, &x, &y); - return ImVec2((float)x, (float)y); -} - -static void ImGui_ImplSDL2_SetWindowPos(ImGuiViewport* viewport, ImVec2 pos) -{ - ImGui_ImplSDL2_ViewportData* vd = (ImGui_ImplSDL2_ViewportData*)viewport->PlatformUserData; - SDL_SetWindowPosition(vd->Window, (int)pos.x, (int)pos.y); -} - -static ImVec2 ImGui_ImplSDL2_GetWindowSize(ImGuiViewport* viewport) -{ - ImGui_ImplSDL2_ViewportData* vd = (ImGui_ImplSDL2_ViewportData*)viewport->PlatformUserData; - int w = 0, h = 0; - SDL_GetWindowSize(vd->Window, &w, &h); - return ImVec2((float)w, (float)h); -} - -static void ImGui_ImplSDL2_SetWindowSize(ImGuiViewport* viewport, ImVec2 size) -{ - ImGui_ImplSDL2_ViewportData* vd = (ImGui_ImplSDL2_ViewportData*)viewport->PlatformUserData; - SDL_SetWindowSize(vd->Window, (int)size.x, (int)size.y); -} - -static void ImGui_ImplSDL2_SetWindowTitle(ImGuiViewport* viewport, const char* title) -{ - ImGui_ImplSDL2_ViewportData* vd = (ImGui_ImplSDL2_ViewportData*)viewport->PlatformUserData; - SDL_SetWindowTitle(vd->Window, title); -} - -#if SDL_HAS_WINDOW_ALPHA -static void ImGui_ImplSDL2_SetWindowAlpha(ImGuiViewport* viewport, float alpha) -{ - ImGui_ImplSDL2_ViewportData* vd = (ImGui_ImplSDL2_ViewportData*)viewport->PlatformUserData; - SDL_SetWindowOpacity(vd->Window, alpha); -} -#endif - -static void ImGui_ImplSDL2_SetWindowFocus(ImGuiViewport* viewport) -{ - ImGui_ImplSDL2_ViewportData* vd = (ImGui_ImplSDL2_ViewportData*)viewport->PlatformUserData; - SDL_RaiseWindow(vd->Window); -} - -static bool ImGui_ImplSDL2_GetWindowFocus(ImGuiViewport* viewport) -{ - ImGui_ImplSDL2_ViewportData* vd = (ImGui_ImplSDL2_ViewportData*)viewport->PlatformUserData; - return (SDL_GetWindowFlags(vd->Window) & SDL_WINDOW_INPUT_FOCUS) != 0; -} - -static bool ImGui_ImplSDL2_GetWindowMinimized(ImGuiViewport* viewport) -{ - ImGui_ImplSDL2_ViewportData* vd = (ImGui_ImplSDL2_ViewportData*)viewport->PlatformUserData; - return (SDL_GetWindowFlags(vd->Window) & SDL_WINDOW_MINIMIZED) != 0; -} - -static void ImGui_ImplSDL2_RenderWindow(ImGuiViewport* viewport, void*) -{ - ImGui_ImplSDL2_ViewportData* vd = (ImGui_ImplSDL2_ViewportData*)viewport->PlatformUserData; - if (vd->GLContext) - SDL_GL_MakeCurrent(vd->Window, vd->GLContext); -} - -static void ImGui_ImplSDL2_SwapBuffers(ImGuiViewport* viewport, void*) -{ - ImGui_ImplSDL2_ViewportData* vd = (ImGui_ImplSDL2_ViewportData*)viewport->PlatformUserData; - if (vd->GLContext) - { - SDL_GL_MakeCurrent(vd->Window, vd->GLContext); - SDL_GL_SwapWindow(vd->Window); - } -} - -// Vulkan support (the Vulkan renderer needs to call a platform-side support function to create the surface) -// SDL is graceful enough to _not_ need so we can safely include this. -#if SDL_HAS_VULKAN -#include -static int ImGui_ImplSDL2_CreateVkSurface(ImGuiViewport* viewport, ImU64 vk_instance, const void* vk_allocator, ImU64* out_vk_surface) -{ - ImGui_ImplSDL2_ViewportData* vd = (ImGui_ImplSDL2_ViewportData*)viewport->PlatformUserData; - (void)vk_allocator; - SDL_bool ret = SDL_Vulkan_CreateSurface(vd->Window, (VkInstance)vk_instance, (VkSurfaceKHR*)out_vk_surface); - return ret ? 0 : 1; // ret ? VK_SUCCESS : VK_NOT_READY -} -#endif // SDL_HAS_VULKAN - -static void ImGui_ImplSDL2_InitMultiViewportSupport(SDL_Window* window, void* sdl_gl_context) -{ - // Register platform interface (will be coupled with a renderer interface) - ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); - platform_io.Platform_CreateWindow = ImGui_ImplSDL2_CreateWindow; - platform_io.Platform_DestroyWindow = ImGui_ImplSDL2_DestroyWindow; - platform_io.Platform_ShowWindow = ImGui_ImplSDL2_ShowWindow; - platform_io.Platform_SetWindowPos = ImGui_ImplSDL2_SetWindowPos; - platform_io.Platform_GetWindowPos = ImGui_ImplSDL2_GetWindowPos; - platform_io.Platform_SetWindowSize = ImGui_ImplSDL2_SetWindowSize; - platform_io.Platform_GetWindowSize = ImGui_ImplSDL2_GetWindowSize; - platform_io.Platform_SetWindowFocus = ImGui_ImplSDL2_SetWindowFocus; - platform_io.Platform_GetWindowFocus = ImGui_ImplSDL2_GetWindowFocus; - platform_io.Platform_GetWindowMinimized = ImGui_ImplSDL2_GetWindowMinimized; - platform_io.Platform_SetWindowTitle = ImGui_ImplSDL2_SetWindowTitle; - platform_io.Platform_RenderWindow = ImGui_ImplSDL2_RenderWindow; - platform_io.Platform_SwapBuffers = ImGui_ImplSDL2_SwapBuffers; -#if SDL_HAS_WINDOW_ALPHA - platform_io.Platform_SetWindowAlpha = ImGui_ImplSDL2_SetWindowAlpha; -#endif -#if SDL_HAS_VULKAN - platform_io.Platform_CreateVkSurface = ImGui_ImplSDL2_CreateVkSurface; -#endif - - // Register main window handle (which is owned by the main application, not by us) - // This is mostly for simplicity and consistency, so that our code (e.g. mouse handling etc.) can use same logic for main and secondary viewports. - ImGuiViewport* main_viewport = ImGui::GetMainViewport(); - ImGui_ImplSDL2_ViewportData* vd = IM_NEW(ImGui_ImplSDL2_ViewportData)(); - vd->Window = window; - vd->WindowID = SDL_GetWindowID(window); - vd->WindowOwned = false; - vd->GLContext = sdl_gl_context; - main_viewport->PlatformUserData = vd; - main_viewport->PlatformHandle = (void*)(intptr_t)vd->WindowID; -} - -static void ImGui_ImplSDL2_ShutdownMultiViewportSupport() -{ - ImGui::DestroyPlatformWindows(); -} - -//----------------------------------------------------------------------------- - -#if defined(__clang__) -#pragma clang diagnostic pop -#endif - -#endif // #ifndef IMGUI_DISABLE diff --git a/engine/modules/engine/render/3rdparty/imgui/imgui_impl_sdl2.h b/engine/modules/engine/render/3rdparty/imgui/imgui_impl_sdl2.h deleted file mode 100644 index 1e87200..0000000 --- a/engine/modules/engine/render/3rdparty/imgui/imgui_impl_sdl2.h +++ /dev/null @@ -1,50 +0,0 @@ -// dear imgui: Platform Backend for SDL2 -// This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..) -// (Info: SDL2 is a cross-platform general purpose library for handling windows, inputs, graphics context creation, etc.) - -// Implemented features: -// [X] Platform: Clipboard support. -// [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen. -// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy SDL_SCANCODE_* values are obsolete since 1.87 and not supported since 1.91.5] -// [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. -// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. -// [X] Platform: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'. -// Issues: -// [ ] Platform: Multi-viewport: Minimized windows seems to break mouse wheel events (at least under Windows). -// [ ] Platform: Multi-viewport: ParentViewportID not honored, and so io.ConfigViewportsNoDefaultParent has no effect (minor). -// [x] Platform: Basic IME support. App needs to call 'SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1");' before SDL_CreateWindow()!. - -// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. -// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. -// Learn about Dear ImGui: -// - FAQ https://dearimgui.com/faq -// - Getting Started https://dearimgui.com/getting-started -// - Documentation https://dearimgui.com/docs (same as your local docs/ folder). -// - Introduction, links and more at the top of imgui.cpp - -#pragma once -#include "imgui.h" // IMGUI_IMPL_API -#ifndef IMGUI_DISABLE - -struct SDL_Window; -struct SDL_Renderer; -struct _SDL_GameController; -typedef union SDL_Event SDL_Event; - -// Follow "Getting Started" link and check examples/ folder to learn about using backends! -IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForOpenGL(SDL_Window* window, void* sdl_gl_context); -IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForVulkan(SDL_Window* window); -IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForD3D(SDL_Window* window); -IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForMetal(SDL_Window* window); -IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForSDLRenderer(SDL_Window* window, SDL_Renderer* renderer); -IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForOther(SDL_Window* window); -IMGUI_IMPL_API void ImGui_ImplSDL2_Shutdown(); -IMGUI_IMPL_API void ImGui_ImplSDL2_NewFrame(); -IMGUI_IMPL_API bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event); - -// Gamepad selection automatically starts in AutoFirst mode, picking first available SDL_Gamepad. You may override this. -// When using manual mode, caller is responsible for opening/closing gamepad. -enum ImGui_ImplSDL2_GamepadMode { ImGui_ImplSDL2_GamepadMode_AutoFirst, ImGui_ImplSDL2_GamepadMode_AutoAll, ImGui_ImplSDL2_GamepadMode_Manual }; -IMGUI_IMPL_API void ImGui_ImplSDL2_SetGamepadMode(ImGui_ImplSDL2_GamepadMode mode, struct _SDL_GameController** manual_gamepads_array = NULL, int manual_gamepads_count = -1); - -#endif // #ifndef IMGUI_DISABLE diff --git a/engine/modules/engine/render/impl/editor_system_impl.inl b/engine/modules/engine/render/impl/editor_system_impl.inl deleted file mode 100644 index 1f35e1b..0000000 --- a/engine/modules/engine/render/impl/editor_system_impl.inl +++ /dev/null @@ -1,14 +0,0 @@ -#include "render/editor_system.h" -namespace api { - SINGLETON_DEFINE(EditorSystem) - EditorSystem::EditorSystem() - { - SINGLETON_PTR(); - } - ImTextureID EditorSystem::AddTexture(FrameGraph& graph, TextureDesc& desc, TextureSampler key) - { - ImageViewPtr imageview = graph.ResolveTextureView(desc); - SamplerPtr sampler = graph.ResolveTextureSampler(key); - return AddTexture(imageview, sampler, desc.state); - } -} \ No newline at end of file diff --git a/engine/modules/engine/render/impl/renderapi_impl.inl b/engine/modules/engine/render/impl/renderapi_impl.inl index ee83533..0916c9f 100644 --- a/engine/modules/engine/render/impl/renderapi_impl.inl +++ b/engine/modules/engine/render/impl/renderapi_impl.inl @@ -1,5 +1,5 @@ #include "render/renderapi.h" -#include "render/module.h" +#include "render/render_module.h" namespace api { SINGLETON_DEFINE(RenderAPI) IMPLEMENT_STATIC_MODULE(RENDER_API, RenderModule, render); diff --git a/engine/modules/engine/render/impl/window_impl.inl b/engine/modules/engine/render/impl/window_impl.inl index d493a5e..2861bd9 100644 --- a/engine/modules/engine/render/impl/window_impl.inl +++ b/engine/modules/engine/render/impl/window_impl.inl @@ -1,13 +1,13 @@ #include "render/window.h" namespace api { SINGLETON_DEFINE(Window) - inline Window::Window(CreatePFN createPFN, const Args& args, int width, int height) noexcept : mHeight(height), mWidth(width) + inline Window::Window(const Args& args, int width, int height) noexcept : mHeight(height), mWidth(width) { SINGLETON_PTR(); uint32_t windowFlags = args.windowFlags | SDL_WINDOW_SHOWN; windowFlags |= args.resizeable ? SDL_WINDOW_RESIZABLE : 0; windowFlags |= args.headless ? SDL_WINDOW_HIDDEN : 0; // Even if we're in headless mode, we still need to create a window, otherwise SDL will not poll events. - mPtr = createPFN(args.title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, windowFlags); + mPtr = SDL_CreateWindow(args.title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, windowFlags); } } \ No newline at end of file diff --git a/engine/modules/engine/render/include/render/editor_system.h b/engine/modules/engine/render/include/render/editor_system.h deleted file mode 100644 index 8b149df..0000000 --- a/engine/modules/engine/render/include/render/editor_system.h +++ /dev/null @@ -1,53 +0,0 @@ -#pragma once -#ifdef WITH_EDITOR -#include "graph/frame_graph.h" -#include "module/module_manager.h" -#include -namespace api { - class EditorSystem; - struct RenderEditorContext { - EditorSystem* editor; - uint32_t frame; - uint32_t frameCount; - EditorSystem* operator->() { - return editor; - } - }; - class EditorPanel { - public: - EditorPanel() = default; - ~EditorPanel() = default; - virtual void DrawPanel(FrameGraph& graph, RenderEditorContext& ctx) = 0; - }; - class EditorWindow { - protected: - std::vector mPanels; - public: - EditorWindow() = default; - ~EditorWindow() = default; - virtual void Draw(FrameGraph& graph, RenderEditorContext& ctx) = 0; - template - T* AddPanel(Args&&... args) { - T* ptr = new (GlobalPool()) T(std::forward(args)...); - mPanels.push_back(ptr); - return ptr; - } - }; - class RENDER_API EditorSystem : public ISystem - { - SINGLETON_IMPL(EditorSystem) - protected: - std::vector mWindows; - public: - EditorSystem(); - template - T* AddWindow(Args&&... args) { - T* ptr = new (GlobalPool()) T(std::forward(args)...); - mWindows.push_back(ptr); - return ptr; - } - ImTextureID AddTexture(FrameGraph& graph, TextureDesc& desc, TextureSampler sampler); - virtual ImTextureID AddTexture(ImageViewPtr imageview, SamplerPtr sampler, ResourceState state) = 0; - }; -} -#endif // WITH_EDITOR \ No newline at end of file diff --git a/engine/modules/engine/render/include/render/module.h b/engine/modules/engine/render/include/render/render_module.h similarity index 100% rename from engine/modules/engine/render/include/render/module.h rename to engine/modules/engine/render/include/render/render_module.h diff --git a/engine/modules/engine/render/include/render/window.h b/engine/modules/engine/render/include/render/window.h index 2fd26c5..f0f0d18 100644 --- a/engine/modules/engine/render/include/render/window.h +++ b/engine/modules/engine/render/include/render/window.h @@ -21,7 +21,7 @@ namespace api { } void operator delete(void* p) {} public: - Window(CreatePFN func, const Args& args, int width, int height) noexcept; + Window(const Args& args, int width, int height) noexcept; SDL_Window* GetPtr() { return mPtr; } }; }; \ No newline at end of file diff --git a/engine/modules/engine/render/src/graph/frame_graph.cpp b/engine/modules/engine/render/src/graph/frame_graph.cpp index 639f005..3c350fb 100644 --- a/engine/modules/engine/render/src/graph/frame_graph.cpp +++ b/engine/modules/engine/render/src/graph/frame_graph.cpp @@ -159,8 +159,10 @@ namespace api { if (surface.state == ResourceState::PRESENT) { return; } + ResourceState srcState = surface.state; + surface.state = ResourceState::PRESENT; TextureBarrier barrier{}; - barrier.mSrcState = surface.state; + barrier.mSrcState = srcState; barrier.mDstState = ResourceState::PRESENT; barrier.mTexture = surface; ResourceBarrierDesc desc{}; diff --git a/engine/modules/engine/render/src/module.cpp b/engine/modules/engine/render/src/render_module.cpp similarity index 85% rename from engine/modules/engine/render/src/module.cpp rename to engine/modules/engine/render/src/render_module.cpp index 9d49cac..683808c 100644 --- a/engine/modules/engine/render/src/module.cpp +++ b/engine/modules/engine/render/src/render_module.cpp @@ -1,4 +1,4 @@ -#include "render/module.h" +#include "render/render_module.h" #include "render/asset/ubo.h" #include "zlog.h" namespace api { diff --git a/engine/modules/engine/render/xmake.lua b/engine/modules/engine/render/xmake.lua index b126fa6..f733138 100644 --- a/engine/modules/engine/render/xmake.lua +++ b/engine/modules/engine/render/xmake.lua @@ -3,12 +3,11 @@ static_component("render","engine") files = {"include/render/asset/*.h"} }) add_includedirs("3rdparty", {public = true}) - add_headerfiles("include/**.h", "include/**.inl", "3rdparty/imgui/*.h") - add_files("src/**.cpp", "3rdparty/imgui/*.cpp") + add_headerfiles("include/**.h") + add_files("src/**.cpp") add_deps("asset", "zlib", "core") add_syslinks("user32", {public = true}) add_packages("libsdl","shaderc","spirv-cross", {public = true}) if WITH_EDITOR then add_defines("WITH_EDITOR", {public = true}) - add_packages("imgui",{public = true}) end \ No newline at end of file diff --git a/engine/modules/engine/ui/include/ui/ui_module.h b/engine/modules/engine/ui/include/ui/ui_module.h new file mode 100644 index 0000000..8d80a17 --- /dev/null +++ b/engine/modules/engine/ui/include/ui/ui_module.h @@ -0,0 +1,11 @@ +#pragma once +#include "module/module.h" +namespace api { + class UI_API UIModule : public IStaticModule + { + public: + void OnLoad(int argc, char** argv) override; + void OnUnload() override; + void InitMetaData(void) override {}; + }; +} \ No newline at end of file diff --git a/engine/modules/engine/ui/src/ui_module.cpp b/engine/modules/engine/ui/src/ui_module.cpp new file mode 100644 index 0000000..0fac347 --- /dev/null +++ b/engine/modules/engine/ui/src/ui_module.cpp @@ -0,0 +1,34 @@ +#include "zlog.h" +#include "ui/ui_module.h" +#include "NoesisPCH.h" +namespace api { + void UIModule::OnLoad(int argc, char** argv) + { + Noesis::SetLogHandler([](const char*, uint32_t, uint32_t level, const char*, const char* msg) + { + switch (level) { + case 0: + case 1: + zlog::debug("[NOESIS] {}\n", msg); + break; + case 2: + zlog::info("[NOESIS] {}\n", msg); + break; + case 3: + zlog::warn("[NOESIS] {}\n", msg); + break; + default: + zlog::error("[NOESIS] {}\n", msg); + break; + } + }); + // Sets the active license + Noesis::GUI::SetLicense(NS_LICENSE_NAME, NS_LICENSE_KEY); + // Noesis initialization. This must be the first step before using any NoesisGUI functionality + Noesis::GUI::Init(); + } + void UIModule::OnUnload() + { + + } +} \ No newline at end of file diff --git a/engine/modules/engine/ui/xmake.lua b/engine/modules/engine/ui/xmake.lua new file mode 100644 index 0000000..8b3cd9b --- /dev/null +++ b/engine/modules/engine/ui/xmake.lua @@ -0,0 +1,5 @@ +static_component("ui","engine") + add_headerfiles("include/**.h") + add_files("src/**.cpp") + add_deps("core", "asset", "zlib", "render") + add_packages("noesis", {public = true}) \ No newline at end of file diff --git a/engine/modules/render/vulkan/include/imgui/imgui_impl_vulkan.cpp b/engine/modules/render/vulkan/include/imgui/imgui_impl_vulkan.cpp deleted file mode 100644 index d8b2da2..0000000 --- a/engine/modules/render/vulkan/include/imgui/imgui_impl_vulkan.cpp +++ /dev/null @@ -1,1960 +0,0 @@ -// dear imgui: Renderer Backend for Vulkan -// This needs to be used along with a Platform Backend (e.g. GLFW, SDL, Win32, custom..) - -// Implemented features: -// [x] Renderer: User texture binding. Use 'VkDescriptorSet' as ImTextureID. Read the FAQ about ImTextureID! See https://github.com/ocornut/imgui/pull/914 for discussions. -// [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices. -// [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'. -// [x] Renderer: Multi-viewport / platform windows. With issues (flickering when creating a new viewport). - -// The aim of imgui_impl_vulkan.h/.cpp is to be usable in your engine without any modification. -// IF YOU FEEL YOU NEED TO MAKE ANY CHANGE TO THIS CODE, please share them and your feedback at https://github.com/ocornut/imgui/ - -// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. -// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. -// Learn about Dear ImGui: -// - FAQ https://dearimgui.com/faq -// - Getting Started https://dearimgui.com/getting-started -// - Documentation https://dearimgui.com/docs (same as your local docs/ folder). -// - Introduction, links and more at the top of imgui.cpp - -// Important note to the reader who wish to integrate imgui_impl_vulkan.cpp/.h in their own engine/app. -// - Common ImGui_ImplVulkan_XXX functions and structures are used to interface with imgui_impl_vulkan.cpp/.h. -// You will use those if you want to use this rendering backend in your engine/app. -// - Helper ImGui_ImplVulkanH_XXX functions and structures are only used by this example (main.cpp) and by -// the backend itself (imgui_impl_vulkan.cpp), but should PROBABLY NOT be used by your own engine/app code. -// Read comments in imgui_impl_vulkan.h. - -// CHANGELOG -// (minor and older changes stripped away, please see git history for details) -// 2024-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. -// 2024-11-27: Vulkan: Make user-provided descriptor pool optional. As a convenience, when setting init_info->DescriptorPoolSize the backend will create one itself. (#8172, #4867) -// 2024-10-07: Vulkan: Changed default texture sampler to Clamp instead of Repeat/Wrap. -// 2024-10-07: Vulkan: Expose selected render state in ImGui_ImplVulkan_RenderState, which you can access in 'void* platform_io.Renderer_RenderState' during draw callbacks. -// 2024-10-07: Vulkan: Compiling with '#define ImTextureID=ImU64' is unnecessary now that dear imgui defaults ImTextureID to u64 instead of void*. -// 2024-04-19: Vulkan: Added convenience support for Volk via IMGUI_IMPL_VULKAN_USE_VOLK define (you can also use IMGUI_IMPL_VULKAN_NO_PROTOTYPES + wrap Volk via ImGui_ImplVulkan_LoadFunctions().) -// 2024-02-14: *BREAKING CHANGE*: Moved RenderPass parameter from ImGui_ImplVulkan_Init() function to ImGui_ImplVulkan_InitInfo structure. Not required when using dynamic rendering. -// 2024-02-12: *BREAKING CHANGE*: Dynamic rendering now require filling PipelineRenderingCreateInfo structure. -// 2024-01-19: Vulkan: Fixed vkAcquireNextImageKHR() validation errors in VulkanSDK 1.3.275 by allocating one extra semaphore than in-flight frames. (#7236) -// 2024-01-11: Vulkan: Fixed vkMapMemory() calls unnecessarily using full buffer size (#3957). Fixed MinAllocationSize handing (#7189). -// 2024-01-03: Vulkan: Added MinAllocationSize field in ImGui_ImplVulkan_InitInfo to workaround zealous "best practice" validation layer. (#7189, #4238) -// 2024-01-03: Vulkan: Stopped creating command pools with VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT as we don't reset them. -// 2023-11-29: Vulkan: Fixed mismatching allocator passed to vkCreateCommandPool() vs vkDestroyCommandPool(). (#7075) -// 2023-11-10: *BREAKING CHANGE*: Removed parameter from ImGui_ImplVulkan_CreateFontsTexture(): backend now creates its own command-buffer to upload fonts. -// *BREAKING CHANGE*: Removed ImGui_ImplVulkan_DestroyFontUploadObjects() which is now unnecessary as we create and destroy those objects in the backend. -// ImGui_ImplVulkan_CreateFontsTexture() is automatically called by NewFrame() the first time. -// You can call ImGui_ImplVulkan_CreateFontsTexture() again to recreate the font atlas texture. -// Added ImGui_ImplVulkan_DestroyFontsTexture() but you probably never need to call this. -// 2023-07-04: Vulkan: Added optional support for VK_KHR_dynamic_rendering. User needs to set init_info->UseDynamicRendering = true and init_info->ColorAttachmentFormat. -// 2023-01-02: Vulkan: Fixed sampler passed to ImGui_ImplVulkan_AddTexture() not being honored + removed a bunch of duplicate code. -// 2022-10-11: Using 'nullptr' instead of 'NULL' as per our switch to C++11. -// 2022-10-04: Vulkan: Added experimental ImGui_ImplVulkan_RemoveTexture() for api symmetry. (#914, #5738). -// 2022-01-20: Vulkan: Added support for ImTextureID as VkDescriptorSet. User need to call ImGui_ImplVulkan_AddTexture(). Building for 32-bit targets requires '#define ImTextureID ImU64'. (#914). -// 2021-10-15: Vulkan: Call vkCmdSetScissor() at the end of render a full-viewport to reduce likehood of issues with people using VK_DYNAMIC_STATE_SCISSOR in their app without calling vkCmdSetScissor() explicitly every frame. -// 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX). -// 2021-03-22: Vulkan: Fix mapped memory validation error when buffer sizes are not multiple of VkPhysicalDeviceLimits::nonCoherentAtomSize. -// 2021-02-18: Vulkan: Change blending equation to preserve alpha in output buffer. -// 2021-01-27: Vulkan: Added support for custom function load and IMGUI_IMPL_VULKAN_NO_PROTOTYPES by using ImGui_ImplVulkan_LoadFunctions(). -// 2020-11-11: Vulkan: Added support for specifying which subpass to reference during VkPipeline creation. -// 2020-09-07: Vulkan: Added VkPipeline parameter to ImGui_ImplVulkan_RenderDrawData (default to one passed to ImGui_ImplVulkan_Init). -// 2020-05-04: Vulkan: Fixed crash if initial frame has no vertices. -// 2020-04-26: Vulkan: Fixed edge case where render callbacks wouldn't be called if the ImDrawData didn't have vertices. -// 2019-08-01: Vulkan: Added support for specifying multisample count. Set ImGui_ImplVulkan_InitInfo::MSAASamples to one of the VkSampleCountFlagBits values to use, default is non-multisampled as before. -// 2019-05-29: Vulkan: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag. -// 2019-04-30: Vulkan: Added support for special ImDrawCallback_ResetRenderState callback to reset render state. -// 2019-04-04: *BREAKING CHANGE*: Vulkan: Added ImageCount/MinImageCount fields in ImGui_ImplVulkan_InitInfo, required for initialization (was previously a hard #define IMGUI_VK_QUEUED_FRAMES 2). Added ImGui_ImplVulkan_SetMinImageCount(). -// 2019-04-04: Vulkan: Added VkInstance argument to ImGui_ImplVulkanH_CreateWindow() optional helper. -// 2019-04-04: Vulkan: Avoid passing negative coordinates to vkCmdSetScissor, which debug validation layers do not like. -// 2019-04-01: Vulkan: Support for 32-bit index buffer (#define ImDrawIdx unsigned int). -// 2019-02-16: Vulkan: Viewport and clipping rectangles correctly using draw_data->FramebufferScale to allow retina display. -// 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window. -// 2018-08-25: Vulkan: Fixed mishandled VkSurfaceCapabilitiesKHR::maxImageCount=0 case. -// 2018-06-22: Inverted the parameters to ImGui_ImplVulkan_RenderDrawData() to be consistent with other backends. -// 2018-06-08: Misc: Extracted imgui_impl_vulkan.cpp/.h away from the old combined GLFW+Vulkan example. -// 2018-06-08: Vulkan: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle. -// 2018-03-03: Vulkan: Various refactor, created a couple of ImGui_ImplVulkanH_XXX helper that the example can use and that viewport support will use. -// 2018-03-01: Vulkan: Renamed ImGui_ImplVulkan_Init_Info to ImGui_ImplVulkan_InitInfo and fields to match more closely Vulkan terminology. -// 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback, ImGui_ImplVulkan_Render() calls ImGui_ImplVulkan_RenderDrawData() itself. -// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves. -// 2017-05-15: Vulkan: Fix scissor offset being negative. Fix new Vulkan validation warnings. Set required depth member for buffer image copy. -// 2016-11-13: Vulkan: Fix validation layer warnings and errors and redeclare gl_PerVertex. -// 2016-10-18: Vulkan: Add location decorators & change to use structs as in/out in glsl, update embedded spv (produced with glslangValidator -x). Null the released resources. -// 2016-08-27: Vulkan: Fix Vulkan example for use when a depth buffer is active. -#include "volk/volk.h" -#include "imgui.h" -#ifndef IMGUI_DISABLE -#include "imgui_impl_vulkan.h" -#include -#ifndef IM_MAX -#define IM_MAX(A, B) (((A) >= (B)) ? (A) : (B)) -#endif - -// Visual Studio warnings -#ifdef _MSC_VER -#pragma warning (disable: 4127) // condition expression is constant -#endif - -// Forward Declarations -struct ImGui_ImplVulkan_FrameRenderBuffers; -struct ImGui_ImplVulkan_WindowRenderBuffers; -bool ImGui_ImplVulkan_CreateDeviceObjects(); -void ImGui_ImplVulkan_DestroyDeviceObjects(); -void ImGui_ImplVulkan_DestroyFrameRenderBuffers(VkDevice device, ImGui_ImplVulkan_FrameRenderBuffers* buffers, const VkAllocationCallbacks* allocator); -void ImGui_ImplVulkan_DestroyWindowRenderBuffers(VkDevice device, ImGui_ImplVulkan_WindowRenderBuffers* buffers, const VkAllocationCallbacks* allocator); -void ImGui_ImplVulkanH_DestroyFrame(VkDevice device, ImGui_ImplVulkanH_Frame* fd, const VkAllocationCallbacks* allocator); -void ImGui_ImplVulkanH_DestroyFrameSemaphores(VkDevice device, ImGui_ImplVulkanH_FrameSemaphores* fsd, const VkAllocationCallbacks* allocator); -void ImGui_ImplVulkanH_DestroyAllViewportsRenderBuffers(VkDevice device, const VkAllocationCallbacks* allocator); -void ImGui_ImplVulkanH_CreateWindowSwapChain(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, const VkAllocationCallbacks* allocator, int w, int h, uint32_t min_image_count); -void ImGui_ImplVulkanH_CreateWindowCommandBuffers(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, uint32_t queue_family, const VkAllocationCallbacks* allocator); - -// Vulkan prototypes for use with custom loaders -// (see description of IMGUI_IMPL_VULKAN_NO_PROTOTYPES in imgui_impl_vulkan.h -#if defined(VK_NO_PROTOTYPES) && !defined(VOLK_H_) -#define IMGUI_IMPL_VULKAN_USE_LOADER -static bool g_FunctionsLoaded = false; -#else -static bool g_FunctionsLoaded = true; -#endif -#ifdef IMGUI_IMPL_VULKAN_USE_LOADER -#define IMGUI_VULKAN_FUNC_MAP(IMGUI_VULKAN_FUNC_MAP_MACRO) \ - IMGUI_VULKAN_FUNC_MAP_MACRO(vkAllocateCommandBuffers) \ - IMGUI_VULKAN_FUNC_MAP_MACRO(vkAllocateDescriptorSets) \ - IMGUI_VULKAN_FUNC_MAP_MACRO(vkAllocateMemory) \ - IMGUI_VULKAN_FUNC_MAP_MACRO(vkAcquireNextImageKHR) \ - IMGUI_VULKAN_FUNC_MAP_MACRO(vkBeginCommandBuffer) \ - IMGUI_VULKAN_FUNC_MAP_MACRO(vkBindBufferMemory) \ - IMGUI_VULKAN_FUNC_MAP_MACRO(vkBindImageMemory) \ - IMGUI_VULKAN_FUNC_MAP_MACRO(vkCmdBeginRenderPass) \ - IMGUI_VULKAN_FUNC_MAP_MACRO(vkCmdBindDescriptorSets) \ - IMGUI_VULKAN_FUNC_MAP_MACRO(vkCmdBindIndexBuffer) \ - IMGUI_VULKAN_FUNC_MAP_MACRO(vkCmdBindPipeline) \ - IMGUI_VULKAN_FUNC_MAP_MACRO(vkCmdBindVertexBuffers) \ - IMGUI_VULKAN_FUNC_MAP_MACRO(vkCmdCopyBufferToImage) \ - IMGUI_VULKAN_FUNC_MAP_MACRO(vkCmdDrawIndexed) \ - IMGUI_VULKAN_FUNC_MAP_MACRO(vkCmdEndRenderPass) \ - IMGUI_VULKAN_FUNC_MAP_MACRO(vkCmdPipelineBarrier) \ - IMGUI_VULKAN_FUNC_MAP_MACRO(vkCmdPushConstants) \ - IMGUI_VULKAN_FUNC_MAP_MACRO(vkCmdSetScissor) \ - IMGUI_VULKAN_FUNC_MAP_MACRO(vkCmdSetViewport) \ - IMGUI_VULKAN_FUNC_MAP_MACRO(vkCreateBuffer) \ - IMGUI_VULKAN_FUNC_MAP_MACRO(vkCreateCommandPool) \ - IMGUI_VULKAN_FUNC_MAP_MACRO(vkCreateDescriptorPool) \ - IMGUI_VULKAN_FUNC_MAP_MACRO(vkCreateDescriptorSetLayout) \ - IMGUI_VULKAN_FUNC_MAP_MACRO(vkCreateFence) \ - IMGUI_VULKAN_FUNC_MAP_MACRO(vkCreateFramebuffer) \ - IMGUI_VULKAN_FUNC_MAP_MACRO(vkCreateGraphicsPipelines) \ - IMGUI_VULKAN_FUNC_MAP_MACRO(vkCreateImage) \ - IMGUI_VULKAN_FUNC_MAP_MACRO(vkCreateImageView) \ - IMGUI_VULKAN_FUNC_MAP_MACRO(vkCreatePipelineLayout) \ - IMGUI_VULKAN_FUNC_MAP_MACRO(vkCreateRenderPass) \ - IMGUI_VULKAN_FUNC_MAP_MACRO(vkCreateSampler) \ - IMGUI_VULKAN_FUNC_MAP_MACRO(vkCreateSemaphore) \ - IMGUI_VULKAN_FUNC_MAP_MACRO(vkCreateShaderModule) \ - IMGUI_VULKAN_FUNC_MAP_MACRO(vkCreateSwapchainKHR) \ - IMGUI_VULKAN_FUNC_MAP_MACRO(vkDestroyBuffer) \ - IMGUI_VULKAN_FUNC_MAP_MACRO(vkDestroyCommandPool) \ - IMGUI_VULKAN_FUNC_MAP_MACRO(vkDestroyDescriptorPool) \ - IMGUI_VULKAN_FUNC_MAP_MACRO(vkDestroyDescriptorSetLayout) \ - IMGUI_VULKAN_FUNC_MAP_MACRO(vkDestroyFence) \ - IMGUI_VULKAN_FUNC_MAP_MACRO(vkDestroyFramebuffer) \ - IMGUI_VULKAN_FUNC_MAP_MACRO(vkDestroyImage) \ - IMGUI_VULKAN_FUNC_MAP_MACRO(vkDestroyImageView) \ - IMGUI_VULKAN_FUNC_MAP_MACRO(vkDestroyPipeline) \ - IMGUI_VULKAN_FUNC_MAP_MACRO(vkDestroyPipelineLayout) \ - IMGUI_VULKAN_FUNC_MAP_MACRO(vkDestroyRenderPass) \ - IMGUI_VULKAN_FUNC_MAP_MACRO(vkDestroySampler) \ - IMGUI_VULKAN_FUNC_MAP_MACRO(vkDestroySemaphore) \ - IMGUI_VULKAN_FUNC_MAP_MACRO(vkDestroyShaderModule) \ - IMGUI_VULKAN_FUNC_MAP_MACRO(vkDestroySurfaceKHR) \ - IMGUI_VULKAN_FUNC_MAP_MACRO(vkDestroySwapchainKHR) \ - IMGUI_VULKAN_FUNC_MAP_MACRO(vkDeviceWaitIdle) \ - IMGUI_VULKAN_FUNC_MAP_MACRO(vkEndCommandBuffer) \ - IMGUI_VULKAN_FUNC_MAP_MACRO(vkFlushMappedMemoryRanges) \ - IMGUI_VULKAN_FUNC_MAP_MACRO(vkFreeCommandBuffers) \ - IMGUI_VULKAN_FUNC_MAP_MACRO(vkFreeDescriptorSets) \ - IMGUI_VULKAN_FUNC_MAP_MACRO(vkFreeMemory) \ - IMGUI_VULKAN_FUNC_MAP_MACRO(vkGetBufferMemoryRequirements) \ - IMGUI_VULKAN_FUNC_MAP_MACRO(vkGetImageMemoryRequirements) \ - IMGUI_VULKAN_FUNC_MAP_MACRO(vkGetPhysicalDeviceMemoryProperties) \ - IMGUI_VULKAN_FUNC_MAP_MACRO(vkGetPhysicalDeviceSurfaceCapabilitiesKHR) \ - IMGUI_VULKAN_FUNC_MAP_MACRO(vkGetPhysicalDeviceSurfaceFormatsKHR) \ - IMGUI_VULKAN_FUNC_MAP_MACRO(vkGetPhysicalDeviceSurfacePresentModesKHR) \ - IMGUI_VULKAN_FUNC_MAP_MACRO(vkGetPhysicalDeviceSurfaceSupportKHR) \ - IMGUI_VULKAN_FUNC_MAP_MACRO(vkGetSwapchainImagesKHR) \ - IMGUI_VULKAN_FUNC_MAP_MACRO(vkMapMemory) \ - IMGUI_VULKAN_FUNC_MAP_MACRO(vkQueuePresentKHR) \ - IMGUI_VULKAN_FUNC_MAP_MACRO(vkQueueSubmit) \ - IMGUI_VULKAN_FUNC_MAP_MACRO(vkQueueWaitIdle) \ - IMGUI_VULKAN_FUNC_MAP_MACRO(vkResetCommandPool) \ - IMGUI_VULKAN_FUNC_MAP_MACRO(vkResetFences) \ - IMGUI_VULKAN_FUNC_MAP_MACRO(vkUnmapMemory) \ - IMGUI_VULKAN_FUNC_MAP_MACRO(vkUpdateDescriptorSets) \ - IMGUI_VULKAN_FUNC_MAP_MACRO(vkWaitForFences) - -// Define function pointers -#define IMGUI_VULKAN_FUNC_DEF(func) static PFN_##func func; -IMGUI_VULKAN_FUNC_MAP(IMGUI_VULKAN_FUNC_DEF) -#undef IMGUI_VULKAN_FUNC_DEF -#endif // IMGUI_IMPL_VULKAN_USE_LOADER - -#ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING -static PFN_vkCmdBeginRenderingKHR ImGuiImplVulkanFuncs_vkCmdBeginRenderingKHR; -static PFN_vkCmdEndRenderingKHR ImGuiImplVulkanFuncs_vkCmdEndRenderingKHR; -#endif - -// Reusable buffers used for rendering 1 current in-flight frame, for ImGui_ImplVulkan_RenderDrawData() -// [Please zero-clear before use!] -struct ImGui_ImplVulkan_FrameRenderBuffers -{ - VkDeviceMemory VertexBufferMemory; - VkDeviceMemory IndexBufferMemory; - VkDeviceSize VertexBufferSize; - VkDeviceSize IndexBufferSize; - VkBuffer VertexBuffer; - VkBuffer IndexBuffer; -}; - -// Each viewport will hold 1 ImGui_ImplVulkanH_WindowRenderBuffers -// [Please zero-clear before use!] -struct ImGui_ImplVulkan_WindowRenderBuffers -{ - uint32_t Index; - uint32_t Count; - ImGui_ImplVulkan_FrameRenderBuffers* FrameRenderBuffers; -}; - -struct ImGui_ImplVulkan_Texture -{ - VkDeviceMemory Memory; - VkImage Image; - VkImageView ImageView; - VkDescriptorSet DescriptorSet; - - ImGui_ImplVulkan_Texture() { memset(this, 0, sizeof(*this)); } -}; - -// For multi-viewport support: -// Helper structure we store in the void* RendererUserData field of each ImGuiViewport to easily retrieve our backend data. -struct ImGui_ImplVulkan_ViewportData -{ - ImGui_ImplVulkanH_Window Window; // Used by secondary viewports only - ImGui_ImplVulkan_WindowRenderBuffers RenderBuffers; // Used by all viewports - bool WindowOwned; - bool SwapChainNeedRebuild; // Flag when viewport swapchain resized in the middle of processing a frame - - ImGui_ImplVulkan_ViewportData() { WindowOwned = SwapChainNeedRebuild = false; memset(&RenderBuffers, 0, sizeof(RenderBuffers)); } - ~ImGui_ImplVulkan_ViewportData() { } -}; - -// Vulkan data -struct ImGui_ImplVulkan_Data -{ - ImGui_ImplVulkan_InitInfo VulkanInitInfo; - VkDeviceSize BufferMemoryAlignment; - VkPipelineCreateFlags PipelineCreateFlags; - VkDescriptorSetLayout DescriptorSetLayout; - VkPipelineLayout PipelineLayout; - VkPipeline Pipeline; // pipeline for main render pass (created by app) - VkPipeline PipelineForViewports; // pipeline for secondary viewports (created by backend) - VkShaderModule ShaderModuleVert; - VkShaderModule ShaderModuleFrag; - VkDescriptorPool DescriptorPool; - - // Texture management - ImGui_ImplVulkan_Texture FontTexture; - VkSampler TexSampler; - VkCommandPool TexCommandPool; - VkCommandBuffer TexCommandBuffer; - - // Render buffers for main window - ImGui_ImplVulkan_WindowRenderBuffers MainWindowRenderBuffers; - - ImGui_ImplVulkan_Data() - { - memset((void*)this, 0, sizeof(*this)); - BufferMemoryAlignment = 256; - } -}; - -//----------------------------------------------------------------------------- -// SHADERS -//----------------------------------------------------------------------------- - -// Forward Declarations -static void ImGui_ImplVulkan_InitMultiViewportSupport(); -static void ImGui_ImplVulkan_ShutdownMultiViewportSupport(); - -// backends/vulkan/glsl_shader.vert, compiled with: -// # glslangValidator -V -x -o glsl_shader.vert.u32 glsl_shader.vert -/* -#version 450 core -layout(location = 0) in vec2 aPos; -layout(location = 1) in vec2 aUV; -layout(location = 2) in vec4 aColor; -layout(push_constant) uniform uPushConstant { vec2 uScale; vec2 uTranslate; } pc; - -out gl_PerVertex { vec4 gl_Position; }; -layout(location = 0) out struct { vec4 Color; vec2 UV; } Out; - -void main() -{ - Out.Color = aColor; - Out.UV = aUV; - gl_Position = vec4(aPos * pc.uScale + pc.uTranslate, 0, 1); -} -*/ -static uint32_t __glsl_shader_vert_spv[] = -{ - 0x07230203,0x00010000,0x00080001,0x0000002e,0x00000000,0x00020011,0x00000001,0x0006000b, - 0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,0x00000000,0x00000001, - 0x000a000f,0x00000000,0x00000004,0x6e69616d,0x00000000,0x0000000b,0x0000000f,0x00000015, - 0x0000001b,0x0000001c,0x00030003,0x00000002,0x000001c2,0x00040005,0x00000004,0x6e69616d, - 0x00000000,0x00030005,0x00000009,0x00000000,0x00050006,0x00000009,0x00000000,0x6f6c6f43, - 0x00000072,0x00040006,0x00000009,0x00000001,0x00005655,0x00030005,0x0000000b,0x0074754f, - 0x00040005,0x0000000f,0x6c6f4361,0x0000726f,0x00030005,0x00000015,0x00565561,0x00060005, - 0x00000019,0x505f6c67,0x65567265,0x78657472,0x00000000,0x00060006,0x00000019,0x00000000, - 0x505f6c67,0x7469736f,0x006e6f69,0x00030005,0x0000001b,0x00000000,0x00040005,0x0000001c, - 0x736f5061,0x00000000,0x00060005,0x0000001e,0x73755075,0x6e6f4368,0x6e617473,0x00000074, - 0x00050006,0x0000001e,0x00000000,0x61635375,0x0000656c,0x00060006,0x0000001e,0x00000001, - 0x61725475,0x616c736e,0x00006574,0x00030005,0x00000020,0x00006370,0x00040047,0x0000000b, - 0x0000001e,0x00000000,0x00040047,0x0000000f,0x0000001e,0x00000002,0x00040047,0x00000015, - 0x0000001e,0x00000001,0x00050048,0x00000019,0x00000000,0x0000000b,0x00000000,0x00030047, - 0x00000019,0x00000002,0x00040047,0x0000001c,0x0000001e,0x00000000,0x00050048,0x0000001e, - 0x00000000,0x00000023,0x00000000,0x00050048,0x0000001e,0x00000001,0x00000023,0x00000008, - 0x00030047,0x0000001e,0x00000002,0x00020013,0x00000002,0x00030021,0x00000003,0x00000002, - 0x00030016,0x00000006,0x00000020,0x00040017,0x00000007,0x00000006,0x00000004,0x00040017, - 0x00000008,0x00000006,0x00000002,0x0004001e,0x00000009,0x00000007,0x00000008,0x00040020, - 0x0000000a,0x00000003,0x00000009,0x0004003b,0x0000000a,0x0000000b,0x00000003,0x00040015, - 0x0000000c,0x00000020,0x00000001,0x0004002b,0x0000000c,0x0000000d,0x00000000,0x00040020, - 0x0000000e,0x00000001,0x00000007,0x0004003b,0x0000000e,0x0000000f,0x00000001,0x00040020, - 0x00000011,0x00000003,0x00000007,0x0004002b,0x0000000c,0x00000013,0x00000001,0x00040020, - 0x00000014,0x00000001,0x00000008,0x0004003b,0x00000014,0x00000015,0x00000001,0x00040020, - 0x00000017,0x00000003,0x00000008,0x0003001e,0x00000019,0x00000007,0x00040020,0x0000001a, - 0x00000003,0x00000019,0x0004003b,0x0000001a,0x0000001b,0x00000003,0x0004003b,0x00000014, - 0x0000001c,0x00000001,0x0004001e,0x0000001e,0x00000008,0x00000008,0x00040020,0x0000001f, - 0x00000009,0x0000001e,0x0004003b,0x0000001f,0x00000020,0x00000009,0x00040020,0x00000021, - 0x00000009,0x00000008,0x0004002b,0x00000006,0x00000028,0x00000000,0x0004002b,0x00000006, - 0x00000029,0x3f800000,0x00050036,0x00000002,0x00000004,0x00000000,0x00000003,0x000200f8, - 0x00000005,0x0004003d,0x00000007,0x00000010,0x0000000f,0x00050041,0x00000011,0x00000012, - 0x0000000b,0x0000000d,0x0003003e,0x00000012,0x00000010,0x0004003d,0x00000008,0x00000016, - 0x00000015,0x00050041,0x00000017,0x00000018,0x0000000b,0x00000013,0x0003003e,0x00000018, - 0x00000016,0x0004003d,0x00000008,0x0000001d,0x0000001c,0x00050041,0x00000021,0x00000022, - 0x00000020,0x0000000d,0x0004003d,0x00000008,0x00000023,0x00000022,0x00050085,0x00000008, - 0x00000024,0x0000001d,0x00000023,0x00050041,0x00000021,0x00000025,0x00000020,0x00000013, - 0x0004003d,0x00000008,0x00000026,0x00000025,0x00050081,0x00000008,0x00000027,0x00000024, - 0x00000026,0x00050051,0x00000006,0x0000002a,0x00000027,0x00000000,0x00050051,0x00000006, - 0x0000002b,0x00000027,0x00000001,0x00070050,0x00000007,0x0000002c,0x0000002a,0x0000002b, - 0x00000028,0x00000029,0x00050041,0x00000011,0x0000002d,0x0000001b,0x0000000d,0x0003003e, - 0x0000002d,0x0000002c,0x000100fd,0x00010038 -}; - -// backends/vulkan/glsl_shader.frag, compiled with: -// # glslangValidator -V -x -o glsl_shader.frag.u32 glsl_shader.frag -/* -#version 450 core -layout(location = 0) out vec4 fColor; -layout(set=0, binding=0) uniform sampler2D sTexture; -layout(location = 0) in struct { vec4 Color; vec2 UV; } In; -void main() -{ - fColor = In.Color * texture(sTexture, In.UV.st); -} -*/ -static uint32_t __glsl_shader_frag_spv[] = -{ - 0x07230203,0x00010000,0x00080001,0x0000001e,0x00000000,0x00020011,0x00000001,0x0006000b, - 0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,0x00000000,0x00000001, - 0x0007000f,0x00000004,0x00000004,0x6e69616d,0x00000000,0x00000009,0x0000000d,0x00030010, - 0x00000004,0x00000007,0x00030003,0x00000002,0x000001c2,0x00040005,0x00000004,0x6e69616d, - 0x00000000,0x00040005,0x00000009,0x6c6f4366,0x0000726f,0x00030005,0x0000000b,0x00000000, - 0x00050006,0x0000000b,0x00000000,0x6f6c6f43,0x00000072,0x00040006,0x0000000b,0x00000001, - 0x00005655,0x00030005,0x0000000d,0x00006e49,0x00050005,0x00000016,0x78655473,0x65727574, - 0x00000000,0x00040047,0x00000009,0x0000001e,0x00000000,0x00040047,0x0000000d,0x0000001e, - 0x00000000,0x00040047,0x00000016,0x00000022,0x00000000,0x00040047,0x00000016,0x00000021, - 0x00000000,0x00020013,0x00000002,0x00030021,0x00000003,0x00000002,0x00030016,0x00000006, - 0x00000020,0x00040017,0x00000007,0x00000006,0x00000004,0x00040020,0x00000008,0x00000003, - 0x00000007,0x0004003b,0x00000008,0x00000009,0x00000003,0x00040017,0x0000000a,0x00000006, - 0x00000002,0x0004001e,0x0000000b,0x00000007,0x0000000a,0x00040020,0x0000000c,0x00000001, - 0x0000000b,0x0004003b,0x0000000c,0x0000000d,0x00000001,0x00040015,0x0000000e,0x00000020, - 0x00000001,0x0004002b,0x0000000e,0x0000000f,0x00000000,0x00040020,0x00000010,0x00000001, - 0x00000007,0x00090019,0x00000013,0x00000006,0x00000001,0x00000000,0x00000000,0x00000000, - 0x00000001,0x00000000,0x0003001b,0x00000014,0x00000013,0x00040020,0x00000015,0x00000000, - 0x00000014,0x0004003b,0x00000015,0x00000016,0x00000000,0x0004002b,0x0000000e,0x00000018, - 0x00000001,0x00040020,0x00000019,0x00000001,0x0000000a,0x00050036,0x00000002,0x00000004, - 0x00000000,0x00000003,0x000200f8,0x00000005,0x00050041,0x00000010,0x00000011,0x0000000d, - 0x0000000f,0x0004003d,0x00000007,0x00000012,0x00000011,0x0004003d,0x00000014,0x00000017, - 0x00000016,0x00050041,0x00000019,0x0000001a,0x0000000d,0x00000018,0x0004003d,0x0000000a, - 0x0000001b,0x0000001a,0x00050057,0x00000007,0x0000001c,0x00000017,0x0000001b,0x00050085, - 0x00000007,0x0000001d,0x00000012,0x0000001c,0x0003003e,0x00000009,0x0000001d,0x000100fd, - 0x00010038 -}; - -//----------------------------------------------------------------------------- -// FUNCTIONS -//----------------------------------------------------------------------------- - -// 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_GetBackendData() -{ - return ImGui::GetCurrentContext() ? (ImGui_ImplVulkan_Data*)ImGui::GetIO().BackendRendererUserData : nullptr; -} - -static uint32_t ImGui_ImplVulkan_MemoryType(VkMemoryPropertyFlags properties, uint32_t type_bits) -{ - ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); - ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo; - VkPhysicalDeviceMemoryProperties prop; - vkGetPhysicalDeviceMemoryProperties(v->PhysicalDevice, &prop); - for (uint32_t i = 0; i < prop.memoryTypeCount; i++) - if ((prop.memoryTypes[i].propertyFlags & properties) == properties && type_bits & (1 << i)) - return i; - return 0xFFFFFFFF; // Unable to find memoryType -} - -static void check_vk_result(VkResult err) -{ - ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); - if (!bd) - return; - ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo; - if (v->CheckVkResultFn) - v->CheckVkResultFn(err); -} - -// Same as IM_MEMALIGN(). 'alignment' must be a power of two. -static inline VkDeviceSize AlignBufferSize(VkDeviceSize size, VkDeviceSize alignment) -{ - return (size + alignment - 1) & ~(alignment - 1); -} - -static void CreateOrResizeBuffer(VkBuffer& buffer, VkDeviceMemory& buffer_memory, VkDeviceSize& buffer_size, VkDeviceSize new_size, VkBufferUsageFlagBits usage) -{ - ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); - ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo; - VkResult err; - if (buffer != VK_NULL_HANDLE) - vkDestroyBuffer(v->Device, buffer, v->Allocator); - if (buffer_memory != VK_NULL_HANDLE) - vkFreeMemory(v->Device, buffer_memory, v->Allocator); - - VkDeviceSize buffer_size_aligned = AlignBufferSize(IM_MAX(v->MinAllocationSize, new_size), bd->BufferMemoryAlignment); - VkBufferCreateInfo buffer_info = {}; - buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - buffer_info.size = buffer_size_aligned; - buffer_info.usage = usage; - buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - err = vkCreateBuffer(v->Device, &buffer_info, v->Allocator, &buffer); - check_vk_result(err); - - VkMemoryRequirements req; - vkGetBufferMemoryRequirements(v->Device, buffer, &req); - bd->BufferMemoryAlignment = (bd->BufferMemoryAlignment > req.alignment) ? bd->BufferMemoryAlignment : req.alignment; - VkMemoryAllocateInfo alloc_info = {}; - alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; - alloc_info.allocationSize = req.size; - alloc_info.memoryTypeIndex = ImGui_ImplVulkan_MemoryType(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, req.memoryTypeBits); - err = vkAllocateMemory(v->Device, &alloc_info, v->Allocator, &buffer_memory); - check_vk_result(err); - - err = vkBindBufferMemory(v->Device, buffer, buffer_memory, 0); - check_vk_result(err); - buffer_size = buffer_size_aligned; -} - -static void ImGui_ImplVulkan_SetupRenderState(ImDrawData* draw_data, VkPipeline pipeline, VkCommandBuffer command_buffer, ImGui_ImplVulkan_FrameRenderBuffers* rb, int fb_width, int fb_height) -{ - ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); - - // Bind pipeline: - { - vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); - } - - // Bind Vertex And Index Buffer: - if (draw_data->TotalVtxCount > 0) - { - VkBuffer vertex_buffers[1] = { rb->VertexBuffer }; - VkDeviceSize vertex_offset[1] = { 0 }; - vkCmdBindVertexBuffers(command_buffer, 0, 1, vertex_buffers, vertex_offset); - vkCmdBindIndexBuffer(command_buffer, rb->IndexBuffer, 0, sizeof(ImDrawIdx) == 2 ? VK_INDEX_TYPE_UINT16 : VK_INDEX_TYPE_UINT32); - } - - // Setup viewport: - { - VkViewport viewport; - viewport.x = 0; - viewport.y = 0; - viewport.width = (float)fb_width; - viewport.height = (float)fb_height; - viewport.minDepth = 0.0f; - viewport.maxDepth = 1.0f; - vkCmdSetViewport(command_buffer, 0, 1, &viewport); - } - - // Setup scale and translation: - // Our visible imgui space lies from draw_data->DisplayPps (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps. - { - float scale[2]; - scale[0] = 2.0f / draw_data->DisplaySize.x; - scale[1] = 2.0f / draw_data->DisplaySize.y; - float translate[2]; - translate[0] = -1.0f - draw_data->DisplayPos.x * scale[0]; - translate[1] = -1.0f - draw_data->DisplayPos.y * scale[1]; - vkCmdPushConstants(command_buffer, bd->PipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, sizeof(float) * 0, sizeof(float) * 2, scale); - vkCmdPushConstants(command_buffer, bd->PipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, sizeof(float) * 2, sizeof(float) * 2, translate); - } -} - -// Render function -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); - if (fb_width <= 0 || fb_height <= 0) - return; - - ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); - ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo; - if (pipeline == VK_NULL_HANDLE) - pipeline = bd->Pipeline; - - // Allocate array to store enough vertex/index buffers. Each unique viewport gets its own storage. - ImGui_ImplVulkan_ViewportData* viewport_renderer_data = (ImGui_ImplVulkan_ViewportData*)draw_data->OwnerViewport->RendererUserData; - IM_ASSERT(viewport_renderer_data != nullptr); - ImGui_ImplVulkan_WindowRenderBuffers* wrb = &viewport_renderer_data->RenderBuffers; - if (wrb->FrameRenderBuffers == nullptr) - { - wrb->Index = 0; - wrb->Count = v->ImageCount; - wrb->FrameRenderBuffers = (ImGui_ImplVulkan_FrameRenderBuffers*)IM_ALLOC(sizeof(ImGui_ImplVulkan_FrameRenderBuffers) * wrb->Count); - memset((void*)wrb->FrameRenderBuffers, 0, sizeof(ImGui_ImplVulkan_FrameRenderBuffers) * wrb->Count); - } - IM_ASSERT(wrb->Count == v->ImageCount); - wrb->Index = (wrb->Index + 1) % wrb->Count; - ImGui_ImplVulkan_FrameRenderBuffers* rb = &wrb->FrameRenderBuffers[wrb->Index]; - - if (draw_data->TotalVtxCount > 0) - { - // Create or resize the vertex/index buffers - VkDeviceSize vertex_size = AlignBufferSize(draw_data->TotalVtxCount * sizeof(ImDrawVert), bd->BufferMemoryAlignment); - VkDeviceSize index_size = AlignBufferSize(draw_data->TotalIdxCount * sizeof(ImDrawIdx), bd->BufferMemoryAlignment); - if (rb->VertexBuffer == VK_NULL_HANDLE || rb->VertexBufferSize < vertex_size) - CreateOrResizeBuffer(rb->VertexBuffer, rb->VertexBufferMemory, rb->VertexBufferSize, vertex_size, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT); - if (rb->IndexBuffer == VK_NULL_HANDLE || rb->IndexBufferSize < index_size) - CreateOrResizeBuffer(rb->IndexBuffer, rb->IndexBufferMemory, rb->IndexBufferSize, index_size, VK_BUFFER_USAGE_INDEX_BUFFER_BIT); - - // Upload vertex/index data into a single contiguous GPU buffer - ImDrawVert* vtx_dst = nullptr; - ImDrawIdx* idx_dst = nullptr; - VkResult err = vkMapMemory(v->Device, rb->VertexBufferMemory, 0, vertex_size, 0, (void**)&vtx_dst); - check_vk_result(err); - err = vkMapMemory(v->Device, rb->IndexBufferMemory, 0, index_size, 0, (void**)&idx_dst); - check_vk_result(err); - for (int n = 0; n < draw_data->CmdListsCount; n++) - { - const ImDrawList* draw_list = draw_data->CmdLists[n]; - memcpy(vtx_dst, draw_list->VtxBuffer.Data, draw_list->VtxBuffer.Size * sizeof(ImDrawVert)); - memcpy(idx_dst, draw_list->IdxBuffer.Data, draw_list->IdxBuffer.Size * sizeof(ImDrawIdx)); - vtx_dst += draw_list->VtxBuffer.Size; - idx_dst += draw_list->IdxBuffer.Size; - } - VkMappedMemoryRange range[2] = {}; - range[0].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE; - range[0].memory = rb->VertexBufferMemory; - range[0].size = VK_WHOLE_SIZE; - range[1].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE; - range[1].memory = rb->IndexBufferMemory; - range[1].size = VK_WHOLE_SIZE; - err = vkFlushMappedMemoryRanges(v->Device, 2, range); - check_vk_result(err); - vkUnmapMemory(v->Device, rb->VertexBufferMemory); - vkUnmapMemory(v->Device, rb->IndexBufferMemory); - } - - // Setup desired Vulkan state - ImGui_ImplVulkan_SetupRenderState(draw_data, pipeline, command_buffer, rb, fb_width, fb_height); - - // Setup render state structure (for callbacks and custom texture bindings) - ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); - ImGui_ImplVulkan_RenderState render_state; - render_state.CommandBuffer = command_buffer; - render_state.Pipeline = pipeline; - render_state.PipelineLayout = bd->PipelineLayout; - platform_io.Renderer_RenderState = &render_state; - - // Will project scissor/clipping rectangles into framebuffer space - ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports - ImVec2 clip_scale = draw_data->FramebufferScale; // (1,1) unless using retina display which are often (2,2) - - // Render command lists - // (Because we merged all buffers into a single one, we maintain our own offset into them) - int global_vtx_offset = 0; - int global_idx_offset = 0; - for (int n = 0; n < draw_data->CmdListsCount; n++) - { - const ImDrawList* draw_list = draw_data->CmdLists[n]; - for (int cmd_i = 0; cmd_i < draw_list->CmdBuffer.Size; cmd_i++) - { - const ImDrawCmd* pcmd = &draw_list->CmdBuffer[cmd_i]; - if (pcmd->UserCallback != nullptr) - { - // User callback, registered via ImDrawList::AddCallback() - // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.) - if (pcmd->UserCallback == ImDrawCallback_ResetRenderState) - ImGui_ImplVulkan_SetupRenderState(draw_data, pipeline, command_buffer, rb, fb_width, fb_height); - else - pcmd->UserCallback(draw_list, pcmd); - } - else - { - // Project scissor/clipping rectangles into framebuffer space - ImVec2 clip_min((pcmd->ClipRect.x - clip_off.x) * clip_scale.x, (pcmd->ClipRect.y - clip_off.y) * clip_scale.y); - ImVec2 clip_max((pcmd->ClipRect.z - clip_off.x) * clip_scale.x, (pcmd->ClipRect.w - clip_off.y) * clip_scale.y); - - // Clamp to viewport as vkCmdSetScissor() won't accept values that are off bounds - if (clip_min.x < 0.0f) { clip_min.x = 0.0f; } - if (clip_min.y < 0.0f) { clip_min.y = 0.0f; } - if (clip_max.x > fb_width) { clip_max.x = (float)fb_width; } - if (clip_max.y > fb_height) { clip_max.y = (float)fb_height; } - if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y) - continue; - - // Apply scissor/clipping rectangle - VkRect2D scissor; - scissor.offset.x = (int32_t)(clip_min.x); - scissor.offset.y = (int32_t)(clip_min.y); - scissor.extent.width = (uint32_t)(clip_max.x - clip_min.x); - scissor.extent.height = (uint32_t)(clip_max.y - clip_min.y); - vkCmdSetScissor(command_buffer, 0, 1, &scissor); - - // Bind DescriptorSet with font or user texture - VkDescriptorSet desc_set = (VkDescriptorSet)pcmd->GetTexID(); - vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, bd->PipelineLayout, 0, 1, &desc_set, 0, nullptr); - - // Draw - vkCmdDrawIndexed(command_buffer, pcmd->ElemCount, 1, pcmd->IdxOffset + global_idx_offset, pcmd->VtxOffset + global_vtx_offset, 0); - } - } - global_idx_offset += draw_list->IdxBuffer.Size; - global_vtx_offset += draw_list->VtxBuffer.Size; - } - platform_io.Renderer_RenderState = NULL; - - // Note: at this point both vkCmdSetViewport() and vkCmdSetScissor() have been called. - // Our last values will leak into user/application rendering IF: - // - Your app uses a pipeline with VK_DYNAMIC_STATE_VIEWPORT or VK_DYNAMIC_STATE_SCISSOR dynamic state - // - And you forgot to call vkCmdSetViewport() and vkCmdSetScissor() yourself to explicitly set that state. - // If you use VK_DYNAMIC_STATE_VIEWPORT or VK_DYNAMIC_STATE_SCISSOR you are responsible for setting the values before rendering. - // In theory we should aim to backup/restore those values but I am not sure this is possible. - // We perform a call to vkCmdSetScissor() to set back a full viewport which is likely to fix things for 99% users but technically this is not perfect. (See github #4644) - VkRect2D scissor = { { 0, 0 }, { (uint32_t)fb_width, (uint32_t)fb_height } }; - vkCmdSetScissor(command_buffer, 0, 1, &scissor); -} - -bool ImGui_ImplVulkan_CreateFontsTexture() -{ - ImGuiIO& io = ImGui::GetIO(); - ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); - ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo; - VkResult err; - - // Destroy existing texture (if any) - if (bd->FontTexture.DescriptorSet) - { - vkQueueWaitIdle(v->Queue); - ImGui_ImplVulkan_DestroyFontsTexture(); - } - - // Create command pool/buffer - if (bd->TexCommandPool == VK_NULL_HANDLE) - { - VkCommandPoolCreateInfo info = {}; - info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; - info.flags = 0; - info.queueFamilyIndex = v->QueueFamily; - vkCreateCommandPool(v->Device, &info, v->Allocator, &bd->TexCommandPool); - } - if (bd->TexCommandBuffer == VK_NULL_HANDLE) - { - VkCommandBufferAllocateInfo info = {}; - info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; - info.commandPool = bd->TexCommandPool; - info.commandBufferCount = 1; - err = vkAllocateCommandBuffers(v->Device, &info, &bd->TexCommandBuffer); - check_vk_result(err); - } - - // Start command buffer - { - err = vkResetCommandPool(v->Device, bd->TexCommandPool, 0); - check_vk_result(err); - VkCommandBufferBeginInfo begin_info = {}; - begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - begin_info.flags |= VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; - err = vkBeginCommandBuffer(bd->TexCommandBuffer, &begin_info); - check_vk_result(err); - } - - unsigned char* pixels; - int width, height; - io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); - size_t upload_size = width * height * 4 * sizeof(char); - - // Create the Image: - ImGui_ImplVulkan_Texture* backend_tex = &bd->FontTexture; - { - VkImageCreateInfo info = {}; - info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; - info.imageType = VK_IMAGE_TYPE_2D; - info.format = VK_FORMAT_R8G8B8A8_UNORM; - info.extent.width = width; - info.extent.height = height; - info.extent.depth = 1; - info.mipLevels = 1; - info.arrayLayers = 1; - info.samples = VK_SAMPLE_COUNT_1_BIT; - info.tiling = VK_IMAGE_TILING_OPTIMAL; - info.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; - info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - err = vkCreateImage(v->Device, &info, v->Allocator, &backend_tex->Image); - check_vk_result(err); - VkMemoryRequirements req; - vkGetImageMemoryRequirements(v->Device, backend_tex->Image, &req); - VkMemoryAllocateInfo alloc_info = {}; - alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; - alloc_info.allocationSize = IM_MAX(v->MinAllocationSize, req.size); - alloc_info.memoryTypeIndex = ImGui_ImplVulkan_MemoryType(VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, req.memoryTypeBits); - err = vkAllocateMemory(v->Device, &alloc_info, v->Allocator, &backend_tex->Memory); - check_vk_result(err); - err = vkBindImageMemory(v->Device, backend_tex->Image, backend_tex->Memory, 0); - check_vk_result(err); - } - - // Create the Image View: - { - VkImageViewCreateInfo info = {}; - info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - info.image = backend_tex->Image; - info.viewType = VK_IMAGE_VIEW_TYPE_2D; - info.format = VK_FORMAT_R8G8B8A8_UNORM; - info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - info.subresourceRange.levelCount = 1; - info.subresourceRange.layerCount = 1; - err = vkCreateImageView(v->Device, &info, v->Allocator, &backend_tex->ImageView); - check_vk_result(err); - } - - // Create the Descriptor Set: - backend_tex->DescriptorSet = ImGui_ImplVulkan_AddTexture(bd->TexSampler, backend_tex->ImageView, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); - - // Create the Upload Buffer: - VkDeviceMemory upload_buffer_memory; - VkBuffer upload_buffer; - { - VkBufferCreateInfo buffer_info = {}; - buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - buffer_info.size = upload_size; - buffer_info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; - buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - err = vkCreateBuffer(v->Device, &buffer_info, v->Allocator, &upload_buffer); - check_vk_result(err); - VkMemoryRequirements req; - vkGetBufferMemoryRequirements(v->Device, upload_buffer, &req); - bd->BufferMemoryAlignment = (bd->BufferMemoryAlignment > req.alignment) ? bd->BufferMemoryAlignment : req.alignment; - VkMemoryAllocateInfo alloc_info = {}; - alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; - alloc_info.allocationSize = IM_MAX(v->MinAllocationSize, req.size); - alloc_info.memoryTypeIndex = ImGui_ImplVulkan_MemoryType(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, req.memoryTypeBits); - err = vkAllocateMemory(v->Device, &alloc_info, v->Allocator, &upload_buffer_memory); - check_vk_result(err); - err = vkBindBufferMemory(v->Device, upload_buffer, upload_buffer_memory, 0); - check_vk_result(err); - } - - // Upload to Buffer: - { - char* map = nullptr; - err = vkMapMemory(v->Device, upload_buffer_memory, 0, upload_size, 0, (void**)(&map)); - check_vk_result(err); - memcpy(map, pixels, upload_size); - VkMappedMemoryRange range[1] = {}; - range[0].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE; - range[0].memory = upload_buffer_memory; - range[0].size = upload_size; - err = vkFlushMappedMemoryRanges(v->Device, 1, range); - check_vk_result(err); - vkUnmapMemory(v->Device, upload_buffer_memory); - } - - // Copy to Image: - { - VkImageMemoryBarrier copy_barrier[1] = {}; - copy_barrier[0].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - copy_barrier[0].dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - copy_barrier[0].oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; - copy_barrier[0].newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; - copy_barrier[0].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - copy_barrier[0].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - copy_barrier[0].image = backend_tex->Image; - copy_barrier[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - copy_barrier[0].subresourceRange.levelCount = 1; - copy_barrier[0].subresourceRange.layerCount = 1; - vkCmdPipelineBarrier(bd->TexCommandBuffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, copy_barrier); - - VkBufferImageCopy region = {}; - region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - region.imageSubresource.layerCount = 1; - region.imageExtent.width = width; - region.imageExtent.height = height; - region.imageExtent.depth = 1; - vkCmdCopyBufferToImage(bd->TexCommandBuffer, upload_buffer, backend_tex->Image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); - - VkImageMemoryBarrier use_barrier[1] = {}; - use_barrier[0].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - use_barrier[0].srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - use_barrier[0].dstAccessMask = VK_ACCESS_SHADER_READ_BIT; - use_barrier[0].oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; - use_barrier[0].newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - use_barrier[0].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - use_barrier[0].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - use_barrier[0].image = backend_tex->Image; - use_barrier[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - use_barrier[0].subresourceRange.levelCount = 1; - use_barrier[0].subresourceRange.layerCount = 1; - vkCmdPipelineBarrier(bd->TexCommandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, use_barrier); - } - - // Store our identifier - io.Fonts->SetTexID((ImTextureID)backend_tex->DescriptorSet); - - // End command buffer - VkSubmitInfo end_info = {}; - end_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - end_info.commandBufferCount = 1; - end_info.pCommandBuffers = &bd->TexCommandBuffer; - err = vkEndCommandBuffer(bd->TexCommandBuffer); - check_vk_result(err); - err = vkQueueSubmit(v->Queue, 1, &end_info, VK_NULL_HANDLE); - check_vk_result(err); - - err = vkQueueWaitIdle(v->Queue); - check_vk_result(err); - - vkDestroyBuffer(v->Device, upload_buffer, v->Allocator); - vkFreeMemory(v->Device, upload_buffer_memory, v->Allocator); - - return true; -} - -// You probably never need to call this, as it is called by ImGui_ImplVulkan_CreateFontsTexture() and ImGui_ImplVulkan_Shutdown(). -void ImGui_ImplVulkan_DestroyFontsTexture() -{ - ImGuiIO& io = ImGui::GetIO(); - ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); - ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo; - - ImGui_ImplVulkan_Texture* backend_tex = &bd->FontTexture; - - if (backend_tex->DescriptorSet) - { - ImGui_ImplVulkan_RemoveTexture(backend_tex->DescriptorSet); - backend_tex->DescriptorSet = VK_NULL_HANDLE; - io.Fonts->SetTexID(0); - } - if (backend_tex->ImageView) { vkDestroyImageView(v->Device, backend_tex->ImageView, v->Allocator); backend_tex->ImageView = VK_NULL_HANDLE; } - if (backend_tex->Image) { vkDestroyImage(v->Device, backend_tex->Image, v->Allocator); backend_tex->Image = VK_NULL_HANDLE; } - if (backend_tex->Memory) { vkFreeMemory(v->Device, backend_tex->Memory, v->Allocator); backend_tex->Memory = VK_NULL_HANDLE; } -} - -static void ImGui_ImplVulkan_CreateShaderModules(VkDevice device, const VkAllocationCallbacks* allocator) -{ - // Create the shader modules - ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); - if (bd->ShaderModuleVert == VK_NULL_HANDLE) - { - VkShaderModuleCreateInfo vert_info = {}; - vert_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; - vert_info.codeSize = sizeof(__glsl_shader_vert_spv); - vert_info.pCode = (uint32_t*)__glsl_shader_vert_spv; - VkResult err = vkCreateShaderModule(device, &vert_info, allocator, &bd->ShaderModuleVert); - check_vk_result(err); - } - if (bd->ShaderModuleFrag == VK_NULL_HANDLE) - { - VkShaderModuleCreateInfo frag_info = {}; - frag_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; - frag_info.codeSize = sizeof(__glsl_shader_frag_spv); - frag_info.pCode = (uint32_t*)__glsl_shader_frag_spv; - VkResult err = vkCreateShaderModule(device, &frag_info, allocator, &bd->ShaderModuleFrag); - check_vk_result(err); - } -} - -static void ImGui_ImplVulkan_CreatePipeline(VkDevice device, const VkAllocationCallbacks* allocator, VkPipelineCache pipelineCache, VkRenderPass renderPass, VkSampleCountFlagBits MSAASamples, VkPipeline* pipeline, uint32_t subpass) -{ - ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); - ImGui_ImplVulkan_CreateShaderModules(device, allocator); - - VkPipelineShaderStageCreateInfo stage[2] = {}; - stage[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; - stage[0].stage = VK_SHADER_STAGE_VERTEX_BIT; - stage[0].module = bd->ShaderModuleVert; - stage[0].pName = "main"; - stage[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; - stage[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT; - stage[1].module = bd->ShaderModuleFrag; - stage[1].pName = "main"; - - VkVertexInputBindingDescription binding_desc[1] = {}; - binding_desc[0].stride = sizeof(ImDrawVert); - binding_desc[0].inputRate = VK_VERTEX_INPUT_RATE_VERTEX; - - VkVertexInputAttributeDescription attribute_desc[3] = {}; - attribute_desc[0].location = 0; - attribute_desc[0].binding = binding_desc[0].binding; - attribute_desc[0].format = VK_FORMAT_R32G32_SFLOAT; - attribute_desc[0].offset = offsetof(ImDrawVert, pos); - attribute_desc[1].location = 1; - attribute_desc[1].binding = binding_desc[0].binding; - attribute_desc[1].format = VK_FORMAT_R32G32_SFLOAT; - attribute_desc[1].offset = offsetof(ImDrawVert, uv); - attribute_desc[2].location = 2; - attribute_desc[2].binding = binding_desc[0].binding; - attribute_desc[2].format = VK_FORMAT_R8G8B8A8_UNORM; - attribute_desc[2].offset = offsetof(ImDrawVert, col); - - VkPipelineVertexInputStateCreateInfo vertex_info = {}; - vertex_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; - vertex_info.vertexBindingDescriptionCount = 1; - vertex_info.pVertexBindingDescriptions = binding_desc; - vertex_info.vertexAttributeDescriptionCount = 3; - vertex_info.pVertexAttributeDescriptions = attribute_desc; - - VkPipelineInputAssemblyStateCreateInfo ia_info = {}; - ia_info.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; - ia_info.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; - - VkPipelineViewportStateCreateInfo viewport_info = {}; - viewport_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; - viewport_info.viewportCount = 1; - viewport_info.scissorCount = 1; - - VkPipelineRasterizationStateCreateInfo raster_info = {}; - raster_info.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; - raster_info.polygonMode = VK_POLYGON_MODE_FILL; - raster_info.cullMode = VK_CULL_MODE_NONE; - raster_info.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; - raster_info.lineWidth = 1.0f; - - VkPipelineMultisampleStateCreateInfo ms_info = {}; - ms_info.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; - ms_info.rasterizationSamples = (MSAASamples != 0) ? MSAASamples : VK_SAMPLE_COUNT_1_BIT; - - VkPipelineColorBlendAttachmentState color_attachment[1] = {}; - color_attachment[0].blendEnable = VK_TRUE; - color_attachment[0].srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; - color_attachment[0].dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; - color_attachment[0].colorBlendOp = VK_BLEND_OP_ADD; - color_attachment[0].srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; - color_attachment[0].dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; - color_attachment[0].alphaBlendOp = VK_BLEND_OP_ADD; - color_attachment[0].colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; - - VkPipelineDepthStencilStateCreateInfo depth_info = {}; - depth_info.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; - - VkPipelineColorBlendStateCreateInfo blend_info = {}; - blend_info.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; - blend_info.attachmentCount = 1; - blend_info.pAttachments = color_attachment; - - VkDynamicState dynamic_states[2] = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR }; - VkPipelineDynamicStateCreateInfo dynamic_state = {}; - dynamic_state.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; - dynamic_state.dynamicStateCount = (uint32_t)IM_ARRAYSIZE(dynamic_states); - dynamic_state.pDynamicStates = dynamic_states; - - VkGraphicsPipelineCreateInfo info = {}; - info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; - info.flags = bd->PipelineCreateFlags; - info.stageCount = 2; - info.pStages = stage; - info.pVertexInputState = &vertex_info; - info.pInputAssemblyState = &ia_info; - info.pViewportState = &viewport_info; - info.pRasterizationState = &raster_info; - info.pMultisampleState = &ms_info; - info.pDepthStencilState = &depth_info; - info.pColorBlendState = &blend_info; - info.pDynamicState = &dynamic_state; - info.layout = bd->PipelineLayout; - info.renderPass = renderPass; - info.subpass = subpass; - -#ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING - if (bd->VulkanInitInfo.UseDynamicRendering) - { - IM_ASSERT(bd->VulkanInitInfo.PipelineRenderingCreateInfo.sType == VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR && "PipelineRenderingCreateInfo sType must be VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR"); - IM_ASSERT(bd->VulkanInitInfo.PipelineRenderingCreateInfo.pNext == nullptr && "PipelineRenderingCreateInfo pNext must be NULL"); - info.pNext = &bd->VulkanInitInfo.PipelineRenderingCreateInfo; - info.renderPass = VK_NULL_HANDLE; // Just make sure it's actually nullptr. - } -#endif - - VkResult err = vkCreateGraphicsPipelines(device, pipelineCache, 1, &info, allocator, pipeline); - check_vk_result(err); -} - -bool ImGui_ImplVulkan_CreateDeviceObjects() -{ - ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); - ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo; - VkResult err; - - if (!bd->TexSampler) - { - // Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling. - VkSamplerCreateInfo info = {}; - info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; - info.magFilter = VK_FILTER_LINEAR; - info.minFilter = VK_FILTER_LINEAR; - info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; - info.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; - info.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; - info.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; - info.minLod = -1000; - info.maxLod = 1000; - info.maxAnisotropy = 1.0f; - err = vkCreateSampler(v->Device, &info, v->Allocator, &bd->TexSampler); - check_vk_result(err); - } - - if (!bd->DescriptorSetLayout) - { - VkDescriptorSetLayoutBinding binding[1] = {}; - binding[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - binding[0].descriptorCount = 1; - binding[0].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; - VkDescriptorSetLayoutCreateInfo info = {}; - info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; - info.bindingCount = 1; - info.pBindings = binding; - err = vkCreateDescriptorSetLayout(v->Device, &info, v->Allocator, &bd->DescriptorSetLayout); - check_vk_result(err); - } - - if (v->DescriptorPoolSize) - { - VkDescriptorPoolSize pool_size = { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, v->DescriptorPoolSize }; - VkDescriptorPoolCreateInfo pool_info = {}; - pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; - pool_info.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT; - pool_info.maxSets = v->DescriptorPoolSize; - pool_info.poolSizeCount = 1; - pool_info.pPoolSizes = &pool_size; - - err = vkCreateDescriptorPool(v->Device, &pool_info, v->Allocator, &bd->DescriptorPool); - check_vk_result(err); - } - - if (!bd->PipelineLayout) - { - // Constants: we are using 'vec2 offset' and 'vec2 scale' instead of a full 3d projection matrix - VkPushConstantRange push_constants[1] = {}; - push_constants[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; - push_constants[0].offset = sizeof(float) * 0; - push_constants[0].size = sizeof(float) * 4; - VkDescriptorSetLayout set_layout[1] = { bd->DescriptorSetLayout }; - VkPipelineLayoutCreateInfo layout_info = {}; - layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; - layout_info.setLayoutCount = 1; - layout_info.pSetLayouts = set_layout; - layout_info.pushConstantRangeCount = 1; - layout_info.pPushConstantRanges = push_constants; - err = vkCreatePipelineLayout(v->Device, &layout_info, v->Allocator, &bd->PipelineLayout); - check_vk_result(err); - } - - ImGui_ImplVulkan_CreatePipeline(v->Device, v->Allocator, v->PipelineCache, v->RenderPass, v->MSAASamples, &bd->Pipeline, v->Subpass); - - return true; -} - -void ImGui_ImplVulkan_DestroyDeviceObjects() -{ - ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); - ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo; - ImGui_ImplVulkanH_DestroyAllViewportsRenderBuffers(v->Device, v->Allocator); - ImGui_ImplVulkan_DestroyFontsTexture(); - - if (bd->TexCommandBuffer) { vkFreeCommandBuffers(v->Device, bd->TexCommandPool, 1, &bd->TexCommandBuffer); bd->TexCommandBuffer = VK_NULL_HANDLE; } - if (bd->TexCommandPool) { vkDestroyCommandPool(v->Device, bd->TexCommandPool, v->Allocator); bd->TexCommandPool = VK_NULL_HANDLE; } - if (bd->TexSampler) { vkDestroySampler(v->Device, bd->TexSampler, v->Allocator); bd->TexSampler = VK_NULL_HANDLE; } - if (bd->ShaderModuleVert) { vkDestroyShaderModule(v->Device, bd->ShaderModuleVert, v->Allocator); bd->ShaderModuleVert = VK_NULL_HANDLE; } - if (bd->ShaderModuleFrag) { vkDestroyShaderModule(v->Device, bd->ShaderModuleFrag, v->Allocator); bd->ShaderModuleFrag = VK_NULL_HANDLE; } - if (bd->DescriptorSetLayout) { vkDestroyDescriptorSetLayout(v->Device, bd->DescriptorSetLayout, v->Allocator); bd->DescriptorSetLayout = VK_NULL_HANDLE; } - if (bd->PipelineLayout) { vkDestroyPipelineLayout(v->Device, bd->PipelineLayout, v->Allocator); bd->PipelineLayout = VK_NULL_HANDLE; } - if (bd->Pipeline) { vkDestroyPipeline(v->Device, bd->Pipeline, v->Allocator); bd->Pipeline = VK_NULL_HANDLE; } - if (bd->PipelineForViewports) { vkDestroyPipeline(v->Device, bd->PipelineForViewports, v->Allocator); bd->PipelineForViewports = VK_NULL_HANDLE; } - if (bd->DescriptorPool) { vkDestroyDescriptorPool(v->Device, bd->DescriptorPool, v->Allocator); bd->DescriptorPool = VK_NULL_HANDLE; } -} - -bool ImGui_ImplVulkan_LoadFunctions(PFN_vkVoidFunction(*loader_func)(const char* function_name, void* user_data), void* user_data) -{ - // Load function pointers - // You can use the default Vulkan loader using: - // ImGui_ImplVulkan_LoadFunctions([](const char* function_name, void*) { return vkGetInstanceProcAddr(your_vk_isntance, function_name); }); - // But this would be roughly equivalent to not setting VK_NO_PROTOTYPES. -#ifdef IMGUI_IMPL_VULKAN_USE_LOADER -#define IMGUI_VULKAN_FUNC_LOAD(func) \ - func = reinterpret_cast(loader_func(#func, user_data)); \ - if (func == nullptr) \ - return false; - IMGUI_VULKAN_FUNC_MAP(IMGUI_VULKAN_FUNC_LOAD) -#undef IMGUI_VULKAN_FUNC_LOAD - -#ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING - // Manually load those two (see #5446) - ImGuiImplVulkanFuncs_vkCmdBeginRenderingKHR = reinterpret_cast(loader_func("vkCmdBeginRenderingKHR", user_data)); - ImGuiImplVulkanFuncs_vkCmdEndRenderingKHR = reinterpret_cast(loader_func("vkCmdEndRenderingKHR", user_data)); -#endif -#else - IM_UNUSED(loader_func); - IM_UNUSED(user_data); -#endif - - g_FunctionsLoaded = true; - return true; -} - -bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info) -{ - IM_ASSERT(g_FunctionsLoaded && "Need to call ImGui_ImplVulkan_LoadFunctions() if IMGUI_IMPL_VULKAN_NO_PROTOTYPES or VK_NO_PROTOTYPES are set!"); - - if (info->UseDynamicRendering) - { -#ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING -#ifndef IMGUI_IMPL_VULKAN_USE_LOADER - ImGuiImplVulkanFuncs_vkCmdBeginRenderingKHR = reinterpret_cast(vkGetInstanceProcAddr(info->Instance, "vkCmdBeginRenderingKHR")); - ImGuiImplVulkanFuncs_vkCmdEndRenderingKHR = reinterpret_cast(vkGetInstanceProcAddr(info->Instance, "vkCmdEndRenderingKHR")); -#endif - IM_ASSERT(ImGuiImplVulkanFuncs_vkCmdBeginRenderingKHR != nullptr); - IM_ASSERT(ImGuiImplVulkanFuncs_vkCmdEndRenderingKHR != nullptr); -#else - IM_ASSERT(0 && "Can't use dynamic rendering when neither VK_VERSION_1_3 or VK_KHR_dynamic_rendering is defined."); -#endif - } - - ImGuiIO& io = ImGui::GetIO(); - IMGUI_CHECKVERSION(); - IM_ASSERT(io.BackendRendererUserData == nullptr && "Already initialized a renderer backend!"); - - // Setup backend capabilities flags - ImGui_ImplVulkan_Data* bd = IM_NEW(ImGui_ImplVulkan_Data)(); - io.BackendRendererUserData = (void*)bd; - io.BackendRendererName = "imgui_impl_vulkan"; - io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes. - io.BackendFlags |= ImGuiBackendFlags_RendererHasViewports; // We can create multi-viewports on the Renderer side (optional) - - IM_ASSERT(info->Instance != VK_NULL_HANDLE); - IM_ASSERT(info->PhysicalDevice != VK_NULL_HANDLE); - IM_ASSERT(info->Device != VK_NULL_HANDLE); - IM_ASSERT(info->Queue != VK_NULL_HANDLE); - if (info->DescriptorPool != VK_NULL_HANDLE) // Either DescriptorPool or DescriptorPoolSize must be set, not both! - IM_ASSERT(info->DescriptorPoolSize == 0); - else - IM_ASSERT(info->DescriptorPoolSize > 0); - IM_ASSERT(info->MinImageCount >= 2); - IM_ASSERT(info->ImageCount >= info->MinImageCount); - if (info->UseDynamicRendering == false) - IM_ASSERT(info->RenderPass != VK_NULL_HANDLE); - - bd->VulkanInitInfo = *info; - - ImGui_ImplVulkan_CreateDeviceObjects(); - - // Our render function expect RendererUserData to be storing the window render buffer we need (for the main viewport we won't use ->Window) - ImGuiViewport* main_viewport = ImGui::GetMainViewport(); - main_viewport->RendererUserData = IM_NEW(ImGui_ImplVulkan_ViewportData)(); - - ImGui_ImplVulkan_InitMultiViewportSupport(); - - return true; -} - -void ImGui_ImplVulkan_Shutdown() -{ - ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); - IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?"); - ImGuiIO& io = ImGui::GetIO(); - - // First destroy objects in all viewports - ImGui_ImplVulkan_DestroyDeviceObjects(); - - // Manually delete main viewport render data in-case we haven't initialized for viewports - ImGuiViewport* main_viewport = ImGui::GetMainViewport(); - if (ImGui_ImplVulkan_ViewportData* vd = (ImGui_ImplVulkan_ViewportData*)main_viewport->RendererUserData) - IM_DELETE(vd); - main_viewport->RendererUserData = nullptr; - - // Clean up windows - ImGui_ImplVulkan_ShutdownMultiViewportSupport(); - - io.BackendRendererName = nullptr; - io.BackendRendererUserData = nullptr; - io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasViewports); - IM_DELETE(bd); -} - -void ImGui_ImplVulkan_NewFrame() -{ - ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); - IM_ASSERT(bd != nullptr && "Context or backend not initialized! Did you call ImGui_ImplVulkan_Init()?"); - - if (!bd->FontTexture.DescriptorSet) - ImGui_ImplVulkan_CreateFontsTexture(); -} - -void ImGui_ImplVulkan_SetMinImageCount(uint32_t min_image_count) -{ - ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); - IM_ASSERT(min_image_count >= 2); - if (bd->VulkanInitInfo.MinImageCount == min_image_count) - return; - - IM_ASSERT(0); // FIXME-VIEWPORT: Unsupported. Need to recreate all swap chains! - ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo; - VkResult err = vkDeviceWaitIdle(v->Device); - check_vk_result(err); - ImGui_ImplVulkanH_DestroyAllViewportsRenderBuffers(v->Device, v->Allocator); - - bd->VulkanInitInfo.MinImageCount = min_image_count; -} - -// Register a texture by creating a descriptor -// FIXME: This is experimental in the sense that we are unsure how to best design/tackle this problem, please post to https://github.com/ocornut/imgui/pull/914 if you have suggestions. -VkDescriptorSet ImGui_ImplVulkan_AddTexture(VkSampler sampler, VkImageView image_view, VkImageLayout image_layout) -{ - ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); - ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo; - VkDescriptorPool pool = bd->DescriptorPool ? bd->DescriptorPool : v->DescriptorPool; - - // Create Descriptor Set: - VkDescriptorSet descriptor_set; - { - VkDescriptorSetAllocateInfo alloc_info = {}; - alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; - alloc_info.descriptorPool = pool; - alloc_info.descriptorSetCount = 1; - alloc_info.pSetLayouts = &bd->DescriptorSetLayout; - VkResult err = vkAllocateDescriptorSets(v->Device, &alloc_info, &descriptor_set); - check_vk_result(err); - } - - // Update the Descriptor Set: - { - VkDescriptorImageInfo desc_image[1] = {}; - desc_image[0].sampler = sampler; - desc_image[0].imageView = image_view; - desc_image[0].imageLayout = image_layout; - VkWriteDescriptorSet write_desc[1] = {}; - write_desc[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - write_desc[0].dstSet = descriptor_set; - write_desc[0].descriptorCount = 1; - write_desc[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - write_desc[0].pImageInfo = desc_image; - vkUpdateDescriptorSets(v->Device, 1, write_desc, 0, nullptr); - } - return descriptor_set; -} - -void ImGui_ImplVulkan_RemoveTexture(VkDescriptorSet descriptor_set) -{ - ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); - ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo; - VkDescriptorPool pool = bd->DescriptorPool ? bd->DescriptorPool : v->DescriptorPool; - vkFreeDescriptorSets(v->Device, pool, 1, &descriptor_set); -} - -void ImGui_ImplVulkan_DestroyFrameRenderBuffers(VkDevice device, ImGui_ImplVulkan_FrameRenderBuffers* buffers, const VkAllocationCallbacks* allocator) -{ - if (buffers->VertexBuffer) { vkDestroyBuffer(device, buffers->VertexBuffer, allocator); buffers->VertexBuffer = VK_NULL_HANDLE; } - if (buffers->VertexBufferMemory) { vkFreeMemory(device, buffers->VertexBufferMemory, allocator); buffers->VertexBufferMemory = VK_NULL_HANDLE; } - if (buffers->IndexBuffer) { vkDestroyBuffer(device, buffers->IndexBuffer, allocator); buffers->IndexBuffer = VK_NULL_HANDLE; } - if (buffers->IndexBufferMemory) { vkFreeMemory(device, buffers->IndexBufferMemory, allocator); buffers->IndexBufferMemory = VK_NULL_HANDLE; } - buffers->VertexBufferSize = 0; - buffers->IndexBufferSize = 0; -} - -void ImGui_ImplVulkan_DestroyWindowRenderBuffers(VkDevice device, ImGui_ImplVulkan_WindowRenderBuffers* buffers, const VkAllocationCallbacks* allocator) -{ - for (uint32_t n = 0; n < buffers->Count; n++) - ImGui_ImplVulkan_DestroyFrameRenderBuffers(device, &buffers->FrameRenderBuffers[n], allocator); - IM_FREE(buffers->FrameRenderBuffers); - buffers->FrameRenderBuffers = nullptr; - buffers->Index = 0; - buffers->Count = 0; -} - -//------------------------------------------------------------------------- -// Internal / Miscellaneous Vulkan Helpers -// (Used by example's main.cpp. Used by multi-viewport features. PROBABLY NOT used by your own app.) -//------------------------------------------------------------------------- -// You probably do NOT need to use or care about those functions. -// Those functions only exist because: -// 1) they facilitate the readability and maintenance of the multiple main.cpp examples files. -// 2) the upcoming multi-viewport feature will need them internally. -// Generally we avoid exposing any kind of superfluous high-level helpers in the backends, -// but it is too much code to duplicate everywhere so we exceptionally expose them. -// -// Your engine/app will likely _already_ have code to setup all that stuff (swap chain, render pass, frame buffers, etc.). -// You may read this code to learn about Vulkan, but it is recommended you use you own custom tailored code to do equivalent work. -// (The ImGui_ImplVulkanH_XXX functions do not interact with any of the state used by the regular ImGui_ImplVulkan_XXX functions) -//------------------------------------------------------------------------- - -VkSurfaceFormatKHR ImGui_ImplVulkanH_SelectSurfaceFormat(VkPhysicalDevice physical_device, VkSurfaceKHR surface, const VkFormat* request_formats, int request_formats_count, VkColorSpaceKHR request_color_space) -{ - IM_ASSERT(g_FunctionsLoaded && "Need to call ImGui_ImplVulkan_LoadFunctions() if IMGUI_IMPL_VULKAN_NO_PROTOTYPES or VK_NO_PROTOTYPES are set!"); - IM_ASSERT(request_formats != nullptr); - IM_ASSERT(request_formats_count > 0); - - // Per Spec Format and View Format are expected to be the same unless VK_IMAGE_CREATE_MUTABLE_BIT was set at image creation - // Assuming that the default behavior is without setting this bit, there is no need for separate Swapchain image and image view format - // Additionally several new color spaces were introduced with Vulkan Spec v1.0.40, - // hence we must make sure that a format with the mostly available color space, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR, is found and used. - uint32_t avail_count; - vkGetPhysicalDeviceSurfaceFormatsKHR(physical_device, surface, &avail_count, nullptr); - ImVector avail_format; - avail_format.resize((int)avail_count); - vkGetPhysicalDeviceSurfaceFormatsKHR(physical_device, surface, &avail_count, avail_format.Data); - - // First check if only one format, VK_FORMAT_UNDEFINED, is available, which would imply that any format is available - if (avail_count == 1) - { - if (avail_format[0].format == VK_FORMAT_UNDEFINED) - { - VkSurfaceFormatKHR ret; - ret.format = request_formats[0]; - ret.colorSpace = request_color_space; - return ret; - } - else - { - // No point in searching another format - return avail_format[0]; - } - } - else - { - // Request several formats, the first found will be used - for (int request_i = 0; request_i < request_formats_count; request_i++) - for (uint32_t avail_i = 0; avail_i < avail_count; avail_i++) - if (avail_format[avail_i].format == request_formats[request_i] && avail_format[avail_i].colorSpace == request_color_space) - return avail_format[avail_i]; - - // If none of the requested image formats could be found, use the first available - return avail_format[0]; - } -} - -VkPresentModeKHR ImGui_ImplVulkanH_SelectPresentMode(VkPhysicalDevice physical_device, VkSurfaceKHR surface, const VkPresentModeKHR* request_modes, int request_modes_count) -{ - IM_ASSERT(g_FunctionsLoaded && "Need to call ImGui_ImplVulkan_LoadFunctions() if IMGUI_IMPL_VULKAN_NO_PROTOTYPES or VK_NO_PROTOTYPES are set!"); - IM_ASSERT(request_modes != nullptr); - IM_ASSERT(request_modes_count > 0); - - // Request a certain mode and confirm that it is available. If not use VK_PRESENT_MODE_FIFO_KHR which is mandatory - uint32_t avail_count = 0; - vkGetPhysicalDeviceSurfacePresentModesKHR(physical_device, surface, &avail_count, nullptr); - ImVector avail_modes; - avail_modes.resize((int)avail_count); - vkGetPhysicalDeviceSurfacePresentModesKHR(physical_device, surface, &avail_count, avail_modes.Data); - //for (uint32_t avail_i = 0; avail_i < avail_count; avail_i++) - // printf("[vulkan] avail_modes[%d] = %d\n", avail_i, avail_modes[avail_i]); - - for (int request_i = 0; request_i < request_modes_count; request_i++) - for (uint32_t avail_i = 0; avail_i < avail_count; avail_i++) - if (request_modes[request_i] == avail_modes[avail_i]) - return request_modes[request_i]; - - return VK_PRESENT_MODE_FIFO_KHR; // Always available -} - -void ImGui_ImplVulkanH_CreateWindowCommandBuffers(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, uint32_t queue_family, const VkAllocationCallbacks* allocator) -{ - IM_ASSERT(physical_device != VK_NULL_HANDLE && device != VK_NULL_HANDLE); - IM_UNUSED(physical_device); - - // Create Command Buffers - VkResult err; - for (uint32_t i = 0; i < wd->ImageCount; i++) - { - ImGui_ImplVulkanH_Frame* fd = &wd->Frames[i]; - { - VkCommandPoolCreateInfo info = {}; - info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; - info.flags = 0; - info.queueFamilyIndex = queue_family; - err = vkCreateCommandPool(device, &info, allocator, &fd->CommandPool); - check_vk_result(err); - } - { - VkCommandBufferAllocateInfo info = {}; - info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; - info.commandPool = fd->CommandPool; - info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; - info.commandBufferCount = 1; - err = vkAllocateCommandBuffers(device, &info, &fd->CommandBuffer); - check_vk_result(err); - } - { - VkFenceCreateInfo info = {}; - info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; - info.flags = VK_FENCE_CREATE_SIGNALED_BIT; - err = vkCreateFence(device, &info, allocator, &fd->Fence); - check_vk_result(err); - } - } - - for (uint32_t i = 0; i < wd->SemaphoreCount; i++) - { - ImGui_ImplVulkanH_FrameSemaphores* fsd = &wd->FrameSemaphores[i]; - { - VkSemaphoreCreateInfo info = {}; - info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; - err = vkCreateSemaphore(device, &info, allocator, &fsd->ImageAcquiredSemaphore); - check_vk_result(err); - err = vkCreateSemaphore(device, &info, allocator, &fsd->RenderCompleteSemaphore); - check_vk_result(err); - } - } -} - -int ImGui_ImplVulkanH_GetMinImageCountFromPresentMode(VkPresentModeKHR present_mode) -{ - if (present_mode == VK_PRESENT_MODE_MAILBOX_KHR) - return 3; - if (present_mode == VK_PRESENT_MODE_FIFO_KHR || present_mode == VK_PRESENT_MODE_FIFO_RELAXED_KHR) - return 2; - if (present_mode == VK_PRESENT_MODE_IMMEDIATE_KHR) - return 1; - IM_ASSERT(0); - return 1; -} - -// Also destroy old swap chain and in-flight frames data, if any. -void ImGui_ImplVulkanH_CreateWindowSwapChain(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, const VkAllocationCallbacks* allocator, int w, int h, uint32_t min_image_count) -{ - VkResult err; - VkSwapchainKHR old_swapchain = wd->Swapchain; - wd->Swapchain = VK_NULL_HANDLE; - err = vkDeviceWaitIdle(device); - check_vk_result(err); - - // We don't use ImGui_ImplVulkanH_DestroyWindow() because we want to preserve the old swapchain to create the new one. - // Destroy old Framebuffer - for (uint32_t i = 0; i < wd->ImageCount; i++) - ImGui_ImplVulkanH_DestroyFrame(device, &wd->Frames[i], allocator); - for (uint32_t i = 0; i < wd->SemaphoreCount; i++) - ImGui_ImplVulkanH_DestroyFrameSemaphores(device, &wd->FrameSemaphores[i], allocator); - IM_FREE(wd->Frames); - IM_FREE(wd->FrameSemaphores); - wd->Frames = nullptr; - wd->FrameSemaphores = nullptr; - wd->ImageCount = 0; - if (wd->RenderPass) - vkDestroyRenderPass(device, wd->RenderPass, allocator); - - // If min image count was not specified, request different count of images dependent on selected present mode - if (min_image_count == 0) - min_image_count = ImGui_ImplVulkanH_GetMinImageCountFromPresentMode(wd->PresentMode); - - // Create Swapchain - { - VkSwapchainCreateInfoKHR info = {}; - info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; - info.surface = wd->Surface; - info.minImageCount = min_image_count; - info.imageFormat = wd->SurfaceFormat.format; - info.imageColorSpace = wd->SurfaceFormat.colorSpace; - info.imageArrayLayers = 1; - info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; - info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; // Assume that graphics family == present family - info.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; - info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; - info.presentMode = wd->PresentMode; - info.clipped = VK_TRUE; - info.oldSwapchain = old_swapchain; - VkSurfaceCapabilitiesKHR cap; - err = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physical_device, wd->Surface, &cap); - check_vk_result(err); - if (info.minImageCount < cap.minImageCount) - info.minImageCount = cap.minImageCount; - else if (cap.maxImageCount != 0 && info.minImageCount > cap.maxImageCount) - info.minImageCount = cap.maxImageCount; - - if (cap.currentExtent.width == 0xffffffff) - { - info.imageExtent.width = wd->Width = w; - info.imageExtent.height = wd->Height = h; - } - else - { - info.imageExtent.width = wd->Width = cap.currentExtent.width; - info.imageExtent.height = wd->Height = cap.currentExtent.height; - } - err = vkCreateSwapchainKHR(device, &info, allocator, &wd->Swapchain); - check_vk_result(err); - err = vkGetSwapchainImagesKHR(device, wd->Swapchain, &wd->ImageCount, nullptr); - check_vk_result(err); - VkImage backbuffers[16] = {}; - IM_ASSERT(wd->ImageCount >= min_image_count); - IM_ASSERT(wd->ImageCount < IM_ARRAYSIZE(backbuffers)); - err = vkGetSwapchainImagesKHR(device, wd->Swapchain, &wd->ImageCount, backbuffers); - check_vk_result(err); - - IM_ASSERT(wd->Frames == nullptr && wd->FrameSemaphores == nullptr); - wd->SemaphoreCount = wd->ImageCount + 1; - wd->Frames = (ImGui_ImplVulkanH_Frame*)IM_ALLOC(sizeof(ImGui_ImplVulkanH_Frame) * wd->ImageCount); - wd->FrameSemaphores = (ImGui_ImplVulkanH_FrameSemaphores*)IM_ALLOC(sizeof(ImGui_ImplVulkanH_FrameSemaphores) * wd->SemaphoreCount); - memset((void*)wd->Frames, 0, sizeof(wd->Frames[0]) * wd->ImageCount); - memset((void*)wd->FrameSemaphores, 0, sizeof(wd->FrameSemaphores[0]) * wd->SemaphoreCount); - for (uint32_t i = 0; i < wd->ImageCount; i++) - wd->Frames[i].Backbuffer = backbuffers[i]; - } - if (old_swapchain) - vkDestroySwapchainKHR(device, old_swapchain, allocator); - - // Create the Render Pass - if (wd->UseDynamicRendering == false) - { - VkAttachmentDescription attachment = {}; - attachment.format = wd->SurfaceFormat.format; - attachment.samples = VK_SAMPLE_COUNT_1_BIT; - attachment.loadOp = wd->ClearEnable ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_DONT_CARE; - attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; - attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - attachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; - VkAttachmentReference color_attachment = {}; - color_attachment.attachment = 0; - color_attachment.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - VkSubpassDescription subpass = {}; - subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; - subpass.colorAttachmentCount = 1; - subpass.pColorAttachments = &color_attachment; - VkSubpassDependency dependency = {}; - dependency.srcSubpass = VK_SUBPASS_EXTERNAL; - dependency.dstSubpass = 0; - dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - dependency.srcAccessMask = 0; - dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - VkRenderPassCreateInfo info = {}; - info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; - info.attachmentCount = 1; - info.pAttachments = &attachment; - info.subpassCount = 1; - info.pSubpasses = &subpass; - info.dependencyCount = 1; - info.pDependencies = &dependency; - err = vkCreateRenderPass(device, &info, allocator, &wd->RenderPass); - check_vk_result(err); - - // We do not create a pipeline by default as this is also used by examples' main.cpp, - // but secondary viewport in multi-viewport mode may want to create one with: - //ImGui_ImplVulkan_CreatePipeline(device, allocator, VK_NULL_HANDLE, wd->RenderPass, VK_SAMPLE_COUNT_1_BIT, &wd->Pipeline, v->Subpass); - } - - // Create The Image Views - { - VkImageViewCreateInfo info = {}; - info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - info.viewType = VK_IMAGE_VIEW_TYPE_2D; - info.format = wd->SurfaceFormat.format; - info.components.r = VK_COMPONENT_SWIZZLE_R; - info.components.g = VK_COMPONENT_SWIZZLE_G; - info.components.b = VK_COMPONENT_SWIZZLE_B; - info.components.a = VK_COMPONENT_SWIZZLE_A; - VkImageSubresourceRange image_range = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }; - info.subresourceRange = image_range; - for (uint32_t i = 0; i < wd->ImageCount; i++) - { - ImGui_ImplVulkanH_Frame* fd = &wd->Frames[i]; - info.image = fd->Backbuffer; - err = vkCreateImageView(device, &info, allocator, &fd->BackbufferView); - check_vk_result(err); - } - } - - // Create Framebuffer - if (wd->UseDynamicRendering == false) - { - VkImageView attachment[1]; - VkFramebufferCreateInfo info = {}; - info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; - info.renderPass = wd->RenderPass; - info.attachmentCount = 1; - info.pAttachments = attachment; - info.width = wd->Width; - info.height = wd->Height; - info.layers = 1; - for (uint32_t i = 0; i < wd->ImageCount; i++) - { - ImGui_ImplVulkanH_Frame* fd = &wd->Frames[i]; - attachment[0] = fd->BackbufferView; - err = vkCreateFramebuffer(device, &info, allocator, &fd->Framebuffer); - check_vk_result(err); - } - } -} - -// Create or resize window -void ImGui_ImplVulkanH_CreateOrResizeWindow(VkInstance instance, VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, uint32_t queue_family, const VkAllocationCallbacks* allocator, int width, int height, uint32_t min_image_count) -{ - IM_ASSERT(g_FunctionsLoaded && "Need to call ImGui_ImplVulkan_LoadFunctions() if IMGUI_IMPL_VULKAN_NO_PROTOTYPES or VK_NO_PROTOTYPES are set!"); - (void)instance; - ImGui_ImplVulkanH_CreateWindowSwapChain(physical_device, device, wd, allocator, width, height, min_image_count); - //ImGui_ImplVulkan_CreatePipeline(device, allocator, VK_NULL_HANDLE, wd->RenderPass, VK_SAMPLE_COUNT_1_BIT, &wd->Pipeline, g_VulkanInitInfo.Subpass); - ImGui_ImplVulkanH_CreateWindowCommandBuffers(physical_device, device, wd, queue_family, allocator); -} - -void ImGui_ImplVulkanH_DestroyWindow(VkInstance instance, VkDevice device, ImGui_ImplVulkanH_Window* wd, const VkAllocationCallbacks* allocator) -{ - vkDeviceWaitIdle(device); // FIXME: We could wait on the Queue if we had the queue in wd-> (otherwise VulkanH functions can't use globals) - //vkQueueWaitIdle(bd->Queue); - - for (uint32_t i = 0; i < wd->ImageCount; i++) - ImGui_ImplVulkanH_DestroyFrame(device, &wd->Frames[i], allocator); - for (uint32_t i = 0; i < wd->SemaphoreCount; i++) - ImGui_ImplVulkanH_DestroyFrameSemaphores(device, &wd->FrameSemaphores[i], allocator); - IM_FREE(wd->Frames); - IM_FREE(wd->FrameSemaphores); - wd->Frames = nullptr; - wd->FrameSemaphores = nullptr; - vkDestroyRenderPass(device, wd->RenderPass, allocator); - vkDestroySwapchainKHR(device, wd->Swapchain, allocator); - vkDestroySurfaceKHR(instance, wd->Surface, allocator); - - *wd = ImGui_ImplVulkanH_Window(); -} - -void ImGui_ImplVulkanH_DestroyFrame(VkDevice device, ImGui_ImplVulkanH_Frame* fd, const VkAllocationCallbacks* allocator) -{ - vkDestroyFence(device, fd->Fence, allocator); - vkFreeCommandBuffers(device, fd->CommandPool, 1, &fd->CommandBuffer); - vkDestroyCommandPool(device, fd->CommandPool, allocator); - fd->Fence = VK_NULL_HANDLE; - fd->CommandBuffer = VK_NULL_HANDLE; - fd->CommandPool = VK_NULL_HANDLE; - - vkDestroyImageView(device, fd->BackbufferView, allocator); - vkDestroyFramebuffer(device, fd->Framebuffer, allocator); -} - -void ImGui_ImplVulkanH_DestroyFrameSemaphores(VkDevice device, ImGui_ImplVulkanH_FrameSemaphores* fsd, const VkAllocationCallbacks* allocator) -{ - vkDestroySemaphore(device, fsd->ImageAcquiredSemaphore, allocator); - vkDestroySemaphore(device, fsd->RenderCompleteSemaphore, allocator); - fsd->ImageAcquiredSemaphore = fsd->RenderCompleteSemaphore = VK_NULL_HANDLE; -} - -void ImGui_ImplVulkanH_DestroyAllViewportsRenderBuffers(VkDevice device, const VkAllocationCallbacks* allocator) -{ - ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); - for (int n = 0; n < platform_io.Viewports.Size; n++) - if (ImGui_ImplVulkan_ViewportData* vd = (ImGui_ImplVulkan_ViewportData*)platform_io.Viewports[n]->RendererUserData) - ImGui_ImplVulkan_DestroyWindowRenderBuffers(device, &vd->RenderBuffers, allocator); -} - -//-------------------------------------------------------------------------------------------------------- -// MULTI-VIEWPORT / PLATFORM INTERFACE SUPPORT -// This is an _advanced_ and _optional_ feature, allowing the backend to create and handle multiple viewports simultaneously. -// If you are new to dear imgui or creating a new binding for dear imgui, it is recommended that you completely ignore this section first.. -//-------------------------------------------------------------------------------------------------------- - -static void ImGui_ImplVulkan_CreateWindow(ImGuiViewport* viewport) -{ - ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); - ImGui_ImplVulkan_ViewportData* vd = IM_NEW(ImGui_ImplVulkan_ViewportData)(); - viewport->RendererUserData = vd; - ImGui_ImplVulkanH_Window* wd = &vd->Window; - ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo; - - // Create surface - ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); - VkResult err = (VkResult)platform_io.Platform_CreateVkSurface(viewport, (ImU64)v->Instance, (const void*)v->Allocator, (ImU64*)&wd->Surface); - check_vk_result(err); - - // Check for WSI support - VkBool32 res; - vkGetPhysicalDeviceSurfaceSupportKHR(v->PhysicalDevice, v->QueueFamily, wd->Surface, &res); - if (res != VK_TRUE) - { - IM_ASSERT(0); // Error: no WSI support on physical device - return; - } - - // Select Surface Format - ImVector requestSurfaceImageFormats; -#ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING - for (uint32_t n = 0; n < v->PipelineRenderingCreateInfo.colorAttachmentCount; n++) - requestSurfaceImageFormats.push_back(v->PipelineRenderingCreateInfo.pColorAttachmentFormats[n]); -#endif - const VkFormat defaultFormats[] = { VK_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_B8G8R8_UNORM, VK_FORMAT_R8G8B8_UNORM }; - for (VkFormat format : defaultFormats) - requestSurfaceImageFormats.push_back(format); - - const VkColorSpaceKHR requestSurfaceColorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR; - wd->SurfaceFormat = ImGui_ImplVulkanH_SelectSurfaceFormat(v->PhysicalDevice, wd->Surface, requestSurfaceImageFormats.Data, (size_t)requestSurfaceImageFormats.Size, requestSurfaceColorSpace); - - // Select Present Mode - // FIXME-VULKAN: Even thought mailbox seems to get us maximum framerate with a single window, it halves framerate with a second window etc. (w/ Nvidia and SDK 1.82.1) - VkPresentModeKHR present_modes[] = { VK_PRESENT_MODE_MAILBOX_KHR, VK_PRESENT_MODE_IMMEDIATE_KHR, VK_PRESENT_MODE_FIFO_KHR }; - wd->PresentMode = ImGui_ImplVulkanH_SelectPresentMode(v->PhysicalDevice, wd->Surface, &present_modes[0], IM_ARRAYSIZE(present_modes)); - //printf("[vulkan] Secondary window selected PresentMode = %d\n", wd->PresentMode); - - // Create SwapChain, RenderPass, Framebuffer, etc. - wd->ClearEnable = (viewport->Flags & ImGuiViewportFlags_NoRendererClear) ? false : true; - wd->UseDynamicRendering = v->UseDynamicRendering; - ImGui_ImplVulkanH_CreateOrResizeWindow(v->Instance, v->PhysicalDevice, v->Device, wd, v->QueueFamily, v->Allocator, (int)viewport->Size.x, (int)viewport->Size.y, v->MinImageCount); - vd->WindowOwned = true; - - // Create pipeline (shared by all secondary viewports) - if (bd->PipelineForViewports == VK_NULL_HANDLE) - ImGui_ImplVulkan_CreatePipeline(v->Device, v->Allocator, VK_NULL_HANDLE, wd->RenderPass, VK_SAMPLE_COUNT_1_BIT, &bd->PipelineForViewports, 0); -} - -static void ImGui_ImplVulkan_DestroyWindow(ImGuiViewport* viewport) -{ - // The main viewport (owned by the application) will always have RendererUserData == 0 since we didn't create the data for it. - ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); - if (ImGui_ImplVulkan_ViewportData* vd = (ImGui_ImplVulkan_ViewportData*)viewport->RendererUserData) - { - ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo; - if (vd->WindowOwned) - ImGui_ImplVulkanH_DestroyWindow(v->Instance, v->Device, &vd->Window, v->Allocator); - ImGui_ImplVulkan_DestroyWindowRenderBuffers(v->Device, &vd->RenderBuffers, v->Allocator); - IM_DELETE(vd); - } - viewport->RendererUserData = nullptr; -} - -static void ImGui_ImplVulkan_SetWindowSize(ImGuiViewport* viewport, ImVec2 size) -{ - ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); - ImGui_ImplVulkan_ViewportData* vd = (ImGui_ImplVulkan_ViewportData*)viewport->RendererUserData; - if (vd == nullptr) // This is nullptr for the main viewport (which is left to the user/app to handle) - return; - ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo; - vd->Window.ClearEnable = (viewport->Flags & ImGuiViewportFlags_NoRendererClear) ? false : true; - ImGui_ImplVulkanH_CreateOrResizeWindow(v->Instance, v->PhysicalDevice, v->Device, &vd->Window, v->QueueFamily, v->Allocator, (int)size.x, (int)size.y, v->MinImageCount); -} - -static void ImGui_ImplVulkan_RenderWindow(ImGuiViewport* viewport, void*) -{ - ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); - ImGui_ImplVulkan_ViewportData* vd = (ImGui_ImplVulkan_ViewportData*)viewport->RendererUserData; - ImGui_ImplVulkanH_Window* wd = &vd->Window; - ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo; - VkResult err; - - if (vd->SwapChainNeedRebuild) - { - ImGui_ImplVulkanH_CreateOrResizeWindow(v->Instance, v->PhysicalDevice, v->Device, wd, v->QueueFamily, v->Allocator, (int)viewport->Size.x, (int)viewport->Size.y, v->MinImageCount); - vd->SwapChainNeedRebuild = false; - } - - ImGui_ImplVulkanH_Frame* fd = &wd->Frames[wd->FrameIndex]; - ImGui_ImplVulkanH_FrameSemaphores* fsd = &wd->FrameSemaphores[wd->SemaphoreIndex]; - { - { - err = vkAcquireNextImageKHR(v->Device, wd->Swapchain, UINT64_MAX, fsd->ImageAcquiredSemaphore, VK_NULL_HANDLE, &wd->FrameIndex); - if (err == VK_ERROR_OUT_OF_DATE_KHR) - { - // Since we are not going to swap this frame anyway, it's ok that recreation happens on next frame. - vd->SwapChainNeedRebuild = true; - return; - } - check_vk_result(err); - fd = &wd->Frames[wd->FrameIndex]; - } - for (;;) - { - err = vkWaitForFences(v->Device, 1, &fd->Fence, VK_TRUE, 100); - if (err == VK_SUCCESS) break; - if (err == VK_TIMEOUT) continue; - check_vk_result(err); - } - { - err = vkResetCommandPool(v->Device, fd->CommandPool, 0); - check_vk_result(err); - VkCommandBufferBeginInfo info = {}; - info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - info.flags |= VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; - err = vkBeginCommandBuffer(fd->CommandBuffer, &info); - check_vk_result(err); - } - { - ImVec4 clear_color = ImVec4(0.0f, 0.0f, 0.0f, 1.0f); - memcpy(&wd->ClearValue.color.float32[0], &clear_color, 4 * sizeof(float)); - } -#ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING - if (v->UseDynamicRendering) - { - // Transition swapchain image to a layout suitable for drawing. - VkImageMemoryBarrier barrier = {}; - barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - barrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; - barrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - barrier.image = fd->Backbuffer; - barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - barrier.subresourceRange.levelCount = 1; - barrier.subresourceRange.layerCount = 1; - vkCmdPipelineBarrier(fd->CommandBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0, 0, nullptr, 0, nullptr, 1, &barrier); - - VkRenderingAttachmentInfo attachmentInfo = {}; - attachmentInfo.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO_KHR; - attachmentInfo.imageView = fd->BackbufferView; - attachmentInfo.imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - attachmentInfo.resolveMode = VK_RESOLVE_MODE_NONE; - attachmentInfo.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - attachmentInfo.storeOp = VK_ATTACHMENT_STORE_OP_STORE; - attachmentInfo.clearValue = wd->ClearValue; - - VkRenderingInfo renderingInfo = {}; - renderingInfo.sType = VK_STRUCTURE_TYPE_RENDERING_INFO_KHR; - renderingInfo.renderArea.extent.width = wd->Width; - renderingInfo.renderArea.extent.height = wd->Height; - renderingInfo.layerCount = 1; - renderingInfo.viewMask = 0; - renderingInfo.colorAttachmentCount = 1; - renderingInfo.pColorAttachments = &attachmentInfo; - - ImGuiImplVulkanFuncs_vkCmdBeginRenderingKHR(fd->CommandBuffer, &renderingInfo); - } - else -#endif - { - VkRenderPassBeginInfo info = {}; - info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; - info.renderPass = wd->RenderPass; - info.framebuffer = fd->Framebuffer; - info.renderArea.extent.width = wd->Width; - info.renderArea.extent.height = wd->Height; - info.clearValueCount = (viewport->Flags & ImGuiViewportFlags_NoRendererClear) ? 0 : 1; - info.pClearValues = (viewport->Flags & ImGuiViewportFlags_NoRendererClear) ? nullptr : &wd->ClearValue; - vkCmdBeginRenderPass(fd->CommandBuffer, &info, VK_SUBPASS_CONTENTS_INLINE); - } - } - - ImGui_ImplVulkan_RenderDrawData(viewport->DrawData, fd->CommandBuffer, bd->PipelineForViewports); - - { -#ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING - if (v->UseDynamicRendering) - { - ImGuiImplVulkanFuncs_vkCmdEndRenderingKHR(fd->CommandBuffer); - - // Transition image to a layout suitable for presentation - VkImageMemoryBarrier barrier = {}; - barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - barrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - barrier.oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - barrier.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; - barrier.image = fd->Backbuffer; - barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - barrier.subresourceRange.levelCount = 1; - barrier.subresourceRange.layerCount = 1; - vkCmdPipelineBarrier(fd->CommandBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, nullptr, 0, nullptr, 1, &barrier); - } - else -#endif - { - vkCmdEndRenderPass(fd->CommandBuffer); - } - { - VkPipelineStageFlags wait_stage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - VkSubmitInfo info = {}; - info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - info.waitSemaphoreCount = 1; - info.pWaitSemaphores = &fsd->ImageAcquiredSemaphore; - info.pWaitDstStageMask = &wait_stage; - info.commandBufferCount = 1; - info.pCommandBuffers = &fd->CommandBuffer; - info.signalSemaphoreCount = 1; - info.pSignalSemaphores = &fsd->RenderCompleteSemaphore; - - err = vkEndCommandBuffer(fd->CommandBuffer); - check_vk_result(err); - err = vkResetFences(v->Device, 1, &fd->Fence); - check_vk_result(err); - err = vkQueueSubmit(v->Queue, 1, &info, fd->Fence); - check_vk_result(err); - } - } -} - -static void ImGui_ImplVulkan_SwapBuffers(ImGuiViewport* viewport, void*) -{ - ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); - ImGui_ImplVulkan_ViewportData* vd = (ImGui_ImplVulkan_ViewportData*)viewport->RendererUserData; - ImGui_ImplVulkanH_Window* wd = &vd->Window; - ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo; - - if (vd->SwapChainNeedRebuild) // Frame data became invalid in the middle of rendering - return; - - VkResult err; - uint32_t present_index = wd->FrameIndex; - - ImGui_ImplVulkanH_FrameSemaphores* fsd = &wd->FrameSemaphores[wd->SemaphoreIndex]; - VkPresentInfoKHR info = {}; - info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; - info.waitSemaphoreCount = 1; - info.pWaitSemaphores = &fsd->RenderCompleteSemaphore; - info.swapchainCount = 1; - info.pSwapchains = &wd->Swapchain; - info.pImageIndices = &present_index; - err = vkQueuePresentKHR(v->Queue, &info); - if (err == VK_ERROR_OUT_OF_DATE_KHR || err == VK_SUBOPTIMAL_KHR) - { - vd->SwapChainNeedRebuild = true; - if (err == VK_ERROR_OUT_OF_DATE_KHR) - return; - } - else - { - check_vk_result(err); - } - - wd->FrameIndex = (wd->FrameIndex + 1) % wd->ImageCount; // This is for the next vkWaitForFences() - wd->SemaphoreIndex = (wd->SemaphoreIndex + 1) % wd->SemaphoreCount; // Now we can use the next set of semaphores -} - -void ImGui_ImplVulkan_InitMultiViewportSupport() -{ - ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); - if (ImGui::GetIO().ConfigFlags & ImGuiConfigFlags_ViewportsEnable) - IM_ASSERT(platform_io.Platform_CreateVkSurface != nullptr && "Platform needs to setup the CreateVkSurface handler."); - platform_io.Renderer_CreateWindow = ImGui_ImplVulkan_CreateWindow; - platform_io.Renderer_DestroyWindow = ImGui_ImplVulkan_DestroyWindow; - platform_io.Renderer_SetWindowSize = ImGui_ImplVulkan_SetWindowSize; - platform_io.Renderer_RenderWindow = ImGui_ImplVulkan_RenderWindow; - platform_io.Renderer_SwapBuffers = ImGui_ImplVulkan_SwapBuffers; -} - -void ImGui_ImplVulkan_ShutdownMultiViewportSupport() -{ - ImGui::DestroyPlatformWindows(); -} - -//----------------------------------------------------------------------------- - -#endif // #ifndef IMGUI_DISABLE diff --git a/engine/modules/render/vulkan/include/imgui/imgui_impl_vulkan.h b/engine/modules/render/vulkan/include/imgui/imgui_impl_vulkan.h deleted file mode 100644 index 280044e..0000000 --- a/engine/modules/render/vulkan/include/imgui/imgui_impl_vulkan.h +++ /dev/null @@ -1,211 +0,0 @@ -// dear imgui: Renderer Backend for Vulkan -// This needs to be used along with a Platform Backend (e.g. GLFW, SDL, Win32, custom..) - -// Implemented features: -// [x] Renderer: User texture binding. Use 'VkDescriptorSet' as ImTextureID. Read the FAQ about ImTextureID! See https://github.com/ocornut/imgui/pull/914 for discussions. -// [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices. -// [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'. -// [x] Renderer: Multi-viewport / platform windows. With issues (flickering when creating a new viewport). - -// The aim of imgui_impl_vulkan.h/.cpp is to be usable in your engine without any modification. -// IF YOU FEEL YOU NEED TO MAKE ANY CHANGE TO THIS CODE, please share them and your feedback at https://github.com/ocornut/imgui/ - -// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. -// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. -// Learn about Dear ImGui: -// - FAQ https://dearimgui.com/faq -// - Getting Started https://dearimgui.com/getting-started -// - Documentation https://dearimgui.com/docs (same as your local docs/ folder). -// - Introduction, links and more at the top of imgui.cpp - -// Important note to the reader who wish to integrate imgui_impl_vulkan.cpp/.h in their own engine/app. -// - Common ImGui_ImplVulkan_XXX functions and structures are used to interface with imgui_impl_vulkan.cpp/.h. -// You will use those if you want to use this rendering backend in your engine/app. -// - Helper ImGui_ImplVulkanH_XXX functions and structures are only used by this example (main.cpp) and by -// the backend itself (imgui_impl_vulkan.cpp), but should PROBABLY NOT be used by your own engine/app code. -// Read comments in imgui_impl_vulkan.h. - -#pragma once -#ifndef IMGUI_DISABLE -#include "imgui.h" // IMGUI_IMPL_API - -// [Configuration] in order to use a custom Vulkan function loader: -// (1) You'll need to disable default Vulkan function prototypes. -// We provide a '#define IMGUI_IMPL_VULKAN_NO_PROTOTYPES' convenience configuration flag. -// In order to make sure this is visible from the imgui_impl_vulkan.cpp compilation unit: -// - Add '#define IMGUI_IMPL_VULKAN_NO_PROTOTYPES' in your imconfig.h file -// - Or as a compilation flag in your build system -// - Or uncomment here (not recommended because you'd be modifying imgui sources!) -// - Do not simply add it in a .cpp file! -// (2) Call ImGui_ImplVulkan_LoadFunctions() before ImGui_ImplVulkan_Init() with your custom function. -// If you have no idea what this is, leave it alone! -//#define IMGUI_IMPL_VULKAN_NO_PROTOTYPES - -// Convenience support for Volk -// (you can also technically use IMGUI_IMPL_VULKAN_NO_PROTOTYPES + wrap Volk via ImGui_ImplVulkan_LoadFunctions().) -//#define IMGUI_IMPL_VULKAN_USE_VOLK - -#if defined(IMGUI_IMPL_VULKAN_NO_PROTOTYPES) && !defined(VK_NO_PROTOTYPES) -#define VK_NO_PROTOTYPES -#endif -#if defined(VK_USE_PLATFORM_WIN32_KHR) && !defined(NOMINMAX) -#define NOMINMAX -#endif - -// Vulkan includes -#ifdef IMGUI_IMPL_VULKAN_USE_VOLK -#include -#else -#include -#endif -#if defined(VK_VERSION_1_3) || defined(VK_KHR_dynamic_rendering) -#define IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING -#endif - -// Initialization data, for ImGui_ImplVulkan_Init() -// [Please zero-clear before use!] -// - About descriptor pool: -// - A VkDescriptorPool should be created with VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, -// and must contain a pool size large enough to hold a small number of VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER descriptors. -// - As an convenience, by setting DescriptorPoolSize > 0 the backend will create one for you. -// - Current version of the backend use 1 descriptor for the font atlas + as many as additional calls done to ImGui_ImplVulkan_AddTexture(). -// - It is expected that as early as Q1 2025 the backend will use a few more descriptors, so aim at 10 + number of desierd calls to ImGui_ImplVulkan_AddTexture(). -// - About dynamic rendering: -// - When using dynamic rendering, set UseDynamicRendering=true and fill PipelineRenderingCreateInfo structure. -struct ImGui_ImplVulkan_InitInfo -{ - VkInstance Instance; - VkPhysicalDevice PhysicalDevice; - VkDevice Device; - uint32_t QueueFamily; - VkQueue Queue; - VkDescriptorPool DescriptorPool; // See requirements in note above; ignored if using DescriptorPoolSize > 0 - VkRenderPass RenderPass; // Ignored if using dynamic rendering - uint32_t MinImageCount; // >= 2 - uint32_t ImageCount; // >= MinImageCount - VkSampleCountFlagBits MSAASamples; // 0 defaults to VK_SAMPLE_COUNT_1_BIT - - // (Optional) - VkPipelineCache PipelineCache; - uint32_t Subpass; - - // (Optional) Set to create internal descriptor pool instead of using DescriptorPool - uint32_t DescriptorPoolSize; - - // (Optional) Dynamic Rendering - // Need to explicitly enable VK_KHR_dynamic_rendering extension to use this, even for Vulkan 1.3. - bool UseDynamicRendering; -#ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING - VkPipelineRenderingCreateInfoKHR PipelineRenderingCreateInfo; -#endif - - // (Optional) Allocation, Debugging - const VkAllocationCallbacks* Allocator; - void (*CheckVkResultFn)(VkResult err); - VkDeviceSize MinAllocationSize; // Minimum allocation size. Set to 1024*1024 to satisfy zealous best practices validation layer and waste a little memory. -}; - -// Follow "Getting Started" link and check examples/ folder to learn about using backends! -IMGUI_IMPL_API bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info); -IMGUI_IMPL_API void ImGui_ImplVulkan_Shutdown(); -IMGUI_IMPL_API void ImGui_ImplVulkan_NewFrame(); -IMGUI_IMPL_API void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer command_buffer, VkPipeline pipeline = VK_NULL_HANDLE); -IMGUI_IMPL_API bool ImGui_ImplVulkan_CreateFontsTexture(); -IMGUI_IMPL_API void ImGui_ImplVulkan_DestroyFontsTexture(); -IMGUI_IMPL_API void ImGui_ImplVulkan_SetMinImageCount(uint32_t min_image_count); // To override MinImageCount after initialization (e.g. if swap chain is recreated) - -// Register a texture (VkDescriptorSet == ImTextureID) -// FIXME: This is experimental in the sense that we are unsure how to best design/tackle this problem -// Please post to https://github.com/ocornut/imgui/pull/914 if you have suggestions. -IMGUI_IMPL_API VkDescriptorSet ImGui_ImplVulkan_AddTexture(VkSampler sampler, VkImageView image_view, VkImageLayout image_layout); -IMGUI_IMPL_API void ImGui_ImplVulkan_RemoveTexture(VkDescriptorSet descriptor_set); - -// Optional: load Vulkan functions with a custom function loader -// This is only useful with IMGUI_IMPL_VULKAN_NO_PROTOTYPES / VK_NO_PROTOTYPES -IMGUI_IMPL_API bool ImGui_ImplVulkan_LoadFunctions(PFN_vkVoidFunction(*loader_func)(const char* function_name, void* user_data), void* user_data = nullptr); - -// [BETA] Selected render state data shared with callbacks. -// This is temporarily stored in GetPlatformIO().Renderer_RenderState during the ImGui_ImplVulkan_RenderDrawData() call. -// (Please open an issue if you feel you need access to more data) -struct ImGui_ImplVulkan_RenderState -{ - VkCommandBuffer CommandBuffer; - VkPipeline Pipeline; - VkPipelineLayout PipelineLayout; -}; - -//------------------------------------------------------------------------- -// Internal / Miscellaneous Vulkan Helpers -// (Used by example's main.cpp. Used by multi-viewport features. PROBABLY NOT used by your own engine/app.) -//------------------------------------------------------------------------- -// You probably do NOT need to use or care about those functions. -// Those functions only exist because: -// 1) they facilitate the readability and maintenance of the multiple main.cpp examples files. -// 2) the multi-viewport / platform window implementation needs them internally. -// Generally we avoid exposing any kind of superfluous high-level helpers in the bindings, -// but it is too much code to duplicate everywhere so we exceptionally expose them. -// -// Your engine/app will likely _already_ have code to setup all that stuff (swap chain, render pass, frame buffers, etc.). -// You may read this code to learn about Vulkan, but it is recommended you use you own custom tailored code to do equivalent work. -// (The ImGui_ImplVulkanH_XXX functions do not interact with any of the state used by the regular ImGui_ImplVulkan_XXX functions) -//------------------------------------------------------------------------- - -struct ImGui_ImplVulkanH_Frame; -struct ImGui_ImplVulkanH_Window; - -// Helpers -IMGUI_IMPL_API void ImGui_ImplVulkanH_CreateOrResizeWindow(VkInstance instance, VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, uint32_t queue_family, const VkAllocationCallbacks* allocator, int w, int h, uint32_t min_image_count); -IMGUI_IMPL_API void ImGui_ImplVulkanH_DestroyWindow(VkInstance instance, VkDevice device, ImGui_ImplVulkanH_Window* wd, const VkAllocationCallbacks* allocator); -IMGUI_IMPL_API VkSurfaceFormatKHR ImGui_ImplVulkanH_SelectSurfaceFormat(VkPhysicalDevice physical_device, VkSurfaceKHR surface, const VkFormat* request_formats, int request_formats_count, VkColorSpaceKHR request_color_space); -IMGUI_IMPL_API VkPresentModeKHR ImGui_ImplVulkanH_SelectPresentMode(VkPhysicalDevice physical_device, VkSurfaceKHR surface, const VkPresentModeKHR* request_modes, int request_modes_count); -IMGUI_IMPL_API int ImGui_ImplVulkanH_GetMinImageCountFromPresentMode(VkPresentModeKHR present_mode); - -// Helper structure to hold the data needed by one rendering frame -// (Used by example's main.cpp. Used by multi-viewport features. Probably NOT used by your own engine/app.) -// [Please zero-clear before use!] -struct ImGui_ImplVulkanH_Frame -{ - VkCommandPool CommandPool; - VkCommandBuffer CommandBuffer; - VkFence Fence; - VkImage Backbuffer; - VkImageView BackbufferView; - VkFramebuffer Framebuffer; -}; - -struct ImGui_ImplVulkanH_FrameSemaphores -{ - VkSemaphore ImageAcquiredSemaphore; - VkSemaphore RenderCompleteSemaphore; -}; - -// Helper structure to hold the data needed by one rendering context into one OS window -// (Used by example's main.cpp. Used by multi-viewport features. Probably NOT used by your own engine/app.) -struct ImGui_ImplVulkanH_Window -{ - int Width; - int Height; - VkSwapchainKHR Swapchain; - VkSurfaceKHR Surface; - VkSurfaceFormatKHR SurfaceFormat; - VkPresentModeKHR PresentMode; - VkRenderPass RenderPass; - bool UseDynamicRendering; - bool ClearEnable; - VkClearValue ClearValue; - uint32_t FrameIndex; // Current frame being rendered to (0 <= FrameIndex < FrameInFlightCount) - uint32_t ImageCount; // Number of simultaneous in-flight frames (returned by vkGetSwapchainImagesKHR, usually derived from min_image_count) - uint32_t SemaphoreCount; // Number of simultaneous in-flight frames + 1, to be able to use it in vkAcquireNextImageKHR - uint32_t SemaphoreIndex; // Current set of swapchain wait semaphores we're using (needs to be distinct from per frame data) - ImGui_ImplVulkanH_Frame* Frames; - ImGui_ImplVulkanH_FrameSemaphores* FrameSemaphores; - - ImGui_ImplVulkanH_Window() - { - memset((void*)this, 0, sizeof(*this)); - PresentMode = (VkPresentModeKHR)~0; // Ensure we get an error if user doesn't set this. - ClearEnable = true; - } -}; - -#endif // #ifndef IMGUI_DISABLE diff --git a/engine/modules/render/vulkan/include/vkn/vulkan_api.h b/engine/modules/render/vulkan/include/vkn/vulkan_api.h index 0ba7732..387ab69 100644 --- a/engine/modules/render/vulkan/include/vkn/vulkan_api.h +++ b/engine/modules/render/vulkan/include/vkn/vulkan_api.h @@ -27,7 +27,7 @@ namespace vkn { table RenderPassNameCache; table FramebufferCache; public: - VulkanAPI(); + VulkanAPI(VulkanWindow* pWindow); void Init() override; void Shutdown() override; diff --git a/engine/modules/render/vulkan/include/vkn/vulkan_imgui_editor.h b/engine/modules/render/vulkan/include/vkn/vulkan_imgui_editor.h deleted file mode 100644 index 0eb38be..0000000 --- a/engine/modules/render/vulkan/include/vkn/vulkan_imgui_editor.h +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once -#include "render/editor_system.h" -#include "render/graph/frame_graph.h" -#include "vkn/vulkan_api.h" -namespace vkn { - using api::FrameGraph; - using api::RenderPassContext; - using api::RenderPassBuilder; - using api::RenderEditorContext; - class VulkanImguiEditor : public api::EditorSystem { - public: - void Initialize() override; - void Finalize() override; - - ImTextureID AddTexture(ImageViewPtr imageview, SamplerPtr sampler, ResourceState state) override; - - void Render(FrameGraph& graph, RenderEditorContext& ctx); - void OnBeginRenderFrame(FrameGraph& graph, uint32_t frame); - static VulkanImguiEditor* Ptr() { - return (VulkanImguiEditor*)api::EditorSystem::Ptr(); - }; - static void Setup(FrameGraph& graph, RenderPassBuilder& builder); - static void Execute(FrameGraph&, RenderPassContext&); - }; -} \ No newline at end of file diff --git a/engine/modules/render/vulkan/include/vkn/module.h b/engine/modules/render/vulkan/include/vkn/vulkan_module.h similarity index 70% rename from engine/modules/render/vulkan/include/vkn/module.h rename to engine/modules/render/vulkan/include/vkn/vulkan_module.h index 6d2a81c..30d78e9 100644 --- a/engine/modules/render/vulkan/include/vkn/module.h +++ b/engine/modules/render/vulkan/include/vkn/vulkan_module.h @@ -7,5 +7,4 @@ public: void OnUnload() override; void InitMetaData(void) override; }; -IMPLEMENT_DYNAMIC_MODULE(VULKAN_API, VulkanModule, vulkan) -#include ".vulkan/vulkan.plugin.inl" \ No newline at end of file +IMPLEMENT_DYNAMIC_MODULE(VULKAN_API, VulkanModule, vulkan) \ No newline at end of file diff --git a/engine/modules/render/vulkan/include/vkn/vulkan_window.h b/engine/modules/render/vulkan/include/vkn/vulkan_window.h index 4933826..33e2b10 100644 --- a/engine/modules/render/vulkan/include/vkn/vulkan_window.h +++ b/engine/modules/render/vulkan/include/vkn/vulkan_window.h @@ -16,7 +16,7 @@ namespace vkn { VkImageUsageFlags imageUsage; uint32_t maxFrameInFlightCount; VkExtent2D EnableImageExtent2D(VkSurfaceCapabilitiesKHR& capabilities); - static VulkanWindowArgs Default(); + static VulkanWindowArgs Default(uint32_t frames); }; class VulkanSwapchain { private: @@ -43,8 +43,7 @@ namespace vkn { void operator delete(void* p) {} public: using api::Window::Window; - using CreatePFN = decltype(&SDL_Vulkan_CreateSurface); - bool CreateRender(CreatePFN createPFN, VulkanWindowArgs& args); + bool CreateRender(VulkanWindowArgs& args); static VulkanWindow* Ptr() { return (VulkanWindow*)api::Window::Ptr(); } diff --git a/engine/modules/render/vulkan/src/vulkan_api.cpp b/engine/modules/render/vulkan/src/vulkan_api.cpp index 2177c3c..06e0f8c 100644 --- a/engine/modules/render/vulkan/src/vulkan_api.cpp +++ b/engine/modules/render/vulkan/src/vulkan_api.cpp @@ -11,8 +11,8 @@ #include "zlog.h" namespace vkn { using api::EventSystem; - VulkanAPI::VulkanAPI() : RenderAPI(new VulkanContext()) - , window(*VulkanWindow::Ptr()) + VulkanAPI::VulkanAPI(VulkanWindow* pWindow) : RenderAPI(new VulkanContext()) + , window(*pWindow) , backend(VulkanEngineName) { diff --git a/engine/modules/render/vulkan/src/vulkan_imgui_editor.cpp b/engine/modules/render/vulkan/src/vulkan_imgui_editor.cpp deleted file mode 100644 index 982a599..0000000 --- a/engine/modules/render/vulkan/src/vulkan_imgui_editor.cpp +++ /dev/null @@ -1,185 +0,0 @@ -#include "vkn/vulkan_imgui_editor.h" -#include "vkn/vulkan_window.h" -#include "vkn/vulkan_api_help.h" -#include "vkn/backend.h" -#include "vkn/wrapper/device.h" -#include "vkn/wrapper/instance.h" -#include "vkn/wrapper/queue.h" -#include "imgui/imgui_impl_vulkan.h" -#include "imgui/imgui_impl_sdl2.h" -#include "data/global.h" -#include "event/event_system.h" -#include "tinyimageformat/tinyimageformat_apis.h" -namespace vkn { - using namespace api; - static Name ImguiPassName{"ImguiPass"}; - static VkDescriptorPool g_DescriptorPool = VK_NULL_HANDLE; - // Vulkan的ImGui接入比较麻烦,参考教程: https://frguthmann.github.io/posts/vulkan_imgui/ - VkDescriptorPool CreateDescriptorPool(VkDevice device) { - VkDescriptorPoolSize pool_sizes[] = - { - { VK_DESCRIPTOR_TYPE_SAMPLER, 1000 }, - { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1000 }, - { VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1000 }, - { VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1000 }, - { VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, 1000 }, - { VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, 1000 }, - { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1000 }, - { VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1000 }, - { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1000 }, - { VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, 1000 }, - { VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, 1000 } - }; - VkDescriptorPoolCreateInfo pool_info = {}; - pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; - pool_info.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT; - pool_info.maxSets = 1000 * IM_ARRAYSIZE(pool_sizes); - pool_info.poolSizeCount = (uint32_t)IM_ARRAYSIZE(pool_sizes); - pool_info.pPoolSizes = pool_sizes; - VkDescriptorPool descriptorPool; - vkCreateDescriptorPool(device, &pool_info, VK_NULL_HANDLE, &descriptorPool); - return descriptorPool; - } - VkRenderPass CreateRenderPass(TinyImageFormat format, VkDevice device) { - VkAttachmentDescription colorAttachment = {}; - colorAttachment.format = (VkFormat)TinyImageFormat_ToVkFormat(format); - colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT; - colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; - colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - colorAttachment.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - colorAttachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; - - VkAttachmentReference colorAttachmentRef = {}; - colorAttachmentRef.attachment = 0; - colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - - VkSubpassDescription subpass = {}; - subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; - subpass.colorAttachmentCount = 1; - subpass.pColorAttachments = &colorAttachmentRef; - - VkSubpassDependency dependency = {}; - dependency.srcSubpass = VK_SUBPASS_EXTERNAL; - dependency.dstSubpass = 0; - dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - dependency.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - - VkRenderPassCreateInfo info = {}; - info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; - info.attachmentCount = 1; - info.pAttachments = &colorAttachment; - info.subpassCount = 1; - info.pSubpasses = &subpass; - info.dependencyCount = 1; - info.pDependencies = &dependency; - VkRenderPass renderPass; - if (vkCreateRenderPass(device, &info, VK_NULL_HANDLE, &renderPass) != VK_SUCCESS) - throw std::runtime_error("Could not create Dear ImGui's render pass"); - return renderPass; - } - void VulkanImguiEditor::Initialize() - { - VulkanAPI* API = VulkanAPI::Ptr(); - VulkanWindow* window = VulkanWindow::Ptr(); - Backend& backend = API->GetBackend(); - Queue* pQueue = backend.GetDevice().GetQueue(Queue::RenderQueue); - VkDescriptorPool descriptorPool = CreateDescriptorPool(backend.GetDevice().Ptr()); - TextureDesc surface = API->context.surface; - VkRenderPass renderPass = CreateRenderPass(surface.format, backend.GetDevice().Ptr()); - - ImGui_ImplVulkan_InitInfo init_info = {}; - init_info.Instance = backend.GetInstance().Ptr(); - init_info.PhysicalDevice = backend.GetDevice().GetPhysical(); - init_info.Device = backend.GetDevice().Ptr(); - init_info.QueueFamily = pQueue->QueueFamilyIndex(); - init_info.Queue = pQueue->Ptr(); - init_info.DescriptorPool = descriptorPool; - init_info.MinImageCount = 2; - init_info.ImageCount = API->context.frameCount; - init_info.RenderPass = renderPass; - init_info.PipelineCache = VK_NULL_HANDLE; - init_info.Subpass = 0; - init_info.MSAASamples = VK_SAMPLE_COUNT_1_BIT; - init_info.Allocator = VK_NULL_HANDLE; - ImGui_ImplVulkan_Init(&init_info); - API->SetRenderPassInfo(ImguiPassName, renderPass); - //gEngineConfig.IsRenderEditorSurface = true; - if (gEngineConfig.IsRenderEditorSurface) { - TextureDesc desc{}; - desc.width = 512; - desc.height = 512; - desc.format = TinyImageFormat_FromVkFormat((TinyImageFormat_VkFormat)VK_FORMAT_B8G8R8A8_SRGB); - desc.state = ResourceState::UNDEFINED; - desc.sampleCount = SampleCount::SAMPLE_COUNT_1; - desc.arraySize = 1; - desc.mipLevel = 1; - desc.depth = 1; - desc.dimension = TextureDimension::TEX_2D; - desc.usage = TextureUsage::COLOR_ATTACHMENT | TextureUsage::SAMPLEABLE; - for (uint32_t i = 0; i < API->context.frameCount; i++) { - API->graph.SetResourceTexture(desc, FrameGraph::NameEditorSurface, i); - } - } - EventSystem::Ptr()->BeginRenderFrame.Subscribe(&VulkanImguiEditor::OnBeginRenderFrame, this); - } - void VulkanImguiEditor::Finalize() - { - - } - ImTextureID VulkanImguiEditor::AddTexture(ImageViewPtr imageview, SamplerPtr sampler, ResourceState state) - { - VkDescriptorSet descriptorSet = ImGui_ImplVulkan_AddTexture((VkSampler)sampler, (VkImageView)imageview, vkApiGetImageLayout(state)); - return reinterpret_cast(descriptorSet); - } - void VulkanImguiEditor::Render(FrameGraph& graph, RenderEditorContext& ctx) - { - for (auto win : mWindows) - { - win->Draw(graph, ctx); - } - } - void VulkanImguiEditor::OnBeginRenderFrame(FrameGraph& graph, uint32_t frame) - { - graph.mIsRenderEditorSurface = gEngineConfig.IsRenderEditorSurface; - if (gEngineConfig.IsRenderEditorSurface) { - graph.mEditorSurfaceID = graph.mSurfaceID; - graph.mSurfaceID = graph.GetTextureID(FrameGraph::NameEditorSurface, frame); - } - graph.AddRenderPass(); - } - void VulkanImguiEditor::Setup(FrameGraph& graph, RenderPassBuilder& builder) - { - builder.Name(ImguiPassName) - .Type(RenderPassNodeType::Imgui, RenderPassNodeFlag::Output) - .Write(graph.GetRenderSurface(), ResourceState::COLOR_ATTACHMENT); - if (gEngineConfig.IsRenderEditorSurface) { - builder.Read(graph.GetSurface(), ResourceState::READ_ONLY); - } - } - void VulkanImguiEditor::Execute(FrameGraph& graph, RenderPassContext& context) - { - graph.GetRenderSurface().state = ResourceState::PRESENT; - ImGui_ImplVulkan_NewFrame(); - ImGui_ImplSDL2_NewFrame(); - ImGui::NewFrame(); - - VulkanImguiEditor* editor = VulkanImguiEditor::Ptr(); - RenderEditorContext editorContext{.editor = editor, .frame = context->frame, .frameCount = context->frameCount }; - editor->Render(graph, editorContext); - - ImGui::Render(); - VulkanContext& ctx = *(VulkanContext*)context.parent; - ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), ctx.command); - ImGuiIO& io = ImGui::GetIO(); - // 更新并渲染平台窗口 - if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) - { - ImGui::UpdatePlatformWindows(); - ImGui::RenderPlatformWindowsDefault(nullptr, ctx.command); - } - } -} diff --git a/engine/modules/render/vulkan/src/module.cpp b/engine/modules/render/vulkan/src/vulkan_module.cpp similarity index 61% rename from engine/modules/render/vulkan/src/module.cpp rename to engine/modules/render/vulkan/src/vulkan_module.cpp index a9d282f..b674cb6 100644 --- a/engine/modules/render/vulkan/src/module.cpp +++ b/engine/modules/render/vulkan/src/vulkan_module.cpp @@ -1,18 +1,20 @@ #include "xmalloc_new_delete.h" -#include "vkn/module.h" -#include "vkn/vulkan_imgui_editor.h" +#include "vkn/vulkan_module.h" #include "vkn/loader/vulkan_glsl_loader.h" #include "pmr/frame_allocator.h" using namespace vkn; void VulkanModule::OnLoad(int argc, char** argv) { VulkanGlslLoader::Init(); -#ifdef WITH_EDITOR - AddSystem(); -#endif // WITH_EDITOR - } void VulkanModule::OnUnload() { } +void VulkanModule::InitMetaData() +{ + mInfo.name = "vulkan"; + mInfo.dependencies = { + {"engine", "1.0.1", "shared" } + }; +} \ No newline at end of file diff --git a/engine/modules/render/vulkan/src/vulkan_window.cpp b/engine/modules/render/vulkan/src/vulkan_window.cpp index 9bcbbf2..b6d271a 100644 --- a/engine/modules/render/vulkan/src/vulkan_window.cpp +++ b/engine/modules/render/vulkan/src/vulkan_window.cpp @@ -10,13 +10,13 @@ #include #include namespace vkn { - bool VulkanWindow::CreateRender(CreatePFN createPFN, VulkanWindowArgs& args) + bool VulkanWindow::CreateRender(VulkanWindowArgs& args) { VulkanAPI* api = VulkanAPI::Ptr(); Backend& backend = api->GetBackend(); VkInstance instance = backend.GetInstance().Ptr(); VkSurfaceKHR surface; - if (!createPFN(mPtr, instance, &surface)) { + if (!SDL_Vulkan_CreateSurface(mPtr, instance, &surface)) { return false; } args.width = mWidth; @@ -134,9 +134,10 @@ namespace vkn { } return image_extent; } - VulkanWindowArgs VulkanWindowArgs::Default() + VulkanWindowArgs VulkanWindowArgs::Default(uint32_t frames) { return { + .frames = frames, .imageFormat = VK_FORMAT_B8G8R8A8_SRGB, .imageColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR, .presentMode = VK_PRESENT_MODE_MAILBOX_KHR, diff --git a/engine/modules/render/vulkan/xmake.lua b/engine/modules/render/vulkan/xmake.lua index 085d01a..a0c8b98 100644 --- a/engine/modules/render/vulkan/xmake.lua +++ b/engine/modules/render/vulkan/xmake.lua @@ -1,6 +1,6 @@ shared_module("vulkan","engine") add_headerfiles("include/**.h") - add_files("src/**.cpp", "include/volk/volk.c", "include/imgui/*.cpp") + add_files("src/**.cpp", "include/volk/volk.c") add_packages("vulkansdk", {public = true}) add_dependency("engine", {public = true}) on_load(function (target) diff --git a/engine/modules/xmake.lua b/engine/modules/xmake.lua index 734b6f3..712da09 100644 --- a/engine/modules/xmake.lua +++ b/engine/modules/xmake.lua @@ -29,7 +29,7 @@ function shared_module(name, owner, opt) set_group("Engine/"..owner.."__dyn") add_rules("engine.api") add_includedirs("include", {public = true}) - add_rules("engine.plugin", {file = opt and opt.file or "include/" .. name .. "/module.h"}) + --add_rules("engine.plugin", {file = opt and opt.file or "include/" .. name .. "/module.h"}) end function add_dependency(...) add_deps(...) @@ -50,7 +50,7 @@ function game_instance(name, opt) set_kind("binary") set_group("Games") add_rules("engine.api") - add_rules("engine.plugin", {file = opt and opt.file or "src/" .. name .. ".h"}) + --add_rules("engine.plugin", {file = opt and opt.file or "src/" .. name .. ".h"}) add_defines("SDL_MAIN_HANDLED") target(name .. "-editor") set_kind("binary") diff --git a/engine/src/editor/editor.cpp b/engine/src/editor/editor.cpp index f9c0c5f..caba00b 100644 --- a/engine/src/editor/editor.cpp +++ b/engine/src/editor/editor.cpp @@ -1,19 +1,8 @@ #include "editor/editor.h" -#include "data/global.h" -#include "render/window.h" -#include "render/renderapi.h" -#include "editor/window/editor_main_window.h" -#include "imgui.h" namespace api { void EditorModule::OnLoad(int argc, char** argv) { - IMGUI_CHECKVERSION(); - ImGui::CreateContext(); - ImGuiIO& io = ImGui::GetIO(); - io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // 可选:启用键盘导航 - io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // 可选:启用Docking - io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // 可选:启用多视口 - ImGui::StyleColorsDark(); + } void EditorModule::OnUnload() @@ -21,7 +10,6 @@ namespace api { } void EditorModule::Initialize(void) { - EditorSystem* Editor = EditorSystem::Ptr(); - Editor->AddWindow(); + } } \ No newline at end of file diff --git a/engine/src/editor/panel/asset_preview_panel.cpp b/engine/src/editor/panel/asset_preview_panel.cpp deleted file mode 100644 index a1a9ce3..0000000 --- a/engine/src/editor/panel/asset_preview_panel.cpp +++ /dev/null @@ -1,28 +0,0 @@ -#include "editor/panel/asset_preview_panel.h" -#include "data/global.h" -#include -namespace api { - TextureSampler sampler{ - .filterMag = SamplerMagFilter::LINEAR, - .filterMin = SamplerMinFilter::LINEAR, - .wrapS = SamplerWrapMode::CLAMP_TO_EDGE, - .wrapT = SamplerWrapMode::CLAMP_TO_EDGE, - .wrapR = SamplerWrapMode::CLAMP_TO_EDGE, - .compareMode = SamplerCompareMode::COMPARE_TO_TEXTURE, - .compareFunc = SamplerCompareFunc::GE, - }; - ImTextureID TextureIDList[10] = {}; - void AssetPreviewPanel::DrawPanel(FrameGraph& graph, RenderEditorContext& context) { - static float my_float = 0.5f; - ImGui::Text("This is some useful text."); - ImGui::SliderFloat("float", &my_float, 0.0f, 1.0f); - if (gEngineConfig.IsRenderEditorSurface) { - TextureDesc surface = graph.GetSurface(); - if (!TextureIDList[context.frame]) { - TextureIDList[context.frame] = context->AddTexture(graph, surface, sampler); - } - // 每帧渲染时都可以通过 ImTextureID 使用 - ImGui::Image(TextureIDList[context.frame], ImVec2(surface.width, surface.height)); - } - } -} \ No newline at end of file diff --git a/engine/src/editor/panel/menu_bar_panel.cpp b/engine/src/editor/panel/menu_bar_panel.cpp deleted file mode 100644 index 8023e34..0000000 --- a/engine/src/editor/panel/menu_bar_panel.cpp +++ /dev/null @@ -1,25 +0,0 @@ -#include "editor/panel/menu_bar_panel.h" -#include - -namespace api { - void MenuBarPanel::DrawPanel(FrameGraph& graph, RenderEditorContext& context) - { - // 面板大小和位置 - if (ImGui::BeginMenu("Tools")) { - if (ImGui::MenuItem("Performance Analyzer")) { - // 显示性能分析工具 - } - if (ImGui::MenuItem("Debug Console")) { - // 显示调试控制台 - } - ImGui::EndMenu(); - } - - if (ImGui::BeginMenu("Help")) { - if (ImGui::MenuItem("About")) { - // 显示关于信息 - } - ImGui::EndMenu(); - } - } -} \ No newline at end of file diff --git a/engine/src/editor/window/editor_main_window.cpp b/engine/src/editor/window/editor_main_window.cpp deleted file mode 100644 index 7821867..0000000 --- a/engine/src/editor/window/editor_main_window.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "editor/window/editor_main_window.h" -#include "editor/panel/asset_preview_panel.h" -#include "editor/panel/menu_bar_panel.h" -#include -namespace api { - EditorMainWindow::EditorMainWindow() - { - AddPanel(); - AddPanel(); - } - void EditorMainWindow::Draw(FrameGraph& graph, RenderEditorContext& context) - { - ImGui::Begin("MainWindow"); - for (auto panel : mPanels) { - panel->DrawPanel(graph, context); - } - ImGui::End(); - } -} \ No newline at end of file diff --git a/engine/src/engine/api.cpp b/engine/src/engine/api.cpp index ceb0c1a..cc73669 100644 --- a/engine/src/engine/api.cpp +++ b/engine/src/engine/api.cpp @@ -17,6 +17,7 @@ public: {"core", "1.0.1", "static" }, {"asset", "1.0.1", "static" }, {"render", "1.0.1", "static" }, + {"ui", "1.0.1", "static" }, }; }; }; diff --git a/engine/src/engine/plugin.cpp b/engine/src/engine/plugin.cpp index eb5f06e..85ef34b 100644 --- a/engine/src/engine/plugin.cpp +++ b/engine/src/engine/plugin.cpp @@ -21,13 +21,13 @@ #define RENDER_API_VAL 1 #include "renderapi_impl.inl" #include "window_impl.inl" -#ifdef WITH_EDITOR - #include "editor_system_impl.inl" -#endif #endif // !RENDER_API_VAL #ifndef APP_API_VAL #define APP_API_VAL 1 #include "app_impl.inl" #include "event_system_impl.inl" -#endif // !APP_API_VAL \ No newline at end of file +#endif // !APP_API_VAL + +#include "ui/ui_module.h" +IMPLEMENT_STATIC_MODULE(UI_API, api::UIModule, ui) \ No newline at end of file diff --git a/engine/xmake.lua b/engine/xmake.lua index 9ca8010..38e219a 100644 --- a/engine/xmake.lua +++ b/engine/xmake.lua @@ -1,12 +1,13 @@ WITH_EDITOR = true target("engine") add_defines("ENGINE_ROOT="..os.curdir():gsub("\\", "\\\\"),{public = false}) - add_headerfiles("include/*.natvis") + add_headerfiles("include/*.natvis","include/engine/**.h") add_includedirs("include", {public = true}) set_kind("shared") set_group("Engine") add_rules("engine.api") add_files("src/engine/**.cpp") + add_packages("noesis") target("editor") set_kind("shared") set_group("Engine") diff --git a/engine/xmake/rule_plugin/xmake.lua b/engine/xmake/rule_plugin/xmake.lua index e87a77a..7e30c1b 100644 --- a/engine/xmake/rule_plugin/xmake.lua +++ b/engine/xmake/rule_plugin/xmake.lua @@ -1,8 +1,8 @@ -rule("engine.plugin") - set_extensions(".h") - on_config(function (target) - import("make_plugin") - local file = target:extraconf("rules", "engine.plugin", "file") - make_plugin(target, file or "module.h") - end) +-- rule("engine.plugin") +-- set_extensions(".h") +-- on_config(function (target) +-- --import("make_plugin") +-- --local file = target:extraconf("rules", "engine.plugin", "file") +-- --make_plugin(target, file or "module.h") +-- end) \ No newline at end of file diff --git a/game/zworld/src/zworld.cpp b/game/zworld/src/zworld.cpp index e41d54e..3a05a63 100644 --- a/game/zworld/src/zworld.cpp +++ b/game/zworld/src/zworld.cpp @@ -4,33 +4,35 @@ #include "event/event_system.h" #include "vkn/vulkan_window.h" #include "vkn/vulkan_api.h" -#ifdef WITH_EDITOR -#include "imgui/imgui_impl_sdl2.h" -#endif #include "render/pass/demo_pass.h" #include using namespace api; RenderAPI* API; void ZWorldModule::OnLoad(int argc, char** argv) { + using vkn::VulkanWindow; + using vkn::VulkanAPI; // 创建窗口 gEngineConfig.API = GraphicsAPI::Vulkan; - auto window = new vkn::VulkanWindow(&SDL_CreateWindow, { "zengine" , SDL_WINDOW_VULKAN }, 1080, 720); - API = new vkn::VulkanAPI(); - auto args = vkn::VulkanWindowArgs::Default(); - args.frames = 3; - if (!window->CreateRender(&SDL_Vulkan_CreateSurface, args)) { - zlog::errorf("SDL_Vulkan_CreateSurface failed {}", SDL_GetError()); - } + VulkanWindow* window = new VulkanWindow({ "zengine" , SDL_WINDOW_VULKAN }, 1080, 720); + API = new vkn::VulkanAPI(window); + auto args = vkn::VulkanWindowArgs::Default(3); + window->CreateRender(args); API->Init(); API->context.views.push_back({}); -#ifdef WITH_EDITOR //绑定窗口交互 - ImGui_ImplSDL2_InitForVulkan(window->GetPtr()); -#endif EventSystem::Ptr()->BeginRenderFrame.Subscribe(mInfo.name, [](FrameGraph& graph, uint32_t frame) { graph.AddRenderPass(); }); } +void ZWorldModule::InitMetaData() +{ + mInfo.name = "zworld"; + mInfo.dependencies = { + {"engine", "1.0.1", "shared" }, + {"editor", "1.0.1", "shared" }, + {"vulkan", "1.0.1", "shared" } + }; +} void ZWorldModule::Initialize() { } @@ -45,9 +47,6 @@ void ZWorldModule::MainLoop() while (running) { // 处理事件 while (SDL_PollEvent(&event_)) { -#ifdef WITH_EDITOR - ImGui_ImplSDL2_ProcessEvent(&event_); -#endif // WITH_EDITOR if (event_.type == SDL_QUIT) { running = false; } @@ -57,5 +56,4 @@ void ZWorldModule::MainLoop() API->EndFrame(); FramePool()->reset(); } -} - +} \ No newline at end of file diff --git a/game/zworld/src/zworld.h b/game/zworld/src/zworld.h index 06dbcfd..99e1ecf 100644 --- a/game/zworld/src/zworld.h +++ b/game/zworld/src/zworld.h @@ -10,5 +10,4 @@ public: void InitMetaData(void) override; void MainLoop()override; }; -IMPLEMENT_DYNAMIC_MODULE(ZWORLD_API, ZWorldModule, zworld) -#include ".zworld/zworld.plugin.inl" \ No newline at end of file +IMPLEMENT_DYNAMIC_MODULE(ZWORLD_API, ZWorldModule, zworld) \ No newline at end of file