BsVulkanSwapChain.cpp 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
  2. //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
  3. #include "BsVulkanSwapChain.h"
  4. #include "BsVulkanRenderAPI.h"
  5. #include "BsVulkanDevice.h"
  6. namespace BansheeEngine
  7. {
  8. VulkanSwapChain::~VulkanSwapChain()
  9. {
  10. if (mSwapChain != VK_NULL_HANDLE)
  11. {
  12. VkDevice logicalDevice = mDevice->getLogical();
  13. for (auto& surface : mSurfaces)
  14. {
  15. vkDestroySemaphore(logicalDevice, surface.sync, gVulkanAllocator);
  16. vkDestroyImageView(logicalDevice, surface.view, gVulkanAllocator);
  17. }
  18. vkDestroySwapchainKHR(logicalDevice, mSwapChain, gVulkanAllocator);
  19. }
  20. }
  21. void VulkanSwapChain::rebuild(const SPtr<VulkanDevice>& device, VkSurfaceKHR surface, UINT32 width, UINT32 height, bool vsync,
  22. VkFormat colorFormat, VkColorSpaceKHR colorSpace)
  23. {
  24. mDevice = device;
  25. VkResult result;
  26. VkPhysicalDevice physicalDevice = device->getPhysical();
  27. // Determine swap chain dimensions
  28. VkSurfaceCapabilitiesKHR surfaceCaps;
  29. result = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, surface, &surfaceCaps);
  30. assert(result == VK_SUCCESS);
  31. VkExtent2D swapchainExtent;
  32. // If width/height is 0xFFFFFFFF, we can manually specify width, height
  33. if (surfaceCaps.currentExtent.width == (uint32_t)-1 || surfaceCaps.currentExtent.height == (uint32_t)-1)
  34. {
  35. swapchainExtent.width = width;
  36. swapchainExtent.height = height;
  37. }
  38. else // Otherwise we must use the size we're given
  39. swapchainExtent = surfaceCaps.currentExtent;
  40. mWidth = swapchainExtent.width;
  41. mHeight = swapchainExtent.height;
  42. // Find present mode
  43. uint32_t numPresentModes;
  44. result = vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, &numPresentModes, nullptr);
  45. assert(result == VK_SUCCESS);
  46. assert(numPresentModes > 0);
  47. VkPresentModeKHR* presentModes = bs_stack_alloc<VkPresentModeKHR>(numPresentModes);
  48. result = vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, &numPresentModes, presentModes);
  49. assert(result == VK_SUCCESS);
  50. VkPresentModeKHR presentMode = VK_PRESENT_MODE_FIFO_KHR;
  51. if(!vsync)
  52. {
  53. for (UINT32 i = 0; i < numPresentModes; i++)
  54. {
  55. if (presentModes[i] == VK_PRESENT_MODE_IMMEDIATE_KHR)
  56. {
  57. presentMode = VK_PRESENT_MODE_IMMEDIATE_KHR;
  58. break;
  59. }
  60. if (presentMode == VK_PRESENT_MODE_FIFO_RELAXED_KHR)
  61. presentMode = VK_PRESENT_MODE_FIFO_RELAXED_KHR;
  62. }
  63. }
  64. else
  65. {
  66. for (UINT32 i = 0; i < numPresentModes; i++)
  67. {
  68. if (presentModes[i] == VK_PRESENT_MODE_MAILBOX_KHR)
  69. {
  70. presentMode = VK_PRESENT_MODE_MAILBOX_KHR;
  71. break;
  72. }
  73. }
  74. }
  75. bs_stack_free(presentModes);
  76. uint32_t numImages = std::min(surfaceCaps.minImageCount + BS_NUM_BACK_BUFFERS, surfaceCaps.maxImageCount);
  77. VkSurfaceTransformFlagsKHR transform;
  78. if (surfaceCaps.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR)
  79. transform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
  80. else
  81. transform = surfaceCaps.currentTransform;
  82. VkSwapchainCreateInfoKHR swapChainCI;
  83. swapChainCI.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
  84. swapChainCI.pNext = nullptr;
  85. swapChainCI.flags = 0;
  86. swapChainCI.surface = surface;
  87. swapChainCI.minImageCount = numImages;
  88. swapChainCI.imageFormat = colorFormat;
  89. swapChainCI.imageColorSpace = colorSpace;
  90. swapChainCI.imageExtent = { swapchainExtent.width, swapchainExtent.height };
  91. swapChainCI.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
  92. swapChainCI.preTransform = (VkSurfaceTransformFlagBitsKHR)transform;
  93. swapChainCI.imageArrayLayers = 1;
  94. swapChainCI.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
  95. swapChainCI.queueFamilyIndexCount = 0;
  96. swapChainCI.pQueueFamilyIndices = NULL;
  97. swapChainCI.presentMode = presentMode;
  98. swapChainCI.oldSwapchain = mSwapChain;
  99. swapChainCI.clipped = VK_TRUE;
  100. swapChainCI.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
  101. VkSwapchainKHR oldSwapChain = mSwapChain;
  102. VkDevice logicalDevice = device->getLogical();
  103. result = vkCreateSwapchainKHR(logicalDevice, &swapChainCI, gVulkanAllocator, &mSwapChain);
  104. assert(result == VK_SUCCESS);
  105. if (oldSwapChain != VK_NULL_HANDLE)
  106. {
  107. for(auto& entry : mSurfaces)
  108. vkDestroyImageView(logicalDevice, entry.view, gVulkanAllocator);
  109. vkDestroySwapchainKHR(logicalDevice, oldSwapChain, gVulkanAllocator);
  110. }
  111. result = vkGetSwapchainImagesKHR(logicalDevice, mSwapChain, &numImages, nullptr);
  112. assert(result == VK_SUCCESS);
  113. // Get the swap chain images
  114. VkImage* images = bs_stack_alloc<VkImage>(numImages);
  115. result = vkGetSwapchainImagesKHR(logicalDevice, mSwapChain, &numImages, images);
  116. assert(result == VK_SUCCESS);
  117. mSurfaces.resize(numImages);
  118. for (UINT32 i = 0; i < numImages; i++)
  119. {
  120. VkImageViewCreateInfo colorViewCI;
  121. colorViewCI.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
  122. colorViewCI.pNext = nullptr;
  123. colorViewCI.flags = 0;
  124. colorViewCI.format = colorFormat;
  125. colorViewCI.components = {
  126. VK_COMPONENT_SWIZZLE_R,
  127. VK_COMPONENT_SWIZZLE_G,
  128. VK_COMPONENT_SWIZZLE_B,
  129. VK_COMPONENT_SWIZZLE_A
  130. };
  131. colorViewCI.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
  132. colorViewCI.subresourceRange.baseMipLevel = 0;
  133. colorViewCI.subresourceRange.levelCount = 1;
  134. colorViewCI.subresourceRange.baseArrayLayer = 0;
  135. colorViewCI.subresourceRange.layerCount = 1;
  136. colorViewCI.viewType = VK_IMAGE_VIEW_TYPE_2D;
  137. colorViewCI.image = images[i];
  138. mSurfaces[i].acquired = false;
  139. mSurfaces[i].image = images[i];
  140. result = vkCreateImageView(logicalDevice, &colorViewCI, gVulkanAllocator, &mSurfaces[i].view);
  141. assert(result == VK_SUCCESS);
  142. VkSemaphoreCreateInfo semaphoreCI;
  143. semaphoreCI.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
  144. semaphoreCI.pNext = nullptr;
  145. semaphoreCI.flags = 0;
  146. result = vkCreateSemaphore(logicalDevice, &semaphoreCI, gVulkanAllocator, &mSurfaces[i].sync);
  147. assert(result == VK_SUCCESS);
  148. }
  149. bs_stack_free(images);
  150. }
  151. void VulkanSwapChain::present(VkQueue queue, VkSemaphore semaphore)
  152. {
  153. assert(mSurfaces[mCurrentBackBufferIdx].acquired && "Attempting to present an unacquired back buffer.");
  154. mSurfaces[mCurrentBackBufferIdx].acquired = false;
  155. VkPresentInfoKHR presentInfo;
  156. presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
  157. presentInfo.pNext = nullptr;
  158. presentInfo.swapchainCount = 1;
  159. presentInfo.pSwapchains = &mSwapChain;
  160. presentInfo.pImageIndices = &mCurrentBackBufferIdx;
  161. presentInfo.pResults = nullptr;
  162. // Wait before presenting, if required
  163. if (semaphore != VK_NULL_HANDLE)
  164. {
  165. presentInfo.pWaitSemaphores = &semaphore;
  166. presentInfo.waitSemaphoreCount = 1;
  167. }
  168. else
  169. {
  170. presentInfo.pWaitSemaphores = nullptr;
  171. presentInfo.waitSemaphoreCount = 0;
  172. }
  173. VkResult result = vkQueuePresentKHR(queue, &presentInfo);
  174. assert(result == VK_SUCCESS || result == VK_SUBOPTIMAL_KHR);
  175. }
  176. SwapChainSurface VulkanSwapChain::acquireBackBuffer()
  177. {
  178. uint32_t imageIndex;
  179. VkResult result = vkAcquireNextImageKHR(mDevice->getLogical(), mSwapChain, UINT64_MAX,
  180. mSurfaces[mCurrentSemaphoreIdx].sync, VK_NULL_HANDLE, &imageIndex);
  181. assert(result == VK_SUCCESS || result == VK_SUBOPTIMAL_KHR);
  182. // In case surfaces aren't being distributed in round-robin fashion the image and semaphore indices might not match,
  183. // in which case just move the semaphores
  184. if(imageIndex != mCurrentSemaphoreIdx)
  185. std::swap(mSurfaces[mCurrentSemaphoreIdx].sync, mSurfaces[imageIndex].sync);
  186. mCurrentSemaphoreIdx = (mCurrentSemaphoreIdx + 1) % mSurfaces.size();
  187. assert(!mSurfaces[imageIndex].acquired && "Same swap chain surface being acquired twice in a row without present().");
  188. mSurfaces[imageIndex].acquired = true;
  189. mCurrentBackBufferIdx = imageIndex;
  190. return mSurfaces[imageIndex];
  191. }
  192. }