1 | // dear imgui: Renderer Backend for Vulkan |
2 | // This needs to be used along with a Platform Backend (e.g. GLFW, SDL, Win32, custom..) |
3 | |
4 | // Implemented features: |
5 | // [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices. |
6 | // Missing features: |
7 | // [ ] Renderer: User texture binding. Changes of ImTextureID aren't supported by this backend! See https://github.com/ocornut/imgui/pull/914 |
8 | |
9 | // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. |
10 | // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. |
11 | // If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp. |
12 | // Read online: https://github.com/ocornut/imgui/tree/master/docs |
13 | |
14 | // The aim of imgui_impl_vulkan.h/.cpp is to be usable in your engine without any modification. |
15 | // IF YOU FEEL YOU NEED TO MAKE ANY CHANGE TO THIS CODE, please share them and your feedback at https://github.com/ocornut/imgui/ |
16 | |
17 | // Important note to the reader who wish to integrate imgui_impl_vulkan.cpp/.h in their own engine/app. |
18 | // - Common ImGui_ImplVulkan_XXX functions and structures are used to interface with imgui_impl_vulkan.cpp/.h. |
19 | // You will use those if you want to use this rendering backend in your engine/app. |
20 | // - Helper ImGui_ImplVulkanH_XXX functions and structures are only used by this example (main.cpp) and by |
21 | // the backend itself (imgui_impl_vulkan.cpp), but should PROBABLY NOT be used by your own engine/app code. |
22 | // Read comments in imgui_impl_vulkan.h. |
23 | |
24 | // CHANGELOG |
25 | // (minor and older changes stripped away, please see git history for details) |
26 | // 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). |
27 | // 2021-03-22: Vulkan: Fix mapped memory validation error when buffer sizes are not multiple of VkPhysicalDeviceLimits::nonCoherentAtomSize. |
28 | // 2021-02-18: Vulkan: Change blending equation to preserve alpha in output buffer. |
29 | // 2021-01-27: Vulkan: Added support for custom function load and IMGUI_IMPL_VULKAN_NO_PROTOTYPES by using ImGui_ImplVulkan_LoadFunctions(). |
30 | // 2020-11-11: Vulkan: Added support for specifying which subpass to reference during VkPipeline creation. |
31 | // 2020-09-07: Vulkan: Added VkPipeline parameter to ImGui_ImplVulkan_RenderDrawData (default to one passed to ImGui_ImplVulkan_Init). |
32 | // 2020-05-04: Vulkan: Fixed crash if initial frame has no vertices. |
33 | // 2020-04-26: Vulkan: Fixed edge case where render callbacks wouldn't be called if the ImDrawData didn't have vertices. |
34 | // 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. |
35 | // 2019-05-29: Vulkan: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag. |
36 | // 2019-04-30: Vulkan: Added support for special ImDrawCallback_ResetRenderState callback to reset render state. |
37 | // 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(). |
38 | // 2019-04-04: Vulkan: Added VkInstance argument to ImGui_ImplVulkanH_CreateWindow() optional helper. |
39 | // 2019-04-04: Vulkan: Avoid passing negative coordinates to vkCmdSetScissor, which debug validation layers do not like. |
40 | // 2019-04-01: Vulkan: Support for 32-bit index buffer (#define ImDrawIdx unsigned int). |
41 | // 2019-02-16: Vulkan: Viewport and clipping rectangles correctly using draw_data->FramebufferScale to allow retina display. |
42 | // 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window. |
43 | // 2018-08-25: Vulkan: Fixed mishandled VkSurfaceCapabilitiesKHR::maxImageCount=0 case. |
44 | // 2018-06-22: Inverted the parameters to ImGui_ImplVulkan_RenderDrawData() to be consistent with other backends. |
45 | // 2018-06-08: Misc: Extracted imgui_impl_vulkan.cpp/.h away from the old combined GLFW+Vulkan example. |
46 | // 2018-06-08: Vulkan: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle. |
47 | // 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. |
48 | // 2018-03-01: Vulkan: Renamed ImGui_ImplVulkan_Init_Info to ImGui_ImplVulkan_InitInfo and fields to match more closely Vulkan terminology. |
49 | // 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback, ImGui_ImplVulkan_Render() calls ImGui_ImplVulkan_RenderDrawData() itself. |
50 | // 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves. |
51 | // 2017-05-15: Vulkan: Fix scissor offset being negative. Fix new Vulkan validation warnings. Set required depth member for buffer image copy. |
52 | // 2016-11-13: Vulkan: Fix validation layer warnings and errors and redeclare gl_PerVertex. |
53 | // 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. |
54 | // 2016-08-27: Vulkan: Fix Vulkan example for use when a depth buffer is active. |
55 | |
56 | #include "imgui_impl_vulkan.h" |
57 | #include <stdio.h> |
58 | |
59 | // Reusable buffers used for rendering 1 current in-flight frame, for ImGui_ImplVulkan_RenderDrawData() |
60 | // [Please zero-clear before use!] |
61 | struct ImGui_ImplVulkanH_FrameRenderBuffers |
62 | { |
63 | VkDeviceMemory VertexBufferMemory; |
64 | VkDeviceMemory IndexBufferMemory; |
65 | VkDeviceSize VertexBufferSize; |
66 | VkDeviceSize IndexBufferSize; |
67 | VkBuffer VertexBuffer; |
68 | VkBuffer IndexBuffer; |
69 | }; |
70 | |
71 | // Each viewport will hold 1 ImGui_ImplVulkanH_WindowRenderBuffers |
72 | // [Please zero-clear before use!] |
73 | struct ImGui_ImplVulkanH_WindowRenderBuffers |
74 | { |
75 | uint32_t Index; |
76 | uint32_t Count; |
77 | ImGui_ImplVulkanH_FrameRenderBuffers* FrameRenderBuffers; |
78 | }; |
79 | |
80 | // Vulkan data |
81 | struct ImGui_ImplVulkan_Data |
82 | { |
83 | ImGui_ImplVulkan_InitInfo VulkanInitInfo; |
84 | VkRenderPass RenderPass; |
85 | VkDeviceSize BufferMemoryAlignment; |
86 | VkPipelineCreateFlags PipelineCreateFlags; |
87 | VkDescriptorSetLayout DescriptorSetLayout; |
88 | VkPipelineLayout PipelineLayout; |
89 | VkDescriptorSet DescriptorSet; |
90 | VkPipeline Pipeline; |
91 | uint32_t Subpass; |
92 | VkShaderModule ShaderModuleVert; |
93 | VkShaderModule ShaderModuleFrag; |
94 | |
95 | // Font data |
96 | VkSampler FontSampler; |
97 | VkDeviceMemory FontMemory; |
98 | VkImage FontImage; |
99 | VkImageView FontView; |
100 | VkDeviceMemory UploadBufferMemory; |
101 | VkBuffer UploadBuffer; |
102 | |
103 | // Render buffers |
104 | ImGui_ImplVulkanH_WindowRenderBuffers MainWindowRenderBuffers; |
105 | |
106 | ImGui_ImplVulkan_Data() |
107 | { |
108 | memset(this, 0, sizeof(*this)); |
109 | BufferMemoryAlignment = 256; |
110 | } |
111 | }; |
112 | |
113 | // Forward Declarations |
114 | bool ImGui_ImplVulkan_CreateDeviceObjects(); |
115 | void ImGui_ImplVulkan_DestroyDeviceObjects(); |
116 | void ImGui_ImplVulkanH_DestroyFrame(VkDevice device, ImGui_ImplVulkanH_Frame* fd, const VkAllocationCallbacks* allocator); |
117 | void ImGui_ImplVulkanH_DestroyFrameSemaphores(VkDevice device, ImGui_ImplVulkanH_FrameSemaphores* fsd, const VkAllocationCallbacks* allocator); |
118 | void ImGui_ImplVulkanH_DestroyFrameRenderBuffers(VkDevice device, ImGui_ImplVulkanH_FrameRenderBuffers* buffers, const VkAllocationCallbacks* allocator); |
119 | void ImGui_ImplVulkanH_DestroyWindowRenderBuffers(VkDevice device, ImGui_ImplVulkanH_WindowRenderBuffers* buffers, const VkAllocationCallbacks* allocator); |
120 | 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); |
121 | void ImGui_ImplVulkanH_CreateWindowCommandBuffers(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, uint32_t queue_family, const VkAllocationCallbacks* allocator); |
122 | |
123 | // Vulkan prototypes for use with custom loaders |
124 | // (see description of IMGUI_IMPL_VULKAN_NO_PROTOTYPES in imgui_impl_vulkan.h |
125 | #ifdef VK_NO_PROTOTYPES |
126 | static bool g_FunctionsLoaded = false; |
127 | #else |
128 | static bool g_FunctionsLoaded = true; |
129 | #endif |
130 | #ifdef VK_NO_PROTOTYPES |
131 | #define IMGUI_VULKAN_FUNC_MAP(IMGUI_VULKAN_FUNC_MAP_MACRO) \ |
132 | IMGUI_VULKAN_FUNC_MAP_MACRO(vkAllocateCommandBuffers) \ |
133 | IMGUI_VULKAN_FUNC_MAP_MACRO(vkAllocateDescriptorSets) \ |
134 | IMGUI_VULKAN_FUNC_MAP_MACRO(vkAllocateMemory) \ |
135 | IMGUI_VULKAN_FUNC_MAP_MACRO(vkBindBufferMemory) \ |
136 | IMGUI_VULKAN_FUNC_MAP_MACRO(vkBindImageMemory) \ |
137 | IMGUI_VULKAN_FUNC_MAP_MACRO(vkCmdBindDescriptorSets) \ |
138 | IMGUI_VULKAN_FUNC_MAP_MACRO(vkCmdBindIndexBuffer) \ |
139 | IMGUI_VULKAN_FUNC_MAP_MACRO(vkCmdBindPipeline) \ |
140 | IMGUI_VULKAN_FUNC_MAP_MACRO(vkCmdBindVertexBuffers) \ |
141 | IMGUI_VULKAN_FUNC_MAP_MACRO(vkCmdCopyBufferToImage) \ |
142 | IMGUI_VULKAN_FUNC_MAP_MACRO(vkCmdDrawIndexed) \ |
143 | IMGUI_VULKAN_FUNC_MAP_MACRO(vkCmdPipelineBarrier) \ |
144 | IMGUI_VULKAN_FUNC_MAP_MACRO(vkCmdPushConstants) \ |
145 | IMGUI_VULKAN_FUNC_MAP_MACRO(vkCmdSetScissor) \ |
146 | IMGUI_VULKAN_FUNC_MAP_MACRO(vkCmdSetViewport) \ |
147 | IMGUI_VULKAN_FUNC_MAP_MACRO(vkCreateBuffer) \ |
148 | IMGUI_VULKAN_FUNC_MAP_MACRO(vkCreateCommandPool) \ |
149 | IMGUI_VULKAN_FUNC_MAP_MACRO(vkCreateDescriptorSetLayout) \ |
150 | IMGUI_VULKAN_FUNC_MAP_MACRO(vkCreateFence) \ |
151 | IMGUI_VULKAN_FUNC_MAP_MACRO(vkCreateFramebuffer) \ |
152 | IMGUI_VULKAN_FUNC_MAP_MACRO(vkCreateGraphicsPipelines) \ |
153 | IMGUI_VULKAN_FUNC_MAP_MACRO(vkCreateImage) \ |
154 | IMGUI_VULKAN_FUNC_MAP_MACRO(vkCreateImageView) \ |
155 | IMGUI_VULKAN_FUNC_MAP_MACRO(vkCreatePipelineLayout) \ |
156 | IMGUI_VULKAN_FUNC_MAP_MACRO(vkCreateRenderPass) \ |
157 | IMGUI_VULKAN_FUNC_MAP_MACRO(vkCreateSampler) \ |
158 | IMGUI_VULKAN_FUNC_MAP_MACRO(vkCreateSemaphore) \ |
159 | IMGUI_VULKAN_FUNC_MAP_MACRO(vkCreateShaderModule) \ |
160 | IMGUI_VULKAN_FUNC_MAP_MACRO(vkCreateSwapchainKHR) \ |
161 | IMGUI_VULKAN_FUNC_MAP_MACRO(vkDestroyBuffer) \ |
162 | IMGUI_VULKAN_FUNC_MAP_MACRO(vkDestroyCommandPool) \ |
163 | IMGUI_VULKAN_FUNC_MAP_MACRO(vkDestroyDescriptorSetLayout) \ |
164 | IMGUI_VULKAN_FUNC_MAP_MACRO(vkDestroyFence) \ |
165 | IMGUI_VULKAN_FUNC_MAP_MACRO(vkDestroyFramebuffer) \ |
166 | IMGUI_VULKAN_FUNC_MAP_MACRO(vkDestroyImage) \ |
167 | IMGUI_VULKAN_FUNC_MAP_MACRO(vkDestroyImageView) \ |
168 | IMGUI_VULKAN_FUNC_MAP_MACRO(vkDestroyPipeline) \ |
169 | IMGUI_VULKAN_FUNC_MAP_MACRO(vkDestroyPipelineLayout) \ |
170 | IMGUI_VULKAN_FUNC_MAP_MACRO(vkDestroyRenderPass) \ |
171 | IMGUI_VULKAN_FUNC_MAP_MACRO(vkDestroySampler) \ |
172 | IMGUI_VULKAN_FUNC_MAP_MACRO(vkDestroySemaphore) \ |
173 | IMGUI_VULKAN_FUNC_MAP_MACRO(vkDestroyShaderModule) \ |
174 | IMGUI_VULKAN_FUNC_MAP_MACRO(vkDestroySurfaceKHR) \ |
175 | IMGUI_VULKAN_FUNC_MAP_MACRO(vkDestroySwapchainKHR) \ |
176 | IMGUI_VULKAN_FUNC_MAP_MACRO(vkDeviceWaitIdle) \ |
177 | IMGUI_VULKAN_FUNC_MAP_MACRO(vkFlushMappedMemoryRanges) \ |
178 | IMGUI_VULKAN_FUNC_MAP_MACRO(vkFreeCommandBuffers) \ |
179 | IMGUI_VULKAN_FUNC_MAP_MACRO(vkFreeMemory) \ |
180 | IMGUI_VULKAN_FUNC_MAP_MACRO(vkGetBufferMemoryRequirements) \ |
181 | IMGUI_VULKAN_FUNC_MAP_MACRO(vkGetImageMemoryRequirements) \ |
182 | IMGUI_VULKAN_FUNC_MAP_MACRO(vkGetPhysicalDeviceMemoryProperties) \ |
183 | IMGUI_VULKAN_FUNC_MAP_MACRO(vkGetPhysicalDeviceSurfaceCapabilitiesKHR) \ |
184 | IMGUI_VULKAN_FUNC_MAP_MACRO(vkGetPhysicalDeviceSurfaceFormatsKHR) \ |
185 | IMGUI_VULKAN_FUNC_MAP_MACRO(vkGetPhysicalDeviceSurfacePresentModesKHR) \ |
186 | IMGUI_VULKAN_FUNC_MAP_MACRO(vkGetSwapchainImagesKHR) \ |
187 | IMGUI_VULKAN_FUNC_MAP_MACRO(vkMapMemory) \ |
188 | IMGUI_VULKAN_FUNC_MAP_MACRO(vkUnmapMemory) \ |
189 | IMGUI_VULKAN_FUNC_MAP_MACRO(vkUpdateDescriptorSets) |
190 | |
191 | // Define function pointers |
192 | #define IMGUI_VULKAN_FUNC_DEF(func) static PFN_##func func; |
193 | IMGUI_VULKAN_FUNC_MAP(IMGUI_VULKAN_FUNC_DEF) |
194 | #undef IMGUI_VULKAN_FUNC_DEF |
195 | #endif // VK_NO_PROTOTYPES |
196 | |
197 | //----------------------------------------------------------------------------- |
198 | // SHADERS |
199 | //----------------------------------------------------------------------------- |
200 | |
201 | // glsl_shader.vert, compiled with: |
202 | // # glslangValidator -V -x -o glsl_shader.vert.u32 glsl_shader.vert |
203 | /* |
204 | #version 450 core |
205 | layout(location = 0) in vec2 aPos; |
206 | layout(location = 1) in vec2 aUV; |
207 | layout(location = 2) in vec4 aColor; |
208 | layout(push_constant) uniform uPushConstant { vec2 uScale; vec2 uTranslate; } pc; |
209 | |
210 | out gl_PerVertex { vec4 gl_Position; }; |
211 | layout(location = 0) out struct { vec4 Color; vec2 UV; } Out; |
212 | |
213 | void main() |
214 | { |
215 | Out.Color = aColor; |
216 | Out.UV = aUV; |
217 | gl_Position = vec4(aPos * pc.uScale + pc.uTranslate, 0, 1); |
218 | } |
219 | */ |
220 | static uint32_t __glsl_shader_vert_spv[] = |
221 | { |
222 | 0x07230203,0x00010000,0x00080001,0x0000002e,0x00000000,0x00020011,0x00000001,0x0006000b, |
223 | 0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,0x00000000,0x00000001, |
224 | 0x000a000f,0x00000000,0x00000004,0x6e69616d,0x00000000,0x0000000b,0x0000000f,0x00000015, |
225 | 0x0000001b,0x0000001c,0x00030003,0x00000002,0x000001c2,0x00040005,0x00000004,0x6e69616d, |
226 | 0x00000000,0x00030005,0x00000009,0x00000000,0x00050006,0x00000009,0x00000000,0x6f6c6f43, |
227 | 0x00000072,0x00040006,0x00000009,0x00000001,0x00005655,0x00030005,0x0000000b,0x0074754f, |
228 | 0x00040005,0x0000000f,0x6c6f4361,0x0000726f,0x00030005,0x00000015,0x00565561,0x00060005, |
229 | 0x00000019,0x505f6c67,0x65567265,0x78657472,0x00000000,0x00060006,0x00000019,0x00000000, |
230 | 0x505f6c67,0x7469736f,0x006e6f69,0x00030005,0x0000001b,0x00000000,0x00040005,0x0000001c, |
231 | 0x736f5061,0x00000000,0x00060005,0x0000001e,0x73755075,0x6e6f4368,0x6e617473,0x00000074, |
232 | 0x00050006,0x0000001e,0x00000000,0x61635375,0x0000656c,0x00060006,0x0000001e,0x00000001, |
233 | 0x61725475,0x616c736e,0x00006574,0x00030005,0x00000020,0x00006370,0x00040047,0x0000000b, |
234 | 0x0000001e,0x00000000,0x00040047,0x0000000f,0x0000001e,0x00000002,0x00040047,0x00000015, |
235 | 0x0000001e,0x00000001,0x00050048,0x00000019,0x00000000,0x0000000b,0x00000000,0x00030047, |
236 | 0x00000019,0x00000002,0x00040047,0x0000001c,0x0000001e,0x00000000,0x00050048,0x0000001e, |
237 | 0x00000000,0x00000023,0x00000000,0x00050048,0x0000001e,0x00000001,0x00000023,0x00000008, |
238 | 0x00030047,0x0000001e,0x00000002,0x00020013,0x00000002,0x00030021,0x00000003,0x00000002, |
239 | 0x00030016,0x00000006,0x00000020,0x00040017,0x00000007,0x00000006,0x00000004,0x00040017, |
240 | 0x00000008,0x00000006,0x00000002,0x0004001e,0x00000009,0x00000007,0x00000008,0x00040020, |
241 | 0x0000000a,0x00000003,0x00000009,0x0004003b,0x0000000a,0x0000000b,0x00000003,0x00040015, |
242 | 0x0000000c,0x00000020,0x00000001,0x0004002b,0x0000000c,0x0000000d,0x00000000,0x00040020, |
243 | 0x0000000e,0x00000001,0x00000007,0x0004003b,0x0000000e,0x0000000f,0x00000001,0x00040020, |
244 | 0x00000011,0x00000003,0x00000007,0x0004002b,0x0000000c,0x00000013,0x00000001,0x00040020, |
245 | 0x00000014,0x00000001,0x00000008,0x0004003b,0x00000014,0x00000015,0x00000001,0x00040020, |
246 | 0x00000017,0x00000003,0x00000008,0x0003001e,0x00000019,0x00000007,0x00040020,0x0000001a, |
247 | 0x00000003,0x00000019,0x0004003b,0x0000001a,0x0000001b,0x00000003,0x0004003b,0x00000014, |
248 | 0x0000001c,0x00000001,0x0004001e,0x0000001e,0x00000008,0x00000008,0x00040020,0x0000001f, |
249 | 0x00000009,0x0000001e,0x0004003b,0x0000001f,0x00000020,0x00000009,0x00040020,0x00000021, |
250 | 0x00000009,0x00000008,0x0004002b,0x00000006,0x00000028,0x00000000,0x0004002b,0x00000006, |
251 | 0x00000029,0x3f800000,0x00050036,0x00000002,0x00000004,0x00000000,0x00000003,0x000200f8, |
252 | 0x00000005,0x0004003d,0x00000007,0x00000010,0x0000000f,0x00050041,0x00000011,0x00000012, |
253 | 0x0000000b,0x0000000d,0x0003003e,0x00000012,0x00000010,0x0004003d,0x00000008,0x00000016, |
254 | 0x00000015,0x00050041,0x00000017,0x00000018,0x0000000b,0x00000013,0x0003003e,0x00000018, |
255 | 0x00000016,0x0004003d,0x00000008,0x0000001d,0x0000001c,0x00050041,0x00000021,0x00000022, |
256 | 0x00000020,0x0000000d,0x0004003d,0x00000008,0x00000023,0x00000022,0x00050085,0x00000008, |
257 | 0x00000024,0x0000001d,0x00000023,0x00050041,0x00000021,0x00000025,0x00000020,0x00000013, |
258 | 0x0004003d,0x00000008,0x00000026,0x00000025,0x00050081,0x00000008,0x00000027,0x00000024, |
259 | 0x00000026,0x00050051,0x00000006,0x0000002a,0x00000027,0x00000000,0x00050051,0x00000006, |
260 | 0x0000002b,0x00000027,0x00000001,0x00070050,0x00000007,0x0000002c,0x0000002a,0x0000002b, |
261 | 0x00000028,0x00000029,0x00050041,0x00000011,0x0000002d,0x0000001b,0x0000000d,0x0003003e, |
262 | 0x0000002d,0x0000002c,0x000100fd,0x00010038 |
263 | }; |
264 | |
265 | // glsl_shader.frag, compiled with: |
266 | // # glslangValidator -V -x -o glsl_shader.frag.u32 glsl_shader.frag |
267 | /* |
268 | #version 450 core |
269 | layout(location = 0) out vec4 fColor; |
270 | layout(set=0, binding=0) uniform sampler2D sTexture; |
271 | layout(location = 0) in struct { vec4 Color; vec2 UV; } In; |
272 | void main() |
273 | { |
274 | fColor = In.Color * texture(sTexture, In.UV.st); |
275 | } |
276 | */ |
277 | static uint32_t __glsl_shader_frag_spv[] = |
278 | { |
279 | 0x07230203,0x00010000,0x00080001,0x0000001e,0x00000000,0x00020011,0x00000001,0x0006000b, |
280 | 0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,0x00000000,0x00000001, |
281 | 0x0007000f,0x00000004,0x00000004,0x6e69616d,0x00000000,0x00000009,0x0000000d,0x00030010, |
282 | 0x00000004,0x00000007,0x00030003,0x00000002,0x000001c2,0x00040005,0x00000004,0x6e69616d, |
283 | 0x00000000,0x00040005,0x00000009,0x6c6f4366,0x0000726f,0x00030005,0x0000000b,0x00000000, |
284 | 0x00050006,0x0000000b,0x00000000,0x6f6c6f43,0x00000072,0x00040006,0x0000000b,0x00000001, |
285 | 0x00005655,0x00030005,0x0000000d,0x00006e49,0x00050005,0x00000016,0x78655473,0x65727574, |
286 | 0x00000000,0x00040047,0x00000009,0x0000001e,0x00000000,0x00040047,0x0000000d,0x0000001e, |
287 | 0x00000000,0x00040047,0x00000016,0x00000022,0x00000000,0x00040047,0x00000016,0x00000021, |
288 | 0x00000000,0x00020013,0x00000002,0x00030021,0x00000003,0x00000002,0x00030016,0x00000006, |
289 | 0x00000020,0x00040017,0x00000007,0x00000006,0x00000004,0x00040020,0x00000008,0x00000003, |
290 | 0x00000007,0x0004003b,0x00000008,0x00000009,0x00000003,0x00040017,0x0000000a,0x00000006, |
291 | 0x00000002,0x0004001e,0x0000000b,0x00000007,0x0000000a,0x00040020,0x0000000c,0x00000001, |
292 | 0x0000000b,0x0004003b,0x0000000c,0x0000000d,0x00000001,0x00040015,0x0000000e,0x00000020, |
293 | 0x00000001,0x0004002b,0x0000000e,0x0000000f,0x00000000,0x00040020,0x00000010,0x00000001, |
294 | 0x00000007,0x00090019,0x00000013,0x00000006,0x00000001,0x00000000,0x00000000,0x00000000, |
295 | 0x00000001,0x00000000,0x0003001b,0x00000014,0x00000013,0x00040020,0x00000015,0x00000000, |
296 | 0x00000014,0x0004003b,0x00000015,0x00000016,0x00000000,0x0004002b,0x0000000e,0x00000018, |
297 | 0x00000001,0x00040020,0x00000019,0x00000001,0x0000000a,0x00050036,0x00000002,0x00000004, |
298 | 0x00000000,0x00000003,0x000200f8,0x00000005,0x00050041,0x00000010,0x00000011,0x0000000d, |
299 | 0x0000000f,0x0004003d,0x00000007,0x00000012,0x00000011,0x0004003d,0x00000014,0x00000017, |
300 | 0x00000016,0x00050041,0x00000019,0x0000001a,0x0000000d,0x00000018,0x0004003d,0x0000000a, |
301 | 0x0000001b,0x0000001a,0x00050057,0x00000007,0x0000001c,0x00000017,0x0000001b,0x00050085, |
302 | 0x00000007,0x0000001d,0x00000012,0x0000001c,0x0003003e,0x00000009,0x0000001d,0x000100fd, |
303 | 0x00010038 |
304 | }; |
305 | |
306 | //----------------------------------------------------------------------------- |
307 | // FUNCTIONS |
308 | //----------------------------------------------------------------------------- |
309 | |
310 | // Backend data stored in io.BackendRendererUserData to allow support for multiple Dear ImGui contexts |
311 | // It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts. |
312 | // FIXME: multi-context support is not tested and probably dysfunctional in this backend. |
313 | static ImGui_ImplVulkan_Data* ImGui_ImplVulkan_GetBackendData() |
314 | { |
315 | return ImGui::GetCurrentContext() ? (ImGui_ImplVulkan_Data*)ImGui::GetIO().BackendRendererUserData : NULL; |
316 | } |
317 | |
318 | static uint32_t ImGui_ImplVulkan_MemoryType(VkMemoryPropertyFlags properties, uint32_t type_bits) |
319 | { |
320 | ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); |
321 | ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo; |
322 | VkPhysicalDeviceMemoryProperties prop; |
323 | vkGetPhysicalDeviceMemoryProperties(v->PhysicalDevice, &prop); |
324 | for (uint32_t i = 0; i < prop.memoryTypeCount; i++) |
325 | if ((prop.memoryTypes[i].propertyFlags & properties) == properties && type_bits & (1 << i)) |
326 | return i; |
327 | return 0xFFFFFFFF; // Unable to find memoryType |
328 | } |
329 | |
330 | static void check_vk_result(VkResult err) |
331 | { |
332 | ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); |
333 | if (!bd) |
334 | return; |
335 | ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo; |
336 | if (v->CheckVkResultFn) |
337 | v->CheckVkResultFn(err); |
338 | } |
339 | |
340 | static void CreateOrResizeBuffer(VkBuffer& buffer, VkDeviceMemory& buffer_memory, VkDeviceSize& p_buffer_size, size_t new_size, VkBufferUsageFlagBits usage) |
341 | { |
342 | ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); |
343 | ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo; |
344 | VkResult err; |
345 | if (buffer != VK_NULL_HANDLE) |
346 | vkDestroyBuffer(v->Device, buffer, v->Allocator); |
347 | if (buffer_memory != VK_NULL_HANDLE) |
348 | vkFreeMemory(v->Device, buffer_memory, v->Allocator); |
349 | |
350 | VkDeviceSize vertex_buffer_size_aligned = ((new_size - 1) / bd->BufferMemoryAlignment + 1) * bd->BufferMemoryAlignment; |
351 | VkBufferCreateInfo buffer_info = {}; |
352 | buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; |
353 | buffer_info.size = vertex_buffer_size_aligned; |
354 | buffer_info.usage = usage; |
355 | buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; |
356 | err = vkCreateBuffer(v->Device, &buffer_info, v->Allocator, &buffer); |
357 | check_vk_result(err); |
358 | |
359 | VkMemoryRequirements req; |
360 | vkGetBufferMemoryRequirements(v->Device, buffer, &req); |
361 | bd->BufferMemoryAlignment = (bd->BufferMemoryAlignment > req.alignment) ? bd->BufferMemoryAlignment : req.alignment; |
362 | VkMemoryAllocateInfo alloc_info = {}; |
363 | alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; |
364 | alloc_info.allocationSize = req.size; |
365 | alloc_info.memoryTypeIndex = ImGui_ImplVulkan_MemoryType(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, req.memoryTypeBits); |
366 | err = vkAllocateMemory(v->Device, &alloc_info, v->Allocator, &buffer_memory); |
367 | check_vk_result(err); |
368 | |
369 | err = vkBindBufferMemory(v->Device, buffer, buffer_memory, 0); |
370 | check_vk_result(err); |
371 | p_buffer_size = req.size; |
372 | } |
373 | |
374 | static void ImGui_ImplVulkan_SetupRenderState(ImDrawData* draw_data, VkPipeline pipeline, VkCommandBuffer command_buffer, ImGui_ImplVulkanH_FrameRenderBuffers* rb, int fb_width, int fb_height) |
375 | { |
376 | ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); |
377 | |
378 | // Bind pipeline and descriptor sets: |
379 | { |
380 | vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); |
381 | VkDescriptorSet desc_set[1] = { bd->DescriptorSet }; |
382 | vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, bd->PipelineLayout, 0, 1, desc_set, 0, NULL); |
383 | } |
384 | |
385 | // Bind Vertex And Index Buffer: |
386 | if (draw_data->TotalVtxCount > 0) |
387 | { |
388 | VkBuffer vertex_buffers[1] = { rb->VertexBuffer }; |
389 | VkDeviceSize vertex_offset[1] = { 0 }; |
390 | vkCmdBindVertexBuffers(command_buffer, 0, 1, vertex_buffers, vertex_offset); |
391 | vkCmdBindIndexBuffer(command_buffer, rb->IndexBuffer, 0, sizeof(ImDrawIdx) == 2 ? VK_INDEX_TYPE_UINT16 : VK_INDEX_TYPE_UINT32); |
392 | } |
393 | |
394 | // Setup viewport: |
395 | { |
396 | VkViewport viewport; |
397 | viewport.x = 0; |
398 | viewport.y = 0; |
399 | viewport.width = (float)fb_width; |
400 | viewport.height = (float)fb_height; |
401 | viewport.minDepth = 0.0f; |
402 | viewport.maxDepth = 1.0f; |
403 | vkCmdSetViewport(command_buffer, 0, 1, &viewport); |
404 | } |
405 | |
406 | // Setup scale and translation: |
407 | // 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. |
408 | { |
409 | float scale[2]; |
410 | scale[0] = 2.0f / draw_data->DisplaySize.x; |
411 | scale[1] = 2.0f / draw_data->DisplaySize.y; |
412 | float translate[2]; |
413 | translate[0] = -1.0f - draw_data->DisplayPos.x * scale[0]; |
414 | translate[1] = -1.0f - draw_data->DisplayPos.y * scale[1]; |
415 | vkCmdPushConstants(command_buffer, bd->PipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, sizeof(float) * 0, sizeof(float) * 2, scale); |
416 | vkCmdPushConstants(command_buffer, bd->PipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, sizeof(float) * 2, sizeof(float) * 2, translate); |
417 | } |
418 | } |
419 | |
420 | // Render function |
421 | void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer command_buffer, VkPipeline pipeline) |
422 | { |
423 | // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates) |
424 | int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x); |
425 | int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y); |
426 | if (fb_width <= 0 || fb_height <= 0) |
427 | return; |
428 | |
429 | ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); |
430 | ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo; |
431 | if (pipeline == VK_NULL_HANDLE) |
432 | pipeline = bd->Pipeline; |
433 | |
434 | // Allocate array to store enough vertex/index buffers |
435 | ImGui_ImplVulkanH_WindowRenderBuffers* wrb = &bd->MainWindowRenderBuffers; |
436 | if (wrb->FrameRenderBuffers == NULL) |
437 | { |
438 | wrb->Index = 0; |
439 | wrb->Count = v->ImageCount; |
440 | wrb->FrameRenderBuffers = (ImGui_ImplVulkanH_FrameRenderBuffers*)IM_ALLOC(sizeof(ImGui_ImplVulkanH_FrameRenderBuffers) * wrb->Count); |
441 | memset(wrb->FrameRenderBuffers, 0, sizeof(ImGui_ImplVulkanH_FrameRenderBuffers) * wrb->Count); |
442 | } |
443 | IM_ASSERT(wrb->Count == v->ImageCount); |
444 | wrb->Index = (wrb->Index + 1) % wrb->Count; |
445 | ImGui_ImplVulkanH_FrameRenderBuffers* rb = &wrb->FrameRenderBuffers[wrb->Index]; |
446 | |
447 | if (draw_data->TotalVtxCount > 0) |
448 | { |
449 | // Create or resize the vertex/index buffers |
450 | size_t vertex_size = draw_data->TotalVtxCount * sizeof(ImDrawVert); |
451 | size_t index_size = draw_data->TotalIdxCount * sizeof(ImDrawIdx); |
452 | if (rb->VertexBuffer == VK_NULL_HANDLE || rb->VertexBufferSize < vertex_size) |
453 | CreateOrResizeBuffer(rb->VertexBuffer, rb->VertexBufferMemory, rb->VertexBufferSize, vertex_size, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT); |
454 | if (rb->IndexBuffer == VK_NULL_HANDLE || rb->IndexBufferSize < index_size) |
455 | CreateOrResizeBuffer(rb->IndexBuffer, rb->IndexBufferMemory, rb->IndexBufferSize, index_size, VK_BUFFER_USAGE_INDEX_BUFFER_BIT); |
456 | |
457 | // Upload vertex/index data into a single contiguous GPU buffer |
458 | ImDrawVert* vtx_dst = NULL; |
459 | ImDrawIdx* idx_dst = NULL; |
460 | VkResult err = vkMapMemory(v->Device, rb->VertexBufferMemory, 0, rb->VertexBufferSize, 0, (void**)(&vtx_dst)); |
461 | check_vk_result(err); |
462 | err = vkMapMemory(v->Device, rb->IndexBufferMemory, 0, rb->IndexBufferSize, 0, (void**)(&idx_dst)); |
463 | check_vk_result(err); |
464 | for (int n = 0; n < draw_data->CmdListsCount; n++) |
465 | { |
466 | const ImDrawList* cmd_list = draw_data->CmdLists[n]; |
467 | memcpy(vtx_dst, cmd_list->VtxBuffer.Data, cmd_list->VtxBuffer.Size * sizeof(ImDrawVert)); |
468 | memcpy(idx_dst, cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx)); |
469 | vtx_dst += cmd_list->VtxBuffer.Size; |
470 | idx_dst += cmd_list->IdxBuffer.Size; |
471 | } |
472 | VkMappedMemoryRange range[2] = {}; |
473 | range[0].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE; |
474 | range[0].memory = rb->VertexBufferMemory; |
475 | range[0].size = VK_WHOLE_SIZE; |
476 | range[1].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE; |
477 | range[1].memory = rb->IndexBufferMemory; |
478 | range[1].size = VK_WHOLE_SIZE; |
479 | err = vkFlushMappedMemoryRanges(v->Device, 2, range); |
480 | check_vk_result(err); |
481 | vkUnmapMemory(v->Device, rb->VertexBufferMemory); |
482 | vkUnmapMemory(v->Device, rb->IndexBufferMemory); |
483 | } |
484 | |
485 | // Setup desired Vulkan state |
486 | ImGui_ImplVulkan_SetupRenderState(draw_data, pipeline, command_buffer, rb, fb_width, fb_height); |
487 | |
488 | // Will project scissor/clipping rectangles into framebuffer space |
489 | ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports |
490 | ImVec2 clip_scale = draw_data->FramebufferScale; // (1,1) unless using retina display which are often (2,2) |
491 | |
492 | // Render command lists |
493 | // (Because we merged all buffers into a single one, we maintain our own offset into them) |
494 | int global_vtx_offset = 0; |
495 | int global_idx_offset = 0; |
496 | for (int n = 0; n < draw_data->CmdListsCount; n++) |
497 | { |
498 | const ImDrawList* cmd_list = draw_data->CmdLists[n]; |
499 | for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) |
500 | { |
501 | const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; |
502 | if (pcmd->UserCallback != NULL) |
503 | { |
504 | // User callback, registered via ImDrawList::AddCallback() |
505 | // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.) |
506 | if (pcmd->UserCallback == ImDrawCallback_ResetRenderState) |
507 | ImGui_ImplVulkan_SetupRenderState(draw_data, pipeline, command_buffer, rb, fb_width, fb_height); |
508 | else |
509 | pcmd->UserCallback(cmd_list, pcmd); |
510 | } |
511 | else |
512 | { |
513 | // Project scissor/clipping rectangles into framebuffer space |
514 | ImVec4 clip_rect; |
515 | clip_rect.x = (pcmd->ClipRect.x - clip_off.x) * clip_scale.x; |
516 | clip_rect.y = (pcmd->ClipRect.y - clip_off.y) * clip_scale.y; |
517 | clip_rect.z = (pcmd->ClipRect.z - clip_off.x) * clip_scale.x; |
518 | clip_rect.w = (pcmd->ClipRect.w - clip_off.y) * clip_scale.y; |
519 | |
520 | if (clip_rect.x < fb_width && clip_rect.y < fb_height && clip_rect.z >= 0.0f && clip_rect.w >= 0.0f) |
521 | { |
522 | // Negative offsets are illegal for vkCmdSetScissor |
523 | if (clip_rect.x < 0.0f) |
524 | clip_rect.x = 0.0f; |
525 | if (clip_rect.y < 0.0f) |
526 | clip_rect.y = 0.0f; |
527 | |
528 | // Apply scissor/clipping rectangle |
529 | VkRect2D scissor; |
530 | scissor.offset.x = (int32_t)(clip_rect.x); |
531 | scissor.offset.y = (int32_t)(clip_rect.y); |
532 | scissor.extent.width = (uint32_t)(clip_rect.z - clip_rect.x); |
533 | scissor.extent.height = (uint32_t)(clip_rect.w - clip_rect.y); |
534 | vkCmdSetScissor(command_buffer, 0, 1, &scissor); |
535 | |
536 | // Draw |
537 | vkCmdDrawIndexed(command_buffer, pcmd->ElemCount, 1, pcmd->IdxOffset + global_idx_offset, pcmd->VtxOffset + global_vtx_offset, 0); |
538 | } |
539 | } |
540 | } |
541 | global_idx_offset += cmd_list->IdxBuffer.Size; |
542 | global_vtx_offset += cmd_list->VtxBuffer.Size; |
543 | } |
544 | } |
545 | |
546 | bool ImGui_ImplVulkan_CreateFontsTexture(VkCommandBuffer command_buffer) |
547 | { |
548 | ImGuiIO& io = ImGui::GetIO(); |
549 | ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); |
550 | ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo; |
551 | |
552 | unsigned char* pixels; |
553 | int width, height; |
554 | io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); |
555 | size_t upload_size = width * height * 4 * sizeof(char); |
556 | |
557 | VkResult err; |
558 | |
559 | // Create the Image: |
560 | { |
561 | VkImageCreateInfo info = {}; |
562 | info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; |
563 | info.imageType = VK_IMAGE_TYPE_2D; |
564 | info.format = VK_FORMAT_R8G8B8A8_UNORM; |
565 | info.extent.width = width; |
566 | info.extent.height = height; |
567 | info.extent.depth = 1; |
568 | info.mipLevels = 1; |
569 | info.arrayLayers = 1; |
570 | info.samples = VK_SAMPLE_COUNT_1_BIT; |
571 | info.tiling = VK_IMAGE_TILING_OPTIMAL; |
572 | info.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; |
573 | info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; |
574 | info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; |
575 | err = vkCreateImage(v->Device, &info, v->Allocator, &bd->FontImage); |
576 | check_vk_result(err); |
577 | VkMemoryRequirements req; |
578 | vkGetImageMemoryRequirements(v->Device, bd->FontImage, &req); |
579 | VkMemoryAllocateInfo alloc_info = {}; |
580 | alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; |
581 | alloc_info.allocationSize = req.size; |
582 | alloc_info.memoryTypeIndex = ImGui_ImplVulkan_MemoryType(VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, req.memoryTypeBits); |
583 | err = vkAllocateMemory(v->Device, &alloc_info, v->Allocator, &bd->FontMemory); |
584 | check_vk_result(err); |
585 | err = vkBindImageMemory(v->Device, bd->FontImage, bd->FontMemory, 0); |
586 | check_vk_result(err); |
587 | } |
588 | |
589 | // Create the Image View: |
590 | { |
591 | VkImageViewCreateInfo info = {}; |
592 | info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; |
593 | info.image = bd->FontImage; |
594 | info.viewType = VK_IMAGE_VIEW_TYPE_2D; |
595 | info.format = VK_FORMAT_R8G8B8A8_UNORM; |
596 | info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; |
597 | info.subresourceRange.levelCount = 1; |
598 | info.subresourceRange.layerCount = 1; |
599 | err = vkCreateImageView(v->Device, &info, v->Allocator, &bd->FontView); |
600 | check_vk_result(err); |
601 | } |
602 | |
603 | // Update the Descriptor Set: |
604 | { |
605 | VkDescriptorImageInfo desc_image[1] = {}; |
606 | desc_image[0].sampler = bd->FontSampler; |
607 | desc_image[0].imageView = bd->FontView; |
608 | desc_image[0].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; |
609 | VkWriteDescriptorSet write_desc[1] = {}; |
610 | write_desc[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; |
611 | write_desc[0].dstSet = bd->DescriptorSet; |
612 | write_desc[0].descriptorCount = 1; |
613 | write_desc[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; |
614 | write_desc[0].pImageInfo = desc_image; |
615 | vkUpdateDescriptorSets(v->Device, 1, write_desc, 0, NULL); |
616 | } |
617 | |
618 | // Create the Upload Buffer: |
619 | { |
620 | VkBufferCreateInfo buffer_info = {}; |
621 | buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; |
622 | buffer_info.size = upload_size; |
623 | buffer_info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; |
624 | buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; |
625 | err = vkCreateBuffer(v->Device, &buffer_info, v->Allocator, &bd->UploadBuffer); |
626 | check_vk_result(err); |
627 | VkMemoryRequirements req; |
628 | vkGetBufferMemoryRequirements(v->Device, bd->UploadBuffer, &req); |
629 | bd->BufferMemoryAlignment = (bd->BufferMemoryAlignment > req.alignment) ? bd->BufferMemoryAlignment : req.alignment; |
630 | VkMemoryAllocateInfo alloc_info = {}; |
631 | alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; |
632 | alloc_info.allocationSize = req.size; |
633 | alloc_info.memoryTypeIndex = ImGui_ImplVulkan_MemoryType(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, req.memoryTypeBits); |
634 | err = vkAllocateMemory(v->Device, &alloc_info, v->Allocator, &bd->UploadBufferMemory); |
635 | check_vk_result(err); |
636 | err = vkBindBufferMemory(v->Device, bd->UploadBuffer, bd->UploadBufferMemory, 0); |
637 | check_vk_result(err); |
638 | } |
639 | |
640 | // Upload to Buffer: |
641 | { |
642 | char* map = NULL; |
643 | err = vkMapMemory(v->Device, bd->UploadBufferMemory, 0, upload_size, 0, (void**)(&map)); |
644 | check_vk_result(err); |
645 | memcpy(map, pixels, upload_size); |
646 | VkMappedMemoryRange range[1] = {}; |
647 | range[0].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE; |
648 | range[0].memory = bd->UploadBufferMemory; |
649 | range[0].size = upload_size; |
650 | err = vkFlushMappedMemoryRanges(v->Device, 1, range); |
651 | check_vk_result(err); |
652 | vkUnmapMemory(v->Device, bd->UploadBufferMemory); |
653 | } |
654 | |
655 | // Copy to Image: |
656 | { |
657 | VkImageMemoryBarrier copy_barrier[1] = {}; |
658 | copy_barrier[0].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; |
659 | copy_barrier[0].dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; |
660 | copy_barrier[0].oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; |
661 | copy_barrier[0].newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; |
662 | copy_barrier[0].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; |
663 | copy_barrier[0].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; |
664 | copy_barrier[0].image = bd->FontImage; |
665 | copy_barrier[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; |
666 | copy_barrier[0].subresourceRange.levelCount = 1; |
667 | copy_barrier[0].subresourceRange.layerCount = 1; |
668 | vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 0, NULL, 1, copy_barrier); |
669 | |
670 | VkBufferImageCopy region = {}; |
671 | region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; |
672 | region.imageSubresource.layerCount = 1; |
673 | region.imageExtent.width = width; |
674 | region.imageExtent.height = height; |
675 | region.imageExtent.depth = 1; |
676 | vkCmdCopyBufferToImage(command_buffer, bd->UploadBuffer, bd->FontImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); |
677 | |
678 | VkImageMemoryBarrier use_barrier[1] = {}; |
679 | use_barrier[0].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; |
680 | use_barrier[0].srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; |
681 | use_barrier[0].dstAccessMask = VK_ACCESS_SHADER_READ_BIT; |
682 | use_barrier[0].oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; |
683 | use_barrier[0].newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; |
684 | use_barrier[0].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; |
685 | use_barrier[0].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; |
686 | use_barrier[0].image = bd->FontImage; |
687 | use_barrier[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; |
688 | use_barrier[0].subresourceRange.levelCount = 1; |
689 | use_barrier[0].subresourceRange.layerCount = 1; |
690 | vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, use_barrier); |
691 | } |
692 | |
693 | // Store our identifier |
694 | io.Fonts->SetTexID((ImTextureID)(intptr_t)bd->FontImage); |
695 | |
696 | return true; |
697 | } |
698 | |
699 | static void ImGui_ImplVulkan_CreateShaderModules(VkDevice device, const VkAllocationCallbacks* allocator) |
700 | { |
701 | // Create the shader modules |
702 | ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); |
703 | if (bd->ShaderModuleVert == NULL) |
704 | { |
705 | VkShaderModuleCreateInfo vert_info = {}; |
706 | vert_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; |
707 | vert_info.codeSize = sizeof(__glsl_shader_vert_spv); |
708 | vert_info.pCode = (uint32_t*)__glsl_shader_vert_spv; |
709 | VkResult err = vkCreateShaderModule(device, &vert_info, allocator, &bd->ShaderModuleVert); |
710 | check_vk_result(err); |
711 | } |
712 | if (bd->ShaderModuleFrag == NULL) |
713 | { |
714 | VkShaderModuleCreateInfo frag_info = {}; |
715 | frag_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; |
716 | frag_info.codeSize = sizeof(__glsl_shader_frag_spv); |
717 | frag_info.pCode = (uint32_t*)__glsl_shader_frag_spv; |
718 | VkResult err = vkCreateShaderModule(device, &frag_info, allocator, &bd->ShaderModuleFrag); |
719 | check_vk_result(err); |
720 | } |
721 | } |
722 | |
723 | static void ImGui_ImplVulkan_CreateFontSampler(VkDevice device, const VkAllocationCallbacks* allocator) |
724 | { |
725 | ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); |
726 | if (bd->FontSampler) |
727 | return; |
728 | |
729 | VkSamplerCreateInfo info = {}; |
730 | info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; |
731 | info.magFilter = VK_FILTER_LINEAR; |
732 | info.minFilter = VK_FILTER_LINEAR; |
733 | info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; |
734 | info.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT; |
735 | info.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT; |
736 | info.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT; |
737 | info.minLod = -1000; |
738 | info.maxLod = 1000; |
739 | info.maxAnisotropy = 1.0f; |
740 | VkResult err = vkCreateSampler(device, &info, allocator, &bd->FontSampler); |
741 | check_vk_result(err); |
742 | } |
743 | |
744 | static void ImGui_ImplVulkan_CreateDescriptorSetLayout(VkDevice device, const VkAllocationCallbacks* allocator) |
745 | { |
746 | ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); |
747 | if (bd->DescriptorSetLayout) |
748 | return; |
749 | |
750 | ImGui_ImplVulkan_CreateFontSampler(device, allocator); |
751 | VkSampler sampler[1] = { bd->FontSampler }; |
752 | VkDescriptorSetLayoutBinding binding[1] = {}; |
753 | binding[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; |
754 | binding[0].descriptorCount = 1; |
755 | binding[0].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; |
756 | binding[0].pImmutableSamplers = sampler; |
757 | VkDescriptorSetLayoutCreateInfo info = {}; |
758 | info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; |
759 | info.bindingCount = 1; |
760 | info.pBindings = binding; |
761 | VkResult err = vkCreateDescriptorSetLayout(device, &info, allocator, &bd->DescriptorSetLayout); |
762 | check_vk_result(err); |
763 | } |
764 | |
765 | static void ImGui_ImplVulkan_CreatePipelineLayout(VkDevice device, const VkAllocationCallbacks* allocator) |
766 | { |
767 | ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); |
768 | if (bd->PipelineLayout) |
769 | return; |
770 | |
771 | // Constants: we are using 'vec2 offset' and 'vec2 scale' instead of a full 3d projection matrix |
772 | ImGui_ImplVulkan_CreateDescriptorSetLayout(device, allocator); |
773 | VkPushConstantRange push_constants[1] = {}; |
774 | push_constants[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; |
775 | push_constants[0].offset = sizeof(float) * 0; |
776 | push_constants[0].size = sizeof(float) * 4; |
777 | VkDescriptorSetLayout set_layout[1] = { bd->DescriptorSetLayout }; |
778 | VkPipelineLayoutCreateInfo layout_info = {}; |
779 | layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; |
780 | layout_info.setLayoutCount = 1; |
781 | layout_info.pSetLayouts = set_layout; |
782 | layout_info.pushConstantRangeCount = 1; |
783 | layout_info.pPushConstantRanges = push_constants; |
784 | VkResult err = vkCreatePipelineLayout(device, &layout_info, allocator, &bd->PipelineLayout); |
785 | check_vk_result(err); |
786 | } |
787 | |
788 | static void ImGui_ImplVulkan_CreatePipeline(VkDevice device, const VkAllocationCallbacks* allocator, VkPipelineCache pipelineCache, VkRenderPass renderPass, VkSampleCountFlagBits MSAASamples, VkPipeline* pipeline, uint32_t subpass) |
789 | { |
790 | ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); |
791 | ImGui_ImplVulkan_CreateShaderModules(device, allocator); |
792 | |
793 | VkPipelineShaderStageCreateInfo stage[2] = {}; |
794 | stage[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; |
795 | stage[0].stage = VK_SHADER_STAGE_VERTEX_BIT; |
796 | stage[0].module = bd->ShaderModuleVert; |
797 | stage[0].pName = "main" ; |
798 | stage[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; |
799 | stage[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT; |
800 | stage[1].module = bd->ShaderModuleFrag; |
801 | stage[1].pName = "main" ; |
802 | |
803 | VkVertexInputBindingDescription binding_desc[1] = {}; |
804 | binding_desc[0].stride = sizeof(ImDrawVert); |
805 | binding_desc[0].inputRate = VK_VERTEX_INPUT_RATE_VERTEX; |
806 | |
807 | VkVertexInputAttributeDescription attribute_desc[3] = {}; |
808 | attribute_desc[0].location = 0; |
809 | attribute_desc[0].binding = binding_desc[0].binding; |
810 | attribute_desc[0].format = VK_FORMAT_R32G32_SFLOAT; |
811 | attribute_desc[0].offset = IM_OFFSETOF(ImDrawVert, pos); |
812 | attribute_desc[1].location = 1; |
813 | attribute_desc[1].binding = binding_desc[0].binding; |
814 | attribute_desc[1].format = VK_FORMAT_R32G32_SFLOAT; |
815 | attribute_desc[1].offset = IM_OFFSETOF(ImDrawVert, uv); |
816 | attribute_desc[2].location = 2; |
817 | attribute_desc[2].binding = binding_desc[0].binding; |
818 | attribute_desc[2].format = VK_FORMAT_R8G8B8A8_UNORM; |
819 | attribute_desc[2].offset = IM_OFFSETOF(ImDrawVert, col); |
820 | |
821 | VkPipelineVertexInputStateCreateInfo vertex_info = {}; |
822 | vertex_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; |
823 | vertex_info.vertexBindingDescriptionCount = 1; |
824 | vertex_info.pVertexBindingDescriptions = binding_desc; |
825 | vertex_info.vertexAttributeDescriptionCount = 3; |
826 | vertex_info.pVertexAttributeDescriptions = attribute_desc; |
827 | |
828 | VkPipelineInputAssemblyStateCreateInfo ia_info = {}; |
829 | ia_info.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; |
830 | ia_info.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; |
831 | |
832 | VkPipelineViewportStateCreateInfo viewport_info = {}; |
833 | viewport_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; |
834 | viewport_info.viewportCount = 1; |
835 | viewport_info.scissorCount = 1; |
836 | |
837 | VkPipelineRasterizationStateCreateInfo raster_info = {}; |
838 | raster_info.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; |
839 | raster_info.polygonMode = VK_POLYGON_MODE_FILL; |
840 | raster_info.cullMode = VK_CULL_MODE_NONE; |
841 | raster_info.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; |
842 | raster_info.lineWidth = 1.0f; |
843 | |
844 | VkPipelineMultisampleStateCreateInfo ms_info = {}; |
845 | ms_info.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; |
846 | ms_info.rasterizationSamples = (MSAASamples != 0) ? MSAASamples : VK_SAMPLE_COUNT_1_BIT; |
847 | |
848 | VkPipelineColorBlendAttachmentState color_attachment[1] = {}; |
849 | color_attachment[0].blendEnable = VK_TRUE; |
850 | color_attachment[0].srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; |
851 | color_attachment[0].dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; |
852 | color_attachment[0].colorBlendOp = VK_BLEND_OP_ADD; |
853 | color_attachment[0].srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; |
854 | color_attachment[0].dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; |
855 | color_attachment[0].alphaBlendOp = VK_BLEND_OP_ADD; |
856 | color_attachment[0].colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; |
857 | |
858 | VkPipelineDepthStencilStateCreateInfo depth_info = {}; |
859 | depth_info.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; |
860 | |
861 | VkPipelineColorBlendStateCreateInfo blend_info = {}; |
862 | blend_info.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; |
863 | blend_info.attachmentCount = 1; |
864 | blend_info.pAttachments = color_attachment; |
865 | |
866 | VkDynamicState dynamic_states[2] = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR }; |
867 | VkPipelineDynamicStateCreateInfo dynamic_state = {}; |
868 | dynamic_state.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; |
869 | dynamic_state.dynamicStateCount = (uint32_t)IM_ARRAYSIZE(dynamic_states); |
870 | dynamic_state.pDynamicStates = dynamic_states; |
871 | |
872 | ImGui_ImplVulkan_CreatePipelineLayout(device, allocator); |
873 | |
874 | VkGraphicsPipelineCreateInfo info = {}; |
875 | info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; |
876 | info.flags = bd->PipelineCreateFlags; |
877 | info.stageCount = 2; |
878 | info.pStages = stage; |
879 | info.pVertexInputState = &vertex_info; |
880 | info.pInputAssemblyState = &ia_info; |
881 | info.pViewportState = &viewport_info; |
882 | info.pRasterizationState = &raster_info; |
883 | info.pMultisampleState = &ms_info; |
884 | info.pDepthStencilState = &depth_info; |
885 | info.pColorBlendState = &blend_info; |
886 | info.pDynamicState = &dynamic_state; |
887 | info.layout = bd->PipelineLayout; |
888 | info.renderPass = renderPass; |
889 | info.subpass = subpass; |
890 | VkResult err = vkCreateGraphicsPipelines(device, pipelineCache, 1, &info, allocator, pipeline); |
891 | check_vk_result(err); |
892 | } |
893 | |
894 | bool ImGui_ImplVulkan_CreateDeviceObjects() |
895 | { |
896 | ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); |
897 | ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo; |
898 | VkResult err; |
899 | |
900 | if (!bd->FontSampler) |
901 | { |
902 | VkSamplerCreateInfo info = {}; |
903 | info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; |
904 | info.magFilter = VK_FILTER_LINEAR; |
905 | info.minFilter = VK_FILTER_LINEAR; |
906 | info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; |
907 | info.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT; |
908 | info.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT; |
909 | info.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT; |
910 | info.minLod = -1000; |
911 | info.maxLod = 1000; |
912 | info.maxAnisotropy = 1.0f; |
913 | err = vkCreateSampler(v->Device, &info, v->Allocator, &bd->FontSampler); |
914 | check_vk_result(err); |
915 | } |
916 | |
917 | if (!bd->DescriptorSetLayout) |
918 | { |
919 | VkSampler sampler[1] = {bd->FontSampler}; |
920 | VkDescriptorSetLayoutBinding binding[1] = {}; |
921 | binding[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; |
922 | binding[0].descriptorCount = 1; |
923 | binding[0].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; |
924 | binding[0].pImmutableSamplers = sampler; |
925 | VkDescriptorSetLayoutCreateInfo info = {}; |
926 | info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; |
927 | info.bindingCount = 1; |
928 | info.pBindings = binding; |
929 | err = vkCreateDescriptorSetLayout(v->Device, &info, v->Allocator, &bd->DescriptorSetLayout); |
930 | check_vk_result(err); |
931 | } |
932 | |
933 | // Create Descriptor Set: |
934 | { |
935 | VkDescriptorSetAllocateInfo alloc_info = {}; |
936 | alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; |
937 | alloc_info.descriptorPool = v->DescriptorPool; |
938 | alloc_info.descriptorSetCount = 1; |
939 | alloc_info.pSetLayouts = &bd->DescriptorSetLayout; |
940 | err = vkAllocateDescriptorSets(v->Device, &alloc_info, &bd->DescriptorSet); |
941 | check_vk_result(err); |
942 | } |
943 | |
944 | if (!bd->PipelineLayout) |
945 | { |
946 | // Constants: we are using 'vec2 offset' and 'vec2 scale' instead of a full 3d projection matrix |
947 | VkPushConstantRange push_constants[1] = {}; |
948 | push_constants[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; |
949 | push_constants[0].offset = sizeof(float) * 0; |
950 | push_constants[0].size = sizeof(float) * 4; |
951 | VkDescriptorSetLayout set_layout[1] = { bd->DescriptorSetLayout }; |
952 | VkPipelineLayoutCreateInfo layout_info = {}; |
953 | layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; |
954 | layout_info.setLayoutCount = 1; |
955 | layout_info.pSetLayouts = set_layout; |
956 | layout_info.pushConstantRangeCount = 1; |
957 | layout_info.pPushConstantRanges = push_constants; |
958 | err = vkCreatePipelineLayout(v->Device, &layout_info, v->Allocator, &bd->PipelineLayout); |
959 | check_vk_result(err); |
960 | } |
961 | |
962 | ImGui_ImplVulkan_CreatePipeline(v->Device, v->Allocator, v->PipelineCache, bd->RenderPass, v->MSAASamples, &bd->Pipeline, bd->Subpass); |
963 | |
964 | return true; |
965 | } |
966 | |
967 | void ImGui_ImplVulkan_DestroyFontUploadObjects() |
968 | { |
969 | ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); |
970 | ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo; |
971 | if (bd->UploadBuffer) |
972 | { |
973 | vkDestroyBuffer(v->Device, bd->UploadBuffer, v->Allocator); |
974 | bd->UploadBuffer = VK_NULL_HANDLE; |
975 | } |
976 | if (bd->UploadBufferMemory) |
977 | { |
978 | vkFreeMemory(v->Device, bd->UploadBufferMemory, v->Allocator); |
979 | bd->UploadBufferMemory = VK_NULL_HANDLE; |
980 | } |
981 | } |
982 | |
983 | void ImGui_ImplVulkan_DestroyDeviceObjects() |
984 | { |
985 | ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); |
986 | ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo; |
987 | ImGui_ImplVulkanH_DestroyWindowRenderBuffers(v->Device, &bd->MainWindowRenderBuffers, v->Allocator); |
988 | ImGui_ImplVulkan_DestroyFontUploadObjects(); |
989 | |
990 | if (bd->ShaderModuleVert) { vkDestroyShaderModule(v->Device, bd->ShaderModuleVert, v->Allocator); bd->ShaderModuleVert = VK_NULL_HANDLE; } |
991 | if (bd->ShaderModuleFrag) { vkDestroyShaderModule(v->Device, bd->ShaderModuleFrag, v->Allocator); bd->ShaderModuleFrag = VK_NULL_HANDLE; } |
992 | if (bd->FontView) { vkDestroyImageView(v->Device, bd->FontView, v->Allocator); bd->FontView = VK_NULL_HANDLE; } |
993 | if (bd->FontImage) { vkDestroyImage(v->Device, bd->FontImage, v->Allocator); bd->FontImage = VK_NULL_HANDLE; } |
994 | if (bd->FontMemory) { vkFreeMemory(v->Device, bd->FontMemory, v->Allocator); bd->FontMemory = VK_NULL_HANDLE; } |
995 | if (bd->FontSampler) { vkDestroySampler(v->Device, bd->FontSampler, v->Allocator); bd->FontSampler = VK_NULL_HANDLE; } |
996 | if (bd->DescriptorSetLayout) { vkDestroyDescriptorSetLayout(v->Device, bd->DescriptorSetLayout, v->Allocator); bd->DescriptorSetLayout = VK_NULL_HANDLE; } |
997 | if (bd->PipelineLayout) { vkDestroyPipelineLayout(v->Device, bd->PipelineLayout, v->Allocator); bd->PipelineLayout = VK_NULL_HANDLE; } |
998 | if (bd->Pipeline) { vkDestroyPipeline(v->Device, bd->Pipeline, v->Allocator); bd->Pipeline = VK_NULL_HANDLE; } |
999 | } |
1000 | |
1001 | bool ImGui_ImplVulkan_LoadFunctions(PFN_vkVoidFunction(*loader_func)(const char* function_name, void* user_data), void* user_data) |
1002 | { |
1003 | // Load function pointers |
1004 | // You can use the default Vulkan loader using: |
1005 | // ImGui_ImplVulkan_LoadFunctions([](const char* function_name, void*) { return vkGetInstanceProcAddr(your_vk_isntance, function_name); }); |
1006 | // But this would be equivalent to not setting VK_NO_PROTOTYPES. |
1007 | #ifdef VK_NO_PROTOTYPES |
1008 | #define IMGUI_VULKAN_FUNC_LOAD(func) \ |
1009 | func = reinterpret_cast<decltype(func)>(loader_func(#func, user_data)); \ |
1010 | if (func == NULL) \ |
1011 | return false; |
1012 | IMGUI_VULKAN_FUNC_MAP(IMGUI_VULKAN_FUNC_LOAD) |
1013 | #undef IMGUI_VULKAN_FUNC_LOAD |
1014 | #else |
1015 | IM_UNUSED(loader_func); |
1016 | IM_UNUSED(user_data); |
1017 | #endif |
1018 | g_FunctionsLoaded = true; |
1019 | return true; |
1020 | } |
1021 | |
1022 | bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info, VkRenderPass render_pass) |
1023 | { |
1024 | IM_ASSERT(g_FunctionsLoaded && "Need to call ImGui_ImplVulkan_LoadFunctions() if IMGUI_IMPL_VULKAN_NO_PROTOTYPES or VK_NO_PROTOTYPES are set!" ); |
1025 | |
1026 | ImGuiIO& io = ImGui::GetIO(); |
1027 | IM_ASSERT(io.BackendRendererUserData == NULL && "Already initialized a renderer backend!" ); |
1028 | |
1029 | // Setup backend capabilities flags |
1030 | ImGui_ImplVulkan_Data* bd = IM_NEW(ImGui_ImplVulkan_Data)(); |
1031 | io.BackendRendererUserData = (void*)bd; |
1032 | io.BackendRendererName = "imgui_impl_vulkan" ; |
1033 | io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes. |
1034 | |
1035 | IM_ASSERT(info->Instance != VK_NULL_HANDLE); |
1036 | IM_ASSERT(info->PhysicalDevice != VK_NULL_HANDLE); |
1037 | IM_ASSERT(info->Device != VK_NULL_HANDLE); |
1038 | IM_ASSERT(info->Queue != VK_NULL_HANDLE); |
1039 | IM_ASSERT(info->DescriptorPool != VK_NULL_HANDLE); |
1040 | IM_ASSERT(info->MinImageCount >= 2); |
1041 | IM_ASSERT(info->ImageCount >= info->MinImageCount); |
1042 | IM_ASSERT(render_pass != VK_NULL_HANDLE); |
1043 | |
1044 | bd->VulkanInitInfo = *info; |
1045 | bd->RenderPass = render_pass; |
1046 | bd->Subpass = info->Subpass; |
1047 | |
1048 | ImGui_ImplVulkan_CreateDeviceObjects(); |
1049 | |
1050 | return true; |
1051 | } |
1052 | |
1053 | void ImGui_ImplVulkan_Shutdown() |
1054 | { |
1055 | ImGuiIO& io = ImGui::GetIO(); |
1056 | ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); |
1057 | |
1058 | ImGui_ImplVulkan_DestroyDeviceObjects(); |
1059 | io.BackendRendererName = NULL; |
1060 | io.BackendRendererUserData = NULL; |
1061 | IM_DELETE(bd); |
1062 | } |
1063 | |
1064 | void ImGui_ImplVulkan_NewFrame() |
1065 | { |
1066 | ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); |
1067 | IM_ASSERT(bd != NULL && "Did you call ImGui_ImplVulkan_Init()?" ); |
1068 | IM_UNUSED(bd); |
1069 | } |
1070 | |
1071 | void ImGui_ImplVulkan_SetMinImageCount(uint32_t min_image_count) |
1072 | { |
1073 | ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); |
1074 | IM_ASSERT(min_image_count >= 2); |
1075 | if (bd->VulkanInitInfo.MinImageCount == min_image_count) |
1076 | return; |
1077 | |
1078 | ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo; |
1079 | VkResult err = vkDeviceWaitIdle(v->Device); |
1080 | check_vk_result(err); |
1081 | ImGui_ImplVulkanH_DestroyWindowRenderBuffers(v->Device, &bd->MainWindowRenderBuffers, v->Allocator); |
1082 | bd->VulkanInitInfo.MinImageCount = min_image_count; |
1083 | } |
1084 | |
1085 | |
1086 | //------------------------------------------------------------------------- |
1087 | // Internal / Miscellaneous Vulkan Helpers |
1088 | // (Used by example's main.cpp. Used by multi-viewport features. PROBABLY NOT used by your own app.) |
1089 | //------------------------------------------------------------------------- |
1090 | // You probably do NOT need to use or care about those functions. |
1091 | // Those functions only exist because: |
1092 | // 1) they facilitate the readability and maintenance of the multiple main.cpp examples files. |
1093 | // 2) the upcoming multi-viewport feature will need them internally. |
1094 | // Generally we avoid exposing any kind of superfluous high-level helpers in the backends, |
1095 | // but it is too much code to duplicate everywhere so we exceptionally expose them. |
1096 | // |
1097 | // Your engine/app will likely _already_ have code to setup all that stuff (swap chain, render pass, frame buffers, etc.). |
1098 | // You may read this code to learn about Vulkan, but it is recommended you use you own custom tailored code to do equivalent work. |
1099 | // (The ImGui_ImplVulkanH_XXX functions do not interact with any of the state used by the regular ImGui_ImplVulkan_XXX functions) |
1100 | //------------------------------------------------------------------------- |
1101 | |
1102 | VkSurfaceFormatKHR ImGui_ImplVulkanH_SelectSurfaceFormat(VkPhysicalDevice physical_device, VkSurfaceKHR surface, const VkFormat* request_formats, int request_formats_count, VkColorSpaceKHR request_color_space) |
1103 | { |
1104 | IM_ASSERT(g_FunctionsLoaded && "Need to call ImGui_ImplVulkan_LoadFunctions() if IMGUI_IMPL_VULKAN_NO_PROTOTYPES or VK_NO_PROTOTYPES are set!" ); |
1105 | IM_ASSERT(request_formats != NULL); |
1106 | IM_ASSERT(request_formats_count > 0); |
1107 | |
1108 | // Per Spec Format and View Format are expected to be the same unless VK_IMAGE_CREATE_MUTABLE_BIT was set at image creation |
1109 | // Assuming that the default behavior is without setting this bit, there is no need for separate Swapchain image and image view format |
1110 | // Additionally several new color spaces were introduced with Vulkan Spec v1.0.40, |
1111 | // hence we must make sure that a format with the mostly available color space, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR, is found and used. |
1112 | uint32_t avail_count; |
1113 | vkGetPhysicalDeviceSurfaceFormatsKHR(physical_device, surface, &avail_count, NULL); |
1114 | ImVector<VkSurfaceFormatKHR> avail_format; |
1115 | avail_format.resize((int)avail_count); |
1116 | vkGetPhysicalDeviceSurfaceFormatsKHR(physical_device, surface, &avail_count, avail_format.Data); |
1117 | |
1118 | // First check if only one format, VK_FORMAT_UNDEFINED, is available, which would imply that any format is available |
1119 | if (avail_count == 1) |
1120 | { |
1121 | if (avail_format[0].format == VK_FORMAT_UNDEFINED) |
1122 | { |
1123 | VkSurfaceFormatKHR ret; |
1124 | ret.format = request_formats[0]; |
1125 | ret.colorSpace = request_color_space; |
1126 | return ret; |
1127 | } |
1128 | else |
1129 | { |
1130 | // No point in searching another format |
1131 | return avail_format[0]; |
1132 | } |
1133 | } |
1134 | else |
1135 | { |
1136 | // Request several formats, the first found will be used |
1137 | for (int request_i = 0; request_i < request_formats_count; request_i++) |
1138 | for (uint32_t avail_i = 0; avail_i < avail_count; avail_i++) |
1139 | if (avail_format[avail_i].format == request_formats[request_i] && avail_format[avail_i].colorSpace == request_color_space) |
1140 | return avail_format[avail_i]; |
1141 | |
1142 | // If none of the requested image formats could be found, use the first available |
1143 | return avail_format[0]; |
1144 | } |
1145 | } |
1146 | |
1147 | VkPresentModeKHR ImGui_ImplVulkanH_SelectPresentMode(VkPhysicalDevice physical_device, VkSurfaceKHR surface, const VkPresentModeKHR* request_modes, int request_modes_count) |
1148 | { |
1149 | IM_ASSERT(g_FunctionsLoaded && "Need to call ImGui_ImplVulkan_LoadFunctions() if IMGUI_IMPL_VULKAN_NO_PROTOTYPES or VK_NO_PROTOTYPES are set!" ); |
1150 | IM_ASSERT(request_modes != NULL); |
1151 | IM_ASSERT(request_modes_count > 0); |
1152 | |
1153 | // Request a certain mode and confirm that it is available. If not use VK_PRESENT_MODE_FIFO_KHR which is mandatory |
1154 | uint32_t avail_count = 0; |
1155 | vkGetPhysicalDeviceSurfacePresentModesKHR(physical_device, surface, &avail_count, NULL); |
1156 | ImVector<VkPresentModeKHR> avail_modes; |
1157 | avail_modes.resize((int)avail_count); |
1158 | vkGetPhysicalDeviceSurfacePresentModesKHR(physical_device, surface, &avail_count, avail_modes.Data); |
1159 | //for (uint32_t avail_i = 0; avail_i < avail_count; avail_i++) |
1160 | // printf("[vulkan] avail_modes[%d] = %d\n", avail_i, avail_modes[avail_i]); |
1161 | |
1162 | for (int request_i = 0; request_i < request_modes_count; request_i++) |
1163 | for (uint32_t avail_i = 0; avail_i < avail_count; avail_i++) |
1164 | if (request_modes[request_i] == avail_modes[avail_i]) |
1165 | return request_modes[request_i]; |
1166 | |
1167 | return VK_PRESENT_MODE_FIFO_KHR; // Always available |
1168 | } |
1169 | |
1170 | void ImGui_ImplVulkanH_CreateWindowCommandBuffers(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, uint32_t queue_family, const VkAllocationCallbacks* allocator) |
1171 | { |
1172 | IM_ASSERT(physical_device != VK_NULL_HANDLE && device != VK_NULL_HANDLE); |
1173 | (void)physical_device; |
1174 | (void)allocator; |
1175 | |
1176 | // Create Command Buffers |
1177 | VkResult err; |
1178 | for (uint32_t i = 0; i < wd->ImageCount; i++) |
1179 | { |
1180 | ImGui_ImplVulkanH_Frame* fd = &wd->Frames[i]; |
1181 | ImGui_ImplVulkanH_FrameSemaphores* fsd = &wd->FrameSemaphores[i]; |
1182 | { |
1183 | VkCommandPoolCreateInfo info = {}; |
1184 | info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; |
1185 | info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; |
1186 | info.queueFamilyIndex = queue_family; |
1187 | err = vkCreateCommandPool(device, &info, allocator, &fd->CommandPool); |
1188 | check_vk_result(err); |
1189 | } |
1190 | { |
1191 | VkCommandBufferAllocateInfo info = {}; |
1192 | info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; |
1193 | info.commandPool = fd->CommandPool; |
1194 | info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; |
1195 | info.commandBufferCount = 1; |
1196 | err = vkAllocateCommandBuffers(device, &info, &fd->CommandBuffer); |
1197 | check_vk_result(err); |
1198 | } |
1199 | { |
1200 | VkFenceCreateInfo info = {}; |
1201 | info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; |
1202 | info.flags = VK_FENCE_CREATE_SIGNALED_BIT; |
1203 | err = vkCreateFence(device, &info, allocator, &fd->Fence); |
1204 | check_vk_result(err); |
1205 | } |
1206 | { |
1207 | VkSemaphoreCreateInfo info = {}; |
1208 | info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; |
1209 | err = vkCreateSemaphore(device, &info, allocator, &fsd->ImageAcquiredSemaphore); |
1210 | check_vk_result(err); |
1211 | err = vkCreateSemaphore(device, &info, allocator, &fsd->RenderCompleteSemaphore); |
1212 | check_vk_result(err); |
1213 | } |
1214 | } |
1215 | } |
1216 | |
1217 | int ImGui_ImplVulkanH_GetMinImageCountFromPresentMode(VkPresentModeKHR present_mode) |
1218 | { |
1219 | if (present_mode == VK_PRESENT_MODE_MAILBOX_KHR) |
1220 | return 3; |
1221 | if (present_mode == VK_PRESENT_MODE_FIFO_KHR || present_mode == VK_PRESENT_MODE_FIFO_RELAXED_KHR) |
1222 | return 2; |
1223 | if (present_mode == VK_PRESENT_MODE_IMMEDIATE_KHR) |
1224 | return 1; |
1225 | IM_ASSERT(0); |
1226 | return 1; |
1227 | } |
1228 | |
1229 | // Also destroy old swap chain and in-flight frames data, if any. |
1230 | 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) |
1231 | { |
1232 | VkResult err; |
1233 | VkSwapchainKHR old_swapchain = wd->Swapchain; |
1234 | wd->Swapchain = NULL; |
1235 | err = vkDeviceWaitIdle(device); |
1236 | check_vk_result(err); |
1237 | |
1238 | // We don't use ImGui_ImplVulkanH_DestroyWindow() because we want to preserve the old swapchain to create the new one. |
1239 | // Destroy old Framebuffer |
1240 | for (uint32_t i = 0; i < wd->ImageCount; i++) |
1241 | { |
1242 | ImGui_ImplVulkanH_DestroyFrame(device, &wd->Frames[i], allocator); |
1243 | ImGui_ImplVulkanH_DestroyFrameSemaphores(device, &wd->FrameSemaphores[i], allocator); |
1244 | } |
1245 | IM_FREE(wd->Frames); |
1246 | IM_FREE(wd->FrameSemaphores); |
1247 | wd->Frames = NULL; |
1248 | wd->FrameSemaphores = NULL; |
1249 | wd->ImageCount = 0; |
1250 | if (wd->RenderPass) |
1251 | vkDestroyRenderPass(device, wd->RenderPass, allocator); |
1252 | if (wd->Pipeline) |
1253 | vkDestroyPipeline(device, wd->Pipeline, allocator); |
1254 | |
1255 | // If min image count was not specified, request different count of images dependent on selected present mode |
1256 | if (min_image_count == 0) |
1257 | min_image_count = ImGui_ImplVulkanH_GetMinImageCountFromPresentMode(wd->PresentMode); |
1258 | |
1259 | // Create Swapchain |
1260 | { |
1261 | VkSwapchainCreateInfoKHR info = {}; |
1262 | info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; |
1263 | info.surface = wd->Surface; |
1264 | info.minImageCount = min_image_count; |
1265 | info.imageFormat = wd->SurfaceFormat.format; |
1266 | info.imageColorSpace = wd->SurfaceFormat.colorSpace; |
1267 | info.imageArrayLayers = 1; |
1268 | info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; |
1269 | info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; // Assume that graphics family == present family |
1270 | info.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; |
1271 | info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; |
1272 | info.presentMode = wd->PresentMode; |
1273 | info.clipped = VK_TRUE; |
1274 | info.oldSwapchain = old_swapchain; |
1275 | VkSurfaceCapabilitiesKHR cap; |
1276 | err = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physical_device, wd->Surface, &cap); |
1277 | check_vk_result(err); |
1278 | if (info.minImageCount < cap.minImageCount) |
1279 | info.minImageCount = cap.minImageCount; |
1280 | else if (cap.maxImageCount != 0 && info.minImageCount > cap.maxImageCount) |
1281 | info.minImageCount = cap.maxImageCount; |
1282 | |
1283 | if (cap.currentExtent.width == 0xffffffff) |
1284 | { |
1285 | info.imageExtent.width = wd->Width = w; |
1286 | info.imageExtent.height = wd->Height = h; |
1287 | } |
1288 | else |
1289 | { |
1290 | info.imageExtent.width = wd->Width = cap.currentExtent.width; |
1291 | info.imageExtent.height = wd->Height = cap.currentExtent.height; |
1292 | } |
1293 | err = vkCreateSwapchainKHR(device, &info, allocator, &wd->Swapchain); |
1294 | check_vk_result(err); |
1295 | err = vkGetSwapchainImagesKHR(device, wd->Swapchain, &wd->ImageCount, NULL); |
1296 | check_vk_result(err); |
1297 | VkImage backbuffers[16] = {}; |
1298 | IM_ASSERT(wd->ImageCount >= min_image_count); |
1299 | IM_ASSERT(wd->ImageCount < IM_ARRAYSIZE(backbuffers)); |
1300 | err = vkGetSwapchainImagesKHR(device, wd->Swapchain, &wd->ImageCount, backbuffers); |
1301 | check_vk_result(err); |
1302 | |
1303 | IM_ASSERT(wd->Frames == NULL); |
1304 | wd->Frames = (ImGui_ImplVulkanH_Frame*)IM_ALLOC(sizeof(ImGui_ImplVulkanH_Frame) * wd->ImageCount); |
1305 | wd->FrameSemaphores = (ImGui_ImplVulkanH_FrameSemaphores*)IM_ALLOC(sizeof(ImGui_ImplVulkanH_FrameSemaphores) * wd->ImageCount); |
1306 | memset(wd->Frames, 0, sizeof(wd->Frames[0]) * wd->ImageCount); |
1307 | memset(wd->FrameSemaphores, 0, sizeof(wd->FrameSemaphores[0]) * wd->ImageCount); |
1308 | for (uint32_t i = 0; i < wd->ImageCount; i++) |
1309 | wd->Frames[i].Backbuffer = backbuffers[i]; |
1310 | } |
1311 | if (old_swapchain) |
1312 | vkDestroySwapchainKHR(device, old_swapchain, allocator); |
1313 | |
1314 | // Create the Render Pass |
1315 | { |
1316 | VkAttachmentDescription attachment = {}; |
1317 | attachment.format = wd->SurfaceFormat.format; |
1318 | attachment.samples = VK_SAMPLE_COUNT_1_BIT; |
1319 | attachment.loadOp = wd->ClearEnable ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_DONT_CARE; |
1320 | attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; |
1321 | attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; |
1322 | attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; |
1323 | attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; |
1324 | attachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; |
1325 | VkAttachmentReference color_attachment = {}; |
1326 | color_attachment.attachment = 0; |
1327 | color_attachment.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; |
1328 | VkSubpassDescription subpass = {}; |
1329 | subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; |
1330 | subpass.colorAttachmentCount = 1; |
1331 | subpass.pColorAttachments = &color_attachment; |
1332 | VkSubpassDependency dependency = {}; |
1333 | dependency.srcSubpass = VK_SUBPASS_EXTERNAL; |
1334 | dependency.dstSubpass = 0; |
1335 | dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; |
1336 | dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; |
1337 | dependency.srcAccessMask = 0; |
1338 | dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; |
1339 | VkRenderPassCreateInfo info = {}; |
1340 | info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; |
1341 | info.attachmentCount = 1; |
1342 | info.pAttachments = &attachment; |
1343 | info.subpassCount = 1; |
1344 | info.pSubpasses = &subpass; |
1345 | info.dependencyCount = 1; |
1346 | info.pDependencies = &dependency; |
1347 | err = vkCreateRenderPass(device, &info, allocator, &wd->RenderPass); |
1348 | check_vk_result(err); |
1349 | |
1350 | // We do not create a pipeline by default as this is also used by examples' main.cpp, |
1351 | // but secondary viewport in multi-viewport mode may want to create one with: |
1352 | //ImGui_ImplVulkan_CreatePipeline(device, allocator, VK_NULL_HANDLE, wd->RenderPass, VK_SAMPLE_COUNT_1_BIT, &wd->Pipeline, bd->Subpass); |
1353 | } |
1354 | |
1355 | // Create The Image Views |
1356 | { |
1357 | VkImageViewCreateInfo info = {}; |
1358 | info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; |
1359 | info.viewType = VK_IMAGE_VIEW_TYPE_2D; |
1360 | info.format = wd->SurfaceFormat.format; |
1361 | info.components.r = VK_COMPONENT_SWIZZLE_R; |
1362 | info.components.g = VK_COMPONENT_SWIZZLE_G; |
1363 | info.components.b = VK_COMPONENT_SWIZZLE_B; |
1364 | info.components.a = VK_COMPONENT_SWIZZLE_A; |
1365 | VkImageSubresourceRange image_range = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }; |
1366 | info.subresourceRange = image_range; |
1367 | for (uint32_t i = 0; i < wd->ImageCount; i++) |
1368 | { |
1369 | ImGui_ImplVulkanH_Frame* fd = &wd->Frames[i]; |
1370 | info.image = fd->Backbuffer; |
1371 | err = vkCreateImageView(device, &info, allocator, &fd->BackbufferView); |
1372 | check_vk_result(err); |
1373 | } |
1374 | } |
1375 | |
1376 | // Create Framebuffer |
1377 | { |
1378 | VkImageView attachment[1]; |
1379 | VkFramebufferCreateInfo info = {}; |
1380 | info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; |
1381 | info.renderPass = wd->RenderPass; |
1382 | info.attachmentCount = 1; |
1383 | info.pAttachments = attachment; |
1384 | info.width = wd->Width; |
1385 | info.height = wd->Height; |
1386 | info.layers = 1; |
1387 | for (uint32_t i = 0; i < wd->ImageCount; i++) |
1388 | { |
1389 | ImGui_ImplVulkanH_Frame* fd = &wd->Frames[i]; |
1390 | attachment[0] = fd->BackbufferView; |
1391 | err = vkCreateFramebuffer(device, &info, allocator, &fd->Framebuffer); |
1392 | check_vk_result(err); |
1393 | } |
1394 | } |
1395 | } |
1396 | |
1397 | // Create or resize window |
1398 | 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) |
1399 | { |
1400 | IM_ASSERT(g_FunctionsLoaded && "Need to call ImGui_ImplVulkan_LoadFunctions() if IMGUI_IMPL_VULKAN_NO_PROTOTYPES or VK_NO_PROTOTYPES are set!" ); |
1401 | (void)instance; |
1402 | ImGui_ImplVulkanH_CreateWindowSwapChain(physical_device, device, wd, allocator, width, height, min_image_count); |
1403 | ImGui_ImplVulkanH_CreateWindowCommandBuffers(physical_device, device, wd, queue_family, allocator); |
1404 | } |
1405 | |
1406 | void ImGui_ImplVulkanH_DestroyWindow(VkInstance instance, VkDevice device, ImGui_ImplVulkanH_Window* wd, const VkAllocationCallbacks* allocator) |
1407 | { |
1408 | vkDeviceWaitIdle(device); // FIXME: We could wait on the Queue if we had the queue in wd-> (otherwise VulkanH functions can't use globals) |
1409 | //vkQueueWaitIdle(bd->Queue); |
1410 | |
1411 | for (uint32_t i = 0; i < wd->ImageCount; i++) |
1412 | { |
1413 | ImGui_ImplVulkanH_DestroyFrame(device, &wd->Frames[i], allocator); |
1414 | ImGui_ImplVulkanH_DestroyFrameSemaphores(device, &wd->FrameSemaphores[i], allocator); |
1415 | } |
1416 | IM_FREE(wd->Frames); |
1417 | IM_FREE(wd->FrameSemaphores); |
1418 | wd->Frames = NULL; |
1419 | wd->FrameSemaphores = NULL; |
1420 | vkDestroyPipeline(device, wd->Pipeline, allocator); |
1421 | vkDestroyRenderPass(device, wd->RenderPass, allocator); |
1422 | vkDestroySwapchainKHR(device, wd->Swapchain, allocator); |
1423 | vkDestroySurfaceKHR(instance, wd->Surface, allocator); |
1424 | |
1425 | *wd = ImGui_ImplVulkanH_Window(); |
1426 | } |
1427 | |
1428 | void ImGui_ImplVulkanH_DestroyFrame(VkDevice device, ImGui_ImplVulkanH_Frame* fd, const VkAllocationCallbacks* allocator) |
1429 | { |
1430 | vkDestroyFence(device, fd->Fence, allocator); |
1431 | vkFreeCommandBuffers(device, fd->CommandPool, 1, &fd->CommandBuffer); |
1432 | vkDestroyCommandPool(device, fd->CommandPool, allocator); |
1433 | fd->Fence = VK_NULL_HANDLE; |
1434 | fd->CommandBuffer = VK_NULL_HANDLE; |
1435 | fd->CommandPool = VK_NULL_HANDLE; |
1436 | |
1437 | vkDestroyImageView(device, fd->BackbufferView, allocator); |
1438 | vkDestroyFramebuffer(device, fd->Framebuffer, allocator); |
1439 | } |
1440 | |
1441 | void ImGui_ImplVulkanH_DestroyFrameSemaphores(VkDevice device, ImGui_ImplVulkanH_FrameSemaphores* fsd, const VkAllocationCallbacks* allocator) |
1442 | { |
1443 | vkDestroySemaphore(device, fsd->ImageAcquiredSemaphore, allocator); |
1444 | vkDestroySemaphore(device, fsd->RenderCompleteSemaphore, allocator); |
1445 | fsd->ImageAcquiredSemaphore = fsd->RenderCompleteSemaphore = VK_NULL_HANDLE; |
1446 | } |
1447 | |
1448 | void ImGui_ImplVulkanH_DestroyFrameRenderBuffers(VkDevice device, ImGui_ImplVulkanH_FrameRenderBuffers* buffers, const VkAllocationCallbacks* allocator) |
1449 | { |
1450 | if (buffers->VertexBuffer) { vkDestroyBuffer(device, buffers->VertexBuffer, allocator); buffers->VertexBuffer = VK_NULL_HANDLE; } |
1451 | if (buffers->VertexBufferMemory) { vkFreeMemory(device, buffers->VertexBufferMemory, allocator); buffers->VertexBufferMemory = VK_NULL_HANDLE; } |
1452 | if (buffers->IndexBuffer) { vkDestroyBuffer(device, buffers->IndexBuffer, allocator); buffers->IndexBuffer = VK_NULL_HANDLE; } |
1453 | if (buffers->IndexBufferMemory) { vkFreeMemory(device, buffers->IndexBufferMemory, allocator); buffers->IndexBufferMemory = VK_NULL_HANDLE; } |
1454 | buffers->VertexBufferSize = 0; |
1455 | buffers->IndexBufferSize = 0; |
1456 | } |
1457 | |
1458 | void ImGui_ImplVulkanH_DestroyWindowRenderBuffers(VkDevice device, ImGui_ImplVulkanH_WindowRenderBuffers* buffers, const VkAllocationCallbacks* allocator) |
1459 | { |
1460 | for (uint32_t n = 0; n < buffers->Count; n++) |
1461 | ImGui_ImplVulkanH_DestroyFrameRenderBuffers(device, &buffers->FrameRenderBuffers[n], allocator); |
1462 | IM_FREE(buffers->FrameRenderBuffers); |
1463 | buffers->FrameRenderBuffers = NULL; |
1464 | buffers->Index = 0; |
1465 | buffers->Count = 0; |
1466 | } |
1467 | |