From 9263f6b7c6773c35276b0a505483c3658d672329 Mon Sep 17 00:00:00 2001 From: iwubcode Date: Mon, 31 Aug 2026 19:51:30 -0500 Subject: [PATCH] VideoCommon: separate out reinterpret and palette texture creation from rendering --- Source/Core/VideoCommon/TextureCacheBase.cpp | 147 +++++++++++-------- Source/Core/VideoCommon/TextureCacheBase.h | 11 +- 2 files changed, 92 insertions(+), 66 deletions(-) diff --git a/Source/Core/VideoCommon/TextureCacheBase.cpp b/Source/Core/VideoCommon/TextureCacheBase.cpp index bbcd1140b4..4e4567da8e 100644 --- a/Source/Core/VideoCommon/TextureCacheBase.cpp +++ b/Source/Core/VideoCommon/TextureCacheBase.cpp @@ -271,25 +271,18 @@ bool TextureCacheBase::DidLinkedAssetsChange(const TCacheEntry& entry) return resource->GetLoadTime() > entry.last_load_time; } -RcTcacheEntry TextureCacheBase::ApplyPaletteToEntry(RcTcacheEntry& entry, const u8* palette, - TLUTFormat tlutfmt) +std::pair +TextureCacheBase::CreatePaletteEntryWithOffset(const RcTcacheEntry& entry, const u8* palette) { DEBUG_ASSERT(g_backend_info.bSupportsPaletteConversion); - const AbstractPipeline* pipeline = g_shader_cache->GetPaletteConversionPipeline(tlutfmt); - if (!pipeline) - { - ERROR_LOG_FMT(VIDEO, "Failed to get conversion pipeline for format {}", tlutfmt); - return {}; - } - TextureConfig new_config = entry->texture->GetConfig(); new_config.levels = 1; new_config.flags |= AbstractTextureFlag_RenderTarget; RcTcacheEntry decoded_entry = AllocateCacheEntry(new_config); if (!decoded_entry) - return decoded_entry; + return {nullptr, 0}; decoded_entry->SetGeneralParameters(entry->addr, entry->size_in_bytes, entry->format, entry->should_force_safe_hashing); @@ -300,58 +293,56 @@ RcTcacheEntry TextureCacheBase::ApplyPaletteToEntry(RcTcacheEntry& entry, const decoded_entry->SetNotCopy(); decoded_entry->may_have_overlapping_textures = entry->may_have_overlapping_textures; - g_gfx->BeginUtilityDrawing(); - const u32 palette_size = entry->format == TextureFormat::I4 ? 32 : 512; u32 texel_buffer_offset; - if (g_vertex_manager->UploadTexelBuffer(palette, palette_size, - TexelBufferFormat::TEXEL_BUFFER_FORMAT_R16_UINT, - &texel_buffer_offset)) - { - struct Uniforms - { - float multiplier; - u32 texel_buffer_offset; - u32 pad[2]; - }; - static_assert(std::is_standard_layout::value); - Uniforms uniforms = {}; - uniforms.multiplier = entry->format == TextureFormat::I4 ? 15.0f : 255.0f; - uniforms.texel_buffer_offset = texel_buffer_offset; - g_vertex_manager->UploadUtilityUniforms(&uniforms, sizeof(uniforms)); - - g_gfx->SetAndDiscardFramebuffer(decoded_entry->framebuffer.get()); - g_gfx->SetViewportAndScissor(decoded_entry->texture->GetRect()); - g_gfx->SetPipeline(pipeline); - g_gfx->SetTexture(1, entry->texture.get()); - g_gfx->SetSamplerState(1, RenderState::GetPointSamplerState()); - g_gfx->Draw(0, 3); - g_gfx->EndUtilityDrawing(); - decoded_entry->texture->FinishedRendering(); - } - else + if (!g_vertex_manager->UploadTexelBuffer(palette, palette_size, + TexelBufferFormat::TEXEL_BUFFER_FORMAT_R16_UINT, + &texel_buffer_offset)) { ERROR_LOG_FMT(VIDEO, "Texel buffer upload of {} bytes failed", palette_size); - g_gfx->EndUtilityDrawing(); } m_textures_by_address.emplace(decoded_entry->addr, decoded_entry); - return decoded_entry; + return {decoded_entry, texel_buffer_offset}; } -RcTcacheEntry TextureCacheBase::ReinterpretEntry(const RcTcacheEntry& existing_entry, - TextureFormat new_format) +void TextureCacheBase::RenderPaletteEntry(u32 texel_buffer_offset, const RcTcacheEntry& entry, + AbstractTexture* texture, TLUTFormat tlutfmt) { - const AbstractPipeline* pipeline = - g_shader_cache->GetTextureReinterpretPipeline(existing_entry->format.texfmt, new_format); + const AbstractPipeline* pipeline = g_shader_cache->GetPaletteConversionPipeline(tlutfmt); if (!pipeline) { - ERROR_LOG_FMT(VIDEO, "Failed to obtain texture reinterpreting pipeline from format {} to {}", - existing_entry->format.texfmt, new_format); - return {}; + ERROR_LOG_FMT(VIDEO, "Failed to get conversion pipeline for format {}", tlutfmt); + return; } + struct Uniforms + { + float multiplier; + u32 texel_buffer_offset; + u32 pad[2]; + }; + static_assert(std::is_standard_layout::value); + Uniforms uniforms = {}; + uniforms.multiplier = entry->format == TextureFormat::I4 ? 15.0f : 255.0f; + uniforms.texel_buffer_offset = texel_buffer_offset; + g_vertex_manager->UploadUtilityUniforms(&uniforms, sizeof(uniforms)); + + g_gfx->BeginUtilityDrawing(); + g_gfx->SetAndDiscardFramebuffer(entry->framebuffer.get()); + g_gfx->SetViewportAndScissor(entry->texture->GetRect()); + g_gfx->SetPipeline(pipeline); + g_gfx->SetTexture(1, texture); + g_gfx->SetSamplerState(1, RenderState::GetPointSamplerState()); + g_gfx->Draw(0, 3); + g_gfx->EndUtilityDrawing(); + entry->texture->FinishedRendering(); +} + +RcTcacheEntry TextureCacheBase::CreateReinterpretEntry(const RcTcacheEntry& existing_entry, + TextureFormat new_format) +{ TextureConfig new_config = existing_entry->texture->GetConfig(); new_config.levels = 1; new_config.flags |= AbstractTextureFlag_RenderTarget; @@ -371,21 +362,34 @@ RcTcacheEntry TextureCacheBase::ReinterpretEntry(const RcTcacheEntry& existing_e reinterpreted_entry->may_have_overlapping_textures = existing_entry->may_have_overlapping_textures; - g_gfx->BeginUtilityDrawing(); - g_gfx->SetAndDiscardFramebuffer(reinterpreted_entry->framebuffer.get()); - g_gfx->SetViewportAndScissor(reinterpreted_entry->texture->GetRect()); - g_gfx->SetPipeline(pipeline); - g_gfx->SetTexture(0, existing_entry->texture.get()); - g_gfx->SetSamplerState(1, RenderState::GetPointSamplerState()); - g_gfx->Draw(0, 3); - g_gfx->EndUtilityDrawing(); - reinterpreted_entry->texture->FinishedRendering(); - m_textures_by_address.emplace(reinterpreted_entry->addr, reinterpreted_entry); return reinterpreted_entry; } +void TextureCacheBase::RenderReinterpretEntry(const RcTcacheEntry& entry, AbstractTexture* texture, + TextureFormat old_format, TextureFormat new_format) +{ + const AbstractPipeline* pipeline = + g_shader_cache->GetTextureReinterpretPipeline(old_format, new_format); + if (!pipeline) + { + ERROR_LOG_FMT(VIDEO, "Failed to obtain texture reinterpreting pipeline from format {} to {}", + old_format, new_format); + return; + } + + g_gfx->BeginUtilityDrawing(); + g_gfx->SetAndDiscardFramebuffer(entry->framebuffer.get()); + g_gfx->SetViewportAndScissor(entry->texture->GetRect()); + g_gfx->SetPipeline(pipeline); + g_gfx->SetTexture(0, texture); + g_gfx->SetSamplerState(1, RenderState::GetPointSamplerState()); + g_gfx->Draw(0, 3); + g_gfx->EndUtilityDrawing(); + entry->texture->FinishedRendering(); +} + void TextureCacheBase::ScaleTextureCacheEntryTo(RcTcacheEntry& entry, u32 new_width, u32 new_height) { if (entry->GetWidth() == new_width && entry->GetHeight() == new_height) @@ -856,14 +860,18 @@ RcTcacheEntry TextureCacheBase::DoPartialTextureUpdates(RcTcacheEntry& entry_to_ continue; } - auto reinterpreted_entry = ReinterpretEntry(entry, entry_to_update->format.texfmt); + auto reinterpreted_entry = CreateReinterpretEntry(entry, entry_to_update->format.texfmt); + RenderReinterpretEntry(reinterpreted_entry, entry->texture.get(), entry->format.texfmt, + reinterpreted_entry->format.texfmt); if (reinterpreted_entry) entry = reinterpreted_entry; } if (isPaletteTexture) { - auto decoded_entry = ApplyPaletteToEntry(entry, palette, tlutfmt); + const auto [decoded_entry, texel_buffer_offset] = + CreatePaletteEntryWithOffset(entry, palette); + RenderPaletteEntry(texel_buffer_offset, decoded_entry, entry->texture.get(), tlutfmt); if (decoded_entry) { // Link the efb copy with the partially updated texture, so we won't apply this partial @@ -1497,12 +1505,21 @@ RcTcacheEntry TextureCacheBase::GetTexture(const int textureCacheSafetyColorSamp if (unreinterpreted_copy != m_textures_by_address.end()) { auto decoded_entry = - ReinterpretEntry(unreinterpreted_copy->second, texture_info.GetTextureFormat()); + CreateReinterpretEntry(unreinterpreted_copy->second, texture_info.GetTextureFormat()); + RenderReinterpretEntry(decoded_entry, unreinterpreted_copy->second->texture.get(), + unreinterpreted_copy->second->format.texfmt, + decoded_entry->format.texfmt); // It's possible to combine reinterpreted textures + palettes. if (unreinterpreted_copy == unconverted_copy && decoded_entry) - decoded_entry = ApplyPaletteToEntry(decoded_entry, texture_info.GetTlutAddress(), - texture_info.GetTlutFormat()); + { + auto existing_entry = decoded_entry; + u32 texel_buffer_offset = 0; + std::tie(decoded_entry, texel_buffer_offset) = + CreatePaletteEntryWithOffset(decoded_entry, texture_info.GetTlutAddress()); + RenderPaletteEntry(texel_buffer_offset, decoded_entry, existing_entry->texture.get(), + texture_info.GetTlutFormat()); + } if (decoded_entry) return decoded_entry; @@ -1510,8 +1527,10 @@ RcTcacheEntry TextureCacheBase::GetTexture(const int textureCacheSafetyColorSamp if (unconverted_copy != m_textures_by_address.end()) { - auto decoded_entry = ApplyPaletteToEntry( - unconverted_copy->second, texture_info.GetTlutAddress(), texture_info.GetTlutFormat()); + const auto [decoded_entry, texel_buffer_offset] = + CreatePaletteEntryWithOffset(unconverted_copy->second, texture_info.GetTlutAddress()); + RenderPaletteEntry(texel_buffer_offset, decoded_entry, unconverted_copy->second->texture.get(), + texture_info.GetTlutFormat()); if (decoded_entry) { diff --git a/Source/Core/VideoCommon/TextureCacheBase.h b/Source/Core/VideoCommon/TextureCacheBase.h index d596f84e5e..7e9d0613d4 100644 --- a/Source/Core/VideoCommon/TextureCacheBase.h +++ b/Source/Core/VideoCommon/TextureCacheBase.h @@ -314,6 +314,11 @@ public: static SamplerState GetSamplerState(u32 index, float custom_tex_scale, bool custom_tex, bool has_arbitrary_mips); + static void RenderPaletteEntry(u32 texel_buffer_offset, const RcTcacheEntry& entry, + AbstractTexture* texture, TLUTFormat tlutfmt); + static void RenderReinterpretEntry(const RcTcacheEntry& entry, AbstractTexture* texture, + TextureFormat old_format, TextureFormat new_format); + protected: // Decodes the specified data to the GPU texture specified by entry. // Returns false if the configuration is not supported. @@ -360,9 +365,11 @@ private: RcTcacheEntry GetXFBFromCache(u32 address, u32 width, u32 height, u32 stride); - RcTcacheEntry ApplyPaletteToEntry(RcTcacheEntry& entry, const u8* palette, TLUTFormat tlutfmt); + std::pair CreatePaletteEntryWithOffset(const RcTcacheEntry& entry, + const u8* palette); - RcTcacheEntry ReinterpretEntry(const RcTcacheEntry& existing_entry, TextureFormat new_format); + RcTcacheEntry CreateReinterpretEntry(const RcTcacheEntry& existing_entry, + TextureFormat new_format); RcTcacheEntry DoPartialTextureUpdates(RcTcacheEntry& entry_to_update, const u8* palette, TLUTFormat tlutfmt);