mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-04-27 06:48:33 +00:00
TextureCache: Support reinterpreting formats for VRAM textures
This commit is contained in:
parent
77f406c8a8
commit
946571b759
7 changed files with 335 additions and 6 deletions
|
@ -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 =
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue