DeviceResources.cpp 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758
  1. // The MIT License(MIT)
  2. //
  3. // Copyright(c) 2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
  4. //
  5. // Permission is hereby granted, free of charge, to any person obtaining a copy of
  6. // this software and associated documentation files(the "Software"), to deal in
  7. // the Software without restriction, including without limitation the rights to
  8. // use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of
  9. // the Software, and to permit persons to whom the Software is furnished to do so,
  10. // subject to the following conditions :
  11. //
  12. // The above copyright notice and this permission notice shall be included in all
  13. // copies or substantial portions of the Software.
  14. //
  15. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
  17. // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR
  18. // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
  19. // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  20. // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  21. #include "DeviceResources.h"
  22. #include <algorithm>
  23. #include <array>
  24. #include <vector>
  25. #include <imgui_impl_vulkan.h>
  26. static void glfw_window_size_callback(GLFWwindow* window, int width, int height)
  27. {
  28. auto devRes = reinterpret_cast<DeviceResources*>(glfwGetWindowUserPointer(window));
  29. devRes->resizeRenderTarget(width, height);
  30. }
  31. const VkFormat DeviceResources::SwapchainFormat = VK_FORMAT_R8G8B8A8_UNORM;
  32. void DeviceResources::create(GLFWwindow* hWnd)
  33. {
  34. m_window = hWnd;
  35. assert(glfwGetWindowUserPointer(hWnd) == nullptr);
  36. uint32_t extensionCount;
  37. auto extensions = glfwGetRequiredInstanceExtensions(&extensionCount);
  38. if (extensions == nullptr)
  39. {
  40. VK_DIE("glfwGetRequiredInstanceExtensions");
  41. }
  42. VkInstanceCreateInfo createInfo{};
  43. createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
  44. createInfo.enabledExtensionCount = extensionCount;
  45. createInfo.ppEnabledExtensionNames = extensions;
  46. VK_OK(vkCreateInstance(&createInfo, nullptr, &m_instance));
  47. selectPhysicalDeviceAndQueueFamily();
  48. VkDeviceQueueCreateInfo qCreateInfo{};
  49. qCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
  50. qCreateInfo.queueFamilyIndex = m_queueFamilyIndex;
  51. qCreateInfo.queueCount = 1;
  52. const float qPriority = 1.f;
  53. qCreateInfo.pQueuePriorities = &qPriority;
  54. VkPhysicalDeviceFeatures physDevFeatures;
  55. vkGetPhysicalDeviceFeatures(m_physicalDevice, &physDevFeatures);
  56. const char* logicalDevExt[] = {
  57. VK_KHR_SWAPCHAIN_EXTENSION_NAME,
  58. VK_KHR_MAINTENANCE2_EXTENSION_NAME, // For VkImageViewUsageCreateInfo
  59. };
  60. VkDeviceCreateInfo devCreateInfo{};
  61. devCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
  62. devCreateInfo.pQueueCreateInfos = &qCreateInfo;
  63. devCreateInfo.queueCreateInfoCount = 1;
  64. devCreateInfo.pEnabledFeatures = &physDevFeatures;
  65. devCreateInfo.enabledExtensionCount = static_cast<uint32_t>(std::size(logicalDevExt));
  66. devCreateInfo.ppEnabledExtensionNames = logicalDevExt;
  67. VK_OK(vkCreateDevice(m_physicalDevice, &devCreateInfo, nullptr, &m_device));
  68. vkGetPhysicalDeviceProperties(m_physicalDevice, &m_physicalDeviceProperties);
  69. vkGetDeviceQueue(m_device, m_queueFamilyIndex, 0, &m_queue);
  70. //See: vkCreateWin32SurfaceKHR
  71. VK_OK(glfwCreateWindowSurface(m_instance, m_window, nullptr, &m_surface));
  72. VkBool32 isSurfaceSupported;
  73. VK_OK(vkGetPhysicalDeviceSurfaceSupportKHR(m_physicalDevice, m_queueFamilyIndex, m_surface, &isSurfaceSupported));
  74. if (isSurfaceSupported != VK_TRUE)
  75. {
  76. VK_DIE("vkGetPhysicalDeviceSurfaceSupportKHR");
  77. }
  78. m_surfaceFormat = ImGui_ImplVulkanH_SelectSurfaceFormat(m_physicalDevice, m_surface, &SwapchainFormat, 1, SwapchainColorSpace);
  79. // Imgui needs a descriptor pool.
  80. // This is probably excessive, but it's what's in the sample and should cover all our other needs.
  81. // https://github.com/ocornut/imgui/wiki/Integrating-with-Vulkan
  82. // https://github.com/ocornut/imgui/blob/master/examples/example_glfw_vulkan/main.cpp
  83. {
  84. const uint32_t POOL_COUNT = 1000;
  85. VkDescriptorPoolSize pool_sizes[] =
  86. {
  87. { VK_DESCRIPTOR_TYPE_SAMPLER, POOL_COUNT },
  88. { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, POOL_COUNT },
  89. { VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, POOL_COUNT },
  90. { VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, POOL_COUNT },
  91. { VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, POOL_COUNT },
  92. { VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, POOL_COUNT },
  93. { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, POOL_COUNT },
  94. { VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, POOL_COUNT },
  95. { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, POOL_COUNT },
  96. { VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, POOL_COUNT },
  97. { VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, POOL_COUNT }
  98. };
  99. constexpr uint32_t NUM_POOLS = static_cast<uint32_t>(std::size(pool_sizes));
  100. VkDescriptorPoolCreateInfo pool_info{};
  101. pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
  102. pool_info.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT;
  103. pool_info.maxSets = POOL_COUNT * NUM_POOLS;
  104. pool_info.poolSizeCount = NUM_POOLS;
  105. pool_info.pPoolSizes = pool_sizes;
  106. VK_OK(vkCreateDescriptorPool(m_device, &pool_info, nullptr, &m_descriptorPool));
  107. }
  108. // Texture sampler
  109. {
  110. VkSamplerCreateInfo info{};
  111. info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
  112. info.magFilter = VK_FILTER_LINEAR;
  113. info.minFilter = VK_FILTER_LINEAR;
  114. info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST;
  115. info.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
  116. info.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
  117. info.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
  118. info.minLod = -1000;
  119. info.maxLod = 1000;
  120. info.maxAnisotropy = 1.0f;
  121. VK_OK(vkCreateSampler(m_device, &info, nullptr, &m_sampler));
  122. }
  123. if (m_physicalDeviceProperties.limits.timestampComputeAndGraphics)
  124. {
  125. VkQueryPoolCreateInfo info{};
  126. info.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO;
  127. info.queryType = VK_QUERY_TYPE_TIMESTAMP;
  128. info.queryCount = DeviceResources::NumQueryValues;
  129. VK_OK(vkCreateQueryPool(m_device, &info, m_allocator, &m_queryPool));
  130. }
  131. int width, height;
  132. glfwGetFramebufferSize(m_window, &width, &height);
  133. resizeRenderTarget(width, height);
  134. m_initialized = true;
  135. glfwSetWindowUserPointer(m_window, this);
  136. glfwSetWindowSizeCallback(m_window, glfw_window_size_callback);
  137. }
  138. void DeviceResources::createSurfaceResources()
  139. {
  140. destroySurfaceResources();
  141. // Swapchain
  142. {
  143. const auto oldSwapchain = m_swapchain;
  144. VkSurfaceCapabilitiesKHR surfCaps{};
  145. VK_OK(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(m_physicalDevice, m_surface, &surfCaps));
  146. VkSwapchainCreateInfoKHR swapCreateInfo{};
  147. swapCreateInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
  148. swapCreateInfo.surface = m_surface;
  149. swapCreateInfo.minImageCount = surfCaps.minImageCount;
  150. swapCreateInfo.imageFormat = m_surfaceFormat.format;
  151. swapCreateInfo.imageColorSpace = m_surfaceFormat.colorSpace;
  152. swapCreateInfo.imageArrayLayers = 1;
  153. // `TRANSFER_DST` allows us to blit into the swapchain images
  154. // `STORAGE` allows us to bind to compute shader output
  155. swapCreateInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_STORAGE_BIT;
  156. swapCreateInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
  157. swapCreateInfo.preTransform = surfCaps.currentTransform;
  158. swapCreateInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
  159. swapCreateInfo.presentMode = VK_PRESENT_MODE_IMMEDIATE_KHR;
  160. swapCreateInfo.clipped = VK_TRUE;
  161. swapCreateInfo.oldSwapchain = oldSwapchain;
  162. if (surfCaps.currentExtent.width != UINT32_MAX)
  163. {
  164. swapCreateInfo.imageExtent = surfCaps.currentExtent;
  165. }
  166. else
  167. {
  168. int width, height;
  169. glfwGetFramebufferSize(m_window, &width, &height);
  170. swapCreateInfo.imageExtent = {
  171. std::clamp<uint32_t>(width, surfCaps.minImageExtent.width, surfCaps.maxImageExtent.width),
  172. std::clamp<uint32_t>(height, surfCaps.minImageExtent.height, surfCaps.maxImageExtent.height)
  173. };
  174. }
  175. m_width = swapCreateInfo.imageExtent.width;
  176. m_height = swapCreateInfo.imageExtent.height;
  177. VK_OK(vkCreateSwapchainKHR(m_device, &swapCreateInfo, m_allocator, &m_swapchain));
  178. if (oldSwapchain != VK_NULL_HANDLE)
  179. {
  180. vkDestroySwapchainKHR(m_device, oldSwapchain, m_allocator);
  181. }
  182. }
  183. // Render pass
  184. {
  185. VkAttachmentDescription colorAttachDesc {};
  186. colorAttachDesc.format = m_surfaceFormat.format;
  187. colorAttachDesc.samples = VK_SAMPLE_COUNT_1_BIT;
  188. // Don't VK_ATTACHMENT_LOAD_OP_CLEAR because this pass is only used for imgui
  189. // and compute shader has already populated buffer
  190. colorAttachDesc.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
  191. colorAttachDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
  192. colorAttachDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
  193. colorAttachDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
  194. colorAttachDesc.initialLayout = VK_IMAGE_LAYOUT_GENERAL;
  195. colorAttachDesc.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
  196. VkAttachmentReference colorRef{};
  197. colorRef.attachment = 0;
  198. colorRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
  199. VkSubpassDescription subpassDesc{};
  200. subpassDesc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
  201. subpassDesc.colorAttachmentCount = 1;
  202. subpassDesc.pColorAttachments = &colorRef;
  203. VkSubpassDependency subpassDep{};
  204. subpassDep.srcSubpass = VK_SUBPASS_EXTERNAL;
  205. subpassDep.dstSubpass = 0;
  206. subpassDep.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
  207. subpassDep.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
  208. subpassDep.srcAccessMask = 0;
  209. subpassDep.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
  210. VkRenderPassCreateInfo info{};
  211. info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
  212. info.attachmentCount = 1;
  213. info.pAttachments = &colorAttachDesc;
  214. info.subpassCount = 1;
  215. info.pSubpasses = &subpassDesc;
  216. info.dependencyCount = 1;
  217. info.pDependencies = &subpassDep;
  218. VK_OK(vkCreateRenderPass(m_device, &info, m_allocator, &m_renderPass));
  219. }
  220. // Swapchain entourage
  221. {
  222. uint32_t imageCount;
  223. VK_OK(vkGetSwapchainImagesKHR(m_device, m_swapchain, &imageCount, nullptr));
  224. std::vector<VkImage> swapchainImages(imageCount);
  225. VK_OK(vkGetSwapchainImagesKHR(m_device, m_swapchain, &imageCount, swapchainImages.data()));
  226. m_frames.resize(imageCount);
  227. m_semaphores.resize(imageCount);
  228. for (uint32_t i = 0; i < imageCount; ++i)
  229. {
  230. m_frames[i].backbuffer = swapchainImages[i];
  231. // Image views
  232. {
  233. const VkImageViewUsageCreateInfo usageInfo{
  234. VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO,
  235. nullptr,
  236. VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_STORAGE_BIT
  237. };
  238. VkImageViewCreateInfo info{};
  239. info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
  240. info.pNext = &usageInfo;
  241. info.image = m_frames[i].backbuffer;
  242. info.viewType = VK_IMAGE_VIEW_TYPE_2D;
  243. info.components = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A };
  244. info.format = m_surfaceFormat.format;
  245. info.subresourceRange.layerCount = 1;
  246. info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
  247. info.subresourceRange.levelCount = 1;
  248. VK_OK(vkCreateImageView(m_device, &info, m_allocator, &m_frames[i].backbufferView));
  249. }
  250. // Framebuffers
  251. {
  252. VkFramebufferCreateInfo info{};
  253. info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
  254. info.renderPass = m_renderPass;
  255. info.attachmentCount = 1;
  256. info.pAttachments = &m_frames[i].backbufferView;
  257. info.width = m_width;
  258. info.height = m_height;
  259. info.layers = 1;
  260. VK_OK(vkCreateFramebuffer(m_device, &info, m_allocator, &m_frames[i].framebuffer));
  261. }
  262. // Command pool
  263. {
  264. VkCommandPoolCreateInfo info{};
  265. info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
  266. info.queueFamilyIndex = m_queueFamilyIndex;
  267. VK_OK(vkCreateCommandPool(m_device, &info, m_allocator, &m_frames[i].commandPool));
  268. }
  269. {
  270. VkCommandBufferAllocateInfo info{};
  271. info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
  272. info.commandPool = m_frames[i].commandPool;
  273. info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
  274. info.commandBufferCount = 1;
  275. VK_OK(vkAllocateCommandBuffers(m_device, &info, &m_frames[i].commandBuffer));
  276. }
  277. {
  278. VkFenceCreateInfo info{};
  279. info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
  280. info.flags = VK_FENCE_CREATE_SIGNALED_BIT;
  281. VK_OK(vkCreateFence(m_device, &info, m_allocator, &m_frames[i].fence));
  282. }
  283. // Per-frame semaphores
  284. {
  285. VkSemaphoreCreateInfo info = {};
  286. info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
  287. VK_OK(vkCreateSemaphore(m_device, &info, m_allocator, &m_semaphores[i].imageAcquired));
  288. VK_OK(vkCreateSemaphore(m_device, &info, m_allocator, &m_semaphores[i].renderComplete));
  289. }
  290. }
  291. }
  292. }
  293. void DeviceResources::destroySurfaceResources()
  294. {
  295. VK_OK(vkDeviceWaitIdle(m_device));
  296. for (auto& frame : m_frames)
  297. {
  298. vkDestroyFence(m_device, frame.fence, m_allocator);
  299. vkFreeCommandBuffers(m_device, frame.commandPool, 1, &frame.commandBuffer);
  300. vkDestroyCommandPool(m_device, frame.commandPool, m_allocator);
  301. vkDestroyFramebuffer(m_device, frame.framebuffer, m_allocator);
  302. vkDestroyImageView(m_device, frame.backbufferView, m_allocator);
  303. }
  304. m_frames.clear();
  305. for (auto& frame : m_semaphores)
  306. {
  307. vkDestroySemaphore(m_device, frame.imageAcquired, m_allocator);
  308. vkDestroySemaphore(m_device, frame.renderComplete, m_allocator);
  309. }
  310. m_semaphores.clear();
  311. if (m_renderPass != VK_NULL_HANDLE)
  312. {
  313. vkDestroyRenderPass(m_device, m_renderPass, m_allocator);
  314. m_renderPass = VK_NULL_HANDLE;
  315. }
  316. // NB: swapchain isn't destroyed because this is called from
  317. // createSurfaceResources() where we need old swapchain when recreating it
  318. }
  319. void DeviceResources::cleanUp()
  320. {
  321. m_initialized = false;
  322. glfwSetWindowUserPointer(m_window, nullptr);
  323. destroySurfaceResources();
  324. vkDestroyQueryPool(m_device, m_queryPool, m_allocator);
  325. vkDestroySampler(m_device, m_sampler, m_allocator);
  326. vkDestroyDescriptorPool(m_device, m_descriptorPool, m_allocator);
  327. vkDestroySwapchainKHR(m_device, m_swapchain, m_allocator);
  328. vkDestroySurfaceKHR(m_instance, m_surface, m_allocator);
  329. vkDestroyDevice(m_device, m_allocator);
  330. vkDestroyInstance(m_instance, m_allocator);
  331. }
  332. void DeviceResources::selectPhysicalDeviceAndQueueFamily()
  333. {
  334. uint32_t deviceCount = 0;
  335. VK_OK(vkEnumeratePhysicalDevices(m_instance, &deviceCount, nullptr));
  336. if (deviceCount == 0) {
  337. VK_DIE("vkEnumeratePhysicalDevices");
  338. }
  339. std::vector<VkPhysicalDevice> physicalDevices(deviceCount);
  340. VK_OK(vkEnumeratePhysicalDevices(m_instance, &deviceCount, physicalDevices.data()));
  341. for (const auto& physDev : physicalDevices)
  342. {
  343. uint32_t queueFamilyCount = 0;
  344. vkGetPhysicalDeviceQueueFamilyProperties(physDev, &queueFamilyCount, nullptr);
  345. std::vector<VkQueueFamilyProperties> queueFamilies(queueFamilyCount);
  346. vkGetPhysicalDeviceQueueFamilyProperties(physDev, &queueFamilyCount, queueFamilies.data());
  347. for (auto i = 0; i < queueFamilies.size(); ++i)
  348. {
  349. const auto& qFamily = queueFamilies[i];
  350. // To make things a bit simpler, we want a single queue that does everything we need
  351. if ((qFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT) && (qFamily.queueFlags & VK_QUEUE_COMPUTE_BIT)
  352. && (qFamily.queueFlags & VK_QUEUE_TRANSFER_BIT)
  353. && glfwGetPhysicalDevicePresentationSupport(m_instance, physDev, i))
  354. {
  355. // Additionally can:
  356. // - vkGetPhysicalDeviceSurfaceFormatsKHR
  357. // - vkGetPhysicalDeviceSurfacePresentModesKHR
  358. m_physicalDevice = physDev;
  359. m_queueFamilyIndex = i;
  360. return;
  361. }
  362. }
  363. }
  364. VK_DIE("selectPhysicalDeviceAndQueueFamily");
  365. }
  366. uint32_t DeviceResources::findMemoryTypeIndex(uint32_t memoryTypeBits, VkMemoryPropertyFlags memPropFlags)
  367. {
  368. VkPhysicalDeviceMemoryProperties physDevMemProps;
  369. vkGetPhysicalDeviceMemoryProperties(m_physicalDevice, &physDevMemProps);
  370. for (uint32_t i = 0; i < physDevMemProps.memoryTypeCount; ++i)
  371. {
  372. if ((memoryTypeBits & (1 << i))
  373. && (physDevMemProps.memoryTypes[i].propertyFlags & memPropFlags) == memPropFlags)
  374. {
  375. return i;
  376. }
  377. }
  378. VK_DIE("findMemoryTypeIndex");
  379. return -1;
  380. }
  381. void DeviceResources::createConstBuffer(void* initialData, uint32_t size, VkBuffer* outBuffer, VkDeviceMemory* outBuffMem, VkDeviceSize* outOffset)
  382. {
  383. const auto align = m_physicalDeviceProperties.limits.minUniformBufferOffsetAlignment;
  384. *outOffset = ((size + align - 1) / align) * align;
  385. createBuffer(*outOffset * numSwapchainImages(),
  386. VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
  387. VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
  388. outBuffer, outBuffMem);
  389. }
  390. void DeviceResources::createBuffer(VkDeviceSize size, VkBufferUsageFlags buffUsage, VkMemoryPropertyFlags memProps, VkBuffer* outBuffer, VkDeviceMemory* outBuffMem)
  391. {
  392. {
  393. VkBufferCreateInfo info{};
  394. info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
  395. info.size = size;
  396. info.usage = buffUsage;
  397. info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
  398. VK_OK(vkCreateBuffer(m_device, &info, nullptr, outBuffer));
  399. }
  400. {
  401. VkMemoryRequirements memReqs;
  402. vkGetBufferMemoryRequirements(m_device, *outBuffer, &memReqs);
  403. VkMemoryAllocateInfo info{};
  404. info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
  405. info.allocationSize = memReqs.size;
  406. info.memoryTypeIndex = findMemoryTypeIndex(memReqs.memoryTypeBits, memProps);
  407. VK_OK(vkAllocateMemory(m_device, &info, nullptr, outBuffMem));
  408. }
  409. VK_OK(vkBindBufferMemory(m_device, *outBuffer, *outBuffMem, 0));
  410. }
  411. void DeviceResources::resizeRenderTarget(uint32_t Width, uint32_t Height)
  412. {
  413. createSurfaceResources();
  414. }
  415. void DeviceResources::update()
  416. {
  417. if (m_swapChainRebuild)
  418. {
  419. int width, height;
  420. glfwGetFramebufferSize(m_window, &width, &height);
  421. if (width > 0 && height > 0)
  422. {
  423. ImGui_ImplVulkan_SetMinImageCount(m_minImageCount);
  424. resizeRenderTarget(width, height);
  425. m_frameIndex = 0;
  426. m_swapChainRebuild = false;
  427. }
  428. }
  429. }
  430. void DeviceResources::beginRender()
  431. {
  432. auto image_acquired_semaphore = imageAcquired();
  433. auto render_complete_semaphore = renderComplete();
  434. VkResult err = vkAcquireNextImageKHR(m_device, swapchain(), UINT64_MAX, image_acquired_semaphore, VK_NULL_HANDLE, &m_frameIndex);
  435. if (err == VK_ERROR_OUT_OF_DATE_KHR || err == VK_SUBOPTIMAL_KHR)
  436. {
  437. requestSwapChainRebuild();
  438. return;
  439. }
  440. auto frame = currentFrame();
  441. auto cmdBuff = commandBuffer();
  442. {
  443. VK_OK(vkWaitForFences(m_device, 1, &frame->fence, VK_TRUE, UINT64_MAX)); // wait indefinitely
  444. VK_OK(vkResetFences(m_device, 1, &frame->fence));
  445. }
  446. {
  447. VK_OK(vkResetCommandPool(m_device, frame->commandPool, 0));
  448. VkCommandBufferBeginInfo info{};
  449. info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
  450. info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
  451. VK_OK(vkBeginCommandBuffer(cmdBuff, &info));
  452. }
  453. // Layout transition backbuffer
  454. {
  455. VkImageMemoryBarrier barrier{};
  456. barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
  457. barrier.srcAccessMask = VK_ACCESS_MEMORY_WRITE_BIT;
  458. barrier.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT;
  459. barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
  460. barrier.newLayout = VK_IMAGE_LAYOUT_GENERAL;
  461. barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
  462. barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
  463. barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
  464. barrier.subresourceRange.levelCount = 1;
  465. barrier.subresourceRange.layerCount = 1;
  466. barrier.image = backBuffer();
  467. vkCmdPipelineBarrier(cmdBuff, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 0, nullptr, 1, &barrier);
  468. }
  469. }
  470. void DeviceResources::present(uint32_t SyncInterval, uint32_t Flags)
  471. {
  472. if (m_swapChainRebuild)
  473. return;
  474. auto cmdBuff = commandBuffer();
  475. // Layout transition backbuffer for present
  476. {
  477. VkImageMemoryBarrier barrier{};
  478. barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
  479. barrier.srcAccessMask = VK_ACCESS_MEMORY_WRITE_BIT;
  480. barrier.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT;
  481. barrier.oldLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
  482. barrier.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
  483. barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
  484. barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
  485. barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
  486. barrier.subresourceRange.levelCount = 1;
  487. barrier.subresourceRange.layerCount = 1;
  488. barrier.image = backBuffer();
  489. vkCmdPipelineBarrier(cmdBuff, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 0, nullptr, 1, &barrier);
  490. }
  491. auto image_acquired_semaphore = imageAcquired();
  492. auto render_complete_semaphore = renderComplete();
  493. auto frame = currentFrame();
  494. // Submit command buffer
  495. {
  496. VkPipelineStageFlags wait_stage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
  497. VkSubmitInfo info = {};
  498. info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
  499. info.waitSemaphoreCount = 1;
  500. info.pWaitSemaphores = &image_acquired_semaphore;
  501. info.pWaitDstStageMask = &wait_stage;
  502. info.commandBufferCount = 1;
  503. info.pCommandBuffers = &cmdBuff;
  504. info.signalSemaphoreCount = 1;
  505. info.pSignalSemaphores = &render_complete_semaphore;
  506. VK_OK(vkEndCommandBuffer(cmdBuff));
  507. VK_OK(vkQueueSubmit(m_queue, 1, &info, frame->fence));
  508. }
  509. // Frame present
  510. VkPresentInfoKHR info{};
  511. info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
  512. info.waitSemaphoreCount = 1;
  513. info.pWaitSemaphores = &render_complete_semaphore;
  514. info.swapchainCount = 1;
  515. info.pSwapchains = &m_swapchain;
  516. info.pImageIndices = &m_frameIndex;
  517. VkResult err = vkQueuePresentKHR(m_queue, &info);
  518. if (err == VK_ERROR_OUT_OF_DATE_KHR || err == VK_SUBOPTIMAL_KHR)
  519. {
  520. requestSwapChainRebuild();
  521. return;
  522. }
  523. assert(err == VK_SUCCESS);
  524. m_semaphoreIndex = (m_semaphoreIndex + 1) % numSwapchainImages(); // Now we can use the next set of semaphores
  525. // SwapBuffers not needed with Vulkan
  526. //glfwSwapBuffers(hwnd);
  527. }
  528. VkCommandBuffer DeviceResources::beginOneTimeSubmitCmd()
  529. {
  530. VkCommandBuffer cmdBuff = commandBuffer();
  531. VK_OK(vkResetCommandPool(m_device, commandPool(), 0));
  532. VkCommandBufferBeginInfo info{};
  533. info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
  534. info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
  535. VK_OK(vkBeginCommandBuffer(cmdBuff, &info));
  536. return cmdBuff;
  537. }
  538. void DeviceResources::endOneTimeSubmitCmd()
  539. {
  540. VkCommandBuffer cmdBuff = commandBuffer();
  541. VkSubmitInfo info{};
  542. info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
  543. info.commandBufferCount = 1;
  544. info.pCommandBuffers = &cmdBuff;
  545. VK_OK(vkEndCommandBuffer(cmdBuff));
  546. VK_OK(vkQueueSubmit(m_queue, 1, &info, VK_NULL_HANDLE));
  547. VK_OK(vkDeviceWaitIdle(m_device));
  548. }
  549. void DeviceResources::createTexture2D(int w, int h, VkFormat format, const void* data, uint32_t rowPitch, uint32_t imageSize, VkImage* outImage, VkDeviceMemory* outDeviceMemory)
  550. {
  551. auto width = static_cast<uint32_t>(w);
  552. auto height = static_cast<uint32_t>(h);
  553. VkBuffer stagingBuff;
  554. VkDeviceMemory stagingBuffMem;
  555. createBuffer(imageSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
  556. VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
  557. &stagingBuff, &stagingBuffMem);
  558. void* mappedMem;
  559. VK_OK(vkMapMemory(m_device, stagingBuffMem, 0, imageSize, 0, &mappedMem));
  560. memcpy(mappedMem, data, imageSize);
  561. vkUnmapMemory(m_device, stagingBuffMem);
  562. // Create texture image object and backing memory
  563. {
  564. VkImageCreateInfo info{};
  565. info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
  566. info.imageType = VK_IMAGE_TYPE_2D;
  567. info.extent.width = width;
  568. info.extent.height = height;
  569. info.extent.depth = 1;
  570. info.mipLevels = 1;
  571. info.arrayLayers = 1;
  572. info.format = format;
  573. info.tiling = VK_IMAGE_TILING_OPTIMAL;
  574. info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
  575. info.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
  576. info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
  577. info.samples = VK_SAMPLE_COUNT_1_BIT;
  578. VK_OK(vkCreateImage(m_device, &info, nullptr, outImage));
  579. }
  580. {
  581. VkMemoryRequirements memReq{};
  582. vkGetImageMemoryRequirements(m_device, *outImage, &memReq);
  583. VkMemoryAllocateInfo info{};
  584. info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
  585. info.allocationSize = memReq.size;
  586. info.memoryTypeIndex = findMemoryTypeIndex(memReq.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
  587. VK_OK(vkAllocateMemory(m_device, &info, nullptr, outDeviceMemory));
  588. VK_OK(vkBindImageMemory(m_device, *outImage, *outDeviceMemory, 0));
  589. }
  590. VkCommandBuffer cmdBuff = beginOneTimeSubmitCmd();
  591. {
  592. VkImageMemoryBarrier transferBarrier{};
  593. transferBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
  594. transferBarrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
  595. transferBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
  596. transferBarrier.srcAccessMask = 0;
  597. transferBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
  598. transferBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
  599. transferBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
  600. transferBarrier.image = *outImage;
  601. transferBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
  602. transferBarrier.subresourceRange.levelCount = 1;
  603. transferBarrier.subresourceRange.layerCount = 1;
  604. vkCmdPipelineBarrier(cmdBuff, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &transferBarrier);
  605. VkBufferImageCopy buffImageCopyRegion{};
  606. buffImageCopyRegion.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
  607. buffImageCopyRegion.imageSubresource.layerCount = 1;
  608. buffImageCopyRegion.imageExtent = { width, height, 1 };
  609. vkCmdCopyBufferToImage(cmdBuff, stagingBuff, *outImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &buffImageCopyRegion);
  610. VkImageMemoryBarrier useBarrier{};
  611. useBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
  612. useBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
  613. useBarrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
  614. useBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
  615. useBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
  616. useBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
  617. useBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
  618. useBarrier.image = *outImage;
  619. useBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
  620. useBarrier.subresourceRange.levelCount = 1;
  621. useBarrier.subresourceRange.layerCount = 1;
  622. vkCmdPipelineBarrier(cmdBuff, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, &useBarrier);
  623. }
  624. endOneTimeSubmitCmd();
  625. vkFreeMemory(m_device, stagingBuffMem, nullptr);
  626. vkDestroyBuffer(m_device, stagingBuff, nullptr);
  627. }
  628. void DeviceResources::createTexture2D(int w, int h, VkFormat format, VkImage* outImage, VkDeviceMemory* outDeviceMemory)
  629. {
  630. auto width = static_cast<uint32_t>(w);
  631. auto height = static_cast<uint32_t>(h);
  632. // Create texture image object and backing memory
  633. {
  634. VkImageCreateInfo info{};
  635. info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
  636. info.imageType = VK_IMAGE_TYPE_2D;
  637. info.extent.width = width;
  638. info.extent.height = height;
  639. info.extent.depth = 1;
  640. info.mipLevels = 1;
  641. info.arrayLayers = 1;
  642. info.format = format;
  643. info.tiling = VK_IMAGE_TILING_OPTIMAL;
  644. info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
  645. info.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT;
  646. info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
  647. info.samples = VK_SAMPLE_COUNT_1_BIT;
  648. VK_OK(vkCreateImage(m_device, &info, nullptr, outImage));
  649. }
  650. {
  651. VkMemoryRequirements memReq{};
  652. vkGetImageMemoryRequirements(m_device, *outImage, &memReq);
  653. VkMemoryAllocateInfo info{};
  654. info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
  655. info.allocationSize = memReq.size;
  656. info.memoryTypeIndex = findMemoryTypeIndex(memReq.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
  657. VK_OK(vkAllocateMemory(m_device, &info, nullptr, outDeviceMemory));
  658. VK_OK(vkBindImageMemory(m_device, *outImage, *outDeviceMemory, 0));
  659. }
  660. }
  661. void DeviceResources::createSRV(VkImage inputImage, VkFormat format, VkImageView* outSrv)
  662. {
  663. VkImageViewCreateInfo info{};
  664. info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
  665. info.image = inputImage;
  666. info.viewType = VK_IMAGE_VIEW_TYPE_2D;
  667. info.format = format;
  668. info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
  669. info.subresourceRange.layerCount = 1;
  670. info.subresourceRange.levelCount = 1;
  671. VK_OK(vkCreateImageView(m_device, &info, nullptr, outSrv));
  672. }