From a21ac22e0786c538ea94d3631ece39c2ba07b771 Mon Sep 17 00:00:00 2001 From: mimimi085181 Date: Wed, 28 Jun 2017 22:33:19 +0200 Subject: [PATCH 1/3] fix stored memory stride for normal textures --- Source/Core/VideoCommon/TextureCacheBase.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/Core/VideoCommon/TextureCacheBase.cpp b/Source/Core/VideoCommon/TextureCacheBase.cpp index cd9b9dd19f9b..ce87a8c76748 100644 --- a/Source/Core/VideoCommon/TextureCacheBase.cpp +++ b/Source/Core/VideoCommon/TextureCacheBase.cpp @@ -823,6 +823,7 @@ TextureCacheBase::TCacheEntry* TextureCacheBase::Load(const u32 stage) entry->SetHashes(base_hash, full_hash); entry->is_efb_copy = false; entry->is_custom_tex = hires_tex != nullptr; + entry->memory_stride = entry->BytesPerRow(); std::string basename = ""; if (g_ActiveConfig.bDumpTextures && !hires_tex) From 4e8ff4250320308a8ddf1105397aa7273c5c32fd Mon Sep 17 00:00:00 2001 From: mimimi085181 Date: Wed, 12 Jul 2017 22:49:06 +0200 Subject: [PATCH 2/3] Do not load overwritten textures by hash In this case, comparing the hash is not enough to check, if two textures are identical. --- Source/Core/VideoCommon/TextureCacheBase.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Source/Core/VideoCommon/TextureCacheBase.cpp b/Source/Core/VideoCommon/TextureCacheBase.cpp index ce87a8c76748..756b8c22e49a 100644 --- a/Source/Core/VideoCommon/TextureCacheBase.cpp +++ b/Source/Core/VideoCommon/TextureCacheBase.cpp @@ -1326,6 +1326,14 @@ void TextureCacheBase::CopyRenderTargetToTexture(u32 dstAddr, EFBCopyFormat dstF continue; } entry->may_have_overlapping_textures = true; + + // Do not load textures by hash, if they were at least partly overwritten by an efb copy. + // In this case, comparing the hash is not enough to check, if two textures are identical. + if (entry->textures_by_hash_iter != textures_by_hash.end()) + { + textures_by_hash.erase(entry->textures_by_hash_iter); + entry->textures_by_hash_iter = textures_by_hash.end(); + } } ++iter.first; } From cdbd9863b4a05db046a377c57485e92ea62ead84 Mon Sep 17 00:00:00 2001 From: mimimi085181 Date: Wed, 28 Jun 2017 16:25:01 +0200 Subject: [PATCH 3/3] Keep textures that are overwritten by efb copies, if the stride matches This is supposed to get efb2tex to the same texture as efb2ram, by applying the related efb copies as updates after each other, in the order of their creation. --- Source/Core/VideoCommon/TextureCacheBase.cpp | 41 ++++++++------------ 1 file changed, 16 insertions(+), 25 deletions(-) diff --git a/Source/Core/VideoCommon/TextureCacheBase.cpp b/Source/Core/VideoCommon/TextureCacheBase.cpp index 756b8c22e49a..be07bb6c94a4 100644 --- a/Source/Core/VideoCommon/TextureCacheBase.cpp +++ b/Source/Core/VideoCommon/TextureCacheBase.cpp @@ -242,6 +242,7 @@ TextureCacheBase::ApplyPaletteToEntry(TCacheEntry* entry, u8* palette, TLUTForma decoded_entry->SetHashes(entry->base_hash, entry->hash); decoded_entry->frameCount = FRAMECOUNT_INVALID; decoded_entry->is_efb_copy = false; + decoded_entry->may_have_overlapping_textures = entry->may_have_overlapping_textures; ConvertTexture(decoded_entry, entry, palette, tlutfmt); textures_by_address.emplace(entry->addr, decoded_entry); @@ -629,9 +630,10 @@ TextureCacheBase::TCacheEntry* TextureCacheBase::Load(const u32 stage) continue; } - // Do not load strided EFB copies, they are not meant to be used directly + // Do not load strided EFB copies, they are not meant to be used directly. + // Also do not directly load EFB copies, which were partly overwritten. if (entry->IsEfbCopy() && entry->native_width == nativeW && entry->native_height == nativeH && - entry->memory_stride == entry->BytesPerRow()) + entry->memory_stride == entry->BytesPerRow() && !entry->may_have_overlapping_textures) { // EFB copies have slightly different rules as EFB copy formats have different // meanings from texture formats. @@ -665,7 +667,7 @@ TextureCacheBase::TCacheEntry* TextureCacheBase::Load(const u32 stage) else { // For normal textures, all texture parameters need to match - if (entry->hash == full_hash && entry->format == full_format && + if (!entry->IsEfbCopy() && entry->hash == full_hash && entry->format == full_format && entry->native_levels >= tex_levels && entry->native_width == nativeW && entry->native_height == nativeH) { @@ -1226,22 +1228,6 @@ void TextureCacheBase::CopyRenderTargetToTexture(u32 dstAddr, EFBCopyFormat dstF unsigned int scaled_tex_h = g_ActiveConfig.bCopyEFBScaled ? g_renderer->EFBToScaledY(tex_h) : tex_h; - // Remove all texture cache entries at dstAddr - // It's not possible to have two EFB copies at the same address, this makes sure any old efb - // copies - // (or normal textures) are removed from texture cache. They are also un-linked from any - // partially - // updated textures, which forces that partially updated texture to be updated. - // TODO: This also wipes out non-efb copies, which is counterproductive. - { - auto iter_range = textures_by_address.equal_range(dstAddr); - TexAddrCache::iterator iter = iter_range.first; - while (iter != iter_range.second) - { - iter = InvalidateTexture(iter); - } - } - // Get the base (in memory) format of this efb copy. TextureFormat baseFormat = TexDecoder_GetEFBCopyBaseFormat(dstFormat); @@ -1309,18 +1295,22 @@ void TextureCacheBase::CopyRenderTargetToTexture(u32 dstAddr, EFBCopyFormat dstF copy_to_vram = false; } - // Invalidate all textures that overlap the range of our efb copy. - // Unless our efb copy has a weird stride, then we mark them to check for partial texture updates. - // TODO: This also invalidates partial overlaps, which we currently don't have a better way - // of dealing with. - bool invalidate_textures = dstStride == bytes_per_row || !copy_to_vram; + // Invalidate all textures, if they are either fully overwritten by our efb copy, or if they + // have a different stride than our efb copy. Partly overwritten textures with the same stride + // as our efb copy are marked to check them for partial texture updates. + // TODO: The logic to detect overlapping strided efb copies is not 100% accurate. + bool strided_efb_copy = dstStride != bytes_per_row; auto iter = FindOverlappingTextures(dstAddr, covered_range); while (iter.first != iter.second) { TCacheEntry* entry = iter.first->second; if (entry->OverlapsMemoryRange(dstAddr, covered_range)) { - if (invalidate_textures) + u32 overlap_range = std::min(entry->addr + entry->size_in_bytes, dstAddr + covered_range) - + std::max(entry->addr, dstAddr); + if (!copy_to_vram || entry->memory_stride != dstStride || + (!strided_efb_copy && entry->size_in_bytes == overlap_range) || + (strided_efb_copy && entry->size_in_bytes == overlap_range && entry->addr == dstAddr)) { iter.first = InvalidateTexture(iter.first); continue; @@ -1356,6 +1346,7 @@ void TextureCacheBase::CopyRenderTargetToTexture(u32 dstAddr, EFBCopyFormat dstF entry->frameCount = FRAMECOUNT_INVALID; entry->SetEfbCopy(dstStride); + entry->may_have_overlapping_textures = false; entry->is_custom_tex = false; CopyEFBToCacheEntry(entry, is_depth_copy, srcRect, scaleByHalf, cbufid, colmat);