mirror of
https://github.com/doitsujin/dxvk.git
synced 2025-01-31 14:52:11 +01:00
[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:
parent
531732fe91
commit
38c5e57025
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user