diff --git a/Source/Core/Core/CoreTiming.cpp b/Source/Core/Core/CoreTiming.cpp index f90c2c6f8f..9987ac84e1 100644 --- a/Source/Core/Core/CoreTiming.cpp +++ b/Source/Core/Core/CoreTiming.cpp @@ -353,6 +353,36 @@ void CoreTimingManager::Advance() power_pc.CheckExternalExceptions(); } +TimePoint CoreTimingManager::GetTargetHostTime(s64 target_cycle) +{ + const double speed = Core::GetIsThrottlerTempDisabled() ? 0.0 : m_emulation_speed; + + if (speed > 0) + { + const s64 cycles = target_cycle - m_throttle_last_cycle; + return m_throttle_deadline + std::chrono::duration_cast
( + DT_s(cycles) / (m_emulation_speed * m_throttle_clock_per_sec)); + } + else + { + return Clock::now(); + } +} + +void CoreTimingManager::SleepUntil(TimePoint time_point) +{ + const TimePoint time = Clock::now(); + + std::this_thread::sleep_until(time_point); + + if (Core::IsCPUThread()) + { + // Count amount of time sleeping for analytics + const TimePoint time_after_sleep = Clock::now(); + g_perf_metrics.CountThrottleSleep(time_after_sleep - time); + } +} + void CoreTimingManager::Throttle(const s64 target_cycle) { // Based on number of cycles and emulation speed, increase the target deadline diff --git a/Source/Core/Core/CoreTiming.h b/Source/Core/Core/CoreTiming.h index 93b3c1e4f1..23bd4c3239 100644 --- a/Source/Core/Core/CoreTiming.h +++ b/Source/Core/Core/CoreTiming.h @@ -98,6 +98,7 @@ public: // doing something evil u64 GetTicks() const; u64 GetIdleTicks() const; + TimePoint GetTargetHostTime(s64 target_cycle); void RefreshConfig(); @@ -157,6 +158,9 @@ public: // Throttle the CPU to the specified target cycle. void Throttle(const s64 target_cycle); + // May be used from any thread. + void SleepUntil(TimePoint time_point); + TimePoint GetCPUTimePoint(s64 cyclesLate) const; // Used by Dolphin Analytics bool GetVISkip() const; // Used By VideoInterface diff --git a/Source/Core/VideoCommon/AsyncRequests.cpp b/Source/Core/VideoCommon/AsyncRequests.cpp index 92c06f0b90..92a7e0c635 100644 --- a/Source/Core/VideoCommon/AsyncRequests.cpp +++ b/Source/Core/VideoCommon/AsyncRequests.cpp @@ -157,7 +157,7 @@ void AsyncRequests::HandleEvent(const AsyncRequests::Event& e) case Event::SWAP_EVENT: g_presenter->ViSwap(e.swap_event.xfbAddr, e.swap_event.fbWidth, e.swap_event.fbStride, - e.swap_event.fbHeight, e.time); + e.swap_event.fbHeight, e.time, e.swap_event.presentation_time); break; case Event::BBOX_READ: diff --git a/Source/Core/VideoCommon/AsyncRequests.h b/Source/Core/VideoCommon/AsyncRequests.h index 5271426f1f..f0b388ffbd 100644 --- a/Source/Core/VideoCommon/AsyncRequests.h +++ b/Source/Core/VideoCommon/AsyncRequests.h @@ -19,6 +19,8 @@ class AsyncRequests public: struct Event { + Event() {} + enum Type { EFB_POKE_COLOR, @@ -55,6 +57,7 @@ public: u32 fbWidth; u32 fbStride; u32 fbHeight; + TimePoint presentation_time; } swap_event; struct diff --git a/Source/Core/VideoCommon/Present.cpp b/Source/Core/VideoCommon/Present.cpp index 8f88c90588..1d1a77b4ca 100644 --- a/Source/Core/VideoCommon/Present.cpp +++ b/Source/Core/VideoCommon/Present.cpp @@ -5,6 +5,7 @@ #include "Common/ChunkFile.h" #include "Core/Config/GraphicsSettings.h" +#include "Core/CoreTiming.h" #include "Core/HW/VideoInterface.h" #include "Core/Host.h" #include "Core/System.h" @@ -17,7 +18,6 @@ #include "VideoCommon/FramebufferManager.h" #include "VideoCommon/OnScreenUI.h" #include "VideoCommon/PostProcessing.h" -#include "VideoCommon/Statistics.h" #include "VideoCommon/VertexManagerBase.h" #include "VideoCommon/VideoConfig.h" #include "VideoCommon/VideoEvents.h" @@ -157,7 +157,8 @@ bool Presenter::FetchXFB(u32 xfb_addr, u32 fb_width, u32 fb_stride, u32 fb_heigh return old_xfb_id == m_last_xfb_id; } -void Presenter::ViSwap(u32 xfb_addr, u32 fb_width, u32 fb_stride, u32 fb_height, u64 ticks) +void Presenter::ViSwap(u32 xfb_addr, u32 fb_width, u32 fb_stride, u32 fb_height, u64 ticks, + TimePoint presentation_time) { bool is_duplicate = FetchXFB(xfb_addr, fb_width, fb_stride, fb_height, ticks); @@ -198,7 +199,7 @@ void Presenter::ViSwap(u32 xfb_addr, u32 fb_width, u32 fb_stride, u32 fb_height, if (!is_duplicate || !g_ActiveConfig.bSkipPresentingDuplicateXFBs) { - Present(); + Present(presentation_time); ProcessFrameDumping(ticks); AfterPresentEvent::Trigger(present_info); @@ -814,7 +815,7 @@ void Presenter::RenderXFBToScreen(const MathUtil::Rectangle& target_rc, } } -void Presenter::Present() +void Presenter::Present(std::optional presentation_time) { m_present_count++; @@ -867,6 +868,10 @@ void Presenter::Present() // Present to the window system. { std::lock_guard guard(m_swap_mutex); + + if (presentation_time.has_value()) + Core::System::GetInstance().GetCoreTiming().SleepUntil(*presentation_time); + g_gfx->PresentBackbuffer(); } diff --git a/Source/Core/VideoCommon/Present.h b/Source/Core/VideoCommon/Present.h index 3f8f43a687..a355af4385 100644 --- a/Source/Core/VideoCommon/Present.h +++ b/Source/Core/VideoCommon/Present.h @@ -14,7 +14,6 @@ #include #include #include -#include #include class AbstractTexture; @@ -36,10 +35,11 @@ public: Presenter(); virtual ~Presenter(); - void ViSwap(u32 xfb_addr, u32 fb_width, u32 fb_stride, u32 fb_height, u64 ticks); + void ViSwap(u32 xfb_addr, u32 fb_width, u32 fb_stride, u32 fb_height, u64 ticks, + TimePoint presentation_time); void ImmediateSwap(u32 xfb_addr, u32 fb_width, u32 fb_stride, u32 fb_height, u64 ticks); - void Present(); + void Present(std::optional presentation_time = std::nullopt); void ClearLastXfbId() { m_last_xfb_id = std::numeric_limits::max(); } bool Initialize(); diff --git a/Source/Core/VideoCommon/VideoBackendBase.cpp b/Source/Core/VideoCommon/VideoBackendBase.cpp index a7a322eab3..c480f3d19b 100644 --- a/Source/Core/VideoCommon/VideoBackendBase.cpp +++ b/Source/Core/VideoCommon/VideoBackendBase.cpp @@ -13,13 +13,13 @@ #include "Common/ChunkFile.h" #include "Common/CommonTypes.h" -#include "Common/Event.h" #include "Common/FileUtil.h" #include "Common/Logging/Log.h" #include "Core/Config/MainSettings.h" #include "Core/ConfigManager.h" #include "Core/Core.h" +#include "Core/CoreTiming.h" #include "Core/DolphinAnalytics.h" #include "Core/System.h" @@ -51,9 +51,7 @@ #include "VideoCommon/FramebufferManager.h" #include "VideoCommon/GeometryShaderManager.h" #include "VideoCommon/GraphicsModSystem/Runtime/GraphicsModManager.h" -#include "VideoCommon/IndexGenerator.h" #include "VideoCommon/OnScreenDisplay.h" -#include "VideoCommon/OpcodeDecoding.h" #include "VideoCommon/PixelEngine.h" #include "VideoCommon/PixelShaderManager.h" #include "VideoCommon/Present.h" @@ -108,6 +106,7 @@ void VideoBackendBase::Video_OutputXFB(u32 xfb_addr, u32 fb_width, u32 fb_stride e.swap_event.fbWidth = fb_width; e.swap_event.fbStride = fb_stride; e.swap_event.fbHeight = fb_height; + e.swap_event.presentation_time = system.GetCoreTiming().GetTargetHostTime(ticks); AsyncRequests::GetInstance()->PushEvent(e, false); } }