diff --git a/Data/Sys/GameSettings/GCH.ini b/Data/Sys/GameSettings/GCH.ini new file mode 100644 index 0000000000..c3da3a46da --- /dev/null +++ b/Data/Sys/GameSettings/GCH.ini @@ -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 diff --git a/Source/Core/Core/Config/GraphicsSettings.cpp b/Source/Core/Core/Config/GraphicsSettings.cpp index f9bd3691b3..d1c7b21cf9 100644 --- a/Source/Core/Core/Config/GraphicsSettings.cpp +++ b/Source/Core/Core/Config/GraphicsSettings.cpp @@ -143,6 +143,7 @@ const Info GFX_HACK_DISABLE_COPY_TO_VRAM{{System::GFX, "Hacks", "DisableCo const Info GFX_HACK_DEFER_EFB_COPIES{{System::GFX, "Hacks", "DeferEFBCopies"}, true}; const Info GFX_HACK_IMMEDIATE_XFB{{System::GFX, "Hacks", "ImmediateXFBEnable"}, false}; const Info GFX_HACK_SKIP_DUPLICATE_XFBS{{System::GFX, "Hacks", "SkipDuplicateXFBs"}, true}; +const Info GFX_HACK_EARLY_XFB_OUTPUT{{System::GFX, "Hacks", "EarlyXFBOutput"}, true}; const Info GFX_HACK_COPY_EFB_SCALED{{System::GFX, "Hacks", "EFBScaledCopy"}, true}; const Info GFX_HACK_EFB_EMULATE_FORMAT_CHANGES{ {System::GFX, "Hacks", "EFBEmulateFormatChanges"}, false}; diff --git a/Source/Core/Core/Config/GraphicsSettings.h b/Source/Core/Core/Config/GraphicsSettings.h index 064af7aa19..cc112722ba 100644 --- a/Source/Core/Core/Config/GraphicsSettings.h +++ b/Source/Core/Core/Config/GraphicsSettings.h @@ -118,6 +118,7 @@ extern const Info GFX_HACK_DISABLE_COPY_TO_VRAM; extern const Info GFX_HACK_DEFER_EFB_COPIES; extern const Info GFX_HACK_IMMEDIATE_XFB; extern const Info GFX_HACK_SKIP_DUPLICATE_XFBS; +extern const Info GFX_HACK_EARLY_XFB_OUTPUT; extern const Info GFX_HACK_COPY_EFB_SCALED; extern const Info GFX_HACK_EFB_EMULATE_FORMAT_CHANGES; extern const Info GFX_HACK_VERTEX_ROUDING; diff --git a/Source/Core/Core/HW/VideoInterface.cpp b/Source/Core/Core/HW/VideoInterface.cpp index a989d4e5ae..bad83c9bc2 100644 --- a/Source/Core/Core/HW/VideoInterface.cpp +++ b/Source/Core/Core/HW/VideoInterface.cpp @@ -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 diff --git a/Source/Core/VideoCommon/Fifo.cpp b/Source/Core/VideoCommon/Fifo.cpp index 620d2a0d67..04fc00d33a 100644 --- a/Source/Core/VideoCommon/Fifo.cpp +++ b/Source/Core/VideoCommon/Fifo.cpp @@ -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(); } diff --git a/Source/Core/VideoCommon/VideoBackendBase.cpp b/Source/Core/VideoCommon/VideoBackendBase.cpp index cadbd08024..66c638cd02 100644 --- a/Source/Core/VideoCommon/VideoBackendBase.cpp +++ b/Source/Core/VideoCommon/VideoBackendBase.cpp @@ -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) { diff --git a/Source/Core/VideoCommon/VideoBackendBase.h b/Source/Core/VideoCommon/VideoBackendBase.h index 4dbf3b3014..8238bc2067 100644 --- a/Source/Core/VideoCommon/VideoBackendBase.h +++ b/Source/Core/VideoCommon/VideoBackendBase.h @@ -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);