BsVulkanSwapChain.cpp 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  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 "Managers/BsVulkanCommandBufferManager.h"
  8. namespace bs { namespace ct
  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.format = colorFormat;
  112. imageDesc.type = TEX_TYPE_2D;
  113. imageDesc.usage = TU_RENDERTARGET;
  114. imageDesc.layout = VK_IMAGE_LAYOUT_UNDEFINED;
  115. imageDesc.numFaces = 1;
  116. imageDesc.numMipLevels = 1;
  117. imageDesc.memory = VK_NULL_HANDLE;
  118. mSurfaces.resize(numImages);
  119. for (UINT32 i = 0; i < numImages; i++)
  120. {
  121. imageDesc.image = images[i];
  122. mSurfaces[i].acquired = false;
  123. mSurfaces[i].needsWait = false;
  124. mSurfaces[i].image = resManager.create<VulkanImage>(imageDesc, false);
  125. mSurfaces[i].sync = resManager.create<VulkanSemaphore>();
  126. }
  127. bs_stack_free(images);
  128. // Create depth stencil image
  129. if (createDepth)
  130. {
  131. VkImageCreateInfo depthStencilImageCI;
  132. depthStencilImageCI.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
  133. depthStencilImageCI.pNext = nullptr;
  134. depthStencilImageCI.flags = 0;
  135. depthStencilImageCI.imageType = VK_IMAGE_TYPE_2D;
  136. depthStencilImageCI.format = depthFormat;
  137. depthStencilImageCI.extent = { width, height, 1 };
  138. depthStencilImageCI.mipLevels = 1;
  139. depthStencilImageCI.arrayLayers = 1;
  140. depthStencilImageCI.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
  141. depthStencilImageCI.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
  142. depthStencilImageCI.samples = VK_SAMPLE_COUNT_1_BIT;
  143. depthStencilImageCI.tiling = VK_IMAGE_TILING_OPTIMAL;
  144. depthStencilImageCI.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
  145. depthStencilImageCI.pQueueFamilyIndices = nullptr;
  146. depthStencilImageCI.queueFamilyIndexCount = 0;
  147. VkImage depthStencilImage;
  148. result = vkCreateImage(logicalDevice, &depthStencilImageCI, gVulkanAllocator, &depthStencilImage);
  149. assert(result == VK_SUCCESS);
  150. imageDesc.image = depthStencilImage;
  151. imageDesc.usage = TU_DEPTHSTENCIL;
  152. imageDesc.format = depthFormat;
  153. imageDesc.memory = mDevice->allocateMemory(depthStencilImage, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
  154. mDepthStencilImage = resManager.create<VulkanImage>(imageDesc, true);
  155. }
  156. else
  157. mDepthStencilImage = nullptr;
  158. // Create a framebuffer for each swap chain buffer
  159. UINT32 numFramebuffers = (UINT32)mSurfaces.size();
  160. for (UINT32 i = 0; i < numFramebuffers; i++)
  161. {
  162. VULKAN_FRAMEBUFFER_DESC& desc = mSurfaces[i].framebufferDesc;
  163. desc.width = getWidth();
  164. desc.height = getHeight();
  165. desc.layers = 1;
  166. desc.numSamples = 1;
  167. desc.offscreen = false;
  168. desc.color[0].format = colorFormat;
  169. desc.color[0].image = mSurfaces[i].image;
  170. desc.color[0].surface = TextureSurface::COMPLETE;
  171. desc.color[0].baseLayer = 0;
  172. desc.depth.format = depthFormat;
  173. desc.depth.image = mDepthStencilImage;
  174. desc.depth.surface = TextureSurface::COMPLETE;
  175. desc.depth.baseLayer = 0;
  176. mSurfaces[i].framebuffer = resManager.create<VulkanFramebuffer>(desc);
  177. }
  178. }
  179. void VulkanSwapChain::acquireBackBuffer()
  180. {
  181. uint32_t imageIndex;
  182. VkResult result = vkAcquireNextImageKHR(mDevice->getLogical(), mSwapChain, UINT64_MAX,
  183. mSurfaces[mCurrentSemaphoreIdx].sync->getHandle(), VK_NULL_HANDLE, &imageIndex);
  184. assert(result == VK_SUCCESS || result == VK_SUBOPTIMAL_KHR);
  185. // In case surfaces aren't being distributed in round-robin fashion the image and semaphore indices might not match,
  186. // in which case just move the semaphores
  187. if(imageIndex != mCurrentSemaphoreIdx)
  188. std::swap(mSurfaces[mCurrentSemaphoreIdx].sync, mSurfaces[imageIndex].sync);
  189. mCurrentSemaphoreIdx = (mCurrentSemaphoreIdx + 1) % mSurfaces.size();
  190. assert(!mSurfaces[imageIndex].acquired && "Same swap chain surface being acquired twice in a row without present().");
  191. mSurfaces[imageIndex].acquired = true;
  192. mSurfaces[imageIndex].needsWait = true;
  193. mCurrentBackBufferIdx = imageIndex;
  194. }
  195. bool VulkanSwapChain::prepareForPresent(UINT32& backBufferIdx)
  196. {
  197. if (!mSurfaces[mCurrentBackBufferIdx].acquired)
  198. return false;
  199. assert(mSurfaces[mCurrentBackBufferIdx].acquired && "Attempting to present an unacquired back buffer.");
  200. mSurfaces[mCurrentBackBufferIdx].acquired = false;
  201. backBufferIdx = mCurrentBackBufferIdx;
  202. return true;
  203. }
  204. void VulkanSwapChain::notifyBackBufferWaitIssued()
  205. {
  206. if (!mSurfaces[mCurrentBackBufferIdx].acquired)
  207. return;
  208. mSurfaces[mCurrentBackBufferIdx].needsWait = false;
  209. }
  210. void VulkanSwapChain::clear(VkSwapchainKHR swapChain)
  211. {
  212. VkDevice logicalDevice = mDevice->getLogical();
  213. if (swapChain != VK_NULL_HANDLE)
  214. {
  215. for (auto& surface : mSurfaces)
  216. {
  217. surface.framebuffer->destroy();
  218. surface.framebuffer = nullptr;
  219. surface.image->destroy();
  220. surface.image = nullptr;
  221. surface.sync->destroy();
  222. surface.sync = nullptr;
  223. }
  224. vkDestroySwapchainKHR(logicalDevice, swapChain, gVulkanAllocator);
  225. }
  226. if (mDepthStencilImage != nullptr)
  227. {
  228. mDepthStencilImage->destroy();
  229. mDepthStencilImage = nullptr;
  230. }
  231. }
  232. }}