Green Sky
5dd9834009
b475309fa1e Fonts: Fixed font ascent and descent calculation when a font hits exact integer values. (#7399, #7404) daecfffefbc Text, DrawList: Improved handling of long single-line wrapped text. (#7496, #5720) fab96a6e593 Backends: SDL3: Re-enable calling SDL_StartTextInput()/SDL_StopTextInput(). (#7452, #6306, #6071, #1953) dad1689bf7b Examples: SDL3: amend for removal of SDL_RENDERER_ACCELERATED. 3caa79c8a53 Version 1.90.6 WIP 76bc1b825e6 Extracted part of NewFrame() into SetupDrawListSharedData() for documentation purpose. (#7495, #6406) f790d516652 Silent zealous/stupid warning introduced by Clang 16 (shipping with VS2022) with -Weverything. Pointers are now illegal! 231cbee0fc4 Version 1.90.5 4f9ba19e520 Drags, Sliders, Inputs: Reactivated decimal point replacement for SliderScalar and DragScalar. (#7389, #6719, #2278) e7712ff103d Out of courtesy/consistency move all the DebugHookIdInfo compares into ifndef block. f959c417fec Refactor moving ID stack functions to their own section (part 2) 0bf134a8e2e Refactor moving ID stack functions to their own section. 9a2b598ec1e ListBox: Fixed text-baseline offset when using SameLine()+Text() after a labeled ListBox(). d3c3514a59b Tables: Fixed auto-width columns when using synced-instances of same table. (#7218) 25a492f3307 ProgressBar: Fixed passing fraction==NaN from leading to a crash. (#7451) 9638c2839a1 Internals: adding ImGuiNavMoveFlags_NoClearActiveId even though there's currently no satisfying way to take advantage of it. (#1418) 742e53434f4 Child Windows: adjust resizing limits to match window padding rather than inner clipping rectangle. (#7440) 515b437c084 Child windows: look at the parent window's flags to decide whether to clamp child resizes. (#7440, #1710) 976dc239656 Windows: extend outer resize borders to the edges when there are no corner grips. (#7440, #1710) 37b37fc2a3e DrawList: Allow AddText() to accept null ranges. (#3615, 7391) 5c5ae806aa1 Comments cf4c10bef74 Style: added ImGuiStyleVar_TabBorderSize, ImGuiStyleVar_TableAngledHeadersAngle. (#7411) f0802287db5 Tables: Angled headers: fixed table contents overflowing when a list clipper is used. (#7416) 29ff159f941 Tables: Angled headers: fixed borders not moving back up after TableAngleHeadersRow stops being called. (#7416) 38ddfb24f09 Tables: Angled headers: fixed border hit box extending beyond non-scrollable tables. (#7416) 8be48a44f78 Backends: WebGPU: Avoid using -1u literal (#7436) 868facff9de ImDrawList: (Breaking) merge float radius_x/radius_y parameters into ImVec2 radius in PathEllipticalArcTo(), AddEllipse(), AddEllipseFilled(). (#2743, #7417) 0a1f5b94e31 Demo: Two minor fixes (unchecked BeginTooltip + incorrect height constraint) (#7410)l 40df3db1a2a Tweaking terminology da29b776eed Backends: SDL3: Fix leak of SDL_GetGamepads() return value (#7381) 3c435c02978 Inputs: (Breaking) More formally obsoleted GetKeyIndex() when IMGUI_DISABLE_OBSOLETE_FUNCTIONS is set. (#4921) 286cd5bd41e Internals, InputText: removed ImGuiInputSource_Clipboard. (#4005) fc570ac9225 Examples: WGPU: fixed initialization of WGPURenderPassColorAttachment (#7371) 65dc67f63c6 Windows: Double-click to collapse may be disabled via key-ownership mechanism. (#7369) 6b7358e9f36 InputText: adding clarifying note about ImGuiInputTextCallbackData::Buf. (#7363) fbf45ad149b ImDrawList: add PathFillConcave(), AddConcavePolyFilled(): amends (#760) 1ff90c52d5f ImDrawList: add PathFillConcave(), AddConcavePolyFilled() (#760) 04f40014a62 Docs: added a mini wiki index in main source files. c6236699671 Added link to crawlable wiki 0573513d6df Windows: Scrollbar visibility decision uses current size when both size and contents size are submitted by API. (#7252) 44c7dfca030 Menus, Popup: Amend c3f8f4d for static analyzer warning ("condition always true"). (#7325) c3f8f4de257 Menus, Popups: Fixed an issue where sibling menu popups re-opening in successive frames would erroneously close the window. (#7325, #7287, #7063) 98779417751 Popups, Menus: rename ImGuiPopupData::BackupNavWindow > RestoreNavWindow and minor tweaks. Should be functionally a no-op. 725f91922d5 Tables: fixed TableGetHoveredRow() with overlapping frozen rows (#7350, #6588, #6347, #6250) e46d1e69ac3 Version 1.90.5 WIP 277ae93c413 Version 1.90.4 f5be90523d6 Nav: Fixed SetKeyboardFocusHere() or programmatic tabbing API from not working on windows with the ImGuiWindowFlags_NoNavInputs flag. 13d91ff9188 Nav: Fixed SetKeyboardFocusHere() or programmatic tabbing API from not working on windows with the ImGuiWindowFlags_NoNavInputs flag. 34965cf23a7 Modals: Temporary changes of ImGuiCol_ModalWindowDimBg are properly handled by BeginPopupModal(). (#7340) 659fb41d0a2 Debug Tools: moved DebugStartItemPicker() to public API. Added to Demo->Tools menu. (#2673) 198c38f0b11 Demo: Custom Rendering: better demonstrate PathArcTo(), PathBezierQuadraticCurveTo(), PathBezierCubicCurveTo(), PathStroke(), PathFillConvex() functions. 3b6d924acd0 ProgressBar: Fixed a minor tesselation issue when rendering rounded progress bars. d3f1a7165cb Popups: allow Child Popups to be resizable if not explicitly disabling. e78ce72eb6d Popups: Fixed resizable popup minimum size being too small. Standardized CalcWindowMinSize() logic a bit more. (#73290 014e0ac8c92 Menus, Popups: Fixed an issue where hovering a parent-menu upward would erroneously close the window. (#7325, #7287, #7063) c16043c1d58 Tables: Angled headers: improve clipping of text since multi-line labels makes clipping issues visible. (#6917) 405e54ebd50 Tables: Angled Headers: fixed support for multi-line labels. various padding/layout fixes. (#6917) 6655ab2e43f Tables: Angled Headers: fixed TableAngledHeadersRow() incorrect background fill drawn too low. Fixed row geometry with non-small values of CellPadding. (#6917) 9159cd7b4ac Updated invalid documentation link (#7331) ccc5347e451 Fix typos (#7332) 8a14b71f228 Version 1.90.4 WIP b19a4c5f2b3 Backends: OSX: remove legacy clearing of io.NavInputs in ImGui_ImplOSX_UpdateGamepads(). (#7320) 5b6f03213dd Version 1.90.3 f80e65a4068 Backends:,Examples: Vulkan: moved RenderPass parameter from ImGui_ImplVulkan_Init() function to ImGui_ImplVulkan_InitInfo structure. (#7308) 829f45df994 Backends: SDL2: removed obsolete ImGui_ImplSDL2_NewFrame(SDL_Window*) signature which was obsoleted in 1.84.. 3cc37170ca7 Examples: GLFW+Metal: Add -I and -L paths for MacPorts. 891b81fc5d7 Backends: SDL3: Fixed gamepad. Added support for disconnection. Added support for multiple gamepads. Added ImGui_ImplSDL3_SetGamepadMode(). (#7180, #3884, #6559, #6890) 262e30e3001 Backends: SDL2: rework new API as ImGui_ImplSDL2_SetGamepadMode(). (#3884, #6559, #6890, #7180) 9dfa2397deb Internals: Fixed ImFileOpen not working before context is created. (#7314, #7315) d15e4100b83 Backends: SDL2: Amend new API, all support for multiple gamepads. (#3884, #6559, #6890) f966da1f8fb Backends: SDL2: Gamepad handlng: amend bf1c96d. (#3884, #6559, #6890) bf1c96d4fa2 Backends: SDL2: Handle gamepad disconnection + fixed increasing refcount. Added ImGui_ImplSDL2_SelectGamepadAuto()/ImGui_ImplSDL2_SelectGamepadExplicit(). (#3884, #6559, #6890) fd8d6dc5d19 Backends: SDL2,SDL3: tidying up. e0ba0d0433a Backends: Vulkan: Fixes for building with pre Vulkan 1.3. Amend 8901931. (#7166) 11d73f03ee5 Backends: Vulkan: Fix/amend 8901931 89019319ddb Backends: Vulkan: use PipelineRenderingCreateInfo for dynamic rendering (#7166, #6855, #5446, #5037) 1d6f0cea0e6 Backends: DX9: use RGBA texture to avoid conversion if supported 3af739a2d17 Menus, Popups: fixed menus and popups with child window flag erroneously not displaying a scrollbar when contents is over parent viewport size. (#7287, #7063) 2af01baffd1 Backends: SDLRenderer3: query newly added SDL_RenderViewportSet() to not restore a wrong viewport if none was initially set. 915c6393ad7 Version 1.90.3 WIP 536090303a8 Version 1.90.2 7b5357d817e Debug Tools: Metrics: Improved Monitors and Viewports minimap display. Highlight on hover. 70aa717a8e1 Combo: Fixed not reusing windows optimally when used inside a popup stack. 5cdc4a2a413 Demo: use ImGui::MemAlloc/MemFree for consistency. (#7300) 76e09c4b0fa ClosePopupsOverWindow(): amend to remove _ChildWindow test. 3a078466a7a Nav: ImGuiWindowFlags_NoNavInputs is tested during scoring so NavFlattened windows can use it. 7d67623d15b InputText: Internal: ReloadUserBufXXX functions don't override revert value. (#2890) fix accidental comment. a5e0e90c16a Nav: tweak RenderNavHighlight() syntax. ImGuiNavHighlightFlags_TypeThin -> ImGuiNavHighlightFlags_Compact. 1e8fc01ddd7 InputText: Internal: ReloadUserBufXXX functions don't override revert value. (#2890) + rename a06dd7a27b6 OpenPopup(): Added ImGuiPopupFlags_NoReopen. Nav, Menus: Fixed click on a BeginMenu() followed by right-arrow. (#1497, #1533) f104967c68f Comments 06ce312745e InputText: Internal: added reload from user-buf feature. (#2890) f50ddc431e3 Fixed some typos. (#7282) 6172c22c5dc CI: Update to `actions/checkout` `v4` from `v3`. (#7281) 96839b445e3 Nav: Improve handling of Alt key to toggle menu so that key ownership may be claimed on indiviudal left/right alt key without intefering with the other. 71947563709 Shortcut: fixed single mod-key Shortcut from working e.g. Shortcut(ImGuiKey_LeftCtrl) f1960b60c1a Added "nop" to IM_DEBUG_BREAK macro on GCC to work around GDB bug (#7266) 8491cf36adb Inputs: g.ActiveIdUsingManyKeys[] prevent routes from being claimed. 9176eedf240 Internals: SetShortcutRouting() move code so next commit is easier to read. Should be no-op. 1509842107d Backends: OpenGL3: Shallow tweak of compile-time extensions detection. 1ce41f6218d Backends: OpenGL3: Backup and restore GL_PIXEL_UNPACK_BUFFER. (#7253) 81e0be856a6 Fixed strict-aliasing violation in FormatTextureIDForDebugDisplay(). (#7090, #7256) a201af73544 Added SetNextItemShortcut() wip function. (#456) 4c2c09450a6 Nav: keyboard/gamepad activation feedback properly timed instead of frame buffer. (#456) 5b5e9bd0cb3 Internals: Tweak shallow compaction as Clang complains about MS ABI signage of enums. 7c3fa7d049a Refactor: moved section in imgui_internal.h 9266c0d2d13 Backends: WebGPU: Avoid leaking pipeline layout. (#7245) 595eb86624d Changelog, comment, minor data compaction 6850194f60a CI: Fixes WGPU example build. 5fc0a361b24 Backends: WebGPU: added ImGui_ImplWGPU_InitInfo::PipelineMultisampleState. (#7240) 831d42c1ab3 Backends: WebGPU: ImGui_ImplWGPU_Init() now takes a ImGui_ImplWGPU_InitInfo structure instead of variety of parameters, allowing for easier further changes. (#7240) e3c7ff944d5 Examples: Emscripten+WebGPU: slightly refactor like other Emscripten compatible Desktop examples, as aiming to make this suppot desktop eventually. 15908502ed6 Backends: Vulkan: Define NOMINMAX when VK_USE_PLATFORM_WIN32_KHR is defined. (#7250) 788747f8635 Examples: Emscripten+WebGPU: Remove use of deprecated ObjectBase<...>::Release in favor of ::MoveToCHandle (#7251) 763100b3858 Nav: Fixed pressing Escape while in a child window with _NavFlattened flag. (#7237) c7edb446caa Shortcut(): always test ownership. 1844f903d55 Nav: space/enter poll check ownership. InputText: declare ownership of Enter key as it doesn't go through Shortcut 5ddfbb80d86 Backends: Vulkan: Fixed vkAcquireNextImageKHR() validation errors in VulkanSDK 1.3.275 by allocating one extra semaphore than in-flight frames. (#7236) 2f483373355 Examples: Vulkan: Rename compile-time defies for the examples to remove misleading IMGUI_ prefixes. d7c2a0e38f4 Shortcut(): fixed 8323a06 adding _Repeat to all Shortcut() calls. 3b828d3701e Refactor: moving ItemAdd() into a section abote ItemSize(). No logic change (part 2) ff5f3aa38b5 Refactor: moving ItemAdd() into a section abote ItemSize(). No logic change (part 1) 1a48a634466 Enclosed a few more remaining sections in ifndef IMGUI_DISABLE_DEBUG_TOOLS for completeness. 33fabdf392d Scrollbar() doesn't forcefully mark itself as hovered when held. d431d85839b Internals: removed obsolete ImPool::GetSize() (last used by implot 0.10, changed in implot 0.11) f0d1f61fa51 Internals: commented out long-time obsoleted FocusableItemRegister()/FocusableItemUnregister() documentaton-only leftovers. + 095665977f6 Nav: marking NavId as hovered in ButtonBehavior() doesn't check for ActiveId. d10641b04a3 Nav: keyboard/gamepad activation mark widgets as held to give better visual feedback. 03417cc77d1 Backends: WebGPU: Filling all WGPUDepthStencilState fields explicitly as a recent Dawn update stopped setting default values. (#7232) 5fdcdf7080a Shortcut: ImGuiInputFlags_RouteFocused policy can filter Shortcuts conflicting with character input when an item is active. (#456) 80d5cb1ab1f Comments around ImGuiInputFlags. 1cc0eb4d322 Internals: Rename NavFocusScopePath to NavFocusRoute + fixed a static analyzer warning. 46e5f44ec8c Shortcut()/SetShortcutRouting(): use mixed current window focus scope + ParentWindowForFocusRoute. (#6798, #2637, #456) e0c8c80adaa Shortcut()/SetShortcutRouting(): focus route testing now use ParentWindowForFocusRoute. Automatically set on child-window, manually configurable otherwise. (#6798, #2637, #456) 4b20a0217eb Internals: add window to FocusScopeStack. (#6798) 2156db7a075 Debug Log: added InputRouting logging. Made GetKeyChordName() use its own buffer. Fixed debug break in SetShortcutRouting(). (#6798, #2637, #456) dd0efdc6371 Fixed SetKeyboardFocusHere() not working when current nav focus is in different scope. (#7226) 8a3dfda8d08 Commented out obsolete ImGuiIO::ImeWindowHandle marked obsolete in 1.87, favor of writing to 'void* ImGuiViewport::PlatformHandleRaw'. 6228c2e1ec7 Backends: Vulkan: moved ImGui_ImplVulkanH_DestroyFrameRenderBuffers/ImGui_ImplVulkanH_DestroyWindowRenderBuffers as they are always used in a state where backend data is available. 70bb6d1e790 Backends: Vulkan: Fixed vkMapMemory() calls unnecessarily using full buffer size. (#3957) 82df7c8bf41 Backends: Vulkan: Fixed handling of ImGui_ImplVulkan_InitInfo::MinAllocationSize field. (#7189, #4238) 29809d72202 Version 1.90.2 WIP db049db8608 Docs: tweak, fixed misplaced changelog entry. (#7084) git-subtree-dir: external/imgui/imgui git-subtree-split: b475309fa1e9d7a91825a169e243f9c4fa085f71
1586 lines
82 KiB
C++
1586 lines
82 KiB
C++
// dear imgui: Renderer Backend for Vulkan
|
|
// This needs to be used along with a Platform Backend (e.g. GLFW, SDL, Win32, custom..)
|
|
|
|
// Implemented features:
|
|
// [!] 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.
|
|
|
|
// Important: on 32-bit systems, user texture binding is only supported if your imconfig file has '#define ImTextureID ImU64'.
|
|
// This is because we need ImTextureID to carry a 64-bit value and by default ImTextureID is defined as void*.
|
|
// To build this on 32-bit systems and support texture changes:
|
|
// - [Solution 1] IDE/msbuild: in "Properties/C++/Preprocessor Definitions" add 'ImTextureID=ImU64' (this is what we do in our .vcxproj files)
|
|
// - [Solution 2] IDE/msbuild: in "Properties/C++/Preprocessor Definitions" add 'IMGUI_USER_CONFIG="my_imgui_config.h"' and inside 'my_imgui_config.h' add '#define ImTextureID ImU64' and as many other options as you like.
|
|
// - [Solution 3] IDE/msbuild: edit imconfig.h and add '#define ImTextureID ImU64' (prefer solution 2 to create your own config file!)
|
|
// - [Solution 4] command-line: add '/D ImTextureID=ImU64' to your cl.exe command-line (this is what we do in our batch files)
|
|
|
|
// 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-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 unecessary 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 symetry. (#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 "imgui.h"
|
|
#ifndef IMGUI_DISABLE
|
|
#include "imgui_impl_vulkan.h"
|
|
#include <stdio.h>
|
|
#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_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
|
|
#ifdef VK_NO_PROTOTYPES
|
|
static bool g_FunctionsLoaded = false;
|
|
#else
|
|
static bool g_FunctionsLoaded = true;
|
|
#endif
|
|
#ifdef VK_NO_PROTOTYPES
|
|
#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(vkBeginCommandBuffer) \
|
|
IMGUI_VULKAN_FUNC_MAP_MACRO(vkBindBufferMemory) \
|
|
IMGUI_VULKAN_FUNC_MAP_MACRO(vkBindImageMemory) \
|
|
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(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(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(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(vkGetSwapchainImagesKHR) \
|
|
IMGUI_VULKAN_FUNC_MAP_MACRO(vkMapMemory) \
|
|
IMGUI_VULKAN_FUNC_MAP_MACRO(vkQueueSubmit) \
|
|
IMGUI_VULKAN_FUNC_MAP_MACRO(vkQueueWaitIdle) \
|
|
IMGUI_VULKAN_FUNC_MAP_MACRO(vkResetCommandPool) \
|
|
IMGUI_VULKAN_FUNC_MAP_MACRO(vkUnmapMemory) \
|
|
IMGUI_VULKAN_FUNC_MAP_MACRO(vkUpdateDescriptorSets)
|
|
|
|
// 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 // VK_NO_PROTOTYPES
|
|
|
|
#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;
|
|
};
|
|
|
|
// Vulkan data
|
|
struct ImGui_ImplVulkan_Data
|
|
{
|
|
ImGui_ImplVulkan_InitInfo VulkanInitInfo;
|
|
VkDeviceSize BufferMemoryAlignment;
|
|
VkPipelineCreateFlags PipelineCreateFlags;
|
|
VkDescriptorSetLayout DescriptorSetLayout;
|
|
VkPipelineLayout PipelineLayout;
|
|
VkPipeline Pipeline;
|
|
VkShaderModule ShaderModuleVert;
|
|
VkShaderModule ShaderModuleFrag;
|
|
|
|
// Font data
|
|
VkSampler FontSampler;
|
|
VkDeviceMemory FontMemory;
|
|
VkImage FontImage;
|
|
VkImageView FontView;
|
|
VkDescriptorSet FontDescriptorSet;
|
|
VkCommandPool FontCommandPool;
|
|
VkCommandBuffer FontCommandBuffer;
|
|
|
|
// Render buffers for main window
|
|
ImGui_ImplVulkan_WindowRenderBuffers MainWindowRenderBuffers;
|
|
|
|
ImGui_ImplVulkan_Data()
|
|
{
|
|
memset((void*)this, 0, sizeof(*this));
|
|
BufferMemoryAlignment = 256;
|
|
}
|
|
};
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// SHADERS
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// 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, size_t 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
|
|
ImGui_ImplVulkan_WindowRenderBuffers* wrb = &bd->MainWindowRenderBuffers;
|
|
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(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
|
|
size_t vertex_size = AlignBufferSize(draw_data->TotalVtxCount * sizeof(ImDrawVert), bd->BufferMemoryAlignment);
|
|
size_t 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* cmd_list = draw_data->CmdLists[n];
|
|
memcpy(vtx_dst, cmd_list->VtxBuffer.Data, cmd_list->VtxBuffer.Size * sizeof(ImDrawVert));
|
|
memcpy(idx_dst, cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx));
|
|
vtx_dst += cmd_list->VtxBuffer.Size;
|
|
idx_dst += cmd_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);
|
|
|
|
// 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* cmd_list = draw_data->CmdLists[n];
|
|
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
|
|
{
|
|
const ImDrawCmd* pcmd = &cmd_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(cmd_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[1] = { (VkDescriptorSet)pcmd->TextureId };
|
|
if (sizeof(ImTextureID) < sizeof(ImU64))
|
|
{
|
|
// We don't support texture switches if ImTextureID hasn't been redefined to be 64-bit. Do a flaky check that other textures haven't been used.
|
|
IM_ASSERT(pcmd->TextureId == (ImTextureID)bd->FontDescriptorSet);
|
|
desc_set[0] = bd->FontDescriptorSet;
|
|
}
|
|
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 += cmd_list->IdxBuffer.Size;
|
|
global_vtx_offset += cmd_list->VtxBuffer.Size;
|
|
}
|
|
|
|
// 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->FontView || bd->FontImage || bd->FontMemory || bd->FontDescriptorSet)
|
|
{
|
|
vkQueueWaitIdle(v->Queue);
|
|
ImGui_ImplVulkan_DestroyFontsTexture();
|
|
}
|
|
|
|
// Create command pool/buffer
|
|
if (bd->FontCommandPool == 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->FontCommandPool);
|
|
}
|
|
if (bd->FontCommandBuffer == VK_NULL_HANDLE)
|
|
{
|
|
VkCommandBufferAllocateInfo info = {};
|
|
info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
|
info.commandPool = bd->FontCommandPool;
|
|
info.commandBufferCount = 1;
|
|
err = vkAllocateCommandBuffers(v->Device, &info, &bd->FontCommandBuffer);
|
|
check_vk_result(err);
|
|
}
|
|
|
|
// Start command buffer
|
|
{
|
|
err = vkResetCommandPool(v->Device, bd->FontCommandPool, 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->FontCommandBuffer, &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:
|
|
{
|
|
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, &bd->FontImage);
|
|
check_vk_result(err);
|
|
VkMemoryRequirements req;
|
|
vkGetImageMemoryRequirements(v->Device, bd->FontImage, &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, &bd->FontMemory);
|
|
check_vk_result(err);
|
|
err = vkBindImageMemory(v->Device, bd->FontImage, bd->FontMemory, 0);
|
|
check_vk_result(err);
|
|
}
|
|
|
|
// Create the Image View:
|
|
{
|
|
VkImageViewCreateInfo info = {};
|
|
info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
|
info.image = bd->FontImage;
|
|
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, &bd->FontView);
|
|
check_vk_result(err);
|
|
}
|
|
|
|
// Create the Descriptor Set:
|
|
bd->FontDescriptorSet = (VkDescriptorSet)ImGui_ImplVulkan_AddTexture(bd->FontSampler, bd->FontView, 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 = bd->FontImage;
|
|
copy_barrier[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
|
copy_barrier[0].subresourceRange.levelCount = 1;
|
|
copy_barrier[0].subresourceRange.layerCount = 1;
|
|
vkCmdPipelineBarrier(bd->FontCommandBuffer, 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->FontCommandBuffer, upload_buffer, bd->FontImage, 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 = bd->FontImage;
|
|
use_barrier[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
|
use_barrier[0].subresourceRange.levelCount = 1;
|
|
use_barrier[0].subresourceRange.layerCount = 1;
|
|
vkCmdPipelineBarrier(bd->FontCommandBuffer, 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)bd->FontDescriptorSet);
|
|
|
|
// End command buffer
|
|
VkSubmitInfo end_info = {};
|
|
end_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
|
end_info.commandBufferCount = 1;
|
|
end_info.pCommandBuffers = &bd->FontCommandBuffer;
|
|
err = vkEndCommandBuffer(bd->FontCommandBuffer);
|
|
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;
|
|
|
|
if (bd->FontDescriptorSet)
|
|
{
|
|
ImGui_ImplVulkan_RemoveTexture(bd->FontDescriptorSet);
|
|
bd->FontDescriptorSet = VK_NULL_HANDLE;
|
|
io.Fonts->SetTexID(0);
|
|
}
|
|
|
|
if (bd->FontView) { vkDestroyImageView(v->Device, bd->FontView, v->Allocator); bd->FontView = VK_NULL_HANDLE; }
|
|
if (bd->FontImage) { vkDestroyImage(v->Device, bd->FontImage, v->Allocator); bd->FontImage = VK_NULL_HANDLE; }
|
|
if (bd->FontMemory) { vkFreeMemory(v->Device, bd->FontMemory, v->Allocator); bd->FontMemory = 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->FontSampler)
|
|
{
|
|
// 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_REPEAT;
|
|
info.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
|
|
info.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
|
|
info.minLod = -1000;
|
|
info.maxLod = 1000;
|
|
info.maxAnisotropy = 1.0f;
|
|
err = vkCreateSampler(v->Device, &info, v->Allocator, &bd->FontSampler);
|
|
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 (!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_ImplVulkan_DestroyWindowRenderBuffers(v->Device, &bd->MainWindowRenderBuffers, v->Allocator);
|
|
ImGui_ImplVulkan_DestroyFontsTexture();
|
|
|
|
if (bd->FontCommandBuffer) { vkFreeCommandBuffers(v->Device, bd->FontCommandPool, 1, &bd->FontCommandBuffer); bd->FontCommandBuffer = VK_NULL_HANDLE; }
|
|
if (bd->FontCommandPool) { vkDestroyCommandPool(v->Device, bd->FontCommandPool, v->Allocator); bd->FontCommandPool = 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->FontSampler) { vkDestroySampler(v->Device, bd->FontSampler, v->Allocator); bd->FontSampler = 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; }
|
|
}
|
|
|
|
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 equivalent to not setting VK_NO_PROTOTYPES.
|
|
#ifdef VK_NO_PROTOTYPES
|
|
#define IMGUI_VULKAN_FUNC_LOAD(func) \
|
|
func = reinterpret_cast<decltype(func)>(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<PFN_vkCmdBeginRenderingKHR>(loader_func("vkCmdBeginRenderingKHR", user_data));
|
|
ImGuiImplVulkanFuncs_vkCmdEndRenderingKHR = reinterpret_cast<PFN_vkCmdEndRenderingKHR>(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 VK_NO_PROTOTYPES
|
|
ImGuiImplVulkanFuncs_vkCmdBeginRenderingKHR = reinterpret_cast<PFN_vkCmdBeginRenderingKHR>(vkGetInstanceProcAddr(info->Instance, "vkCmdBeginRenderingKHR"));
|
|
ImGuiImplVulkanFuncs_vkCmdEndRenderingKHR = reinterpret_cast<PFN_vkCmdEndRenderingKHR>(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();
|
|
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.
|
|
|
|
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);
|
|
IM_ASSERT(info->DescriptorPool != VK_NULL_HANDLE);
|
|
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();
|
|
|
|
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();
|
|
|
|
ImGui_ImplVulkan_DestroyDeviceObjects();
|
|
io.BackendRendererName = nullptr;
|
|
io.BackendRendererUserData = nullptr;
|
|
io.BackendFlags &= ~ImGuiBackendFlags_RendererHasVtxOffset;
|
|
IM_DELETE(bd);
|
|
}
|
|
|
|
void ImGui_ImplVulkan_NewFrame()
|
|
{
|
|
ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData();
|
|
IM_ASSERT(bd != nullptr && "Did you call ImGui_ImplVulkan_Init()?");
|
|
|
|
if (!bd->FontDescriptorSet)
|
|
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;
|
|
|
|
ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo;
|
|
VkResult err = vkDeviceWaitIdle(v->Device);
|
|
check_vk_result(err);
|
|
ImGui_ImplVulkan_DestroyWindowRenderBuffers(v->Device, &bd->MainWindowRenderBuffers, v->Allocator);
|
|
bd->VulkanInitInfo.MinImageCount = min_image_count;
|
|
}
|
|
|
|
// Register a texture
|
|
// 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;
|
|
|
|
// Create Descriptor Set:
|
|
VkDescriptorSet descriptor_set;
|
|
{
|
|
VkDescriptorSetAllocateInfo alloc_info = {};
|
|
alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
|
|
alloc_info.descriptorPool = v->DescriptorPool;
|
|
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;
|
|
vkFreeDescriptorSets(v->Device, v->DescriptorPool, 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<VkSurfaceFormatKHR> 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<VkPresentModeKHR> 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 (wd->Pipeline)
|
|
vkDestroyPipeline(device, wd->Pipeline, 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(wd->Frames, 0, sizeof(wd->Frames[0]) * wd->ImageCount);
|
|
memset(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_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;
|
|
vkDestroyPipeline(device, wd->Pipeline, allocator);
|
|
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;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#endif // #ifndef IMGUI_DISABLE
|