Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update to partial texture updates #5718

Merged
merged 3 commits into from
Sep 3, 2017
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
50 changes: 25 additions & 25 deletions Source/Core/VideoCommon/TextureCacheBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -823,6 +825,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)
Expand Down Expand Up @@ -1225,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);

Expand Down Expand Up @@ -1308,23 +1295,35 @@ 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;
}
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;
}
Expand All @@ -1347,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);
Expand Down