Stitch together overlapping XFB regions in order of XFB copy creation.

This commit is contained in:
Admiral H. Curtiss 2018-09-12 23:53:40 +02:00
parent ce9e9186f7
commit 3e95d3c477
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
@ -1296,6 +1297,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)
{
@ -1306,6 +1316,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)
{
@ -1322,7 +1349,6 @@ bool TextureCacheBase::LoadTextureFromOverlappingTextures(TCacheEntry* entry_to_
}
else
{
++iter.first;
continue;
}
}
@ -1352,8 +1378,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);
@ -1389,8 +1414,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;
@ -1408,15 +1433,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;
}