diff --git a/src/dxgi/dxgi_presenter.cpp b/src/dxgi/dxgi_presenter.cpp index 6f8a7efd6..1ad17d3a3 100644 --- a/src/dxgi/dxgi_presenter.cpp +++ b/src/dxgi/dxgi_presenter.cpp @@ -7,8 +7,9 @@ namespace dxvk { DxgiPresenter::DxgiPresenter( const Rc& device, HWND window, - UINT bufferWidth, - UINT bufferHeight) + uint32_t bufferWidth, + uint32_t bufferHeight, + DXGI_FORMAT bufferFormat) : m_device (device), m_context (device->createContext()) { @@ -20,11 +21,10 @@ namespace dxvk { // Create swap chain for the surface DxvkSwapchainProperties swapchainProperties; - swapchainProperties.preferredSurfaceFormat.format = VK_FORMAT_B8G8R8A8_SRGB; - swapchainProperties.preferredSurfaceFormat.colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; - swapchainProperties.preferredPresentMode = VK_PRESENT_MODE_FIFO_KHR; - swapchainProperties.preferredBufferSize.width = bufferWidth; - swapchainProperties.preferredBufferSize.height = bufferHeight; + swapchainProperties.preferredSurfaceFormat = this->pickFormat(bufferFormat); + swapchainProperties.preferredPresentMode = VK_PRESENT_MODE_FIFO_KHR; + swapchainProperties.preferredBufferSize.width = bufferWidth; + swapchainProperties.preferredBufferSize.height = bufferHeight; m_swapchain = m_device->createSwapchain( m_surface, swapchainProperties); @@ -173,6 +173,45 @@ namespace dxvk { } + void DxgiPresenter::recreateSwapchain( + uint32_t bufferWidth, + uint32_t bufferHeight, + DXGI_FORMAT bufferFormat) { + DxvkSwapchainProperties swapchainProperties; + swapchainProperties.preferredSurfaceFormat = this->pickFormat(bufferFormat); + swapchainProperties.preferredPresentMode = VK_PRESENT_MODE_FIFO_KHR; + swapchainProperties.preferredBufferSize.width = bufferWidth; + swapchainProperties.preferredBufferSize.height = bufferHeight; + + m_swapchain->changeProperties(swapchainProperties); + } + + + VkSurfaceFormatKHR DxgiPresenter::pickFormat(DXGI_FORMAT fmt) const { + std::vector formats; + + switch (fmt) { + case DXGI_FORMAT_R8G8B8A8_UNORM: + case DXGI_FORMAT_B8G8R8A8_UNORM: { + formats.push_back({ VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR }); + formats.push_back({ VK_FORMAT_B8G8R8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR }); + } break; + + case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: + case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: { + formats.push_back({ VK_FORMAT_R8G8B8A8_SRGB, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR }); + formats.push_back({ VK_FORMAT_B8G8R8A8_SRGB, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR }); + } break; + + default: + Logger::warn(str::format("DxgiPresenter: Unknown format: ", fmt)); + } + + return m_surface->pickSurfaceFormat( + formats.size(), formats.data()); + } + + Rc DxgiPresenter::createVertexShader() { SpirvModule module; diff --git a/src/dxgi/dxgi_presenter.h b/src/dxgi/dxgi_presenter.h index 7db2ed1f5..5c8b9da85 100644 --- a/src/dxgi/dxgi_presenter.h +++ b/src/dxgi/dxgi_presenter.h @@ -4,6 +4,8 @@ #include #include +#include "dxgi_include.h" + #include "../spirv/spirv_module.h" namespace dxvk { @@ -22,8 +24,9 @@ namespace dxvk { DxgiPresenter( const Rc& device, HWND window, - UINT bufferWidth, - UINT bufferHeight); + uint32_t bufferWidth, + uint32_t bufferHeight, + DXGI_FORMAT bufferFormat); ~DxgiPresenter(); @@ -41,6 +44,15 @@ namespace dxvk { void presentImage( const Rc& view); + /** + * \brief Renders image to the screen + * \param [in] view Source image view + */ + void recreateSwapchain( + uint32_t bufferWidth, + uint32_t bufferHeight, + DXGI_FORMAT bufferFormat); + private: enum BindingIds : uint32_t { @@ -59,6 +71,8 @@ namespace dxvk { Rc m_sampler; + VkSurfaceFormatKHR pickFormat(DXGI_FORMAT fmt) const; + Rc createVertexShader(); Rc createFragmentShader(); diff --git a/src/dxgi/dxgi_swapchain.cpp b/src/dxgi/dxgi_swapchain.cpp index 207f68215..65383acc8 100644 --- a/src/dxgi/dxgi_swapchain.cpp +++ b/src/dxgi/dxgi_swapchain.cpp @@ -46,6 +46,13 @@ namespace dxvk { SDL_GetError())); } + // Adjust initial back buffer size. If zero, these + // shall be set to the current window size. + VkExtent2D windowSize = this->getWindowSize(); + + if (m_desc.BufferDesc.Width == 0) m_desc.BufferDesc.Width = windowSize.width; + if (m_desc.BufferDesc.Height == 0) m_desc.BufferDesc.Height = windowSize.height; + // Set initial window mode and fullscreen state if (FAILED(this->SetFullscreenState(!pDesc->Windowed, nullptr))) throw DxvkError("DxgiSwapChain::DxgiSwapChain: Failed to set initial fullscreen state"); @@ -187,15 +194,24 @@ namespace dxvk { UINT SwapChainFlags) { std::lock_guard lock(m_mutex); - m_desc.BufferDesc.Width = Width; - m_desc.BufferDesc.Height = Height; - m_desc.BufferDesc.Format = NewFormat; - m_desc.Flags = SwapChainFlags; + VkExtent2D windowSize = this->getWindowSize(); + + m_desc.BufferDesc.Width = Width != 0 ? Width : windowSize.width; + m_desc.BufferDesc.Height = Height != 0 ? Height : windowSize.height; + + m_desc.Flags = SwapChainFlags; if (BufferCount != 0) - m_desc.BufferCount = BufferCount; + m_desc.BufferCount = BufferCount; + + if (NewFormat != DXGI_FORMAT_UNKNOWN) + m_desc.BufferDesc.Format = NewFormat; try { + m_presenter->recreateSwapchain( + m_desc.BufferDesc.Width, + m_desc.BufferDesc.Height, + m_desc.BufferDesc.Format); this->createBackBuffer(); return S_OK; } catch (const DxvkError& err) { @@ -289,7 +305,8 @@ namespace dxvk { m_device->GetDXVKDevice(), m_desc.OutputWindow, m_desc.BufferDesc.Width, - m_desc.BufferDesc.Height); + m_desc.BufferDesc.Height, + m_desc.BufferDesc.Format); } @@ -369,4 +386,17 @@ namespace dxvk { m_presenter->initBackBuffer(m_backBuffer); } + + VkExtent2D DxgiSwapChain::getWindowSize() const { + int winWidth = 0; + int winHeight = 0; + + SDL_GetWindowSize(m_window, &winWidth, &winHeight); + + VkExtent2D result; + result.width = winWidth; + result.height = winHeight; + return result; + } + } diff --git a/src/dxgi/dxgi_swapchain.h b/src/dxgi/dxgi_swapchain.h index 673c87764..15828bdec 100644 --- a/src/dxgi/dxgi_swapchain.h +++ b/src/dxgi/dxgi_swapchain.h @@ -113,6 +113,8 @@ namespace dxvk { void createContext(); + VkExtent2D getWindowSize() const; + }; } diff --git a/src/dxvk/dxvk_surface.cpp b/src/dxvk/dxvk_surface.cpp index 302ca6da2..630ee6fa0 100644 --- a/src/dxvk/dxvk_surface.cpp +++ b/src/dxvk/dxvk_surface.cpp @@ -32,18 +32,24 @@ namespace dxvk { } - VkSurfaceFormatKHR DxvkSurface::pickSurfaceFormat(VkSurfaceFormatKHR preferred) const { - // If the implementation allows us to freely choose - // the format, we'll just use the preferred format. - if (m_surfaceFormats.size() == 1 && m_surfaceFormats.at(0).format == VK_FORMAT_UNDEFINED) - return preferred; - - // If the preferred format is explicitly listed in - // the array of supported surface formats, use it - for (auto fmt : m_surfaceFormats) { - if (fmt.format == preferred.format - && fmt.colorSpace == preferred.colorSpace) - return fmt; + VkSurfaceFormatKHR DxvkSurface::pickSurfaceFormat( + uint32_t preferredCount, + const VkSurfaceFormatKHR* preferred) const { + if (preferredCount > 0) { + // If the implementation allows us to freely choose + // the format, we'll just use the preferred format. + if (m_surfaceFormats.size() == 1 && m_surfaceFormats.at(0).format == VK_FORMAT_UNDEFINED) + return preferred[0]; + + // If the preferred format is explicitly listed in + // the array of supported surface formats, use it + for (uint32_t i = 0; i < preferredCount; i++) { + for (auto fmt : m_surfaceFormats) { + if (fmt.format == preferred[i].format + && fmt.colorSpace == preferred[i].colorSpace) + return fmt; + } + } } // Otherwise, fall back to the first format @@ -51,10 +57,14 @@ namespace dxvk { } - VkPresentModeKHR DxvkSurface::pickPresentMode(VkPresentModeKHR preferred) const { - for (auto mode : m_presentModes) { - if (mode == preferred) - return mode; + VkPresentModeKHR DxvkSurface::pickPresentMode( + uint32_t preferredCount, + const VkPresentModeKHR* preferred) const { + for (uint32_t i = 0; i < preferredCount; i++) { + for (auto mode : m_presentModes) { + if (mode == preferred[i]) + return mode; + } } // This mode is guaranteed to be available diff --git a/src/dxvk/dxvk_surface.h b/src/dxvk/dxvk_surface.h index ee25508ec..252f29b49 100644 --- a/src/dxvk/dxvk_surface.h +++ b/src/dxvk/dxvk_surface.h @@ -41,20 +41,24 @@ namespace dxvk { /** * \brief Picks a suitable surface format * - * \param [in] preferred Preferred surface format + * \param [in] preferredCount Number of formats to probe + * \param [in] preferred Preferred surface formats * \returns The actual surface format */ VkSurfaceFormatKHR pickSurfaceFormat( - VkSurfaceFormatKHR preferred) const; + uint32_t preferredCount, + const VkSurfaceFormatKHR* preferred) const; /** * \brief Picks a supported present mode * - * \param [in] preferred The preferred present mode + * \param [in] preferredCount Number of modes to probe + * \param [in] preferred Preferred present modes * \returns The actual present mode */ VkPresentModeKHR pickPresentMode( - VkPresentModeKHR preferred) const; + uint32_t preferredCount, + const VkPresentModeKHR* preferred) const; /** * \brief Picks a suitable image count for a swap chain diff --git a/src/dxvk/dxvk_swapchain.cpp b/src/dxvk/dxvk_swapchain.cpp index ffdd76eb3..060e0f894 100644 --- a/src/dxvk/dxvk_swapchain.cpp +++ b/src/dxvk/dxvk_swapchain.cpp @@ -94,8 +94,8 @@ namespace dxvk { // Recreate the actual swapchain object auto caps = m_surface->getSurfaceCapabilities(); - auto fmt = m_surface->pickSurfaceFormat(m_properties.preferredSurfaceFormat); - auto mode = m_surface->pickPresentMode (m_properties.preferredPresentMode); + 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;