From 44c8974aba8dbfab844af41ea61a755ffb6bbd55 Mon Sep 17 00:00:00 2001 From: Connor McLaughlin Date: Mon, 10 Oct 2022 22:04:56 +1000 Subject: [PATCH] GS: Set vsync based on host decision Fixes bug where after changing settings in the big picture UI, if you didn't have a game running, it would turn off vsync, making GPU go brr. Also cleans up HostDisplay a bit, removing redundant parameters. --- pcsx2-qt/MainWindow.cpp | 9 ++- pcsx2-qt/QtHost.cpp | 35 +++++++--- pcsx2-qt/QtHost.h | 2 +- pcsx2/Config.h | 2 - pcsx2/Frontend/CommonHotkeys.cpp | 3 +- pcsx2/Frontend/D3D11HostDisplay.cpp | 44 ++++++------ pcsx2/Frontend/D3D11HostDisplay.h | 24 +++---- pcsx2/Frontend/D3D12HostDisplay.cpp | 41 ++++++------ pcsx2/Frontend/D3D12HostDisplay.h | 24 +++---- pcsx2/Frontend/FullscreenUI.cpp | 32 ++------- pcsx2/Frontend/MetalHostDisplay.h | 24 +++---- pcsx2/Frontend/MetalHostDisplay.mm | 37 +++++------ pcsx2/Frontend/OpenGLHostDisplay.cpp | 28 ++++---- pcsx2/Frontend/OpenGLHostDisplay.h | 24 +++---- pcsx2/Frontend/VulkanHostDisplay.cpp | 41 ++++++------ pcsx2/Frontend/VulkanHostDisplay.h | 24 +++---- pcsx2/GS.h | 3 +- pcsx2/GS/GS.cpp | 55 +++++++-------- pcsx2/GS/Renderers/DX11/GSDevice11.cpp | 8 +-- pcsx2/GS/Renderers/Metal/GSDeviceMTL.mm | 10 +-- pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.cpp | 2 +- pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp | 4 +- pcsx2/HostDisplay.cpp | 4 +- pcsx2/HostDisplay.h | 81 ++++++++++++++--------- pcsx2/MTGS.cpp | 9 ++- pcsx2/Pcsx2Config.cpp | 12 ---- pcsx2/VMManager.cpp | 5 +- pcsx2/gui/AppHost.cpp | 21 ++++-- pcsx2/gui/SysCoreThread.cpp | 4 +- 29 files changed, 309 insertions(+), 303 deletions(-) diff --git a/pcsx2-qt/MainWindow.cpp b/pcsx2-qt/MainWindow.cpp index 847580a461..dddf4c1956 100644 --- a/pcsx2-qt/MainWindow.cpp +++ b/pcsx2-qt/MainWindow.cpp @@ -1828,8 +1828,7 @@ DisplayWidget* MainWindow::createDisplay(bool fullscreen, bool render_to_main) g_emu_thread->connectDisplaySignals(m_display_widget); - if (!g_host_display->CreateRenderDevice(wi.value(), Host::GetStringSettingValue("EmuCore/GS", "Adapter", ""), EmuConfig.GetEffectiveVsyncMode(), - Host::GetBoolSettingValue("EmuCore/GS", "ThreadedPresentation", false), Host::GetBoolSettingValue("EmuCore/GS", "UseDebugDevice", false))) + if (!g_host_display->CreateDevice(wi.value())) { QMessageBox::critical(this, tr("Error"), tr("Failed to create host display device context.")); destroyDisplayWidget(true); @@ -1852,7 +1851,7 @@ DisplayWidget* MainWindow::createDisplay(bool fullscreen, bool render_to_main) m_display_widget->updateCursor(s_vm_valid && !s_vm_paused); m_display_widget->setFocus(); - g_host_display->DoneRenderContextCurrent(); + g_host_display->DoneCurrent(); return m_display_widget; } @@ -1904,7 +1903,7 @@ DisplayWidget* MainWindow::updateDisplay(bool fullscreen, bool render_to_main, b return m_display_widget; } - g_host_display->DestroyRenderSurface(); + g_host_display->DestroySurface(); destroyDisplayWidget(surfaceless); @@ -1924,7 +1923,7 @@ DisplayWidget* MainWindow::updateDisplay(bool fullscreen, bool render_to_main, b g_emu_thread->connectDisplaySignals(m_display_widget); - if (!g_host_display->ChangeRenderWindow(wi.value())) + if (!g_host_display->ChangeWindow(wi.value())) pxFailRel("Failed to recreate surface on new widget."); if (is_exclusive_fullscreen) diff --git a/pcsx2-qt/QtHost.cpp b/pcsx2-qt/QtHost.cpp index fc68e98c41..dfedda9f76 100644 --- a/pcsx2-qt/QtHost.cpp +++ b/pcsx2-qt/QtHost.cpp @@ -832,24 +832,24 @@ void EmuThread::updateDisplay() pxAssertRel(!isOnEmuThread(), "Not on emu thread"); // finished with the display for now - g_host_display->DoneRenderContextCurrent(); + g_host_display->DoneCurrent(); // but we should get it back after this call onUpdateDisplayRequested(m_is_fullscreen, !m_is_fullscreen && m_is_rendering_to_main, m_is_surfaceless); - if (!g_host_display->MakeRenderContextCurrent()) + if (!g_host_display->MakeCurrent()) { pxFailRel("Failed to recreate context after updating"); return; } } -bool EmuThread::acquireHostDisplay(HostDisplay::RenderAPI api) +bool EmuThread::acquireHostDisplay(RenderAPI api) { pxAssertRel(!g_host_display, "Host display does not exist on create"); m_is_rendering_to_main = shouldRenderToMain(); m_is_surfaceless = false; - g_host_display = HostDisplay::CreateDisplayForAPI(api); + g_host_display = HostDisplay::CreateForAPI(api); if (!g_host_display) return false; @@ -862,15 +862,14 @@ bool EmuThread::acquireHostDisplay(HostDisplay::RenderAPI api) connectDisplaySignals(widget); - if (!g_host_display->MakeRenderContextCurrent()) + if (!g_host_display->MakeCurrent()) { Console.Error("Failed to make render context current"); releaseHostDisplay(); return false; } - if (!g_host_display->InitializeRenderDevice(EmuFolders::Cache, false) || - !ImGuiManager::Initialize()) + if (!g_host_display->SetupDevice() || !ImGuiManager::Initialize()) { Console.Error("Failed to initialize device/imgui"); releaseHostDisplay(); @@ -899,7 +898,7 @@ void EmuThread::releaseHostDisplay() emit onDestroyDisplayRequested(); } -bool Host::AcquireHostDisplay(HostDisplay::RenderAPI api) +bool Host::AcquireHostDisplay(RenderAPI api) { return g_emu_thread->acquireHostDisplay(api); } @@ -909,6 +908,24 @@ void Host::ReleaseHostDisplay() g_emu_thread->releaseHostDisplay(); } +VsyncMode Host::GetEffectiveVSyncMode() +{ + // Force vsync on when running big picture UI, and paused or no VM. + if (g_emu_thread->isRunningFullscreenUI()) + { + const VMState state = VMManager::GetState(); + if (state == VMState::Shutdown || state == VMState::Paused) + return VsyncMode::On; + } + + // Force vsync off when not running at 100% speed. + if (EmuConfig.GS.LimitScalar != 1.0f) + return VsyncMode::Off; + + // Otherwise use the config setting. + return EmuConfig.GS.VsyncEnable; +} + bool Host::BeginPresentFrame(bool frame_skip) { if (!g_host_display->BeginPresent(frame_skip)) @@ -935,7 +952,7 @@ void Host::EndPresentFrame() void Host::ResizeHostDisplay(u32 new_window_width, u32 new_window_height, float new_window_scale) { - g_host_display->ResizeRenderWindow(new_window_width, new_window_height, new_window_scale); + g_host_display->ResizeWindow(new_window_width, new_window_height, new_window_scale); ImGuiManager::WindowResized(); // if we're paused, re-present the current frame at the new window size. diff --git a/pcsx2-qt/QtHost.h b/pcsx2-qt/QtHost.h index 2d34fa5e71..e1629c62a8 100644 --- a/pcsx2-qt/QtHost.h +++ b/pcsx2-qt/QtHost.h @@ -70,7 +70,7 @@ public: bool shouldRenderToMain() const; /// Called back from the GS thread when the display state changes (e.g. fullscreen, render to main). - bool acquireHostDisplay(HostDisplay::RenderAPI api); + bool acquireHostDisplay(RenderAPI api); void connectDisplaySignals(DisplayWidget* widget); void releaseHostDisplay(); void updateDisplay(); diff --git a/pcsx2/Config.h b/pcsx2/Config.h index c77e9be969..9aa7436089 100644 --- a/pcsx2/Config.h +++ b/pcsx2/Config.h @@ -1089,8 +1089,6 @@ struct Pcsx2Config bool MultitapEnabled(uint port) const; - VsyncMode GetEffectiveVsyncMode() const; - bool operator==(const Pcsx2Config& right) const; bool operator!=(const Pcsx2Config& right) const { diff --git a/pcsx2/Frontend/CommonHotkeys.cpp b/pcsx2/Frontend/CommonHotkeys.cpp index da2523e61c..822471c169 100644 --- a/pcsx2/Frontend/CommonHotkeys.cpp +++ b/pcsx2/Frontend/CommonHotkeys.cpp @@ -22,6 +22,7 @@ #include "Frontend/InputManager.h" #include "GS.h" #include "Host.h" +#include "HostDisplay.h" #include "IconsFontAwesome5.h" #include "Recording/InputRecordingControls.h" #include "VMManager.h" @@ -45,7 +46,7 @@ static void HotkeyAdjustTargetSpeed(double delta) EmuConfig.Framerate.NominalScalar = std::max(min_speed, EmuConfig.GS.LimitScalar + delta); VMManager::SetLimiterMode(LimiterModeType::Nominal); gsUpdateFrequency(EmuConfig); - GetMTGS().SetVSync(EmuConfig.GetEffectiveVsyncMode()); + GetMTGS().UpdateVSyncMode(); Host::AddIconOSDMessage("SpeedChanged", ICON_FA_CLOCK, fmt::format("Target speed set to {:.0f}%.", std::round(EmuConfig.Framerate.NominalScalar * 100.0)), 5.0f); } diff --git a/pcsx2/Frontend/D3D11HostDisplay.cpp b/pcsx2/Frontend/D3D11HostDisplay.cpp index 3521889f23..8a295ba5a3 100644 --- a/pcsx2/Frontend/D3D11HostDisplay.cpp +++ b/pcsx2/Frontend/D3D11HostDisplay.cpp @@ -95,37 +95,37 @@ D3D11HostDisplay::D3D11HostDisplay() = default; D3D11HostDisplay::~D3D11HostDisplay() { - D3D11HostDisplay::DestroyRenderSurface(); + D3D11HostDisplay::DestroySurface(); m_context.reset(); m_device.reset(); } -HostDisplay::RenderAPI D3D11HostDisplay::GetRenderAPI() const +RenderAPI D3D11HostDisplay::GetRenderAPI() const { - return HostDisplay::RenderAPI::D3D11; + return RenderAPI::D3D11; } -void* D3D11HostDisplay::GetRenderDevice() const +void* D3D11HostDisplay::GetDevice() const { return m_device.get(); } -void* D3D11HostDisplay::GetRenderContext() const +void* D3D11HostDisplay::GetContext() const { return m_context.get(); } -void* D3D11HostDisplay::GetRenderSurface() const +void* D3D11HostDisplay::GetSurface() const { return m_swap_chain.get(); } -bool D3D11HostDisplay::HasRenderDevice() const +bool D3D11HostDisplay::HasDevice() const { return static_cast(m_device); } -bool D3D11HostDisplay::HasRenderSurface() const +bool D3D11HostDisplay::HasSurface() const { return static_cast(m_swap_chain); } @@ -210,10 +210,10 @@ void D3D11HostDisplay::SetVSync(VsyncMode mode) m_vsync_mode = mode; } -bool D3D11HostDisplay::CreateRenderDevice(const WindowInfo& wi, std::string_view adapter_name, VsyncMode vsync, bool threaded_presentation, bool debug_device) +bool D3D11HostDisplay::CreateDevice(const WindowInfo& wi) { UINT create_flags = 0; - if (debug_device) + if (EmuConfig.GS.UseDebugDevice) create_flags |= D3D11_CREATE_DEVICE_DEBUG; ComPtr temp_dxgi_factory; @@ -225,17 +225,17 @@ bool D3D11HostDisplay::CreateRenderDevice(const WindowInfo& wi, std::string_view } u32 adapter_index; - if (!adapter_name.empty()) + if (!EmuConfig.GS.Adapter.empty()) { AdapterAndModeList adapter_info(GetAdapterAndModeList(temp_dxgi_factory.get())); for (adapter_index = 0; adapter_index < static_cast(adapter_info.adapter_names.size()); adapter_index++) { - if (adapter_name == adapter_info.adapter_names[adapter_index]) + if (EmuConfig.GS.Adapter == adapter_info.adapter_names[adapter_index]) break; } if (adapter_index == static_cast(adapter_info.adapter_names.size())) { - Console.Warning("Could not find adapter '%s', using first (%s)", std::string(adapter_name).c_str(), + Console.Warning("Could not find adapter '%s', using first (%s)", EmuConfig.GS.Adapter.c_str(), adapter_info.adapter_names[0].c_str()); adapter_index = 0; } @@ -269,7 +269,7 @@ bool D3D11HostDisplay::CreateRenderDevice(const WindowInfo& wi, std::string_view return false; } - if (debug_device && IsDebuggerPresent()) + if (EmuConfig.GS.UseDebugDevice && IsDebuggerPresent()) { ComPtr info; if (m_device.try_query_to(&info)) @@ -314,7 +314,7 @@ bool D3D11HostDisplay::CreateRenderDevice(const WindowInfo& wi, std::string_view } m_window_info = wi; - m_vsync_mode = vsync; + m_vsync_mode = Host::GetEffectiveVSyncMode(); if (m_window_info.type != WindowInfo::Type::Surfaceless && !CreateSwapChain(nullptr)) return false; @@ -322,17 +322,17 @@ bool D3D11HostDisplay::CreateRenderDevice(const WindowInfo& wi, std::string_view return true; } -bool D3D11HostDisplay::InitializeRenderDevice(std::string_view shader_cache_directory, bool debug_device) +bool D3D11HostDisplay::SetupDevice() { return true; } -bool D3D11HostDisplay::MakeRenderContextCurrent() +bool D3D11HostDisplay::MakeCurrent() { return true; } -bool D3D11HostDisplay::DoneRenderContextCurrent() +bool D3D11HostDisplay::DoneCurrent() { return true; } @@ -450,15 +450,15 @@ bool D3D11HostDisplay::CreateSwapChainRTV() return true; } -bool D3D11HostDisplay::ChangeRenderWindow(const WindowInfo& new_wi) +bool D3D11HostDisplay::ChangeWindow(const WindowInfo& new_wi) { - DestroyRenderSurface(); + DestroySurface(); m_window_info = new_wi; return CreateSwapChain(nullptr); } -void D3D11HostDisplay::DestroyRenderSurface() +void D3D11HostDisplay::DestroySurface() { if (IsFullscreen()) SetFullscreen(false, 0, 0, 0.0f); @@ -559,7 +559,7 @@ std::string D3D11HostDisplay::GetDriverInfo() const return ret; } -void D3D11HostDisplay::ResizeRenderWindow(s32 new_window_width, s32 new_window_height, float new_window_scale) +void D3D11HostDisplay::ResizeWindow(s32 new_window_width, s32 new_window_height, float new_window_scale) { if (!m_swap_chain) return; diff --git a/pcsx2/Frontend/D3D11HostDisplay.h b/pcsx2/Frontend/D3D11HostDisplay.h index ea3e982658..6eccfd8afe 100644 --- a/pcsx2/Frontend/D3D11HostDisplay.h +++ b/pcsx2/Frontend/D3D11HostDisplay.h @@ -36,26 +36,26 @@ public: ~D3D11HostDisplay(); RenderAPI GetRenderAPI() const override; - void* GetRenderDevice() const override; - void* GetRenderContext() const override; - void* GetRenderSurface() const override; + void* GetDevice() const override; + void* GetContext() const override; + void* GetSurface() const override; - bool HasRenderDevice() const override; - bool HasRenderSurface() const override; + bool HasDevice() const override; + bool HasSurface() const 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; + bool CreateDevice(const WindowInfo& wi) override; + bool SetupDevice() override; - bool MakeRenderContextCurrent() override; - bool DoneRenderContextCurrent() override; + bool MakeCurrent() override; + bool DoneCurrent() override; - bool ChangeRenderWindow(const WindowInfo& new_wi) override; - void ResizeRenderWindow(s32 new_window_width, s32 new_window_height, float new_window_scale) override; + bool ChangeWindow(const WindowInfo& new_wi) override; + void ResizeWindow(s32 new_window_width, s32 new_window_height, float new_window_scale) override; bool SupportsFullscreen() const override; bool IsFullscreen() override; bool SetFullscreen(bool fullscreen, u32 width, u32 height, float refresh_rate) override; AdapterAndModeList GetAdapterAndModeList() override; - void DestroyRenderSurface() override; + void DestroySurface() override; std::string GetDriverInfo() const override; std::unique_ptr CreateTexture(u32 width, u32 height, const void* data, u32 data_stride, bool dynamic = false) override; diff --git a/pcsx2/Frontend/D3D12HostDisplay.cpp b/pcsx2/Frontend/D3D12HostDisplay.cpp index 16291086fd..dc45c8baea 100644 --- a/pcsx2/Frontend/D3D12HostDisplay.cpp +++ b/pcsx2/Frontend/D3D12HostDisplay.cpp @@ -54,37 +54,37 @@ D3D12HostDisplay::~D3D12HostDisplay() if (g_d3d12_context) { g_d3d12_context->WaitForGPUIdle(); - D3D12HostDisplay::DestroyRenderSurface(); + D3D12HostDisplay::DestroySurface(); g_d3d12_context->Destroy(); } } -HostDisplay::RenderAPI D3D12HostDisplay::GetRenderAPI() const +RenderAPI D3D12HostDisplay::GetRenderAPI() const { - return HostDisplay::RenderAPI::D3D12; + return RenderAPI::D3D12; } -void* D3D12HostDisplay::GetRenderDevice() const +void* D3D12HostDisplay::GetDevice() const { return g_d3d12_context->GetDevice(); } -void* D3D12HostDisplay::GetRenderContext() const +void* D3D12HostDisplay::GetContext() const { return g_d3d12_context.get(); } -void* D3D12HostDisplay::GetRenderSurface() const +void* D3D12HostDisplay::GetSurface() const { return m_swap_chain.get(); } -bool D3D12HostDisplay::HasRenderDevice() const +bool D3D12HostDisplay::HasDevice() const { return static_cast(g_d3d12_context); } -bool D3D12HostDisplay::HasRenderSurface() const +bool D3D12HostDisplay::HasSurface() const { return static_cast(m_swap_chain); } @@ -136,7 +136,7 @@ void D3D12HostDisplay::SetVSync(VsyncMode mode) m_vsync_mode = mode; } -bool D3D12HostDisplay::CreateRenderDevice(const WindowInfo& wi, std::string_view adapter_name, VsyncMode vsync, bool threaded_presentation, bool debug_device) +bool D3D12HostDisplay::CreateDevice(const WindowInfo& wi) { ComPtr temp_dxgi_factory; HRESULT hr = CreateDXGIFactory(IID_PPV_ARGS(temp_dxgi_factory.put())); @@ -147,18 +147,17 @@ bool D3D12HostDisplay::CreateRenderDevice(const WindowInfo& wi, std::string_view } u32 adapter_index; - if (!adapter_name.empty()) + if (!EmuConfig.GS.Adapter.empty()) { AdapterAndModeList adapter_info(GetAdapterAndModeList(temp_dxgi_factory.get())); for (adapter_index = 0; adapter_index < static_cast(adapter_info.adapter_names.size()); adapter_index++) { - if (adapter_name == adapter_info.adapter_names[adapter_index]) + if (EmuConfig.GS.Adapter == adapter_info.adapter_names[adapter_index]) break; } if (adapter_index == static_cast(adapter_info.adapter_names.size())) { - Console.Warning("Could not find adapter '%*s', using first (%s)", static_cast(adapter_name.size()), - adapter_name.data(), adapter_info.adapter_names[0].c_str()); + Console.Warning("Could not find adapter '%s', using first (%s)", EmuConfig.GS.Adapter.c_str(), adapter_info.adapter_names[0].c_str()); adapter_index = 0; } } @@ -168,7 +167,7 @@ bool D3D12HostDisplay::CreateRenderDevice(const WindowInfo& wi, std::string_view adapter_index = 0; } - if (!D3D12::Context::Create(temp_dxgi_factory.get(), adapter_index, debug_device)) + if (!D3D12::Context::Create(temp_dxgi_factory.get(), adapter_index, EmuConfig.GS.UseDebugDevice)) return false; if (FAILED(hr)) @@ -198,17 +197,17 @@ bool D3D12HostDisplay::CreateRenderDevice(const WindowInfo& wi, std::string_view return true; } -bool D3D12HostDisplay::InitializeRenderDevice(std::string_view shader_cache_directory, bool debug_device) +bool D3D12HostDisplay::SetupDevice() { return true; } -bool D3D12HostDisplay::MakeRenderContextCurrent() +bool D3D12HostDisplay::MakeCurrent() { return true; } -bool D3D12HostDisplay::DoneRenderContextCurrent() +bool D3D12HostDisplay::DoneCurrent() { return true; } @@ -323,15 +322,15 @@ void D3D12HostDisplay::DestroySwapChainRTVs() m_current_swap_chain_buffer = 0; } -bool D3D12HostDisplay::ChangeRenderWindow(const WindowInfo& new_wi) +bool D3D12HostDisplay::ChangeWindow(const WindowInfo& new_wi) { - DestroyRenderSurface(); + DestroySurface(); m_window_info = new_wi; return CreateSwapChain(nullptr); } -void D3D12HostDisplay::DestroyRenderSurface() +void D3D12HostDisplay::DestroySurface() { // For some reason if we don't execute the command list here, the swap chain is in use.. not sure where. g_d3d12_context->ExecuteCommandList(true); @@ -428,7 +427,7 @@ std::string D3D12HostDisplay::GetDriverInfo() const return ret; } -void D3D12HostDisplay::ResizeRenderWindow(s32 new_window_width, s32 new_window_height, float new_window_scale) +void D3D12HostDisplay::ResizeWindow(s32 new_window_width, s32 new_window_height, float new_window_scale) { if (!m_swap_chain) return; diff --git a/pcsx2/Frontend/D3D12HostDisplay.h b/pcsx2/Frontend/D3D12HostDisplay.h index 7003131abf..2377cf4fe8 100644 --- a/pcsx2/Frontend/D3D12HostDisplay.h +++ b/pcsx2/Frontend/D3D12HostDisplay.h @@ -42,26 +42,26 @@ public: ~D3D12HostDisplay(); RenderAPI GetRenderAPI() const override; - void* GetRenderDevice() const override; - void* GetRenderContext() const override; - void* GetRenderSurface() const override; + void* GetDevice() const override; + void* GetContext() const override; + void* GetSurface() const override; - bool HasRenderDevice() const override; - bool HasRenderSurface() const override; + bool HasDevice() const override; + bool HasSurface() const 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; + bool CreateDevice(const WindowInfo& wi) override; + bool SetupDevice() override; - bool MakeRenderContextCurrent() override; - bool DoneRenderContextCurrent() override; + bool MakeCurrent() override; + bool DoneCurrent() override; - bool ChangeRenderWindow(const WindowInfo& new_wi) override; - void ResizeRenderWindow(s32 new_window_width, s32 new_window_height, float new_window_scale) override; + bool ChangeWindow(const WindowInfo& new_wi) override; + void ResizeWindow(s32 new_window_width, s32 new_window_height, float new_window_scale) override; bool SupportsFullscreen() const override; bool IsFullscreen() override; bool SetFullscreen(bool fullscreen, u32 width, u32 height, float refresh_rate) override; AdapterAndModeList GetAdapterAndModeList() override; - void DestroyRenderSurface() override; + void DestroySurface() override; std::string GetDriverInfo() const override; std::unique_ptr CreateTexture(u32 width, u32 height, const void* data, u32 data_stride, bool dynamic = false) override; diff --git a/pcsx2/Frontend/FullscreenUI.cpp b/pcsx2/Frontend/FullscreenUI.cpp index 92b106b1da..3a22eecedd 100644 --- a/pcsx2/Frontend/FullscreenUI.cpp +++ b/pcsx2/Frontend/FullscreenUI.cpp @@ -202,7 +202,6 @@ namespace FullscreenUI ////////////////////////////////////////////////////////////////////////// // Main ////////////////////////////////////////////////////////////////////////// - static void UpdateForcedVsync(bool should_force); static void UpdateGameDetails(std::string path, std::string serial, std::string title, u32 crc); static void ToggleTheme(); static void PauseForMenuOpen(); @@ -567,10 +566,6 @@ bool FullscreenUI::Initialize() SwitchToLanding(); } - // force vsync on so we don't run at thousands of fps - // Initialize is called on the GS thread, so we can access the display directly. - UpdateForcedVsync(VMManager::GetState() != VMState::Running); - return true; } @@ -585,15 +580,6 @@ bool FullscreenUI::HasActiveWindow() ImGuiFullscreen::IsFileSelectorOpen(); } -void FullscreenUI::UpdateForcedVsync(bool should_force) -{ - // force vsync on so we don't run at thousands of fps - const VsyncMode mode = EmuConfig.GetEffectiveVsyncMode(); - - // toss it through regardless of the mode, because options can change it - g_host_display->SetVSync((should_force && mode == VsyncMode::Off) ? VsyncMode::On : mode); -} - void FullscreenUI::CheckForConfigChanges(const Pcsx2Config& old_config) { if (!IsInitialized()) @@ -635,12 +621,8 @@ void FullscreenUI::OnVMPaused() if (!IsInitialized()) return; - GetMTGS().RunOnGSThread([]() { - if (!IsInitialized()) - return; - - UpdateForcedVsync(true); - }); + // Force vsync on. + GetMTGS().UpdateVSyncMode(); } void FullscreenUI::OnVMResumed() @@ -648,12 +630,8 @@ void FullscreenUI::OnVMResumed() if (!IsInitialized()) return; - GetMTGS().RunOnGSThread([]() { - if (!IsInitialized()) - return; - - UpdateForcedVsync(false); - }); + // Restore game vsync. + GetMTGS().UpdateVSyncMode(); } void FullscreenUI::OnVMDestroyed() @@ -667,7 +645,7 @@ void FullscreenUI::OnVMDestroyed() s_pause_menu_was_open = false; SwitchToLanding(); - UpdateForcedVsync(true); + GetMTGS().UpdateVSyncMode(); }); } diff --git a/pcsx2/Frontend/MetalHostDisplay.h b/pcsx2/Frontend/MetalHostDisplay.h index ec53ff4146..6698033cbf 100644 --- a/pcsx2/Frontend/MetalHostDisplay.h +++ b/pcsx2/Frontend/MetalHostDisplay.h @@ -51,25 +51,25 @@ public: MetalHostDisplay(); ~MetalHostDisplay(); RenderAPI GetRenderAPI() const override; - void* GetRenderDevice() const override; - void* GetRenderContext() const override; - void* GetRenderSurface() const override; + void* GetDevice() const override; + void* GetContext() const override; + void* GetSurface() const override; - bool HasRenderDevice() const override; - bool HasRenderSurface() const 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; - bool MakeRenderContextCurrent() override; - bool DoneRenderContextCurrent() override; - void DestroyRenderSurface() override; - bool ChangeRenderWindow(const WindowInfo& wi) override; + bool HasDevice() const override; + bool HasSurface() const override; + bool CreateDevice(const WindowInfo& wi) override; + bool SetupDevice() override; + bool MakeCurrent() override; + bool DoneCurrent() override; + void DestroySurface() override; + bool ChangeWindow(const WindowInfo& wi) override; bool SupportsFullscreen() const override; bool IsFullscreen() override; bool SetFullscreen(bool fullscreen, u32 width, u32 height, float refresh_rate) override; AdapterAndModeList GetAdapterAndModeList() override; std::string GetDriverInfo() const override; - void ResizeRenderWindow(s32 new_window_width, s32 new_window_height, float new_window_scale) override; + void ResizeWindow(s32 new_window_width, s32 new_window_height, float new_window_scale) override; std::unique_ptr CreateTexture(u32 width, u32 height, const void* data, u32 data_stride, bool dynamic = false) override; void UpdateTexture(id texture, u32 x, u32 y, u32 width, u32 height, const void* data, u32 data_stride); diff --git a/pcsx2/Frontend/MetalHostDisplay.mm b/pcsx2/Frontend/MetalHostDisplay.mm index 56f55686c0..38c5093dd5 100644 --- a/pcsx2/Frontend/MetalHostDisplay.mm +++ b/pcsx2/Frontend/MetalHostDisplay.mm @@ -49,7 +49,7 @@ MetalHostDisplay::MetalHostDisplay() MetalHostDisplay::~MetalHostDisplay() { - MetalHostDisplay::DestroyRenderSurface(); + MetalHostDisplay::DestroySurface(); m_queue = nullptr; m_dev.Reset(); } @@ -72,16 +72,16 @@ static void OnMainThread(Fn&& fn) dispatch_sync(dispatch_get_main_queue(), fn); } -HostDisplay::RenderAPI MetalHostDisplay::GetRenderAPI() const +RenderAPI MetalHostDisplay::GetRenderAPI() const { return RenderAPI::Metal; } -void* MetalHostDisplay::GetRenderDevice() const { return const_cast(static_cast(&m_dev)); } -void* MetalHostDisplay::GetRenderContext() const { return (__bridge void*)m_queue; } -void* MetalHostDisplay::GetRenderSurface() const { return (__bridge void*)m_layer; } -bool MetalHostDisplay::HasRenderDevice() const { return m_dev.IsOk(); } -bool MetalHostDisplay::HasRenderSurface() const { return static_cast(m_layer);} +void* MetalHostDisplay::GetDevice() const { return const_cast(static_cast(&m_dev)); } +void* MetalHostDisplay::GetContext() const { return (__bridge void*)m_queue; } +void* MetalHostDisplay::GetSurface() const { return (__bridge void*)m_layer; } +bool MetalHostDisplay::HasDevice() const { return m_dev.IsOk(); } +bool MetalHostDisplay::HasSurface() const { return static_cast(m_layer);} void MetalHostDisplay::AttachSurfaceOnMainThread() { @@ -103,12 +103,11 @@ void MetalHostDisplay::DetachSurfaceOnMainThread() m_layer = nullptr; } -bool MetalHostDisplay::CreateRenderDevice(const WindowInfo& wi, std::string_view adapter_name, VsyncMode vsync, bool threaded_presentation, bool debug_device) +bool MetalHostDisplay::CreateDevice(const WindowInfo& wi) { @autoreleasepool { m_window_info = wi; pxAssertRel(!m_dev.dev, "Device already created!"); - std::string null_terminated_adapter_name(adapter_name); - NSString* ns_adapter_name = [NSString stringWithUTF8String:null_terminated_adapter_name.c_str()]; + NSString* ns_adapter_name = [NSString stringWithUTF8String:EmuConfig.GS.Adapter.c_str()]; auto devs = MRCTransfer(MTLCopyAllDevices()); for (id dev in devs.Get()) { @@ -117,8 +116,8 @@ bool MetalHostDisplay::CreateRenderDevice(const WindowInfo& wi, std::string_view } if (!m_dev.dev) { - if (!adapter_name.empty()) - Console.Warning("Metal: Couldn't find adapter %s, using default", null_terminated_adapter_name.c_str()); + if (!EmuConfig.GS.Adapter.empty()) + Console.Warning("Metal: Couldn't find adapter %s, using default", EmuConfig.GS.Adapter.c_str()); m_dev = GSMTLDevice(MRCTransfer(MTLCreateSystemDefaultDevice())); if (!m_dev.dev) Host::ReportErrorAsync("No Metal Devices Available", "No Metal-supporting GPUs were found. PCSX2 requires a Metal GPU (available on all macs from 2012 onwards)."); @@ -146,22 +145,22 @@ bool MetalHostDisplay::CreateRenderDevice(const WindowInfo& wi, std::string_view { AttachSurfaceOnMainThread(); }); - SetVSync(vsync); + SetVSync(Host::GetEffectiveVSyncMode()); return true; } else return false; }} -bool MetalHostDisplay::InitializeRenderDevice(std::string_view shader_cache_directory, bool debug_device) +bool MetalHostDisplay::SetupDevice() { return true; } -bool MetalHostDisplay::MakeRenderContextCurrent() { return true; } -bool MetalHostDisplay::DoneRenderContextCurrent() { return true; } +bool MetalHostDisplay::MakeCurrent() { return true; } +bool MetalHostDisplay::DoneCurrent() { return true; } -void MetalHostDisplay::DestroyRenderSurface() +void MetalHostDisplay::DestroySurface() { if (!m_layer) return; @@ -169,7 +168,7 @@ void MetalHostDisplay::DestroyRenderSurface() m_layer = nullptr; } -bool MetalHostDisplay::ChangeRenderWindow(const WindowInfo& wi) +bool MetalHostDisplay::ChangeWindow(const WindowInfo& wi) { OnMainThread([this, &wi] { @@ -201,7 +200,7 @@ std::string MetalHostDisplay::GetDriverInfo() const return desc; }} -void MetalHostDisplay::ResizeRenderWindow(s32 new_window_width, s32 new_window_height, float new_window_scale) +void MetalHostDisplay::ResizeWindow(s32 new_window_width, s32 new_window_height, float new_window_scale) { m_window_info.surface_scale = new_window_scale; if (m_window_info.surface_width == static_cast(new_window_width) && m_window_info.surface_height == static_cast(new_window_height)) diff --git a/pcsx2/Frontend/OpenGLHostDisplay.cpp b/pcsx2/Frontend/OpenGLHostDisplay.cpp index b37d428cfd..b6a332460d 100644 --- a/pcsx2/Frontend/OpenGLHostDisplay.cpp +++ b/pcsx2/Frontend/OpenGLHostDisplay.cpp @@ -60,22 +60,22 @@ OpenGLHostDisplay::~OpenGLHostDisplay() } } -HostDisplay::RenderAPI OpenGLHostDisplay::GetRenderAPI() const +RenderAPI OpenGLHostDisplay::GetRenderAPI() const { return m_gl_context->IsGLES() ? RenderAPI::OpenGLES : RenderAPI::OpenGL; } -void* OpenGLHostDisplay::GetRenderDevice() const +void* OpenGLHostDisplay::GetDevice() const { return nullptr; } -void* OpenGLHostDisplay::GetRenderContext() const +void* OpenGLHostDisplay::GetContext() const { return m_gl_context.get(); } -void* OpenGLHostDisplay::GetRenderSurface() const +void* OpenGLHostDisplay::GetSurface() const { return nullptr; } @@ -188,17 +188,17 @@ std::string OpenGLHostDisplay::GetGLSLVersionHeader() const return header; } -bool OpenGLHostDisplay::HasRenderDevice() const +bool OpenGLHostDisplay::HasDevice() const { return static_cast(m_gl_context); } -bool OpenGLHostDisplay::HasRenderSurface() const +bool OpenGLHostDisplay::HasSurface() const { return m_window_info.type != WindowInfo::Type::Surfaceless; } -bool OpenGLHostDisplay::CreateRenderDevice(const WindowInfo& wi, std::string_view adapter_name, VsyncMode vsync, bool threaded_presentation, bool debug_device) +bool OpenGLHostDisplay::CreateDevice(const WindowInfo& wi) { m_gl_context = GL::Context::Create(wi); if (!m_gl_context) @@ -209,11 +209,11 @@ bool OpenGLHostDisplay::CreateRenderDevice(const WindowInfo& wi, std::string_vie } m_window_info = m_gl_context->GetWindowInfo(); - m_vsync_mode = vsync; + m_vsync_mode = Host::GetEffectiveVSyncMode(); return true; } -bool OpenGLHostDisplay::InitializeRenderDevice(std::string_view shader_cache_directory, bool debug_device) +bool OpenGLHostDisplay::SetupDevice() { SetSwapInterval(); GL::Program::ResetLastProgram(); @@ -226,7 +226,7 @@ void OpenGLHostDisplay::SetSwapInterval() m_gl_context->SetSwapInterval(interval); } -bool OpenGLHostDisplay::MakeRenderContextCurrent() +bool OpenGLHostDisplay::MakeCurrent() { if (!m_gl_context->MakeCurrent()) { @@ -238,12 +238,12 @@ bool OpenGLHostDisplay::MakeRenderContextCurrent() return true; } -bool OpenGLHostDisplay::DoneRenderContextCurrent() +bool OpenGLHostDisplay::DoneCurrent() { return m_gl_context->DoneCurrent(); } -bool OpenGLHostDisplay::ChangeRenderWindow(const WindowInfo& new_wi) +bool OpenGLHostDisplay::ChangeWindow(const WindowInfo& new_wi) { pxAssert(m_gl_context); @@ -265,7 +265,7 @@ bool OpenGLHostDisplay::ChangeRenderWindow(const WindowInfo& new_wi) return true; } -void OpenGLHostDisplay::ResizeRenderWindow(s32 new_window_width, s32 new_window_height, float new_window_scale) +void OpenGLHostDisplay::ResizeWindow(s32 new_window_width, s32 new_window_height, float new_window_scale) { if (!m_gl_context) return; @@ -309,7 +309,7 @@ HostDisplay::AdapterAndModeList OpenGLHostDisplay::GetAdapterAndModeList() return aml; } -void OpenGLHostDisplay::DestroyRenderSurface() +void OpenGLHostDisplay::DestroySurface() { if (!m_gl_context) return; diff --git a/pcsx2/Frontend/OpenGLHostDisplay.h b/pcsx2/Frontend/OpenGLHostDisplay.h index 2af6683648..345592e251 100644 --- a/pcsx2/Frontend/OpenGLHostDisplay.h +++ b/pcsx2/Frontend/OpenGLHostDisplay.h @@ -31,26 +31,26 @@ public: ~OpenGLHostDisplay(); RenderAPI GetRenderAPI() const override; - void* GetRenderDevice() const override; - void* GetRenderContext() const override; - void* GetRenderSurface() const override; + void* GetDevice() const override; + void* GetContext() const override; + void* GetSurface() const override; - bool HasRenderDevice() const override; - bool HasRenderSurface() const override; + bool HasDevice() const override; + bool HasSurface() const 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; + bool CreateDevice(const WindowInfo& wi) override; + bool SetupDevice() override; - bool MakeRenderContextCurrent() override; - bool DoneRenderContextCurrent() override; + bool MakeCurrent() override; + bool DoneCurrent() override; - bool ChangeRenderWindow(const WindowInfo& new_wi) override; - void ResizeRenderWindow(s32 new_window_width, s32 new_window_height, float new_window_scale) override; + bool ChangeWindow(const WindowInfo& new_wi) override; + void ResizeWindow(s32 new_window_width, s32 new_window_height, float new_window_scale) override; bool SupportsFullscreen() const override; bool IsFullscreen() override; bool SetFullscreen(bool fullscreen, u32 width, u32 height, float refresh_rate) override; AdapterAndModeList GetAdapterAndModeList() override; - void DestroyRenderSurface() override; + void DestroySurface() override; std::string GetDriverInfo() const override; std::unique_ptr CreateTexture(u32 width, u32 height, const void* data, u32 data_stride, bool dynamic) override; diff --git a/pcsx2/Frontend/VulkanHostDisplay.cpp b/pcsx2/Frontend/VulkanHostDisplay.cpp index 7e9994b5c2..75847d224e 100644 --- a/pcsx2/Frontend/VulkanHostDisplay.cpp +++ b/pcsx2/Frontend/VulkanHostDisplay.cpp @@ -61,27 +61,27 @@ VulkanHostDisplay::~VulkanHostDisplay() } } -HostDisplay::RenderAPI VulkanHostDisplay::GetRenderAPI() const +RenderAPI VulkanHostDisplay::GetRenderAPI() const { - return HostDisplay::RenderAPI::Vulkan; + return RenderAPI::Vulkan; } -void* VulkanHostDisplay::GetRenderDevice() const +void* VulkanHostDisplay::GetDevice() const { return nullptr; } -void* VulkanHostDisplay::GetRenderContext() const +void* VulkanHostDisplay::GetContext() const { return nullptr; } -void* VulkanHostDisplay::GetRenderSurface() const +void* VulkanHostDisplay::GetSurface() const { return m_swap_chain.get(); } -bool VulkanHostDisplay::ChangeRenderWindow(const WindowInfo& new_wi) +bool VulkanHostDisplay::ChangeWindow(const WindowInfo& new_wi) { g_vulkan_context->WaitForGPUIdle(); @@ -126,7 +126,7 @@ bool VulkanHostDisplay::ChangeRenderWindow(const WindowInfo& new_wi) return true; } -void VulkanHostDisplay::ResizeRenderWindow(s32 new_window_width, s32 new_window_height, float new_window_scale) +void VulkanHostDisplay::ResizeWindow(s32 new_window_width, s32 new_window_height, float new_window_scale) { if (m_swap_chain->GetWidth() == static_cast(new_window_width) && m_swap_chain->GetHeight() == static_cast(new_window_height)) { @@ -167,7 +167,7 @@ HostDisplay::AdapterAndModeList VulkanHostDisplay::GetAdapterAndModeList() return StaticGetAdapterAndModeList(m_window_info.type != WindowInfo::Type::Surfaceless ? &m_window_info : nullptr); } -void VulkanHostDisplay::DestroyRenderSurface() +void VulkanHostDisplay::DestroySurface() { g_vulkan_context->WaitForGPUIdle(); m_swap_chain.reset(); @@ -275,14 +275,13 @@ void VulkanHostDisplay::SetVSync(VsyncMode mode) m_vsync_mode = mode; } -bool VulkanHostDisplay::CreateRenderDevice( - const WindowInfo& wi, std::string_view adapter_name, VsyncMode vsync, bool threaded_presentation, bool debug_device) +bool VulkanHostDisplay::CreateDevice(const WindowInfo& wi) { - // debug_device = true; - WindowInfo local_wi(wi); - if (!Vulkan::Context::Create(adapter_name, &local_wi, &m_swap_chain, GetPreferredPresentModeForVsyncMode(vsync), threaded_presentation, - debug_device, debug_device)) + const VsyncMode vsync = Host::GetEffectiveVSyncMode(); + const bool debug_device = EmuConfig.GS.UseDebugDevice; + if (!Vulkan::Context::Create(EmuConfig.GS.Adapter, &local_wi, &m_swap_chain, GetPreferredPresentModeForVsyncMode(vsync), + EmuConfig.GS.ThreadedPresentation, debug_device, debug_device)) { Console.Error("Failed to create Vulkan context"); m_window_info = {}; @@ -295,18 +294,18 @@ bool VulkanHostDisplay::CreateRenderDevice( return true; } -bool VulkanHostDisplay::InitializeRenderDevice(std::string_view shader_cache_directory, bool debug_device) +bool VulkanHostDisplay::SetupDevice() { - Vulkan::ShaderCache::Create(shader_cache_directory, SHADER_CACHE_VERSION, debug_device); + Vulkan::ShaderCache::Create(EmuFolders::Cache, SHADER_CACHE_VERSION, EmuConfig.GS.UseDebugDevice); return true; } -bool VulkanHostDisplay::HasRenderDevice() const +bool VulkanHostDisplay::HasDevice() const { return static_cast(g_vulkan_context); } -bool VulkanHostDisplay::HasRenderSurface() const +bool VulkanHostDisplay::HasSurface() const { return static_cast(m_swap_chain); } @@ -327,12 +326,12 @@ bool VulkanHostDisplay::UpdateImGuiFontTexture() return ImGui_ImplVulkan_CreateFontsTexture(); } -bool VulkanHostDisplay::MakeRenderContextCurrent() +bool VulkanHostDisplay::MakeCurrent() { return true; } -bool VulkanHostDisplay::DoneRenderContextCurrent() +bool VulkanHostDisplay::DoneCurrent() { return true; } @@ -353,7 +352,7 @@ bool VulkanHostDisplay::BeginPresent(bool frame_skip) { if (res == VK_SUBOPTIMAL_KHR || res == VK_ERROR_OUT_OF_DATE_KHR) { - ResizeRenderWindow(0, 0, m_window_info.surface_scale); + ResizeWindow(0, 0, m_window_info.surface_scale); res = m_swap_chain->AcquireNextImage(); } else if (res == VK_ERROR_SURFACE_LOST_KHR) diff --git a/pcsx2/Frontend/VulkanHostDisplay.h b/pcsx2/Frontend/VulkanHostDisplay.h index 90d0a4f42d..f308cc1cbc 100644 --- a/pcsx2/Frontend/VulkanHostDisplay.h +++ b/pcsx2/Frontend/VulkanHostDisplay.h @@ -20,26 +20,26 @@ public: ~VulkanHostDisplay(); RenderAPI GetRenderAPI() const override; - void* GetRenderDevice() const override; - void* GetRenderContext() const override; - void* GetRenderSurface() const override; + void* GetDevice() const override; + void* GetContext() const override; + void* GetSurface() const override; - bool HasRenderDevice() const override; - bool HasRenderSurface() const override; + bool HasDevice() const override; + bool HasSurface() const 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; + bool CreateDevice(const WindowInfo& wi) override; + bool SetupDevice() override; - bool MakeRenderContextCurrent() override; - bool DoneRenderContextCurrent() override; + bool MakeCurrent() override; + bool DoneCurrent() override; - bool ChangeRenderWindow(const WindowInfo& new_wi) override; - void ResizeRenderWindow(s32 new_window_width, s32 new_window_height, float new_window_scale) override; + bool ChangeWindow(const WindowInfo& new_wi) override; + void ResizeWindow(s32 new_window_width, s32 new_window_height, float new_window_scale) override; bool SupportsFullscreen() const override; bool IsFullscreen() override; bool SetFullscreen(bool fullscreen, u32 width, u32 height, float refresh_rate) override; AdapterAndModeList GetAdapterAndModeList() override; - void DestroyRenderSurface() override; + void DestroySurface() override; std::string GetDriverInfo() const override; std::unique_ptr CreateTexture(u32 width, u32 height, const void* data, u32 data_stride, bool dynamic = false) override; diff --git a/pcsx2/GS.h b/pcsx2/GS.h index 87e8a67d8f..6b8ede1d51 100644 --- a/pcsx2/GS.h +++ b/pcsx2/GS.h @@ -413,7 +413,8 @@ public: void ApplySettings(); void ResizeDisplayWindow(int width, int height, float scale); void UpdateDisplayWindow(); - void SetVSync(VsyncMode mode); + void SetVSyncMode(VsyncMode mode); + void UpdateVSyncMode(); void SwitchRenderer(GSRendererType renderer, bool display_message = true); void SetSoftwareRendering(bool software, bool display_message = true); void ToggleSoftwareRendering(); diff --git a/pcsx2/GS/GS.cpp b/pcsx2/GS/GS.cpp index 19f9bf533a..177e9318d3 100644 --- a/pcsx2/GS/GS.cpp +++ b/pcsx2/GS/GS.cpp @@ -76,7 +76,7 @@ static HRESULT s_hr = E_FAIL; Pcsx2Config::GSOptions GSConfig; -static HostDisplay::RenderAPI s_render_api; +static RenderAPI s_render_api; int GSinit() { @@ -164,45 +164,45 @@ void GSclose() Host::ReleaseHostDisplay(); } -static HostDisplay::RenderAPI GetAPIForRenderer(GSRendererType renderer) +static RenderAPI GetAPIForRenderer(GSRendererType renderer) { #if defined(_WIN32) // On Windows, we use DX11 for software, since it's always available. - constexpr HostDisplay::RenderAPI default_api = HostDisplay::RenderAPI::D3D11; + constexpr RenderAPI default_api = RenderAPI::D3D11; #elif defined(__APPLE__) // For Macs, default to Metal. - constexpr HostDisplay::RenderAPI default_api = HostDisplay::RenderAPI::Metal; + constexpr RenderAPI default_api = RenderAPI::Metal; #else // For Linux, default to OpenGL (because of hardware compatibility), if we // have it, otherwise Vulkan (if we have it). #if defined(ENABLE_OPENGL) - constexpr HostDisplay::RenderAPI default_api = HostDisplay::RenderAPI::OpenGL; + constexpr RenderAPI default_api = RenderAPI::OpenGL; #elif defined(ENABLE_VULKAN) - constexpr HostDisplay::RenderAPI default_api = HostDisplay::RenderAPI::Vulkan; + constexpr RenderAPI default_api = RenderAPI::Vulkan; #else - constexpr HostDisplay::RenderAPI default_api = HostDisplay::RenderAPI::None; + constexpr RenderAPI default_api = RenderAPI::None; #endif #endif switch (renderer) { case GSRendererType::OGL: - return HostDisplay::RenderAPI::OpenGL; + return RenderAPI::OpenGL; case GSRendererType::VK: - return HostDisplay::RenderAPI::Vulkan; + return RenderAPI::Vulkan; #ifdef _WIN32 case GSRendererType::DX11: - return HostDisplay::RenderAPI::D3D11; + return RenderAPI::D3D11; case GSRendererType::DX12: - return HostDisplay::RenderAPI::D3D12; + return RenderAPI::D3D12; #endif #ifdef __APPLE__ case GSRendererType::Metal: - return HostDisplay::RenderAPI::Metal; + return RenderAPI::Metal; #endif default: @@ -217,27 +217,27 @@ static bool DoGSOpen(GSRendererType renderer, u8* basemem) switch (g_host_display->GetRenderAPI()) { #ifdef _WIN32 - case HostDisplay::RenderAPI::D3D11: + case RenderAPI::D3D11: g_gs_device = std::make_unique(); break; - case HostDisplay::RenderAPI::D3D12: + case RenderAPI::D3D12: g_gs_device = std::make_unique(); break; #endif #ifdef __APPLE__ - case HostDisplay::RenderAPI::Metal: + case RenderAPI::Metal: g_gs_device = std::unique_ptr(MakeGSDeviceMTL()); break; #endif #ifdef ENABLE_OPENGL - case HostDisplay::RenderAPI::OpenGL: - case HostDisplay::RenderAPI::OpenGLES: + case RenderAPI::OpenGL: + case RenderAPI::OpenGLES: g_gs_device = std::make_unique(); break; #endif #ifdef ENABLE_VULKAN - case HostDisplay::RenderAPI::Vulkan: + case RenderAPI::Vulkan: g_gs_device = std::make_unique(); break; #endif @@ -279,13 +279,6 @@ static bool DoGSOpen(GSRendererType renderer, u8* basemem) return false; } -#ifdef PCSX2_CORE - // Don't override the fullscreen UI's vsync choice. - if (!FullscreenUI::IsInitialized()) - g_host_display->SetVSync(EmuConfig.GetEffectiveVsyncMode()); -#else - g_host_display->SetVSync(EmuConfig.GetEffectiveVsyncMode()); -#endif GSConfig.OsdShowGPU = EmuConfig.GS.OsdShowGPU && g_host_display->SetGPUTimingEnabled(true); g_gs_renderer->SetRegsMem(basemem); @@ -774,9 +767,9 @@ void GSUpdateConfig(const Pcsx2Config::GSOptions& new_config) // Options which need a full teardown/recreate. if (!GSConfig.RestartOptionsAreEqual(old_config)) { - HostDisplay::RenderAPI existing_api = g_host_display->GetRenderAPI(); - if (existing_api == HostDisplay::RenderAPI::OpenGLES) - existing_api = HostDisplay::RenderAPI::OpenGL; + RenderAPI existing_api = g_host_display->GetRenderAPI(); + if (existing_api == RenderAPI::OpenGLES) + existing_api = RenderAPI::OpenGL; const bool do_full_restart = ( existing_api != GetAPIForRenderer(GSConfig.Renderer) || @@ -877,9 +870,9 @@ void GSSwitchRenderer(GSRendererType new_renderer) if (!g_gs_renderer || GSConfig.Renderer == new_renderer) return; - HostDisplay::RenderAPI existing_api = g_host_display->GetRenderAPI(); - if (existing_api == HostDisplay::RenderAPI::OpenGLES) - existing_api = HostDisplay::RenderAPI::OpenGL; + RenderAPI existing_api = g_host_display->GetRenderAPI(); + if (existing_api == RenderAPI::OpenGLES) + existing_api = RenderAPI::OpenGL; const bool is_software_switch = (new_renderer == GSRendererType::SW || GSConfig.Renderer == GSRendererType::SW); const bool recreate_display = (!is_software_switch && existing_api != GetAPIForRenderer(new_renderer)); diff --git a/pcsx2/GS/Renderers/DX11/GSDevice11.cpp b/pcsx2/GS/Renderers/DX11/GSDevice11.cpp index fdbfe51775..97cb387c28 100644 --- a/pcsx2/GS/Renderers/DX11/GSDevice11.cpp +++ b/pcsx2/GS/Renderers/DX11/GSDevice11.cpp @@ -79,14 +79,14 @@ bool GSDevice11::Create() D3D_FEATURE_LEVEL level; - if (g_host_display->GetRenderAPI() != HostDisplay::RenderAPI::D3D11) + if (g_host_display->GetRenderAPI() != RenderAPI::D3D11) { - fprintf(stderr, "Render API is incompatible with D3D11\n"); + Console.Error("Render API is incompatible with D3D11"); return false; } - m_dev = static_cast(g_host_display->GetRenderDevice()); - m_ctx = static_cast(g_host_display->GetRenderContext()); + m_dev = static_cast(g_host_display->GetDevice()); + m_ctx = static_cast(g_host_display->GetContext()); level = m_dev->GetFeatureLevel(); if (!GSConfig.DisableShaderCache) diff --git a/pcsx2/GS/Renderers/Metal/GSDeviceMTL.mm b/pcsx2/GS/Renderers/Metal/GSDeviceMTL.mm index 69198e70c5..6fa6a3b8a3 100644 --- a/pcsx2/GS/Renderers/Metal/GSDeviceMTL.mm +++ b/pcsx2/GS/Renderers/Metal/GSDeviceMTL.mm @@ -581,14 +581,14 @@ bool GSDeviceMTL::Create() if (!GSDevice::Create()) return false; - if (g_host_display->GetRenderAPI() != HostDisplay::RenderAPI::Metal) + if (g_host_display->GetRenderAPI() != RenderAPI::Metal) return false; - if (!g_host_display->HasRenderDevice() || !g_host_display->HasRenderSurface()) + if (!g_host_display->HasDevice() || !g_host_display->HasSurface()) return false; - m_dev = *static_cast(g_host_display->GetRenderDevice()); - m_queue = MRCRetain((__bridge id)g_host_display->GetRenderContext()); - MTLPixelFormat layer_px_fmt = [(__bridge CAMetalLayer*)g_host_display->GetRenderSurface() pixelFormat]; + m_dev = *static_cast(g_host_display->GetDevice()); + m_queue = MRCRetain((__bridge id)g_host_display->GetContext()); + MTLPixelFormat layer_px_fmt = [(__bridge CAMetalLayer*)g_host_display->GetSurface() pixelFormat]; m_features.broken_point_sampler = [[m_dev.dev name] containsString:@"AMD"]; m_features.geometry_shader = false; diff --git a/pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.cpp b/pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.cpp index 72c8323d43..2415a4641b 100644 --- a/pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.cpp +++ b/pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.cpp @@ -196,7 +196,7 @@ bool GSDeviceOGL::Create() if (!GSDevice::Create()) return false; - if (g_host_display->GetRenderAPI() != HostDisplay::RenderAPI::OpenGL) + if (g_host_display->GetRenderAPI() != RenderAPI::OpenGL) return false; // Check openGL requirement as soon as possible so we can switch to another diff --git a/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp b/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp index 5f999e90e5..41537e36cb 100644 --- a/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp +++ b/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp @@ -1308,7 +1308,7 @@ bool GSDeviceVK::CreateRenderPasses() bool GSDeviceVK::CompileConvertPipelines() { // we may not have a swap chain if running in headless mode. - Vulkan::SwapChain* swapchain = static_cast(g_host_display->GetRenderSurface()); + Vulkan::SwapChain* swapchain = static_cast(g_host_display->GetSurface()); if (swapchain) { m_swap_chain_render_pass = @@ -1506,7 +1506,7 @@ bool GSDeviceVK::CompileConvertPipelines() bool GSDeviceVK::CompilePresentPipelines() { // we may not have a swap chain if running in headless mode. - Vulkan::SwapChain* swapchain = static_cast(g_host_display->GetRenderSurface()); + Vulkan::SwapChain* swapchain = static_cast(g_host_display->GetSurface()); if (swapchain) { m_swap_chain_render_pass = diff --git a/pcsx2/HostDisplay.cpp b/pcsx2/HostDisplay.cpp index 8c812a799a..cdcb38e817 100644 --- a/pcsx2/HostDisplay.cpp +++ b/pcsx2/HostDisplay.cpp @@ -142,7 +142,7 @@ std::string HostDisplay::GetFullscreenModeString(u32 width, u32 height, float re #endif #include "GS/Renderers/Metal/GSMetalCPPAccessible.h" -std::unique_ptr HostDisplay::CreateDisplayForAPI(RenderAPI api) +std::unique_ptr HostDisplay::CreateForAPI(RenderAPI api) { switch (api) { @@ -153,7 +153,7 @@ std::unique_ptr HostDisplay::CreateDisplayForAPI(RenderAPI api) return std::make_unique(); #endif #ifdef __APPLE__ - case HostDisplay::RenderAPI::Metal: + case RenderAPI::Metal: return std::unique_ptr(MakeMetalHostDisplay()); #endif diff --git a/pcsx2/HostDisplay.h b/pcsx2/HostDisplay.h index ba1d31181a..058bfec5c1 100644 --- a/pcsx2/HostDisplay.h +++ b/pcsx2/HostDisplay.h @@ -27,6 +27,17 @@ #include "Host.h" #include "Config.h" +enum class RenderAPI +{ + None, + D3D11, + Metal, + D3D12, + Vulkan, + OpenGL, + OpenGLES +}; + /// An abstracted RGBA8 texture. class HostDisplayTexture { @@ -42,17 +53,6 @@ public: class HostDisplay { public: - enum class RenderAPI - { - None, - D3D11, - Metal, - D3D12, - Vulkan, - OpenGL, - OpenGLES - }; - enum class Alignment { LeftOrTop, @@ -72,7 +72,7 @@ public: static const char* RenderAPIToString(RenderAPI api); /// Creates a display for the specified API. - static std::unique_ptr CreateDisplayForAPI(RenderAPI api); + static std::unique_ptr CreateForAPI(RenderAPI api); /// Parses a fullscreen mode into its components (width * height @ refresh hz) static bool ParseFullscreenMode(const std::string_view& mode, u32* width, u32* height, float* refresh_rate); @@ -90,27 +90,45 @@ public: __fi void SetDisplayAlignment(Alignment alignment) { m_display_alignment = alignment; } virtual RenderAPI GetRenderAPI() const = 0; - virtual void* GetRenderDevice() const = 0; - virtual void* GetRenderContext() const = 0; - virtual void* GetRenderSurface() const = 0; + virtual void* GetDevice() const = 0; + virtual void* GetContext() const = 0; + virtual void* GetSurface() const = 0; - virtual bool HasRenderDevice() const = 0; - virtual bool HasRenderSurface() const = 0; + virtual bool HasDevice() const = 0; + virtual bool HasSurface() const = 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; - virtual void DestroyRenderSurface() = 0; - virtual bool ChangeRenderWindow(const WindowInfo& wi) = 0; - virtual bool SupportsFullscreen() const = 0; - virtual bool IsFullscreen() = 0; - virtual bool SetFullscreen(bool fullscreen, u32 width, u32 height, float refresh_rate) = 0; - virtual AdapterAndModeList GetAdapterAndModeList() = 0; - virtual std::string GetDriverInfo() const = 0; + /// Creates the rendering/GPU device. This should be called on the thread which owns the window. + virtual bool CreateDevice(const WindowInfo& wi) = 0; + + /// Fully initializes the rendering device. This should be called on the GS thread. + virtual bool SetupDevice() = 0; + + /// Sets the device for the current thread. Only needed for OpenGL. + virtual bool MakeCurrent() = 0; + + /// Clears the device for the current thread. Only needed for OpenGL. + virtual bool DoneCurrent() = 0; + + /// Destroys the surface we're currently drawing to. + virtual void DestroySurface() = 0; + + /// Switches to a new window/surface. + virtual bool ChangeWindow(const WindowInfo& wi) = 0; /// Call when the window size changes externally to recreate any resources. - virtual void ResizeRenderWindow(s32 new_window_width, s32 new_window_height, float new_window_scale) = 0; + virtual void ResizeWindow(s32 new_window_width, s32 new_window_height, float new_window_scale) = 0; + + /// Returns true if exclusive fullscreen is supported. + virtual bool SupportsFullscreen() const = 0; + + /// Returns true if exclusive fullscreen is active. + virtual bool IsFullscreen() = 0; + + /// Attempts to switch to the specified mode in exclusive fullscreen. + virtual bool SetFullscreen(bool fullscreen, u32 width, u32 height, float refresh_rate) = 0; + + virtual AdapterAndModeList GetAdapterAndModeList() = 0; + virtual std::string GetDriverInfo() const = 0; /// Creates an abstracted RGBA8 texture. If dynamic, the texture can be updated with UpdateTexture() below. virtual std::unique_ptr CreateTexture(u32 width, u32 height, const void* data, u32 data_stride, bool dynamic = false) = 0; @@ -155,11 +173,14 @@ extern std::unique_ptr g_host_display; namespace Host { /// Creates the host display. This may create a new window. The API used depends on the current configuration. - bool AcquireHostDisplay(HostDisplay::RenderAPI api); + bool AcquireHostDisplay(RenderAPI api); /// Destroys the host display. This may close the display window. void ReleaseHostDisplay(); + /// Returns the desired vsync mode, depending on the runtime environment. + VsyncMode GetEffectiveVSyncMode(); + /// Returns false if the window was completely occluded. If frame_skip is set, the frame won't be /// displayed, but the GPU command queue will still be flushed. bool BeginPresentFrame(bool frame_skip); diff --git a/pcsx2/MTGS.cpp b/pcsx2/MTGS.cpp index 8d40ad0a9d..c8e94e71eb 100644 --- a/pcsx2/MTGS.cpp +++ b/pcsx2/MTGS.cpp @@ -935,6 +935,7 @@ void SysMtgsThread::ApplySettings() RunOnGSThread([opts = EmuConfig.GS]() { GSUpdateConfig(opts); + g_host_display->SetVSync(Host::GetEffectiveVSyncMode()); }); // We need to synchronize the thread when changing any settings when the download mode @@ -964,15 +965,21 @@ void SysMtgsThread::UpdateDisplayWindow() }); } -void SysMtgsThread::SetVSync(VsyncMode mode) +void SysMtgsThread::SetVSyncMode(VsyncMode mode) { pxAssertRel(IsOpen(), "MTGS is running"); RunOnGSThread([mode]() { + Console.WriteLn("Vsync is %s", mode == VsyncMode::Off ? "OFF" : (mode == VsyncMode::Adaptive ? "ADAPTIVE" : "ON")); g_host_display->SetVSync(mode); }); } +void SysMtgsThread::UpdateVSyncMode() +{ + SetVSyncMode(Host::GetEffectiveVSyncMode()); +} + void SysMtgsThread::SwitchRenderer(GSRendererType renderer, bool display_message /* = true */) { pxAssertRel(IsOpen(), "MTGS is running"); diff --git a/pcsx2/Pcsx2Config.cpp b/pcsx2/Pcsx2Config.cpp index 32f15c1ffb..876bef4731 100644 --- a/pcsx2/Pcsx2Config.cpp +++ b/pcsx2/Pcsx2Config.cpp @@ -678,18 +678,6 @@ bool Pcsx2Config::GSOptions::UseHardwareRenderer() const return (Renderer != GSRendererType::Null && Renderer != GSRendererType::SW); } -VsyncMode Pcsx2Config::GetEffectiveVsyncMode() const -{ - if (GS.LimitScalar != 1.0f) - { - Console.WriteLn("Vsync is OFF"); - return VsyncMode::Off; - } - - Console.WriteLn("Vsync is %s", GS.VsyncEnable == VsyncMode::Off ? "OFF" : (GS.VsyncEnable == VsyncMode::Adaptive ? "ADAPTIVE" : "ON")); - return GS.VsyncEnable; -} - Pcsx2Config::SPU2Options::SPU2Options() { bitset = 0; diff --git a/pcsx2/VMManager.cpp b/pcsx2/VMManager.cpp index 986b46edfe..5cc658107e 100644 --- a/pcsx2/VMManager.cpp +++ b/pcsx2/VMManager.cpp @@ -1377,7 +1377,7 @@ void VMManager::SetLimiterMode(LimiterModeType type) EmuConfig.LimiterMode = type; gsUpdateFrequency(EmuConfig); - GetMTGS().SetVSync(EmuConfig.GetEffectiveVsyncMode()); + GetMTGS().UpdateVSyncMode(); } void VMManager::FrameAdvance(u32 num_frames /*= 1*/) @@ -1586,7 +1586,6 @@ void VMManager::CheckForGSConfigChanges(const Pcsx2Config& old_config) UpdateVSyncRate(); frameLimitReset(); GetMTGS().ApplySettings(); - GetMTGS().SetVSync(EmuConfig.GetEffectiveVsyncMode()); } void VMManager::CheckForFramerateConfigChanges(const Pcsx2Config& old_config) @@ -1598,7 +1597,7 @@ void VMManager::CheckForFramerateConfigChanges(const Pcsx2Config& old_config) gsUpdateFrequency(EmuConfig); UpdateVSyncRate(); frameLimitReset(); - GetMTGS().SetVSync(EmuConfig.GetEffectiveVsyncMode()); + GetMTGS().UpdateVSyncMode(); } void VMManager::CheckForPatchConfigChanges(const Pcsx2Config& old_config) diff --git a/pcsx2/gui/AppHost.cpp b/pcsx2/gui/AppHost.cpp index a8b1ce6fbb..54b8bcb7c6 100644 --- a/pcsx2/gui/AppHost.cpp +++ b/pcsx2/gui/AppHost.cpp @@ -117,7 +117,7 @@ bool Host::ConfirmMessage(const std::string_view& title, const std::string_view& return true; } -bool Host::AcquireHostDisplay(HostDisplay::RenderAPI api) +bool Host::AcquireHostDisplay(RenderAPI api) { sApp.OpenGsPanel(); @@ -125,14 +125,11 @@ bool Host::AcquireHostDisplay(HostDisplay::RenderAPI api) if (g_gs_window_info.type == WindowInfo::Type::Surfaceless) return false; - g_host_display = HostDisplay::CreateDisplayForAPI(api); + g_host_display = HostDisplay::CreateForAPI(api); if (!g_host_display) return false; - if (!g_host_display->CreateRenderDevice(g_gs_window_info, GSConfig.Adapter, EmuConfig.GetEffectiveVsyncMode(), - GSConfig.ThreadedPresentation, GSConfig.UseDebugDevice) || - !g_host_display->InitializeRenderDevice(EmuFolders::Cache, GSConfig.UseDebugDevice) || - !ImGuiManager::Initialize()) + if (!g_host_display->CreateDevice(g_gs_window_info) || !g_host_display->SetupDevice() || !ImGuiManager::Initialize()) { g_host_display.reset(); return false; @@ -154,6 +151,16 @@ void Host::ReleaseHostDisplay() sApp.CloseGsPanel(); } +VsyncMode Host::GetEffectiveVSyncMode() +{ + // Force vsync off when not running at 100% speed. + if (EmuConfig.GS.LimitScalar != 1.0f) + return VsyncMode::Off; + + // Otherwise use the config setting. + return EmuConfig.GS.VsyncEnable; +} + bool Host::BeginPresentFrame(bool frame_skip) { CheckForGSWindowResize(); @@ -221,7 +228,7 @@ void Host::CheckForGSWindowResize() return; GSResetAPIState(); - g_host_display->ResizeRenderWindow(width, height, scale); + g_host_display->ResizeWindow(width, height, scale); GSRestoreAPIState(); ImGuiManager::WindowResized(); } diff --git a/pcsx2/gui/SysCoreThread.cpp b/pcsx2/gui/SysCoreThread.cpp index 85f118a954..a1edea4946 100644 --- a/pcsx2/gui/SysCoreThread.cpp +++ b/pcsx2/gui/SysCoreThread.cpp @@ -196,7 +196,7 @@ void SysCoreThread::ApplySettings(const Pcsx2Config& src) { Console.WriteLn("Applying GS settings..."); GetMTGS().ApplySettings(); - GetMTGS().SetVSync(EmuConfig.GetEffectiveVsyncMode()); + GetMTGS().UpdateVSyncMode(); } } @@ -237,7 +237,7 @@ void SysCoreThread::_reset_stuff_as_needed() if (m_resetVsyncTimers) { - GetMTGS().SetVSync(EmuConfig.GetEffectiveVsyncMode()); + GetMTGS().UpdateVSyncMode(); UpdateVSyncRate(); frameLimitReset();