From ee649c6d9f38510b2acad42dcce894400a8b4d4b Mon Sep 17 00:00:00 2001 From: Scott Mansell Date: Sun, 6 Sep 2015 02:03:49 +1200 Subject: [PATCH 1/3] Make efb2tex behave more like efb2ram. Instead of having special case code for efb2tex that ignores hashes, the only diffence between efb2tex and efb2ram now is that efb2tex writes zeros to the memory instead of actual texture data. Though keep in mind, all efb2tex copies will have hashes of zero as their hash. --- .../Core/VideoBackends/D3D/TextureCache.cpp | 6 +-- .../Core/VideoBackends/OGL/TextureCache.cpp | 6 ++- Source/Core/VideoCommon/TextureCacheBase.cpp | 43 ++++++++++--------- Source/Core/VideoCommon/TextureCacheBase.h | 2 +- 4 files changed, 32 insertions(+), 25 deletions(-) diff --git a/Source/Core/VideoBackends/D3D/TextureCache.cpp b/Source/Core/VideoBackends/D3D/TextureCache.cpp index 603084dd33..602c00cb18 100644 --- a/Source/Core/VideoBackends/D3D/TextureCache.cpp +++ b/Source/Core/VideoBackends/D3D/TextureCache.cpp @@ -237,10 +237,10 @@ void TextureCache::TCacheEntry::FromRenderTarget(u8* dst, unsigned int dstFormat g_renderer->RestoreAPIState(); - if (!g_ActiveConfig.bSkipEFBCopyToRam) - { + if (g_ActiveConfig.bSkipEFBCopyToRam) + this->Zero(dst); + else g_encoder->Encode(dst, this, srcFormat, srcRect, isIntensity, scaleByHalf); - } } const char palette_shader[] = diff --git a/Source/Core/VideoBackends/OGL/TextureCache.cpp b/Source/Core/VideoBackends/OGL/TextureCache.cpp index 86360976bf..2becd641e7 100644 --- a/Source/Core/VideoBackends/OGL/TextureCache.cpp +++ b/Source/Core/VideoBackends/OGL/TextureCache.cpp @@ -262,7 +262,11 @@ void TextureCache::TCacheEntry::FromRenderTarget(u8* dstPointer, unsigned int ds glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - if (!g_ActiveConfig.bSkipEFBCopyToRam) + if (g_ActiveConfig.bSkipEFBCopyToRam) + { + this->Zero(dstPointer); + } + else { TextureConverter::EncodeToRamFromTexture( dstPointer, diff --git a/Source/Core/VideoCommon/TextureCacheBase.cpp b/Source/Core/VideoCommon/TextureCacheBase.cpp index 9dcd960037..21b2e792bd 100644 --- a/Source/Core/VideoCommon/TextureCacheBase.cpp +++ b/Source/Core/VideoCommon/TextureCacheBase.cpp @@ -439,11 +439,9 @@ TextureCache::TCacheEntryBase* TextureCache::Load(const u32 stage) TCacheEntryBase* entry = iter->second; if (entry->IsEfbCopy()) { - // EFB copies have slightly different rules: the hash doesn't need to match - // in EFB2Tex mode, and EFB copy formats have different meanings from texture - // formats. - if (g_ActiveConfig.bSkipEFBCopyToRam || - (tex_hash == entry->hash && (!isPaletteTexture || g_Config.backend_info.bSupportsPaletteConversion))) + // 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)) { // TODO: We should check format/width/height/levels for EFB copies. Checking // format is complicated because EFB copy formats don't exactly match @@ -986,11 +984,13 @@ void TextureCache::CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat unsigned int scaled_tex_h = g_ActiveConfig.bCopyEFBScaled ? Renderer::EFBToScaledY(tex_h) : tex_h; // remove all texture cache entries at dstAddr - std::pair iter_range = textures_by_address.equal_range((u64)dstAddr); - TexCache::iterator iter = iter_range.first; - while (iter != iter_range.second) { - iter = FreeTexture(iter); + std::pair iter_range = textures_by_address.equal_range((u64)dstAddr); + TexCache::iterator iter = iter_range.first; + while (iter != iter_range.second) + { + iter = FreeTexture(iter); + } } // create the texture @@ -1012,24 +1012,17 @@ void TextureCache::CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat entry->FromRenderTarget(dst, dstFormat, dstStride, srcFormat, srcRect, isIntensity, scaleByHalf, cbufid, colmat); - if (!g_ActiveConfig.bSkipEFBCopyToRam) + entry->hash = GetHash64(dst, (int)entry->size_in_bytes, g_ActiveConfig.iSafeTextureCache_ColorSamples); + + // Invalidate all textures that overlap the range of our texture { - entry->hash = GetHash64(dst, (int)entry->size_in_bytes, g_ActiveConfig.iSafeTextureCache_ColorSamples); - - // Invalidate all textures that overlap the range of our texture - TexCache::iterator - iter = textures_by_address.begin(); - + TexCache::iterator iter = textures_by_address.begin(); while (iter != textures_by_address.end()) { if (iter->second->OverlapsMemoryRange(dstAddr, entry->size_in_bytes)) - { iter = FreeTexture(iter); - } else - { ++iter; - } } } @@ -1110,3 +1103,13 @@ void TextureCache::TCacheEntryBase::SetEfbCopy(u32 stride) size_in_bytes = memory_stride * NumBlocksY(); } + +// Fill gamecube memory backing this texture with zeros. +void TextureCache::TCacheEntryBase::Zero(u8* ptr) +{ + for (u32 i = 0; i < NumBlocksY(); i++) + { + memset(ptr, 0, CacheLinesPerRow() * 32); + ptr += memory_stride; + } +} diff --git a/Source/Core/VideoCommon/TextureCacheBase.h b/Source/Core/VideoCommon/TextureCacheBase.h index c012cad0fc..56e1f0b1e2 100644 --- a/Source/Core/VideoCommon/TextureCacheBase.h +++ b/Source/Core/VideoCommon/TextureCacheBase.h @@ -111,7 +111,7 @@ public: u32 NumBlocksY() const; u32 CacheLinesPerRow() const; - void Memset(u8* ptr, u32 tag); + void Zero(u8* ptr); }; virtual ~TextureCache(); // needs virtual for DX11 dtor From bda964e0b97deef869260a0f12681c38f9528a68 Mon Sep 17 00:00:00 2001 From: Scott Mansell Date: Sun, 6 Sep 2015 03:13:44 +1200 Subject: [PATCH 2/3] Workaround to allow partial texture updates to keep working in NSMBWii --- Source/Core/VideoCommon/TextureCacheBase.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Source/Core/VideoCommon/TextureCacheBase.cpp b/Source/Core/VideoCommon/TextureCacheBase.cpp index 21b2e792bd..8626749283 100644 --- a/Source/Core/VideoCommon/TextureCacheBase.cpp +++ b/Source/Core/VideoCommon/TextureCacheBase.cpp @@ -1014,7 +1014,10 @@ void TextureCache::CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat entry->hash = GetHash64(dst, (int)entry->size_in_bytes, g_ActiveConfig.iSafeTextureCache_ColorSamples); - // Invalidate all textures that overlap the range of our texture + // Invalidate all textures that overlap the range of our efb copy. + // Unless our efb copy has a weird stride, then we want avoid invalidating textures which + // we might be able to do a partial texture update on. + if (entry->memory_stride == entry->CacheLinesPerRow() * 32) { TexCache::iterator iter = textures_by_address.begin(); while (iter != textures_by_address.end()) From ac467d9fb9fba8580246394ddf289c1ccb2312d6 Mon Sep 17 00:00:00 2001 From: Scott Mansell Date: Mon, 7 Sep 2015 02:31:32 +1200 Subject: [PATCH 3/3] FifoPlayer: Don't check efb copy hashes when plaing back a broken dff --- Source/Core/Core/FifoPlayer/FifoPlayer.cpp | 7 +++++ Source/Core/Core/FifoPlayer/FifoPlayer.h | 27 ++++++++++++++++++++ Source/Core/VideoCommon/TextureCacheBase.cpp | 4 ++- 3 files changed, 37 insertions(+), 1 deletion(-) 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