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.
This commit is contained in:
Connor McLaughlin 2022-10-10 22:04:56 +10:00 committed by refractionpcsx2
parent 6a1eb231dd
commit 44c8974aba
29 changed files with 309 additions and 303 deletions

View File

@ -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)

View File

@ -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.

View File

@ -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();

View File

@ -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
{

View File

@ -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);
}

View File

@ -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<bool>(m_device);
}
bool D3D11HostDisplay::HasRenderSurface() const
bool D3D11HostDisplay::HasSurface() const
{
return static_cast<bool>(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<IDXGIFactory> 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<u32>(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<u32>(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<ID3D11InfoQueue> 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;

View File

@ -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<HostDisplayTexture> CreateTexture(u32 width, u32 height, const void* data, u32 data_stride, bool dynamic = false) override;

View File

@ -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<bool>(g_d3d12_context);
}
bool D3D12HostDisplay::HasRenderSurface() const
bool D3D12HostDisplay::HasSurface() const
{
return static_cast<bool>(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<IDXGIFactory> 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<u32>(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<u32>(adapter_info.adapter_names.size()))
{
Console.Warning("Could not find adapter '%*s', using first (%s)", static_cast<int>(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;

View File

@ -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<HostDisplayTexture> CreateTexture(u32 width, u32 height, const void* data, u32 data_stride, bool dynamic = false) override;

View File

@ -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();
});
}

View File

@ -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<HostDisplayTexture> CreateTexture(u32 width, u32 height, const void* data, u32 data_stride, bool dynamic = false) override;
void UpdateTexture(id<MTLTexture> texture, u32 x, u32 y, u32 width, u32 height, const void* data, u32 data_stride);

View File

@ -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<void*>(static_cast<const void*>(&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<bool>(m_layer);}
void* MetalHostDisplay::GetDevice() const { return const_cast<void*>(static_cast<const void*>(&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<bool>(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<MTLDevice> 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<u32>(new_window_width) && m_window_info.surface_height == static_cast<u32>(new_window_height))

View File

@ -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<bool>(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;

View File

@ -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<HostDisplayTexture> CreateTexture(u32 width, u32 height, const void* data, u32 data_stride, bool dynamic) override;

View File

@ -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<u32>(new_window_width) && m_swap_chain->GetHeight() == static_cast<u32>(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<bool>(g_vulkan_context);
}
bool VulkanHostDisplay::HasRenderSurface() const
bool VulkanHostDisplay::HasSurface() const
{
return static_cast<bool>(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)

View File

@ -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<HostDisplayTexture> CreateTexture(u32 width, u32 height, const void* data, u32 data_stride, bool dynamic = false) override;

View File

@ -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();

View File

@ -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<GSDevice11>();
break;
case HostDisplay::RenderAPI::D3D12:
case RenderAPI::D3D12:
g_gs_device = std::make_unique<GSDevice12>();
break;
#endif
#ifdef __APPLE__
case HostDisplay::RenderAPI::Metal:
case RenderAPI::Metal:
g_gs_device = std::unique_ptr<GSDevice>(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<GSDeviceOGL>();
break;
#endif
#ifdef ENABLE_VULKAN
case HostDisplay::RenderAPI::Vulkan:
case RenderAPI::Vulkan:
g_gs_device = std::make_unique<GSDeviceVK>();
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));

View File

@ -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<ID3D11Device*>(g_host_display->GetRenderDevice());
m_ctx = static_cast<ID3D11DeviceContext*>(g_host_display->GetRenderContext());
m_dev = static_cast<ID3D11Device*>(g_host_display->GetDevice());
m_ctx = static_cast<ID3D11DeviceContext*>(g_host_display->GetContext());
level = m_dev->GetFeatureLevel();
if (!GSConfig.DisableShaderCache)

View File

@ -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<const GSMTLDevice*>(g_host_display->GetRenderDevice());
m_queue = MRCRetain((__bridge id<MTLCommandQueue>)g_host_display->GetRenderContext());
MTLPixelFormat layer_px_fmt = [(__bridge CAMetalLayer*)g_host_display->GetRenderSurface() pixelFormat];
m_dev = *static_cast<const GSMTLDevice*>(g_host_display->GetDevice());
m_queue = MRCRetain((__bridge id<MTLCommandQueue>)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;

View File

@ -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

View File

@ -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<Vulkan::SwapChain*>(g_host_display->GetRenderSurface());
Vulkan::SwapChain* swapchain = static_cast<Vulkan::SwapChain*>(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<Vulkan::SwapChain*>(g_host_display->GetRenderSurface());
Vulkan::SwapChain* swapchain = static_cast<Vulkan::SwapChain*>(g_host_display->GetSurface());
if (swapchain)
{
m_swap_chain_render_pass =

View File

@ -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> HostDisplay::CreateDisplayForAPI(RenderAPI api)
std::unique_ptr<HostDisplay> HostDisplay::CreateForAPI(RenderAPI api)
{
switch (api)
{
@ -153,7 +153,7 @@ std::unique_ptr<HostDisplay> HostDisplay::CreateDisplayForAPI(RenderAPI api)
return std::make_unique<D3D12HostDisplay>();
#endif
#ifdef __APPLE__
case HostDisplay::RenderAPI::Metal:
case RenderAPI::Metal:
return std::unique_ptr<HostDisplay>(MakeMetalHostDisplay());
#endif

View File

@ -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<HostDisplay> CreateDisplayForAPI(RenderAPI api);
static std::unique_ptr<HostDisplay> 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<HostDisplayTexture> CreateTexture(u32 width, u32 height, const void* data, u32 data_stride, bool dynamic = false) = 0;
@ -155,11 +173,14 @@ extern std::unique_ptr<HostDisplay> 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);

View File

@ -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");

View File

@ -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;

View File

@ -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)

View File

@ -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();
}

View File

@ -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();