mirror of https://github.com/PCSX2/pcsx2.git
GS: Add heuristic-based internal FPS
This commit is contained in:
parent
a504b429bd
commit
d3152bee9c
|
@ -552,8 +552,6 @@ static __fi void VSyncStart(u32 sCycle)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
PerformanceMetrics::Update();
|
|
||||||
|
|
||||||
frameLimit(); // limit FPS
|
frameLimit(); // limit FPS
|
||||||
gsPostVsyncStart(); // MUST be after framelimit; doing so before causes funk with frame times!
|
gsPostVsyncStart(); // MUST be after framelimit; doing so before causes funk with frame times!
|
||||||
|
|
||||||
|
|
|
@ -509,7 +509,21 @@ static void DrawPerformanceOverlay()
|
||||||
const float speed = PerformanceMetrics::GetSpeed();
|
const float speed = PerformanceMetrics::GetSpeed();
|
||||||
if (GSConfig.OsdShowFPS)
|
if (GSConfig.OsdShowFPS)
|
||||||
{
|
{
|
||||||
text.Write("%.2f", PerformanceMetrics::GetFPS());
|
switch (PerformanceMetrics::GetInternalFPSMethod())
|
||||||
|
{
|
||||||
|
case PerformanceMetrics::InternalFPSMethod::GSPrivilegedRegister:
|
||||||
|
text.Write("G: %.2f [P] | V: %.2f", PerformanceMetrics::GetInternalFPS(), PerformanceMetrics::GetFPS());
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PerformanceMetrics::InternalFPSMethod::DISPFBBlit:
|
||||||
|
text.Write("G: %.2f [B] | V: %.2f", PerformanceMetrics::GetInternalFPS(), PerformanceMetrics::GetFPS());
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PerformanceMetrics::InternalFPSMethod::None:
|
||||||
|
default:
|
||||||
|
text.Write("V: %.2f", PerformanceMetrics::GetFPS());
|
||||||
|
break;
|
||||||
|
}
|
||||||
first = false;
|
first = false;
|
||||||
}
|
}
|
||||||
if (GSConfig.OsdShowSpeed)
|
if (GSConfig.OsdShowSpeed)
|
||||||
|
|
|
@ -26,6 +26,7 @@ using namespace Threading;
|
||||||
using namespace R5900;
|
using namespace R5900;
|
||||||
|
|
||||||
alignas(16) u8 g_RealGSMem[Ps2MemSize::GSregs];
|
alignas(16) u8 g_RealGSMem[Ps2MemSize::GSregs];
|
||||||
|
static bool s_GSRegistersWritten = false;
|
||||||
|
|
||||||
void gsSetVideoMode(GS_VideoMode mode)
|
void gsSetVideoMode(GS_VideoMode mode)
|
||||||
{
|
{
|
||||||
|
@ -222,6 +223,8 @@ void __fastcall gsWrite64_generic( u32 mem, const mem64_t* value )
|
||||||
|
|
||||||
void __fastcall gsWrite64_page_00( u32 mem, const mem64_t* value )
|
void __fastcall gsWrite64_page_00( u32 mem, const mem64_t* value )
|
||||||
{
|
{
|
||||||
|
s_GSRegistersWritten |= (mem == GS_DISPFB1 || mem == GS_DISPFB2 || mem == GS_PMODE);
|
||||||
|
|
||||||
gsWrite64_generic( mem, value );
|
gsWrite64_generic( mem, value );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -433,7 +436,9 @@ void gsPostVsyncStart()
|
||||||
{
|
{
|
||||||
//gifUnit.FlushToMTGS(); // Needed for some (broken?) homebrew game loaders
|
//gifUnit.FlushToMTGS(); // Needed for some (broken?) homebrew game loaders
|
||||||
|
|
||||||
GetMTGS().PostVsyncStart();
|
const bool registers_written = s_GSRegistersWritten;
|
||||||
|
s_GSRegistersWritten = false;
|
||||||
|
GetMTGS().PostVsyncStart(registers_written);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _gs_ResetFrameskip()
|
void _gs_ResetFrameskip()
|
||||||
|
|
|
@ -385,7 +385,7 @@ public:
|
||||||
|
|
||||||
u8* GetDataPacketPtr() const;
|
u8* GetDataPacketPtr() const;
|
||||||
void SetEvent();
|
void SetEvent();
|
||||||
void PostVsyncStart();
|
void PostVsyncStart(bool registers_written);
|
||||||
|
|
||||||
bool IsGSOpened() const { return m_Opened; }
|
bool IsGSOpened() const { return m_Opened; }
|
||||||
|
|
||||||
|
|
|
@ -464,11 +464,11 @@ void GSgifTransfer3(u8* mem, u32 size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GSvsync(u32 field)
|
void GSvsync(u32 field, bool registers_written)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
s_gs->VSync(field);
|
s_gs->VSync(field, registers_written);
|
||||||
}
|
}
|
||||||
catch (GSRecoverableError)
|
catch (GSRecoverableError)
|
||||||
{
|
{
|
||||||
|
|
|
@ -68,7 +68,7 @@ void GSgifTransfer(const u8* mem, u32 size);
|
||||||
void GSgifTransfer1(u8* mem, u32 addr);
|
void GSgifTransfer1(u8* mem, u32 addr);
|
||||||
void GSgifTransfer2(u8* mem, u32 size);
|
void GSgifTransfer2(u8* mem, u32 size);
|
||||||
void GSgifTransfer3(u8* mem, u32 size);
|
void GSgifTransfer3(u8* mem, u32 size);
|
||||||
void GSvsync(u32 field);
|
void GSvsync(u32 field, bool registers_written);
|
||||||
u32 GSmakeSnapshot(char* path);
|
u32 GSmakeSnapshot(char* path);
|
||||||
int GSfreeze(FreezeAction mode, freezeData* data);
|
int GSfreeze(FreezeAction mode, freezeData* data);
|
||||||
#ifndef PCSX2_CORE
|
#ifndef PCSX2_CORE
|
||||||
|
|
|
@ -52,6 +52,7 @@ protected:
|
||||||
u64 m_frame;
|
u64 m_frame;
|
||||||
clock_t m_lastframe;
|
clock_t m_lastframe;
|
||||||
int m_count;
|
int m_count;
|
||||||
|
int m_disp_fb_sprite_blits;
|
||||||
|
|
||||||
friend class GSPerfMonAutoTimer;
|
friend class GSPerfMonAutoTimer;
|
||||||
|
|
||||||
|
@ -69,6 +70,14 @@ public:
|
||||||
|
|
||||||
void Start(int timer = Main);
|
void Start(int timer = Main);
|
||||||
void Stop(int timer = Main);
|
void Stop(int timer = Main);
|
||||||
|
|
||||||
|
__fi void AddDisplayFramebufferSpriteBlit() { m_disp_fb_sprite_blits++; }
|
||||||
|
__fi int GetDisplayFramebufferSpriteBlits()
|
||||||
|
{
|
||||||
|
const int blits = m_disp_fb_sprite_blits;
|
||||||
|
m_disp_fb_sprite_blits = 0;
|
||||||
|
return blits;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class GSPerfMonAutoTimer
|
class GSPerfMonAutoTimer
|
||||||
|
|
|
@ -1406,6 +1406,16 @@ void GSState::FlushPrim()
|
||||||
{
|
{
|
||||||
GL_REG("FlushPrim ctxt %d", PRIM->CTXT);
|
GL_REG("FlushPrim ctxt %d", PRIM->CTXT);
|
||||||
|
|
||||||
|
// internal frame rate detection based on sprite blits to the display framebuffer
|
||||||
|
{
|
||||||
|
const u32 FRAME_FBP = m_context->FRAME.FBP;
|
||||||
|
if ((m_regs->DISP[0].DISPFB.FBP == FRAME_FBP && m_regs->PMODE.EN1) ||
|
||||||
|
(m_regs->DISP[1].DISPFB.FBP == FRAME_FBP && m_regs->PMODE.EN2))
|
||||||
|
{
|
||||||
|
g_perfmon.AddDisplayFramebufferSpriteBlit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
GSVertex buff[2];
|
GSVertex buff[2];
|
||||||
s_n++;
|
s_n++;
|
||||||
|
|
||||||
|
|
|
@ -388,7 +388,7 @@ static GSVector4 CalculateDrawRect(s32 window_width, s32 window_height, s32 text
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GSRenderer::VSync(u32 field)
|
void GSRenderer::VSync(u32 field, bool registers_written)
|
||||||
{
|
{
|
||||||
GSPerfMonAutoTimer pmat(&g_perfmon);
|
GSPerfMonAutoTimer pmat(&g_perfmon);
|
||||||
|
|
||||||
|
@ -399,6 +399,10 @@ void GSRenderer::VSync(u32 field)
|
||||||
m_regs->Dump(root_sw + format("%05d_f%lld_gs_reg.txt", s_n, g_perfmon.GetFrame()));
|
m_regs->Dump(root_sw + format("%05d_f%lld_gs_reg.txt", s_n, g_perfmon.GetFrame()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const int fb_sprite_blits = g_perfmon.GetDisplayFramebufferSpriteBlits();
|
||||||
|
const bool fb_sprite_frame = (fb_sprite_blits > 0);
|
||||||
|
PerformanceMetrics::Update(registers_written, fb_sprite_frame);
|
||||||
|
|
||||||
g_gs_device->AgePool();
|
g_gs_device->AgePool();
|
||||||
|
|
||||||
const bool blank_frame = !Merge(field ? 1 : 0);
|
const bool blank_frame = !Merge(field ? 1 : 0);
|
||||||
|
|
|
@ -44,7 +44,7 @@ public:
|
||||||
|
|
||||||
virtual void Destroy();
|
virtual void Destroy();
|
||||||
|
|
||||||
virtual void VSync(u32 field);
|
virtual void VSync(u32 field, bool registers_written);
|
||||||
virtual bool MakeSnapshot(const std::string& path);
|
virtual bool MakeSnapshot(const std::string& path);
|
||||||
virtual void KeyEvent(const HostKeyEvent& e);
|
virtual void KeyEvent(const HostKeyEvent& e);
|
||||||
virtual bool CanUpscale() { return false; }
|
virtual bool CanUpscale() { return false; }
|
||||||
|
|
|
@ -291,7 +291,7 @@ void GSRendererHW::Reset()
|
||||||
GSRenderer::Reset();
|
GSRenderer::Reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GSRendererHW::VSync(u32 field)
|
void GSRendererHW::VSync(u32 field, bool registers_written)
|
||||||
{
|
{
|
||||||
//Check if the frame buffer width or display width has changed
|
//Check if the frame buffer width or display width has changed
|
||||||
SetScaling();
|
SetScaling();
|
||||||
|
@ -303,7 +303,7 @@ void GSRendererHW::VSync(u32 field)
|
||||||
m_reset = false;
|
m_reset = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
GSRenderer::VSync(field);
|
GSRenderer::VSync(field, registers_written);
|
||||||
|
|
||||||
m_tc->IncAge();
|
m_tc->IncAge();
|
||||||
|
|
||||||
|
|
|
@ -182,7 +182,7 @@ public:
|
||||||
GSVector2 GetTextureScaleFactor() override;
|
GSVector2 GetTextureScaleFactor() override;
|
||||||
|
|
||||||
void Reset() override;
|
void Reset() override;
|
||||||
void VSync(u32 field) override;
|
void VSync(u32 field, bool registers_written) override;
|
||||||
|
|
||||||
GSTexture* GetOutput(int i, int& y_offset) override;
|
GSTexture* GetOutput(int i, int& y_offset) override;
|
||||||
GSTexture* GetFeedbackOutput() override;
|
GSTexture* GetFeedbackOutput() override;
|
||||||
|
|
|
@ -91,7 +91,7 @@ void GSRendererSW::Reset()
|
||||||
GSRenderer::Reset();
|
GSRenderer::Reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GSRendererSW::VSync(u32 field)
|
void GSRendererSW::VSync(u32 field, bool registers_written)
|
||||||
{
|
{
|
||||||
Sync(0); // IncAge might delete a cached texture in use
|
Sync(0); // IncAge might delete a cached texture in use
|
||||||
|
|
||||||
|
@ -128,7 +128,7 @@ void GSRendererSW::VSync(u32 field)
|
||||||
//
|
//
|
||||||
*/
|
*/
|
||||||
|
|
||||||
GSRenderer::VSync(field);
|
GSRenderer::VSync(field, registers_written);
|
||||||
|
|
||||||
m_tc->IncAge();
|
m_tc->IncAge();
|
||||||
|
|
||||||
|
|
|
@ -80,7 +80,7 @@ protected:
|
||||||
std::atomic<u16> m_tex_pages[512];
|
std::atomic<u16> m_tex_pages[512];
|
||||||
|
|
||||||
void Reset() override;
|
void Reset() override;
|
||||||
void VSync(u32 field) override;
|
void VSync(u32 field, bool registers_written) override;
|
||||||
GSTexture* GetOutput(int i, int& y_offset) override;
|
GSTexture* GetOutput(int i, int& y_offset) override;
|
||||||
GSTexture* GetFeedbackOutput() override;
|
GSTexture* GetFeedbackOutput() override;
|
||||||
|
|
||||||
|
|
|
@ -129,9 +129,13 @@ struct RingCmdPacket_Vsync
|
||||||
u32 csr;
|
u32 csr;
|
||||||
u32 imr;
|
u32 imr;
|
||||||
GSRegSIGBLID siglblid;
|
GSRegSIGBLID siglblid;
|
||||||
|
|
||||||
|
// must be 16 byte aligned
|
||||||
|
u32 registers_written;
|
||||||
|
u32 pad[3];
|
||||||
};
|
};
|
||||||
|
|
||||||
void SysMtgsThread::PostVsyncStart()
|
void SysMtgsThread::PostVsyncStart(bool registers_written)
|
||||||
{
|
{
|
||||||
// Optimization note: Typically regset1 isn't needed. The regs in that area are typically
|
// Optimization note: Typically regset1 isn't needed. The regs in that area are typically
|
||||||
// changed infrequently, usually during video mode changes. However, on modern systems the
|
// changed infrequently, usually during video mode changes. However, on modern systems the
|
||||||
|
@ -146,7 +150,8 @@ void SysMtgsThread::PostVsyncStart()
|
||||||
remainder[0] = GSCSRr;
|
remainder[0] = GSCSRr;
|
||||||
remainder[1] = GSIMR._u32;
|
remainder[1] = GSIMR._u32;
|
||||||
(GSRegSIGBLID&)remainder[2] = GSSIGLBLID;
|
(GSRegSIGBLID&)remainder[2] = GSSIGLBLID;
|
||||||
m_packet_writepos = (m_packet_writepos + 1) & RingBufferMask;
|
remainder[4] = static_cast<u32>(registers_written);
|
||||||
|
m_packet_writepos = (m_packet_writepos + 2) & RingBufferMask;
|
||||||
|
|
||||||
SendDataPacket();
|
SendDataPacket();
|
||||||
|
|
||||||
|
@ -436,7 +441,7 @@ void SysMtgsThread::ExecuteTaskInThread()
|
||||||
((GSRegSIGBLID&)RingBuffer.Regs[0x1080]) = (GSRegSIGBLID&)remainder[2];
|
((GSRegSIGBLID&)RingBuffer.Regs[0x1080]) = (GSRegSIGBLID&)remainder[2];
|
||||||
|
|
||||||
// CSR & 0x2000; is the pageflip id.
|
// CSR & 0x2000; is the pageflip id.
|
||||||
GSvsync(((u32&)RingBuffer.Regs[0x1000]) & 0x2000);
|
GSvsync(((u32&)RingBuffer.Regs[0x1000]) & 0x2000, remainder[4] != 0);
|
||||||
gsFrameSkip();
|
gsFrameSkip();
|
||||||
|
|
||||||
m_QueuedFrameCount.fetch_sub(1);
|
m_QueuedFrameCount.fetch_sub(1);
|
||||||
|
|
|
@ -28,6 +28,7 @@ static const float UPDATE_INTERVAL = 0.5f;
|
||||||
|
|
||||||
static float s_vertical_frequency = 0.0f;
|
static float s_vertical_frequency = 0.0f;
|
||||||
static float s_fps = 0.0f;
|
static float s_fps = 0.0f;
|
||||||
|
static float s_internal_fps = 0.0f;
|
||||||
static float s_worst_frame_time = 0.0f;
|
static float s_worst_frame_time = 0.0f;
|
||||||
static float s_average_frame_time = 0.0f;
|
static float s_average_frame_time = 0.0f;
|
||||||
static float s_average_frame_time_accumulator = 0.0f;
|
static float s_average_frame_time_accumulator = 0.0f;
|
||||||
|
@ -36,6 +37,14 @@ static u32 s_frames_since_last_update = 0;
|
||||||
static Common::Timer s_last_update_time;
|
static Common::Timer s_last_update_time;
|
||||||
static Common::Timer s_last_frame_time;
|
static Common::Timer s_last_frame_time;
|
||||||
|
|
||||||
|
// frame number, updated by the GS thread
|
||||||
|
static u64 s_frame_number = 0;
|
||||||
|
|
||||||
|
// internal fps heuristics
|
||||||
|
static PerformanceMetrics::InternalFPSMethod s_internal_fps_method = PerformanceMetrics::InternalFPSMethod::None;
|
||||||
|
static u32 s_gs_framebuffer_blits_since_last_update = 0;
|
||||||
|
static u32 s_gs_privileged_register_writes_since_last_update = 0;
|
||||||
|
|
||||||
static Common::ThreadCPUTimer s_cpu_thread_timer;
|
static Common::ThreadCPUTimer s_cpu_thread_timer;
|
||||||
static u64 s_last_gs_time = 0;
|
static u64 s_last_gs_time = 0;
|
||||||
static u64 s_last_vu_time = 0;
|
static u64 s_last_vu_time = 0;
|
||||||
|
@ -53,8 +62,10 @@ void PerformanceMetrics::Clear()
|
||||||
Reset();
|
Reset();
|
||||||
|
|
||||||
s_fps = 0.0f;
|
s_fps = 0.0f;
|
||||||
|
s_internal_fps = 0.0f;
|
||||||
s_worst_frame_time = 0.0f;
|
s_worst_frame_time = 0.0f;
|
||||||
s_average_frame_time = 0.0f;
|
s_average_frame_time = 0.0f;
|
||||||
|
s_internal_fps_method = PerformanceMetrics::InternalFPSMethod::None;
|
||||||
|
|
||||||
s_cpu_thread_usage = 0.0f;
|
s_cpu_thread_usage = 0.0f;
|
||||||
s_cpu_thread_time = 0.0f;
|
s_cpu_thread_time = 0.0f;
|
||||||
|
@ -62,10 +73,15 @@ void PerformanceMetrics::Clear()
|
||||||
s_gs_thread_time = 0.0f;
|
s_gs_thread_time = 0.0f;
|
||||||
s_vu_thread_usage = 0.0f;
|
s_vu_thread_usage = 0.0f;
|
||||||
s_vu_thread_time = 0.0f;
|
s_vu_thread_time = 0.0f;
|
||||||
|
|
||||||
|
s_frame_number = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PerformanceMetrics::Reset()
|
void PerformanceMetrics::Reset()
|
||||||
{
|
{
|
||||||
|
s_frames_since_last_update = 0;
|
||||||
|
s_gs_framebuffer_blits_since_last_update = 0;
|
||||||
|
s_gs_privileged_register_writes_since_last_update = 0;
|
||||||
s_average_frame_time_accumulator = 0.0f;
|
s_average_frame_time_accumulator = 0.0f;
|
||||||
s_worst_frame_time_accumulator = 0.0f;
|
s_worst_frame_time_accumulator = 0.0f;
|
||||||
|
|
||||||
|
@ -78,12 +94,15 @@ void PerformanceMetrics::Reset()
|
||||||
s_last_ticks = GetCPUTicks();
|
s_last_ticks = GetCPUTicks();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PerformanceMetrics::Update()
|
void PerformanceMetrics::Update(bool gs_register_write, bool fb_blit)
|
||||||
{
|
{
|
||||||
const float frame_time = s_last_frame_time.GetTimeMillisecondsAndReset();
|
const float frame_time = s_last_frame_time.GetTimeMillisecondsAndReset();
|
||||||
s_average_frame_time_accumulator += frame_time;
|
s_average_frame_time_accumulator += frame_time;
|
||||||
s_worst_frame_time_accumulator = std::max(s_worst_frame_time_accumulator, frame_time);
|
s_worst_frame_time_accumulator = std::max(s_worst_frame_time_accumulator, frame_time);
|
||||||
s_frames_since_last_update++;
|
s_frames_since_last_update++;
|
||||||
|
s_gs_privileged_register_writes_since_last_update += static_cast<u32>(gs_register_write);
|
||||||
|
s_gs_framebuffer_blits_since_last_update += static_cast<u32>(fb_blit);
|
||||||
|
s_frame_number++;
|
||||||
|
|
||||||
const Common::Timer::Value now_ticks = Common::Timer::GetCurrentValue();
|
const Common::Timer::Value now_ticks = Common::Timer::GetCurrentValue();
|
||||||
const Common::Timer::Value ticks_diff = now_ticks - s_last_update_time.GetStartValue();
|
const Common::Timer::Value ticks_diff = now_ticks - s_last_update_time.GetStartValue();
|
||||||
|
@ -97,6 +116,26 @@ void PerformanceMetrics::Update()
|
||||||
s_average_frame_time_accumulator = 0.0f;
|
s_average_frame_time_accumulator = 0.0f;
|
||||||
s_fps = static_cast<float>(s_frames_since_last_update) / time;
|
s_fps = static_cast<float>(s_frames_since_last_update) / time;
|
||||||
|
|
||||||
|
// prefer privileged register write based framerate detection, it's less likely to have false positives
|
||||||
|
if (s_gs_privileged_register_writes_since_last_update > 0)
|
||||||
|
{
|
||||||
|
s_internal_fps = static_cast<float>(s_gs_privileged_register_writes_since_last_update) / time;
|
||||||
|
s_internal_fps_method = InternalFPSMethod::GSPrivilegedRegister;
|
||||||
|
}
|
||||||
|
else if (s_gs_framebuffer_blits_since_last_update > 0)
|
||||||
|
{
|
||||||
|
s_internal_fps = static_cast<float>(s_gs_framebuffer_blits_since_last_update) / time;
|
||||||
|
s_internal_fps_method = InternalFPSMethod::DISPFBBlit;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
s_internal_fps = 0;
|
||||||
|
s_internal_fps_method = InternalFPSMethod::None;
|
||||||
|
}
|
||||||
|
|
||||||
|
s_gs_privileged_register_writes_since_last_update = 0;
|
||||||
|
s_gs_framebuffer_blits_since_last_update = 0;
|
||||||
|
|
||||||
s_cpu_thread_timer.GetUsageInMillisecondsAndReset(ticks_diff, &s_cpu_thread_time, &s_cpu_thread_usage);
|
s_cpu_thread_timer.GetUsageInMillisecondsAndReset(ticks_diff, &s_cpu_thread_time, &s_cpu_thread_usage);
|
||||||
s_cpu_thread_time /= static_cast<double>(s_frames_since_last_update);
|
s_cpu_thread_time /= static_cast<double>(s_frames_since_last_update);
|
||||||
|
|
||||||
|
@ -137,11 +176,31 @@ void PerformanceMetrics::SetVerticalFrequency(float rate)
|
||||||
s_vertical_frequency = rate;
|
s_vertical_frequency = rate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u64 PerformanceMetrics::GetFrameNumber()
|
||||||
|
{
|
||||||
|
return s_frame_number;
|
||||||
|
}
|
||||||
|
|
||||||
|
PerformanceMetrics::InternalFPSMethod PerformanceMetrics::GetInternalFPSMethod()
|
||||||
|
{
|
||||||
|
return s_internal_fps_method;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PerformanceMetrics::IsInternalFPSValid()
|
||||||
|
{
|
||||||
|
return s_internal_fps_method != InternalFPSMethod::None;
|
||||||
|
}
|
||||||
|
|
||||||
float PerformanceMetrics::GetFPS()
|
float PerformanceMetrics::GetFPS()
|
||||||
{
|
{
|
||||||
return s_fps;
|
return s_fps;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float PerformanceMetrics::GetInternalFPS()
|
||||||
|
{
|
||||||
|
return s_internal_fps;
|
||||||
|
}
|
||||||
|
|
||||||
float PerformanceMetrics::GetSpeed()
|
float PerformanceMetrics::GetSpeed()
|
||||||
{
|
{
|
||||||
return (s_fps / s_vertical_frequency) * 100.0;
|
return (s_fps / s_vertical_frequency) * 100.0;
|
||||||
|
|
|
@ -18,9 +18,16 @@
|
||||||
|
|
||||||
namespace PerformanceMetrics
|
namespace PerformanceMetrics
|
||||||
{
|
{
|
||||||
|
enum class InternalFPSMethod
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
GSPrivilegedRegister,
|
||||||
|
DISPFBBlit
|
||||||
|
};
|
||||||
|
|
||||||
void Clear();
|
void Clear();
|
||||||
void Reset();
|
void Reset();
|
||||||
void Update();
|
void Update(bool gs_register_write, bool fb_blit);
|
||||||
|
|
||||||
/// Sets the EE thread for CPU usage calculations.
|
/// Sets the EE thread for CPU usage calculations.
|
||||||
void SetCPUThreadTimer(Common::ThreadCPUTimer timer);
|
void SetCPUThreadTimer(Common::ThreadCPUTimer timer);
|
||||||
|
@ -28,7 +35,13 @@ namespace PerformanceMetrics
|
||||||
/// Sets the vertical frequency, used in speed calculations.
|
/// Sets the vertical frequency, used in speed calculations.
|
||||||
void SetVerticalFrequency(float rate);
|
void SetVerticalFrequency(float rate);
|
||||||
|
|
||||||
|
u64 GetFrameNumber();
|
||||||
|
|
||||||
|
InternalFPSMethod GetInternalFPSMethod();
|
||||||
|
bool IsInternalFPSValid();
|
||||||
|
|
||||||
float GetFPS();
|
float GetFPS();
|
||||||
|
float GetInternalFPS();
|
||||||
float GetSpeed();
|
float GetSpeed();
|
||||||
float GetAverageFrameTime();
|
float GetAverageFrameTime();
|
||||||
float GetWorstFrameTime();
|
float GetWorstFrameTime();
|
||||||
|
|
|
@ -662,8 +662,7 @@ void Dialogs::GSDumpDialog::ProcessDumpEvent(const GSData& event, char* regs)
|
||||||
}
|
}
|
||||||
case VSync:
|
case VSync:
|
||||||
{
|
{
|
||||||
GSvsync((*((int*)(regs + 4096)) & 0x2000) > 0 ? (u8)1 : (u8)0);
|
GSvsync((*((int*)(regs + 4096)) & 0x2000) > 0 ? (u8)1 : (u8)0, false);
|
||||||
PerformanceMetrics::Update();
|
|
||||||
g_FrameCount++;
|
g_FrameCount++;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -813,7 +812,7 @@ void Dialogs::GSDumpDialog::GSThread::ExecuteTaskInThread()
|
||||||
|
|
||||||
if (GSfreeze(FreezeAction::Load, &fd))
|
if (GSfreeze(FreezeAction::Load, &fd))
|
||||||
GSDump::isRunning = false;
|
GSDump::isRunning = false;
|
||||||
GSvsync(1);
|
GSvsync(1, false);
|
||||||
GSreset();
|
GSreset();
|
||||||
GSfreeze(FreezeAction::Load, &fd);
|
GSfreeze(FreezeAction::Load, &fd);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue