summaryrefslogtreecommitdiff
path: root/Source/Core/VideoCommon/TextureCacheBase.cpp
diff options
context:
space:
mode:
authorStenzek <stenzek@gmail.com>2018-11-13 12:48:27 +1000
committerStenzek <stenzek@gmail.com>2018-11-13 12:48:27 +1000
commit502c4c0e87976d183a2e2b299201f3b9771ebe79 (patch)
tree07ab86b9db26218882d20db725c8a34fb4ec5e56 /Source/Core/VideoCommon/TextureCacheBase.cpp
parent8104caa06bf6dd322bd1b095eca47153c0d244b7 (diff)
TextureCache: Recompute overlapping XFB copy hashes after copying to RAM
Diffstat (limited to 'Source/Core/VideoCommon/TextureCacheBase.cpp')
-rw-r--r--Source/Core/VideoCommon/TextureCacheBase.cpp161
1 files changed, 90 insertions, 71 deletions
diff --git a/Source/Core/VideoCommon/TextureCacheBase.cpp b/Source/Core/VideoCommon/TextureCacheBase.cpp
index d6b746ed9d..e0406708ba 100644
--- a/Source/Core/VideoCommon/TextureCacheBase.cpp
+++ b/Source/Core/VideoCommon/TextureCacheBase.cpp
@@ -1695,18 +1695,6 @@ void TextureCacheBase::CopyRenderTargetToTexture(
const u32 bytes_per_row = num_blocks_x * bytes_per_block;
const u32 covered_range = num_blocks_y * dstStride;
- if (g_bRecordFifoData)
- {
- // Mark the memory behind this efb copy as dynamicly generated for the Fifo log
- u32 address = dstAddr;
- for (u32 i = 0; i < num_blocks_y; i++)
- {
- FifoRecorder::GetInstance().UseMemory(address, bytes_per_row, MemoryUpdate::TEXTURE_MAP,
- true);
- address += dstStride;
- }
- }
-
if (dstStride < bytes_per_row)
{
// This kind of efb copy results in a scrambled image.
@@ -1722,63 +1710,6 @@ void TextureCacheBase::CopyRenderTargetToTexture(
copy_to_vram = false;
}
- // 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->addr == dstAddr && entry->is_xfb_copy)
- {
- for (auto& reference : entry->references)
- {
- reference->reference_changed = true;
- }
- }
-
- if (entry->OverlapsMemoryRange(dstAddr, covered_range))
- {
- 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))
- {
- // Pending EFB copies which are completely covered by this new copy can simply be tossed,
- // instead of having to flush them later on, since this copy will write over everything.
- iter.first = InvalidateTexture(iter.first, true);
- continue;
- }
- entry->may_have_overlapping_textures = true;
-
- // There are cases (Rogue Squadron 2 / Texas Holdem on Wiiware) where
- // for xfb copies the textures overlap which causes the hash of the first copy
- // to be different (from when it was originally created). This has no implications
- // for XFB2Tex because the underlying memory doesn't change (dummy values) but
- // can affect XFB2Ram when we compare the texture cache copy hash with the
- // newly computed hash
- // By calculating the hash when we receive overlapping xfbs, we are able
- // to mitigate this
- if (entry->is_xfb_copy && copy_to_ram)
- {
- entry->hash = entry->CalculateHash();
- }
-
- // 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;
- }
-
TCacheEntry* entry = nullptr;
if (copy_to_vram)
{
@@ -1828,8 +1759,6 @@ void TextureCacheBase::CopyRenderTargetToTexture(
xfb_count++),
0);
}
-
- textures_by_address.emplace(dstAddr, entry);
}
}
@@ -1884,12 +1813,84 @@ void TextureCacheBase::CopyRenderTargetToTexture(
}
}
+ // 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* overlapping_entry = iter.first->second;
+
+ if (overlapping_entry->addr == dstAddr && overlapping_entry->is_xfb_copy)
+ {
+ for (auto& reference : overlapping_entry->references)
+ {
+ reference->reference_changed = true;
+ }
+ }
+
+ if (overlapping_entry->OverlapsMemoryRange(dstAddr, covered_range))
+ {
+ u32 overlap_range = std::min(overlapping_entry->addr + overlapping_entry->size_in_bytes,
+ dstAddr + covered_range) -
+ std::max(overlapping_entry->addr, dstAddr);
+ if (!copy_to_vram || overlapping_entry->memory_stride != dstStride ||
+ (!strided_efb_copy && overlapping_entry->size_in_bytes == overlap_range) ||
+ (strided_efb_copy && overlapping_entry->size_in_bytes == overlap_range &&
+ overlapping_entry->addr == dstAddr))
+ {
+ // Pending EFB copies which are completely covered by this new copy can simply be tossed,
+ // instead of having to flush them later on, since this copy will write over everything.
+ iter.first = InvalidateTexture(iter.first, true);
+ continue;
+ }
+ overlapping_entry->may_have_overlapping_textures = true;
+
+ // There are cases (Rogue Squadron 2 / Texas Holdem on Wiiware) where
+ // for xfb copies the textures overlap which causes the hash of the first copy
+ // to be different (from when it was originally created). This has no implications
+ // for XFB2Tex because the underlying memory doesn't change (dummy values) but
+ // can affect XFB2Ram when we compare the texture cache copy hash with the
+ // newly computed hash
+ // By calculating the hash when we receive overlapping xfbs, we are able
+ // to mitigate this
+ if (overlapping_entry->is_xfb_copy && copy_to_ram)
+ {
+ overlapping_entry->hash = overlapping_entry->CalculateHash();
+ }
+
+ // 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 (overlapping_entry->textures_by_hash_iter != textures_by_hash.end())
+ {
+ textures_by_hash.erase(overlapping_entry->textures_by_hash_iter);
+ overlapping_entry->textures_by_hash_iter = textures_by_hash.end();
+ }
+ }
+ ++iter.first;
+ }
+
+ if (g_bRecordFifoData)
+ {
+ // Mark the memory behind this efb copy as dynamicly generated for the Fifo log
+ u32 address = dstAddr;
+ for (u32 i = 0; i < num_blocks_y; i++)
+ {
+ FifoRecorder::GetInstance().UseMemory(address, bytes_per_row, MemoryUpdate::TEXTURE_MAP,
+ true);
+ address += dstStride;
+ }
+ }
+
// Even if the copy is deferred, still compute the hash. This way if the copy is used as a texture
// in a subsequent draw before it is flushed, it will have the same hash.
if (entry)
{
const u64 hash = entry->CalculateHash();
entry->SetHashes(hash, hash);
+ textures_by_address.emplace(dstAddr, entry);
}
}
@@ -1936,6 +1937,24 @@ void TextureCacheBase::FlushEFBCopy(TCacheEntry* entry)
// This should be safe because we'll catch any writes before the game can modify it.
const u64 hash = entry->CalculateHash();
entry->SetHashes(hash, hash);
+
+ // Check for any overlapping XFB copies which now need the hash recomputed.
+ // See the comment above regarding Rogue Squadron 2.
+ if (entry->is_xfb_copy)
+ {
+ const u32 covered_range = entry->pending_efb_copy_height * entry->memory_stride;
+ auto range = FindOverlappingTextures(entry->addr, covered_range);
+ for (auto iter = range.first; iter != range.second; ++iter)
+ {
+ TCacheEntry* overlapping_entry = iter->second;
+ if (overlapping_entry->may_have_overlapping_textures && overlapping_entry->is_xfb_copy &&
+ overlapping_entry->OverlapsMemoryRange(entry->addr, covered_range))
+ {
+ const u64 overlapping_hash = overlapping_entry->CalculateHash();
+ entry->SetHashes(overlapping_hash, overlapping_hash);
+ }
+ }
+ }
}
std::unique_ptr<AbstractStagingTexture> TextureCacheBase::GetEFBCopyStagingTexture()