Merge pull request #7412 from AdmiralCurtiss/xfb-stitch-in-order

Stitch together overlapping XFB regions in order of XFB copy creation.
This commit is contained in:
Tilka 2018-10-14 12:00:41 +01:00 committed by GitHub
commit 660fb3fca0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 116 additions and 100 deletions

View File

@ -8,6 +8,7 @@
#include <memory>
#include <string>
#include <utility>
#include <vector>
#if defined(_M_X86) || defined(_M_X86_64)
#include <pmmintrin.h>
#endif
@ -1303,6 +1304,15 @@ bool TextureCacheBase::LoadTextureFromOverlappingTextures(TCacheEntry* entry_to_
u32 numBlocksX = entry_to_update->native_width / tex_info.block_width;
// It is possible that some of the overlapping textures overlap each other.
// This behavior has been seen with XFB copies in Rogue Leader.
// To get the correct result, we apply the texture updates in the order the textures were
// originally loaded. This ensures that the parts of the texture that would have been overwritten
// in memory on real hardware get overwritten the same way here too.
// This should work, but it may be a better idea to keep track of partial XFB copy invalidations
// instead, which would reduce the amount of copying work here.
std::vector<TCacheEntry*> candidates;
auto iter = FindOverlappingTextures(entry_to_update->addr, entry_to_update->size_in_bytes);
while (iter.first != iter.second)
{
@ -1313,6 +1323,23 @@ bool TextureCacheBase::LoadTextureFromOverlappingTextures(TCacheEntry* entry_to_
entry->memory_stride == entry_to_update->memory_stride)
{
if (entry->hash == entry->CalculateHash())
{
candidates.emplace_back(entry);
}
else
{
// If the hash does not match, this EFB copy will not be used for anything, so remove it
iter.first = InvalidateTexture(iter.first);
continue;
}
}
++iter.first;
}
std::sort(candidates.begin(), candidates.end(),
[](const TCacheEntry* a, const TCacheEntry* b) { return a->id < b->id; });
for (TCacheEntry* entry : candidates)
{
if (tex_info.is_palette_texture)
{
@ -1329,7 +1356,6 @@ bool TextureCacheBase::LoadTextureFromOverlappingTextures(TCacheEntry* entry_to_
}
else
{
++iter.first;
continue;
}
}
@ -1359,8 +1385,7 @@ bool TextureCacheBase::LoadTextureFromOverlappingTextures(TCacheEntry* entry_to_
dst_y = 0;
}
u32 copy_width =
std::min(entry->native_width - src_x, entry_to_update->native_width - dst_x);
u32 copy_width = std::min(entry->native_width - src_x, entry_to_update->native_width - dst_x);
u32 copy_height =
std::min(entry->native_height - src_y, entry_to_update->native_height - dst_y);
@ -1396,8 +1421,8 @@ bool TextureCacheBase::LoadTextureFromOverlappingTextures(TCacheEntry* entry_to_
for (u32 layer = 0; layer < entry->texture->GetConfig().layers; layer++)
{
entry_to_update->texture->CopyRectangleFromTexture(entry->texture.get(), srcrect, layer,
0, dstrect, layer, 0);
entry_to_update->texture->CopyRectangleFromTexture(entry->texture.get(), srcrect, layer, 0,
dstrect, layer, 0);
}
updated_entry = true;
@ -1415,15 +1440,6 @@ bool TextureCacheBase::LoadTextureFromOverlappingTextures(TCacheEntry* entry_to_
entry->frameCount = FRAMECOUNT_INVALID;
}
}
else
{
// If the hash does not match, this EFB copy will not be used for anything, so remove it
iter.first = InvalidateTexture(iter.first);
continue;
}
}
++iter.first;
}
return updated_entry;
}