diff --git a/Source/Core/Core/FifoPlayer/FifoPlayer.cpp b/Source/Core/Core/FifoPlayer/FifoPlayer.cpp index 04adaff74c..0d4696c161 100644 --- a/Source/Core/Core/FifoPlayer/FifoPlayer.cpp +++ b/Source/Core/Core/FifoPlayer/FifoPlayer.cpp @@ -19,6 +19,8 @@ #include "Core/PowerPC/PowerPC.h" #include "VideoCommon/BPMemory.h" +bool IsPlayingBackFifologWithBrokenEFBCopies = false; + FifoPlayer::~FifoPlayer() { delete m_File; @@ -61,6 +63,9 @@ bool FifoPlayer::Play() if (m_File->GetFrameCount() == 0) return false; + // Currently these is no such thing as a Fifolog without broken EFB copies. + IsPlayingBackFifologWithBrokenEFBCopies = true; + m_CurrentFrame = m_FrameRangeStart; LoadMemory(); @@ -100,6 +105,8 @@ bool FifoPlayer::Play() } } + IsPlayingBackFifologWithBrokenEFBCopies = false; + return true; } diff --git a/Source/Core/Core/FifoPlayer/FifoPlayer.h b/Source/Core/Core/FifoPlayer/FifoPlayer.h index 9a5eb2227c..24a3cb8c88 100644 --- a/Source/Core/Core/FifoPlayer/FifoPlayer.h +++ b/Source/Core/Core/FifoPlayer/FifoPlayer.h @@ -13,6 +13,33 @@ class FifoDataFile; struct MemoryUpdate; struct AnalyzedFrameInfo; +// Story time: +// When FifoRecorder was created, efb copies weren't really used or they used efb2tex which ignored +// the underlying memory, so FifoRecorder didn't do anything special about the memory backing efb +// copies. This means the memory underlying efb copies go treated like regular textures and was +// baked into the fifo log. If you recorded with efb2ram on, the result of efb2ram would be baked +// into the fifo. If you recorded with efb2tex or efb off, random data would be included in the fifo +// log. +// Later the behaviour of efb2tex was changed to zero the underlying memory and check the hash of that. +// But this broke a whole lot of fifologs due to the following sequence of events: +// 1. fifoplayer would trigger the efb copy +// 2. Texture cache would zero the memory backing the texture and hash it. +// 3. Time passes. +// 4. fifoplayer would encounter the drawcall using the efb copy +// 5. fifoplayer would overwrite the memory backing the efb copy back to it's state when recording. +// 6. Texture cache would hash the memory and see that the hash no-longer matches +// 7. Texture cache would load whatever data was now in memory as a texture either a baked in +// efb2ram copy from recording time or just random data. +// 8. The output of fifoplayer would be wrong. + +// To keep compatibility with old fifologs, we have this flag which signals texture cache to not bother +// hashing the memory and just assume the hash matched. +// At a later point proper efb copy support should be added to fiforecorder and this flag will change +// based on the version of the .dff file, but until then it will always be true when a fifolog is playing. + +// Shitty global to fix a shitty problem +extern bool IsPlayingBackFifologWithBrokenEFBCopies; + class FifoPlayer { public: diff --git a/Source/Core/VideoCommon/TextureCacheBase.cpp b/Source/Core/VideoCommon/TextureCacheBase.cpp index 8626749283..0107b3e57d 100644 --- a/Source/Core/VideoCommon/TextureCacheBase.cpp +++ b/Source/Core/VideoCommon/TextureCacheBase.cpp @@ -10,6 +10,7 @@ #include "Common/StringUtil.h" #include "Core/ConfigManager.h" +#include "Core/FifoPlayer/FifoPlayer.h" #include "Core/HW/Memmap.h" #include "VideoCommon/Debugger.h" @@ -441,7 +442,8 @@ TextureCache::TCacheEntryBase* TextureCache::Load(const u32 stage) { // EFB copies have slightly different rules as EFB copy formats have different // meanings from texture formats. - if (tex_hash == entry->hash && (!isPaletteTexture || g_Config.backend_info.bSupportsPaletteConversion)) + if ((tex_hash == entry->hash && (!isPaletteTexture || g_Config.backend_info.bSupportsPaletteConversion)) || + IsPlayingBackFifologWithBrokenEFBCopies) { // TODO: We should check format/width/height/levels for EFB copies. Checking // format is complicated because EFB copy formats don't exactly match