BsVulkanSwapChain.cpp 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
  2. //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
  3. #include "BsVulkanSwapChain.h"
  4. #include "BsVulkanTexture.h"
  5. #include "BsVulkanRenderAPI.h"
  6. #include "BsVulkanDevice.h"
  7. #include "BsVulkanCommandBufferManager.h"
  8. namespace bs
  9. {
  10. VulkanSwapChain::~VulkanSwapChain()
  11. {
  12. clear(mSwapChain);
  13. }
  14. void VulkanSwapChain::rebuild(const SPtr<VulkanDevice>& device, VkSurfaceKHR surface, UINT32 width, UINT32 height,
  15. bool vsync, VkFormat colorFormat, VkColorSpaceKHR colorSpace, bool createDepth, VkFormat depthFormat)
  16. {
  17. mDevice = device;
  18. VkResult result;
  19. VkPhysicalDevice physicalDevice = device->getPhysical();
  20. // Determine swap chain dimensions
  21. VkSurfaceCapabilitiesKHR surfaceCaps;
  22. result = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, surface, &surfaceCaps);
  23. assert(result == VK_SUCCESS);
  24. VkExtent2D swapchainExtent;
  25. // If width/height is 0xFFFFFFFF, we can manually specify width, height
  26. if (surfaceCaps.currentExtent.width == (uint32_t)-1 || surfaceCaps.currentExtent.height == (uint32_t)-1)
  27. {
  28. swapchainExtent.width = width;
  29. swapchainExtent.height = height;
  30. }
  31. else // Otherwise we must use the size we're given
  32. swapchainExtent = surfaceCaps.currentExtent;
  33. mWidth = swapchainExtent.width;
  34. mHeight = swapchainExtent.height;
  35. // Find present mode
  36. uint32_t numPresentModes;
  37. result = vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, &numPresentModes, nullptr);
  38. assert(result == VK_SUCCESS);
  39. assert(numPresentModes > 0);
  40. VkPresentModeKHR* presentModes = bs_stack_alloc<VkPresentModeKHR>(numPresentModes);
  41. result = vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, &numPresentModes, presentModes);
  42. assert(result == VK_SUCCESS);
  43. VkPresentModeKHR presentMode = VK_PRESENT_MODE_FIFO_KHR;
  44. if(!vsync)
  45. {
  46. for (UINT32 i = 0; i < numPresentModes; i++)
  47. {
  48. if (presentModes[i] == VK_PRESENT_MODE_IMMEDIATE_KHR)
  49. {
  50. presentMode = VK_PRESENT_MODE_IMMEDIATE_KHR;
  51. break;
  52. }
  53. if (presentModes[i] == VK_PRESENT_MODE_FIFO_RELAXED_KHR)
  54. presentMode = VK_PRESENT_MODE_FIFO_RELAXED_KHR;
  55. }
  56. }
  57. else
  58. {
  59. // Mailbox comes with lower input latency than FIFO, but can waste GPU power by rendering frames that are never
  60. // displayed, especially if the app runs much faster than the refresh rate. This is a concern for mobiles.
  61. #if BS_PLATFORM != BS_PLATFORM_ANDROID && BS_PLATFORM != BS_PLATFORM_IOS
  62. for (UINT32 i = 0; i < numPresentModes; i++)
  63. {
  64. if (presentModes[i] == VK_PRESENT_MODE_MAILBOX_KHR)
  65. {
  66. presentMode = VK_PRESENT_MODE_MAILBOX_KHR;
  67. break;
  68. }
  69. }
  70. #endif
  71. }
  72. bs_stack_free(presentModes);
  73. uint32_t numImages = surfaceCaps.minImageCount;
  74. VkSurfaceTransformFlagsKHR transform;
  75. if (surfaceCaps.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR)
  76. transform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
  77. else
  78. transform = surfaceCaps.currentTransform;
  79. VkSwapchainCreateInfoKHR swapChainCI;
  80. swapChainCI.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
  81. swapChainCI.pNext = nullptr;
  82. swapChainCI.flags = 0;
  83. swapChainCI.surface = surface;
  84. swapChainCI.minImageCount = numImages;
  85. swapChainCI.imageFormat = colorFormat;
  86. swapChainCI.imageColorSpace = colorSpace;
  87. swapChainCI.imageExtent = { swapchainExtent.width, swapchainExtent.height };
  88. swapChainCI.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
  89. swapChainCI.preTransform = (VkSurfaceTransformFlagBitsKHR)transform;
  90. swapChainCI.imageArrayLayers = 1;
  91. swapChainCI.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
  92. swapChainCI.queueFamilyIndexCount = 0;
  93. swapChainCI.pQueueFamilyIndices = NULL;
  94. swapChainCI.presentMode = presentMode;
  95. swapChainCI.oldSwapchain = mSwapChain;
  96. swapChainCI.clipped = VK_TRUE;
  97. swapChainCI.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
  98. VkSwapchainKHR oldSwapChain = mSwapChain;
  99. VkDevice logicalDevice = device->getLogical();
  100. result = vkCreateSwapchainKHR(logicalDevice, &swapChainCI, gVulkanAllocator, &mSwapChain);
  101. assert(result == VK_SUCCESS);
  102. clear(oldSwapChain);
  103. result = vkGetSwapchainImagesKHR(logicalDevice, mSwapChain, &numImages, nullptr);
  104. assert(result == VK_SUCCESS);
  105. // Get the swap chain images
  106. VkImage* images = bs_stack_alloc<VkImage>(numImages);
  107. result = vkGetSwapchainImagesKHR(logicalDevice, mSwapChain, &numImages, images);
  108. assert(result == VK_SUCCESS);
  109. VulkanResourceManager& resManager = device->getResourceManager();
  110. VULKAN_IMAGE_DESC imageDesc;
  111. imageDesc.isDepthStencil = false;
  112. imageDesc.isStorage = false;
  113. imageDesc.format = colorFormat;
  114. imageDesc.type = TEX_TYPE_2D;
  115. imageDesc.layout = VK_IMAGE_LAYOUT_UNDEFINED;
  116. imageDesc.numFaces = 1;
  117. imageDesc.numMipLevels = 1;
  118. imageDesc.memory = VK_NULL_HANDLE;
  119. mSurfaces.resize(numImages);
  120. for (UINT32 i = 0; i < numImages; i++)
  121. {
  122. imageDesc.image = images[i];
  123. mSurfaces[i].acquired = false;
  124. mSurfaces[i].image = resManager.create<VulkanImage>(imageDesc, false);
  125. mSurfaces[i].view = mSurfaces[i].image->getView(true);
  126. mSurfaces[i].sync = resManager.create<VulkanSemaphore>();
  127. }
  128. bs_stack_free(images);
  129. // Create depth stencil image
  130. if (createDepth)
  131. {
  132. VkImageCreateInfo depthStencilImageCI;
  133. depthStencilImageCI.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
  134. depthStencilImageCI.pNext = nullptr;
  135. depthStencilImageCI.flags = 0;
  136. depthStencilImageCI.imageType = VK_IMAGE_TYPE_2D;
  137. depthStencilImageCI.format = depthFormat;
  138. depthStencilImageCI.extent = { width, height, 1 };
  139. depthStencilImageCI.mipLevels = 1;
  140. depthStencilImageCI.arrayLayers = 1;
  141. depthStencilImageCI.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
  142. depthStencilImageCI.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
  143. depthStencilImageCI.samples = VK_SAMPLE_COUNT_1_BIT;
  144. depthStencilImageCI.tiling = VK_IMAGE_TILING_OPTIMAL;
  145. depthStencilImageCI.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
  146. depthStencilImageCI.pQueueFamilyIndices = nullptr;
  147. depthStencilImageCI.queueFamilyIndexCount = 0;
  148. VkImage depthStencilImage;
  149. result = vkCreateImage(logicalDevice, &depthStencilImageCI, gVulkanAllocator, &depthStencilImage);
  150. assert(result == VK_SUCCESS);
  151. imageDesc.image = depthStencilImage;
  152. imageDesc.isDepthStencil = true;
  153. imageDesc.format = depthFormat;
  154. imageDesc.memory = mDevice->allocateMemory(depthStencilImage, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
  155. mDepthStencilImage = resManager.create<VulkanImage>(imageDesc, true);
  156. mDepthStencilView = mDepthStencilImage->getView(true);
  157. }
  158. else
  159. {
  160. mDepthStencilImage = nullptr;
  161. mDepthStencilView = VK_NULL_HANDLE;
  162. }
  163. // Create a framebuffer for each swap chain buffer
  164. UINT32 numFramebuffers = (UINT32)mSurfaces.size();
  165. for (UINT32 i = 0; i < numFramebuffers; i++)
  166. {
  167. VULKAN_FRAMEBUFFER_DESC& desc = mSurfaces[i].framebufferDesc;
  168. desc.width = getWidth();
  169. desc.height = getHeight();
  170. desc.layers = 1;
  171. desc.numSamples = 1;
  172. desc.offscreen = false;
  173. desc.color[0].format = colorFormat;
  174. desc.color[0].image = mSurfaces[i].image;
  175. desc.color[0].view = mSurfaces[i].view;
  176. desc.color[0].baseLayer = 0;
  177. desc.depth.format = depthFormat;
  178. desc.depth.image = mDepthStencilImage;
  179. desc.depth.view = mDepthStencilView;
  180. desc.depth.baseLayer = 0;
  181. mSurfaces[i].framebuffer = resManager.create<VulkanFramebuffer>(desc);
  182. }
  183. }
  184. void VulkanSwapChain::acquireBackBuffer()
  185. {
  186. uint32_t imageIndex;
  187. VkResult result = vkAcquireNextImageKHR(mDevice->getLogical(), mSwapChain, UINT64_MAX,
  188. mSurfaces[mCurrentSemaphoreIdx].sync->getHandle(), VK_NULL_HANDLE, &imageIndex);
  189. assert(result == VK_SUCCESS || result == VK_SUBOPTIMAL_KHR);
  190. // In case surfaces aren't being distributed in round-robin fashion the image and semaphore indices might not match,
  191. // in which case just move the semaphores
  192. if(imageIndex != mCurrentSemaphoreIdx)
  193. std::swap(mSurfaces[mCurrentSemaphoreIdx].sync, mSurfaces[imageIndex].sync);
  194. mCurrentSemaphoreIdx = (mCurrentSemaphoreIdx + 1) % mSurfaces.size();
  195. assert(!mSurfaces[imageIndex].acquired && "Same swap chain surface being acquired twice in a row without present().");
  196. mSurfaces[imageIndex].acquired = true;
  197. mCurrentBackBufferIdx = imageIndex;
  198. }
  199. bool VulkanSwapChain::prepareForPresent(UINT32& backBufferIdx)
  200. {
  201. if (!mSurfaces[mCurrentBackBufferIdx].acquired)
  202. return false;
  203. assert(mSurfaces[mCurrentBackBufferIdx].acquired && "Attempting to present an unacquired back buffer.");
  204. mSurfaces[mCurrentBackBufferIdx].acquired = false;
  205. backBufferIdx = mCurrentBackBufferIdx;
  206. return true;
  207. }
  208. void VulkanSwapChain::clear(VkSwapchainKHR swapChain)
  209. {
  210. VkDevice logicalDevice = mDevice->getLogical();
  211. if (swapChain != VK_NULL_HANDLE)
  212. {
  213. for (auto& surface : mSurfaces)
  214. {
  215. surface.framebuffer->destroy();
  216. surface.framebuffer = nullptr;
  217. surface.image->destroy();
  218. surface.image = nullptr;
  219. surface.sync->destroy();
  220. surface.sync = nullptr;
  221. }
  222. vkDestroySwapchainKHR(logicalDevice, swapChain, gVulkanAllocator);
  223. }
  224. if (mDepthStencilImage != nullptr)
  225. {
  226. mDepthStencilImage->destroy();
  227. mDepthStencilImage = nullptr;
  228. }
  229. }
  230. }