vk_engine.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631
  1. #include "vk_engine.h"
  2. #include <SDL.h>
  3. #include <SDL_vulkan.h>
  4. #include <vk_initializers.h>
  5. #include <vk_pipelines.h>
  6. #include <vk_images.h>
  7. #define VMA_IMPLEMENTATION
  8. #include <vk_mem_alloc.h>
  9. #include <VkBootstrap.h>
  10. // IMGUI
  11. #include <imgui.h>
  12. #include <imgui_impl_sdl2.h>
  13. #include <imgui_impl_vulkan.h>
  14. #include <chrono>
  15. #include <thread>
  16. VulkanEngine* loadedEngine = nullptr;
  17. VulkanEngine& VulkanEngine::Get() { return *loadedEngine; }
  18. #ifdef NDEBUG
  19. constexpr bool bUseValidationLayers = false;
  20. #else
  21. constexpr bool bUseValidationLayers = true;
  22. #endif
  23. void VulkanEngine::init()
  24. {
  25. // only one engine initialization is allowed with the application.
  26. assert(loadedEngine == nullptr);
  27. loadedEngine = this;
  28. // We initialize SDL and create a window with it.
  29. SDL_Init(SDL_INIT_VIDEO);
  30. SDL_WindowFlags window_flags = (SDL_WindowFlags)(SDL_WINDOW_VULKAN);
  31. _window = SDL_CreateWindow(
  32. "Coral3D",
  33. SDL_WINDOWPOS_UNDEFINED,
  34. SDL_WINDOWPOS_UNDEFINED,
  35. _windowExtent.width,
  36. _windowExtent.height,
  37. window_flags);
  38. _mainDeletionQueue.push([&](){
  39. SDL_DestroyWindow(_window);
  40. });
  41. init_vulkan();
  42. init_swapchain();
  43. init_commands();
  44. init_sync_structures();
  45. init_descriptors();
  46. init_pipelines();
  47. init_imgui();
  48. // everything went fine
  49. _isInitialized = true;
  50. }
  51. void VulkanEngine::cleanup()
  52. {
  53. if (_isInitialized)
  54. {
  55. // Wait for GPU
  56. vkDeviceWaitIdle(_device);
  57. // Cleanup frame data
  58. for (auto & frame : _frames)
  59. {
  60. frame._deletionQueue.flush();
  61. }
  62. _mainDeletionQueue.flush();
  63. }
  64. loadedEngine = nullptr;
  65. }
  66. void VulkanEngine::draw()
  67. {
  68. // Wait for GPU to finish rendering last frame, timeout: 1 second
  69. VK_CHECK(vkWaitForFences(_device, 1, &get_current_frame()._renderFence, true, 1000000000));
  70. VK_CHECK(vkResetFences(_device, 1, &get_current_frame()._renderFence));
  71. get_current_frame()._deletionQueue.flush();
  72. // Request swapchain image
  73. uint32_t swapchainImageIndex;
  74. VK_CHECK(vkAcquireNextImageKHR(_device, _swapchain, 1000000000, get_current_frame()._swapchainSemaphore, nullptr,
  75. &swapchainImageIndex));
  76. // Get current frames command buffer
  77. VkCommandBuffer cmd = get_current_frame()._mainCommandBuffer;
  78. // Commands finished executing, reset command buffer
  79. VK_CHECK(vkResetCommandBuffer(cmd, 0));
  80. // Command buffer will be used exactly once
  81. VkCommandBufferBeginInfo cmdBeginInfo = vkinit::command_buffer_begin_info(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT);
  82. _drawExtent.width = _drawImage.imageExtent.width;
  83. _drawExtent.height = _drawImage.imageExtent.height;
  84. // Begin recording
  85. VK_CHECK(vkBeginCommandBuffer(cmd, &cmdBeginInfo));
  86. // Transition draw image to general layout for writing into it
  87. vkutil::transition_image(cmd, _drawImage.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL);
  88. draw_clear_color(cmd);
  89. // Transition draw image and swapchain image to correct layout for transferring
  90. vkutil::transition_image(cmd, _drawImage.image, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
  91. vkutil::transition_image(cmd, _swapchainImages[swapchainImageIndex], VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
  92. // Copy draw image to swapchain image
  93. vkutil::copy_image_to_image(cmd, _drawImage.image, _swapchainImages[swapchainImageIndex], _drawExtent, _swapchainExtent);
  94. // Set swapchain image to Attachment Optimal, so we can directly draw to it
  95. vkutil::transition_image(cmd, _swapchainImages[swapchainImageIndex], VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
  96. // Draw IMGUI into swapchain image
  97. draw_imgui(cmd, _swapchainImageViews[swapchainImageIndex]);
  98. // Transition swapchain image to presentable layout
  99. vkutil::transition_image(cmd, _swapchainImages[swapchainImageIndex], VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
  100. // End recording to command buffer
  101. VK_CHECK(vkEndCommandBuffer(cmd));
  102. // Wait for swapchain to be ready (_presentSemaphore)
  103. // Signal when rendering has finished (_renderSemaphore)
  104. VkCommandBufferSubmitInfo cmdInfo = vkinit::command_buffer_submit_info(cmd);
  105. VkSemaphoreSubmitInfo waitInfo = vkinit::semaphore_submit_info(VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT_KHR,get_current_frame()._swapchainSemaphore);
  106. VkSemaphoreSubmitInfo signalInfo = vkinit::semaphore_submit_info(VK_PIPELINE_STAGE_2_ALL_GRAPHICS_BIT, get_current_frame()._renderSemaphore);
  107. VkSubmitInfo2 submit = vkinit::submit_info(&cmdInfo, &signalInfo, &waitInfo);
  108. // Submit to queue and execute
  109. // Block until queue finishes execution (_renderFence)
  110. VK_CHECK(vkQueueSubmit2(_graphicsQueue, 1, &submit, get_current_frame()._renderFence));
  111. // Wait for drawing commands to have finished (_renderSemaphore)
  112. // Then display the image
  113. VkPresentInfoKHR presentInfo = {};
  114. presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
  115. presentInfo.pNext = nullptr;
  116. presentInfo.pSwapchains = &_swapchain;
  117. presentInfo.swapchainCount = 1;
  118. presentInfo.pWaitSemaphores = &get_current_frame()._renderSemaphore;
  119. presentInfo.waitSemaphoreCount = 1;
  120. presentInfo.pImageIndices = &swapchainImageIndex;
  121. VK_CHECK(vkQueuePresentKHR(_graphicsQueue, &presentInfo));
  122. _frameNumber++;
  123. }
  124. void VulkanEngine::run()
  125. {
  126. SDL_Event e;
  127. bool bQuit = false;
  128. while (!bQuit)
  129. {
  130. while (SDL_PollEvent(&e) != 0)
  131. {
  132. if (e.type == SDL_QUIT)
  133. bQuit = true;
  134. if (e.type == SDL_WINDOWEVENT)
  135. {
  136. if (e.window.event == SDL_WINDOWEVENT_MINIMIZED)
  137. {
  138. _stopRendering = true;
  139. }
  140. if (e.window.event == SDL_WINDOWEVENT_RESTORED)
  141. {
  142. _stopRendering = false;
  143. }
  144. }
  145. ImGui_ImplSDL2_ProcessEvent(&e);
  146. }
  147. // do not draw if we are minimized
  148. if (_stopRendering)
  149. {
  150. std::this_thread::sleep_for(std::chrono::milliseconds(100));
  151. continue;
  152. }
  153. // New IMGUI frame
  154. ImGui_ImplVulkan_NewFrame();
  155. ImGui_ImplSDL2_NewFrame(_window);
  156. ImGui::NewFrame();
  157. // Debug
  158. ImGui::ShowDemoWindow();
  159. // Render IMGUI
  160. ImGui::Render();
  161. draw();
  162. }
  163. }
  164. void VulkanEngine::init_vulkan()
  165. {
  166. vkb::InstanceBuilder builder;
  167. auto inst_ret = builder.set_app_name("Coral3D")
  168. .request_validation_layers(bUseValidationLayers)
  169. .use_default_debug_messenger()
  170. .require_api_version(1, 3, 0)
  171. .build();
  172. vkb::Instance vkb_inst = inst_ret.value();
  173. _instance = vkb_inst.instance;
  174. _debugMessenger = vkb_inst.debug_messenger;
  175. SDL_Vulkan_CreateSurface(_window, _instance, &_surface);
  176. //vulkan 1.3 features
  177. VkPhysicalDeviceVulkan13Features features{};
  178. features.dynamicRendering = true;
  179. features.synchronization2 = true;
  180. //vulkan 1.2 features
  181. VkPhysicalDeviceVulkan12Features features12{};
  182. features12.bufferDeviceAddress = true;
  183. features12.descriptorIndexing = true;
  184. //use vkbootstrap to select a gpu.
  185. //We want a gpu that can write to the SDL surface and supports vulkan 1.3 with the correct features
  186. vkb::PhysicalDeviceSelector selector{ vkb_inst };
  187. vkb::PhysicalDevice physicalDevice = selector
  188. .set_minimum_version(1, 3)
  189. .set_required_features_13(features)
  190. .set_required_features_12(features12)
  191. .set_surface(_surface)
  192. .select()
  193. .value();
  194. //create the final vulkan device
  195. vkb::DeviceBuilder deviceBuilder{ physicalDevice };
  196. vkb::Device vkbDevice = deviceBuilder.build().value();
  197. // Get the VkDevice handle used in the rest of a vulkan application
  198. _device = vkbDevice.device;
  199. _physicalGPU = physicalDevice.physical_device;
  200. _graphicsQueue = vkbDevice.get_queue(vkb::QueueType::graphics).value();
  201. _graphicsQueueFamily = vkbDevice.get_queue_index(vkb::QueueType::graphics).value();
  202. // Initialize VMA
  203. VmaAllocatorCreateInfo allocInfo{};
  204. allocInfo.physicalDevice = _physicalGPU;
  205. allocInfo.device = _device;
  206. allocInfo.instance = _instance;
  207. allocInfo.flags = VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT;
  208. vmaCreateAllocator(&allocInfo, &_allocator);
  209. _mainDeletionQueue.push([&](){
  210. vmaDestroyAllocator(_allocator);
  211. vkDestroySurfaceKHR(_instance, _surface, nullptr);
  212. vkDestroyDevice(_device, nullptr);
  213. vkb::destroy_debug_utils_messenger(_instance, _debugMessenger);
  214. vkDestroyInstance(_instance, nullptr);
  215. });
  216. }
  217. void VulkanEngine::init_swapchain()
  218. {
  219. create_swapchain(_windowExtent.width, _windowExtent.height);
  220. // Create draw image
  221. _drawImage.imageFormat = VK_FORMAT_R16G16B16A16_SFLOAT;
  222. _drawImage.imageExtent = {
  223. _windowExtent.width,
  224. _windowExtent.height,
  225. 1
  226. };;
  227. VkImageUsageFlags drawImageUsages{};
  228. drawImageUsages |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
  229. drawImageUsages |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
  230. drawImageUsages |= VK_IMAGE_USAGE_STORAGE_BIT;
  231. drawImageUsages |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
  232. VkImageCreateInfo imgCI = vkinit::image_create_info(_drawImage.imageFormat, drawImageUsages,
  233. _drawImage.imageExtent);
  234. // Allocate the draw image from device (GPU) local memory
  235. VmaAllocationCreateInfo imgAllocCI{};
  236. imgAllocCI.usage = VMA_MEMORY_USAGE_GPU_ONLY;
  237. imgAllocCI.requiredFlags = VkMemoryPropertyFlags(VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
  238. // Allocate image
  239. vmaCreateImage(_allocator, &imgCI, &imgAllocCI, &_drawImage.image, &_drawImage.allocation, nullptr);
  240. // Build image view for draw image
  241. VkImageViewCreateInfo imgViewCI = vkinit::imageview_create_info(_drawImage.imageFormat, _drawImage.image,
  242. VK_IMAGE_ASPECT_COLOR_BIT);
  243. VK_CHECK(vkCreateImageView(_device, &imgViewCI, nullptr, &_drawImage.imageView));
  244. _mainDeletionQueue.push([=, this](){
  245. vkDestroyImageView(_device, _drawImage.imageView, nullptr);
  246. vmaDestroyImage(_allocator, _drawImage.image, _drawImage.allocation);
  247. });
  248. }
  249. void VulkanEngine::init_commands()
  250. {
  251. // Create command pool for commands submitted to the graphics queue
  252. // and allow resetting individual command buffers;
  253. VkCommandPoolCreateInfo commandPoolInfo
  254. {
  255. vkinit::command_pool_create_info(_graphicsQueueFamily,
  256. VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT)
  257. };
  258. // Initialize immediate buffer
  259. VK_CHECK(vkCreateCommandPool(_device, &commandPoolInfo, nullptr, &_immediateBuffer._commandPool));
  260. VkCommandBufferAllocateInfo immCmdAllocInfo
  261. {
  262. vkinit::command_buffer_allocate_info(_immediateBuffer._commandPool,1)
  263. };
  264. VK_CHECK(vkAllocateCommandBuffers(_device, &immCmdAllocInfo, &_immediateBuffer._commandBuffer));
  265. _mainDeletionQueue.push([=, this]() {
  266. vkDestroyCommandPool(_device, _immediateBuffer._commandPool, nullptr);
  267. });
  268. for (auto & frame : _frames)
  269. {
  270. VK_CHECK(vkCreateCommandPool(_device, &commandPoolInfo, nullptr, &frame._commandPool));
  271. // Allocate default command buffer used for rendering
  272. VkCommandBufferAllocateInfo cmdAllocInfo {vkinit::command_buffer_allocate_info(frame._commandPool, 1)};
  273. VK_CHECK(vkAllocateCommandBuffers(_device, &cmdAllocInfo, &frame._mainCommandBuffer));
  274. _mainDeletionQueue.push([=, this](){
  275. vkDestroyCommandPool(_device, frame._commandPool, nullptr);
  276. });
  277. }
  278. }
  279. void VulkanEngine::init_sync_structures()
  280. {
  281. // Fence is used to not record into cmd buffer that is being rendered
  282. // and 2 semaphores to synchronize rendering with swapchain.
  283. // Fence start signaled to be able to wait on it in the first frame.
  284. VkFenceCreateInfo fenceCreateInfo = vkinit::fence_create_info(VK_FENCE_CREATE_SIGNALED_BIT);
  285. VkSemaphoreCreateInfo semaphoreCreateInfo = vkinit::semaphore_create_info();
  286. VK_CHECK(vkCreateFence(_device, &fenceCreateInfo, nullptr, &_immediateBuffer._fence));
  287. _mainDeletionQueue.push([=, this](){
  288. vkDestroyFence(_device, _immediateBuffer._fence, nullptr);
  289. });
  290. for (auto & frame : _frames)
  291. {
  292. VK_CHECK(vkCreateFence(_device, &fenceCreateInfo, nullptr, &frame._renderFence));
  293. VK_CHECK(vkCreateSemaphore(_device, &semaphoreCreateInfo, nullptr, &frame._swapchainSemaphore));
  294. VK_CHECK(vkCreateSemaphore(_device, &semaphoreCreateInfo, nullptr, &frame._renderSemaphore));
  295. // Deletion queue
  296. _mainDeletionQueue.push([=, this](){
  297. vkDestroyFence(_device, frame._renderFence, nullptr);
  298. vkDestroySemaphore(_device, frame._renderSemaphore, nullptr);
  299. vkDestroySemaphore(_device, frame._swapchainSemaphore, nullptr);
  300. });
  301. }
  302. }
  303. void VulkanEngine::create_swapchain(uint32_t width, uint32_t height)
  304. {
  305. vkb::SwapchainBuilder swapchainBuilder{ _physicalGPU,_device,_surface };
  306. _swapchainImageFormat = VK_FORMAT_B8G8R8A8_UNORM;
  307. vkb::Swapchain vkbSwapchain = swapchainBuilder
  308. .set_desired_format(VkSurfaceFormatKHR
  309. { .format = _swapchainImageFormat, .colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR })
  310. .set_desired_present_mode(VK_PRESENT_MODE_FIFO_KHR) // VSync present mode
  311. .set_desired_extent(width, height)
  312. .add_image_usage_flags(VK_IMAGE_USAGE_TRANSFER_DST_BIT)
  313. .build()
  314. .value();
  315. _swapchainExtent = vkbSwapchain.extent;
  316. // Store swapchain and its images
  317. _swapchain = vkbSwapchain.swapchain;
  318. _swapchainImages = vkbSwapchain.get_images().value();
  319. _swapchainImageViews = vkbSwapchain.get_image_views().value();
  320. _mainDeletionQueue.push([=, this](){
  321. vkDestroySwapchainKHR(_device, _swapchain, nullptr);
  322. for (int i = 0; i < _swapchainImageViews.size(); ++i)
  323. {
  324. vkDestroyImageView(_device, _swapchainImageViews[i], nullptr);
  325. }
  326. });
  327. }
  328. void VulkanEngine::draw_clear_color(VkCommandBuffer cmd)
  329. {
  330. // bind the gradient drawing compute pipeline
  331. vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, _computePipeline);
  332. // bind the descriptor set containing the draw image for the compute pipeline
  333. vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, _computePipelineLayout, 0, 1, &_drawImageDescriptors, 0, nullptr);
  334. // execute the compute pipeline dispatch. We are using 16x16 workgroup size so we need to divide by it
  335. vkCmdDispatch(cmd, std::ceil(_drawExtent.width / 16.0), std::ceil(_drawExtent.height / 16.0), 1);
  336. }
  337. void VulkanEngine::init_descriptors()
  338. {
  339. std::vector<DescriptorAllocator::PoolSizeRatio> sizes
  340. {
  341. {VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1}
  342. };
  343. _globalDescriptorAllocator.init_pool(_device, 10, sizes);
  344. {
  345. DescriptorLayoutBuilder layoutBuilder;
  346. layoutBuilder.add_binding(0, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE);
  347. _drawImageDescriptorLayout = layoutBuilder.build(_device, VK_SHADER_STAGE_COMPUTE_BIT);
  348. }
  349. // Allocate descriptor for draw image
  350. _drawImageDescriptors = _globalDescriptorAllocator.allocate(_device, _drawImageDescriptorLayout);
  351. // The DescImageInfo holds a "pointer" to the resource that will get bound to the descriptor
  352. VkDescriptorImageInfo imgInfo
  353. {
  354. .imageView = _drawImage.imageView,
  355. .imageLayout = VK_IMAGE_LAYOUT_GENERAL
  356. };
  357. // A write is used to "write" the resource into the descriptor set
  358. VkWriteDescriptorSet drawImageWrite
  359. {
  360. .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
  361. .pNext = nullptr,
  362. .dstSet = _drawImageDescriptors,
  363. .dstBinding = 0,
  364. .descriptorCount = 1,
  365. .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
  366. .pImageInfo = &imgInfo
  367. };
  368. vkUpdateDescriptorSets(_device, 1, &drawImageWrite, 0, nullptr);
  369. _mainDeletionQueue.push([&](){
  370. _globalDescriptorAllocator.destroy_pool(_device);
  371. vkDestroyDescriptorSetLayout(_device, _drawImageDescriptorLayout, nullptr);
  372. });
  373. }
  374. void VulkanEngine::init_pipelines()
  375. {
  376. init_background_pipelines();
  377. }
  378. void VulkanEngine::init_background_pipelines()
  379. {
  380. VkPipelineLayoutCreateInfo computeLayout{};
  381. computeLayout.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
  382. computeLayout.pNext = nullptr;
  383. computeLayout.pSetLayouts = &_drawImageDescriptorLayout;
  384. computeLayout.setLayoutCount = 1;
  385. VK_CHECK(vkCreatePipelineLayout(_device, &computeLayout, nullptr, &_computePipelineLayout));
  386. VkShaderModule computeDrawShader;
  387. if (!vkutil::load_shader_module("../shaders/gradient.comp.spv", _device, &computeDrawShader))
  388. {
  389. fmt::print("Error when building the compute shader \n");
  390. }
  391. VkPipelineShaderStageCreateInfo stageinfo{};
  392. stageinfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
  393. stageinfo.pNext = nullptr;
  394. stageinfo.stage = VK_SHADER_STAGE_COMPUTE_BIT;
  395. stageinfo.module = computeDrawShader;
  396. stageinfo.pName = "main";
  397. VkComputePipelineCreateInfo computePipelineCreateInfo{};
  398. computePipelineCreateInfo.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO;
  399. computePipelineCreateInfo.pNext = nullptr;
  400. computePipelineCreateInfo.layout = _computePipelineLayout;
  401. computePipelineCreateInfo.stage = stageinfo;
  402. VK_CHECK(vkCreateComputePipelines(_device,VK_NULL_HANDLE,1,&computePipelineCreateInfo, nullptr, &_computePipeline));
  403. vkDestroyShaderModule(_device, computeDrawShader, nullptr);
  404. _mainDeletionQueue.push([&]() {
  405. vkDestroyPipelineLayout(_device, _computePipelineLayout, nullptr);
  406. vkDestroyPipeline(_device, _computePipeline, nullptr);
  407. });
  408. }
  409. void VulkanEngine::draw_imgui(VkCommandBuffer cmd, VkImageView targetImageView)
  410. {
  411. VkRenderingAttachmentInfo colorAttachment = vkinit::attachment_info(targetImageView, nullptr, VK_IMAGE_LAYOUT_GENERAL);
  412. VkRenderingInfo renderInfo = vkinit::rendering_info(_swapchainExtent, &colorAttachment, nullptr);
  413. vkCmdBeginRendering(cmd, &renderInfo);
  414. ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmd);
  415. vkCmdEndRendering(cmd);
  416. }
  417. void VulkanEngine::immediate_submit(std::function<void(VkCommandBuffer)> &&function)
  418. {
  419. VK_CHECK(vkResetFences(_device, 1, &_immediateBuffer._fence));
  420. VK_CHECK(vkResetCommandBuffer(_immediateBuffer._commandBuffer, 0));
  421. VkCommandBuffer cmd = _immediateBuffer._commandBuffer;
  422. VkCommandBufferBeginInfo cmdBeginInfo = vkinit::command_buffer_begin_info(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT);
  423. VK_CHECK(vkBeginCommandBuffer(cmd, &cmdBeginInfo));
  424. function(cmd);
  425. VK_CHECK(vkEndCommandBuffer(cmd));
  426. VkCommandBufferSubmitInfo cmdinfo = vkinit::command_buffer_submit_info(cmd);
  427. VkSubmitInfo2 submit = vkinit::submit_info(&cmdinfo, nullptr, nullptr);
  428. // Submit and execute command buffer
  429. VK_CHECK(vkQueueSubmit2(_graphicsQueue, 1, &submit, _immediateBuffer._fence));
  430. // _fence will block until graphic commands execution have finished execution
  431. VK_CHECK(vkWaitForFences(_device, 1, &_immediateBuffer._fence, true, 9999999999));
  432. }
  433. void VulkanEngine::init_imgui()
  434. {
  435. // Create descriptor pool used by IMGUI
  436. // Pool size is oversize but as provided by imgui demo
  437. VkDescriptorPoolSize pool_sizes[] = { { VK_DESCRIPTOR_TYPE_SAMPLER, 1000 },
  438. { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1000 },
  439. { VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1000 },
  440. { VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1000 },
  441. { VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, 1000 },
  442. { VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, 1000 },
  443. { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1000 },
  444. { VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1000 },
  445. { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1000 },
  446. { VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, 1000 },
  447. { VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, 1000 } };
  448. VkDescriptorPoolCreateInfo pool_info = {};
  449. pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
  450. pool_info.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT;
  451. pool_info.maxSets = 1000;
  452. pool_info.poolSizeCount = (uint32_t)std::size(pool_sizes);
  453. pool_info.pPoolSizes = pool_sizes;
  454. VkDescriptorPool imguiPool;
  455. VK_CHECK(vkCreateDescriptorPool(_device, &pool_info, nullptr, &imguiPool));
  456. // Initialize IMGUI structures
  457. ImGui::CreateContext();
  458. // Initialize IMGUI for SDL
  459. ImGui_ImplSDL2_InitForVulkan(_window);
  460. // Initialize IMGUI for Vulkan
  461. ImGui_ImplVulkan_InitInfo init_info = {};
  462. init_info.Instance = _instance;
  463. init_info.PhysicalDevice = _physicalGPU;
  464. init_info.Device = _device;
  465. init_info.Queue = _graphicsQueue;
  466. init_info.DescriptorPool = imguiPool;
  467. init_info.MinImageCount = 3;
  468. init_info.ImageCount = 3;
  469. init_info.UseDynamicRendering = true;
  470. init_info.ColorAttachmentFormat = _swapchainImageFormat;
  471. init_info.MSAASamples = VK_SAMPLE_COUNT_1_BIT;
  472. ImGui_ImplVulkan_Init(&init_info, VK_NULL_HANDLE);
  473. // Upload font textures to GPU
  474. immediate_submit([&](VkCommandBuffer cmd) { ImGui_ImplVulkan_CreateFontsTexture(cmd); });
  475. // Clear font textures from CPU
  476. ImGui_ImplVulkan_DestroyFontUploadObjects();
  477. _mainDeletionQueue.push([=, this]() {
  478. vkDestroyDescriptorPool(_device, imguiPool, nullptr);
  479. ImGui_ImplVulkan_Shutdown();
  480. });
  481. }