From 2a18b34a73f4f1bc798dab0a5eec46c222ec7429 Mon Sep 17 00:00:00 2001 From: Scott Mansell Date: Mon, 30 Jan 2023 23:59:54 +1300 Subject: [PATCH] Wire up frame before/after events --- Source/Core/VideoCommon/AsyncRequests.cpp | 6 +- Source/Core/VideoCommon/BPStructs.cpp | 12 +- Source/Core/VideoCommon/Present.cpp | 123 ++++++++++++------ Source/Core/VideoCommon/Present.h | 14 +- Source/Core/VideoCommon/VertexManagerBase.cpp | 6 + Source/Core/VideoCommon/VertexManagerBase.h | 1 + 6 files changed, 117 insertions(+), 45 deletions(-) diff --git a/Source/Core/VideoCommon/AsyncRequests.cpp b/Source/Core/VideoCommon/AsyncRequests.cpp index 4ab52845f9..8c254d4e71 100644 --- a/Source/Core/VideoCommon/AsyncRequests.cpp +++ b/Source/Core/VideoCommon/AsyncRequests.cpp @@ -9,12 +9,14 @@ #include "VideoCommon/BoundingBox.h" #include "VideoCommon/Fifo.h" +#include "VideoCommon/Present.h" #include "VideoCommon/RenderBase.h" #include "VideoCommon/Statistics.h" #include "VideoCommon/VertexManagerBase.h" #include "VideoCommon/VideoBackendBase.h" #include "VideoCommon/VideoCommon.h" #include "VideoCommon/VideoState.h" +#include "VideoCommon/VideoEvents.h" AsyncRequests AsyncRequests::s_singleton; @@ -154,8 +156,8 @@ void AsyncRequests::HandleEvent(const AsyncRequests::Event& e) break; case Event::SWAP_EVENT: - g_renderer->Swap(e.swap_event.xfbAddr, e.swap_event.fbWidth, e.swap_event.fbStride, - e.swap_event.fbHeight, e.time); + g_presenter->ViSwap(e.swap_event.xfbAddr, e.swap_event.fbWidth, e.swap_event.fbStride, + e.swap_event.fbHeight, e.time); break; case Event::BBOX_READ: diff --git a/Source/Core/VideoCommon/BPStructs.cpp b/Source/Core/VideoCommon/BPStructs.cpp index 8979031d3d..865d73dbed 100644 --- a/Source/Core/VideoCommon/BPStructs.cpp +++ b/Source/Core/VideoCommon/BPStructs.cpp @@ -31,6 +31,7 @@ #include "VideoCommon/GeometryShaderManager.h" #include "VideoCommon/OpcodeDecoding.h" #include "VideoCommon/PerfQueryBase.h" +#include "VideoCommon/Present.h" #include "VideoCommon/PixelEngine.h" #include "VideoCommon/PixelShaderManager.h" #include "VideoCommon/RenderBase.h" @@ -42,6 +43,7 @@ #include "VideoCommon/VideoBackendBase.h" #include "VideoCommon/VideoCommon.h" #include "VideoCommon/VideoConfig.h" +#include "VideoCommon/VideoEvents.h" using namespace BPFunctions; @@ -340,14 +342,16 @@ static void BPWritten(PixelShaderManager& pixel_shader_manager, false, false, yScale, s_gammaLUT[PE_copy.gamma], bpmem.triggerEFBCopy.clamp_top, bpmem.triggerEFBCopy.clamp_bottom, bpmem.copyfilter.GetCoefficients()); - // This stays in to signal end of a "frame" - g_renderer->RenderToXFB(destAddr, srcRect, destStride, height, s_gammaLUT[PE_copy.gamma]); + // This is as closest as we have to an "end of the frame" + // It works 99% of the time. + AfterFrameEvent::Trigger(); + if (g_ActiveConfig.bImmediateXFB) { // below div two to convert from bytes to pixels - it expects width, not stride - g_renderer->Swap(destAddr, destStride / 2, destStride, height, - Core::System::GetInstance().GetCoreTiming().GetTicks()); + g_presenter->ImmediateSwap(destAddr, destStride / 2, destStride, height, + Core::System::GetInstance().GetCoreTiming().GetTicks()); } else { diff --git a/Source/Core/VideoCommon/Present.cpp b/Source/Core/VideoCommon/Present.cpp index 159fe080af..69deb32e2c 100644 --- a/Source/Core/VideoCommon/Present.cpp +++ b/Source/Core/VideoCommon/Present.cpp @@ -16,6 +16,7 @@ #include "VideoCommon/Statistics.h" #include "VideoCommon/VertexManagerBase.h" #include "VideoCommon/VideoConfig.h" +#include "VideoCommon/VideoEvents.h" std::unique_ptr g_presenter; @@ -60,6 +61,88 @@ bool Presenter::Initialize() return true; } +bool Presenter::FetchXFB(u32 xfb_addr, u32 fb_width, u32 fb_stride, u32 fb_height) +{ + ReleaseXFBContentLock(); + + m_xfb_entry = g_texture_cache->GetXFBTexture(xfb_addr, fb_width, fb_height, fb_stride, &m_xfb_rect); + + m_xfb_entry->AcquireContentLock(); + if (m_last_xfb_id == m_xfb_entry->id) + return false; + + m_last_xfb_id = m_xfb_entry->id; + + return true; +} + +void Presenter::ViSwap(u32 xfb_addr, u32 fb_width, u32 fb_stride, u32 fb_height, u64 ticks) +{ + bool unique = FetchXFB(xfb_addr, fb_width, fb_stride, fb_height); + + PresentInfo present_info; + present_info.emulated_timestamp = ticks; + if (unique) + { + present_info.frame_count = m_frame_count++; + present_info.reason = PresentInfo::PresentReason::VideoInterface; + } + else + { + present_info.frame_count = m_frame_count - 1; + present_info.reason = PresentInfo::PresentReason::VideoInterfaceDuplicate; + } + present_info.present_count = m_present_count; + + BeforePresentEvent::Trigger(present_info); + + if (unique || !g_ActiveConfig.bSkipPresentingDuplicateXFBs) + { + Present(); + ProcessFrameDumping(ticks); + } + else + { + g_gfx->Flush(); + } +} + +void Presenter::ImmediateSwap(u32 xfb_addr, u32 fb_width, u32 fb_stride, u32 fb_height, u64 ticks) +{ + FetchXFB(xfb_addr, fb_width, fb_stride, fb_height); + + PresentInfo present_info; + 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++; + + Present(); + ProcessFrameDumping(ticks); +} + +void Presenter::ProcessFrameDumping(u64 ticks) const +{ + if (g_frame_dumper->IsFrameDumping()) + { + MathUtil::Rectangle target_rect; + if (!g_ActiveConfig.bInternalResolutionFrameDumps && !g_gfx->IsHeadless()) + { + target_rect = GetTargetRectangle(); + } + else + { + int width, height; + std::tie(width, height) = + CalculateOutputDimensions(m_xfb_rect.GetWidth(), m_xfb_rect.GetHeight()); + target_rect = MathUtil::Rectangle(0, 0, width, height); + } + + g_frame_dumper->DumpCurrentFrame(m_xfb_entry->texture.get(), m_xfb_rect, target_rect, ticks, + m_frame_count); + } +} + void Presenter::SetBackbuffer(int backbuffer_width, int backbuffer_height) { m_backbuffer_width = backbuffer_width; @@ -80,8 +163,7 @@ void Presenter::CheckForConfigChanges(u32 changed_bits) { // Check for post-processing shader changes. Done up here as it doesn't affect anything outside // the post-processor. Note that options are applied every frame, so no need to check those. - if (m_post_processor && - m_post_processor->GetConfig()->GetShader() != g_ActiveConfig.sPostProcessingShader) + if (changed_bits & ConfigChangeBits::CONFIG_CHANGE_BIT_POST_PROCESSING_SHADER && m_post_processor) { // The existing shader must not be in use when it's destroyed g_gfx->WaitForGPUIdle(); @@ -404,43 +486,10 @@ void Presenter::RenderXFBToScreen(const MathUtil::Rectangle& target_rc, } } -bool Presenter::SubmitXFB(RcTcacheEntry xfb_entry, MathUtil::Rectangle& xfb_rect, u64 ticks, - int frame_count) -{ - m_xfb_entry = std::move(xfb_entry); - m_xfb_rect = xfb_rect; - bool is_duplicate_frame = m_last_xfb_id == m_xfb_entry->id; - m_last_xfb_id = m_xfb_entry->id; - - if (!is_duplicate_frame || !g_ActiveConfig.bSkipPresentingDuplicateXFBs) - { - Present(); - - if (g_frame_dumper->IsFrameDumping()) - { - MathUtil::Rectangle target_rect; - if (!g_ActiveConfig.bInternalResolutionFrameDumps && !g_gfx->IsHeadless()) - { - target_rect = GetTargetRectangle(); - } - else - { - int width, height; - std::tie(width, height) = - CalculateOutputDimensions(m_xfb_rect.GetWidth(), m_xfb_rect.GetHeight()); - target_rect = MathUtil::Rectangle(0, 0, width, height); - } - - g_frame_dumper->DumpCurrentFrame(m_xfb_entry->texture.get(), m_xfb_rect, target_rect, ticks, - frame_count); - } - } - - return is_duplicate_frame; -} - void Presenter::Present() { + m_present_count++; + if (g_gfx->IsHeadless() || (!m_onscreen_ui && !m_xfb_entry)) return; diff --git a/Source/Core/VideoCommon/Present.h b/Source/Core/VideoCommon/Present.h index 507c5ee424..4c870c93b0 100644 --- a/Source/Core/VideoCommon/Present.h +++ b/Source/Core/VideoCommon/Present.h @@ -31,8 +31,9 @@ public: Presenter(); virtual ~Presenter(); - bool SubmitXFB(RcTcacheEntry xfb_entry, MathUtil::Rectangle& xfb_rect, u64 ticks, - int frame_count); + void ViSwap(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 ClearLastXfbId() { m_last_xfb_id = std::numeric_limits::max(); } @@ -86,6 +87,12 @@ public: const MathUtil::Rectangle& GetTargetRectangle() const { return m_target_rectangle; } private: + // Fetches the XFB texture from the texture cache. + // Returns true the contents have changed since last time + bool FetchXFB(u32 xfb_addr, u32 fb_width, u32 fb_stride, u32 fb_height); + + void ProcessFrameDumping(u64 ticks) const; + std::tuple CalculateOutputDimensions(int width, int height) const; std::tuple ApplyStandardAspectCrop(float width, float height) const; std::tuple ScaleToDisplayAspectRatio(int width, int height) const; @@ -120,6 +127,9 @@ private: std::unique_ptr m_post_processor; std::unique_ptr m_onscreen_ui; + + u64 m_frame_count = 0; + u64 m_present_count = 0; }; } // namespace VideoCommon diff --git a/Source/Core/VideoCommon/VertexManagerBase.cpp b/Source/Core/VideoCommon/VertexManagerBase.cpp index 959b080510..34fe374d25 100644 --- a/Source/Core/VideoCommon/VertexManagerBase.cpp +++ b/Source/Core/VideoCommon/VertexManagerBase.cpp @@ -417,6 +417,12 @@ void VertexManagerBase::Flush() m_is_flushed = true; + if (m_draw_counter == 0) + { + // This is more or less the start of the Frame + BeforeFrameEvent::Trigger(); + } + if (xfmem.numTexGen.numTexGens != bpmem.genMode.numtexgens || xfmem.numChan.numColorChans != bpmem.genMode.numcolchans) { diff --git a/Source/Core/VideoCommon/VertexManagerBase.h b/Source/Core/VideoCommon/VertexManagerBase.h index 3b8180c5d2..b2cb8b54bd 100644 --- a/Source/Core/VideoCommon/VertexManagerBase.h +++ b/Source/Core/VideoCommon/VertexManagerBase.h @@ -13,6 +13,7 @@ #include "VideoCommon/IndexGenerator.h" #include "VideoCommon/RenderState.h" #include "VideoCommon/ShaderCache.h" +#include "VideoCommon/VideoEvents.h" class DataReader; class NativeVertexFormat;