mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-12-16 04:09:39 +00:00
VideoCommon: Make Presenter aware of the next swap time to eliminate unsafe usage of GetTicks() with ImmediateXFB + DualCore.
This commit is contained in:
parent
d4f68cb164
commit
cc331feb02
@ -13,7 +13,6 @@
|
|||||||
#include "Common/EnumMap.h"
|
#include "Common/EnumMap.h"
|
||||||
#include "Common/Logging/Log.h"
|
#include "Common/Logging/Log.h"
|
||||||
|
|
||||||
#include "Core/CoreTiming.h"
|
|
||||||
#include "Core/DolphinAnalytics.h"
|
#include "Core/DolphinAnalytics.h"
|
||||||
#include "Core/FifoPlayer/FifoPlayer.h"
|
#include "Core/FifoPlayer/FifoPlayer.h"
|
||||||
#include "Core/FifoPlayer/FifoRecorder.h"
|
#include "Core/FifoPlayer/FifoRecorder.h"
|
||||||
@ -359,14 +358,8 @@ static void BPWritten(PixelShaderManager& pixel_shader_manager, XFStateManager&
|
|||||||
|
|
||||||
if (g_ActiveConfig.bImmediateXFB)
|
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
|
// 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
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@ -65,6 +65,7 @@ namespace
|
|||||||
{
|
{
|
||||||
AVRational GetTimeBaseForCurrentRefreshRate(s64 max_denominator)
|
AVRational GetTimeBaseForCurrentRefreshRate(s64 max_denominator)
|
||||||
{
|
{
|
||||||
|
// TODO: GetTargetRefreshRate* are not safe from GPU thread.
|
||||||
auto& vi = Core::System::GetInstance().GetVideoInterface();
|
auto& vi = Core::System::GetInstance().GetVideoInterface();
|
||||||
int num;
|
int num;
|
||||||
int den;
|
int den;
|
||||||
@ -368,6 +369,7 @@ void FFMpegFrameDump::AddFrame(const FrameData& frame)
|
|||||||
// Calculate presentation timestamp from ticks since start.
|
// Calculate presentation timestamp from ticks since start.
|
||||||
const s64 pts = av_rescale_q(
|
const s64 pts = av_rescale_q(
|
||||||
frame.state.ticks - m_context->start_ticks,
|
frame.state.ticks - m_context->start_ticks,
|
||||||
|
// TODO: GetTicksPerSecond is not safe from GPU thread.
|
||||||
AVRational{1, int(Core::System::GetInstance().GetSystemTimers().GetTicksPerSecond())},
|
AVRational{1, int(Core::System::GetInstance().GetSystemTimers().GetTicksPerSecond())},
|
||||||
m_context->codec->time_base);
|
m_context->codec->time_base);
|
||||||
|
|
||||||
|
|||||||
@ -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);
|
FetchXFB(xfb_addr, fb_width, fb_stride, fb_height, ticks);
|
||||||
|
|
||||||
PresentInfo present_info;
|
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.frame_count = m_frame_count++;
|
||||||
present_info.reason = PresentInfo::PresentReason::Immediate;
|
present_info.reason = PresentInfo::PresentReason::Immediate;
|
||||||
present_info.present_count = m_present_count++;
|
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);
|
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
|
void Presenter::ProcessFrameDumping(u64 ticks) const
|
||||||
{
|
{
|
||||||
if (g_frame_dumper->IsFrameDumping() && m_xfb_entry)
|
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
|
// This technically counts as the end of the frame
|
||||||
GetVideoEvents().after_frame_event.Trigger(Core::System::GetInstance());
|
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_next_swap_estimated_ticks = m_last_xfb_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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -37,7 +37,9 @@ public:
|
|||||||
|
|
||||||
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);
|
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 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(); }
|
||||||
@ -167,6 +169,11 @@ private:
|
|||||||
u32 m_last_xfb_height = MAX_XFB_HEIGHT;
|
u32 m_last_xfb_height = MAX_XFB_HEIGHT;
|
||||||
|
|
||||||
Common::EventHook m_config_changed;
|
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
|
} // namespace VideoCommon
|
||||||
|
|||||||
@ -21,6 +21,8 @@
|
|||||||
#include "Core/Core.h"
|
#include "Core/Core.h"
|
||||||
#include "Core/CoreTiming.h"
|
#include "Core/CoreTiming.h"
|
||||||
#include "Core/DolphinAnalytics.h"
|
#include "Core/DolphinAnalytics.h"
|
||||||
|
#include "Core/HW/SystemTimers.h"
|
||||||
|
#include "Core/HW/VideoInterface.h"
|
||||||
#include "Core/System.h"
|
#include "Core/System.h"
|
||||||
|
|
||||||
// TODO: ugly
|
// 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,
|
void VideoBackendBase::Video_OutputXFB(u32 xfb_addr, u32 fb_width, u32 fb_stride, u32 fb_height,
|
||||||
u64 ticks)
|
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);
|
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([=] {
|
AsyncRequests::GetInstance()->PushEvent([=] {
|
||||||
g_presenter->ViSwap(xfb_addr, fb_width, fb_stride, fb_height, ticks, presentation_time);
|
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)
|
u32 VideoBackendBase::Video_GetQueryResult(PerfQueryType type)
|
||||||
|
|||||||
@ -34,7 +34,6 @@ struct PresentInfo
|
|||||||
PresentReason reason = PresentReason::Immediate;
|
PresentReason reason = PresentReason::Immediate;
|
||||||
|
|
||||||
// The exact emulated time of the when real hardware would have presented this frame
|
// 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;
|
u64 emulated_timestamp = 0;
|
||||||
|
|
||||||
// TODO:
|
// TODO:
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user