SwapchainFactory.cpp 7.6 KB

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