Skip to content

Commit

Permalink
[dxgi] Refactor Vulkan swap chain and surface creation
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
doitsujin committed May 23, 2018
1 parent 531732f commit 38c5e57
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 61 deletions.
75 changes: 43 additions & 32 deletions src/dxgi/dxgi_presenter.cpp
Expand Up @@ -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 };
Expand Down Expand Up @@ -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;
}
}

Expand Down Expand Up @@ -339,20 +359,11 @@ namespace dxvk {
}


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);
Rc<DxvkSurface> DxgiVkPresenter::CreateSurface() {
HINSTANCE instance = reinterpret_cast<HINSTANCE>(
GetWindowLongPtr(m_window, GWLP_HINSTANCE));

m_device->submitCommandList(
m_context->endRecording(),
nullptr, nullptr);
return m_device->adapter()->createSurface(instance, m_window);
}


Expand Down
34 changes: 14 additions & 20 deletions src/dxgi/dxgi_presenter.h
Expand Up @@ -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
Expand All @@ -142,6 +128,8 @@ namespace dxvk {
GammaTex = 3,
};

HWND m_window;

Rc<DxvkDevice> m_device;
Rc<DxvkContext> m_context;

Expand All @@ -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);
Expand Down
14 changes: 5 additions & 9 deletions src/dxgi/dxgi_swapchain.cpp
Expand Up @@ -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) {
Expand Down

0 comments on commit 38c5e57

Please sign in to comment.