summaryrefslogtreecommitdiff
path: root/Source/Core/VideoCommon/TextureCacheBase.cpp
diff options
context:
space:
mode:
authorStenzek <stenzek@gmail.com>2019-07-14 15:24:12 +1000
committerStenzek <stenzek@gmail.com>2019-07-14 19:16:27 +1000
commit946571b7595b6b24e02cf8622f2bd5935b5aa360 (patch)
treeeef0c948d64df352f6b37e0625e4dbd917d8f7e4 /Source/Core/VideoCommon/TextureCacheBase.cpp
parent77f406c8a8dc638bd6404dd71b7537eed9498b69 (diff)
TextureCache: Support reinterpreting formats for VRAM textures
Diffstat (limited to 'Source/Core/VideoCommon/TextureCacheBase.cpp')
-rw-r--r--Source/Core/VideoCommon/TextureCacheBase.cpp99
1 files changed, 95 insertions, 4 deletions
diff --git a/Source/Core/VideoCommon/TextureCacheBase.cpp b/Source/Core/VideoCommon/TextureCacheBase.cpp
index f21e8e0e0e..5fcf667514 100644
--- a/Source/Core/VideoCommon/TextureCacheBase.cpp
+++ b/Source/Core/VideoCommon/TextureCacheBase.cpp
@@ -311,6 +311,44 @@ TextureCacheBase::ApplyPaletteToEntry(TCacheEntry* entry, u8* palette, TLUTForma
return decoded_entry;
}
+TextureCacheBase::TCacheEntry* TextureCacheBase::ReinterpretEntry(const TCacheEntry* existing_entry,
+ TextureFormat new_format)
+{
+ TextureConfig new_config = existing_entry->texture->GetConfig();
+ new_config.levels = 1;
+ new_config.flags |= AbstractTextureFlag_RenderTarget;
+
+ TCacheEntry* reinterpreted_entry = AllocateCacheEntry(new_config);
+ if (!reinterpreted_entry)
+ return nullptr;
+
+ reinterpreted_entry->SetGeneralParameters(existing_entry->addr, existing_entry->size_in_bytes,
+ new_format, existing_entry->should_force_safe_hashing);
+ reinterpreted_entry->SetDimensions(existing_entry->native_width, existing_entry->native_height,
+ 1);
+ reinterpreted_entry->SetHashes(existing_entry->base_hash, existing_entry->hash);
+ reinterpreted_entry->frameCount = existing_entry->frameCount;
+ reinterpreted_entry->SetNotCopy();
+ reinterpreted_entry->is_efb_copy = existing_entry->is_efb_copy;
+ reinterpreted_entry->may_have_overlapping_textures =
+ existing_entry->may_have_overlapping_textures;
+
+ g_renderer->BeginUtilityDrawing();
+ g_renderer->SetAndDiscardFramebuffer(reinterpreted_entry->framebuffer.get());
+ g_renderer->SetViewportAndScissor(reinterpreted_entry->texture->GetRect());
+ g_renderer->SetPipeline(
+ g_shader_cache->GetTextureReinterpretPipeline(existing_entry->format.texfmt, new_format));
+ g_renderer->SetTexture(0, existing_entry->texture.get());
+ g_renderer->SetSamplerState(1, RenderState::GetPointSamplerState());
+ g_renderer->Draw(0, 3);
+ g_renderer->EndUtilityDrawing();
+ reinterpreted_entry->texture->FinishedRendering();
+
+ textures_by_address.emplace(reinterpreted_entry->addr, reinterpreted_entry);
+
+ return reinterpreted_entry;
+}
+
void TextureCacheBase::ScaleTextureCacheEntryTo(TextureCacheBase::TCacheEntry* entry, u32 new_width,
u32 new_height)
{
@@ -385,6 +423,18 @@ TextureCacheBase::DoPartialTextureUpdates(TCacheEntry* entry_to_update, u8* pale
{
if (entry->hash == entry->CalculateHash())
{
+ // If the texture formats are not compatible or convertible, skip it.
+ if (!IsCompatibleTextureFormat(entry_to_update->format.texfmt, entry->format.texfmt))
+ {
+ if (!CanReinterpretTextureOnGPU(entry_to_update->format.texfmt, entry->format.texfmt))
+ {
+ ++iter.first;
+ continue;
+ }
+
+ entry = ReinterpretEntry(entry, entry_to_update->format.texfmt);
+ }
+
if (isPaletteTexture)
{
TCacheEntry* decoded_entry = ApplyPaletteToEntry(entry, palette, tlutfmt);
@@ -930,6 +980,7 @@ TextureCacheBase::GetTexture(u32 address, u32 width, u32 height, const TextureFo
TexAddrCache::iterator oldest_entry = iter;
int temp_frameCount = 0x7fffffff;
TexAddrCache::iterator unconverted_copy = textures_by_address.end();
+ TexAddrCache::iterator unreinterpreted_copy = textures_by_address.end();
while (iter != iter_range.second)
{
@@ -958,10 +1009,38 @@ TextureCacheBase::GetTexture(u32 address, u32 width, u32 height, const TextureFo
(!isPaletteTexture || g_Config.backend_info.bSupportsPaletteConversion)) ||
IsPlayingBackFifologWithBrokenEFBCopies)
{
- // TODO: We should check format/width/height/levels for EFB copies. Checking
- // format is complicated because EFB copy formats don't exactly match
- // texture formats. I'm not sure what effect checking width/height/levels
- // would have.
+ // The texture format in VRAM must match the format that the copy was created with. Some
+ // formats are inherently compatible, as the channel and bit layout is identical (e.g.
+ // I8/C8). Others have the same number of bits per texel, and can be reinterpreted on the
+ // GPU (e.g. IA4 and I8 or RGB565 and RGBA5). The only known game which reinteprets texels
+ // in this manner is Spiderman Shattered Dimensions, where it creates a copy in B8 format,
+ // and sets it up as a IA4 texture.
+ if (!IsCompatibleTextureFormat(entry->format.texfmt, texformat))
+ {
+ // Can we reinterpret this in VRAM?
+ if (CanReinterpretTextureOnGPU(entry->format.texfmt, texformat))
+ {
+ // Delay the conversion until afterwards, it's possible this texture has already been
+ // converted.
+ unreinterpreted_copy = iter++;
+ continue;
+ }
+ else
+ {
+ // If the EFB copies are in a different format and are not reinterpretable, use the RAM
+ // copy.
+ ++iter;
+ continue;
+ }
+ }
+ else
+ {
+ // Prefer the already-converted copy.
+ unconverted_copy = textures_by_address.end();
+ }
+
+ // TODO: We should check width/height/levels for EFB copies. I'm not sure what effect
+ // checking width/height/levels would have.
if (!isPaletteTexture || !g_Config.backend_info.bSupportsPaletteConversion)
return entry;
@@ -1010,6 +1089,18 @@ TextureCacheBase::GetTexture(u32 address, u32 width, u32 height, const TextureFo
++iter;
}
+ if (unreinterpreted_copy != textures_by_address.end())
+ {
+ TCacheEntry* decoded_entry = ReinterpretEntry(unreinterpreted_copy->second, texformat);
+
+ // It's possible to combine reinterpreted textures + palettes.
+ if (unreinterpreted_copy == unconverted_copy && decoded_entry)
+ decoded_entry = ApplyPaletteToEntry(decoded_entry, &texMem[tlutaddr], tlutfmt);
+
+ if (decoded_entry)
+ return decoded_entry;
+ }
+
if (unconverted_copy != textures_by_address.end())
{
TCacheEntry* decoded_entry =