#include "dxvk_main.h" #include "dxvk_device.h" #include "dxvk_framebuffer.h" #include "dxvk_surface.h" #include "dxvk_swapchain.h" namespace dxvk { DxvkSwapchain::DxvkSwapchain( const Rc& device, const Rc& surface, const DxvkSwapchainProperties& properties) : m_device (device), m_vkd (device->vkd()), m_surface (surface), m_properties(properties) { this->recreateSwapchain(); } DxvkSwapchain::~DxvkSwapchain() { m_device->waitForIdle(); m_vkd->vkDestroySwapchainKHR( m_vkd->device(), m_handle, nullptr); } DxvkSwapSemaphores DxvkSwapchain::getSemaphorePair() { // It doesn't really matter that we increment the // counter *before* returning the semaphore pair m_frameIndex = (m_frameIndex + 1) % m_semaphoreSet.size(); return m_semaphoreSet.at(m_frameIndex); } Rc DxvkSwapchain::getImageView( const Rc& wakeSync) { // AcquireNextImage might interfere with the Vulkan // device queue internally, so we should lock it m_device->lockSubmission(); VkResult status = this->acquireNextImage(wakeSync); if (status == VK_ERROR_OUT_OF_DATE_KHR) { this->recreateSwapchain(); status = this->acquireNextImage(wakeSync); } m_device->unlockSubmission(); if (status != VK_SUCCESS && status != VK_SUBOPTIMAL_KHR) throw DxvkError("DxvkSwapchain: Failed to acquire image"); return m_framebuffers.at(m_imageIndex); } void DxvkSwapchain::present(const Rc& waitSync) { const VkSemaphore waitSemaphore = waitSync->handle(); VkPresentInfoKHR info; info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; info.pNext = nullptr; info.waitSemaphoreCount = 1; info.pWaitSemaphores = &waitSemaphore; info.swapchainCount = 1; info.pSwapchains = &m_handle; info.pImageIndices = &m_imageIndex; info.pResults = nullptr; VkResult status = m_device->presentSwapImage(info); if (status == VK_SUBOPTIMAL_KHR || status == VK_ERROR_OUT_OF_DATE_KHR) this->recreateSwapchain(); else if (status != VK_SUCCESS) throw DxvkError("DxvkSwapchain: Failed to present image"); } void DxvkSwapchain::changeProperties( const DxvkSwapchainProperties& props) { m_properties = props; this->recreateSwapchain(); } VkResult DxvkSwapchain::acquireNextImage( const Rc& wakeSync) { return m_vkd->vkAcquireNextImageKHR( m_vkd->device(), m_handle, std::numeric_limits::max(), wakeSync->handle(), VK_NULL_HANDLE, &m_imageIndex); } void DxvkSwapchain::recreateSwapchain() { // Wait until we can be certain that none of our // resources are still in use by the device. m_device->waitForIdle(); // Destroy previous swapchain object m_vkd->vkDestroySwapchainKHR( m_vkd->device(), m_handle, nullptr); // Recreate the actual swapchain object auto caps = m_surface->getSurfaceCapabilities(); auto fmt = m_surface->pickSurfaceFormat(1, &m_properties.preferredSurfaceFormat); auto mode = m_surface->pickPresentMode (1, &m_properties.preferredPresentMode); VkSwapchainCreateInfoKHR swapInfo; swapInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; swapInfo.pNext = nullptr; swapInfo.flags = 0; swapInfo.surface = m_surface->handle(); swapInfo.minImageCount = m_surface->pickImageCount(caps, mode); swapInfo.imageFormat = fmt.format; swapInfo.imageColorSpace = fmt.colorSpace; swapInfo.imageExtent = m_surface->pickImageExtent(caps, m_properties.preferredBufferSize); swapInfo.imageArrayLayers = 1; swapInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; swapInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; swapInfo.queueFamilyIndexCount = 0; swapInfo.pQueueFamilyIndices = nullptr; swapInfo.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; swapInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; swapInfo.presentMode = mode; swapInfo.clipped = VK_TRUE; swapInfo.oldSwapchain = VK_NULL_HANDLE; Logger::debug(str::format( "DxvkSwapchain: Actual swap chain properties: ", "\n Format: ", swapInfo.imageFormat, "\n Present mode: ", swapInfo.presentMode, "\n Buffer size: ", swapInfo.imageExtent.width, "x", swapInfo.imageExtent.height, "\n Image count: ", swapInfo.minImageCount)); if (m_vkd->vkCreateSwapchainKHR(m_vkd->device(), &swapInfo, nullptr, &m_handle) != VK_SUCCESS) throw DxvkError("DxvkSwapchain: Failed to recreate swap chain"); // Retrieve swap images auto swapImages = this->retrieveSwapImages(); m_framebuffers.resize(swapImages.size()); m_semaphoreSet.resize(swapImages.size()); DxvkImageCreateInfo imageInfo; imageInfo.type = VK_IMAGE_TYPE_2D; imageInfo.format = fmt.format; imageInfo.flags = 0; imageInfo.sampleCount = VK_SAMPLE_COUNT_1_BIT; imageInfo.extent.width = swapInfo.imageExtent.width; imageInfo.extent.height = swapInfo.imageExtent.height; imageInfo.extent.depth = 1; imageInfo.numLayers = swapInfo.imageArrayLayers; imageInfo.mipLevels = 1; imageInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL; imageInfo.stages = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; imageInfo.access = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_MEMORY_READ_BIT; imageInfo.layout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; DxvkImageViewCreateInfo viewInfo; viewInfo.type = VK_IMAGE_VIEW_TYPE_2D; viewInfo.format = fmt.format; viewInfo.aspect = VK_IMAGE_ASPECT_COLOR_BIT; viewInfo.minLevel = 0; viewInfo.numLevels = 1; viewInfo.minLayer = 0; viewInfo.numLayers = swapInfo.imageArrayLayers; for (size_t i = 0; i < swapImages.size(); i++) { m_framebuffers.at(i) = m_device->createImageView( new DxvkImage(m_vkd, imageInfo, swapImages.at(i)), viewInfo); m_semaphoreSet.at(i).acquireSync = m_device->createSemaphore(); m_semaphoreSet.at(i).presentSync = m_device->createSemaphore(); } } std::vector DxvkSwapchain::retrieveSwapImages() { uint32_t imageCount = 0; if (m_vkd->vkGetSwapchainImagesKHR(m_vkd->device(), m_handle, &imageCount, nullptr) != VK_SUCCESS) throw DxvkError("DxvkSwapchain: Failed to retrieve swap chain images"); std::vector images(imageCount); if (m_vkd->vkGetSwapchainImagesKHR(m_vkd->device(), m_handle, &imageCount, images.data()) != VK_SUCCESS) throw DxvkError("DxvkSwapchain: Failed to retrieve swap chain images"); return images; } }