VkSwapchainFactory.cpp 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. // Copyright (C) 2009-present, Panagiotis Christopoulos Charitos and contributors.
  2. // All rights reserved.
  3. // Code licensed under the BSD License.
  4. // http://www.anki3d.org/LICENSE
  5. #include <AnKi/Gr/Vulkan/VkSwapchainFactory.h>
  6. #include <AnKi/Gr/Vulkan/VkGrManager.h>
  7. #include <AnKi/Gr/Vulkan/VkTexture.h>
  8. #include <AnKi/Math/Functions.h>
  9. namespace anki {
  10. MicroSwapchain::MicroSwapchain()
  11. {
  12. if(initInternal())
  13. {
  14. ANKI_VK_LOGF("Error creating the swapchain. Will not try to recover");
  15. }
  16. }
  17. MicroSwapchain::~MicroSwapchain()
  18. {
  19. m_textures.destroy();
  20. if(m_swapchain)
  21. {
  22. vkDestroySwapchainKHR(getVkDevice(), m_swapchain, nullptr);
  23. m_swapchain = {};
  24. }
  25. }
  26. Error MicroSwapchain::initInternal()
  27. {
  28. const VkDevice dev = getVkDevice();
  29. const VkPhysicalDevice pdev = getGrManagerImpl().getPhysicalDevice();
  30. // Get the surface size
  31. VkSurfaceCapabilitiesKHR surfaceProperties;
  32. U32 swapchainImages = 0;
  33. U32 surfaceWidth = 0, surfaceHeight = 0;
  34. {
  35. ANKI_VK_CHECK(
  36. vkGetPhysicalDeviceSurfaceCapabilitiesKHR(getGrManagerImpl().getPhysicalDevice(), getGrManagerImpl().getSurface(), &surfaceProperties));
  37. if(surfaceProperties.currentExtent.width == kMaxU32 && surfaceProperties.currentExtent.height == kMaxU32)
  38. {
  39. // On some platforms this isn't set for some reason (wayland & headless)
  40. getGrManagerImpl().getNativeWindowSize(surfaceWidth, surfaceHeight);
  41. }
  42. else
  43. {
  44. surfaceWidth = surfaceProperties.currentExtent.width;
  45. surfaceHeight = surfaceProperties.currentExtent.height;
  46. }
  47. swapchainImages = max<U32>(surfaceProperties.minImageCount, kMaxFramesInFlight);
  48. }
  49. // Get the surface format
  50. VkFormat surfaceFormat = VK_FORMAT_UNDEFINED;
  51. VkColorSpaceKHR colorspace = VK_COLOR_SPACE_MAX_ENUM_KHR;
  52. {
  53. uint32_t formatCount;
  54. ANKI_VK_CHECK(vkGetPhysicalDeviceSurfaceFormatsKHR(pdev, getGrManagerImpl().getSurface(), &formatCount, nullptr));
  55. GrDynamicArray<VkSurfaceFormatKHR> formats;
  56. formats.resize(formatCount);
  57. ANKI_VK_CHECK(vkGetPhysicalDeviceSurfaceFormatsKHR(pdev, getGrManagerImpl().getSurface(), &formatCount, &formats[0]));
  58. ANKI_VK_LOGV("Supported surface formats:");
  59. Format akSurfaceFormat = Format::kNone;
  60. for(U32 i = 0; i < formatCount; ++i)
  61. {
  62. const VkFormat vkFormat = formats[i].format;
  63. Format akFormat;
  64. switch(formats[i].format)
  65. {
  66. #define ANKI_FORMAT_DEF(type, vk, d3d, componentCount, texelSize, blockWidth, blockHeight, blockSize, shaderType, depthStencil) \
  67. case vk: \
  68. akFormat = Format::k##type; \
  69. break;
  70. #include <AnKi/Gr/BackendCommon/Format.def.h>
  71. #undef ANKI_FORMAT_DEF
  72. default:
  73. akFormat = Format::kNone;
  74. }
  75. ANKI_VK_LOGV("\t%s", (akFormat != Format::kNone) ? getFormatInfo(akFormat).m_name : "Unknown format");
  76. if(surfaceFormat == VK_FORMAT_UNDEFINED
  77. && (vkFormat == VK_FORMAT_R8G8B8A8_UNORM || vkFormat == VK_FORMAT_B8G8R8A8_UNORM || vkFormat == VK_FORMAT_A8B8G8R8_UNORM_PACK32))
  78. {
  79. surfaceFormat = vkFormat;
  80. colorspace = formats[i].colorSpace;
  81. akSurfaceFormat = akFormat;
  82. }
  83. }
  84. if(surfaceFormat == VK_FORMAT_UNDEFINED)
  85. {
  86. ANKI_VK_LOGE("Suitable surface format not found");
  87. return Error::kFunctionFailed;
  88. }
  89. else
  90. {
  91. ANKI_VK_LOGV("Selecting surface format %s", getFormatInfo(akSurfaceFormat).m_name);
  92. }
  93. }
  94. // Chose present mode
  95. VkPresentModeKHR presentMode = VK_PRESENT_MODE_MAX_ENUM_KHR;
  96. VkPresentModeKHR presentModeSecondChoice = VK_PRESENT_MODE_MAX_ENUM_KHR;
  97. {
  98. uint32_t presentModeCount;
  99. vkGetPhysicalDeviceSurfacePresentModesKHR(pdev, getGrManagerImpl().getSurface(), &presentModeCount, nullptr);
  100. presentModeCount = min(presentModeCount, 4u);
  101. Array<VkPresentModeKHR, 4> presentModes;
  102. vkGetPhysicalDeviceSurfacePresentModesKHR(pdev, getGrManagerImpl().getSurface(), &presentModeCount, &presentModes[0]);
  103. if(SwapchainFactory::getSingleton().m_vsync)
  104. {
  105. for(U i = 0; i < presentModeCount; ++i)
  106. {
  107. if(presentModes[i] == VK_PRESENT_MODE_FIFO_RELAXED_KHR)
  108. {
  109. presentMode = presentModes[i];
  110. }
  111. else if(presentModes[i] == VK_PRESENT_MODE_FIFO_KHR)
  112. {
  113. presentModeSecondChoice = presentModes[i];
  114. }
  115. }
  116. }
  117. else
  118. {
  119. for(U i = 0; i < presentModeCount; ++i)
  120. {
  121. if(presentModes[i] == VK_PRESENT_MODE_IMMEDIATE_KHR)
  122. {
  123. presentMode = presentModes[i];
  124. }
  125. else if(presentModes[i] == VK_PRESENT_MODE_MAILBOX_KHR)
  126. {
  127. presentModeSecondChoice = presentModes[i];
  128. }
  129. }
  130. }
  131. presentMode = (presentMode != VK_PRESENT_MODE_MAX_ENUM_KHR) ? presentMode : presentModeSecondChoice;
  132. if(presentMode == VK_PRESENT_MODE_MAX_ENUM_KHR)
  133. {
  134. ANKI_VK_LOGE("Couldn't find a present mode");
  135. return Error::kFunctionFailed;
  136. }
  137. }
  138. // Create swapchain
  139. {
  140. VkCompositeAlphaFlagBitsKHR compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
  141. if(surfaceProperties.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR)
  142. {
  143. compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
  144. }
  145. else if(surfaceProperties.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR)
  146. {
  147. compositeAlpha = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR;
  148. }
  149. else if(surfaceProperties.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR)
  150. {
  151. compositeAlpha = VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR;
  152. }
  153. else if(surfaceProperties.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR)
  154. {
  155. compositeAlpha = VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR;
  156. }
  157. else
  158. {
  159. ANKI_VK_LOGE("Failed to set compositeAlpha");
  160. return Error::kFunctionFailed;
  161. }
  162. VkSwapchainCreateInfoKHR ci = {};
  163. ci.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
  164. ci.surface = getGrManagerImpl().getSurface();
  165. ci.minImageCount = swapchainImages;
  166. ci.imageFormat = surfaceFormat;
  167. ci.imageColorSpace = colorspace;
  168. ci.imageExtent.width = surfaceWidth;
  169. ci.imageExtent.height = surfaceHeight;
  170. ci.imageArrayLayers = 1;
  171. ci.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_STORAGE_BIT;
  172. ci.queueFamilyIndexCount = getGrManagerImpl().getQueueFamilies().getSize();
  173. ci.pQueueFamilyIndices = &getGrManagerImpl().getQueueFamilies()[0];
  174. ci.imageSharingMode = (ci.queueFamilyIndexCount > 1) ? VK_SHARING_MODE_CONCURRENT : VK_SHARING_MODE_EXCLUSIVE;
  175. ci.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
  176. ci.compositeAlpha = compositeAlpha;
  177. ci.presentMode = presentMode;
  178. ci.clipped = false;
  179. ci.oldSwapchain = VK_NULL_HANDLE;
  180. ANKI_VK_CHECK(vkCreateSwapchainKHR(dev, &ci, nullptr, &m_swapchain));
  181. }
  182. // Get images
  183. {
  184. U32 count = 0;
  185. ANKI_VK_CHECK(vkGetSwapchainImagesKHR(dev, m_swapchain, &count, nullptr));
  186. if(count != swapchainImages)
  187. {
  188. ANKI_VK_LOGI("Requested a swapchain with %u images but got one with %u", swapchainImages, count);
  189. }
  190. m_textures.resize(count);
  191. m_acquireSemaphores.resize(count);
  192. m_renderSemaphores.resize(count);
  193. ANKI_VK_LOGI("Created a swapchain. Image count: %u, present mode: %u, size: %ux%u, vsync: %u", count, presentMode, surfaceWidth,
  194. surfaceHeight, U32(SwapchainFactory::getSingleton().m_vsync));
  195. Array<VkImage, 64> images;
  196. ANKI_ASSERT(count <= 64);
  197. ANKI_VK_CHECK(vkGetSwapchainImagesKHR(dev, m_swapchain, &count, &images[0]));
  198. for(U32 i = 0; i < count; ++i)
  199. {
  200. TextureInitInfo init(GrString().sprintf("SwapchainImage #%u", i));
  201. init.m_width = surfaceWidth;
  202. init.m_height = surfaceHeight;
  203. init.m_format = Format(surfaceFormat); // anki::Format is compatible with VkFormat
  204. init.m_usage = TextureUsageBit::kUavCompute | TextureUsageBit::kUavDispatchRays | TextureUsageBit::kRtvDsvRead
  205. | TextureUsageBit::kRtvDsvWrite | TextureUsageBit::kPresent;
  206. init.m_type = TextureType::k2D;
  207. TextureImpl* tex = newInstance<TextureImpl>(GrMemoryPool::getSingleton(), init.getName());
  208. m_textures[i].reset(tex);
  209. ANKI_CHECK(tex->initExternal(images[i], init));
  210. m_acquireSemaphores[i] = SemaphoreFactory::getSingleton().newInstance(false, GrString().sprintf("Acquire #%u", i));
  211. m_renderSemaphores[i] = SemaphoreFactory::getSingleton().newInstance(false, GrString().sprintf("Present #%u", i));
  212. }
  213. }
  214. return Error::kNone;
  215. }
  216. void MicroSwapchain::releaseInternal()
  217. {
  218. SwapchainFactory::getSingleton().m_recycler.recycle(this);
  219. }
  220. MicroSwapchainPtr SwapchainFactory::newInstance()
  221. {
  222. // Delete stale swapchains (they are stale because they are probably out of data) and always create a new one
  223. m_recycler.trimCache();
  224. // This is useless but call it to avoid assertions
  225. [[maybe_unused]] MicroSwapchain* dummy = m_recycler.findToReuse();
  226. ANKI_ASSERT(dummy == nullptr);
  227. return MicroSwapchainPtr(anki::newInstance<MicroSwapchain>(GrMemoryPool::getSingleton()));
  228. }
  229. } // end namespace anki