1// Dear ImGui: standalone example application for Win32 + Vulkan
2
3// Learn about Dear ImGui:
4// - FAQ https://dearimgui.com/faq
5// - Getting Started https://dearimgui.com/getting-started
6// - Documentation https://dearimgui.com/docs (same as your local docs/ folder).
7// - Introduction, links and more at the top of imgui.cpp
8
9// Important note to the reader who wish to integrate imgui_impl_vulkan.cpp/.h in their own engine/app.
10// - Common ImGui_ImplVulkan_XXX functions and structures are used to interface with imgui_impl_vulkan.cpp/.h.
11// You will use those if you want to use this rendering backend in your engine/app.
12// - Helper ImGui_ImplVulkanH_XXX functions and structures are only used by this example (main.cpp) and by
13// the backend itself (imgui_impl_vulkan.cpp), but should PROBABLY NOT be used by your own engine/app code.
14// Read comments in imgui_impl_vulkan.h.
15
16#include "imgui.h"
17#include "imgui_impl_win32.h"
18#define VK_USE_PLATFORM_WIN32_KHR
19#include "imgui_impl_vulkan.h"
20#include <windows.h>
21#include <stdio.h> // printf, fprintf
22#include <stdlib.h> // abort
23#include <tchar.h>
24
25// Volk headers
26#ifdef IMGUI_IMPL_VULKAN_USE_VOLK
27#define VOLK_IMPLEMENTATION
28#include <volk.h>
29#endif
30
31//#define APP_USE_UNLIMITED_FRAME_RATE
32#ifdef _DEBUG
33#define APP_USE_VULKAN_DEBUG_REPORT
34#endif
35
36// Data
37static VkAllocationCallbacks* g_Allocator = nullptr;
38static VkInstance g_Instance = VK_NULL_HANDLE;
39static VkPhysicalDevice g_PhysicalDevice = VK_NULL_HANDLE;
40static VkDevice g_Device = VK_NULL_HANDLE;
41static uint32_t g_QueueFamily = (uint32_t)-1;
42static VkQueue g_Queue = VK_NULL_HANDLE;
43static VkDebugReportCallbackEXT g_DebugReport = VK_NULL_HANDLE;
44static VkPipelineCache g_PipelineCache = VK_NULL_HANDLE;
45static VkDescriptorPool g_DescriptorPool = VK_NULL_HANDLE;
46
47static ImGui_ImplVulkanH_Window g_MainWindowData;
48static uint32_t g_MinImageCount = 2;
49static bool g_SwapChainRebuild = false;
50
51static void check_vk_result(VkResult err)
52{
53 if (err == VK_SUCCESS)
54 return;
55 fprintf(stderr, format: "[vulkan] Error: VkResult = %d\n", err);
56 if (err < 0)
57 abort();
58}
59
60#ifdef APP_USE_VULKAN_DEBUG_REPORT
61static VKAPI_ATTR VkBool32 VKAPI_CALL debug_report(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType, uint64_t object, size_t location, int32_t messageCode, const char* pLayerPrefix, const char* pMessage, void* pUserData)
62{
63 (void)flags; (void)object; (void)location; (void)messageCode; (void)pUserData; (void)pLayerPrefix; // Unused arguments
64 fprintf(stderr, "[vulkan] Debug report from ObjectType: %i\nMessage: %s\n\n", objectType, pMessage);
65 return VK_FALSE;
66}
67#endif // APP_USE_VULKAN_DEBUG_REPORT
68
69static bool IsExtensionAvailable(const ImVector<VkExtensionProperties>& properties, const char* extension)
70{
71 for (const VkExtensionProperties& p : properties)
72 if (strcmp(s1: p.extensionName, s2: extension) == 0)
73 return true;
74 return false;
75}
76
77static void SetupVulkan(ImVector<const char*> instance_extensions)
78{
79 VkResult err;
80#ifdef IMGUI_IMPL_VULKAN_USE_VOLK
81 volkInitialize();
82#endif
83
84 // Create Vulkan Instance
85 {
86 VkInstanceCreateInfo create_info = {};
87 create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
88
89 // Enumerate available extensions
90 uint32_t properties_count;
91 ImVector<VkExtensionProperties> properties;
92 vkEnumerateInstanceExtensionProperties(pLayerName: nullptr, pPropertyCount: &properties_count, pProperties: nullptr);
93 properties.resize(new_size: properties_count);
94 err = vkEnumerateInstanceExtensionProperties(pLayerName: nullptr, pPropertyCount: &properties_count, pProperties: properties.Data);
95 check_vk_result(err);
96
97 // Enable required extensions
98 if (IsExtensionAvailable(properties, VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME))
99 instance_extensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
100#ifdef VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME
101 if (IsExtensionAvailable(properties, VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME))
102 {
103 instance_extensions.push_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME);
104 create_info.flags |= VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR;
105 }
106#endif
107
108 // Enabling validation layers
109#ifdef APP_USE_VULKAN_DEBUG_REPORT
110 const char* layers[] = { "VK_LAYER_KHRONOS_validation" };
111 create_info.enabledLayerCount = 1;
112 create_info.ppEnabledLayerNames = layers;
113 instance_extensions.push_back("VK_EXT_debug_report");
114#endif
115
116 // Create Vulkan Instance
117 create_info.enabledExtensionCount = (uint32_t)instance_extensions.Size;
118 create_info.ppEnabledExtensionNames = instance_extensions.Data;
119 err = vkCreateInstance(pCreateInfo: &create_info, pAllocator: g_Allocator, pInstance: &g_Instance);
120 check_vk_result(err);
121#ifdef IMGUI_IMPL_VULKAN_USE_VOLK
122 volkLoadInstance(g_Instance);
123#endif
124
125 // Setup the debug report callback
126#ifdef APP_USE_VULKAN_DEBUG_REPORT
127 auto f_vkCreateDebugReportCallbackEXT = (PFN_vkCreateDebugReportCallbackEXT)vkGetInstanceProcAddr(g_Instance, "vkCreateDebugReportCallbackEXT");
128 IM_ASSERT(f_vkCreateDebugReportCallbackEXT != nullptr);
129 VkDebugReportCallbackCreateInfoEXT debug_report_ci = {};
130 debug_report_ci.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT;
131 debug_report_ci.flags = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT | VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT;
132 debug_report_ci.pfnCallback = debug_report;
133 debug_report_ci.pUserData = nullptr;
134 err = f_vkCreateDebugReportCallbackEXT(g_Instance, &debug_report_ci, g_Allocator, &g_DebugReport);
135 check_vk_result(err);
136#endif
137 }
138
139 // Select Physical Device (GPU)
140 g_PhysicalDevice = ImGui_ImplVulkanH_SelectPhysicalDevice(instance: g_Instance);
141 IM_ASSERT(g_PhysicalDevice != VK_NULL_HANDLE);
142
143 // Select graphics queue family
144 g_QueueFamily = ImGui_ImplVulkanH_SelectQueueFamilyIndex(physical_device: g_PhysicalDevice);
145 IM_ASSERT(g_QueueFamily != (uint32_t)-1);
146
147 // Create Logical Device (with 1 queue)
148 {
149 ImVector<const char*> device_extensions;
150 device_extensions.push_back(v: "VK_KHR_swapchain");
151
152 // Enumerate physical device extension
153 uint32_t properties_count;
154 ImVector<VkExtensionProperties> properties;
155 vkEnumerateDeviceExtensionProperties(physicalDevice: g_PhysicalDevice, pLayerName: nullptr, pPropertyCount: &properties_count, pProperties: nullptr);
156 properties.resize(new_size: properties_count);
157 vkEnumerateDeviceExtensionProperties(physicalDevice: g_PhysicalDevice, pLayerName: nullptr, pPropertyCount: &properties_count, pProperties: properties.Data);
158#ifdef VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME
159 if (IsExtensionAvailable(properties, VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME))
160 device_extensions.push_back(VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME);
161#endif
162
163 const float queue_priority[] = { 1.0f };
164 VkDeviceQueueCreateInfo queue_info[1] = {};
165 queue_info[0].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
166 queue_info[0].queueFamilyIndex = g_QueueFamily;
167 queue_info[0].queueCount = 1;
168 queue_info[0].pQueuePriorities = queue_priority;
169 VkDeviceCreateInfo create_info = {};
170 create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
171 create_info.queueCreateInfoCount = sizeof(queue_info) / sizeof(queue_info[0]);
172 create_info.pQueueCreateInfos = queue_info;
173 create_info.enabledExtensionCount = (uint32_t)device_extensions.Size;
174 create_info.ppEnabledExtensionNames = device_extensions.Data;
175 err = vkCreateDevice(physicalDevice: g_PhysicalDevice, pCreateInfo: &create_info, pAllocator: g_Allocator, pDevice: &g_Device);
176 check_vk_result(err);
177 vkGetDeviceQueue(device: g_Device, queueFamilyIndex: g_QueueFamily, queueIndex: 0, pQueue: &g_Queue);
178 }
179
180 // Create Descriptor Pool
181 // If you wish to load e.g. additional textures you may need to alter pools sizes and maxSets.
182 {
183 VkDescriptorPoolSize pool_sizes[] =
184 {
185 { .type: VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, IMGUI_IMPL_VULKAN_MINIMUM_IMAGE_SAMPLER_POOL_SIZE },
186 };
187 VkDescriptorPoolCreateInfo pool_info = {};
188 pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
189 pool_info.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT;
190 pool_info.maxSets = 0;
191 for (VkDescriptorPoolSize& pool_size : pool_sizes)
192 pool_info.maxSets += pool_size.descriptorCount;
193 pool_info.poolSizeCount = (uint32_t)IM_ARRAYSIZE(pool_sizes);
194 pool_info.pPoolSizes = pool_sizes;
195 err = vkCreateDescriptorPool(device: g_Device, pCreateInfo: &pool_info, pAllocator: g_Allocator, pDescriptorPool: &g_DescriptorPool);
196 check_vk_result(err);
197 }
198}
199
200// All the ImGui_ImplVulkanH_XXX structures/functions are optional helpers used by the demo.
201// Your real engine/app may not use them.
202static void SetupVulkanWindow(ImGui_ImplVulkanH_Window* wd, VkSurfaceKHR surface, int width, int height)
203{
204 wd->Surface = surface;
205
206 // Check for WSI support
207 VkBool32 res;
208 vkGetPhysicalDeviceSurfaceSupportKHR(physicalDevice: g_PhysicalDevice, queueFamilyIndex: g_QueueFamily, surface: wd->Surface, pSupported: &res);
209 if (res != VK_TRUE)
210 {
211 fprintf(stderr, format: "Error no WSI support on physical device 0\n");
212 exit(status: -1);
213 }
214
215 // Select Surface Format
216 const VkFormat requestSurfaceImageFormat[] = { VK_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_B8G8R8_UNORM, VK_FORMAT_R8G8B8_UNORM };
217 const VkColorSpaceKHR requestSurfaceColorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;
218 wd->SurfaceFormat = ImGui_ImplVulkanH_SelectSurfaceFormat(physical_device: g_PhysicalDevice, surface: wd->Surface, request_formats: requestSurfaceImageFormat, request_formats_count: (size_t)IM_ARRAYSIZE(requestSurfaceImageFormat), request_color_space: requestSurfaceColorSpace);
219
220 // Select Present Mode
221#ifdef APP_USE_UNLIMITED_FRAME_RATE
222 VkPresentModeKHR present_modes[] = { VK_PRESENT_MODE_MAILBOX_KHR, VK_PRESENT_MODE_IMMEDIATE_KHR, VK_PRESENT_MODE_FIFO_KHR };
223#else
224 VkPresentModeKHR present_modes[] = { VK_PRESENT_MODE_FIFO_KHR };
225#endif
226 wd->PresentMode = ImGui_ImplVulkanH_SelectPresentMode(physical_device: g_PhysicalDevice, surface: wd->Surface, request_modes: &present_modes[0], IM_ARRAYSIZE(present_modes));
227 //printf("[vulkan] Selected PresentMode = %d\n", wd->PresentMode);
228
229 // Create SwapChain, RenderPass, Framebuffer, etc.
230 IM_ASSERT(g_MinImageCount >= 2);
231 ImGui_ImplVulkanH_CreateOrResizeWindow(instance: g_Instance, physical_device: g_PhysicalDevice, device: g_Device, wd, queue_family: g_QueueFamily, allocator: g_Allocator, w: width, h: height, min_image_count: g_MinImageCount);
232}
233
234static void CleanupVulkan()
235{
236 vkDestroyDescriptorPool(device: g_Device, descriptorPool: g_DescriptorPool, pAllocator: g_Allocator);
237
238#ifdef APP_USE_VULKAN_DEBUG_REPORT
239 // Remove the debug report callback
240 auto f_vkDestroyDebugReportCallbackEXT = (PFN_vkDestroyDebugReportCallbackEXT)vkGetInstanceProcAddr(g_Instance, "vkDestroyDebugReportCallbackEXT");
241 f_vkDestroyDebugReportCallbackEXT(g_Instance, g_DebugReport, g_Allocator);
242#endif // APP_USE_VULKAN_DEBUG_REPORT
243
244 vkDestroyDevice(device: g_Device, pAllocator: g_Allocator);
245 vkDestroyInstance(instance: g_Instance, pAllocator: g_Allocator);
246}
247
248static void CleanupVulkanWindow()
249{
250 ImGui_ImplVulkanH_DestroyWindow(instance: g_Instance, device: g_Device, wd: &g_MainWindowData, allocator: g_Allocator);
251}
252
253static void FrameRender(ImGui_ImplVulkanH_Window* wd, ImDrawData* draw_data)
254{
255 VkSemaphore image_acquired_semaphore = wd->FrameSemaphores[wd->SemaphoreIndex].ImageAcquiredSemaphore;
256 VkSemaphore render_complete_semaphore = wd->FrameSemaphores[wd->SemaphoreIndex].RenderCompleteSemaphore;
257 VkResult err = vkAcquireNextImageKHR(device: g_Device, swapchain: wd->Swapchain, UINT64_MAX, semaphore: image_acquired_semaphore, VK_NULL_HANDLE, pImageIndex: &wd->FrameIndex);
258 if (err == VK_ERROR_OUT_OF_DATE_KHR || err == VK_SUBOPTIMAL_KHR)
259 g_SwapChainRebuild = true;
260 if (err == VK_ERROR_OUT_OF_DATE_KHR)
261 return;
262 if (err != VK_SUBOPTIMAL_KHR)
263 check_vk_result(err);
264
265 ImGui_ImplVulkanH_Frame* fd = &wd->Frames[wd->FrameIndex];
266 {
267 err = vkWaitForFences(device: g_Device, fenceCount: 1, pFences: &fd->Fence, VK_TRUE, UINT64_MAX); // wait indefinitely instead of periodically checking
268 check_vk_result(err);
269
270 err = vkResetFences(device: g_Device, fenceCount: 1, pFences: &fd->Fence);
271 check_vk_result(err);
272 }
273 {
274 err = vkResetCommandPool(device: g_Device, commandPool: fd->CommandPool, flags: 0);
275 check_vk_result(err);
276 VkCommandBufferBeginInfo info = {};
277 info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
278 info.flags |= VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
279 err = vkBeginCommandBuffer(commandBuffer: fd->CommandBuffer, pBeginInfo: &info);
280 check_vk_result(err);
281 }
282 {
283 VkRenderPassBeginInfo info = {};
284 info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
285 info.renderPass = wd->RenderPass;
286 info.framebuffer = fd->Framebuffer;
287 info.renderArea.extent.width = wd->Width;
288 info.renderArea.extent.height = wd->Height;
289 info.clearValueCount = 1;
290 info.pClearValues = &wd->ClearValue;
291 vkCmdBeginRenderPass(commandBuffer: fd->CommandBuffer, pRenderPassBegin: &info, contents: VK_SUBPASS_CONTENTS_INLINE);
292 }
293
294 // Record dear imgui primitives into command buffer
295 ImGui_ImplVulkan_RenderDrawData(draw_data, command_buffer: fd->CommandBuffer);
296
297 // Submit command buffer
298 vkCmdEndRenderPass(commandBuffer: fd->CommandBuffer);
299 {
300 VkPipelineStageFlags wait_stage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
301 VkSubmitInfo info = {};
302 info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
303 info.waitSemaphoreCount = 1;
304 info.pWaitSemaphores = &image_acquired_semaphore;
305 info.pWaitDstStageMask = &wait_stage;
306 info.commandBufferCount = 1;
307 info.pCommandBuffers = &fd->CommandBuffer;
308 info.signalSemaphoreCount = 1;
309 info.pSignalSemaphores = &render_complete_semaphore;
310
311 err = vkEndCommandBuffer(commandBuffer: fd->CommandBuffer);
312 check_vk_result(err);
313 err = vkQueueSubmit(queue: g_Queue, submitCount: 1, pSubmits: &info, fence: fd->Fence);
314 check_vk_result(err);
315 }
316}
317
318static void FramePresent(ImGui_ImplVulkanH_Window* wd)
319{
320 if (g_SwapChainRebuild)
321 return;
322 VkSemaphore render_complete_semaphore = wd->FrameSemaphores[wd->SemaphoreIndex].RenderCompleteSemaphore;
323 VkPresentInfoKHR info = {};
324 info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
325 info.waitSemaphoreCount = 1;
326 info.pWaitSemaphores = &render_complete_semaphore;
327 info.swapchainCount = 1;
328 info.pSwapchains = &wd->Swapchain;
329 info.pImageIndices = &wd->FrameIndex;
330 VkResult err = vkQueuePresentKHR(queue: g_Queue, pPresentInfo: &info);
331 if (err == VK_ERROR_OUT_OF_DATE_KHR || err == VK_SUBOPTIMAL_KHR)
332 g_SwapChainRebuild = true;
333 if (err == VK_ERROR_OUT_OF_DATE_KHR)
334 return;
335 if (err != VK_SUBOPTIMAL_KHR)
336 check_vk_result(err);
337 wd->SemaphoreIndex = (wd->SemaphoreIndex + 1) % wd->SemaphoreCount; // Now we can use the next set of semaphores
338}
339
340LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
341
342// FIXME: This code would ideally be inside imgui_impl_win32.cpp, it would create a dependency on Vulkan headers in imgui_impl_win32.cpp
343static int ImGui_ImplWin32_CreateVkSurface(ImGuiViewport* viewport, ImU64 vk_instance, const void* vk_allocator, ImU64* out_vk_surface)
344{
345 VkWin32SurfaceCreateInfoKHR createInfo = {};
346 createInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
347 createInfo.hwnd = (HWND)viewport->PlatformHandleRaw;
348 createInfo.hinstance = ::GetModuleHandle(nullptr);
349 return (int)vkCreateWin32SurfaceKHR(instance: (VkInstance)vk_instance, pCreateInfo: &createInfo, pAllocator: (VkAllocationCallbacks*)vk_allocator, pSurface: (VkSurfaceKHR*)out_vk_surface);
350}
351
352// Main code
353int main(int, char**)
354{
355 // Create application window
356 //ImGui_ImplWin32_EnableDpiAwareness();
357 WNDCLASSEXW wc = { sizeof(wc), CS_CLASSDC, WndProc, 0L, 0L, GetModuleHandle(nullptr), nullptr, nullptr, nullptr, nullptr, L"ImGui Example", nullptr };
358 ::RegisterClassExW(&wc);
359 HWND hwnd = ::CreateWindowW(wc.lpszClassName, L"Dear ImGui Win32+Vulkan Example", WS_OVERLAPPEDWINDOW, 100, 100, 1280, 800, nullptr, nullptr, wc.hInstance, nullptr);
360
361 ImVector<const char*> extensions;
362 extensions.push_back(v: "VK_KHR_surface");
363 extensions.push_back(v: "VK_KHR_win32_surface");
364 SetupVulkan(extensions);
365
366 // Create Window Surface
367 VkSurfaceKHR surface;
368 VkResult err;
369 VkWin32SurfaceCreateInfoKHR createInfo = {};
370 createInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
371 createInfo.hwnd = hwnd;
372 createInfo.hinstance = ::GetModuleHandle(nullptr);
373 if (vkCreateWin32SurfaceKHR(instance: g_Instance, pCreateInfo: &createInfo, pAllocator: nullptr, pSurface: &surface) != VK_SUCCESS)
374 {
375 printf(format: "Failed to create Vulkan surface.\n");
376 return 1;
377 }
378
379 // Show the window
380 // FIXME: Retrieve client size from window itself.
381 ImGui_ImplVulkanH_Window* wd = &g_MainWindowData;
382 SetupVulkanWindow(wd, surface, width: 1280, height: 800);
383 ::ShowWindow(hwnd, SW_SHOWDEFAULT);
384 ::UpdateWindow(hwnd);
385
386 // Setup Dear ImGui context
387 IMGUI_CHECKVERSION();
388 ImGui::CreateContext();
389 ImGuiIO& io = ImGui::GetIO(); (void)io;
390 io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
391 io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
392 io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking
393 io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows
394 //io.ConfigFlags |= ImGuiConfigFlags_ViewportsNoTaskBarIcons;
395 //io.ConfigFlags |= ImGuiConfigFlags_ViewportsNoMerge;
396
397 // Setup Dear ImGui style
398 ImGui::StyleColorsDark();
399 //ImGui::StyleColorsLight();
400
401 // When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones.
402 ImGuiStyle& style = ImGui::GetStyle();
403 if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
404 {
405 style.WindowRounding = 0.0f;
406 style.Colors[ImGuiCol_WindowBg].w = 1.0f;
407 }
408
409 // Setup Platform/Renderer backends
410 ImGui_ImplWin32_Init(hwnd);
411 ImGui::GetPlatformIO().Platform_CreateVkSurface = ImGui_ImplWin32_CreateVkSurface;
412
413 ImGui_ImplVulkan_InitInfo init_info = {};
414 //init_info.ApiVersion = VK_API_VERSION_1_3; // Pass in your value of VkApplicationInfo::apiVersion, otherwise will default to header version.
415 init_info.Instance = g_Instance;
416 init_info.PhysicalDevice = g_PhysicalDevice;
417 init_info.Device = g_Device;
418 init_info.QueueFamily = g_QueueFamily;
419 init_info.Queue = g_Queue;
420 init_info.PipelineCache = g_PipelineCache;
421 init_info.DescriptorPool = g_DescriptorPool;
422 init_info.RenderPass = wd->RenderPass;
423 init_info.Subpass = 0;
424 init_info.MinImageCount = g_MinImageCount;
425 init_info.ImageCount = wd->ImageCount;
426 init_info.MSAASamples = VK_SAMPLE_COUNT_1_BIT;
427 init_info.Allocator = g_Allocator;
428 init_info.CheckVkResultFn = check_vk_result;
429 ImGui_ImplVulkan_Init(info: &init_info);
430
431 // Load Fonts
432 // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them.
433 // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple.
434 // - If the file cannot be loaded, the function will return a nullptr. Please handle those errors in your application (e.g. use an assertion, or display an error and quit).
435 // - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call.
436 // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use Freetype for higher quality font rendering.
437 // - Read 'docs/FONTS.md' for more instructions and details.
438 // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ !
439 //io.Fonts->AddFontDefault();
440 //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf", 18.0f);
441 //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf", 16.0f);
442 //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f);
443 //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf", 15.0f);
444 //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f, nullptr, io.Fonts->GetGlyphRangesJapanese());
445 //IM_ASSERT(font != nullptr);
446
447 // Our state
448 bool show_demo_window = true;
449 bool show_another_window = false;
450 ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f);
451
452 // Main loop
453 bool done = false;
454 while (!done)
455 {
456 // Poll and handle messages (inputs, window resize, etc.)
457 // See the WndProc() function below for our to dispatch events to the Win32 backend.
458 MSG msg;
459 while (::PeekMessage(&msg, nullptr, 0U, 0U, PM_REMOVE))
460 {
461 ::TranslateMessage(&msg);
462 ::DispatchMessage(&msg);
463 if (msg.message == WM_QUIT)
464 done = true;
465 }
466 if (done)
467 break;
468
469 // Start the Dear ImGui frame
470 ImGui_ImplVulkan_NewFrame();
471 ImGui_ImplWin32_NewFrame();
472 ImGui::NewFrame();
473
474 // 1. Show the big demo window (Most of the sample code is in ImGui::ShowDemoWindow()! You can browse its code to learn more about Dear ImGui!).
475 if (show_demo_window)
476 ImGui::ShowDemoWindow(p_open: &show_demo_window);
477
478 // 2. Show a simple window that we create ourselves. We use a Begin/End pair to create a named window.
479 {
480 static float f = 0.0f;
481 static int counter = 0;
482
483 ImGui::Begin(name: "Hello, world!"); // Create a window called "Hello, world!" and append into it.
484
485 ImGui::Text(fmt: "This is some useful text."); // Display some text (you can use a format strings too)
486 ImGui::Checkbox(label: "Demo Window", v: &show_demo_window); // Edit bools storing our window open/close state
487 ImGui::Checkbox(label: "Another Window", v: &show_another_window);
488
489 ImGui::SliderFloat(label: "float", v: &f, v_min: 0.0f, v_max: 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f
490 ImGui::ColorEdit3(label: "clear color", col: (float*)&clear_color); // Edit 3 floats representing a color
491
492 if (ImGui::Button(label: "Button")) // Buttons return true when clicked (most widgets return true when edited/activated)
493 counter++;
494 ImGui::SameLine();
495 ImGui::Text(fmt: "counter = %d", counter);
496
497 ImGui::Text(fmt: "Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate);
498 ImGui::End();
499 }
500
501 // 3. Show another simple window.
502 if (show_another_window)
503 {
504 ImGui::Begin(name: "Another Window", p_open: &show_another_window); // Pass a pointer to our bool variable (the window will have a closing button that will clear the bool when clicked)
505 ImGui::Text(fmt: "Hello from another window!");
506 if (ImGui::Button(label: "Close Me"))
507 show_another_window = false;
508 ImGui::End();
509 }
510
511 // Rendering
512 ImGui::Render();
513 ImDrawData* main_draw_data = ImGui::GetDrawData();
514 const bool main_is_minimized = (main_draw_data->DisplaySize.x <= 0.0f || main_draw_data->DisplaySize.y <= 0.0f);
515 wd->ClearValue.color.float32[0] = clear_color.x * clear_color.w;
516 wd->ClearValue.color.float32[1] = clear_color.y * clear_color.w;
517 wd->ClearValue.color.float32[2] = clear_color.z * clear_color.w;
518 wd->ClearValue.color.float32[3] = clear_color.w;
519 if (!main_is_minimized)
520 FrameRender(wd, draw_data: main_draw_data);
521
522 // Update and Render additional Platform Windows
523 if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
524 {
525 ImGui::UpdatePlatformWindows();
526 ImGui::RenderPlatformWindowsDefault();
527 }
528
529 // Present Main Platform Window
530 if (!main_is_minimized)
531 FramePresent(wd);
532 }
533
534 // Cleanup
535 err = vkDeviceWaitIdle(device: g_Device);
536 check_vk_result(err);
537 ImGui_ImplVulkan_Shutdown();
538 ImGui_ImplWin32_Shutdown();
539 ImGui::DestroyContext();
540
541 CleanupVulkanWindow();
542 CleanupVulkan();
543
544 ::DestroyWindow(hwnd);
545 ::UnregisterClassW(wc.lpszClassName, wc.hInstance);
546
547 return 0;
548}
549
550// Helper functions
551
552// Forward declare message handler from imgui_impl_win32.cpp
553extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
554
555// Win32 message handler
556// You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs.
557// - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application, or clear/overwrite your copy of the mouse data.
558// - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application, or clear/overwrite your copy of the keyboard data.
559// Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags.
560LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
561{
562 if (ImGui_ImplWin32_WndProcHandler(hWnd, msg, wParam, lParam))
563 return true;
564
565 switch (msg)
566 {
567 case WM_SIZE:
568 if (g_Device != VK_NULL_HANDLE && wParam != SIZE_MINIMIZED)
569 {
570 // Resize swap chain
571 int fb_width = (UINT)LOWORD(lParam);
572 int fb_height = (UINT)HIWORD(lParam);
573 if (fb_width > 0 && fb_height > 0 && (g_SwapChainRebuild || g_MainWindowData.Width != fb_width || g_MainWindowData.Height != fb_height))
574 {
575 ImGui_ImplVulkan_SetMinImageCount(g_MinImageCount);
576 ImGui_ImplVulkanH_CreateOrResizeWindow(g_Instance, g_PhysicalDevice, g_Device, &g_MainWindowData, g_QueueFamily, g_Allocator, fb_width, fb_height, g_MinImageCount);
577 g_MainWindowData.FrameIndex = 0;
578 g_SwapChainRebuild = false;
579 }
580 }
581 return 0;
582 case WM_SYSCOMMAND:
583 if ((wParam & 0xfff0) == SC_KEYMENU) // Disable ALT application menu
584 return 0;
585 break;
586 case WM_DESTROY:
587 ::PostQuitMessage(0);
588 return 0;
589 }
590 return ::DefWindowProcW(hWnd, msg, wParam, lParam);
591}
592

Provided by KDAB

Privacy Policy
Improve your Profiling and Debugging skills
Find out more

source code of imgui/examples/example_win32_vulkan/main.cpp