HostDisplay: Fix vsync getting lost on window changes

This commit is contained in:
Connor McLaughlin 2022-02-06 20:23:30 +10:00 committed by refractionpcsx2
parent 061fff6f17
commit c74cc9bc12
11 changed files with 34 additions and 22 deletions

View File

@ -291,7 +291,7 @@ namespace Vulkan
}
bool Context::Create(std::string_view gpu_name, const WindowInfo* wi, std::unique_ptr<SwapChain>* out_swap_chain,
bool threaded_presentation, bool enable_debug_utils, bool enable_validation_layer)
bool vsync, bool threaded_presentation, bool enable_debug_utils, bool enable_validation_layer)
{
pxAssertMsg(!g_vulkan_context, "Has no current context");
@ -370,7 +370,7 @@ namespace Vulkan
if (!g_vulkan_context->CreateDevice(surface, enable_validation_layer, nullptr, 0, nullptr, 0, nullptr) ||
!g_vulkan_context->CreateAllocator() || !g_vulkan_context->CreateGlobalDescriptorPool() ||
!g_vulkan_context->CreateCommandBuffers() || !g_vulkan_context->CreateTextureStreamBuffer() ||
(enable_surface && (*out_swap_chain = SwapChain::Create(wi_copy, surface, true)) == nullptr))
(enable_surface && (*out_swap_chain = SwapChain::Create(wi_copy, surface, vsync)) == nullptr))
{
// Since we are destroying the instance, we're also responsible for destroying the surface.
if (surface != VK_NULL_HANDLE)

View File

@ -70,7 +70,7 @@ namespace Vulkan
// Creates a new context and sets it up as global.
static bool Create(std::string_view gpu_name, const WindowInfo* wi, std::unique_ptr<SwapChain>* out_swap_chain,
bool threaded_presentation, bool enable_debug_utils, bool enable_validation_layer);
bool vsync, bool threaded_presentation, bool enable_debug_utils, bool enable_validation_layer);
// Destroys context.
static void Destroy();

View File

@ -906,7 +906,7 @@ DisplayWidget* MainWindow::createDisplay(bool fullscreen, bool render_to_main)
}
if (!host_display->CreateRenderDevice(wi.value(), Host::GetStringSettingValue("EmuCore/GS", "Adapter", ""),
Host::GetBoolSettingValue("EmuCore/GS", "ThreadedPresentation", false),
EmuConfig.GetEffectiveVsyncMode(), Host::GetBoolSettingValue("EmuCore/GS", "ThreadedPresentation", false),
Host::GetBoolSettingValue("EmuCore/GS", "UseDebugDevice", false)))
{
QMessageBox::critical(this, tr("Error"), tr("Failed to create host display device context."));

View File

@ -205,10 +205,10 @@ bool D3D11HostDisplay::GetHostRefreshRate(float* refresh_rate)
void D3D11HostDisplay::SetVSync(VsyncMode mode)
{
m_vsync = mode;
m_vsync_mode = mode;
}
bool D3D11HostDisplay::CreateRenderDevice(const WindowInfo& wi, std::string_view adapter_name, bool threaded_presentation, bool debug_device)
bool D3D11HostDisplay::CreateRenderDevice(const WindowInfo& wi, std::string_view adapter_name, VsyncMode vsync, bool threaded_presentation, bool debug_device)
{
UINT create_flags = 0;
if (debug_device)
@ -318,6 +318,7 @@ bool D3D11HostDisplay::CreateRenderDevice(const WindowInfo& wi, std::string_view
}
m_window_info = wi;
m_vsync_mode = vsync;
return true;
}
@ -741,7 +742,7 @@ void D3D11HostDisplay::EndPresent()
ImGui::Render();
ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData());
const UINT vsync_rate = static_cast<UINT>(m_vsync != VsyncMode::Off);
const UINT vsync_rate = static_cast<UINT>(m_vsync_mode != VsyncMode::Off);
if (vsync_rate == 0 && m_using_allow_tearing)
m_swap_chain->Present(0, DXGI_PRESENT_ALLOW_TEARING);
else

View File

@ -42,7 +42,7 @@ public:
bool HasRenderDevice() const override;
bool HasRenderSurface() const override;
bool CreateRenderDevice(const WindowInfo& wi, std::string_view adapter_name, bool threaded_presentation, bool debug_device) override;
bool CreateRenderDevice(const WindowInfo& wi, std::string_view adapter_name, VsyncMode vsync, bool threaded_presentation, bool debug_device) override;
bool InitializeRenderDevice(std::string_view shader_cache_directory, bool debug_device) override;
void DestroyRenderDevice() override;
@ -89,7 +89,6 @@ protected:
ComPtr<IDXGISwapChain> m_swap_chain;
ComPtr<ID3D11RenderTargetView> m_swap_chain_rtv;
VsyncMode m_vsync = VsyncMode::Off;
bool m_allow_tearing_supported = false;
bool m_using_flip_model_swap_chain = true;
bool m_using_allow_tearing = false;

View File

@ -190,7 +190,7 @@ bool OpenGLHostDisplay::HasRenderSurface() const
return m_window_info.type != WindowInfo::Type::Surfaceless;
}
bool OpenGLHostDisplay::CreateRenderDevice(const WindowInfo& wi, std::string_view adapter_name, bool threaded_presentation, bool debug_device)
bool OpenGLHostDisplay::CreateRenderDevice(const WindowInfo& wi, std::string_view adapter_name, VsyncMode vsync, bool threaded_presentation, bool debug_device)
{
m_gl_context = GL::Context::Create(wi);
if (!m_gl_context)
@ -201,17 +201,23 @@ bool OpenGLHostDisplay::CreateRenderDevice(const WindowInfo& wi, std::string_vie
}
m_window_info = m_gl_context->GetWindowInfo();
m_vsync_mode = vsync;
return true;
}
bool OpenGLHostDisplay::InitializeRenderDevice(std::string_view shader_cache_directory, bool debug_device)
{
// Start with vsync off.
m_gl_context->SetSwapInterval(0);
SetSwapInterval();
GL::Program::ResetLastProgram();
return true;
}
void OpenGLHostDisplay::SetSwapInterval()
{
const int interval = ((m_vsync_mode == VsyncMode::Adaptive) ? -1 : ((m_vsync_mode == VsyncMode::On) ? 1 : 0));
m_gl_context->SetSwapInterval(interval);
}
bool OpenGLHostDisplay::MakeRenderContextCurrent()
{
if (!m_gl_context->MakeCurrent())
@ -220,6 +226,7 @@ bool OpenGLHostDisplay::MakeRenderContextCurrent()
return false;
}
SetSwapInterval();
return true;
}

View File

@ -36,7 +36,7 @@ public:
bool HasRenderDevice() const override;
bool HasRenderSurface() const override;
bool CreateRenderDevice(const WindowInfo& wi, std::string_view adapter_name, bool threaded_presentation, bool debug_device) override;
bool CreateRenderDevice(const WindowInfo& wi, std::string_view adapter_name, VsyncMode vsync, bool threaded_presentation, bool debug_device) override;
bool InitializeRenderDevice(std::string_view shader_cache_directory, bool debug_device) override;
void DestroyRenderDevice() override;
@ -68,8 +68,8 @@ protected:
void DestroyImGuiContext() override;
bool UpdateImGuiFontTexture() override;
std::unique_ptr<GL::Context> m_gl_context;
void SetSwapInterval();
VsyncMode m_vsync_mode = VsyncMode::Off;
std::unique_ptr<GL::Context> m_gl_context;
};

View File

@ -85,7 +85,7 @@ bool VulkanHostDisplay::ChangeRenderWindow(const WindowInfo& new_wi)
return false;
}
m_swap_chain = Vulkan::SwapChain::Create(wi_copy, surface, false);
m_swap_chain = Vulkan::SwapChain::Create(wi_copy, surface, m_vsync_mode != VsyncMode::Off);
if (!m_swap_chain)
{
Console.Error("Failed to create swap chain");
@ -216,29 +216,32 @@ void VulkanHostDisplay::UpdateTexture(
void VulkanHostDisplay::SetVSync(VsyncMode mode)
{
if (!m_swap_chain)
if (!m_swap_chain || m_vsync_mode == mode)
return;
// This swap chain should not be used by the current buffer, thus safe to destroy.
g_vulkan_context->WaitForGPUIdle();
m_swap_chain->SetVSync(mode != VsyncMode::Off);
m_vsync_mode = mode;
}
bool VulkanHostDisplay::CreateRenderDevice(
const WindowInfo& wi, std::string_view adapter_name, bool threaded_presentation, bool debug_device)
const WindowInfo& wi, std::string_view adapter_name, VsyncMode vsync, bool threaded_presentation, bool debug_device)
{
// debug_device = true;
WindowInfo local_wi(wi);
if (!Vulkan::Context::Create(
adapter_name, &local_wi, &m_swap_chain, threaded_presentation, debug_device, debug_device))
adapter_name, &local_wi, &m_swap_chain, vsync != VsyncMode::Off, threaded_presentation, debug_device, debug_device))
{
Console.Error("Failed to create Vulkan context");
m_window_info = {};
return false;
}
// NOTE: This is assigned afterwards, because some platforms can modify the window info (e.g. Metal).
m_window_info = m_swap_chain ? m_swap_chain->GetWindowInfo() : local_wi;
m_vsync_mode = vsync;
return true;
}

View File

@ -27,7 +27,7 @@ public:
bool HasRenderDevice() const override;
bool HasRenderSurface() const override;
bool CreateRenderDevice(const WindowInfo& wi, std::string_view adapter_name, bool threaded_presentation, bool debug_device) override;
bool CreateRenderDevice(const WindowInfo& wi, std::string_view adapter_name, VsyncMode vsync, bool threaded_presentation, bool debug_device) override;
bool InitializeRenderDevice(std::string_view shader_cache_directory, bool debug_device) override;
void DestroyRenderDevice() override;

View File

@ -95,7 +95,7 @@ public:
virtual bool HasRenderDevice() const = 0;
virtual bool HasRenderSurface() const = 0;
virtual bool CreateRenderDevice(const WindowInfo& wi, std::string_view adapter_name, bool threaded_presentation, bool debug_device) = 0;
virtual bool CreateRenderDevice(const WindowInfo& wi, std::string_view adapter_name, VsyncMode vsync, bool threaded_presentation, bool debug_device) = 0;
virtual bool InitializeRenderDevice(std::string_view shader_cache_directory, bool debug_device) = 0;
virtual bool MakeRenderContextCurrent() = 0;
virtual bool DoneRenderContextCurrent() = 0;
@ -139,6 +139,7 @@ public:
protected:
WindowInfo m_window_info;
Alignment m_display_alignment = Alignment::Center;
VsyncMode m_vsync_mode = VsyncMode::Off;
};
namespace Host

View File

@ -120,7 +120,8 @@ HostDisplay* Host::AcquireHostDisplay(HostDisplay::RenderAPI api)
if (!s_host_display)
return nullptr;
if (!s_host_display->CreateRenderDevice(g_gs_window_info, GSConfig.Adapter, GSConfig.ThreadedPresentation, GSConfig.UseDebugDevice) ||
if (!s_host_display->CreateRenderDevice(g_gs_window_info, GSConfig.Adapter, EmuConfig.GetEffectiveVsyncMode(),
GSConfig.ThreadedPresentation, GSConfig.UseDebugDevice) ||
!s_host_display->InitializeRenderDevice(StringUtil::wxStringToUTF8String(EmuFolders::Cache.ToString()), GSConfig.UseDebugDevice) ||
!ImGuiManager::Initialize())
{