summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Source/Core/VideoCommon/BPStructs.cpp9
-rw-r--r--Source/Core/VideoCommon/FrameDumpFFMpeg.cpp2
-rw-r--r--Source/Core/VideoCommon/Present.cpp18
-rw-r--r--Source/Core/VideoCommon/Present.h9
-rw-r--r--Source/Core/VideoCommon/VideoBackendBase.cpp27
-rw-r--r--Source/Core/VideoCommon/VideoEvents.h1
6 files changed, 49 insertions, 17 deletions
diff --git a/Source/Core/VideoCommon/BPStructs.cpp b/Source/Core/VideoCommon/BPStructs.cpp
index 1ece9f278e..9518fd0446 100644
--- a/Source/Core/VideoCommon/BPStructs.cpp
+++ b/Source/Core/VideoCommon/BPStructs.cpp
@@ -13,7 +13,6 @@
#include "Common/EnumMap.h"
#include "Common/Logging/Log.h"
-#include "Core/CoreTiming.h"
#include "Core/DolphinAnalytics.h"
#include "Core/FifoPlayer/FifoPlayer.h"
#include "Core/FifoPlayer/FifoRecorder.h"
@@ -359,14 +358,8 @@ static void BPWritten(PixelShaderManager& pixel_shader_manager, XFStateManager&
if (g_ActiveConfig.bImmediateXFB)
{
- // TODO: GetTicks is not sane from the GPU thread.
- // This value is currently used for frame dumping and the custom shader "time_ms" value.
- // Frame dumping has more calls that aren't sane from the GPU thread.
- // i.e. Frame dumping is not sane in "Dual Core" mode in general.
- const u64 ticks = system.GetCoreTiming().GetTicks();
-
// below div two to convert from bytes to pixels - it expects width, not stride
- g_presenter->ImmediateSwap(destAddr, destStride / 2, destStride, height, ticks);
+ g_presenter->ImmediateSwap(destAddr, destStride / 2, destStride, height);
}
else
{
diff --git a/Source/Core/VideoCommon/FrameDumpFFMpeg.cpp b/Source/Core/VideoCommon/FrameDumpFFMpeg.cpp
index e0e61529f7..52d41549dd 100644
--- a/Source/Core/VideoCommon/FrameDumpFFMpeg.cpp
+++ b/Source/Core/VideoCommon/FrameDumpFFMpeg.cpp
@@ -65,6 +65,7 @@ namespace
{
AVRational GetTimeBaseForCurrentRefreshRate(s64 max_denominator)
{
+ // TODO: GetTargetRefreshRate* are not safe from GPU thread.
auto& vi = Core::System::GetInstance().GetVideoInterface();
int num;
int den;
@@ -368,6 +369,7 @@ void FFMpegFrameDump::AddFrame(const FrameData& frame)
// Calculate presentation timestamp from ticks since start.
const s64 pts = av_rescale_q(
frame.state.ticks - m_context->start_ticks,
+ // TODO: GetTicksPerSecond is not safe from GPU thread.
AVRational{1, int(Core::System::GetInstance().GetSystemTimers().GetTicksPerSecond())},
m_context->codec->time_base);
diff --git a/Source/Core/VideoCommon/Present.cpp b/Source/Core/VideoCommon/Present.cpp
index ce4b62a85b..bedc1c128f 100644
--- a/Source/Core/VideoCommon/Present.cpp
+++ b/Source/Core/VideoCommon/Present.cpp
@@ -215,12 +215,14 @@ void Presenter::ViSwap(u32 xfb_addr, u32 fb_width, u32 fb_stride, u32 fb_height,
}
}
-void Presenter::ImmediateSwap(u32 xfb_addr, u32 fb_width, u32 fb_stride, u32 fb_height, u64 ticks)
+void Presenter::ImmediateSwap(u32 xfb_addr, u32 fb_width, u32 fb_stride, u32 fb_height)
{
+ const u64 ticks = m_next_swap_estimated_ticks;
+
FetchXFB(xfb_addr, fb_width, fb_stride, fb_height, ticks);
PresentInfo present_info;
- present_info.emulated_timestamp = ticks; // TODO: This should be the time of the next VI field
+ present_info.emulated_timestamp = ticks;
present_info.frame_count = m_frame_count++;
present_info.reason = PresentInfo::PresentReason::Immediate;
present_info.present_count = m_present_count++;
@@ -235,6 +237,12 @@ void Presenter::ImmediateSwap(u32 xfb_addr, u32 fb_width, u32 fb_stride, u32 fb_
video_events.after_present_event.Trigger(present_info);
}
+void Presenter::SetNextSwapEstimatedTime(u64 ticks, TimePoint host_time)
+{
+ m_next_swap_estimated_ticks = ticks;
+ m_next_swap_estimated_time = host_time;
+}
+
void Presenter::ProcessFrameDumping(u64 ticks) const
{
if (g_frame_dumper->IsFrameDumping() && m_xfb_entry)
@@ -938,8 +946,10 @@ void Presenter::DoState(PointerWrap& p)
// This technically counts as the end of the frame
GetVideoEvents().after_frame_event.Trigger(Core::System::GetInstance());
- ImmediateSwap(m_last_xfb_addr, m_last_xfb_width, m_last_xfb_stride, m_last_xfb_height,
- m_last_xfb_ticks);
+ m_next_swap_estimated_ticks = m_last_xfb_ticks;
+ m_next_swap_estimated_time = Clock::now();
+
+ ImmediateSwap(m_last_xfb_addr, m_last_xfb_width, m_last_xfb_stride, m_last_xfb_height);
}
}
diff --git a/Source/Core/VideoCommon/Present.h b/Source/Core/VideoCommon/Present.h
index a355af4385..d6662f97f1 100644
--- a/Source/Core/VideoCommon/Present.h
+++ b/Source/Core/VideoCommon/Present.h
@@ -37,7 +37,9 @@ public:
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);
+
+ void SetNextSwapEstimatedTime(u64 ticks, TimePoint host_time);
void Present(std::optional<TimePoint> presentation_time = std::nullopt);
void ClearLastXfbId() { m_last_xfb_id = std::numeric_limits<u64>::max(); }
@@ -167,6 +169,11 @@ private:
u32 m_last_xfb_height = MAX_XFB_HEIGHT;
Common::EventHook m_config_changed;
+
+ // Calculated from the previous swap time and current refresh rate.
+ // Can be used for presentation of ImmediateXFB swaps which don't have timing information.
+ u64 m_next_swap_estimated_ticks = 0;
+ TimePoint m_next_swap_estimated_time{Clock::now()};
};
} // namespace VideoCommon
diff --git a/Source/Core/VideoCommon/VideoBackendBase.cpp b/Source/Core/VideoCommon/VideoBackendBase.cpp
index 676349b65b..23d9d6e7f4 100644
--- a/Source/Core/VideoCommon/VideoBackendBase.cpp
+++ b/Source/Core/VideoCommon/VideoBackendBase.cpp
@@ -21,6 +21,8 @@
#include "Core/Core.h"
#include "Core/CoreTiming.h"
#include "Core/DolphinAnalytics.h"
+#include "Core/HW/SystemTimers.h"
+#include "Core/HW/VideoInterface.h"
#include "Core/System.h"
// TODO: ugly
@@ -93,16 +95,35 @@ std::string VideoBackendBase::BadShaderFilename(const char* shader_stage, int co
void VideoBackendBase::Video_OutputXFB(u32 xfb_addr, u32 fb_width, u32 fb_stride, u32 fb_height,
u64 ticks)
{
- if (m_initialized && g_presenter && !g_ActiveConfig.bImmediateXFB)
+ if (!m_initialized || !g_presenter)
+ return;
+
+ auto& system = Core::System::GetInstance();
+ auto& core_timing = system.GetCoreTiming();
+
+ if (!g_ActiveConfig.bImmediateXFB)
{
- auto& system = Core::System::GetInstance();
system.GetFifo().SyncGPU(Fifo::SyncGPUReason::Swap);
- const TimePoint presentation_time = system.GetCoreTiming().GetTargetHostTime(ticks);
+ const TimePoint presentation_time = core_timing.GetTargetHostTime(ticks);
AsyncRequests::GetInstance()->PushEvent([=] {
g_presenter->ViSwap(xfb_addr, fb_width, fb_stride, fb_height, ticks, presentation_time);
});
}
+
+ // Inform the Presenter of the next estimated swap time.
+
+ auto& vi = system.GetVideoInterface();
+ const s64 refresh_rate_den = vi.GetTargetRefreshRateDenominator();
+ const s64 refresh_rate_num = vi.GetTargetRefreshRateNumerator();
+
+ const auto next_swap_estimated_ticks =
+ ticks + (system.GetSystemTimers().GetTicksPerSecond() * refresh_rate_den / refresh_rate_num);
+ const auto next_swap_estimated_time = core_timing.GetTargetHostTime(next_swap_estimated_ticks);
+
+ AsyncRequests::GetInstance()->PushEvent([=] {
+ g_presenter->SetNextSwapEstimatedTime(next_swap_estimated_ticks, next_swap_estimated_time);
+ });
}
u32 VideoBackendBase::Video_GetQueryResult(PerfQueryType type)
diff --git a/Source/Core/VideoCommon/VideoEvents.h b/Source/Core/VideoCommon/VideoEvents.h
index ccee5bc3bd..b7ecf0fca5 100644
--- a/Source/Core/VideoCommon/VideoEvents.h
+++ b/Source/Core/VideoCommon/VideoEvents.h
@@ -34,7 +34,6 @@ struct PresentInfo
PresentReason reason = PresentReason::Immediate;
// The exact emulated time of the when real hardware would have presented this frame
- // FIXME: Immediate should predict the timestamp of this present
u64 emulated_timestamp = 0;
// TODO: