mirror of https://github.com/PCSX2/pcsx2.git
VMManager: Rewrite frame limiting
No more messing with counter state on setting changes. Closes #9929.
This commit is contained in:
parent
5df6fc4c1b
commit
abe64ae8fb
|
@ -658,7 +658,6 @@ struct Pcsx2Config
|
|||
PCRTCOffsets : 1,
|
||||
PCRTCOverscan : 1,
|
||||
IntegerScaling : 1,
|
||||
SyncToHostRefreshRate : 1,
|
||||
UseDebugDevice : 1,
|
||||
UseBlitSwapChain : 1,
|
||||
DisableShaderCache : 1,
|
||||
|
@ -726,11 +725,9 @@ struct Pcsx2Config
|
|||
// forces the MTGS to execute tags/tasks in fully blocking/synchronous
|
||||
// style. Useful for debugging potential bugs in the MTGS pipeline.
|
||||
bool SynchronousMTGS = false;
|
||||
bool FrameLimitEnable = true;
|
||||
|
||||
VsyncMode VsyncEnable = VsyncMode::Off;
|
||||
|
||||
float LimitScalar = 1.0f;
|
||||
float FramerateNTSC = DEFAULT_FRAME_RATE_NTSC;
|
||||
float FrameratePAL = DEFAULT_FRAME_RATE_PAL;
|
||||
|
||||
|
@ -1137,24 +1134,24 @@ struct Pcsx2Config
|
|||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
struct FramerateOptions
|
||||
struct EmulationSpeedOptions
|
||||
{
|
||||
BITFIELD32()
|
||||
bool FrameLimitEnable : 1;
|
||||
bool SyncToHostRefreshRate : 1;
|
||||
BITFIELD_END
|
||||
|
||||
float NominalScalar{1.0f};
|
||||
float TurboScalar{2.0f};
|
||||
float SlomoScalar{0.5f};
|
||||
|
||||
EmulationSpeedOptions();
|
||||
|
||||
void LoadSave(SettingsWrapper& wrap);
|
||||
void SanityCheck();
|
||||
|
||||
bool operator==(const FramerateOptions& right) const
|
||||
{
|
||||
return OpEqu(NominalScalar) && OpEqu(TurboScalar) && OpEqu(SlomoScalar);
|
||||
}
|
||||
|
||||
bool operator!=(const FramerateOptions& right) const
|
||||
{
|
||||
return !this->operator==(right);
|
||||
}
|
||||
bool operator==(const EmulationSpeedOptions& right) const;
|
||||
bool operator!=(const EmulationSpeedOptions& right) const;
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
@ -1320,7 +1317,7 @@ struct Pcsx2Config
|
|||
GamefixOptions Gamefixes;
|
||||
ProfilerOptions Profiler;
|
||||
DebugOptions Debugger;
|
||||
FramerateOptions Framerate;
|
||||
EmulationSpeedOptions EmulationSpeed;
|
||||
SPU2Options SPU2;
|
||||
DEV9Options DEV9;
|
||||
USBOptions USB;
|
||||
|
@ -1346,7 +1343,6 @@ struct Pcsx2Config
|
|||
std::string CurrentIRX;
|
||||
std::string CurrentGameArgs;
|
||||
AspectRatioType CurrentAspectRatio = AspectRatioType::RAuto4_3_3_2;
|
||||
LimiterModeType LimiterMode = LimiterModeType::Nominal;
|
||||
|
||||
Pcsx2Config();
|
||||
void LoadSave(SettingsWrapper& wrap);
|
||||
|
@ -1359,11 +1355,8 @@ struct Pcsx2Config
|
|||
std::string FullpathToBios() const;
|
||||
std::string FullpathToMcd(uint slot) const;
|
||||
|
||||
bool operator==(const Pcsx2Config& right) const;
|
||||
bool operator!=(const Pcsx2Config& right) const
|
||||
{
|
||||
return !this->operator==(right);
|
||||
}
|
||||
bool operator==(const Pcsx2Config& right) const = delete;
|
||||
bool operator!=(const Pcsx2Config& right) const = delete;
|
||||
|
||||
/// Copies runtime configuration settings (e.g. frame limiter state).
|
||||
void CopyRuntimeConfig(Pcsx2Config& cfg);
|
||||
|
|
|
@ -36,12 +36,9 @@
|
|||
#include "VMManager.h"
|
||||
#include "VUmicro.h"
|
||||
|
||||
using namespace Threading;
|
||||
|
||||
extern u8 psxhblankgate;
|
||||
static const uint EECNT_FUTURE_TARGET = 0x10000000;
|
||||
static int gates = 0;
|
||||
static bool s_use_vsync_for_timing = false;
|
||||
|
||||
uint g_FrameCount = 0;
|
||||
|
||||
|
@ -187,14 +184,6 @@ void rcntInit()
|
|||
cpuRcntSet();
|
||||
}
|
||||
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
static s64 m_iTicks=0;
|
||||
static u64 m_iStart=0;
|
||||
|
||||
struct vSyncTimingInfo
|
||||
{
|
||||
double Framerate; // frames per second (8 bit fixed)
|
||||
|
@ -210,10 +199,8 @@ struct vSyncTimingInfo
|
|||
u32 hScanlinesPerFrame; // number of scanlines per frame (525/625 for NTSC/PAL)
|
||||
};
|
||||
|
||||
|
||||
static vSyncTimingInfo vSyncInfo;
|
||||
|
||||
|
||||
static void vSyncInfoCalc(vSyncTimingInfo* info, double framesPerSecond, u32 scansPerFrame)
|
||||
{
|
||||
constexpr double clock = static_cast<double>(PS2CLK);
|
||||
|
@ -350,39 +337,6 @@ double GetVerticalFrequency()
|
|||
}
|
||||
}
|
||||
|
||||
static double AdjustToHostRefreshRate(double vertical_frequency, double frame_limit)
|
||||
{
|
||||
if (!EmuConfig.GS.SyncToHostRefreshRate || EmuConfig.GS.LimitScalar != 1.0f)
|
||||
{
|
||||
SPU2::SetDeviceSampleRateMultiplier(1.0);
|
||||
s_use_vsync_for_timing = false;
|
||||
return frame_limit;
|
||||
}
|
||||
|
||||
float host_refresh_rate;
|
||||
if (!GSGetHostRefreshRate(&host_refresh_rate))
|
||||
{
|
||||
Console.Warning("Cannot sync to host refresh since the query failed.");
|
||||
SPU2::SetDeviceSampleRateMultiplier(1.0);
|
||||
s_use_vsync_for_timing = false;
|
||||
return frame_limit;
|
||||
}
|
||||
|
||||
const double ratio = host_refresh_rate / vertical_frequency;
|
||||
const bool syncing_to_host = (ratio >= 0.95f && ratio <= 1.05f);
|
||||
s_use_vsync_for_timing = (syncing_to_host && !EmuConfig.GS.SkipDuplicateFrames && EmuConfig.GS.VsyncEnable != VsyncMode::Off);
|
||||
Console.WriteLn("Refresh rate: Host=%fhz Guest=%fhz Ratio=%f - %s %s", host_refresh_rate,
|
||||
vertical_frequency, ratio, syncing_to_host ? "can sync" : "can't sync",
|
||||
s_use_vsync_for_timing ? "and using vsync for pacing" : "and using sleep for pacing");
|
||||
|
||||
if (!syncing_to_host)
|
||||
return frame_limit;
|
||||
|
||||
frame_limit *= ratio;
|
||||
SPU2::SetDeviceSampleRateMultiplier(ratio);
|
||||
return frame_limit;
|
||||
}
|
||||
|
||||
void UpdateVSyncRate(bool force)
|
||||
{
|
||||
// Notice: (and I probably repeat this elsewhere, but it's worth repeating)
|
||||
|
@ -397,11 +351,6 @@ void UpdateVSyncRate(bool force)
|
|||
|
||||
if (vSyncInfo.Framerate != frames_per_second || vSyncInfo.VideoMode != gsVideoMode || force)
|
||||
{
|
||||
const double frame_limit = AdjustToHostRefreshRate(vertical_frequency, frames_per_second * EmuConfig.GS.LimitScalar);
|
||||
|
||||
const double tick_rate = GetTickFrequency() / 2.0;
|
||||
const s64 ticks = static_cast<s64>(tick_rate / std::max(frame_limit, 1.0));
|
||||
|
||||
u32 total_scanlines = 0;
|
||||
bool custom = false;
|
||||
|
||||
|
@ -471,20 +420,10 @@ void UpdateVSyncRate(bool force)
|
|||
((vsyncCounter.Mode == MODE_VSYNC) ? vSyncInfo.Blank : vSyncInfo.Render);
|
||||
cpuRcntSet();
|
||||
|
||||
PerformanceMetrics::SetVerticalFrequency(vertical_frequency);
|
||||
|
||||
if (m_iTicks != ticks)
|
||||
m_iTicks = ticks;
|
||||
|
||||
m_iStart = GetCPUTicks();
|
||||
VMManager::Internal::FrameRateChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void frameLimitReset()
|
||||
{
|
||||
m_iStart = GetCPUTicks();
|
||||
}
|
||||
|
||||
// FMV switch stuff
|
||||
extern uint eecount_on_last_vdec;
|
||||
extern bool FMVstarted;
|
||||
|
@ -546,55 +485,16 @@ static __fi void DoFMVSwitch()
|
|||
RendererSwitched = false;
|
||||
}
|
||||
|
||||
// Framelimiter - Measures the delta time between calls and stalls until a
|
||||
// certain amount of time passes if such time hasn't passed yet.
|
||||
static __fi void frameLimit()
|
||||
{
|
||||
// Framelimiter off in settings? Framelimiter go brrr.
|
||||
if (EmuConfig.GS.LimitScalar == 0.0f || s_use_vsync_for_timing)
|
||||
return;
|
||||
|
||||
const u64 uExpectedEnd = m_iStart + m_iTicks; // Compute when we would expect this frame to end, assuming everything goes perfectly perfect.
|
||||
const u64 iEnd = GetCPUTicks(); // The current tick we actually stopped on.
|
||||
const s64 sDeltaTime = iEnd - uExpectedEnd; // The diff between when we stopped and when we expected to.
|
||||
|
||||
// If frame ran too long...
|
||||
if (sDeltaTime >= m_iTicks)
|
||||
{
|
||||
// ... Fudge the next frame start over a bit. Prevents fast forward zoomies.
|
||||
m_iStart += (sDeltaTime / m_iTicks) * m_iTicks;
|
||||
return;
|
||||
}
|
||||
|
||||
// Conversion of delta from CPU ticks (microseconds) to milliseconds
|
||||
s32 msec = (int) ((sDeltaTime * -1000) / (s64) GetTickFrequency());
|
||||
|
||||
// If any integer value of milliseconds exists, sleep it off.
|
||||
// Prior comments suggested that 1-2 ms sleeps were inaccurate on some OSes;
|
||||
// further testing suggests instead that this was utter bullshit.
|
||||
if (msec > 1)
|
||||
{
|
||||
Threading::Sleep(msec - 1);
|
||||
}
|
||||
|
||||
// Conversion to milliseconds loses some precision; after sleeping off whole milliseconds,
|
||||
// spin the thread without sleeping until we finally reach our expected end time.
|
||||
while (GetCPUTicks() < uExpectedEnd)
|
||||
{
|
||||
// SKREEEEEEEE
|
||||
}
|
||||
|
||||
// Finally, set our next frame start to when this one ends
|
||||
m_iStart = uExpectedEnd;
|
||||
}
|
||||
|
||||
static __fi void VSyncStart(u32 sCycle)
|
||||
{
|
||||
// End-of-frame tasks.
|
||||
DoFMVSwitch();
|
||||
VMManager::Internal::VSyncOnCPUThread();
|
||||
|
||||
frameLimit(); // limit FPS
|
||||
// Don't bother throttling if we're going to pause.
|
||||
if (!VMManager::Internal::IsExecutionInterrupted())
|
||||
VMManager::Internal::Throttle();
|
||||
|
||||
gsPostVsyncStart(); // MUST be after framelimit; doing so before causes funk with frame times!
|
||||
|
||||
if(EmuConfig.Trace.Enabled && EmuConfig.Trace.EE.m_EnableAll)
|
||||
|
@ -628,7 +528,8 @@ static __fi void VSyncStart(u32 sCycle)
|
|||
// Without the patch and fixing this, the games have other issues, so I'm not going to rush to fix it.
|
||||
// Refraction
|
||||
|
||||
// Bail out before the next frame starts if we're paused, or the CPU has changed
|
||||
// Bail out before the next frame starts if we're paused, or the CPU has changed.
|
||||
// Need to re-check this, because we might've paused during the sleep time.
|
||||
if (VMManager::Internal::IsExecutionInterrupted())
|
||||
Cpu->ExitExecution();
|
||||
}
|
||||
|
|
|
@ -146,5 +146,4 @@ template< uint page > extern bool rcntWrite32( u32 mem, mem32_t& value );
|
|||
template< uint page > extern u16 rcntRead32( u32 mem ); // returns u16 by design! (see implementation for details)
|
||||
|
||||
extern void UpdateVSyncRate(bool force);
|
||||
extern void frameLimitReset();
|
||||
|
||||
|
|
32
pcsx2/GS.cpp
32
pcsx2/GS.cpp
|
@ -42,38 +42,6 @@ void gsReset()
|
|||
UpdateVSyncRate(true);
|
||||
}
|
||||
|
||||
void gsUpdateFrequency(Pcsx2Config& config)
|
||||
{
|
||||
if (config.GS.FrameLimitEnable &&
|
||||
(!config.EnableFastBootFastForward || !VMManager::Internal::IsFastBootInProgress()))
|
||||
{
|
||||
switch (config.LimiterMode)
|
||||
{
|
||||
case LimiterModeType::Nominal:
|
||||
config.GS.LimitScalar = config.Framerate.NominalScalar;
|
||||
break;
|
||||
case LimiterModeType::Slomo:
|
||||
config.GS.LimitScalar = config.Framerate.SlomoScalar;
|
||||
break;
|
||||
case LimiterModeType::Turbo:
|
||||
config.GS.LimitScalar = config.Framerate.TurboScalar;
|
||||
break;
|
||||
case LimiterModeType::Unlimited:
|
||||
config.GS.LimitScalar = 0.0f;
|
||||
break;
|
||||
default:
|
||||
pxAssert("Unknown framelimiter mode!");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
config.GS.LimitScalar = 0.0f;
|
||||
}
|
||||
|
||||
MTGS::UpdateVSyncMode();
|
||||
UpdateVSyncRate(true);
|
||||
}
|
||||
|
||||
static __fi void gsCSRwrite( const tGS_CSR& csr )
|
||||
{
|
||||
if (csr.RESET) {
|
||||
|
|
|
@ -283,7 +283,6 @@ extern bool gsIsInterlaced;
|
|||
extern void gsReset();
|
||||
extern void gsSetVideoMode(GS_VideoMode mode);
|
||||
extern void gsPostVsyncStart();
|
||||
extern void gsUpdateFrequency(Pcsx2Config& config);
|
||||
|
||||
extern void gsWrite8(u32 mem, u8 value);
|
||||
extern void gsWrite16(u32 mem, u16 value);
|
||||
|
|
|
@ -237,7 +237,7 @@ static void GSDumpReplayerSendPacketToMTGS(GIF_PATH path, const u8* data, u32 le
|
|||
static void GSDumpReplayerUpdateFrameLimit()
|
||||
{
|
||||
constexpr u32 default_frame_limit = 60;
|
||||
const u32 frame_limit = static_cast<u32>(default_frame_limit * EmuConfig.GS.LimitScalar);
|
||||
const u32 frame_limit = static_cast<u32>(default_frame_limit * VMManager::GetTargetSpeed());
|
||||
|
||||
if (frame_limit > 0)
|
||||
s_frame_ticks = (GetTickFrequency() + (frame_limit / 2)) / frame_limit;
|
||||
|
|
|
@ -41,12 +41,15 @@ void VMManager::Internal::ResetVMHotkeyState()
|
|||
static void HotkeyAdjustTargetSpeed(double delta)
|
||||
{
|
||||
const double min_speed = Achievements::ChallengeModeActive() ? 1.0 : 0.1;
|
||||
EmuConfig.Framerate.NominalScalar = std::max(min_speed, EmuConfig.Framerate.NominalScalar + delta);
|
||||
EmuConfig.LimiterMode = LimiterModeType::Unlimited; // force update
|
||||
VMManager::SetLimiterMode(LimiterModeType::Nominal);
|
||||
EmuConfig.EmulationSpeed.NominalScalar = std::max(min_speed, EmuConfig.EmulationSpeed.NominalScalar + delta);
|
||||
if (VMManager::GetLimiterMode() != LimiterModeType::Nominal)
|
||||
VMManager::SetLimiterMode(LimiterModeType::Nominal);
|
||||
else
|
||||
VMManager::UpdateTargetSpeed();
|
||||
|
||||
Host::AddIconOSDMessage("SpeedChanged", ICON_FA_CLOCK,
|
||||
fmt::format(TRANSLATE_FS("Hotkeys", "Target speed set to {:.0f}%."),
|
||||
std::round(EmuConfig.Framerate.NominalScalar * 100.0)),
|
||||
std::round(EmuConfig.EmulationSpeed.NominalScalar * 100.0)),
|
||||
Host::OSD_QUICK_DURATION);
|
||||
}
|
||||
|
||||
|
@ -166,7 +169,7 @@ DEFINE_HOTKEY("ToggleFrameLimit", TRANSLATE_NOOP("Hotkeys", "System"), TRANSLATE
|
|||
[](s32 pressed) {
|
||||
if (!pressed && VMManager::HasValidVM())
|
||||
{
|
||||
VMManager::SetLimiterMode((EmuConfig.LimiterMode != LimiterModeType::Unlimited) ?
|
||||
VMManager::SetLimiterMode((VMManager::GetLimiterMode() != LimiterModeType::Unlimited) ?
|
||||
LimiterModeType::Unlimited :
|
||||
LimiterModeType::Nominal);
|
||||
}
|
||||
|
@ -176,7 +179,7 @@ DEFINE_HOTKEY("ToggleTurbo", TRANSLATE_NOOP("Hotkeys", "System"),
|
|||
if (!pressed && VMManager::HasValidVM())
|
||||
{
|
||||
VMManager::SetLimiterMode(
|
||||
(EmuConfig.LimiterMode != LimiterModeType::Turbo) ? LimiterModeType::Turbo : LimiterModeType::Nominal);
|
||||
(VMManager::GetLimiterMode() != LimiterModeType::Turbo) ? LimiterModeType::Turbo : LimiterModeType::Nominal);
|
||||
}
|
||||
})
|
||||
DEFINE_HOTKEY("ToggleSlowMotion", TRANSLATE_NOOP("Hotkeys", "System"), TRANSLATE_NOOP("Hotkeys", "Toggle Slow Motion"),
|
||||
|
@ -184,7 +187,7 @@ DEFINE_HOTKEY("ToggleSlowMotion", TRANSLATE_NOOP("Hotkeys", "System"), TRANSLATE
|
|||
if (!pressed && VMManager::HasValidVM())
|
||||
{
|
||||
VMManager::SetLimiterMode(
|
||||
(EmuConfig.LimiterMode != LimiterModeType::Slomo) ? LimiterModeType::Slomo : LimiterModeType::Nominal);
|
||||
(VMManager::GetLimiterMode() != LimiterModeType::Slomo) ? LimiterModeType::Slomo : LimiterModeType::Nominal);
|
||||
}
|
||||
})
|
||||
DEFINE_HOTKEY("HoldTurbo", TRANSLATE_NOOP("Hotkeys", "System"),
|
||||
|
|
|
@ -1076,7 +1076,7 @@ void FullscreenUI::DoToggleFrameLimit()
|
|||
return;
|
||||
|
||||
VMManager::SetLimiterMode(
|
||||
(EmuConfig.LimiterMode != LimiterModeType::Unlimited) ? LimiterModeType::Unlimited : LimiterModeType::Nominal);
|
||||
(VMManager::GetLimiterMode() != LimiterModeType::Unlimited) ? LimiterModeType::Unlimited : LimiterModeType::Nominal);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -156,11 +156,11 @@ void ImGuiManager::DrawPerformanceOverlay(float& position_y)
|
|||
{
|
||||
fmt::format_to(std::back_inserter(text), "{}{}%", first ? "" : " | ", static_cast<u32>(std::round(speed)));
|
||||
|
||||
// We read the main config here, since MTGS doesn't get updated with speed toggles.
|
||||
if (EmuConfig.GS.LimitScalar == 0.0f)
|
||||
const float target_speed = VMManager::GetTargetSpeed();
|
||||
if (target_speed == 0.0f)
|
||||
text += " (Max)";
|
||||
else
|
||||
fmt::format_to(std::back_inserter(text), " ({:.0f}%)", EmuConfig.GS.LimitScalar * 100.0f);
|
||||
fmt::format_to(std::back_inserter(text), " ({:.0f}%)", target_speed * 100.0f);
|
||||
}
|
||||
if (!text.empty())
|
||||
{
|
||||
|
@ -249,10 +249,11 @@ void ImGuiManager::DrawPerformanceOverlay(float& position_y)
|
|||
|
||||
if (GSConfig.OsdShowIndicators)
|
||||
{
|
||||
const bool is_normal_speed = (EmuConfig.GS.LimitScalar == EmuConfig.Framerate.NominalScalar);
|
||||
const float target_speed = VMManager::GetTargetSpeed();
|
||||
const bool is_normal_speed = (target_speed == EmuConfig.EmulationSpeed.NominalScalar);
|
||||
if (!is_normal_speed)
|
||||
{
|
||||
const bool is_slowmo = (EmuConfig.GS.LimitScalar < EmuConfig.Framerate.NominalScalar);
|
||||
const bool is_slowmo = (target_speed < EmuConfig.EmulationSpeed.NominalScalar);
|
||||
DRAW_LINE(standard_font, is_slowmo ? ICON_FA_FORWARD : ICON_FA_FAST_FORWARD, IM_COL32(255, 255, 255, 255));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -500,7 +500,6 @@ Pcsx2Config::GSOptions::GSOptions()
|
|||
PCRTCOverscan = false;
|
||||
IntegerScaling = false;
|
||||
LinearPresent = GSPostBilinearMode::BilinearSmooth;
|
||||
SyncToHostRefreshRate = false;
|
||||
UseDebugDevice = false;
|
||||
UseBlitSwapChain = false;
|
||||
DisableShaderCache = false;
|
||||
|
@ -563,9 +562,6 @@ bool Pcsx2Config::GSOptions::operator==(const GSOptions& right) const
|
|||
OpEqu(SynchronousMTGS) &&
|
||||
OpEqu(VsyncQueueSize) &&
|
||||
|
||||
OpEqu(FrameLimitEnable) &&
|
||||
|
||||
OpEqu(LimitScalar) &&
|
||||
OpEqu(FramerateNTSC) &&
|
||||
OpEqu(FrameratePAL) &&
|
||||
|
||||
|
@ -686,14 +682,11 @@ void Pcsx2Config::GSOptions::LoadSave(SettingsWrapper& wrap)
|
|||
#endif
|
||||
SettingsWrapEntry(VsyncQueueSize);
|
||||
|
||||
SettingsWrapEntry(FrameLimitEnable);
|
||||
wrap.EnumEntry(CURRENT_SETTINGS_SECTION, "VsyncEnable", VsyncEnable, NULL, VsyncEnable);
|
||||
|
||||
// LimitScalar is set at runtime.
|
||||
SettingsWrapEntry(FramerateNTSC);
|
||||
SettingsWrapEntry(FrameratePAL);
|
||||
|
||||
SettingsWrapBitBool(SyncToHostRefreshRate);
|
||||
SettingsWrapEnumEx(AspectRatio, "AspectRatio", AspectRatioNames);
|
||||
SettingsWrapEnumEx(FMVAspectRatioSwitch, "FMVAspectRatioSwitch", FMVAspectRatioSwitchNames);
|
||||
SettingsWrapIntEnumEx(ScreenshotSize, "ScreenshotSize");
|
||||
|
@ -1270,7 +1263,15 @@ void Pcsx2Config::FilenameOptions::LoadSave(SettingsWrapper& wrap)
|
|||
wrap.Entry(CURRENT_SETTINGS_SECTION, "BIOS", Bios, Bios);
|
||||
}
|
||||
|
||||
void Pcsx2Config::FramerateOptions::SanityCheck()
|
||||
Pcsx2Config::EmulationSpeedOptions::EmulationSpeedOptions()
|
||||
{
|
||||
bitset = 0;
|
||||
|
||||
FrameLimitEnable = true;
|
||||
SyncToHostRefreshRate = false;
|
||||
}
|
||||
|
||||
void Pcsx2Config::EmulationSpeedOptions::SanityCheck()
|
||||
{
|
||||
// Ensure Conformation of various options...
|
||||
|
||||
|
@ -1279,13 +1280,29 @@ void Pcsx2Config::FramerateOptions::SanityCheck()
|
|||
SlomoScalar = std::clamp(SlomoScalar, 0.05f, 10.0f);
|
||||
}
|
||||
|
||||
void Pcsx2Config::FramerateOptions::LoadSave(SettingsWrapper& wrap)
|
||||
void Pcsx2Config::EmulationSpeedOptions::LoadSave(SettingsWrapper& wrap)
|
||||
{
|
||||
SettingsWrapSection("Framerate");
|
||||
|
||||
SettingsWrapEntry(NominalScalar);
|
||||
SettingsWrapEntry(TurboScalar);
|
||||
SettingsWrapEntry(SlomoScalar);
|
||||
|
||||
// This was in the wrong place... but we can't change it without breaking existing configs.
|
||||
//SettingsWrapBitBool(FrameLimitEnable);
|
||||
//SettingsWrapBitBool(SyncToHostRefreshRate);
|
||||
FrameLimitEnable = wrap.EntryBitBool("EmuCore/GS", "FrameLimitEnable", FrameLimitEnable, FrameLimitEnable);
|
||||
SyncToHostRefreshRate = wrap.EntryBitBool("EmuCore/GS", "SyncToHostRefreshRate", SyncToHostRefreshRate, SyncToHostRefreshRate);
|
||||
}
|
||||
|
||||
bool Pcsx2Config::EmulationSpeedOptions::operator==(const EmulationSpeedOptions& right) const
|
||||
{
|
||||
return OpEqu(bitset) && OpEqu(NominalScalar) && OpEqu(TurboScalar) && OpEqu(SlomoScalar);
|
||||
}
|
||||
|
||||
bool Pcsx2Config::EmulationSpeedOptions::operator!=(const EmulationSpeedOptions& right) const
|
||||
{
|
||||
return !this->operator==(right);
|
||||
}
|
||||
|
||||
Pcsx2Config::USBOptions::USBOptions()
|
||||
|
@ -1543,7 +1560,7 @@ void Pcsx2Config::LoadSaveCore(SettingsWrapper& wrap)
|
|||
SettingsWrapEntryEx(CurrentBlockdump, "BlockDumpSaveDirectory");
|
||||
|
||||
BaseFilenames.LoadSave(wrap);
|
||||
Framerate.LoadSave(wrap);
|
||||
EmulationSpeed.LoadSave(wrap);
|
||||
LoadSaveMemcards(wrap);
|
||||
|
||||
#ifdef _WIN32
|
||||
|
@ -1600,39 +1617,12 @@ std::string Pcsx2Config::FullpathToMcd(uint slot) const
|
|||
return Path::Combine(EmuFolders::MemoryCards, Mcd[slot].Filename);
|
||||
}
|
||||
|
||||
bool Pcsx2Config::operator==(const Pcsx2Config& right) const
|
||||
{
|
||||
bool equal =
|
||||
OpEqu(bitset) &&
|
||||
OpEqu(Cpu) &&
|
||||
OpEqu(GS) &&
|
||||
OpEqu(DEV9) &&
|
||||
OpEqu(Speedhacks) &&
|
||||
OpEqu(Gamefixes) &&
|
||||
OpEqu(Profiler) &&
|
||||
OpEqu(Debugger) &&
|
||||
OpEqu(Framerate) &&
|
||||
OpEqu(Trace) &&
|
||||
OpEqu(BaseFilenames) &&
|
||||
OpEqu(GzipIsoIndexTemplate) &&
|
||||
OpEqu(PINESlot);
|
||||
for (u32 i = 0; i < sizeof(Mcd) / sizeof(Mcd[0]); i++)
|
||||
{
|
||||
equal &= OpEqu(Mcd[i].Enabled);
|
||||
equal &= OpEqu(Mcd[i].Filename);
|
||||
}
|
||||
|
||||
return equal;
|
||||
}
|
||||
|
||||
void Pcsx2Config::CopyRuntimeConfig(Pcsx2Config& cfg)
|
||||
{
|
||||
GS.LimitScalar = cfg.GS.LimitScalar;
|
||||
CurrentBlockdump = std::move(cfg.CurrentBlockdump);
|
||||
CurrentIRX = std::move(cfg.CurrentIRX);
|
||||
CurrentGameArgs = std::move(cfg.CurrentGameArgs);
|
||||
CurrentAspectRatio = cfg.CurrentAspectRatio;
|
||||
LimiterMode = cfg.LimiterMode;
|
||||
|
||||
for (u32 i = 0; i < sizeof(Mcd) / sizeof(Mcd[0]); i++)
|
||||
{
|
||||
|
|
|
@ -32,7 +32,6 @@
|
|||
|
||||
static const float UPDATE_INTERVAL = 0.5f;
|
||||
|
||||
static float s_vertical_frequency = 0.0f;
|
||||
static float s_fps = 0.0f;
|
||||
static float s_internal_fps = 0.0f;
|
||||
static float s_minimum_frame_time = 0.0f;
|
||||
|
@ -268,11 +267,6 @@ void PerformanceMetrics::SetGSSWThread(u32 index, Threading::ThreadHandle thread
|
|||
s_gs_sw_threads[index].handle = std::move(thread);
|
||||
}
|
||||
|
||||
void PerformanceMetrics::SetVerticalFrequency(float rate)
|
||||
{
|
||||
s_vertical_frequency = rate;
|
||||
}
|
||||
|
||||
u64 PerformanceMetrics::GetFrameNumber()
|
||||
{
|
||||
return s_frame_number;
|
||||
|
@ -300,7 +294,7 @@ float PerformanceMetrics::GetInternalFPS()
|
|||
|
||||
float PerformanceMetrics::GetSpeed()
|
||||
{
|
||||
return (s_fps / s_vertical_frequency) * 100.0;
|
||||
return (s_fps / VMManager::GetFrameRate()) * 100.0;
|
||||
}
|
||||
|
||||
float PerformanceMetrics::GetAverageFrameTime()
|
||||
|
|
|
@ -42,9 +42,6 @@ namespace PerformanceMetrics
|
|||
void SetGSSWThreadCount(u32 count);
|
||||
void SetGSSWThread(u32 index, Threading::ThreadHandle thread);
|
||||
|
||||
/// Sets the vertical frequency, used in speed calculations.
|
||||
void SetVerticalFrequency(float rate);
|
||||
|
||||
u64 GetFrameNumber();
|
||||
|
||||
InternalFPSMethod GetInternalFPSMethod();
|
||||
|
|
|
@ -445,6 +445,11 @@ bool SndBuffer::Init(const char* modname)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool SndBuffer::IsOpen()
|
||||
{
|
||||
return (s_output_module != nullptr);
|
||||
}
|
||||
|
||||
void SndBuffer::Cleanup()
|
||||
{
|
||||
if (s_output_module)
|
||||
|
|
|
@ -304,6 +304,7 @@ namespace SndBuffer
|
|||
{
|
||||
void UpdateTempoChangeAsyncMixing();
|
||||
bool Init(const char* modname);
|
||||
bool IsOpen();
|
||||
void Cleanup();
|
||||
void Write(StereoOut16 Sample);
|
||||
void ClearContents();
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "Host.h"
|
||||
#include "IconsFontAwesome5.h"
|
||||
|
||||
#include "common/Assertions.h"
|
||||
#include "common/Console.h"
|
||||
#include "common/StringUtil.h"
|
||||
#include "common/RedtapeWindows.h"
|
||||
|
@ -136,6 +137,9 @@ public:
|
|||
|
||||
bool Init() override
|
||||
{
|
||||
if (stream)
|
||||
pxFailRel("Cubeb stream already open in Init()");
|
||||
|
||||
#ifdef _WIN32
|
||||
const HRESULT hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
|
||||
m_COMInitializedByUs = SUCCEEDED(hr);
|
||||
|
|
|
@ -174,7 +174,8 @@ void SPU2::SetDeviceSampleRateMultiplier(double multiplier)
|
|||
return;
|
||||
|
||||
s_device_sample_rate_multiplier = multiplier;
|
||||
UpdateSampleRate();
|
||||
if (SndBuffer::IsOpen())
|
||||
UpdateSampleRate();
|
||||
}
|
||||
|
||||
bool SPU2::Open()
|
||||
|
|
|
@ -96,7 +96,7 @@ namespace VMManager
|
|||
static void CheckForConfigChanges(const Pcsx2Config& old_config);
|
||||
static void CheckForCPUConfigChanges(const Pcsx2Config& old_config);
|
||||
static void CheckForGSConfigChanges(const Pcsx2Config& old_config);
|
||||
static void CheckForFramerateConfigChanges(const Pcsx2Config& old_config);
|
||||
static void CheckForEmulationSpeedConfigChanges(const Pcsx2Config& old_config);
|
||||
static void CheckForPatchConfigChanges(const Pcsx2Config& old_config);
|
||||
static void CheckForDEV9ConfigChanges(const Pcsx2Config& old_config);
|
||||
static void CheckForMemoryCardConfigChanges(const Pcsx2Config& old_config);
|
||||
|
@ -104,7 +104,6 @@ namespace VMManager
|
|||
static void EnforceAchievementsChallengeModeSettings();
|
||||
static void LogUnsafeSettingsToConsole(const std::string& messages);
|
||||
static void WarnAboutUnsafeSettings();
|
||||
static void ResetFrameLimiterState();
|
||||
|
||||
static bool AutoDetectSource(const std::string& filename);
|
||||
static void UpdateDiscDetails(bool booting);
|
||||
|
@ -133,6 +132,11 @@ namespace VMManager
|
|||
static void SaveSessionTime(const std::string& prev_serial);
|
||||
static void ReloadPINE();
|
||||
|
||||
static LimiterModeType GetInitialLimiterMode();
|
||||
static float GetTargetSpeedForLimiterMode(LimiterModeType mode);
|
||||
static void ResetFrameLimiter();
|
||||
static double AdjustToHostRefreshRate(float frame_rate, float target_speed);
|
||||
|
||||
static void SetTimerResolutionIncreased(bool enabled);
|
||||
static void SetHardwareDependentDefaultSettings(SettingsInterface& si);
|
||||
static void EnsureCPUInfoInitialized();
|
||||
|
@ -175,6 +179,12 @@ static u32 s_mxcsr_saved;
|
|||
static bool s_fast_boot_requested = false;
|
||||
static bool s_gs_open_on_initialize = false;
|
||||
|
||||
static LimiterModeType s_limiter_mode = LimiterModeType::Nominal;
|
||||
static s64 s_limiter_ticks_per_frame = 0;
|
||||
static u64 s_limiter_frame_start = 0;
|
||||
static float s_target_speed = 0.0f;
|
||||
static bool s_use_vsync_for_timing = false;
|
||||
|
||||
// Used to track play time. We use a monotonic timer here, in case of clock changes.
|
||||
static u64 s_session_start_time = 0;
|
||||
|
||||
|
@ -247,7 +257,7 @@ void VMManager::SetState(VMState state)
|
|||
else
|
||||
{
|
||||
PerformanceMetrics::Reset();
|
||||
frameLimitReset();
|
||||
ResetFrameLimiter();
|
||||
}
|
||||
|
||||
SPU2::SetOutputPaused(paused);
|
||||
|
@ -997,11 +1007,6 @@ bool VMManager::HasBootedELF()
|
|||
return s_current_crc != 0 && s_elf_executed;
|
||||
}
|
||||
|
||||
static LimiterModeType GetInitialLimiterMode()
|
||||
{
|
||||
return EmuConfig.GS.FrameLimitEnable ? LimiterModeType::Nominal : LimiterModeType::Unlimited;
|
||||
}
|
||||
|
||||
bool VMManager::AutoDetectSource(const std::string& filename)
|
||||
{
|
||||
if (!filename.empty())
|
||||
|
@ -1191,7 +1196,9 @@ bool VMManager::Initialize(VMBootParameters boot_params)
|
|||
}
|
||||
#endif
|
||||
|
||||
EmuConfig.LimiterMode = GetInitialLimiterMode();
|
||||
s_limiter_mode = GetInitialLimiterMode();
|
||||
s_target_speed = GetTargetSpeedForLimiterMode(s_limiter_mode);
|
||||
s_use_vsync_for_timing = false;
|
||||
|
||||
Console.WriteLn("Opening GS...");
|
||||
s_gs_open_on_initialize = MTGS::IsOpen();
|
||||
|
@ -1297,8 +1304,6 @@ bool VMManager::Initialize(VMBootParameters boot_params)
|
|||
SysClearExecutionCache();
|
||||
memBindConditionalHandlers();
|
||||
|
||||
gsUpdateFrequency(EmuConfig);
|
||||
frameLimitReset();
|
||||
cpuReset();
|
||||
|
||||
Console.WriteLn("VM subsystems initialized in %.2f ms", init_timer.GetTimeMilliseconds());
|
||||
|
@ -1309,8 +1314,6 @@ bool VMManager::Initialize(VMBootParameters boot_params)
|
|||
|
||||
SetEmuThreadAffinities();
|
||||
|
||||
PerformanceMetrics::Clear();
|
||||
|
||||
// do we want to load state?
|
||||
if (!GSDumpReplayer::IsReplayingDump() && !state_to_load.empty())
|
||||
{
|
||||
|
@ -1321,6 +1324,7 @@ bool VMManager::Initialize(VMBootParameters boot_params)
|
|||
}
|
||||
}
|
||||
|
||||
PerformanceMetrics::Clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1443,8 +1447,6 @@ void VMManager::Reset()
|
|||
|
||||
SysClearExecutionCache();
|
||||
memBindConditionalHandlers();
|
||||
UpdateVSyncRate(true);
|
||||
frameLimitReset();
|
||||
cpuReset();
|
||||
|
||||
if (g_InputRecording.isActive())
|
||||
|
@ -1453,6 +1455,8 @@ void VMManager::Reset()
|
|||
MTGS::PresentCurrentFrame();
|
||||
}
|
||||
|
||||
ResetFrameLimiter();
|
||||
|
||||
// If we were paused, state won't be resetting, so don't flip back to running.
|
||||
if (s_state.load(std::memory_order_acquire) == VMState::Resetting)
|
||||
s_state.store(VMState::Running, std::memory_order_release);
|
||||
|
@ -1747,17 +1751,160 @@ bool VMManager::SaveStateToSlot(s32 slot, bool zip_on_thread)
|
|||
|
||||
LimiterModeType VMManager::GetLimiterMode()
|
||||
{
|
||||
return EmuConfig.LimiterMode;
|
||||
return s_limiter_mode;
|
||||
}
|
||||
|
||||
void VMManager::SetLimiterMode(LimiterModeType type)
|
||||
{
|
||||
if (EmuConfig.LimiterMode == type)
|
||||
if (s_limiter_mode == type)
|
||||
return;
|
||||
|
||||
EmuConfig.LimiterMode = type;
|
||||
gsUpdateFrequency(EmuConfig);
|
||||
SPU2::OnTargetSpeedChanged();
|
||||
s_limiter_mode = type;
|
||||
UpdateTargetSpeed();
|
||||
}
|
||||
|
||||
float VMManager::GetTargetSpeed()
|
||||
{
|
||||
return s_target_speed;
|
||||
}
|
||||
|
||||
LimiterModeType VMManager::GetInitialLimiterMode()
|
||||
{
|
||||
return EmuConfig.EmulationSpeed.FrameLimitEnable ? LimiterModeType::Nominal : LimiterModeType::Unlimited;
|
||||
}
|
||||
|
||||
double VMManager::AdjustToHostRefreshRate(float frame_rate, float target_speed)
|
||||
{
|
||||
if (!EmuConfig.EmulationSpeed.SyncToHostRefreshRate || target_speed != 1.0f)
|
||||
{
|
||||
SPU2::SetDeviceSampleRateMultiplier(1.0);
|
||||
s_use_vsync_for_timing = false;
|
||||
return target_speed;
|
||||
}
|
||||
|
||||
float host_refresh_rate;
|
||||
if (!GSGetHostRefreshRate(&host_refresh_rate))
|
||||
{
|
||||
Console.Warning("Cannot sync to host refresh since the query failed.");
|
||||
SPU2::SetDeviceSampleRateMultiplier(1.0);
|
||||
s_use_vsync_for_timing = false;
|
||||
return target_speed;
|
||||
}
|
||||
|
||||
const double ratio = host_refresh_rate / frame_rate;
|
||||
const bool syncing_to_host = (ratio >= 0.95f && ratio <= 1.05f);
|
||||
s_use_vsync_for_timing = (syncing_to_host && !EmuConfig.GS.SkipDuplicateFrames && EmuConfig.GS.VsyncEnable != VsyncMode::Off);
|
||||
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");
|
||||
|
||||
if (!syncing_to_host)
|
||||
return target_speed;
|
||||
|
||||
target_speed *= ratio;
|
||||
SPU2::SetDeviceSampleRateMultiplier(ratio);
|
||||
return target_speed;
|
||||
}
|
||||
|
||||
float VMManager::GetTargetSpeedForLimiterMode(LimiterModeType mode)
|
||||
{
|
||||
if (EmuConfig.EmulationSpeed.FrameLimitEnable && (!EmuConfig.EnableFastBootFastForward || !VMManager::Internal::IsFastBootInProgress()))
|
||||
{
|
||||
switch (s_limiter_mode)
|
||||
{
|
||||
case LimiterModeType::Nominal:
|
||||
return EmuConfig.EmulationSpeed.NominalScalar;
|
||||
|
||||
case LimiterModeType::Slomo:
|
||||
return EmuConfig.EmulationSpeed.SlomoScalar;
|
||||
|
||||
case LimiterModeType::Turbo:
|
||||
return EmuConfig.EmulationSpeed.TurboScalar;
|
||||
|
||||
case LimiterModeType::Unlimited:
|
||||
return 0.0f;
|
||||
|
||||
jNO_DEFAULT
|
||||
}
|
||||
}
|
||||
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
void VMManager::UpdateTargetSpeed()
|
||||
{
|
||||
const float frame_rate = GetFrameRate();
|
||||
const float target_speed = AdjustToHostRefreshRate(frame_rate, GetTargetSpeedForLimiterMode(s_limiter_mode));
|
||||
const float target_frame_rate = frame_rate * target_speed;
|
||||
|
||||
s_limiter_ticks_per_frame =
|
||||
static_cast<s64>(static_cast<double>(GetTickFrequency()) / static_cast<double>(std::max(frame_rate * target_speed, 1.0f)));
|
||||
|
||||
DevCon.WriteLn(fmt::format("Frame rate: {}, target speed: {}, target frame rate: {}, ticks per frame: {}", frame_rate, target_speed,
|
||||
target_frame_rate, s_limiter_ticks_per_frame));
|
||||
|
||||
if (s_target_speed != target_speed)
|
||||
{
|
||||
s_target_speed = target_speed;
|
||||
|
||||
MTGS::UpdateVSyncMode();
|
||||
SPU2::OnTargetSpeedChanged();
|
||||
ResetFrameLimiter();
|
||||
}
|
||||
}
|
||||
|
||||
float VMManager::GetFrameRate()
|
||||
{
|
||||
return GetVerticalFrequency();
|
||||
}
|
||||
|
||||
void VMManager::ResetFrameLimiter()
|
||||
{
|
||||
s_limiter_frame_start = GetCPUTicks();
|
||||
}
|
||||
|
||||
void VMManager::Internal::Throttle()
|
||||
{
|
||||
if (s_target_speed == 0.0f || s_use_vsync_for_timing)
|
||||
return;
|
||||
|
||||
const u64 uExpectedEnd =
|
||||
s_limiter_frame_start +
|
||||
s_limiter_ticks_per_frame; // Compute when we would expect this frame to end, assuming everything goes perfectly perfect.
|
||||
const u64 iEnd = GetCPUTicks(); // The current tick we actually stopped on.
|
||||
const s64 sDeltaTime = iEnd - uExpectedEnd; // The diff between when we stopped and when we expected to.
|
||||
|
||||
// If frame ran too long...
|
||||
if (sDeltaTime >= s_limiter_ticks_per_frame)
|
||||
{
|
||||
// ... Fudge the next frame start over a bit. Prevents fast forward zoomies.
|
||||
s_limiter_frame_start += (sDeltaTime / s_limiter_ticks_per_frame) * s_limiter_ticks_per_frame;
|
||||
return;
|
||||
}
|
||||
|
||||
// Conversion of delta from CPU ticks (microseconds) to milliseconds
|
||||
const s32 msec = static_cast<s32>((sDeltaTime * -1000) / static_cast<s64>(GetTickFrequency()));
|
||||
|
||||
// If any integer value of milliseconds exists, sleep it off.
|
||||
// Prior comments suggested that 1-2 ms sleeps were inaccurate on some OSes;
|
||||
// further testing suggests instead that this was utter bullshit.
|
||||
if (msec > 1)
|
||||
{
|
||||
Threading::Sleep(msec - 1);
|
||||
}
|
||||
|
||||
// Conversion to milliseconds loses some precision; after sleeping off whole milliseconds,
|
||||
// spin the thread without sleeping until we finally reach our expected end time.
|
||||
while (GetCPUTicks() < uExpectedEnd)
|
||||
{
|
||||
}
|
||||
|
||||
// Finally, set our next frame start to when this one ends
|
||||
s_limiter_frame_start = uExpectedEnd;
|
||||
}
|
||||
|
||||
void VMManager::Internal::FrameRateChanged()
|
||||
{
|
||||
UpdateTargetSpeed();
|
||||
}
|
||||
|
||||
void VMManager::FrameAdvance(u32 num_frames /*= 1*/)
|
||||
|
@ -1904,7 +2051,7 @@ VsyncMode Host::GetEffectiveVSyncMode()
|
|||
const bool has_vm = VMManager::GetState() != VMState::Shutdown;
|
||||
|
||||
// Force vsync off when not running at 100% speed.
|
||||
if (has_vm && EmuConfig.GS.LimitScalar != 1.0f)
|
||||
if (has_vm && (s_target_speed != 1.0f && !s_use_vsync_for_timing))
|
||||
return VsyncMode::Off;
|
||||
|
||||
// Otherwise use the config setting.
|
||||
|
@ -1925,7 +2072,7 @@ void VMManager::Internal::DisableFastBoot()
|
|||
|
||||
// Stop fast forwarding boot if enabled.
|
||||
if (EmuConfig.EnableFastBootFastForward && !s_elf_executed)
|
||||
ResetFrameLimiterState();
|
||||
UpdateTargetSpeed();
|
||||
}
|
||||
|
||||
bool VMManager::Internal::HasBootedELF()
|
||||
|
@ -1978,7 +2125,7 @@ void VMManager::Internal::EntryPointCompilingOnCPUThread()
|
|||
|
||||
if (reset_speed_limiter)
|
||||
{
|
||||
ResetFrameLimiterState();
|
||||
UpdateTargetSpeed();
|
||||
PerformanceMetrics::Reset();
|
||||
}
|
||||
|
||||
|
@ -2077,22 +2224,30 @@ void VMManager::CheckForGSConfigChanges(const Pcsx2Config& old_config)
|
|||
|
||||
Console.WriteLn("Updating GS configuration...");
|
||||
|
||||
if (EmuConfig.GS.FrameLimitEnable != old_config.GS.FrameLimitEnable)
|
||||
EmuConfig.LimiterMode = GetInitialLimiterMode();
|
||||
// We could just check whichever NTSC or PAL is appropriate for our current mode,
|
||||
// but people _really_ shouldn't be screwing with framerate, so whatever.
|
||||
if (EmuConfig.GS.FramerateNTSC != old_config.GS.FramerateNTSC ||
|
||||
EmuConfig.GS.FrameratePAL != old_config.GS.FrameratePAL)
|
||||
{
|
||||
UpdateVSyncRate(false);
|
||||
UpdateTargetSpeed();
|
||||
}
|
||||
else if (EmuConfig.GS.VsyncEnable != old_config.GS.VsyncEnable)
|
||||
{
|
||||
// Still need to update target speed, because of sync-to-host-refresh.
|
||||
UpdateTargetSpeed();
|
||||
}
|
||||
|
||||
ResetFrameLimiterState();
|
||||
MTGS::ApplySettings();
|
||||
}
|
||||
|
||||
void VMManager::CheckForFramerateConfigChanges(const Pcsx2Config& old_config)
|
||||
void VMManager::CheckForEmulationSpeedConfigChanges(const Pcsx2Config& old_config)
|
||||
{
|
||||
if (EmuConfig.Framerate == old_config.Framerate)
|
||||
if (EmuConfig.EmulationSpeed == old_config.EmulationSpeed)
|
||||
return;
|
||||
|
||||
Console.WriteLn("Updating frame rate configuration");
|
||||
gsUpdateFrequency(EmuConfig);
|
||||
UpdateVSyncRate(true);
|
||||
frameLimitReset();
|
||||
Console.WriteLn("Updating emulation speed configuration");
|
||||
UpdateTargetSpeed();
|
||||
}
|
||||
|
||||
void VMManager::CheckForPatchConfigChanges(const Pcsx2Config& old_config)
|
||||
|
@ -2176,7 +2331,7 @@ void VMManager::CheckForMiscConfigChanges(const Pcsx2Config& old_config)
|
|||
if (EmuConfig.EnableFastBootFastForward && !old_config.EnableFastBootFastForward &&
|
||||
VMManager::Internal::IsFastBootInProgress())
|
||||
{
|
||||
ResetFrameLimiterState();
|
||||
UpdateTargetSpeed();
|
||||
}
|
||||
|
||||
if (EmuConfig.InhibitScreensaver != old_config.InhibitScreensaver)
|
||||
|
@ -2196,7 +2351,7 @@ void VMManager::CheckForConfigChanges(const Pcsx2Config& old_config)
|
|||
if (HasValidVM())
|
||||
{
|
||||
CheckForCPUConfigChanges(old_config);
|
||||
CheckForFramerateConfigChanges(old_config);
|
||||
CheckForEmulationSpeedConfigChanges(old_config);
|
||||
CheckForPatchConfigChanges(old_config);
|
||||
SPU2::CheckForConfigChanges(old_config);
|
||||
CheckForDEV9ConfigChanges(old_config);
|
||||
|
@ -2219,13 +2374,6 @@ void VMManager::CheckForConfigChanges(const Pcsx2Config& old_config)
|
|||
Host::CheckForSettingsChanges(old_config);
|
||||
}
|
||||
|
||||
void VMManager::ResetFrameLimiterState()
|
||||
{
|
||||
gsUpdateFrequency(EmuConfig);
|
||||
UpdateVSyncRate(true);
|
||||
frameLimitReset();
|
||||
}
|
||||
|
||||
void VMManager::ReloadPatches(bool reload_files, bool reload_enabled_list, bool verbose, bool verbose_if_changed)
|
||||
{
|
||||
if (!HasValidVM())
|
||||
|
@ -2252,9 +2400,9 @@ void VMManager::EnforceAchievementsChallengeModeSettings()
|
|||
};
|
||||
|
||||
// Can't use slow motion.
|
||||
ClampSpeed(EmuConfig.Framerate.NominalScalar);
|
||||
ClampSpeed(EmuConfig.Framerate.TurboScalar);
|
||||
ClampSpeed(EmuConfig.Framerate.SlomoScalar);
|
||||
ClampSpeed(EmuConfig.EmulationSpeed.NominalScalar);
|
||||
ClampSpeed(EmuConfig.EmulationSpeed.TurboScalar);
|
||||
ClampSpeed(EmuConfig.EmulationSpeed.SlomoScalar);
|
||||
|
||||
// Can't use cheats.
|
||||
if (EmuConfig.EnableCheats)
|
||||
|
|
|
@ -18,10 +18,8 @@
|
|||
#include <functional>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
|
||||
#include "common/Pcsx2Defs.h"
|
||||
|
||||
|
@ -149,6 +147,16 @@ namespace VMManager
|
|||
/// Updates the host vsync state, as well as timer frequencies. Call when the speed limiter is adjusted.
|
||||
void SetLimiterMode(LimiterModeType type);
|
||||
|
||||
/// Returns the target speed, based on the limiter mode.
|
||||
float GetTargetSpeed();
|
||||
|
||||
/// Ensures the target speed reflects the current configuration. Call if you change anything in
|
||||
/// EmuConfig.EmulationSpeed without going through the usual config apply.
|
||||
void UpdateTargetSpeed();
|
||||
|
||||
/// Returns the current frame rate of the virtual machine.
|
||||
float GetFrameRate();
|
||||
|
||||
/// Runs the virtual machine for the specified number of video frames, and then automatically pauses.
|
||||
void FrameAdvance(u32 num_frames = 1);
|
||||
|
||||
|
@ -236,6 +244,12 @@ namespace VMManager
|
|||
/// Returns the PC of the currently-executing ELF's entry point.
|
||||
u32 GetCurrentELFEntryPoint();
|
||||
|
||||
/// Called when the internal frame rate changes.
|
||||
void FrameRateChanged();
|
||||
|
||||
/// Throttles execution, or limits the frame rate.
|
||||
void Throttle();
|
||||
|
||||
const std::string& GetELFOverride();
|
||||
bool IsExecutionInterrupted();
|
||||
void ELFLoadingOnCPUThread(std::string elf_path);
|
||||
|
|
Loading…
Reference in New Issue