[dxgi] Refactor Vulkan swap chain and surface creation

Creating the Vulkan surface at the latest possible moment fixes
an issue with Frostpunk, which renders to a D3D9 swap chain
before presenting to the GXGI swap chain.
This commit is contained in:
Philip Rebohle 2018-05-23 13:03:12 +02:00
parent 531732fe91
commit 38c5e57025
No known key found for this signature in database
GPG Key ID: C8CC613427A31C99
3 changed files with 62 additions and 61 deletions

View File

@ -10,15 +10,10 @@ namespace dxvk {
DxgiVkPresenter::DxgiVkPresenter(
const Rc<DxvkDevice>& device,
HWND window)
: m_device (device),
: m_window (window),
m_device (device),
m_context (device->createContext()) {
// Create Vulkan surface for the window
HINSTANCE instance = reinterpret_cast<HINSTANCE>(
GetWindowLongPtr(window, GWLP_HINSTANCE));
m_surface = m_device->adapter()->createSurface(instance, window);
// Reset options for the swap chain itself. We will
// create a swap chain object before presentation.
m_options.preferredSurfaceFormat = { VK_FORMAT_UNDEFINED, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR };
@ -275,27 +270,52 @@ namespace dxvk {
}
void DxgiVkPresenter::RecreateSwapchain(const DxvkSwapchainProperties* pOptions) {
void DxgiVkPresenter::SetGammaControl(
const DXGI_VK_GAMMA_CURVE* pGammaCurve) {
m_context->beginRecording(
m_device->createCommandList());
m_context->updateImage(m_gammaTexture,
VkImageSubresourceLayers { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 },
VkOffset3D { 0, 0, 0 },
VkExtent3D { DXGI_VK_GAMMA_CP_COUNT, 1, 1 },
pGammaCurve, 0, 0);
m_device->submitCommandList(
m_context->endRecording(),
nullptr, nullptr);
}
void DxgiVkPresenter::RecreateSwapchain(DXGI_FORMAT Format, VkPresentModeKHR PresentMode, VkExtent2D WindowSize) {
if (m_surface == nullptr)
m_surface = CreateSurface();
DxvkSwapchainProperties options;
options.preferredSurfaceFormat = PickSurfaceFormat(Format);
options.preferredPresentMode = PickPresentMode(PresentMode);
options.preferredBufferSize = WindowSize;
const bool doRecreate =
pOptions->preferredSurfaceFormat.format != m_options.preferredSurfaceFormat.format
|| pOptions->preferredSurfaceFormat.colorSpace != m_options.preferredSurfaceFormat.colorSpace
|| pOptions->preferredPresentMode != m_options.preferredPresentMode
|| pOptions->preferredBufferSize.width != m_options.preferredBufferSize.width
|| pOptions->preferredBufferSize.height != m_options.preferredBufferSize.height;
options.preferredSurfaceFormat.format != m_options.preferredSurfaceFormat.format
|| options.preferredSurfaceFormat.colorSpace != m_options.preferredSurfaceFormat.colorSpace
|| options.preferredPresentMode != m_options.preferredPresentMode
|| options.preferredBufferSize.width != m_options.preferredBufferSize.width
|| options.preferredBufferSize.height != m_options.preferredBufferSize.height;
if (doRecreate) {
Logger::info(str::format(
"DxgiVkPresenter: Recreating swap chain: ",
"\n Format: ", pOptions->preferredSurfaceFormat.format,
"\n Present mode: ", pOptions->preferredPresentMode,
"\n Buffer size: ", pOptions->preferredBufferSize.width, "x", pOptions->preferredBufferSize.height));
"\n Format: ", options.preferredSurfaceFormat.format,
"\n Present mode: ", options.preferredPresentMode,
"\n Buffer size: ", options.preferredBufferSize.width, "x", options.preferredBufferSize.height));
if (m_swapchain == nullptr)
m_swapchain = m_device->createSwapchain(m_surface, *pOptions);
m_swapchain = m_device->createSwapchain(m_surface, options);
else
m_swapchain->changeProperties(*pOptions);
m_swapchain->changeProperties(options);
m_options = *pOptions;
m_options = options;
}
}
@ -339,20 +359,11 @@ namespace dxvk {
}
void DxgiVkPresenter::SetGammaControl(
const DXGI_VK_GAMMA_CURVE* pGammaCurve) {
m_context->beginRecording(
m_device->createCommandList());
Rc<DxvkSurface> DxgiVkPresenter::CreateSurface() {
HINSTANCE instance = reinterpret_cast<HINSTANCE>(
GetWindowLongPtr(m_window, GWLP_HINSTANCE));
m_context->updateImage(m_gammaTexture,
VkImageSubresourceLayers { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 },
VkOffset3D { 0, 0, 0 },
VkExtent3D { DXGI_VK_GAMMA_CP_COUNT, 1, 1 },
pGammaCurve, 0, 0);
m_device->submitCommandList(
m_context->endRecording(),
nullptr, nullptr);
return m_device->adapter()->createSurface(instance, m_window);
}

View File

@ -100,28 +100,14 @@ namespace dxvk {
* Only actually recreates the swap chain object
* if any of the properties have changed. If no
* properties have changed, this is a no-op.
* \param [in] options New swap chain options
* \param [in] Format New surface format
* \param [in] PresentMode Present mode
* \param [in] WindowSize Window size
*/
void RecreateSwapchain(
const DxvkSwapchainProperties* pOptions);
/**
* \brief Picks a surface format based on a DXGI format
*
* This will return a supported format that, if possible,
* has properties similar to those of the DXGI format.
* \param [in] fmt The DXGI format
* \returns The Vulkan format
*/
VkSurfaceFormatKHR PickSurfaceFormat(DXGI_FORMAT Fmt) const;
/**
* \brief Picks a supported present mode
*
* \param [in] preferred Preferred present mode
* \returns An actually supported present mode
*/
VkPresentModeKHR PickPresentMode(VkPresentModeKHR Preferred) const;
DXGI_FORMAT Format,
VkPresentModeKHR PresentMode,
VkExtent2D WindowSize);
/**
* \brief Sets gamma curve
@ -142,6 +128,8 @@ namespace dxvk {
GammaTex = 3,
};
HWND m_window;
Rc<DxvkDevice> m_device;
Rc<DxvkContext> m_context;
@ -164,6 +152,12 @@ namespace dxvk {
DxvkBlendMode m_blendMode;
DxvkSwapchainProperties m_options;
VkSurfaceFormatKHR PickSurfaceFormat(DXGI_FORMAT Fmt) const;
VkPresentModeKHR PickPresentMode(VkPresentModeKHR Preferred) const;
Rc<DxvkSurface> CreateSurface();
Rc<DxvkSampler> CreateSampler(
VkFilter Filter,
VkSamplerAddressMode AddressMode);

View File

@ -306,15 +306,11 @@ namespace dxvk {
// up vertical synchronization properly, but also apply
// changes that were made to the window size even if the
// Vulkan swap chain itself remains valid.
DxvkSwapchainProperties swapchainProps;
swapchainProps.preferredSurfaceFormat
= m_presenter->PickSurfaceFormat(m_desc.Format);
swapchainProps.preferredPresentMode = SyncInterval == 0
? m_presenter->PickPresentMode(VK_PRESENT_MODE_IMMEDIATE_KHR)
: m_presenter->PickPresentMode(VK_PRESENT_MODE_FIFO_KHR);
swapchainProps.preferredBufferSize = GetWindowSize();
m_presenter->RecreateSwapchain(&swapchainProps);
VkPresentModeKHR presentMode = SyncInterval == 0
? VK_PRESENT_MODE_IMMEDIATE_KHR
: VK_PRESENT_MODE_FIFO_KHR;
m_presenter->RecreateSwapchain(m_desc.Format, presentMode, GetWindowSize());
m_presenter->PresentImage();
return S_OK;
} catch (const DxvkError& err) {