mirror of https://github.com/PCSX2/pcsx2.git
GS: Make VSync a boolean toggle
i.e. ditch the old adaptive mode, and always use adaptive if available.
This commit is contained in:
parent
81203d9a15
commit
9fac941570
|
@ -107,7 +107,7 @@ bool GSRunner::InitializeConfig()
|
||||||
|
|
||||||
// complete as quickly as possible
|
// complete as quickly as possible
|
||||||
si.SetBoolValue("EmuCore/GS", "FrameLimitEnable", false);
|
si.SetBoolValue("EmuCore/GS", "FrameLimitEnable", false);
|
||||||
si.SetIntValue("EmuCore/GS", "VsyncEnable", static_cast<int>(VsyncMode::Off));
|
si.SetIntValue("EmuCore/GS", "VsyncEnable", false);
|
||||||
|
|
||||||
// ensure all input sources are disabled, we're not using them
|
// ensure all input sources are disabled, we're not using them
|
||||||
si.SetBoolValue("InputSources", "SDL", false);
|
si.SetBoolValue("InputSources", "SDL", false);
|
||||||
|
|
|
@ -190,13 +190,6 @@ enum class SpeedHack
|
||||||
MaxCount,
|
MaxCount,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class VsyncMode
|
|
||||||
{
|
|
||||||
Off,
|
|
||||||
On,
|
|
||||||
Adaptive,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class AspectRatioType : u8
|
enum class AspectRatioType : u8
|
||||||
{
|
{
|
||||||
Stretch,
|
Stretch,
|
||||||
|
@ -596,6 +589,8 @@ struct Pcsx2Config
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
bool
|
bool
|
||||||
|
SynchronousMTGS : 1,
|
||||||
|
VsyncEnable : 1,
|
||||||
PCRTCAntiBlur : 1,
|
PCRTCAntiBlur : 1,
|
||||||
DisableInterlaceOffset : 1,
|
DisableInterlaceOffset : 1,
|
||||||
PCRTCOffsets : 1,
|
PCRTCOffsets : 1,
|
||||||
|
@ -618,9 +613,7 @@ struct Pcsx2Config
|
||||||
OsdShowIndicators : 1,
|
OsdShowIndicators : 1,
|
||||||
OsdShowSettings : 1,
|
OsdShowSettings : 1,
|
||||||
OsdShowInputs : 1,
|
OsdShowInputs : 1,
|
||||||
OsdShowFrameTimes : 1;
|
OsdShowFrameTimes : 1,
|
||||||
|
|
||||||
bool
|
|
||||||
HWSpinGPUForReadbacks : 1,
|
HWSpinGPUForReadbacks : 1,
|
||||||
HWSpinCPUForReadbacks : 1,
|
HWSpinCPUForReadbacks : 1,
|
||||||
GPUPaletteConversion : 1,
|
GPUPaletteConversion : 1,
|
||||||
|
@ -664,12 +657,6 @@ struct Pcsx2Config
|
||||||
|
|
||||||
int VsyncQueueSize = 2;
|
int VsyncQueueSize = 2;
|
||||||
|
|
||||||
// forces the MTGS to execute tags/tasks in fully blocking/synchronous
|
|
||||||
// style. Useful for debugging potential bugs in the MTGS pipeline.
|
|
||||||
bool SynchronousMTGS = false;
|
|
||||||
|
|
||||||
VsyncMode VsyncEnable = VsyncMode::Off;
|
|
||||||
|
|
||||||
float FramerateNTSC = DEFAULT_FRAME_RATE_NTSC;
|
float FramerateNTSC = DEFAULT_FRAME_RATE_NTSC;
|
||||||
float FrameratePAL = DEFAULT_FRAME_RATE_PAL;
|
float FrameratePAL = DEFAULT_FRAME_RATE_PAL;
|
||||||
|
|
||||||
|
|
|
@ -471,7 +471,7 @@ void GSPresentCurrentFrame()
|
||||||
|
|
||||||
void GSThrottlePresentation()
|
void GSThrottlePresentation()
|
||||||
{
|
{
|
||||||
if (g_gs_device->GetVsyncMode() != VsyncMode::Off)
|
if (g_gs_device->IsVSyncEnabled())
|
||||||
{
|
{
|
||||||
// Let vsync take care of throttling.
|
// Let vsync take care of throttling.
|
||||||
return;
|
return;
|
||||||
|
@ -528,9 +528,9 @@ void GSUpdateDisplayWindow()
|
||||||
ImGuiManager::WindowResized();
|
ImGuiManager::WindowResized();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GSSetVSyncMode(VsyncMode mode)
|
void GSSetVSyncEnabled(bool enabled)
|
||||||
{
|
{
|
||||||
g_gs_device->SetVSync(mode);
|
g_gs_device->SetVSyncEnabled(enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GSWantsExclusiveFullscreen()
|
bool GSWantsExclusiveFullscreen()
|
||||||
|
|
|
@ -84,7 +84,7 @@ void GSSetDisplayAlignment(GSDisplayAlignment alignment);
|
||||||
bool GSHasDisplayWindow();
|
bool GSHasDisplayWindow();
|
||||||
void GSResizeDisplayWindow(int width, int height, float scale);
|
void GSResizeDisplayWindow(int width, int height, float scale);
|
||||||
void GSUpdateDisplayWindow();
|
void GSUpdateDisplayWindow();
|
||||||
void GSSetVSyncMode(VsyncMode mode);
|
void GSSetVSyncEnabled(bool enabled);
|
||||||
|
|
||||||
GSRendererType GSGetCurrentRenderer();
|
GSRendererType GSGetCurrentRenderer();
|
||||||
bool GSIsHardwareRenderer();
|
bool GSIsHardwareRenderer();
|
||||||
|
@ -127,7 +127,7 @@ namespace Host
|
||||||
void SetFullscreen(bool enabled);
|
void SetFullscreen(bool enabled);
|
||||||
|
|
||||||
/// Returns the desired vsync mode, depending on the runtime environment.
|
/// Returns the desired vsync mode, depending on the runtime environment.
|
||||||
VsyncMode GetEffectiveVSyncMode();
|
bool IsVsyncEffectivelyEnabled();
|
||||||
|
|
||||||
/// Called when video capture starts or stops. Called on the MTGS thread.
|
/// Called when video capture starts or stops. Called on the MTGS thread.
|
||||||
void OnCaptureStarted(const std::string& filename);
|
void OnCaptureStarted(const std::string& filename);
|
||||||
|
|
|
@ -307,7 +307,7 @@ int GSDevice::GetMipmapLevelsForSize(int width, int height)
|
||||||
|
|
||||||
bool GSDevice::Create()
|
bool GSDevice::Create()
|
||||||
{
|
{
|
||||||
m_vsync_mode = Host::GetEffectiveVSyncMode();
|
m_vsync_enabled = Host::IsVsyncEffectivelyEnabled();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -803,7 +803,6 @@ protected:
|
||||||
static constexpr u32 EXPAND_BUFFER_SIZE = sizeof(u16) * 16383 * 6;
|
static constexpr u32 EXPAND_BUFFER_SIZE = sizeof(u16) * 16383 * 6;
|
||||||
|
|
||||||
WindowInfo m_window_info;
|
WindowInfo m_window_info;
|
||||||
VsyncMode m_vsync_mode = VsyncMode::Off;
|
|
||||||
|
|
||||||
GSTexture* m_imgui_font = nullptr;
|
GSTexture* m_imgui_font = nullptr;
|
||||||
|
|
||||||
|
@ -824,6 +823,7 @@ protected:
|
||||||
u32 start, count;
|
u32 start, count;
|
||||||
} m_index = {};
|
} m_index = {};
|
||||||
unsigned int m_frame = 0; // for ageing the pool
|
unsigned int m_frame = 0; // for ageing the pool
|
||||||
|
bool m_vsync_enabled = false;
|
||||||
bool m_rbswapped = false;
|
bool m_rbswapped = false;
|
||||||
FeatureSupport m_features;
|
FeatureSupport m_features;
|
||||||
|
|
||||||
|
@ -874,7 +874,7 @@ public:
|
||||||
__fi s32 GetWindowHeight() const { return static_cast<s32>(m_window_info.surface_height); }
|
__fi s32 GetWindowHeight() const { return static_cast<s32>(m_window_info.surface_height); }
|
||||||
__fi GSVector2i GetWindowSize() const { return GSVector2i(static_cast<s32>(m_window_info.surface_width), static_cast<s32>(m_window_info.surface_height)); }
|
__fi GSVector2i GetWindowSize() const { return GSVector2i(static_cast<s32>(m_window_info.surface_width), static_cast<s32>(m_window_info.surface_height)); }
|
||||||
__fi float GetWindowScale() const { return m_window_info.surface_scale; }
|
__fi float GetWindowScale() const { return m_window_info.surface_scale; }
|
||||||
__fi VsyncMode GetVsyncMode() const { return m_vsync_mode; }
|
__fi bool IsVSyncEnabled() const { return m_vsync_enabled; }
|
||||||
|
|
||||||
__fi GSTexture* GetCurrent() const { return m_current; }
|
__fi GSTexture* GetCurrent() const { return m_current; }
|
||||||
|
|
||||||
|
@ -915,7 +915,7 @@ public:
|
||||||
virtual void EndPresent() = 0;
|
virtual void EndPresent() = 0;
|
||||||
|
|
||||||
/// Changes vsync mode for this display.
|
/// Changes vsync mode for this display.
|
||||||
virtual void SetVSync(VsyncMode mode) = 0;
|
virtual void SetVSyncEnabled(bool enabled) = 0;
|
||||||
|
|
||||||
/// Returns the effective refresh rate of this display.
|
/// Returns the effective refresh rate of this display.
|
||||||
virtual bool GetHostRefreshRate(float* refresh_rate);
|
virtual bool GetHostRefreshRate(float* refresh_rate);
|
||||||
|
|
|
@ -628,9 +628,9 @@ bool GSDevice11::GetHostRefreshRate(float* refresh_rate)
|
||||||
return GSDevice::GetHostRefreshRate(refresh_rate);
|
return GSDevice::GetHostRefreshRate(refresh_rate);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GSDevice11::SetVSync(VsyncMode mode)
|
void GSDevice11::SetVSyncEnabled(bool enabled)
|
||||||
{
|
{
|
||||||
m_vsync_mode = mode;
|
m_vsync_enabled = enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GSDevice11::CreateSwapChain()
|
bool GSDevice11::CreateSwapChain()
|
||||||
|
@ -928,7 +928,7 @@ GSDevice::PresentResult GSDevice11::BeginPresent(bool frame_skip)
|
||||||
// This blows our our GPU usage number considerably, so read the timestamp before the final blit
|
// This blows our our GPU usage number considerably, so read the timestamp before the final blit
|
||||||
// in this configuration. It does reduce accuracy a little, but better than seeing 100% all of
|
// in this configuration. It does reduce accuracy a little, but better than seeing 100% all of
|
||||||
// the time, when it's more like a couple of percent.
|
// the time, when it's more like a couple of percent.
|
||||||
if (m_vsync_mode != VsyncMode::Off && m_gpu_timing_enabled)
|
if (m_vsync_enabled && m_gpu_timing_enabled)
|
||||||
PopTimestampQuery();
|
PopTimestampQuery();
|
||||||
|
|
||||||
m_ctx->ClearRenderTargetView(m_swap_chain_rtv.get(), s_present_clear_color.data());
|
m_ctx->ClearRenderTargetView(m_swap_chain_rtv.get(), s_present_clear_color.data());
|
||||||
|
@ -957,14 +957,13 @@ void GSDevice11::EndPresent()
|
||||||
RenderImGui();
|
RenderImGui();
|
||||||
|
|
||||||
// See note in BeginPresent() for why it's conditional on vsync-off.
|
// See note in BeginPresent() for why it's conditional on vsync-off.
|
||||||
const bool vsync_on = m_vsync_mode != VsyncMode::Off;
|
if (!m_vsync_enabled && m_gpu_timing_enabled)
|
||||||
if (!vsync_on && m_gpu_timing_enabled)
|
|
||||||
PopTimestampQuery();
|
PopTimestampQuery();
|
||||||
|
|
||||||
if (!vsync_on && m_using_allow_tearing)
|
if (!m_vsync_enabled && m_using_allow_tearing)
|
||||||
m_swap_chain->Present(0, DXGI_PRESENT_ALLOW_TEARING);
|
m_swap_chain->Present(0, DXGI_PRESENT_ALLOW_TEARING);
|
||||||
else
|
else
|
||||||
m_swap_chain->Present(static_cast<UINT>(vsync_on), 0);
|
m_swap_chain->Present(static_cast<UINT>(m_vsync_enabled), 0);
|
||||||
|
|
||||||
if (m_gpu_timing_enabled)
|
if (m_gpu_timing_enabled)
|
||||||
KickTimestampQuery();
|
KickTimestampQuery();
|
||||||
|
|
|
@ -273,7 +273,7 @@ public:
|
||||||
|
|
||||||
bool GetHostRefreshRate(float* refresh_rate) override;
|
bool GetHostRefreshRate(float* refresh_rate) override;
|
||||||
|
|
||||||
void SetVSync(VsyncMode mode) override;
|
void SetVSyncEnabled(bool enabled) override;
|
||||||
|
|
||||||
PresentResult BeginPresent(bool frame_skip) override;
|
PresentResult BeginPresent(bool frame_skip) override;
|
||||||
void EndPresent() override;
|
void EndPresent() override;
|
||||||
|
|
|
@ -774,9 +774,9 @@ bool GSDevice12::GetHostRefreshRate(float* refresh_rate)
|
||||||
return GSDevice::GetHostRefreshRate(refresh_rate);
|
return GSDevice::GetHostRefreshRate(refresh_rate);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GSDevice12::SetVSync(VsyncMode mode)
|
void GSDevice12::SetVSyncEnabled(bool enabled)
|
||||||
{
|
{
|
||||||
m_vsync_mode = mode;
|
m_vsync_enabled = enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GSDevice12::CreateSwapChain()
|
bool GSDevice12::CreateSwapChain()
|
||||||
|
@ -1109,11 +1109,10 @@ void GSDevice12::EndPresent()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const bool vsync = static_cast<UINT>(m_vsync_mode != VsyncMode::Off);
|
if (!m_vsync_enabled && m_using_allow_tearing)
|
||||||
if (!vsync && m_using_allow_tearing)
|
|
||||||
m_swap_chain->Present(0, DXGI_PRESENT_ALLOW_TEARING);
|
m_swap_chain->Present(0, DXGI_PRESENT_ALLOW_TEARING);
|
||||||
else
|
else
|
||||||
m_swap_chain->Present(static_cast<UINT>(vsync), 0);
|
m_swap_chain->Present(static_cast<UINT>(m_vsync_enabled), 0);
|
||||||
|
|
||||||
InvalidateCachedState();
|
InvalidateCachedState();
|
||||||
}
|
}
|
||||||
|
|
|
@ -409,7 +409,7 @@ public:
|
||||||
|
|
||||||
bool GetHostRefreshRate(float* refresh_rate) override;
|
bool GetHostRefreshRate(float* refresh_rate) override;
|
||||||
|
|
||||||
void SetVSync(VsyncMode mode) override;
|
void SetVSyncEnabled(bool enabled) override;
|
||||||
|
|
||||||
PresentResult BeginPresent(bool frame_skip) override;
|
PresentResult BeginPresent(bool frame_skip) override;
|
||||||
void EndPresent() override;
|
void EndPresent() override;
|
||||||
|
|
|
@ -392,7 +392,7 @@ public:
|
||||||
|
|
||||||
PresentResult BeginPresent(bool frame_skip) override;
|
PresentResult BeginPresent(bool frame_skip) override;
|
||||||
void EndPresent() override;
|
void EndPresent() override;
|
||||||
void SetVSync(VsyncMode mode) override;
|
void SetVSyncEnabled(bool enabled) override;
|
||||||
|
|
||||||
bool GetHostRefreshRate(float* refresh_rate) override;
|
bool GetHostRefreshRate(float* refresh_rate) override;
|
||||||
|
|
||||||
|
|
|
@ -877,7 +877,7 @@ bool GSDeviceMTL::Create()
|
||||||
{
|
{
|
||||||
AttachSurfaceOnMainThread();
|
AttachSurfaceOnMainThread();
|
||||||
});
|
});
|
||||||
[m_layer setDisplaySyncEnabled:m_vsync_mode != VsyncMode::Off];
|
[m_layer setDisplaySyncEnabled:m_vsync_enabled];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1305,7 +1305,7 @@ void GSDeviceMTL::EndPresent()
|
||||||
if (m_current_drawable)
|
if (m_current_drawable)
|
||||||
{
|
{
|
||||||
const bool use_present_drawable = m_use_present_drawable == UsePresentDrawable::Always ||
|
const bool use_present_drawable = m_use_present_drawable == UsePresentDrawable::Always ||
|
||||||
(m_use_present_drawable == UsePresentDrawable::IfVsync && m_vsync_mode != VsyncMode::Off);
|
(m_use_present_drawable == UsePresentDrawable::IfVsync && m_vsync_enabled);
|
||||||
|
|
||||||
if (use_present_drawable)
|
if (use_present_drawable)
|
||||||
[m_current_render_cmdbuf presentDrawable:m_current_drawable];
|
[m_current_render_cmdbuf presentDrawable:m_current_drawable];
|
||||||
|
@ -1367,13 +1367,13 @@ void GSDeviceMTL::EndPresent()
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
|
|
||||||
void GSDeviceMTL::SetVSync(VsyncMode mode)
|
void GSDeviceMTL::SetVSyncEnabled(bool enabled)
|
||||||
{
|
{
|
||||||
if (m_vsync_mode == mode)
|
if (m_vsync_enabled == enabled)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
[m_layer setDisplaySyncEnabled:mode != VsyncMode::Off];
|
[m_layer setDisplaySyncEnabled:enabled];
|
||||||
m_vsync_mode = mode;
|
m_vsync_enabled = enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GSDeviceMTL::GetHostRefreshRate(float* refresh_rate)
|
bool GSDeviceMTL::GetHostRefreshRate(float* refresh_rate)
|
||||||
|
|
|
@ -35,6 +35,7 @@ public:
|
||||||
virtual bool IsCurrent() = 0;
|
virtual bool IsCurrent() = 0;
|
||||||
virtual bool MakeCurrent() = 0;
|
virtual bool MakeCurrent() = 0;
|
||||||
virtual bool DoneCurrent() = 0;
|
virtual bool DoneCurrent() = 0;
|
||||||
|
virtual bool SupportsNegativeSwapInterval() const = 0;
|
||||||
virtual bool SetSwapInterval(s32 interval) = 0;
|
virtual bool SetSwapInterval(s32 interval) = 0;
|
||||||
virtual std::unique_ptr<GLContext> CreateSharedContext(const WindowInfo& wi, Error* error) = 0;
|
virtual std::unique_ptr<GLContext> CreateSharedContext(const WindowInfo& wi, Error* error) = 0;
|
||||||
|
|
||||||
|
|
|
@ -312,6 +312,11 @@ bool GLContextEGL::DoneCurrent()
|
||||||
return eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
|
return eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool GLContextEGL::SupportsNegativeSwapInterval() const
|
||||||
|
{
|
||||||
|
return m_supports_negative_swap_interval;
|
||||||
|
}
|
||||||
|
|
||||||
bool GLContextEGL::SetSwapInterval(s32 interval)
|
bool GLContextEGL::SetSwapInterval(s32 interval)
|
||||||
{
|
{
|
||||||
return eglSwapInterval(m_display, interval);
|
return eglSwapInterval(m_display, interval);
|
||||||
|
@ -492,6 +497,19 @@ bool GLContextEGL::CreateContext(const Version& version, EGLContext share_contex
|
||||||
}
|
}
|
||||||
|
|
||||||
Console.WriteLnFmt("Got GL version {}.{}", version.major_version, version.minor_version);
|
Console.WriteLnFmt("Got GL version {}.{}", version.major_version, version.minor_version);
|
||||||
|
|
||||||
|
EGLint min_swap_interval, max_swap_interval;
|
||||||
|
m_supports_negative_swap_interval = false;
|
||||||
|
if (eglGetConfigAttrib(m_display, config.value(), EGL_MIN_SWAP_INTERVAL, &min_swap_interval) &&
|
||||||
|
eglGetConfigAttrib(m_display, config.value(), EGL_MAX_SWAP_INTERVAL, &max_swap_interval))
|
||||||
|
{
|
||||||
|
DEV_LOG("EGL_MIN_SWAP_INTERVAL = {}", min_swap_interval);
|
||||||
|
DEV_LOG("EGL_MAX_SWAP_INTERVAL = {}", max_swap_interval);
|
||||||
|
m_supports_negative_swap_interval = (min_swap_interval <= -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
INFO_LOG("Negative swap interval/tear-control is {}supported", m_supports_negative_swap_interval ? "" : "NOT ");
|
||||||
|
|
||||||
m_config = config.value();
|
m_config = config.value();
|
||||||
m_version = version;
|
m_version = version;
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -24,6 +24,7 @@ public:
|
||||||
bool IsCurrent() override;
|
bool IsCurrent() override;
|
||||||
bool MakeCurrent() override;
|
bool MakeCurrent() override;
|
||||||
bool DoneCurrent() override;
|
bool DoneCurrent() override;
|
||||||
|
bool SupportsNegativeSwapInterval() const override;
|
||||||
bool SetSwapInterval(s32 interval) override;
|
bool SetSwapInterval(s32 interval) override;
|
||||||
virtual std::unique_ptr<GLContext> CreateSharedContext(const WindowInfo& wi, Error* error) override;
|
virtual std::unique_ptr<GLContext> CreateSharedContext(const WindowInfo& wi, Error* error) override;
|
||||||
|
|
||||||
|
@ -52,4 +53,5 @@ protected:
|
||||||
EGLConfig m_config = {};
|
EGLConfig m_config = {};
|
||||||
|
|
||||||
bool m_use_ext_platform_base = false;
|
bool m_use_ext_platform_base = false;
|
||||||
|
bool m_supports_negative_swap_interval = false;
|
||||||
};
|
};
|
||||||
|
|
|
@ -152,6 +152,11 @@ bool GLContextWGL::DoneCurrent()
|
||||||
return wglMakeCurrent(m_dc, nullptr);
|
return wglMakeCurrent(m_dc, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool GLContextWGL::SupportsNegativeSwapInterval() const
|
||||||
|
{
|
||||||
|
return GLAD_WGL_EXT_swap_control && GLAD_WGL_EXT_swap_control_tear;
|
||||||
|
}
|
||||||
|
|
||||||
bool GLContextWGL::SetSwapInterval(s32 interval)
|
bool GLContextWGL::SetSwapInterval(s32 interval)
|
||||||
{
|
{
|
||||||
if (!GLAD_WGL_EXT_swap_control)
|
if (!GLAD_WGL_EXT_swap_control)
|
||||||
|
|
|
@ -27,6 +27,7 @@ public:
|
||||||
bool IsCurrent() override;
|
bool IsCurrent() override;
|
||||||
bool MakeCurrent() override;
|
bool MakeCurrent() override;
|
||||||
bool DoneCurrent() override;
|
bool DoneCurrent() override;
|
||||||
|
bool SupportsNegativeSwapInterval() const override;
|
||||||
bool SetSwapInterval(s32 interval) override;
|
bool SetSwapInterval(s32 interval) override;
|
||||||
std::unique_ptr<GLContext> CreateSharedContext(const WindowInfo& wi, Error* error) override;
|
std::unique_ptr<GLContext> CreateSharedContext(const WindowInfo& wi, Error* error) override;
|
||||||
|
|
||||||
|
|
|
@ -146,21 +146,13 @@ bool GSDeviceOGL::HasSurface() const
|
||||||
return m_window_info.type != WindowInfo::Type::Surfaceless;
|
return m_window_info.type != WindowInfo::Type::Surfaceless;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GSDeviceOGL::SetVSync(VsyncMode mode)
|
void GSDeviceOGL::SetVSyncEnabled(bool enabled)
|
||||||
{
|
{
|
||||||
if (m_vsync_mode == mode || m_gl_context->GetWindowInfo().type == WindowInfo::Type::Surfaceless)
|
if (m_vsync_enabled == enabled)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Window framebuffer has to be bound to call SetSwapInterval.
|
m_vsync_enabled = enabled;
|
||||||
GLint current_fbo = 0;
|
SetSwapInterval();
|
||||||
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, ¤t_fbo);
|
|
||||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
|
||||||
|
|
||||||
if (mode != VsyncMode::Adaptive || !m_gl_context->SetSwapInterval(-1))
|
|
||||||
m_gl_context->SetSwapInterval(static_cast<s32>(mode != VsyncMode::Off));
|
|
||||||
|
|
||||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, current_fbo);
|
|
||||||
m_vsync_mode = mode;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GSDeviceOGL::Create()
|
bool GSDeviceOGL::Create()
|
||||||
|
@ -777,8 +769,19 @@ bool GSDeviceOGL::CheckFeatures(bool& buggy_pbo)
|
||||||
|
|
||||||
void GSDeviceOGL::SetSwapInterval()
|
void GSDeviceOGL::SetSwapInterval()
|
||||||
{
|
{
|
||||||
const int interval = ((m_vsync_mode == VsyncMode::Adaptive) ? -1 : ((m_vsync_mode == VsyncMode::On) ? 1 : 0));
|
if (m_window_info.type == WindowInfo::Type::Surfaceless)
|
||||||
m_gl_context->SetSwapInterval(interval);
|
return;
|
||||||
|
|
||||||
|
// Window framebuffer has to be bound to call SetSwapInterval.
|
||||||
|
const s32 interval = m_vsync_enabled ? (m_gl_context->SupportsNegativeSwapInterval() ? -1 : 1) : 0;
|
||||||
|
GLint current_fbo = 0;
|
||||||
|
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, ¤t_fbo);
|
||||||
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||||
|
|
||||||
|
if (!m_gl_context->SetSwapInterval(interval))
|
||||||
|
WARNING_LOG("Failed to set swap interval to {}", interval);
|
||||||
|
|
||||||
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, current_fbo);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GSDeviceOGL::DestroyResources()
|
void GSDeviceOGL::DestroyResources()
|
||||||
|
@ -868,9 +871,7 @@ bool GSDeviceOGL::UpdateWindow()
|
||||||
if (m_window_info.type != WindowInfo::Type::Surfaceless)
|
if (m_window_info.type != WindowInfo::Type::Surfaceless)
|
||||||
{
|
{
|
||||||
// reset vsync rate, since it (usually) gets lost
|
// reset vsync rate, since it (usually) gets lost
|
||||||
if (m_vsync_mode != VsyncMode::Adaptive || !m_gl_context->SetSwapInterval(-1))
|
SetSwapInterval();
|
||||||
m_gl_context->SetSwapInterval(static_cast<s32>(m_vsync_mode != VsyncMode::Off));
|
|
||||||
|
|
||||||
RenderBlankFrame();
|
RenderBlankFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -292,7 +292,7 @@ public:
|
||||||
void DestroySurface() override;
|
void DestroySurface() override;
|
||||||
std::string GetDriverInfo() const override;
|
std::string GetDriverInfo() const override;
|
||||||
|
|
||||||
void SetVSync(VsyncMode mode) override;
|
void SetVSyncEnabled(bool enabled) override;
|
||||||
|
|
||||||
PresentResult BeginPresent(bool frame_skip) override;
|
PresentResult BeginPresent(bool frame_skip) override;
|
||||||
void EndPresent() override;
|
void EndPresent() override;
|
||||||
|
|
|
@ -2222,7 +2222,7 @@ bool GSDeviceVK::UpdateWindow()
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_swap_chain = VKSwapChain::Create(m_window_info, surface, m_vsync_mode,
|
m_swap_chain = VKSwapChain::Create(m_window_info, surface, m_vsync_enabled,
|
||||||
Pcsx2Config::GSOptions::TriStateToOptionalBoolean(GSConfig.ExclusiveFullscreenControl));
|
Pcsx2Config::GSOptions::TriStateToOptionalBoolean(GSConfig.ExclusiveFullscreenControl));
|
||||||
if (!m_swap_chain)
|
if (!m_swap_chain)
|
||||||
{
|
{
|
||||||
|
@ -2297,24 +2297,27 @@ std::string GSDeviceVK::GetDriverInfo() const
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GSDeviceVK::SetVSync(VsyncMode mode)
|
void GSDeviceVK::SetVSyncEnabled(bool enabled)
|
||||||
{
|
{
|
||||||
if (!m_swap_chain || m_vsync_mode == mode)
|
if (!m_swap_chain || m_vsync_enabled == enabled)
|
||||||
|
{
|
||||||
|
m_vsync_enabled = enabled;
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// This swap chain should not be used by the current buffer, thus safe to destroy.
|
// This swap chain should not be used by the current buffer, thus safe to destroy.
|
||||||
WaitForGPUIdle();
|
WaitForGPUIdle();
|
||||||
if (!m_swap_chain->SetVSync(mode))
|
if (!m_swap_chain->SetVSyncEnabled(enabled))
|
||||||
{
|
{
|
||||||
// Try switching back to the old mode..
|
// Try switching back to the old mode..
|
||||||
if (!m_swap_chain->SetVSync(m_vsync_mode))
|
if (!m_swap_chain->SetVSyncEnabled(m_vsync_enabled))
|
||||||
{
|
{
|
||||||
pxFailRel("Failed to reset old vsync mode after failure");
|
pxFailRel("Failed to reset old vsync mode after failure");
|
||||||
m_swap_chain.reset();
|
m_swap_chain.reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_vsync_mode = mode;
|
m_vsync_enabled = enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
GSDevice::PresentResult GSDeviceVK::BeginPresent(bool frame_skip)
|
GSDevice::PresentResult GSDeviceVK::BeginPresent(bool frame_skip)
|
||||||
|
@ -2613,7 +2616,7 @@ bool GSDeviceVK::CreateDeviceAndSwapChain()
|
||||||
|
|
||||||
if (surface != VK_NULL_HANDLE)
|
if (surface != VK_NULL_HANDLE)
|
||||||
{
|
{
|
||||||
m_swap_chain = VKSwapChain::Create(m_window_info, surface, m_vsync_mode,
|
m_swap_chain = VKSwapChain::Create(m_window_info, surface, m_vsync_enabled,
|
||||||
Pcsx2Config::GSOptions::TriStateToOptionalBoolean(GSConfig.ExclusiveFullscreenControl));
|
Pcsx2Config::GSOptions::TriStateToOptionalBoolean(GSConfig.ExclusiveFullscreenControl));
|
||||||
if (!m_swap_chain)
|
if (!m_swap_chain)
|
||||||
{
|
{
|
||||||
|
|
|
@ -524,7 +524,7 @@ public:
|
||||||
void DestroySurface() override;
|
void DestroySurface() override;
|
||||||
std::string GetDriverInfo() const override;
|
std::string GetDriverInfo() const override;
|
||||||
|
|
||||||
void SetVSync(VsyncMode mode) override;
|
void SetVSyncEnabled(bool enabled) override;
|
||||||
|
|
||||||
PresentResult BeginPresent(bool frame_skip) override;
|
PresentResult BeginPresent(bool frame_skip) override;
|
||||||
void EndPresent() override;
|
void EndPresent() override;
|
||||||
|
|
|
@ -18,11 +18,11 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
VKSwapChain::VKSwapChain(
|
VKSwapChain::VKSwapChain(
|
||||||
const WindowInfo& wi, VkSurfaceKHR surface, VsyncMode vsync, std::optional<bool> exclusive_fullscreen_control)
|
const WindowInfo& wi, VkSurfaceKHR surface, bool vsync, std::optional<bool> exclusive_fullscreen_control)
|
||||||
: m_window_info(wi)
|
: m_window_info(wi)
|
||||||
, m_surface(surface)
|
, m_surface(surface)
|
||||||
, m_vsync_mode(vsync)
|
|
||||||
, m_exclusive_fullscreen_control(exclusive_fullscreen_control)
|
, m_exclusive_fullscreen_control(exclusive_fullscreen_control)
|
||||||
|
, m_vsync_enabled(vsync)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -135,7 +135,7 @@ void VKSwapChain::DestroyVulkanSurface(VkInstance instance, WindowInfo* wi, VkSu
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<VKSwapChain> VKSwapChain::Create(
|
std::unique_ptr<VKSwapChain> VKSwapChain::Create(
|
||||||
const WindowInfo& wi, VkSurfaceKHR surface, VsyncMode vsync, std::optional<bool> exclusive_fullscreen_control)
|
const WindowInfo& wi, VkSurfaceKHR surface, bool vsync, std::optional<bool> exclusive_fullscreen_control)
|
||||||
{
|
{
|
||||||
std::unique_ptr<VKSwapChain> swap_chain =
|
std::unique_ptr<VKSwapChain> swap_chain =
|
||||||
std::unique_ptr<VKSwapChain>(new VKSwapChain(wi, surface, vsync, exclusive_fullscreen_control));
|
std::unique_ptr<VKSwapChain>(new VKSwapChain(wi, surface, vsync, exclusive_fullscreen_control));
|
||||||
|
@ -226,17 +226,7 @@ static const char* PresentModeToString(VkPresentModeKHR mode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static VkPresentModeKHR GetPreferredPresentModeForVsyncMode(VsyncMode mode)
|
std::optional<VkPresentModeKHR> VKSwapChain::SelectPresentMode(VkSurfaceKHR surface, VkPresentModeKHR requested_mode)
|
||||||
{
|
|
||||||
if (mode == VsyncMode::On)
|
|
||||||
return VK_PRESENT_MODE_FIFO_KHR;
|
|
||||||
else if (mode == VsyncMode::Adaptive)
|
|
||||||
return VK_PRESENT_MODE_FIFO_RELAXED_KHR;
|
|
||||||
else
|
|
||||||
return VK_PRESENT_MODE_IMMEDIATE_KHR;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<VkPresentModeKHR> VKSwapChain::SelectPresentMode(VkSurfaceKHR surface, VsyncMode vsync)
|
|
||||||
{
|
{
|
||||||
VkResult res;
|
VkResult res;
|
||||||
u32 mode_count;
|
u32 mode_count;
|
||||||
|
@ -260,31 +250,30 @@ std::optional<VkPresentModeKHR> VKSwapChain::SelectPresentMode(VkSurfaceKHR surf
|
||||||
return it != present_modes.end();
|
return it != present_modes.end();
|
||||||
};
|
};
|
||||||
|
|
||||||
// Use preferred mode if available.
|
// Use preferred mode if available.
|
||||||
const VkPresentModeKHR preferred_mode = GetPreferredPresentModeForVsyncMode(vsync);
|
VkPresentModeKHR selected_mode;
|
||||||
VkPresentModeKHR selected_mode;
|
if (CheckForMode(requested_mode))
|
||||||
if (CheckForMode(preferred_mode))
|
{
|
||||||
{
|
selected_mode = requested_mode;
|
||||||
selected_mode = preferred_mode;
|
}
|
||||||
}
|
else if (requested_mode != VK_PRESENT_MODE_FIFO_KHR && CheckForMode(VK_PRESENT_MODE_MAILBOX_KHR))
|
||||||
else if (vsync != VsyncMode::On && CheckForMode(VK_PRESENT_MODE_MAILBOX_KHR))
|
{
|
||||||
{
|
// Prefer mailbox over fifo for adaptive vsync/no-vsync. This way it'll only delay one frame.
|
||||||
// Prefer mailbox over fifo for adaptive vsync/no-vsync.
|
selected_mode = VK_PRESENT_MODE_MAILBOX_KHR;
|
||||||
selected_mode = VK_PRESENT_MODE_MAILBOX_KHR;
|
}
|
||||||
}
|
else if (requested_mode == VK_PRESENT_MODE_FIFO_RELAXED_KHR && CheckForMode(VK_PRESENT_MODE_FIFO_KHR))
|
||||||
else if (vsync != VsyncMode::Off && CheckForMode(VK_PRESENT_MODE_FIFO_KHR))
|
{
|
||||||
{
|
// Fallback to FIFO if we're using any kind of vsync.
|
||||||
// Fallback to FIFO if we're using any kind of vsync.
|
// This should never fail, FIFO is mandated.
|
||||||
// This should never fail, FIFO is mandated.
|
selected_mode = VK_PRESENT_MODE_FIFO_KHR;
|
||||||
selected_mode = VK_PRESENT_MODE_FIFO_KHR;
|
}
|
||||||
}
|
else
|
||||||
else
|
{
|
||||||
{
|
// Fall back to whatever is available.
|
||||||
// Fall back to whatever is available.
|
selected_mode = present_modes[0];
|
||||||
selected_mode = present_modes[0];
|
}
|
||||||
}
|
|
||||||
|
|
||||||
DevCon.WriteLn("(SwapChain) Preferred present mode: %s, selected: %s", PresentModeToString(preferred_mode),
|
DevCon.WriteLn("(SwapChain) Preferred present mode: %s, selected: %s", PresentModeToString(requested_mode),
|
||||||
PresentModeToString(selected_mode));
|
PresentModeToString(selected_mode));
|
||||||
|
|
||||||
return selected_mode;
|
return selected_mode;
|
||||||
|
@ -294,7 +283,11 @@ bool VKSwapChain::CreateSwapChain()
|
||||||
{
|
{
|
||||||
// Select swap chain format and present mode
|
// Select swap chain format and present mode
|
||||||
std::optional<VkSurfaceFormatKHR> surface_format = SelectSurfaceFormat(m_surface);
|
std::optional<VkSurfaceFormatKHR> surface_format = SelectSurfaceFormat(m_surface);
|
||||||
std::optional<VkPresentModeKHR> present_mode = SelectPresentMode(m_surface, m_vsync_mode);
|
|
||||||
|
// Prefer relaxed vsync if available, stalling is bad.
|
||||||
|
const VkPresentModeKHR requested_mode =
|
||||||
|
m_vsync_enabled ? VK_PRESENT_MODE_FIFO_RELAXED_KHR : VK_PRESENT_MODE_IMMEDIATE_KHR;
|
||||||
|
std::optional<VkPresentModeKHR> present_mode = SelectPresentMode(m_surface, requested_mode);
|
||||||
if (!surface_format.has_value() || !present_mode.has_value())
|
if (!surface_format.has_value() || !present_mode.has_value())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -414,6 +407,7 @@ bool VKSwapChain::CreateSwapChain()
|
||||||
|
|
||||||
m_window_info.surface_width = std::max(1u, size.width);
|
m_window_info.surface_width = std::max(1u, size.width);
|
||||||
m_window_info.surface_height = std::max(1u, size.height);
|
m_window_info.surface_height = std::max(1u, size.height);
|
||||||
|
m_actual_present_mode = present_mode.value();
|
||||||
|
|
||||||
// Get and create images.
|
// Get and create images.
|
||||||
pxAssert(m_images.empty());
|
pxAssert(m_images.empty());
|
||||||
|
@ -558,12 +552,12 @@ bool VKSwapChain::ResizeSwapChain(u32 new_width, u32 new_height, float new_scale
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VKSwapChain::SetVSync(VsyncMode mode)
|
bool VKSwapChain::SetVSyncEnabled(bool enabled)
|
||||||
{
|
{
|
||||||
if (m_vsync_mode == mode)
|
if (m_vsync_enabled == enabled)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
m_vsync_mode = mode;
|
m_vsync_enabled = enabled;
|
||||||
|
|
||||||
// Recreate the swap chain with the new present mode.
|
// Recreate the swap chain with the new present mode.
|
||||||
DevCon.WriteLn("Recreating swap chain to change present mode.");
|
DevCon.WriteLn("Recreating swap chain to change present mode.");
|
||||||
|
|
|
@ -25,7 +25,7 @@ public:
|
||||||
|
|
||||||
// Create a new swap chain from a pre-existing surface.
|
// Create a new swap chain from a pre-existing surface.
|
||||||
static std::unique_ptr<VKSwapChain> Create(
|
static std::unique_ptr<VKSwapChain> Create(
|
||||||
const WindowInfo& wi, VkSurfaceKHR surface, VsyncMode vsync, std::optional<bool> exclusive_fullscreen_control);
|
const WindowInfo& wi, VkSurfaceKHR surface, bool vsync, std::optional<bool> exclusive_fullscreen_control);
|
||||||
|
|
||||||
__fi VkSurfaceKHR GetSurface() const { return m_surface; }
|
__fi VkSurfaceKHR GetSurface() const { return m_surface; }
|
||||||
__fi VkSwapchainKHR GetSwapChain() const { return m_swap_chain; }
|
__fi VkSwapchainKHR GetSwapChain() const { return m_swap_chain; }
|
||||||
|
@ -57,7 +57,11 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns true if the current present mode is synchronizing (adaptive or hard).
|
// Returns true if the current present mode is synchronizing (adaptive or hard).
|
||||||
__fi bool IsPresentModeSynchronizing() const { return (m_vsync_mode != VsyncMode::Off); }
|
__fi bool IsPresentModeSynchronizing() const
|
||||||
|
{
|
||||||
|
return (m_actual_present_mode == VK_PRESENT_MODE_FIFO_KHR ||
|
||||||
|
m_actual_present_mode == VK_PRESENT_MODE_FIFO_RELAXED_KHR);
|
||||||
|
}
|
||||||
|
|
||||||
VkFormat GetTextureFormat() const;
|
VkFormat GetTextureFormat() const;
|
||||||
VkResult AcquireNextImage();
|
VkResult AcquireNextImage();
|
||||||
|
@ -67,14 +71,14 @@ public:
|
||||||
bool ResizeSwapChain(u32 new_width = 0, u32 new_height = 0, float new_scale = 1.0f);
|
bool ResizeSwapChain(u32 new_width = 0, u32 new_height = 0, float new_scale = 1.0f);
|
||||||
|
|
||||||
// Change vsync enabled state. This may fail as it causes a swapchain recreation.
|
// Change vsync enabled state. This may fail as it causes a swapchain recreation.
|
||||||
bool SetVSync(VsyncMode mode);
|
bool SetVSyncEnabled(bool enabled);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
VKSwapChain(
|
VKSwapChain(
|
||||||
const WindowInfo& wi, VkSurfaceKHR surface, VsyncMode vsync, std::optional<bool> exclusive_fullscreen_control);
|
const WindowInfo& wi, VkSurfaceKHR surface, bool vsync, std::optional<bool> exclusive_fullscreen_control);
|
||||||
|
|
||||||
static std::optional<VkSurfaceFormatKHR> SelectSurfaceFormat(VkSurfaceKHR surface);
|
static std::optional<VkSurfaceFormatKHR> SelectSurfaceFormat(VkSurfaceKHR surface);
|
||||||
static std::optional<VkPresentModeKHR> SelectPresentMode(VkSurfaceKHR surface, VsyncMode vsync);
|
static std::optional<VkPresentModeKHR> SelectPresentMode(VkSurfaceKHR surface, VkPresentModeKHR requested_mode);
|
||||||
|
|
||||||
bool CreateSwapChain();
|
bool CreateSwapChain();
|
||||||
void DestroySwapChain();
|
void DestroySwapChain();
|
||||||
|
@ -98,10 +102,11 @@ private:
|
||||||
std::vector<std::unique_ptr<GSTextureVK>> m_images;
|
std::vector<std::unique_ptr<GSTextureVK>> m_images;
|
||||||
std::vector<ImageSemaphores> m_semaphores;
|
std::vector<ImageSemaphores> m_semaphores;
|
||||||
|
|
||||||
VsyncMode m_vsync_mode = VsyncMode::Off;
|
VkPresentModeKHR m_actual_present_mode = VK_PRESENT_MODE_IMMEDIATE_KHR;
|
||||||
u32 m_current_image = 0;
|
u32 m_current_image = 0;
|
||||||
u32 m_current_semaphore = 0;
|
u32 m_current_semaphore = 0;
|
||||||
|
|
||||||
std::optional<VkResult> m_image_acquire_result;
|
std::optional<VkResult> m_image_acquire_result;
|
||||||
std::optional<bool> m_exclusive_fullscreen_control;
|
std::optional<bool> m_exclusive_fullscreen_control;
|
||||||
|
bool m_vsync_enabled = false;
|
||||||
};
|
};
|
||||||
|
|
|
@ -16,8 +16,6 @@
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
enum class VsyncMode;
|
|
||||||
|
|
||||||
class SettingsInterface;
|
class SettingsInterface;
|
||||||
|
|
||||||
namespace Host
|
namespace Host
|
||||||
|
|
|
@ -3482,11 +3482,6 @@ void FullscreenUI::DrawGraphicsSettingsPage(SettingsInterface* bsi, bool show_ad
|
||||||
"13", //GSRendererType::SW,
|
"13", //GSRendererType::SW,
|
||||||
"11", //GSRendererType::Null
|
"11", //GSRendererType::Null
|
||||||
};
|
};
|
||||||
static constexpr const char* s_vsync_values[] = {
|
|
||||||
FSUI_NSTR("Off"),
|
|
||||||
FSUI_NSTR("On"),
|
|
||||||
FSUI_NSTR("Adaptive"),
|
|
||||||
};
|
|
||||||
static constexpr const char* s_bilinear_present_options[] = {
|
static constexpr const char* s_bilinear_present_options[] = {
|
||||||
FSUI_NSTR("Off"),
|
FSUI_NSTR("Off"),
|
||||||
FSUI_NSTR("Bilinear (Smooth)"),
|
FSUI_NSTR("Bilinear (Smooth)"),
|
||||||
|
@ -3621,8 +3616,8 @@ void FullscreenUI::DrawGraphicsSettingsPage(SettingsInterface* bsi, bool show_ad
|
||||||
MenuHeading(FSUI_CSTR("Renderer"));
|
MenuHeading(FSUI_CSTR("Renderer"));
|
||||||
DrawStringListSetting(bsi, FSUI_CSTR("Renderer"), FSUI_CSTR("Selects the API used to render the emulated GS."), "EmuCore/GS",
|
DrawStringListSetting(bsi, FSUI_CSTR("Renderer"), FSUI_CSTR("Selects the API used to render the emulated GS."), "EmuCore/GS",
|
||||||
"Renderer", "-1", s_renderer_names, s_renderer_values, std::size(s_renderer_names), true);
|
"Renderer", "-1", s_renderer_names, s_renderer_values, std::size(s_renderer_names), true);
|
||||||
DrawIntListSetting(bsi, FSUI_CSTR("Sync To Host Refresh (VSync)"), FSUI_CSTR("Synchronizes frame presentation with host refresh."),
|
DrawToggleSetting(bsi, FSUI_CSTR("Sync To Host Refresh (VSync)"), FSUI_CSTR("Synchronizes frame presentation with host refresh."),
|
||||||
"EmuCore/GS", "VsyncEnable", static_cast<int>(VsyncMode::Off), s_vsync_values, std::size(s_vsync_values), true);
|
"EmuCore/GS", "VsyncEnable", false);
|
||||||
|
|
||||||
MenuHeading(FSUI_CSTR("Display"));
|
MenuHeading(FSUI_CSTR("Display"));
|
||||||
DrawStringListSetting(bsi, FSUI_CSTR("Aspect Ratio"), FSUI_CSTR("Selects the aspect ratio to display the game content at."),
|
DrawStringListSetting(bsi, FSUI_CSTR("Aspect Ratio"), FSUI_CSTR("Selects the aspect ratio to display the game content at."),
|
||||||
|
@ -7410,8 +7405,6 @@ TRANSLATE_NOOP("FullscreenUI", "Metal");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Software");
|
TRANSLATE_NOOP("FullscreenUI", "Software");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Null");
|
TRANSLATE_NOOP("FullscreenUI", "Null");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Off");
|
TRANSLATE_NOOP("FullscreenUI", "Off");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "On");
|
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Adaptive");
|
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Bilinear (Smooth)");
|
TRANSLATE_NOOP("FullscreenUI", "Bilinear (Smooth)");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "Bilinear (Sharp)");
|
TRANSLATE_NOOP("FullscreenUI", "Bilinear (Sharp)");
|
||||||
TRANSLATE_NOOP("FullscreenUI", "No Deinterlacing");
|
TRANSLATE_NOOP("FullscreenUI", "No Deinterlacing");
|
||||||
|
|
|
@ -931,7 +931,7 @@ void MTGS::ApplySettings()
|
||||||
|
|
||||||
RunOnGSThread([opts = EmuConfig.GS]() {
|
RunOnGSThread([opts = EmuConfig.GS]() {
|
||||||
GSUpdateConfig(opts);
|
GSUpdateConfig(opts);
|
||||||
GSSetVSyncMode(Host::GetEffectiveVSyncMode());
|
GSSetVSyncEnabled(Host::IsVsyncEffectivelyEnabled());
|
||||||
});
|
});
|
||||||
|
|
||||||
// We need to synchronize the thread when changing any settings when the download mode
|
// We need to synchronize the thread when changing any settings when the download mode
|
||||||
|
@ -970,19 +970,19 @@ void MTGS::UpdateDisplayWindow()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void MTGS::SetVSyncMode(VsyncMode mode)
|
void MTGS::SetVSyncEnabled(bool enabled)
|
||||||
{
|
{
|
||||||
pxAssertRel(IsOpen(), "MTGS is running");
|
pxAssertRel(IsOpen(), "MTGS is running");
|
||||||
|
|
||||||
RunOnGSThread([mode]() {
|
RunOnGSThread([enabled]() {
|
||||||
Console.WriteLn("Vsync is %s", mode == VsyncMode::Off ? "OFF" : (mode == VsyncMode::Adaptive ? "ADAPTIVE" : "ON"));
|
INFO_LOG("Vsync is {}", enabled ? "ON" : "OFF");
|
||||||
GSSetVSyncMode(mode);
|
GSSetVSyncEnabled(enabled);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void MTGS::UpdateVSyncMode()
|
void MTGS::UpdateVSyncEnabled()
|
||||||
{
|
{
|
||||||
SetVSyncMode(Host::GetEffectiveVSyncMode());
|
SetVSyncEnabled(Host::IsVsyncEffectivelyEnabled());
|
||||||
}
|
}
|
||||||
|
|
||||||
void MTGS::SetSoftwareRendering(bool software, GSInterlaceMode interlace, bool display_message /* = true */)
|
void MTGS::SetSoftwareRendering(bool software, GSInterlaceMode interlace, bool display_message /* = true */)
|
||||||
|
|
|
@ -70,8 +70,8 @@ namespace MTGS
|
||||||
void ApplySettings();
|
void ApplySettings();
|
||||||
void ResizeDisplayWindow(int width, int height, float scale);
|
void ResizeDisplayWindow(int width, int height, float scale);
|
||||||
void UpdateDisplayWindow();
|
void UpdateDisplayWindow();
|
||||||
void SetVSyncMode(VsyncMode mode);
|
void SetVSyncEnabled(bool enabled);
|
||||||
void UpdateVSyncMode();
|
void UpdateVSyncEnabled();
|
||||||
void SetSoftwareRendering(bool software, GSInterlaceMode interlace, bool display_message = true);
|
void SetSoftwareRendering(bool software, GSInterlaceMode interlace, bool display_message = true);
|
||||||
void ToggleSoftwareRendering();
|
void ToggleSoftwareRendering();
|
||||||
bool SaveMemorySnapshot(u32 window_width, u32 window_height, bool apply_aspect, bool crop_borders,
|
bool SaveMemorySnapshot(u32 window_width, u32 window_height, bool apply_aspect, bool crop_borders,
|
||||||
|
|
|
@ -793,11 +793,12 @@ void Pcsx2Config::GSOptions::LoadSave(SettingsWrapper& wrap)
|
||||||
SettingsWrapSection("EmuCore/GS");
|
SettingsWrapSection("EmuCore/GS");
|
||||||
|
|
||||||
#ifdef PCSX2_DEVBUILD
|
#ifdef PCSX2_DEVBUILD
|
||||||
SettingsWrapEntry(SynchronousMTGS);
|
SettingsWrapBitBool(SynchronousMTGS);
|
||||||
#endif
|
#endif
|
||||||
SettingsWrapEntry(VsyncQueueSize);
|
|
||||||
|
|
||||||
wrap.EnumEntry(CURRENT_SETTINGS_SECTION, "VsyncEnable", VsyncEnable, NULL, VsyncEnable);
|
SettingsWrapBitBool(VsyncEnable);
|
||||||
|
|
||||||
|
SettingsWrapEntry(VsyncQueueSize);
|
||||||
|
|
||||||
SettingsWrapEntry(FramerateNTSC);
|
SettingsWrapEntry(FramerateNTSC);
|
||||||
SettingsWrapEntry(FrameratePAL);
|
SettingsWrapEntry(FrameratePAL);
|
||||||
|
|
|
@ -2004,7 +2004,7 @@ double VMManager::AdjustToHostRefreshRate(float frame_rate, float target_speed)
|
||||||
const float ratio = host_refresh_rate / frame_rate;
|
const float ratio = host_refresh_rate / frame_rate;
|
||||||
const bool syncing_to_host = (ratio >= 0.95f && ratio <= 1.05f);
|
const bool syncing_to_host = (ratio >= 0.95f && ratio <= 1.05f);
|
||||||
s_target_speed_synced_to_host = syncing_to_host;
|
s_target_speed_synced_to_host = syncing_to_host;
|
||||||
s_use_vsync_for_timing = (syncing_to_host && !EmuConfig.GS.SkipDuplicateFrames && EmuConfig.GS.VsyncEnable != VsyncMode::Off);
|
s_use_vsync_for_timing = (syncing_to_host && !EmuConfig.GS.SkipDuplicateFrames && EmuConfig.GS.VsyncEnable);
|
||||||
Console.WriteLn("Refresh rate: Host=%fhz Guest=%fhz Ratio=%f - %s %s", host_refresh_rate, frame_rate, ratio,
|
Console.WriteLn("Refresh rate: Host=%fhz Guest=%fhz Ratio=%f - %s %s", host_refresh_rate, frame_rate, ratio,
|
||||||
syncing_to_host ? "can sync" : "can't sync", s_use_vsync_for_timing ? "and using vsync for pacing" : "and using sleep for pacing");
|
syncing_to_host ? "can sync" : "can't sync", s_use_vsync_for_timing ? "and using vsync for pacing" : "and using sleep for pacing");
|
||||||
|
|
||||||
|
@ -2051,7 +2051,7 @@ void VMManager::UpdateTargetSpeed()
|
||||||
{
|
{
|
||||||
s_target_speed = target_speed;
|
s_target_speed = target_speed;
|
||||||
|
|
||||||
MTGS::UpdateVSyncMode();
|
MTGS::UpdateVSyncEnabled();
|
||||||
SPU2::OnTargetSpeedChanged();
|
SPU2::OnTargetSpeedChanged();
|
||||||
ResetFrameLimiter();
|
ResetFrameLimiter();
|
||||||
}
|
}
|
||||||
|
@ -2546,13 +2546,13 @@ void VMManager::SetPaused(bool paused)
|
||||||
SetState(paused ? VMState::Paused : VMState::Running);
|
SetState(paused ? VMState::Paused : VMState::Running);
|
||||||
}
|
}
|
||||||
|
|
||||||
VsyncMode Host::GetEffectiveVSyncMode()
|
bool Host::IsVsyncEffectivelyEnabled()
|
||||||
{
|
{
|
||||||
const bool has_vm = VMManager::GetState() != VMState::Shutdown;
|
const bool has_vm = VMManager::GetState() != VMState::Shutdown;
|
||||||
|
|
||||||
// Force vsync off when not running at 100% speed.
|
// Force vsync off when not running at 100% speed.
|
||||||
if (has_vm && (s_target_speed != 1.0f && !s_use_vsync_for_timing))
|
if (has_vm && (s_target_speed != 1.0f && !s_use_vsync_for_timing))
|
||||||
return VsyncMode::Off;
|
return false;
|
||||||
|
|
||||||
// Otherwise use the config setting.
|
// Otherwise use the config setting.
|
||||||
return EmuConfig.GS.VsyncEnable;
|
return EmuConfig.GS.VsyncEnable;
|
||||||
|
@ -2739,6 +2739,7 @@ void VMManager::CheckForGSConfigChanges(const Pcsx2Config& old_config)
|
||||||
{
|
{
|
||||||
// Still need to update target speed, because of sync-to-host-refresh.
|
// Still need to update target speed, because of sync-to-host-refresh.
|
||||||
UpdateTargetSpeed();
|
UpdateTargetSpeed();
|
||||||
|
MTGS::UpdateVSyncEnabled();
|
||||||
}
|
}
|
||||||
|
|
||||||
MTGS::ApplySettings();
|
MTGS::ApplySettings();
|
||||||
|
|
Loading…
Reference in New Issue