Partial updates for paletted textures

This pr fixes another regression that happened after pr #3165 was merged. The shadows in mario baseball should now work again.
This commit is contained in:
mimimi085181 2016-03-26 03:43:32 +01:00
parent e98fb0af84
commit 9f625417c0
2 changed files with 77 additions and 41 deletions

View File

@ -211,6 +211,32 @@ bool TextureCacheBase::TCacheEntryBase::OverlapsMemoryRange(u32 range_address, u
return true; return true;
} }
TextureCacheBase::TCacheEntryBase* TextureCacheBase::TCacheEntryBase::ApplyPalette(u8* palette, u32 tlutfmt)
{
TCacheEntryConfig newconfig;
newconfig.rendertarget = true;
newconfig.width = config.width;
newconfig.height = config.height;
newconfig.layers = config.layers;
TCacheEntryBase *decoded_entry = AllocateTexture(newconfig);
if (decoded_entry)
{
decoded_entry->SetGeneralParameters(addr, size_in_bytes, format);
decoded_entry->SetDimensions(native_width, native_height, 1);
decoded_entry->SetHashes(base_hash, hash);
decoded_entry->frameCount = FRAMECOUNT_INVALID;
decoded_entry->is_efb_copy = false;
g_texture_cache->ConvertTexture(decoded_entry, this, palette, static_cast<TlutFormat>(tlutfmt));
textures_by_address.emplace(addr, decoded_entry);
return decoded_entry;
}
return nullptr;
}
void TextureCacheBase::ScaleTextureCacheEntryTo(TextureCacheBase::TCacheEntryBase** entry, u32 new_width, u32 new_height) void TextureCacheBase::ScaleTextureCacheEntryTo(TextureCacheBase::TCacheEntryBase** entry, u32 new_width, u32 new_height)
{ {
if ((*entry)->config.width == new_width && (*entry)->config.height == new_height) if ((*entry)->config.width == new_width && (*entry)->config.height == new_height)
@ -256,21 +282,7 @@ void TextureCacheBase::ScaleTextureCacheEntryTo(TextureCacheBase::TCacheEntryBas
newentry->textures_by_hash_iter = textures_by_hash.emplace((*entry)->hash, newentry); newentry->textures_by_hash_iter = textures_by_hash.emplace((*entry)->hash, newentry);
} }
// Remove the old texture FreeTexture(GetTexCacheIter(*entry));
std::pair<TexCache::iterator, TexCache::iterator>iter_range = textures_by_address.equal_range((*entry)->addr);
TexCache::iterator iter = iter_range.first;
while (iter != iter_range.second)
{
if (iter->second == *entry)
{
FreeTexture(iter);
iter = iter_range.second;
}
else
{
iter++;
}
}
*entry = newentry; *entry = newentry;
textures_by_address.emplace((*entry)->addr, *entry); textures_by_address.emplace((*entry)->addr, *entry);
@ -281,7 +293,7 @@ void TextureCacheBase::ScaleTextureCacheEntryTo(TextureCacheBase::TCacheEntryBas
} }
} }
TextureCacheBase::TCacheEntryBase* TextureCacheBase::DoPartialTextureUpdates(TexCache::iterator iter_t) TextureCacheBase::TCacheEntryBase* TextureCacheBase::DoPartialTextureUpdates(TexCache::iterator iter_t, u8* palette, u32 tlutfmt)
{ {
TCacheEntryBase* entry_to_update = iter_t->second; TCacheEntryBase* entry_to_update = iter_t->second;
const bool isPaletteTexture = (entry_to_update->format == GX_TF_C4 const bool isPaletteTexture = (entry_to_update->format == GX_TF_C4
@ -289,10 +301,9 @@ TextureCacheBase::TCacheEntryBase* TextureCacheBase::DoPartialTextureUpdates(Tex
|| entry_to_update->format == GX_TF_C14X2 || entry_to_update->format == GX_TF_C14X2
|| entry_to_update->format >= 0x10000); || entry_to_update->format >= 0x10000);
// Efb copies and paletted textures are excluded from these updates, until there's an example where a game would // EFB copies are excluded from these updates, until there's an example where a game would
// benefit from this. Both would require more work to be done. // benefit from updating. This would require more work to be done.
if (entry_to_update->IsEfbCopy() if (entry_to_update->IsEfbCopy())
|| isPaletteTexture)
return entry_to_update; return entry_to_update;
u32 block_width = TexDecoder_GetBlockWidthInTexels(entry_to_update->format & 0xf); u32 block_width = TexDecoder_GetBlockWidthInTexels(entry_to_update->format & 0xf);
@ -313,6 +324,22 @@ TextureCacheBase::TCacheEntryBase* TextureCacheBase::DoPartialTextureUpdates(Tex
{ {
if (entry->hash == entry->CalculateHash()) if (entry->hash == entry->CalculateHash())
{ {
if (isPaletteTexture)
{
TCacheEntryBase *decoded_entry = entry->ApplyPalette(palette, tlutfmt);
if (decoded_entry)
{
// Mark the texture update as used, as if it was loaded directly
entry->frameCount = FRAMECOUNT_INVALID;
entry = decoded_entry;
}
else
{
++iter;
continue;
}
}
u32 src_x, src_y, dst_x, dst_y; u32 src_x, src_y, dst_x, dst_y;
// Note for understanding the math: // Note for understanding the math:
@ -369,6 +396,10 @@ TextureCacheBase::TCacheEntryBase* TextureCacheBase::DoPartialTextureUpdates(Tex
entry_to_update->CopyRectangleFromTexture(entry, srcrect, dstrect); entry_to_update->CopyRectangleFromTexture(entry, srcrect, dstrect);
// Mark the texture update as used, as if it was loaded directly // Mark the texture update as used, as if it was loaded directly
entry->frameCount = FRAMECOUNT_INVALID; entry->frameCount = FRAMECOUNT_INVALID;
// Remove the converted texture, it won't be used anywhere else
if (isPaletteTexture)
FreeTexture(GetTexCacheIter(entry));
} }
else else
{ {
@ -591,7 +622,7 @@ TextureCacheBase::TCacheEntryBase* TextureCacheBase::Load(const u32 stage)
if (entry->hash == full_hash && entry->format == full_format && entry->native_levels >= tex_levels && if (entry->hash == full_hash && entry->format == full_format && entry->native_levels >= tex_levels &&
entry->native_width == nativeW && entry->native_height == nativeH) entry->native_width == nativeW && entry->native_height == nativeH)
{ {
entry = DoPartialTextureUpdates(iter); entry = DoPartialTextureUpdates(iter, &texMem[tlutaddr], tlutfmt);
return ReturnEntry(stage, entry); return ReturnEntry(stage, entry);
} }
@ -613,26 +644,10 @@ TextureCacheBase::TCacheEntryBase* TextureCacheBase::Load(const u32 stage)
if (unconverted_copy != textures_by_address.end()) if (unconverted_copy != textures_by_address.end())
{ {
// Perform palette decoding. TCacheEntryBase* decoded_entry = unconverted_copy->second->ApplyPalette(&texMem[tlutaddr], tlutfmt);
TCacheEntryBase *entry = unconverted_copy->second;
TCacheEntryConfig config;
config.rendertarget = true;
config.width = entry->config.width;
config.height = entry->config.height;
config.layers = FramebufferManagerBase::GetEFBLayers();
TCacheEntryBase *decoded_entry = AllocateTexture(config);
if (decoded_entry) if (decoded_entry)
{ {
decoded_entry->SetGeneralParameters(address, texture_size, full_format);
decoded_entry->SetDimensions(entry->native_width, entry->native_height, 1);
decoded_entry->SetHashes(base_hash, full_hash);
decoded_entry->frameCount = FRAMECOUNT_INVALID;
decoded_entry->is_efb_copy = false;
g_texture_cache->ConvertTexture(decoded_entry, entry, &texMem[tlutaddr], (TlutFormat)tlutfmt);
textures_by_address.emplace((u64)address, decoded_entry);
return ReturnEntry(stage, decoded_entry); return ReturnEntry(stage, decoded_entry);
} }
} }
@ -653,7 +668,7 @@ TextureCacheBase::TCacheEntryBase* TextureCacheBase::Load(const u32 stage)
if (entry->format == full_format && entry->native_levels >= tex_levels && if (entry->format == full_format && entry->native_levels >= tex_levels &&
entry->native_width == nativeW && entry->native_height == nativeH) entry->native_width == nativeW && entry->native_height == nativeH)
{ {
entry = DoPartialTextureUpdates(iter); entry = DoPartialTextureUpdates(iter, &texMem[tlutaddr], tlutfmt);
return ReturnEntry(stage, entry); return ReturnEntry(stage, entry);
} }
@ -798,7 +813,7 @@ TextureCacheBase::TCacheEntryBase* TextureCacheBase::Load(const u32 stage)
INCSTAT(stats.numTexturesUploaded); INCSTAT(stats.numTexturesUploaded);
SETSTAT(stats.numTexturesAlive, textures_by_address.size()); SETSTAT(stats.numTexturesAlive, textures_by_address.size());
entry = DoPartialTextureUpdates(iter); entry = DoPartialTextureUpdates(iter, &texMem[tlutaddr], tlutfmt);
return ReturnEntry(stage, entry); return ReturnEntry(stage, entry);
} }
@ -1271,8 +1286,26 @@ TextureCacheBase::TCacheEntryBase* TextureCacheBase::AllocateTexture(const TCach
return entry; return entry;
} }
TextureCacheBase::TexCache::iterator TextureCacheBase::GetTexCacheIter(TextureCacheBase::TCacheEntryBase* entry)
{
std::pair<TexCache::iterator, TexCache::iterator>iter_range = textures_by_address.equal_range(entry->addr);
TexCache::iterator iter = iter_range.first;
while (iter != iter_range.second)
{
if (iter->second == entry)
{
return iter;
}
++iter;
}
return textures_by_address.end();
}
TextureCacheBase::TexCache::iterator TextureCacheBase::FreeTexture(TexCache::iterator iter) TextureCacheBase::TexCache::iterator TextureCacheBase::FreeTexture(TexCache::iterator iter)
{ {
if (iter == textures_by_address.end())
return textures_by_address.end();
TCacheEntryBase* entry = iter->second; TCacheEntryBase* entry = iter->second;
if (entry->textures_by_hash_iter != textures_by_hash.end()) if (entry->textures_by_hash_iter != textures_by_hash.end())

View File

@ -109,6 +109,8 @@ public:
bool OverlapsMemoryRange(u32 range_address, u32 range_size) const; bool OverlapsMemoryRange(u32 range_address, u32 range_size) const;
TextureCacheBase::TCacheEntryBase* ApplyPalette(u8* palette, u32 tlutfmt);
bool IsEfbCopy() const { return is_efb_copy; } bool IsEfbCopy() const { return is_efb_copy; }
u32 NumBlocksY() const; u32 NumBlocksY() const;
@ -156,11 +158,12 @@ private:
typedef std::multimap<u64, TCacheEntryBase*> TexCache; typedef std::multimap<u64, TCacheEntryBase*> TexCache;
typedef std::unordered_multimap<TCacheEntryConfig, TCacheEntryBase*, TCacheEntryConfig::Hasher> TexPool; typedef std::unordered_multimap<TCacheEntryConfig, TCacheEntryBase*, TCacheEntryConfig::Hasher> TexPool;
static void ScaleTextureCacheEntryTo(TCacheEntryBase** entry, u32 new_width, u32 new_height); static void ScaleTextureCacheEntryTo(TCacheEntryBase** entry, u32 new_width, u32 new_height);
static TCacheEntryBase* DoPartialTextureUpdates(TexCache::iterator iter); static TCacheEntryBase* DoPartialTextureUpdates(TexCache::iterator iter, u8* palette, u32 tlutfmt);
static void DumpTexture(TCacheEntryBase* entry, std::string basename, unsigned int level); static void DumpTexture(TCacheEntryBase* entry, std::string basename, unsigned int level);
static void CheckTempSize(size_t required_size); static void CheckTempSize(size_t required_size);
static TCacheEntryBase* AllocateTexture(const TCacheEntryConfig& config); static TCacheEntryBase* AllocateTexture(const TCacheEntryConfig& config);
static TexCache::iterator GetTexCacheIter(TCacheEntryBase* entry);
static TexCache::iterator FreeTexture(TexCache::iterator t_iter); static TexCache::iterator FreeTexture(TexCache::iterator t_iter);
static TCacheEntryBase* ReturnEntry(unsigned int stage, TCacheEntryBase* entry); static TCacheEntryBase* ReturnEntry(unsigned int stage, TCacheEntryBase* entry);