26.9 KB、603行 生 Blame 履歴
1// Dear ImGui: standalone example application for Windows API + 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, "[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(p.extensionName, 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(nullptr, &properties_count, nullptr);
93 properties.resize(properties_count);
94 err = vkEnumerateInstanceExtensionProperties(nullptr, &properties_count, 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(&create_info, g_Allocator, &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(g_Instance);
141 IM_ASSERT(g_PhysicalDevice != VK_NULL_HANDLE);
142
143 // Select graphics queue family
144 g_QueueFamily = ImGui_ImplVulkanH_SelectQueueFamilyIndex(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("VK_KHR_swapchain");
151
152 // Enumerate physical device extension
153 uint32_t properties_count;
154 ImVector<VkExtensionProperties> properties;
155 vkEnumerateDeviceExtensionProperties(g_PhysicalDevice, nullptr, &properties_count, nullptr);
156 properties.resize(properties_count);
157 vkEnumerateDeviceExtensionProperties(g_PhysicalDevice, nullptr, &properties_count, 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(g_PhysicalDevice, &create_info, g_Allocator, &g_Device);
176 check_vk_result(err);
177 vkGetDeviceQueue(g_Device, g_QueueFamily, 0, &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 { VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, IMGUI_IMPL_VULKAN_MINIMUM_SAMPLED_IMAGE_POOL_SIZE },
186 { VK_DESCRIPTOR_TYPE_SAMPLER, IMGUI_IMPL_VULKAN_MINIMUM_SAMPLER_POOL_SIZE },
187 };
188 VkDescriptorPoolCreateInfo pool_info = {};
189 pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
190 pool_info.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT;
191 pool_info.maxSets = 0;
192 for (VkDescriptorPoolSize& pool_size : pool_sizes)
193 pool_info.maxSets += pool_size.descriptorCount;
194 pool_info.poolSizeCount = (uint32_t)IM_COUNTOF(pool_sizes);
195 pool_info.pPoolSizes = pool_sizes;
196 err = vkCreateDescriptorPool(g_Device, &pool_info, g_Allocator, &g_DescriptorPool);
197 check_vk_result(err);
198 }
199}
200
201// All the ImGui_ImplVulkanH_XXX structures/functions are optional helpers used by the demo.
202// Your real engine/app may not use them.
203static void SetupVulkanWindow(ImGui_ImplVulkanH_Window* wd, VkSurfaceKHR surface, int width, int height)
204{
205 // Check for WSI support
206 VkBool32 res;
207 vkGetPhysicalDeviceSurfaceSupportKHR(g_PhysicalDevice, g_QueueFamily, surface, &res);
208 if (res != VK_TRUE)
209 {
210 fprintf(stderr, "Error no WSI support on physical device 0\n");
211 exit(-1);
212 }
213
214 // Select Surface Format
215 const VkFormat requestSurfaceImageFormat[] = { VK_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_B8G8R8_UNORM, VK_FORMAT_R8G8B8_UNORM };
216 const VkColorSpaceKHR requestSurfaceColorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;
217 wd->Surface = surface;
218 wd->SurfaceFormat = ImGui_ImplVulkanH_SelectSurfaceFormat(g_PhysicalDevice, wd->Surface, requestSurfaceImageFormat, (size_t)IM_COUNTOF(requestSurfaceImageFormat), 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(g_PhysicalDevice, wd->Surface, &present_modes[0], IM_COUNTOF(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(g_Instance, g_PhysicalDevice, g_Device, wd, g_QueueFamily, g_Allocator, width, height, g_MinImageCount, 0);
232}
233
234static void CleanupVulkan()
235{
236 vkDestroyDescriptorPool(g_Device, g_DescriptorPool, 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(g_Device, g_Allocator);
245 vkDestroyInstance(g_Instance, g_Allocator);
246}
247
248static void CleanupVulkanWindow(ImGui_ImplVulkanH_Window* wd)
249{
250 ImGui_ImplVulkanH_DestroyWindow(g_Instance, g_Device, wd, g_Allocator);
251 vkDestroySurfaceKHR(g_Instance, wd->Surface, g_Allocator);
252}
253
254static void FrameRender(ImGui_ImplVulkanH_Window* wd, ImDrawData* draw_data)
255{
256 VkSemaphore image_acquired_semaphore = wd->FrameSemaphores[wd->SemaphoreIndex].ImageAcquiredSemaphore;
257 VkSemaphore render_complete_semaphore = wd->FrameSemaphores[wd->SemaphoreIndex].RenderCompleteSemaphore;
258 VkResult err = vkAcquireNextImageKHR(g_Device, wd->Swapchain, UINT64_MAX, image_acquired_semaphore, VK_NULL_HANDLE, &wd->FrameIndex);
259 if (err == VK_ERROR_OUT_OF_DATE_KHR || err == VK_SUBOPTIMAL_KHR)
260 g_SwapChainRebuild = true;
261 if (err == VK_ERROR_OUT_OF_DATE_KHR)
262 return;
263 if (err != VK_SUBOPTIMAL_KHR)
264 check_vk_result(err);
265
266 ImGui_ImplVulkanH_Frame* fd = &wd->Frames[wd->FrameIndex];
267 {
268 err = vkWaitForFences(g_Device, 1, &fd->Fence, VK_TRUE, UINT64_MAX); // wait indefinitely instead of periodically checking
269 check_vk_result(err);
270
271 err = vkResetFences(g_Device, 1, &fd->Fence);
272 check_vk_result(err);
273 }
274 {
275 err = vkResetCommandPool(g_Device, fd->CommandPool, 0);
276 check_vk_result(err);
277 VkCommandBufferBeginInfo info = {};
278 info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
279 info.flags |= VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
280 err = vkBeginCommandBuffer(fd->CommandBuffer, &info);
281 check_vk_result(err);
282 }
283 {
284 VkRenderPassBeginInfo info = {};
285 info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
286 info.renderPass = wd->RenderPass;
287 info.framebuffer = fd->Framebuffer;
288 info.renderArea.extent.width = wd->Width;
289 info.renderArea.extent.height = wd->Height;
290 info.clearValueCount = 1;
291 info.pClearValues = &wd->ClearValue;
292 vkCmdBeginRenderPass(fd->CommandBuffer, &info, VK_SUBPASS_CONTENTS_INLINE);
293 }
294
295 // Record dear imgui primitives into command buffer
296 ImGui_ImplVulkan_RenderDrawData(draw_data, fd->CommandBuffer);
297
298 // Submit command buffer
299 vkCmdEndRenderPass(fd->CommandBuffer);
300 {
301 VkPipelineStageFlags wait_stage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
302 VkSubmitInfo info = {};
303 info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
304 info.waitSemaphoreCount = 1;
305 info.pWaitSemaphores = &image_acquired_semaphore;
306 info.pWaitDstStageMask = &wait_stage;
307 info.commandBufferCount = 1;
308 info.pCommandBuffers = &fd->CommandBuffer;
309 info.signalSemaphoreCount = 1;
310 info.pSignalSemaphores = &render_complete_semaphore;
311
312 err = vkEndCommandBuffer(fd->CommandBuffer);
313 check_vk_result(err);
314 err = vkQueueSubmit(g_Queue, 1, &info, fd->Fence);
315 check_vk_result(err);
316 }
317}
318
319static void FramePresent(ImGui_ImplVulkanH_Window* wd)
320{
321 if (g_SwapChainRebuild)
322 return;
323 VkSemaphore render_complete_semaphore = wd->FrameSemaphores[wd->SemaphoreIndex].RenderCompleteSemaphore;
324 VkPresentInfoKHR info = {};
325 info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
326 info.waitSemaphoreCount = 1;
327 info.pWaitSemaphores = &render_complete_semaphore;
328 info.swapchainCount = 1;
329 info.pSwapchains = &wd->Swapchain;
330 info.pImageIndices = &wd->FrameIndex;
331 VkResult err = vkQueuePresentKHR(g_Queue, &info);
332 if (err == VK_ERROR_OUT_OF_DATE_KHR || err == VK_SUBOPTIMAL_KHR)
333 g_SwapChainRebuild = true;
334 if (err == VK_ERROR_OUT_OF_DATE_KHR)
335 return;
336 if (err != VK_SUBOPTIMAL_KHR)
337 check_vk_result(err);
338 wd->SemaphoreIndex = (wd->SemaphoreIndex + 1) % wd->SemaphoreCount; // Now we can use the next set of semaphores
339}
340
341LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
342
343// FIXME: This code would ideally be inside imgui_impl_win32.cpp, it would create a dependency on Vulkan headers in imgui_impl_win32.cpp
344static int ImGui_ImplWin32_CreateVkSurface(ImGuiViewport* viewport, ImU64 vk_instance, const void* vk_allocator, ImU64* out_vk_surface)
345{
346 VkWin32SurfaceCreateInfoKHR createInfo = {};
347 createInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
348 createInfo.hwnd = (HWND)viewport->PlatformHandleRaw;
349 createInfo.hinstance = ::GetModuleHandle(nullptr);
350 return (int)vkCreateWin32SurfaceKHR((VkInstance)vk_instance, &createInfo, (VkAllocationCallbacks*)vk_allocator, (VkSurfaceKHR*)out_vk_surface);
351}
352
353// Main code
354int main(int, char**)
355{
356 // Make process DPI aware and obtain main monitor scale
357 ImGui_ImplWin32_EnableDpiAwareness();
358 float main_scale = ImGui_ImplWin32_GetDpiScaleForMonitor(::MonitorFromPoint(POINT{ 0, 0 }, MONITOR_DEFAULTTOPRIMARY));
359
360 // Create application window
361 WNDCLASSEXW wc = { sizeof(wc), CS_CLASSDC, WndProc, 0L, 0L, GetModuleHandle(nullptr), nullptr, nullptr, nullptr, nullptr, L"ImGui Example", nullptr };
362 ::RegisterClassExW(&wc);
363 HWND hwnd = ::CreateWindowW(wc.lpszClassName, L"Dear ImGui Win32+Vulkan Example", WS_OVERLAPPEDWINDOW, 100, 100, (int)(1280 * main_scale), (int)(800 * main_scale), nullptr, nullptr, wc.hInstance, nullptr);
364
365 ImVector<const char*> extensions;
366 extensions.push_back("VK_KHR_surface");
367 extensions.push_back("VK_KHR_win32_surface");
368 SetupVulkan(extensions);
369
370 // Create Window Surface
371 VkSurfaceKHR surface;
372 VkResult err;
373 VkWin32SurfaceCreateInfoKHR createInfo = {};
374 createInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
375 createInfo.hwnd = hwnd;
376 createInfo.hinstance = ::GetModuleHandle(nullptr);
377 if (vkCreateWin32SurfaceKHR(g_Instance, &createInfo, nullptr, &surface) != VK_SUCCESS)
378 {
379 printf("Failed to create Vulkan surface.\n");
380 return 1;
381 }
382
383 // Show the window
384 // FIXME: Retrieve client size from window itself.
385 ImGui_ImplVulkanH_Window* wd = &g_MainWindowData;
386 SetupVulkanWindow(wd, surface, (int)(1280 * main_scale), (int)(800 * main_scale));
387 ::ShowWindow(hwnd, SW_SHOWDEFAULT);
388 ::UpdateWindow(hwnd);
389
390 // Setup Dear ImGui context
391 IMGUI_CHECKVERSION();
392 ImGui::CreateContext();
393 ImGuiIO& io = ImGui::GetIO(); (void)io;
394 io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
395 io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
396 io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking
397 io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows
398 //io.ConfigFlags |= ImGuiConfigFlags_ViewportsNoTaskBarIcons;
399 //io.ConfigFlags |= ImGuiConfigFlags_ViewportsNoMerge;
400
401 // Setup Dear ImGui style
402 ImGui::StyleColorsDark();
403 //ImGui::StyleColorsLight();
404
405 // Setup scaling
406 ImGuiStyle& style = ImGui::GetStyle();
407 style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again)
408 style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor)
409 io.ConfigDpiScaleFonts = true; // [Experimental] Automatically overwrite style.FontScaleDpi in Begin() when Monitor DPI changes. This will scale fonts but _NOT_ scale sizes/padding for now.
410 io.ConfigDpiScaleViewports = true; // [Experimental] Scale Dear ImGui and Platform Windows when Monitor DPI changes.
411
412 // When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones.
413 if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
414 {
415 style.WindowRounding = 0.0f;
416 style.Colors[ImGuiCol_WindowBg].w = 1.0f;
417 }
418
419 // Setup Platform/Renderer backends
420 ImGui_ImplWin32_Init(hwnd);
421 ImGui::GetPlatformIO().Platform_CreateVkSurface = ImGui_ImplWin32_CreateVkSurface;
422
423 ImGui_ImplVulkan_InitInfo init_info = {};
424 //init_info.ApiVersion = VK_API_VERSION_1_3; // Pass in your value of VkApplicationInfo::apiVersion, otherwise will default to header version.
425 init_info.Instance = g_Instance;
426 init_info.PhysicalDevice = g_PhysicalDevice;
427 init_info.Device = g_Device;
428 init_info.QueueFamily = g_QueueFamily;
429 init_info.Queue = g_Queue;
430 init_info.PipelineCache = g_PipelineCache;
431 init_info.DescriptorPool = g_DescriptorPool;
432 init_info.MinImageCount = g_MinImageCount;
433 init_info.ImageCount = wd->ImageCount;
434 init_info.Allocator = g_Allocator;
435 init_info.PipelineInfoMain.RenderPass = wd->RenderPass;
436 init_info.PipelineInfoMain.Subpass = 0;
437 init_info.PipelineInfoMain.MSAASamples = VK_SAMPLE_COUNT_1_BIT;
438 init_info.CheckVkResultFn = check_vk_result;
439 ImGui_ImplVulkan_Init(&init_info);
440
441 // Load Fonts
442 // - If fonts are not explicitly loaded, Dear ImGui will select an embedded font: either AddFontDefaultVector() or AddFontDefaultBitmap().
443 // This selection is based on (style.FontSizeBase * style.FontScaleMain * style.FontScaleDpi) reaching a small threshold.
444 // - You can load multiple fonts and use ImGui::PushFont()/PopFont() to select them.
445 // - If a file cannot be loaded, AddFont functions will return a nullptr. Please handle those errors in your code (e.g. use an assertion, display an error and quit).
446 // - Read 'docs/FONTS.md' for more instructions and details.
447 // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use FreeType for higher quality font rendering.
448 // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ !
449 //style.FontSizeBase = 20.0f;
450 //io.Fonts->AddFontDefaultVector();
451 //io.Fonts->AddFontDefaultBitmap();
452 //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf");
453 //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf");
454 //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf");
455 //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf");
456 //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf");
457 //IM_ASSERT(font != nullptr);
458
459 // Our state
460 bool show_demo_window = true;
461 bool show_another_window = false;
462 ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f);
463
464 // Main loop
465 bool done = false;
466 while (!done)
467 {
468 // Poll and handle messages (inputs, window resize, etc.)
469 // See the WndProc() function below for our to dispatch events to the Win32 backend.
470 MSG msg;
471 while (::PeekMessage(&msg, nullptr, 0U, 0U, PM_REMOVE))
472 {
473 ::TranslateMessage(&msg);
474 ::DispatchMessage(&msg);
475 if (msg.message == WM_QUIT)
476 done = true;
477 }
478 if (done)
479 break;
480
481 // Start the Dear ImGui frame
482 ImGui_ImplVulkan_NewFrame();
483 ImGui_ImplWin32_NewFrame();
484 ImGui::NewFrame();
485
486 // 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!).
487 if (show_demo_window)
488 ImGui::ShowDemoWindow(&show_demo_window);
489
490 // 2. Show a simple window that we create ourselves. We use a Begin/End pair to create a named window.
491 {
492 static float f = 0.0f;
493 static int counter = 0;
494
495 ImGui::Begin("Hello, world!"); // Create a window called "Hello, world!" and append into it.
496
497 ImGui::Text("This is some useful text."); // Display some text (you can use a format strings too)
498 ImGui::Checkbox("Demo Window", &show_demo_window); // Edit bools storing our window open/close state
499 ImGui::Checkbox("Another Window", &show_another_window);
500
501 ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f
502 ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color
503
504 if (ImGui::Button("Button")) // Buttons return true when clicked (most widgets return true when edited/activated)
505 counter++;
506 ImGui::SameLine();
507 ImGui::Text("counter = %d", counter);
508
509 ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate);
510 ImGui::End();
511 }
512
513 // 3. Show another simple window.
514 if (show_another_window)
515 {
516 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)
517 ImGui::Text("Hello from another window!");
518 if (ImGui::Button("Close Me"))
519 show_another_window = false;
520 ImGui::End();
521 }
522
523 // Rendering
524 ImGui::Render();
525 ImDrawData* main_draw_data = ImGui::GetDrawData();
526 const bool main_is_minimized = (main_draw_data->DisplaySize.x <= 0.0f || main_draw_data->DisplaySize.y <= 0.0f);
527 wd->ClearValue.color.float32[0] = clear_color.x * clear_color.w;
528 wd->ClearValue.color.float32[1] = clear_color.y * clear_color.w;
529 wd->ClearValue.color.float32[2] = clear_color.z * clear_color.w;
530 wd->ClearValue.color.float32[3] = clear_color.w;
531 if (!main_is_minimized)
532 FrameRender(wd, main_draw_data);
533
534 // Update and Render additional Platform Windows
535 if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
536 {
537 ImGui::UpdatePlatformWindows();
538 ImGui::RenderPlatformWindowsDefault();
539 }
540
541 // Present Main Platform Window
542 if (!main_is_minimized)
543 FramePresent(wd);
544 }
545
546 // Cleanup
547 err = vkDeviceWaitIdle(g_Device);
548 check_vk_result(err);
549 ImGui_ImplVulkan_Shutdown();
550 ImGui_ImplWin32_Shutdown();
551 ImGui::DestroyContext();
552
553 CleanupVulkanWindow(&g_MainWindowData);
554 CleanupVulkan();
555
556 ::DestroyWindow(hwnd);
557 ::UnregisterClassW(wc.lpszClassName, wc.hInstance);
558
559 return 0;
560}
561
562// Helper functions
563
564// Forward declare message handler from imgui_impl_win32.cpp
565extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
566
567// Win32 message handler
568// You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs.
569// - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application, or clear/overwrite your copy of the mouse data.
570// - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application, or clear/overwrite your copy of the keyboard data.
571// Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags.
572LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
573{
574 if (ImGui_ImplWin32_WndProcHandler(hWnd, msg, wParam, lParam))
575 return true;
576
577 switch (msg)
578 {
579 case WM_SIZE:
580 if (g_Device != VK_NULL_HANDLE && wParam != SIZE_MINIMIZED)
581 {
582 // Resize swap chain
583 int fb_width = (UINT)LOWORD(lParam);
584 int fb_height = (UINT)HIWORD(lParam);
585 if (fb_width > 0 && fb_height > 0 && (g_SwapChainRebuild || g_MainWindowData.Width != fb_width || g_MainWindowData.Height != fb_height))
586 {
587 ImGui_ImplVulkan_SetMinImageCount(g_MinImageCount);
588 ImGui_ImplVulkanH_CreateOrResizeWindow(g_Instance, g_PhysicalDevice, g_Device, &g_MainWindowData, g_QueueFamily, g_Allocator, fb_width, fb_height, g_MinImageCount, 0);
589 g_MainWindowData.FrameIndex = 0;
590 g_SwapChainRebuild = false;
591 }
592 }
593 return 0;
594 case WM_SYSCOMMAND:
595 if ((wParam & 0xfff0) == SC_KEYMENU) // Disable ALT application menu
596 return 0;
597 break;
598 case WM_DESTROY:
599 ::PostQuitMessage(0);
600 return 0;
601 }
602 return ::DefWindowProcW(hWnd, msg, wParam, lParam);
603}