From f169b892c1aeb099d3e4519ad74387f1b746cf6d Mon Sep 17 00:00:00 2001 From: Stenzek Date: Sun, 22 Sep 2024 12:35:17 +1000 Subject: [PATCH] GPU: Defer frame done if not running events Prevents interruption/execution exiting if the frame was ticked over by a MMIO access, e.g. reading GPUSTAT. --- src/core/gpu.cpp | 25 ++++++++++++++++++++++++- src/core/gpu.h | 1 + src/core/system.cpp | 1 + 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/core/gpu.cpp b/src/core/gpu.cpp index 64d7d0853..6de97d785 100644 --- a/src/core/gpu.cpp +++ b/src/core/gpu.cpp @@ -49,6 +49,9 @@ static TimingEvent s_crtc_tick_event( static TimingEvent s_command_tick_event( "GPU Command Tick", 1, 1, [](void* param, TickCount ticks, TickCount ticks_late) { g_gpu->CommandTickEvent(ticks); }, nullptr); +static TimingEvent s_frame_done_event( + "Frame Done", 1, 1, [](void* param, TickCount ticks, TickCount ticks_late) { g_gpu->FrameDoneEvent(ticks); }, + nullptr); static std::deque s_screenshot_threads; static std::mutex s_screenshot_threads_mutex; @@ -76,6 +79,7 @@ GPU::~GPU() { s_command_tick_event.Deactivate(); s_crtc_tick_event.Deactivate(); + s_frame_done_event.Deactivate(); JoinScreenshotThreads(); DestroyDeinterlaceTextures(); @@ -1089,7 +1093,19 @@ void GPU::CRTCTickEvent(TickCount ticks) UpdateCRTCTickEvent(); if (frame_done) - System::FrameDone(); + { + // we can't issue frame done if we're in the middle of executing a rec block, e.g. from reading GPUSTAT + // defer it until the end of the block in this case. + if (!TimingEvents::IsRunningEvents()) [[unlikely]] + { + DEBUG_LOG("Deferring frame done call"); + s_frame_done_event.Schedule(0); + } + else + { + System::FrameDone(); + } + } } void GPU::CommandTickEvent(TickCount ticks) @@ -1102,6 +1118,13 @@ void GPU::CommandTickEvent(TickCount ticks) m_executing_commands = false; } +void GPU::FrameDoneEvent(TickCount ticks) +{ + DebugAssert(TimingEvents::IsRunningEvents()); + s_frame_done_event.Deactivate(); + System::FrameDone(); +} + void GPU::UpdateCommandTickEvent() { if (m_pending_command_ticks <= 0) diff --git a/src/core/gpu.h b/src/core/gpu.h index 3e67f5463..d1d183ee9 100644 --- a/src/core/gpu.h +++ b/src/core/gpu.h @@ -206,6 +206,7 @@ public: // Ticks for hblank/vblank. void CRTCTickEvent(TickCount ticks); void CommandTickEvent(TickCount ticks); + void FrameDoneEvent(TickCount ticks); // Dumps raw VRAM to a file. bool DumpVRAMToFile(const char* filename); diff --git a/src/core/system.cpp b/src/core/system.cpp index a3e238584..df5a846d9 100644 --- a/src/core/system.cpp +++ b/src/core/system.cpp @@ -1479,6 +1479,7 @@ void System::ResetSystem() Host::AddIconOSDMessage("SystemReset", ICON_FA_POWER_OFF, TRANSLATE_STR("OSDMessage", "System reset."), Host::OSD_QUICK_DURATION); + ResetPerformanceCounters(); InterruptExecution(); }