mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2026-09-08 11:26:23 -05:00
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:
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user