Merge pull request #9993 from Techjar/late-vi-output

VI: Implement post-scanout XFB output
This commit is contained in:
JosJuice 2021-08-07 12:41:59 +02:00 committed by GitHub
commit c79757618d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 46 additions and 13 deletions

View File

@ -0,0 +1,16 @@
# GCHE78, GCHP78 - WWE Crush Hour
[Core]
# Values set here will override the main Dolphin settings.
[OnLoad]
# Add memory patches to be loaded once on boot here.
[OnFrame]
# Add memory patches to be applied every frame here.
[ActionReplay]
# Add action replay cheats here.
[Video_Hacks]
EarlyXFBOutput = False

View File

@ -143,6 +143,7 @@ const Info<bool> GFX_HACK_DISABLE_COPY_TO_VRAM{{System::GFX, "Hacks", "DisableCo
const Info<bool> GFX_HACK_DEFER_EFB_COPIES{{System::GFX, "Hacks", "DeferEFBCopies"}, true};
const Info<bool> GFX_HACK_IMMEDIATE_XFB{{System::GFX, "Hacks", "ImmediateXFBEnable"}, false};
const Info<bool> GFX_HACK_SKIP_DUPLICATE_XFBS{{System::GFX, "Hacks", "SkipDuplicateXFBs"}, true};
const Info<bool> GFX_HACK_EARLY_XFB_OUTPUT{{System::GFX, "Hacks", "EarlyXFBOutput"}, true};
const Info<bool> GFX_HACK_COPY_EFB_SCALED{{System::GFX, "Hacks", "EFBScaledCopy"}, true};
const Info<bool> GFX_HACK_EFB_EMULATE_FORMAT_CHANGES{
{System::GFX, "Hacks", "EFBEmulateFormatChanges"}, false};

View File

@ -118,6 +118,7 @@ extern const Info<bool> GFX_HACK_DISABLE_COPY_TO_VRAM;
extern const Info<bool> GFX_HACK_DEFER_EFB_COPIES;
extern const Info<bool> GFX_HACK_IMMEDIATE_XFB;
extern const Info<bool> GFX_HACK_SKIP_DUPLICATE_XFBS;
extern const Info<bool> GFX_HACK_EARLY_XFB_OUTPUT;
extern const Info<bool> GFX_HACK_COPY_EFB_SCALED;
extern const Info<bool> GFX_HACK_EFB_EMULATE_FORMAT_CHANGES;
extern const Info<bool> GFX_HACK_VERTEX_ROUDING;

View File

@ -13,6 +13,7 @@
#include "Common/Config/Config.h"
#include "Common/Logging/Log.h"
#include "Core/Config/GraphicsSettings.h"
#include "Core/Config/MainSettings.h"
#include "Core/Config/SYSCONFSettings.h"
#include "Core/ConfigManager.h"
@ -757,7 +758,7 @@ static void LogField(FieldType field, u32 xfb_address)
GetTicksPerOddField());
}
static void BeginField(FieldType field, u64 ticks)
static void OutputField(FieldType field, u64 ticks)
{
// Could we fit a second line of data in the stride?
// (Datel's Wii FreeLoaders are the only titles known to set WPL to 0)
@ -811,16 +812,30 @@ static void BeginField(FieldType field, u64 ticks)
LogField(field, xfbAddr);
// This assumes the game isn't going to change the VI registers while a
// frame is scanning out.
// To correctly handle that case we would need to collate all changes
// to VI during scanout and delay outputting the frame till then.
// Outputting the entire frame using a single set of VI register values isn't accurate, as games
// can change the register values during scanout. To correctly emulate the scanout process, we
// would need to collate all changes to the VI registers during scanout.
if (xfbAddr)
g_video_backend->Video_BeginField(xfbAddr, fbWidth, fbStride, fbHeight, ticks);
g_video_backend->Video_OutputXFB(xfbAddr, fbWidth, fbStride, fbHeight, ticks);
}
static void EndField()
static void BeginField(FieldType field, u64 ticks)
{
// Outputting the frame at the beginning of scanout reduces latency. This assumes the game isn't
// going to change the VI registers while a frame is scanning out.
if (Config::Get(Config::GFX_HACK_EARLY_XFB_OUTPUT))
OutputField(field, ticks);
}
static void EndField(FieldType field, u64 ticks)
{
// If the game does change VI registers while a frame is scanning out, we can defer output
// until the end so the last register values are used. This still isn't accurate, but it does
// produce more acceptable results in some problematic cases.
// Currently, this is only known to be necessary to eliminate flickering in WWE Crush Hour.
if (!Config::Get(Config::GFX_HACK_EARLY_XFB_OUTPUT))
OutputField(field, ticks);
Core::VideoThrottle();
Core::OnFrameEnd();
}
@ -849,11 +864,11 @@ void Update(u64 ticks)
}
else if (s_half_line_count == s_even_field_last_hl)
{
EndField();
EndField(FieldType::Even, ticks);
}
else if (s_half_line_count == s_odd_field_last_hl)
{
EndField();
EndField(FieldType::Odd, ticks);
}
// If this half-line is at a field boundary, deal with frame stepping before potentially

View File

@ -373,7 +373,7 @@ void RunGpuLoop()
// This call is pretty important in DualCore mode and must be called in the FIFO Loop.
// If we don't, s_swapRequested or s_efbAccessRequested won't be set to false
// leading the CPU thread to wait in Video_BeginField or Video_AccessEFB thus slowing
// leading the CPU thread to wait in Video_OutputXFB or Video_AccessEFB thus slowing
// things down.
AsyncRequests::GetInstance()->PullEvents();
}

View File

@ -83,8 +83,8 @@ void VideoBackendBase::Video_ExitLoop()
}
// Run from the CPU thread (from VideoInterface.cpp)
void VideoBackendBase::Video_BeginField(u32 xfb_addr, u32 fb_width, u32 fb_stride, u32 fb_height,
u64 ticks)
void VideoBackendBase::Video_OutputXFB(u32 xfb_addr, u32 fb_width, u32 fb_stride, u32 fb_height,
u64 ticks)
{
if (m_initialized && g_renderer && !g_ActiveConfig.bImmediateXFB)
{

View File

@ -52,7 +52,7 @@ public:
void Video_ExitLoop();
void Video_BeginField(u32 xfb_addr, u32 fb_width, u32 fb_stride, u32 fb_height, u64 ticks);
void Video_OutputXFB(u32 xfb_addr, u32 fb_width, u32 fb_stride, u32 fb_height, u64 ticks);
u32 Video_AccessEFB(EFBAccessType type, u32 x, u32 y, u32 data);
u32 Video_GetQueryResult(PerfQueryType type);