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
|
||||
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
|
||||
si.SetBoolValue("InputSources", "SDL", false);
|
||||
|
|
|
@ -190,13 +190,6 @@ enum class SpeedHack
|
|||
MaxCount,
|
||||
};
|
||||
|
||||
enum class VsyncMode
|
||||
{
|
||||
Off,
|
||||
On,
|
||||
Adaptive,
|
||||
};
|
||||
|
||||
enum class AspectRatioType : u8
|
||||
{
|
||||
Stretch,
|
||||
|
@ -596,6 +589,8 @@ struct Pcsx2Config
|
|||
struct
|
||||
{
|
||||
bool
|
||||
SynchronousMTGS : 1,
|
||||
VsyncEnable : 1,
|
||||
PCRTCAntiBlur : 1,
|
||||
DisableInterlaceOffset : 1,
|
||||
PCRTCOffsets : 1,
|
||||
|
@ -618,9 +613,7 @@ struct Pcsx2Config
|
|||
OsdShowIndicators : 1,
|
||||
OsdShowSettings : 1,
|
||||
OsdShowInputs : 1,
|
||||
OsdShowFrameTimes : 1;
|
||||
|
||||
bool
|
||||
OsdShowFrameTimes : 1,
|
||||
HWSpinGPUForReadbacks : 1,
|
||||
HWSpinCPUForReadbacks : 1,
|
||||
GPUPaletteConversion : 1,
|
||||
|
@ -664,12 +657,6 @@ struct Pcsx2Config
|
|||
|
||||
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 FrameratePAL = DEFAULT_FRAME_RATE_PAL;
|
||||
|
||||
|
|
|
@ -471,7 +471,7 @@ void GSPresentCurrentFrame()
|
|||
|
||||
void GSThrottlePresentation()
|
||||
{
|
||||
if (g_gs_device->GetVsyncMode() != VsyncMode::Off)
|
||||
if (g_gs_device->IsVSyncEnabled())
|
||||
{
|
||||
// Let vsync take care of throttling.
|
||||
return;
|
||||
|
@ -528,9 +528,9 @@ void GSUpdateDisplayWindow()
|
|||
ImGuiManager::WindowResized();
|
||||
}
|
||||
|
||||
void GSSetVSyncMode(VsyncMode mode)
|
||||
void GSSetVSyncEnabled(bool enabled)
|
||||
{
|
||||
g_gs_device->SetVSync(mode);
|
||||
g_gs_device->SetVSyncEnabled(enabled);
|
||||
}
|
||||
|
||||
bool GSWantsExclusiveFullscreen()
|
||||
|
|
|
@ -84,7 +84,7 @@ void GSSetDisplayAlignment(GSDisplayAlignment alignment);
|
|||
bool GSHasDisplayWindow();
|
||||
void GSResizeDisplayWindow(int width, int height, float scale);
|
||||
void GSUpdateDisplayWindow();
|
||||
void GSSetVSyncMode(VsyncMode mode);
|
||||
void GSSetVSyncEnabled(bool enabled);
|
||||
|
||||
GSRendererType GSGetCurrentRenderer();
|
||||
bool GSIsHardwareRenderer();
|
||||
|
@ -127,7 +127,7 @@ namespace Host
|
|||
void SetFullscreen(bool enabled);
|
||||
|
||||
/// 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.
|
||||
void OnCaptureStarted(const std::string& filename);
|
||||
|
|
|
@ -307,7 +307,7 @@ int GSDevice::GetMipmapLevelsForSize(int width, int height)
|
|||
|
||||
bool GSDevice::Create()
|
||||
{
|
||||
m_vsync_mode = Host::GetEffectiveVSyncMode();
|
||||
m_vsync_enabled = Host::IsVsyncEffectivelyEnabled();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -803,7 +803,6 @@ protected:
|
|||
static constexpr u32 EXPAND_BUFFER_SIZE = sizeof(u16) * 16383 * 6;
|
||||
|
||||
WindowInfo m_window_info;
|
||||
VsyncMode m_vsync_mode = VsyncMode::Off;
|
||||
|
||||
GSTexture* m_imgui_font = nullptr;
|
||||
|
||||
|
@ -824,6 +823,7 @@ protected:
|
|||
u32 start, count;
|
||||
} m_index = {};
|
||||
unsigned int m_frame = 0; // for ageing the pool
|
||||
bool m_vsync_enabled = false;
|
||||
bool m_rbswapped = false;
|
||||
FeatureSupport m_features;
|
||||
|
||||
|
@ -874,7 +874,7 @@ public:
|
|||
__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 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; }
|
||||
|
||||
|
@ -915,7 +915,7 @@ public:
|
|||
virtual void EndPresent() = 0;
|
||||
|
||||
/// 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.
|
||||
virtual bool GetHostRefreshRate(float* refresh_rate);
|
||||
|
|
|
@ -628,9 +628,9 @@ bool GSDevice11::GetHostRefreshRate(float* 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()
|
||||
|
@ -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
|
||||
// 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.
|
||||
if (m_vsync_mode != VsyncMode::Off && m_gpu_timing_enabled)
|
||||
if (m_vsync_enabled && m_gpu_timing_enabled)
|
||||
PopTimestampQuery();
|
||||
|
||||
m_ctx->ClearRenderTargetView(m_swap_chain_rtv.get(), s_present_clear_color.data());
|
||||
|
@ -957,14 +957,13 @@ void GSDevice11::EndPresent()
|
|||
RenderImGui();
|
||||
|
||||
// See note in BeginPresent() for why it's conditional on vsync-off.
|
||||
const bool vsync_on = m_vsync_mode != VsyncMode::Off;
|
||||
if (!vsync_on && m_gpu_timing_enabled)
|
||||
if (!m_vsync_enabled && m_gpu_timing_enabled)
|
||||
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);
|
||||
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)
|
||||
KickTimestampQuery();
|
||||
|
|
|
@ -273,7 +273,7 @@ public:
|
|||
|
||||
bool GetHostRefreshRate(float* refresh_rate) override;
|
||||
|
||||
void SetVSync(VsyncMode mode) override;
|
||||
void SetVSyncEnabled(bool enabled) override;
|
||||
|
||||
PresentResult BeginPresent(bool frame_skip) override;
|
||||
void EndPresent() override;
|
||||
|
|
|
@ -774,9 +774,9 @@ bool GSDevice12::GetHostRefreshRate(float* 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()
|
||||
|
@ -1109,11 +1109,10 @@ void GSDevice12::EndPresent()
|
|||
return;
|
||||
}
|
||||
|
||||
const bool vsync = static_cast<UINT>(m_vsync_mode != VsyncMode::Off);
|
||||
if (!vsync && m_using_allow_tearing)
|
||||
if (!m_vsync_enabled && m_using_allow_tearing)
|
||||
m_swap_chain->Present(0, DXGI_PRESENT_ALLOW_TEARING);
|
||||
else
|
||||
m_swap_chain->Present(static_cast<UINT>(vsync), 0);
|
||||
m_swap_chain->Present(static_cast<UINT>(m_vsync_enabled), 0);
|
||||
|
||||
InvalidateCachedState();
|
||||
}
|
||||
|
|
|
@ -409,7 +409,7 @@ public:
|
|||
|
||||
bool GetHostRefreshRate(float* refresh_rate) override;
|
||||
|
||||
void SetVSync(VsyncMode mode) override;
|
||||
void SetVSyncEnabled(bool enabled) override;
|
||||
|
||||
PresentResult BeginPresent(bool frame_skip) override;
|
||||
void EndPresent() override;
|
||||
|
|
|
@ -392,7 +392,7 @@ public:
|
|||
|
||||
PresentResult BeginPresent(bool frame_skip) override;
|
||||
void EndPresent() override;
|
||||
void SetVSync(VsyncMode mode) override;
|
||||
void SetVSyncEnabled(bool enabled) override;
|
||||
|
||||
bool GetHostRefreshRate(float* refresh_rate) override;
|
||||
|
||||
|
|
|
@ -877,7 +877,7 @@ bool GSDeviceMTL::Create()
|
|||
{
|
||||
AttachSurfaceOnMainThread();
|
||||
});
|
||||
[m_layer setDisplaySyncEnabled:m_vsync_mode != VsyncMode::Off];
|
||||
[m_layer setDisplaySyncEnabled:m_vsync_enabled];
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1305,7 +1305,7 @@ void GSDeviceMTL::EndPresent()
|
|||
if (m_current_drawable)
|
||||
{
|
||||
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)
|
||||
[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;
|
||||
|
||||
[m_layer setDisplaySyncEnabled:mode != VsyncMode::Off];
|
||||
m_vsync_mode = mode;
|
||||
[m_layer setDisplaySyncEnabled:enabled];
|
||||
m_vsync_enabled = enabled;
|
||||
}
|
||||
|
||||
bool GSDeviceMTL::GetHostRefreshRate(float* refresh_rate)
|
||||
|
|
|
@ -35,6 +35,7 @@ public:
|
|||
virtual bool IsCurrent() = 0;
|
||||
virtual bool MakeCurrent() = 0;
|
||||
virtual bool DoneCurrent() = 0;
|
||||
virtual bool SupportsNegativeSwapInterval() const = 0;
|
||||
virtual bool SetSwapInterval(s32 interval) = 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);
|
||||
}
|
||||
|
||||
bool GLContextEGL::SupportsNegativeSwapInterval() const
|
||||
{
|
||||
return m_supports_negative_swap_interval;
|
||||
}
|
||||
|
||||
bool GLContextEGL::SetSwapInterval(s32 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);
|
||||
|
||||
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_version = version;
|
||||
return true;
|
||||
|
|
|
@ -24,6 +24,7 @@ public:
|
|||
bool IsCurrent() override;
|
||||
bool MakeCurrent() override;
|
||||
bool DoneCurrent() override;
|
||||
bool SupportsNegativeSwapInterval() const override;
|
||||
bool SetSwapInterval(s32 interval) override;
|
||||
virtual std::unique_ptr<GLContext> CreateSharedContext(const WindowInfo& wi, Error* error) override;
|
||||
|
||||
|
@ -52,4 +53,5 @@ protected:
|
|||
EGLConfig m_config = {};
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
bool GLContextWGL::SupportsNegativeSwapInterval() const
|
||||
{
|
||||
return GLAD_WGL_EXT_swap_control && GLAD_WGL_EXT_swap_control_tear;
|
||||
}
|
||||
|
||||
bool GLContextWGL::SetSwapInterval(s32 interval)
|
||||
{
|
||||
if (!GLAD_WGL_EXT_swap_control)
|
||||
|
|
|
@ -27,6 +27,7 @@ public:
|
|||
bool IsCurrent() override;
|
||||
bool MakeCurrent() override;
|
||||
bool DoneCurrent() override;
|
||||
bool SupportsNegativeSwapInterval() const override;
|
||||
bool SetSwapInterval(s32 interval) 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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
// Window framebuffer has to be bound to call SetSwapInterval.
|
||||
GLint current_fbo = 0;
|
||||
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;
|
||||
m_vsync_enabled = enabled;
|
||||
SetSwapInterval();
|
||||
}
|
||||
|
||||
bool GSDeviceOGL::Create()
|
||||
|
@ -777,8 +769,19 @@ bool GSDeviceOGL::CheckFeatures(bool& buggy_pbo)
|
|||
|
||||
void GSDeviceOGL::SetSwapInterval()
|
||||
{
|
||||
const int interval = ((m_vsync_mode == VsyncMode::Adaptive) ? -1 : ((m_vsync_mode == VsyncMode::On) ? 1 : 0));
|
||||
m_gl_context->SetSwapInterval(interval);
|
||||
if (m_window_info.type == WindowInfo::Type::Surfaceless)
|
||||
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()
|
||||
|
@ -868,9 +871,7 @@ bool GSDeviceOGL::UpdateWindow()
|
|||
if (m_window_info.type != WindowInfo::Type::Surfaceless)
|
||||
{
|
||||
// reset vsync rate, since it (usually) gets lost
|
||||
if (m_vsync_mode != VsyncMode::Adaptive || !m_gl_context->SetSwapInterval(-1))
|
||||
m_gl_context->SetSwapInterval(static_cast<s32>(m_vsync_mode != VsyncMode::Off));
|
||||
|
||||
SetSwapInterval();
|
||||
RenderBlankFrame();
|
||||
}
|
||||
|
||||
|
|
|
@ -292,7 +292,7 @@ public:
|
|||
void DestroySurface() override;
|
||||
std::string GetDriverInfo() const override;
|
||||
|
||||
void SetVSync(VsyncMode mode) override;
|
||||
void SetVSyncEnabled(bool enabled) override;
|
||||
|
||||
PresentResult BeginPresent(bool frame_skip) override;
|
||||
void EndPresent() override;
|
||||
|
|
|
@ -2222,7 +2222,7 @@ bool GSDeviceVK::UpdateWindow()
|
|||
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));
|
||||
if (!m_swap_chain)
|
||||
{
|
||||
|
@ -2297,24 +2297,27 @@ std::string GSDeviceVK::GetDriverInfo() const
|
|||
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;
|
||||
}
|
||||
|
||||
// This swap chain should not be used by the current buffer, thus safe to destroy.
|
||||
WaitForGPUIdle();
|
||||
if (!m_swap_chain->SetVSync(mode))
|
||||
if (!m_swap_chain->SetVSyncEnabled(enabled))
|
||||
{
|
||||
// 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");
|
||||
m_swap_chain.reset();
|
||||
}
|
||||
}
|
||||
|
||||
m_vsync_mode = mode;
|
||||
m_vsync_enabled = enabled;
|
||||
}
|
||||
|
||||
GSDevice::PresentResult GSDeviceVK::BeginPresent(bool frame_skip)
|
||||
|
@ -2613,7 +2616,7 @@ bool GSDeviceVK::CreateDeviceAndSwapChain()
|
|||
|
||||
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));
|
||||
if (!m_swap_chain)
|
||||
{
|
||||
|
|
|
@ -524,7 +524,7 @@ public:
|
|||
void DestroySurface() override;
|
||||
std::string GetDriverInfo() const override;
|
||||
|
||||
void SetVSync(VsyncMode mode) override;
|
||||
void SetVSyncEnabled(bool enabled) override;
|
||||
|
||||
PresentResult BeginPresent(bool frame_skip) override;
|
||||
void EndPresent() override;
|
||||
|
|
|
@ -18,11 +18,11 @@
|
|||
#endif
|
||||
|
||||
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_surface(surface)
|
||||
, m_vsync_mode(vsync)
|
||||
, 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(
|
||||
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>(new VKSwapChain(wi, surface, vsync, exclusive_fullscreen_control));
|
||||
|
@ -226,17 +226,7 @@ static const char* PresentModeToString(VkPresentModeKHR mode)
|
|||
}
|
||||
}
|
||||
|
||||
static VkPresentModeKHR GetPreferredPresentModeForVsyncMode(VsyncMode 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)
|
||||
std::optional<VkPresentModeKHR> VKSwapChain::SelectPresentMode(VkSurfaceKHR surface, VkPresentModeKHR requested_mode)
|
||||
{
|
||||
VkResult res;
|
||||
u32 mode_count;
|
||||
|
@ -261,18 +251,17 @@ std::optional<VkPresentModeKHR> VKSwapChain::SelectPresentMode(VkSurfaceKHR surf
|
|||
};
|
||||
|
||||
// Use preferred mode if available.
|
||||
const VkPresentModeKHR preferred_mode = GetPreferredPresentModeForVsyncMode(vsync);
|
||||
VkPresentModeKHR selected_mode;
|
||||
if (CheckForMode(preferred_mode))
|
||||
if (CheckForMode(requested_mode))
|
||||
{
|
||||
selected_mode = preferred_mode;
|
||||
selected_mode = requested_mode;
|
||||
}
|
||||
else if (vsync != VsyncMode::On && CheckForMode(VK_PRESENT_MODE_MAILBOX_KHR))
|
||||
else if (requested_mode != VK_PRESENT_MODE_FIFO_KHR && CheckForMode(VK_PRESENT_MODE_MAILBOX_KHR))
|
||||
{
|
||||
// Prefer mailbox over fifo for adaptive vsync/no-vsync.
|
||||
// Prefer mailbox over fifo for adaptive vsync/no-vsync. This way it'll only delay one frame.
|
||||
selected_mode = VK_PRESENT_MODE_MAILBOX_KHR;
|
||||
}
|
||||
else if (vsync != VsyncMode::Off && CheckForMode(VK_PRESENT_MODE_FIFO_KHR))
|
||||
else if (requested_mode == VK_PRESENT_MODE_FIFO_RELAXED_KHR && CheckForMode(VK_PRESENT_MODE_FIFO_KHR))
|
||||
{
|
||||
// Fallback to FIFO if we're using any kind of vsync.
|
||||
// This should never fail, FIFO is mandated.
|
||||
|
@ -284,7 +273,7 @@ std::optional<VkPresentModeKHR> VKSwapChain::SelectPresentMode(VkSurfaceKHR surf
|
|||
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));
|
||||
|
||||
return selected_mode;
|
||||
|
@ -294,7 +283,11 @@ bool VKSwapChain::CreateSwapChain()
|
|||
{
|
||||
// Select swap chain format and present mode
|
||||
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())
|
||||
return false;
|
||||
|
||||
|
@ -414,6 +407,7 @@ bool VKSwapChain::CreateSwapChain()
|
|||
|
||||
m_window_info.surface_width = std::max(1u, size.width);
|
||||
m_window_info.surface_height = std::max(1u, size.height);
|
||||
m_actual_present_mode = present_mode.value();
|
||||
|
||||
// Get and create images.
|
||||
pxAssert(m_images.empty());
|
||||
|
@ -558,12 +552,12 @@ bool VKSwapChain::ResizeSwapChain(u32 new_width, u32 new_height, float new_scale
|
|||
return true;
|
||||
}
|
||||
|
||||
bool VKSwapChain::SetVSync(VsyncMode mode)
|
||||
bool VKSwapChain::SetVSyncEnabled(bool enabled)
|
||||
{
|
||||
if (m_vsync_mode == mode)
|
||||
if (m_vsync_enabled == enabled)
|
||||
return true;
|
||||
|
||||
m_vsync_mode = mode;
|
||||
m_vsync_enabled = enabled;
|
||||
|
||||
// Recreate the swap chain with the new 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.
|
||||
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 VkSwapchainKHR GetSwapChain() const { return m_swap_chain; }
|
||||
|
@ -57,7 +57,11 @@ public:
|
|||
}
|
||||
|
||||
// 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;
|
||||
VkResult AcquireNextImage();
|
||||
|
@ -67,14 +71,14 @@ public:
|
|||
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.
|
||||
bool SetVSync(VsyncMode mode);
|
||||
bool SetVSyncEnabled(bool enabled);
|
||||
|
||||
private:
|
||||
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<VkPresentModeKHR> SelectPresentMode(VkSurfaceKHR surface, VsyncMode vsync);
|
||||
static std::optional<VkPresentModeKHR> SelectPresentMode(VkSurfaceKHR surface, VkPresentModeKHR requested_mode);
|
||||
|
||||
bool CreateSwapChain();
|
||||
void DestroySwapChain();
|
||||
|
@ -98,10 +102,11 @@ private:
|
|||
std::vector<std::unique_ptr<GSTextureVK>> m_images;
|
||||
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_semaphore = 0;
|
||||
|
||||
std::optional<VkResult> m_image_acquire_result;
|
||||
std::optional<bool> m_exclusive_fullscreen_control;
|
||||
bool m_vsync_enabled = false;
|
||||
};
|
||||
|
|
|
@ -16,8 +16,6 @@
|
|||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
enum class VsyncMode;
|
||||
|
||||
class SettingsInterface;
|
||||
|
||||
namespace Host
|
||||
|
|
|
@ -3482,11 +3482,6 @@ void FullscreenUI::DrawGraphicsSettingsPage(SettingsInterface* bsi, bool show_ad
|
|||
"13", //GSRendererType::SW,
|
||||
"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[] = {
|
||||
FSUI_NSTR("Off"),
|
||||
FSUI_NSTR("Bilinear (Smooth)"),
|
||||
|
@ -3621,8 +3616,8 @@ void FullscreenUI::DrawGraphicsSettingsPage(SettingsInterface* bsi, bool show_ad
|
|||
MenuHeading(FSUI_CSTR("Renderer"));
|
||||
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);
|
||||
DrawIntListSetting(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);
|
||||
DrawToggleSetting(bsi, FSUI_CSTR("Sync To Host Refresh (VSync)"), FSUI_CSTR("Synchronizes frame presentation with host refresh."),
|
||||
"EmuCore/GS", "VsyncEnable", false);
|
||||
|
||||
MenuHeading(FSUI_CSTR("Display"));
|
||||
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", "Null");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Off");
|
||||
TRANSLATE_NOOP("FullscreenUI", "On");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Adaptive");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Bilinear (Smooth)");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Bilinear (Sharp)");
|
||||
TRANSLATE_NOOP("FullscreenUI", "No Deinterlacing");
|
||||
|
|
|
@ -931,7 +931,7 @@ void MTGS::ApplySettings()
|
|||
|
||||
RunOnGSThread([opts = EmuConfig.GS]() {
|
||||
GSUpdateConfig(opts);
|
||||
GSSetVSyncMode(Host::GetEffectiveVSyncMode());
|
||||
GSSetVSyncEnabled(Host::IsVsyncEffectivelyEnabled());
|
||||
});
|
||||
|
||||
// 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");
|
||||
|
||||
RunOnGSThread([mode]() {
|
||||
Console.WriteLn("Vsync is %s", mode == VsyncMode::Off ? "OFF" : (mode == VsyncMode::Adaptive ? "ADAPTIVE" : "ON"));
|
||||
GSSetVSyncMode(mode);
|
||||
RunOnGSThread([enabled]() {
|
||||
INFO_LOG("Vsync is {}", enabled ? "ON" : "OFF");
|
||||
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 */)
|
||||
|
|
|
@ -70,8 +70,8 @@ namespace MTGS
|
|||
void ApplySettings();
|
||||
void ResizeDisplayWindow(int width, int height, float scale);
|
||||
void UpdateDisplayWindow();
|
||||
void SetVSyncMode(VsyncMode mode);
|
||||
void UpdateVSyncMode();
|
||||
void SetVSyncEnabled(bool enabled);
|
||||
void UpdateVSyncEnabled();
|
||||
void SetSoftwareRendering(bool software, GSInterlaceMode interlace, bool display_message = true);
|
||||
void ToggleSoftwareRendering();
|
||||
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");
|
||||
|
||||
#ifdef PCSX2_DEVBUILD
|
||||
SettingsWrapEntry(SynchronousMTGS);
|
||||
SettingsWrapBitBool(SynchronousMTGS);
|
||||
#endif
|
||||
SettingsWrapEntry(VsyncQueueSize);
|
||||
|
||||
wrap.EnumEntry(CURRENT_SETTINGS_SECTION, "VsyncEnable", VsyncEnable, NULL, VsyncEnable);
|
||||
SettingsWrapBitBool(VsyncEnable);
|
||||
|
||||
SettingsWrapEntry(VsyncQueueSize);
|
||||
|
||||
SettingsWrapEntry(FramerateNTSC);
|
||||
SettingsWrapEntry(FrameratePAL);
|
||||
|
|
|
@ -2004,7 +2004,7 @@ double VMManager::AdjustToHostRefreshRate(float frame_rate, float target_speed)
|
|||
const float ratio = host_refresh_rate / frame_rate;
|
||||
const bool syncing_to_host = (ratio >= 0.95f && ratio <= 1.05f);
|
||||
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,
|
||||
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;
|
||||
|
||||
MTGS::UpdateVSyncMode();
|
||||
MTGS::UpdateVSyncEnabled();
|
||||
SPU2::OnTargetSpeedChanged();
|
||||
ResetFrameLimiter();
|
||||
}
|
||||
|
@ -2546,13 +2546,13 @@ void VMManager::SetPaused(bool paused)
|
|||
SetState(paused ? VMState::Paused : VMState::Running);
|
||||
}
|
||||
|
||||
VsyncMode Host::GetEffectiveVSyncMode()
|
||||
bool Host::IsVsyncEffectivelyEnabled()
|
||||
{
|
||||
const bool has_vm = VMManager::GetState() != VMState::Shutdown;
|
||||
|
||||
// Force vsync off when not running at 100% speed.
|
||||
if (has_vm && (s_target_speed != 1.0f && !s_use_vsync_for_timing))
|
||||
return VsyncMode::Off;
|
||||
return false;
|
||||
|
||||
// Otherwise use the config setting.
|
||||
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.
|
||||
UpdateTargetSpeed();
|
||||
MTGS::UpdateVSyncEnabled();
|
||||
}
|
||||
|
||||
MTGS::ApplySettings();
|
||||
|
|
Loading…
Reference in New Issue