main.cpp 26 KB

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