Wire up frame before/after events
This commit is contained in:
parent
154cb4f722
commit
2a18b34a73
|
@ -9,12 +9,14 @@
|
||||||
|
|
||||||
#include "VideoCommon/BoundingBox.h"
|
#include "VideoCommon/BoundingBox.h"
|
||||||
#include "VideoCommon/Fifo.h"
|
#include "VideoCommon/Fifo.h"
|
||||||
|
#include "VideoCommon/Present.h"
|
||||||
#include "VideoCommon/RenderBase.h"
|
#include "VideoCommon/RenderBase.h"
|
||||||
#include "VideoCommon/Statistics.h"
|
#include "VideoCommon/Statistics.h"
|
||||||
#include "VideoCommon/VertexManagerBase.h"
|
#include "VideoCommon/VertexManagerBase.h"
|
||||||
#include "VideoCommon/VideoBackendBase.h"
|
#include "VideoCommon/VideoBackendBase.h"
|
||||||
#include "VideoCommon/VideoCommon.h"
|
#include "VideoCommon/VideoCommon.h"
|
||||||
#include "VideoCommon/VideoState.h"
|
#include "VideoCommon/VideoState.h"
|
||||||
|
#include "VideoCommon/VideoEvents.h"
|
||||||
|
|
||||||
AsyncRequests AsyncRequests::s_singleton;
|
AsyncRequests AsyncRequests::s_singleton;
|
||||||
|
|
||||||
|
@ -154,8 +156,8 @@ void AsyncRequests::HandleEvent(const AsyncRequests::Event& e)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Event::SWAP_EVENT:
|
case Event::SWAP_EVENT:
|
||||||
g_renderer->Swap(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);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Event::BBOX_READ:
|
case Event::BBOX_READ:
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
#include "VideoCommon/GeometryShaderManager.h"
|
#include "VideoCommon/GeometryShaderManager.h"
|
||||||
#include "VideoCommon/OpcodeDecoding.h"
|
#include "VideoCommon/OpcodeDecoding.h"
|
||||||
#include "VideoCommon/PerfQueryBase.h"
|
#include "VideoCommon/PerfQueryBase.h"
|
||||||
|
#include "VideoCommon/Present.h"
|
||||||
#include "VideoCommon/PixelEngine.h"
|
#include "VideoCommon/PixelEngine.h"
|
||||||
#include "VideoCommon/PixelShaderManager.h"
|
#include "VideoCommon/PixelShaderManager.h"
|
||||||
#include "VideoCommon/RenderBase.h"
|
#include "VideoCommon/RenderBase.h"
|
||||||
|
@ -42,6 +43,7 @@
|
||||||
#include "VideoCommon/VideoBackendBase.h"
|
#include "VideoCommon/VideoBackendBase.h"
|
||||||
#include "VideoCommon/VideoCommon.h"
|
#include "VideoCommon/VideoCommon.h"
|
||||||
#include "VideoCommon/VideoConfig.h"
|
#include "VideoCommon/VideoConfig.h"
|
||||||
|
#include "VideoCommon/VideoEvents.h"
|
||||||
|
|
||||||
using namespace BPFunctions;
|
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,
|
false, false, yScale, s_gammaLUT[PE_copy.gamma], bpmem.triggerEFBCopy.clamp_top,
|
||||||
bpmem.triggerEFBCopy.clamp_bottom, bpmem.copyfilter.GetCoefficients());
|
bpmem.triggerEFBCopy.clamp_bottom, bpmem.copyfilter.GetCoefficients());
|
||||||
|
|
||||||
// This stays in to signal end of a "frame"
|
// This is as closest as we have to an "end of the frame"
|
||||||
g_renderer->RenderToXFB(destAddr, srcRect, destStride, height, s_gammaLUT[PE_copy.gamma]);
|
// It works 99% of the time.
|
||||||
|
AfterFrameEvent::Trigger();
|
||||||
|
|
||||||
|
|
||||||
if (g_ActiveConfig.bImmediateXFB)
|
if (g_ActiveConfig.bImmediateXFB)
|
||||||
{
|
{
|
||||||
// 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_renderer->Swap(destAddr, destStride / 2, destStride, height,
|
g_presenter->ImmediateSwap(destAddr, destStride / 2, destStride, height,
|
||||||
Core::System::GetInstance().GetCoreTiming().GetTicks());
|
Core::System::GetInstance().GetCoreTiming().GetTicks());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#include "VideoCommon/Statistics.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"
|
||||||
|
|
||||||
std::unique_ptr<VideoCommon::Presenter> g_presenter;
|
std::unique_ptr<VideoCommon::Presenter> g_presenter;
|
||||||
|
|
||||||
|
@ -60,6 +61,88 @@ bool Presenter::Initialize()
|
||||||
return true;
|
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<int> 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<int>(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)
|
void Presenter::SetBackbuffer(int backbuffer_width, int backbuffer_height)
|
||||||
{
|
{
|
||||||
m_backbuffer_width = backbuffer_width;
|
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
|
// 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.
|
// the post-processor. Note that options are applied every frame, so no need to check those.
|
||||||
if (m_post_processor &&
|
if (changed_bits & ConfigChangeBits::CONFIG_CHANGE_BIT_POST_PROCESSING_SHADER && m_post_processor)
|
||||||
m_post_processor->GetConfig()->GetShader() != g_ActiveConfig.sPostProcessingShader)
|
|
||||||
{
|
{
|
||||||
// The existing shader must not be in use when it's destroyed
|
// The existing shader must not be in use when it's destroyed
|
||||||
g_gfx->WaitForGPUIdle();
|
g_gfx->WaitForGPUIdle();
|
||||||
|
@ -404,43 +486,10 @@ void Presenter::RenderXFBToScreen(const MathUtil::Rectangle<int>& target_rc,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Presenter::SubmitXFB(RcTcacheEntry xfb_entry, MathUtil::Rectangle<int>& 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<int> 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<int>(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()
|
void Presenter::Present()
|
||||||
{
|
{
|
||||||
|
m_present_count++;
|
||||||
|
|
||||||
if (g_gfx->IsHeadless() || (!m_onscreen_ui && !m_xfb_entry))
|
if (g_gfx->IsHeadless() || (!m_onscreen_ui && !m_xfb_entry))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
|
@ -31,8 +31,9 @@ public:
|
||||||
Presenter();
|
Presenter();
|
||||||
virtual ~Presenter();
|
virtual ~Presenter();
|
||||||
|
|
||||||
bool SubmitXFB(RcTcacheEntry xfb_entry, MathUtil::Rectangle<int>& xfb_rect, u64 ticks,
|
void ViSwap(u32 xfb_addr, u32 fb_width, u32 fb_stride, u32 fb_height, u64 ticks);
|
||||||
int frame_count);
|
void ImmediateSwap(u32 xfb_addr, u32 fb_width, u32 fb_stride, u32 fb_height, u64 ticks);
|
||||||
|
|
||||||
void Present();
|
void Present();
|
||||||
void ClearLastXfbId() { m_last_xfb_id = std::numeric_limits<u64>::max(); }
|
void ClearLastXfbId() { m_last_xfb_id = std::numeric_limits<u64>::max(); }
|
||||||
|
|
||||||
|
@ -86,6 +87,12 @@ public:
|
||||||
const MathUtil::Rectangle<int>& GetTargetRectangle() const { return m_target_rectangle; }
|
const MathUtil::Rectangle<int>& GetTargetRectangle() const { return m_target_rectangle; }
|
||||||
|
|
||||||
private:
|
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<int, int> CalculateOutputDimensions(int width, int height) const;
|
std::tuple<int, int> CalculateOutputDimensions(int width, int height) const;
|
||||||
std::tuple<float, float> ApplyStandardAspectCrop(float width, float height) const;
|
std::tuple<float, float> ApplyStandardAspectCrop(float width, float height) const;
|
||||||
std::tuple<float, float> ScaleToDisplayAspectRatio(int width, int height) const;
|
std::tuple<float, float> ScaleToDisplayAspectRatio(int width, int height) const;
|
||||||
|
@ -120,6 +127,9 @@ private:
|
||||||
|
|
||||||
std::unique_ptr<VideoCommon::PostProcessing> m_post_processor;
|
std::unique_ptr<VideoCommon::PostProcessing> m_post_processor;
|
||||||
std::unique_ptr<VideoCommon::OnScreenUI> m_onscreen_ui;
|
std::unique_ptr<VideoCommon::OnScreenUI> m_onscreen_ui;
|
||||||
|
|
||||||
|
u64 m_frame_count = 0;
|
||||||
|
u64 m_present_count = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace VideoCommon
|
} // namespace VideoCommon
|
||||||
|
|
|
@ -417,6 +417,12 @@ void VertexManagerBase::Flush()
|
||||||
|
|
||||||
m_is_flushed = true;
|
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 ||
|
if (xfmem.numTexGen.numTexGens != bpmem.genMode.numtexgens ||
|
||||||
xfmem.numChan.numColorChans != bpmem.genMode.numcolchans)
|
xfmem.numChan.numColorChans != bpmem.genMode.numcolchans)
|
||||||
{
|
{
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include "VideoCommon/IndexGenerator.h"
|
#include "VideoCommon/IndexGenerator.h"
|
||||||
#include "VideoCommon/RenderState.h"
|
#include "VideoCommon/RenderState.h"
|
||||||
#include "VideoCommon/ShaderCache.h"
|
#include "VideoCommon/ShaderCache.h"
|
||||||
|
#include "VideoCommon/VideoEvents.h"
|
||||||
|
|
||||||
class DataReader;
|
class DataReader;
|
||||||
class NativeVertexFormat;
|
class NativeVertexFormat;
|
||||||
|
|
Loading…
Reference in New Issue