2
0

SwapchainFactory.cpp 7.6 KB

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