diff --git a/Core/HLE/ReplaceTables.cpp b/Core/HLE/ReplaceTables.cpp index 16b8ca7fe8..1ef09439ef 100644 --- a/Core/HLE/ReplaceTables.cpp +++ b/Core/HLE/ReplaceTables.cpp @@ -20,6 +20,7 @@ #include #include "Common/Common.h" +#include "Common/Data/Convert/SmallDataConvert.h" #include "Common/Log.h" #include "Core/Config.h" #include "Core/Debugger/Breakpoints.h" @@ -1053,6 +1054,20 @@ static int Hook_youkosohitsujimura_download_frame() { return 0; } +static int Hook_zettai_hero_update_minimap_tex() { + const MIPSOpcode storeOffset = Memory::Read_Instruction(currentMIPS->pc + 4, true); + const uint32_t texAddr = currentMIPS->r[MIPS_REG_A0] + SignExtend16ToS32(storeOffset); + const uint32_t texSize = 64 * 64 * 1; + const uint32_t writeAddr = currentMIPS->r[MIPS_REG_V1] + SignExtend16ToS32(storeOffset); + if (Memory::IsValidRange(texAddr, texSize) && writeAddr >= texAddr && writeAddr < texAddr + texSize) { + const uint8_t currentValue = Memory::Read_U8(writeAddr); + if (currentValue != currentMIPS->r[MIPS_REG_A3]) { + gpu->InvalidateCache(texAddr, texSize, GPU_INVALIDATE_FORCE); + } + } + return 0; +} + static int Hook_tonyhawkp8_upload_tutorial_frame() { const u32 fb_address = currentMIPS->r[MIPS_REG_A0]; if (Memory::IsVRAMAddress(fb_address)) { @@ -1323,6 +1338,7 @@ static const ReplacementTableEntry entries[] = { { "photokano_download_frame_2", &Hook_photokano_download_frame_2, 0, REPFLAG_HOOKENTER, }, { "gakuenheaven_download_frame", &Hook_gakuenheaven_download_frame, 0, REPFLAG_HOOKENTER, }, { "youkosohitsujimura_download_frame", &Hook_youkosohitsujimura_download_frame, 0, REPFLAG_HOOKENTER, 0x94 }, + { "zettai_hero_update_minimap_tex", &Hook_zettai_hero_update_minimap_tex, 0, REPFLAG_HOOKEXIT, }, { "tonyhawkp8_upload_tutorial_frame", &Hook_tonyhawkp8_upload_tutorial_frame, 0, REPFLAG_HOOKENTER, }, { "sdgundamggenerationportable_download_frame", &Hook_sdgundamggenerationportable_download_frame, 0, REPFLAG_HOOKENTER, 0x34 }, { "atvoffroadfurypro_download_frame", &Hook_atvoffroadfurypro_download_frame, 0, REPFLAG_HOOKENTER, 0xA0 }, diff --git a/Core/MIPS/MIPSAnalyst.cpp b/Core/MIPS/MIPSAnalyst.cpp index 1a39988abc..18abd29d7f 100644 --- a/Core/MIPS/MIPSAnalyst.cpp +++ b/Core/MIPS/MIPSAnalyst.cpp @@ -102,6 +102,7 @@ static const HardHashTableEntry hardcodedHashes[] = { { 0x030507c9a1f0fc85, 92, "matrix_rot_x", }, { 0x0483fceefa4557ff, 1360, "__udivdi3", }, { 0x0558ad5c5be00ca1, 76, "vtfm_t", }, + { 0x05aceb23092fd6a1, 36, "zettai_hero_update_minimap_tex", }, // Zettai Hero Project (US) { 0x05aedd0c04b451a1, 356, "sqrt", }, { 0x0654fc8adbe16ef7, 28, "vmul_q", }, { 0x06628f6052cda3c1, 1776, "toheart2_download_frame", }, // To Heart 2 Portable diff --git a/GPU/Common/TextureCacheCommon.cpp b/GPU/Common/TextureCacheCommon.cpp index 91f54c06ff..83cfe23181 100644 --- a/GPU/Common/TextureCacheCommon.cpp +++ b/GPU/Common/TextureCacheCommon.cpp @@ -1795,7 +1795,7 @@ void TextureCacheCommon::Invalidate(u32 addr, int size, GPUInvalidationType type } // If we're hashing every use, without backoff, then this isn't needed. - if (!g_Config.bTextureBackoffCache) { + if (!g_Config.bTextureBackoffCache && type != GPU_INVALIDATE_FORCE) { return; } @@ -1806,28 +1806,34 @@ void TextureCacheCommon::Invalidate(u32 addr, int size, GPUInvalidationType type } for (TexCache::iterator iter = cache_.lower_bound(startKey), end = cache_.upper_bound(endKey); iter != end; ++iter) { - u32 texAddr = iter->second->addr; - u32 texEnd = iter->second->addr + iter->second->sizeInRAM; + auto &entry = iter->second; + u32 texAddr = entry->addr; + u32 texEnd = entry->addr + entry->sizeInRAM; // Quick check for overlap. Yes the check is right. if (addr < texEnd && addr_end > texAddr) { - if (iter->second->GetHashStatus() == TexCacheEntry::STATUS_RELIABLE) { - iter->second->SetHashStatus(TexCacheEntry::STATUS_HASHING); + if (entry->GetHashStatus() == TexCacheEntry::STATUS_RELIABLE) { + entry->SetHashStatus(TexCacheEntry::STATUS_HASHING); + } + if (type == GPU_INVALIDATE_FORCE) { + // Just random values to force the hash not to match. + entry->fullhash = (entry->fullhash ^ 0x12345678) + 13; + entry->hash = (entry->hash ^ 0x89ABCDEF) + 89; } if (type != GPU_INVALIDATE_ALL) { gpuStats.numTextureInvalidations++; // Start it over from 0 (unless it's safe.) - iter->second->numFrames = type == GPU_INVALIDATE_SAFE ? 256 : 0; + entry->numFrames = type == GPU_INVALIDATE_SAFE ? 256 : 0; if (type == GPU_INVALIDATE_SAFE) { - u32 diff = gpuStats.numFlips - iter->second->lastFrame; + u32 diff = gpuStats.numFlips - entry->lastFrame; // We still need to mark if the texture is frequently changing, even if it's safely changing. if (diff < TEXCACHE_FRAME_CHANGE_FREQUENT) { - iter->second->status |= TexCacheEntry::STATUS_CHANGE_FREQUENT; + entry->status |= TexCacheEntry::STATUS_CHANGE_FREQUENT; } } - iter->second->framesUntilNextFullHash = 0; + entry->framesUntilNextFullHash = 0; } else { - iter->second->invalidHint++; + entry->invalidHint++; } } } diff --git a/GPU/GPUInterface.h b/GPU/GPUInterface.h index ebc569f9d2..19c2cc72ab 100644 --- a/GPU/GPUInterface.h +++ b/GPU/GPUInterface.h @@ -153,6 +153,8 @@ enum GPUInvalidationType { GPU_INVALIDATE_HINT, // Reliable invalidation (where any hashing, etc. is unneeded, it'll always invalidate.) GPU_INVALIDATE_SAFE, + // Forced invalidation for when the texture hash may not catch changes. + GPU_INVALIDATE_FORCE, }; namespace Draw {