SwapchainFactory.cpp 6.7 KB

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