| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279 |
- // Copyright (C) 2009-2022, Panagiotis Christopoulos Charitos and contributors.
- // All rights reserved.
- // Code licensed under the BSD License.
- // http://www.anki3d.org/LICENSE
- #include <AnKi/Gr/Vulkan/SwapchainFactory.h>
- #include <AnKi/Gr/Vulkan/GrManagerImpl.h>
- namespace anki {
- MicroSwapchain::MicroSwapchain(SwapchainFactory* factory)
- : m_factory(factory)
- {
- ANKI_ASSERT(factory);
- if(initInternal())
- {
- ANKI_VK_LOGF("Error creating the swapchain. Will not try to recover");
- }
- }
- MicroSwapchain::~MicroSwapchain()
- {
- const VkDevice dev = m_factory->m_gr->getDevice();
- m_textures.destroy(getAllocator());
- if(m_swapchain)
- {
- vkDestroySwapchainKHR(dev, m_swapchain, nullptr);
- m_swapchain = {};
- }
- }
- Error MicroSwapchain::initInternal()
- {
- const VkDevice dev = m_factory->m_gr->getDevice();
- // Get the surface size
- VkSurfaceCapabilitiesKHR surfaceProperties;
- U32 surfaceWidth = 0, surfaceHeight = 0;
- {
- ANKI_VK_CHECK(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(m_factory->m_gr->getPhysicalDevice(),
- m_factory->m_gr->getSurface(), &surfaceProperties));
- #if ANKI_WINDOWING_SYSTEM_HEADLESS
- if(surfaceProperties.currentExtent.width != MAX_U32 || surfaceProperties.currentExtent.height != MAX_U32)
- {
- ANKI_VK_LOGE("Was expecting an indication that the surface size will be determined by the extent of a "
- "swapchain targeting the surface");
- return Error::FUNCTION_FAILED;
- }
- m_factory->m_gr->getNativeWindowSize(surfaceWidth, surfaceHeight);
- #else
- if(surfaceProperties.currentExtent.width == MAX_U32 || surfaceProperties.currentExtent.height == MAX_U32)
- {
- ANKI_VK_LOGE("Wrong surface size");
- return Error::FUNCTION_FAILED;
- }
- surfaceWidth = surfaceProperties.currentExtent.width;
- surfaceHeight = surfaceProperties.currentExtent.height;
- #endif
- }
- // Get the surface format
- VkFormat surfaceFormat = VK_FORMAT_UNDEFINED;
- VkColorSpaceKHR colorspace = VK_COLOR_SPACE_MAX_ENUM_KHR;
- {
- uint32_t formatCount;
- ANKI_VK_CHECK(vkGetPhysicalDeviceSurfaceFormatsKHR(m_factory->m_gr->getPhysicalDevice(),
- m_factory->m_gr->getSurface(), &formatCount, nullptr));
- DynamicArrayAuto<VkSurfaceFormatKHR> formats(getAllocator());
- formats.create(formatCount);
- ANKI_VK_CHECK(vkGetPhysicalDeviceSurfaceFormatsKHR(m_factory->m_gr->getPhysicalDevice(),
- m_factory->m_gr->getSurface(), &formatCount, &formats[0]));
- ANKI_VK_LOGV("Supported surface formats:");
- Format akSurfaceFormat = Format::NONE;
- for(U32 i = 0; i < formatCount; ++i)
- {
- const VkFormat vkFormat = formats[i].format;
- Format akFormat;
- switch(formats[i].format)
- {
- #define ANKI_FORMAT_DEF(type, id, componentCount, texelSize, blockWidth, blockHeight, blockSize, shaderType, \
- depthStencil) \
- case id: \
- akFormat = Format::type; \
- break;
- #include <AnKi/Gr/Format.defs.h>
- #undef ANKI_FORMAT_DEF
- default:
- akFormat = Format::NONE;
- }
- ANKI_VK_LOGV("\t%s", (akFormat != Format::NONE) ? getFormatInfo(akFormat).m_name : "Unknown format");
- if(surfaceFormat == VK_FORMAT_UNDEFINED
- && (vkFormat == VK_FORMAT_R8G8B8A8_UNORM || vkFormat == VK_FORMAT_B8G8R8A8_UNORM
- || vkFormat == VK_FORMAT_A8B8G8R8_UNORM_PACK32))
- {
- surfaceFormat = vkFormat;
- colorspace = formats[i].colorSpace;
- akSurfaceFormat = akFormat;
- }
- }
- if(surfaceFormat == VK_FORMAT_UNDEFINED)
- {
- ANKI_VK_LOGE("Suitable surface format not found");
- return Error::FUNCTION_FAILED;
- }
- else
- {
- ANKI_VK_LOGV("Selecting surface format %s", getFormatInfo(akSurfaceFormat).m_name);
- }
- }
- // Chose present mode
- VkPresentModeKHR presentMode = VK_PRESENT_MODE_MAX_ENUM_KHR;
- VkPresentModeKHR presentModeSecondChoice = VK_PRESENT_MODE_MAX_ENUM_KHR;
- {
- uint32_t presentModeCount;
- vkGetPhysicalDeviceSurfacePresentModesKHR(m_factory->m_gr->getPhysicalDevice(), m_factory->m_gr->getSurface(),
- &presentModeCount, nullptr);
- presentModeCount = min(presentModeCount, 4u);
- Array<VkPresentModeKHR, 4> presentModes;
- vkGetPhysicalDeviceSurfacePresentModesKHR(m_factory->m_gr->getPhysicalDevice(), m_factory->m_gr->getSurface(),
- &presentModeCount, &presentModes[0]);
- if(m_factory->m_vsync)
- {
- for(U i = 0; i < presentModeCount; ++i)
- {
- if(presentModes[i] == VK_PRESENT_MODE_FIFO_RELAXED_KHR)
- {
- presentMode = presentModes[i];
- }
- else if(presentModes[i] == VK_PRESENT_MODE_FIFO_KHR)
- {
- presentModeSecondChoice = presentModes[i];
- }
- }
- }
- else
- {
- for(U i = 0; i < presentModeCount; ++i)
- {
- if(presentModes[i] == VK_PRESENT_MODE_IMMEDIATE_KHR)
- {
- presentMode = presentModes[i];
- }
- else if(presentModes[i] == VK_PRESENT_MODE_MAILBOX_KHR)
- {
- presentModeSecondChoice = presentModes[i];
- }
- }
- }
- presentMode = (presentMode != VK_PRESENT_MODE_MAX_ENUM_KHR) ? presentMode : presentModeSecondChoice;
- if(presentMode == VK_PRESENT_MODE_MAX_ENUM_KHR)
- {
- ANKI_VK_LOGE("Couldn't find a present mode");
- return Error::FUNCTION_FAILED;
- }
- }
- // Create swapchain
- {
- VkCompositeAlphaFlagBitsKHR compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
- if(surfaceProperties.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR)
- {
- compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
- }
- else if(surfaceProperties.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR)
- {
- compositeAlpha = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR;
- }
- else if(surfaceProperties.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR)
- {
- compositeAlpha = VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR;
- }
- else if(surfaceProperties.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR)
- {
- compositeAlpha = VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR;
- }
- else
- {
- ANKI_VK_LOGE("Failed to set compositeAlpha");
- return Error::FUNCTION_FAILED;
- }
- VkSwapchainCreateInfoKHR ci = {};
- ci.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
- ci.surface = m_factory->m_gr->getSurface();
- ci.minImageCount = MAX_FRAMES_IN_FLIGHT;
- ci.imageFormat = surfaceFormat;
- ci.imageColorSpace = colorspace;
- ci.imageExtent.width = surfaceWidth;
- ci.imageExtent.height = surfaceHeight;
- ci.imageArrayLayers = 1;
- ci.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_STORAGE_BIT;
- ci.queueFamilyIndexCount = m_factory->m_gr->getQueueFamilies().getSize();
- ci.pQueueFamilyIndices = &m_factory->m_gr->getQueueFamilies()[0];
- ci.imageSharingMode = (ci.queueFamilyIndexCount > 1) ? VK_SHARING_MODE_CONCURRENT : VK_SHARING_MODE_EXCLUSIVE;
- ci.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
- ci.compositeAlpha = compositeAlpha;
- ci.presentMode = presentMode;
- ci.clipped = false;
- ci.oldSwapchain = VK_NULL_HANDLE;
- ANKI_VK_CHECK(vkCreateSwapchainKHR(dev, &ci, nullptr, &m_swapchain));
- }
- // Get images
- {
- U32 count = 0;
- ANKI_VK_CHECK(vkGetSwapchainImagesKHR(dev, m_swapchain, &count, nullptr));
- if(count != MAX_FRAMES_IN_FLIGHT)
- {
- ANKI_VK_LOGI("Requested a swapchain with %u images but got one with %u", MAX_FRAMES_IN_FLIGHT, count);
- }
- m_textures.create(getAllocator(), count);
- ANKI_VK_LOGI("Created a swapchain. Image count: %u, present mode: %u, size: %ux%u, vsync: %u", count,
- presentMode, surfaceWidth, surfaceHeight, U32(m_factory->m_vsync));
- Array<VkImage, 64> images;
- ANKI_ASSERT(count <= 64);
- ANKI_VK_CHECK(vkGetSwapchainImagesKHR(dev, m_swapchain, &count, &images[0]));
- for(U32 i = 0; i < count; ++i)
- {
- TextureInitInfo init("SwapchainImg");
- init.m_width = surfaceWidth;
- init.m_height = surfaceHeight;
- init.m_format = Format(surfaceFormat); // anki::Format is compatible with VkFormat
- init.m_usage = TextureUsageBit::IMAGE_COMPUTE_WRITE | TextureUsageBit::IMAGE_TRACE_RAYS_WRITE
- | TextureUsageBit::FRAMEBUFFER_ATTACHMENT_READ
- | TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE | TextureUsageBit::PRESENT;
- init.m_type = TextureType::_2D;
- TextureImpl* tex =
- m_factory->m_gr->getAllocator().newInstance<TextureImpl>(m_factory->m_gr, init.getName());
- m_textures[i].reset(tex);
- ANKI_CHECK(tex->initExternal(images[i], init));
- }
- }
- return Error::NONE;
- }
- GrAllocator<U8> MicroSwapchain::getAllocator() const
- {
- return m_factory->m_gr->getAllocator();
- }
- MicroSwapchainPtr SwapchainFactory::newInstance()
- {
- // Delete stale swapchains (they are stale because they are probably out of data) and always create a new one
- m_recycler.trimCache();
- // This is useless but call it to avoid assertions
- [[maybe_unused]] MicroSwapchain* dummy = m_recycler.findToReuse();
- ANKI_ASSERT(dummy == nullptr);
- return MicroSwapchainPtr(m_gr->getAllocator().newInstance<MicroSwapchain>(this));
- }
- void SwapchainFactory::init(GrManagerImpl* manager, Bool vsync)
- {
- ANKI_ASSERT(manager);
- m_gr = manager;
- m_vsync = vsync;
- m_recycler.init(m_gr->getAllocator());
- }
- } // end namespace anki
|