Core/VideoCommon: Push presentation time calculated from CPU thread to GPU thread.

This commit is contained in:
Jordan Woyak
2025-03-06 03:01:53 -06:00
parent c4bd98c626
commit 7222188cde
7 changed files with 52 additions and 11 deletions

View File

@ -353,6 +353,36 @@ void CoreTimingManager::Advance()
power_pc.CheckExternalExceptions(); 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>(
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) void CoreTimingManager::Throttle(const s64 target_cycle)
{ {
// Based on number of cycles and emulation speed, increase the target deadline // Based on number of cycles and emulation speed, increase the target deadline

View File

@ -98,6 +98,7 @@ public:
// doing something evil // doing something evil
u64 GetTicks() const; u64 GetTicks() const;
u64 GetIdleTicks() const; u64 GetIdleTicks() const;
TimePoint GetTargetHostTime(s64 target_cycle);
void RefreshConfig(); void RefreshConfig();
@ -157,6 +158,9 @@ public:
// Throttle the CPU to the specified target cycle. // Throttle the CPU to the specified target cycle.
void Throttle(const s64 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 TimePoint GetCPUTimePoint(s64 cyclesLate) const; // Used by Dolphin Analytics
bool GetVISkip() const; // Used By VideoInterface bool GetVISkip() const; // Used By VideoInterface

View File

@ -157,7 +157,7 @@ void AsyncRequests::HandleEvent(const AsyncRequests::Event& e)
case Event::SWAP_EVENT: case Event::SWAP_EVENT:
g_presenter->ViSwap(e.swap_event.xfbAddr, e.swap_event.fbWidth, e.swap_event.fbStride, 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; break;
case Event::BBOX_READ: case Event::BBOX_READ:

View File

@ -19,6 +19,8 @@ class AsyncRequests
public: public:
struct Event struct Event
{ {
Event() {}
enum Type enum Type
{ {
EFB_POKE_COLOR, EFB_POKE_COLOR,
@ -55,6 +57,7 @@ public:
u32 fbWidth; u32 fbWidth;
u32 fbStride; u32 fbStride;
u32 fbHeight; u32 fbHeight;
TimePoint presentation_time;
} swap_event; } swap_event;
struct struct

View File

@ -5,6 +5,7 @@
#include "Common/ChunkFile.h" #include "Common/ChunkFile.h"
#include "Core/Config/GraphicsSettings.h" #include "Core/Config/GraphicsSettings.h"
#include "Core/CoreTiming.h"
#include "Core/HW/VideoInterface.h" #include "Core/HW/VideoInterface.h"
#include "Core/Host.h" #include "Core/Host.h"
#include "Core/System.h" #include "Core/System.h"
@ -17,7 +18,6 @@
#include "VideoCommon/FramebufferManager.h" #include "VideoCommon/FramebufferManager.h"
#include "VideoCommon/OnScreenUI.h" #include "VideoCommon/OnScreenUI.h"
#include "VideoCommon/PostProcessing.h" #include "VideoCommon/PostProcessing.h"
#include "VideoCommon/Statistics.h"
#include "VideoCommon/VertexManagerBase.h" #include "VideoCommon/VertexManagerBase.h"
#include "VideoCommon/VideoConfig.h" #include "VideoCommon/VideoConfig.h"
#include "VideoCommon/VideoEvents.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; 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); 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) if (!is_duplicate || !g_ActiveConfig.bSkipPresentingDuplicateXFBs)
{ {
Present(); Present(presentation_time);
ProcessFrameDumping(ticks); ProcessFrameDumping(ticks);
AfterPresentEvent::Trigger(present_info); AfterPresentEvent::Trigger(present_info);
@ -814,7 +815,7 @@ void Presenter::RenderXFBToScreen(const MathUtil::Rectangle<int>& target_rc,
} }
} }
void Presenter::Present() void Presenter::Present(std::optional<TimePoint> presentation_time)
{ {
m_present_count++; m_present_count++;
@ -867,6 +868,10 @@ void Presenter::Present()
// Present to the window system. // Present to the window system.
{ {
std::lock_guard<std::mutex> guard(m_swap_mutex); std::lock_guard<std::mutex> guard(m_swap_mutex);
if (presentation_time.has_value())
Core::System::GetInstance().GetCoreTiming().SleepUntil(*presentation_time);
g_gfx->PresentBackbuffer(); g_gfx->PresentBackbuffer();
} }

View File

@ -14,7 +14,6 @@
#include <array> #include <array>
#include <memory> #include <memory>
#include <mutex> #include <mutex>
#include <span>
#include <tuple> #include <tuple>
class AbstractTexture; class AbstractTexture;
@ -36,10 +35,11 @@ public:
Presenter(); Presenter();
virtual ~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 ImmediateSwap(u32 xfb_addr, u32 fb_width, u32 fb_stride, u32 fb_height, u64 ticks);
void Present(); void Present(std::optional<TimePoint> presentation_time = std::nullopt);
void ClearLastXfbId() { m_last_xfb_id = std::numeric_limits<u64>::max(); } void ClearLastXfbId() { m_last_xfb_id = std::numeric_limits<u64>::max(); }
bool Initialize(); bool Initialize();

View File

@ -13,13 +13,13 @@
#include "Common/ChunkFile.h" #include "Common/ChunkFile.h"
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
#include "Common/Event.h"
#include "Common/FileUtil.h" #include "Common/FileUtil.h"
#include "Common/Logging/Log.h" #include "Common/Logging/Log.h"
#include "Core/Config/MainSettings.h" #include "Core/Config/MainSettings.h"
#include "Core/ConfigManager.h" #include "Core/ConfigManager.h"
#include "Core/Core.h" #include "Core/Core.h"
#include "Core/CoreTiming.h"
#include "Core/DolphinAnalytics.h" #include "Core/DolphinAnalytics.h"
#include "Core/System.h" #include "Core/System.h"
@ -51,9 +51,7 @@
#include "VideoCommon/FramebufferManager.h" #include "VideoCommon/FramebufferManager.h"
#include "VideoCommon/GeometryShaderManager.h" #include "VideoCommon/GeometryShaderManager.h"
#include "VideoCommon/GraphicsModSystem/Runtime/GraphicsModManager.h" #include "VideoCommon/GraphicsModSystem/Runtime/GraphicsModManager.h"
#include "VideoCommon/IndexGenerator.h"
#include "VideoCommon/OnScreenDisplay.h" #include "VideoCommon/OnScreenDisplay.h"
#include "VideoCommon/OpcodeDecoding.h"
#include "VideoCommon/PixelEngine.h" #include "VideoCommon/PixelEngine.h"
#include "VideoCommon/PixelShaderManager.h" #include "VideoCommon/PixelShaderManager.h"
#include "VideoCommon/Present.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.fbWidth = fb_width;
e.swap_event.fbStride = fb_stride; e.swap_event.fbStride = fb_stride;
e.swap_event.fbHeight = fb_height; e.swap_event.fbHeight = fb_height;
e.swap_event.presentation_time = system.GetCoreTiming().GetTargetHostTime(ticks);
AsyncRequests::GetInstance()->PushEvent(e, false); AsyncRequests::GetInstance()->PushEvent(e, false);
} }
} }