SwapchainFactory.cpp 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. // Copyright (C) 2009-2022, 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/SwapchainFactory.h>
  6. #include <AnKi/Gr/Vulkan/GrManagerImpl.h>
  7. namespace anki {
  8. MicroSwapchain::MicroSwapchain(SwapchainFactory* factory)
  9. : m_factory(factory)
  10. {
  11. ANKI_ASSERT(factory);
  12. if(initInternal())
  13. {
  14. ANKI_VK_LOGF("Error creating the swapchain. Will not try to recover");
  15. }
  16. }
  17. MicroSwapchain::~MicroSwapchain()
  18. {
  19. const VkDevice dev = m_factory->m_gr->getDevice();
  20. m_textures.destroy(getAllocator());
  21. if(m_swapchain)
  22. {
  23. vkDestroySwapchainKHR(dev, m_swapchain, nullptr);
  24. m_swapchain = {};
  25. }
  26. }
  27. Error MicroSwapchain::initInternal()
  28. {
  29. const VkDevice dev = m_factory->m_gr->getDevice();
  30. // Get the surface size
  31. VkSurfaceCapabilitiesKHR surfaceProperties;
  32. U32 surfaceWidth = 0, surfaceHeight = 0;
  33. {
  34. ANKI_VK_CHECK(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(m_factory->m_gr->getPhysicalDevice(),
  35. m_factory->m_gr->getSurface(), &surfaceProperties));
  36. #if ANKI_WINDOWING_SYSTEM_HEADLESS
  37. if(surfaceProperties.currentExtent.width != MAX_U32 || surfaceProperties.currentExtent.height != MAX_U32)
  38. {
  39. ANKI_VK_LOGE("Was expecting an indication that the surface size will be determined by the extent of a "
  40. "swapchain targeting the surface");
  41. return Error::FUNCTION_FAILED;
  42. }
  43. m_factory->m_gr->getNativeWindowSize(surfaceWidth, surfaceHeight);
  44. #else
  45. if(surfaceProperties.currentExtent.width == MAX_U32 || surfaceProperties.currentExtent.height == MAX_U32)
  46. {
  47. ANKI_VK_LOGE("Wrong surface size");
  48. return Error::FUNCTION_FAILED;
  49. }
  50. surfaceWidth = surfaceProperties.currentExtent.width;
  51. surfaceHeight = surfaceProperties.currentExtent.height;
  52. #endif
  53. }
  54. // Get the surface format
  55. VkFormat surfaceFormat = VK_FORMAT_UNDEFINED;
  56. VkColorSpaceKHR colorspace = VK_COLOR_SPACE_MAX_ENUM_KHR;
  57. {
  58. uint32_t formatCount;
  59. ANKI_VK_CHECK(vkGetPhysicalDeviceSurfaceFormatsKHR(m_factory->m_gr->getPhysicalDevice(),
  60. m_factory->m_gr->getSurface(), &formatCount, nullptr));
  61. DynamicArrayAuto<VkSurfaceFormatKHR> formats(getAllocator());
  62. formats.create(formatCount);
  63. ANKI_VK_CHECK(vkGetPhysicalDeviceSurfaceFormatsKHR(m_factory->m_gr->getPhysicalDevice(),
  64. m_factory->m_gr->getSurface(), &formatCount, &formats[0]));
  65. ANKI_VK_LOGV("Supported surface formats:");
  66. Format akSurfaceFormat = Format::NONE;
  67. for(U32 i = 0; i < formatCount; ++i)
  68. {
  69. const VkFormat vkFormat = formats[i].format;
  70. Format akFormat;
  71. switch(formats[i].format)
  72. {
  73. #define ANKI_FORMAT_DEF(type, id, componentCount, texelSize, blockWidth, blockHeight, blockSize, shaderType, \
  74. depthStencil) \
  75. case id: \
  76. akFormat = Format::type; \
  77. break;
  78. #include <AnKi/Gr/Format.defs.h>
  79. #undef ANKI_FORMAT_DEF
  80. default:
  81. akFormat = Format::NONE;
  82. }
  83. ANKI_VK_LOGV("\t%s", (akFormat != Format::NONE) ? getFormatInfo(akFormat).m_name : "Unknown format");
  84. if(surfaceFormat == VK_FORMAT_UNDEFINED
  85. && (vkFormat == VK_FORMAT_R8G8B8A8_UNORM || vkFormat == VK_FORMAT_B8G8R8A8_UNORM
  86. || vkFormat == VK_FORMAT_A8B8G8R8_UNORM_PACK32))
  87. {
  88. surfaceFormat = vkFormat;
  89. colorspace = formats[i].colorSpace;
  90. akSurfaceFormat = akFormat;
  91. }
  92. }
  93. if(surfaceFormat == VK_FORMAT_UNDEFINED)
  94. {
  95. ANKI_VK_LOGE("Suitable surface format not found");
  96. return Error::FUNCTION_FAILED;
  97. }
  98. else
  99. {
  100. ANKI_VK_LOGV("Selecting surface format %s", getFormatInfo(akSurfaceFormat).m_name);
  101. }
  102. }
  103. // Chose present mode
  104. VkPresentModeKHR presentMode = VK_PRESENT_MODE_MAX_ENUM_KHR;
  105. VkPresentModeKHR presentModeSecondChoice = VK_PRESENT_MODE_MAX_ENUM_KHR;
  106. {
  107. uint32_t presentModeCount;
  108. vkGetPhysicalDeviceSurfacePresentModesKHR(m_factory->m_gr->getPhysicalDevice(), m_factory->m_gr->getSurface(),
  109. &presentModeCount, nullptr);
  110. presentModeCount = min(presentModeCount, 4u);
  111. Array<VkPresentModeKHR, 4> presentModes;
  112. vkGetPhysicalDeviceSurfacePresentModesKHR(m_factory->m_gr->getPhysicalDevice(), m_factory->m_gr->getSurface(),
  113. &presentModeCount, &presentModes[0]);
  114. if(m_factory->m_vsync)
  115. {
  116. for(U i = 0; i < presentModeCount; ++i)
  117. {
  118. if(presentModes[i] == VK_PRESENT_MODE_FIFO_RELAXED_KHR)
  119. {
  120. presentMode = presentModes[i];
  121. }
  122. else if(presentModes[i] == VK_PRESENT_MODE_FIFO_KHR)
  123. {
  124. presentModeSecondChoice = presentModes[i];
  125. }
  126. }
  127. }
  128. else
  129. {
  130. for(U i = 0; i < presentModeCount; ++i)
  131. {
  132. if(presentModes[i] == VK_PRESENT_MODE_IMMEDIATE_KHR)
  133. {
  134. presentMode = presentModes[i];
  135. }
  136. else if(presentModes[i] == VK_PRESENT_MODE_MAILBOX_KHR)
  137. {
  138. presentModeSecondChoice = presentModes[i];
  139. }
  140. }
  141. }
  142. presentMode = (presentMode != VK_PRESENT_MODE_MAX_ENUM_KHR) ? presentMode : presentModeSecondChoice;
  143. if(presentMode == VK_PRESENT_MODE_MAX_ENUM_KHR)
  144. {
  145. ANKI_VK_LOGE("Couldn't find a present mode");
  146. return Error::FUNCTION_FAILED;
  147. }
  148. }
  149. // Create swapchain
  150. {
  151. VkCompositeAlphaFlagBitsKHR compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
  152. if(surfaceProperties.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR)
  153. {
  154. compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
  155. }
  156. else if(surfaceProperties.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR)
  157. {
  158. compositeAlpha = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR;
  159. }
  160. else if(surfaceProperties.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR)
  161. {
  162. compositeAlpha = VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR;
  163. }
  164. else if(surfaceProperties.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR)
  165. {
  166. compositeAlpha = VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR;
  167. }
  168. else
  169. {
  170. ANKI_VK_LOGE("Failed to set compositeAlpha");
  171. return Error::FUNCTION_FAILED;
  172. }
  173. VkSwapchainCreateInfoKHR ci = {};
  174. ci.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
  175. ci.surface = m_factory->m_gr->getSurface();
  176. ci.minImageCount = MAX_FRAMES_IN_FLIGHT;
  177. ci.imageFormat = surfaceFormat;
  178. ci.imageColorSpace = colorspace;
  179. ci.imageExtent.width = surfaceWidth;
  180. ci.imageExtent.height = surfaceHeight;
  181. ci.imageArrayLayers = 1;
  182. ci.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_STORAGE_BIT;
  183. ci.queueFamilyIndexCount = m_factory->m_gr->getQueueFamilies().getSize();
  184. ci.pQueueFamilyIndices = &m_factory->m_gr->getQueueFamilies()[0];
  185. ci.imageSharingMode = (ci.queueFamilyIndexCount > 1) ? VK_SHARING_MODE_CONCURRENT : VK_SHARING_MODE_EXCLUSIVE;
  186. ci.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
  187. ci.compositeAlpha = compositeAlpha;
  188. ci.presentMode = presentMode;
  189. ci.clipped = false;
  190. ci.oldSwapchain = VK_NULL_HANDLE;
  191. ANKI_VK_CHECK(vkCreateSwapchainKHR(dev, &ci, nullptr, &m_swapchain));
  192. }
  193. // Get images
  194. {
  195. U32 count = 0;
  196. ANKI_VK_CHECK(vkGetSwapchainImagesKHR(dev, m_swapchain, &count, nullptr));
  197. if(count != MAX_FRAMES_IN_FLIGHT)
  198. {
  199. ANKI_VK_LOGI("Requested a swapchain with %u images but got one with %u", MAX_FRAMES_IN_FLIGHT, count);
  200. }
  201. m_textures.create(getAllocator(), count);
  202. ANKI_VK_LOGI("Created a swapchain. Image count: %u, present mode: %u, size: %ux%u, vsync: %u", count,
  203. presentMode, surfaceWidth, surfaceHeight, U32(m_factory->m_vsync));
  204. Array<VkImage, 64> images;
  205. ANKI_ASSERT(count <= 64);
  206. ANKI_VK_CHECK(vkGetSwapchainImagesKHR(dev, m_swapchain, &count, &images[0]));
  207. for(U32 i = 0; i < count; ++i)
  208. {
  209. TextureInitInfo init("SwapchainImg");
  210. init.m_width = surfaceWidth;
  211. init.m_height = surfaceHeight;
  212. init.m_format = Format(surfaceFormat); // anki::Format is compatible with VkFormat
  213. init.m_usage = TextureUsageBit::IMAGE_COMPUTE_WRITE | TextureUsageBit::IMAGE_TRACE_RAYS_WRITE
  214. | TextureUsageBit::FRAMEBUFFER_ATTACHMENT_READ
  215. | TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE | TextureUsageBit::PRESENT;
  216. init.m_type = TextureType::_2D;
  217. TextureImpl* tex =
  218. m_factory->m_gr->getAllocator().newInstance<TextureImpl>(m_factory->m_gr, init.getName());
  219. m_textures[i].reset(tex);
  220. ANKI_CHECK(tex->initExternal(images[i], init));
  221. }
  222. }
  223. return Error::NONE;
  224. }
  225. GrAllocator<U8> MicroSwapchain::getAllocator() const
  226. {
  227. return m_factory->m_gr->getAllocator();
  228. }
  229. MicroSwapchainPtr SwapchainFactory::newInstance()
  230. {
  231. // Delete stale swapchains (they are stale because they are probably out of data) and always create a new one
  232. m_recycler.trimCache();
  233. // This is useless but call it to avoid assertions
  234. [[maybe_unused]] MicroSwapchain* dummy = m_recycler.findToReuse();
  235. ANKI_ASSERT(dummy == nullptr);
  236. return MicroSwapchainPtr(m_gr->getAllocator().newInstance<MicroSwapchain>(this));
  237. }
  238. void SwapchainFactory::init(GrManagerImpl* manager, Bool vsync)
  239. {
  240. ANKI_ASSERT(manager);
  241. m_gr = manager;
  242. m_vsync = vsync;
  243. m_recycler.init(m_gr->getAllocator());
  244. }
  245. } // end namespace anki