Merge pull request #14837 from iwubcode/dolphin_texture_refactor_2

VideoCommon: separate out reinterpret and palette texture creation from rendering
This commit is contained in:
Scott Mansell
2026-09-01 16:47:42 +12:00
committed by GitHub
2 changed files with 92 additions and 66 deletions

View File

@@ -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<RcTcacheEntry, u32>
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<Uniforms>::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<Uniforms>::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)
{

View File

@@ -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<RcTcacheEntry, u32> 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);