GPU/TextureCache: Prefill dumped texture list with replacements

Allows skipping dumping replaced textures without replacements enabled.
This commit is contained in:
Stenzek 2025-01-31 14:16:23 +10:00
parent b5925ab139
commit d65c4efdd8
No known key found for this signature in database
1 changed files with 136 additions and 76 deletions

View File

@ -228,6 +228,13 @@ struct DumpedTextureKey
{
return (std::memcmp(&k, this, sizeof(DumpedTextureKey)) != 0);
}
static DumpedTextureKey FromName(const TextureReplacementName& name)
{
return DumpedTextureKey{name.src_hash, name.pal_hash, name.offset_x,
name.offset_y, name.width, name.height,
name.type, name.texture_mode, {}};
}
};
struct DumpedTextureKeyHash
{
@ -311,7 +318,8 @@ static bool IsMatchingReplacementPalette(HashType full_palette_hash, GPUTextureM
const TextureReplacementName& name);
static bool LoadLocalConfiguration(bool load_vram_write_replacement_aliases, bool load_texture_replacement_aliases);
static void FindTextureReplacements(bool load_vram_write_replacements, bool load_texture_replacements);
static void FindTextureReplacements(bool load_vram_write_replacements, bool load_texture_replacements,
bool prefill_dumped_texture_list, bool prefill_dumped_vram_list);
static void LoadTextureReplacementAliases(const ryml::ConstNodeRef& root, bool load_vram_write_replacement_aliases,
bool load_texture_replacement_aliases);
@ -604,7 +612,12 @@ bool GPUTextureCache::UpdateSettings(bool use_texture_cache, const GPUSettings&
g_gpu_settings.texture_replacements.enable_texture_replacements !=
old_settings.texture_replacements.enable_texture_replacements ||
g_gpu_settings.texture_replacements.enable_vram_write_replacements !=
old_settings.texture_replacements.enable_vram_write_replacements)
old_settings.texture_replacements.enable_vram_write_replacements ||
g_gpu_settings.texture_replacements.dump_textures != old_settings.texture_replacements.dump_textures ||
g_gpu_settings.texture_replacements.dump_vram_writes != old_settings.texture_replacements.dump_vram_writes ||
(g_gpu_settings.texture_replacements.dump_replaced_textures !=
old_settings.texture_replacements.dump_replaced_textures &&
(g_gpu_settings.texture_replacements.dump_textures || g_gpu_settings.texture_replacements.dump_vram_writes)))
{
if (use_texture_cache)
{
@ -2707,17 +2720,13 @@ void GPUTextureCache::DumpVRAMWrite(u32 width, u32 height, const void* pixels)
{
const VRAMReplacementName name = GetVRAMWriteHash(width, height, pixels);
if (s_state.dumped_vram_writes.find(name) != s_state.dumped_vram_writes.end())
return;
s_state.dumped_vram_writes.insert(name);
if (!g_gpu_settings.texture_replacements.dump_replaced_textures &&
s_state.vram_replacements.find(name) != s_state.vram_replacements.end())
{
INFO_LOG("Not dumping VRAM write '{}' because it already has a replacement", name.ToString());
DEV_COLOR_LOG(Green, "Not dumping {}", name.ToString());
return;
}
s_state.dumped_vram_writes.insert(name);
const std::string path = GetVRAMWriteDumpPath(name);
if (path.empty() || FileSystem::FileExists(path.c_str()))
return;
@ -2765,27 +2774,6 @@ void GPUTextureCache::DumpTexture(TextureReplacementType type, u32 offset_x, u32
!s_state.config.dump_texture_force_alpha_channel);
const u8 dumped_texture_mode = static_cast<u8>(mode) | (semitransparent ? 4 : 0);
const DumpedTextureKey key = {src_hash,
pal_hash,
Truncate16(offset_x),
Truncate16(offset_y),
Truncate16(width),
Truncate16(height),
type,
dumped_texture_mode,
{}};
if (s_state.dumped_textures.find(key) != s_state.dumped_textures.end())
return;
if (!EnsureGameDirectoryExists())
return;
const std::string dump_directory = GetTextureDumpDirectory();
if (!FileSystem::EnsureDirectoryExists(dump_directory.c_str(), false))
return;
s_state.dumped_textures.insert(key);
const TextureReplacementName name = {
.src_hash = src_hash,
.pal_hash = pal_hash,
@ -2801,24 +2789,22 @@ void GPUTextureCache::DumpTexture(TextureReplacementType type, u32 offset_x, u32
.pal_max = Truncate8(pal_max),
};
// skip if dumped already
if (!g_gpu_settings.texture_replacements.dump_replaced_textures)
const DumpedTextureKey key = DumpedTextureKey::FromName(name);
if (s_state.dumped_textures.find(key) != s_state.dumped_textures.end())
{
const TextureReplacementMap& map = (type == TextureReplacementType::TextureFromPage) ?
s_state.texture_page_texture_replacements :
s_state.vram_write_texture_replacements;
const auto& [begin, end] = map.equal_range(name.GetIndex());
for (auto it = begin; it != end; ++it)
{
// only match on the hash, not the sizes, we could be trying to dump a smaller texture
if (it->second.first.pal_hash == name.pal_hash)
{
DEV_LOG("Not dumping currently-replaced VRAM write {:016X} [{}x{}] at {}", src_hash, width, height, rect);
return;
}
}
DEV_COLOR_LOG(Green, "Not dumping {}", name.ToString());
return;
}
if (!EnsureGameDirectoryExists())
return;
const std::string dump_directory = GetTextureDumpDirectory();
if (!FileSystem::EnsureDirectoryExists(dump_directory.c_str(), false))
return;
s_state.dumped_textures.insert(key);
SmallString filename = name.ToString();
filename.append(".png");
@ -3036,7 +3022,8 @@ bool GPUTextureCache::HasValidReplacementExtension(const std::string_view path)
return false;
}
void GPUTextureCache::FindTextureReplacements(bool load_vram_write_replacements, bool load_texture_replacements)
void GPUTextureCache::FindTextureReplacements(bool load_vram_write_replacements, bool load_texture_replacements,
bool prefill_dumped_texture_list, bool prefill_dumped_vram_list)
{
if (GPUThread::GetGameSerial().empty())
return;
@ -3045,6 +3032,11 @@ void GPUTextureCache::FindTextureReplacements(bool load_vram_write_replacements,
FileSystem::FindFiles(GetTextureReplacementDirectory().c_str(), "*",
FILESYSTEM_FIND_FILES | FILESYSTEM_FIND_RECURSIVE, &files);
const bool add_texture_replacements_to_dumped =
prefill_dumped_texture_list && !g_gpu_settings.texture_replacements.dump_replaced_textures;
const bool add_vram_replacements_to_dumped =
prefill_dumped_vram_list && !g_gpu_settings.texture_replacements.dump_replaced_textures;
for (FILESYSTEM_FIND_DATA& fd : files)
{
if ((fd.Attributes & FILESYSTEM_FILE_ATTRIBUTE_DIRECTORY) || !HasValidReplacementExtension(fd.FileName))
@ -3060,17 +3052,23 @@ void GPUTextureCache::FindTextureReplacements(bool load_vram_write_replacements,
case TextureReplacementType::VRAMReplacement:
{
VRAMReplacementName name;
if (!load_vram_write_replacements || !name.Parse(file_title))
if (!name.Parse(file_title))
continue;
if (const auto it = s_state.vram_replacements.find(name); it != s_state.vram_replacements.end())
if (add_vram_replacements_to_dumped)
s_state.dumped_vram_writes.insert(name);
if (load_vram_write_replacements)
{
WARNING_LOG("Duplicate VRAM replacement: '{}' and '{}'", Path::GetFileName(it->second),
Path::GetFileName(fd.FileName));
continue;
}
if (const auto it = s_state.vram_replacements.find(name); it != s_state.vram_replacements.end())
{
WARNING_LOG("Duplicate VRAM replacement: '{}' and '{}'", Path::GetFileName(it->second),
Path::GetFileName(fd.FileName));
continue;
}
s_state.vram_replacements.emplace(name, std::move(fd.FileName));
s_state.vram_replacements.emplace(name, std::move(fd.FileName));
}
}
break;
@ -3078,32 +3076,38 @@ void GPUTextureCache::FindTextureReplacements(bool load_vram_write_replacements,
case TextureReplacementType::TextureFromPage:
{
TextureReplacementName name;
if (!load_texture_replacements || !name.Parse(file_title))
if (!name.Parse(file_title))
continue;
DebugAssert(name.type == type.value());
if (add_texture_replacements_to_dumped)
s_state.dumped_textures.insert(DumpedTextureKey::FromName(name));
const TextureReplacementIndex index = name.GetIndex();
TextureReplacementMap& dest_map = (type.value() == TextureReplacementType::TextureFromVRAMWrite) ?
s_state.vram_write_texture_replacements :
s_state.texture_page_texture_replacements;
// Multiple replacements in the same write are fine. But they should have different rects.
const auto range = dest_map.equal_range(index);
bool duplicate = false;
for (auto it = range.first; it != range.second; ++it)
if (load_texture_replacements)
{
if (it->second.first == name) [[unlikely]]
{
WARNING_LOG("Duplicate texture replacement: '{}' and '{}'", Path::GetFileName(it->second.second),
Path::GetFileName(fd.FileName));
duplicate = true;
}
}
if (duplicate) [[unlikely]]
continue;
DebugAssert(name.type == type.value());
dest_map.emplace(index, std::make_pair(name, std::move(fd.FileName)));
const TextureReplacementIndex index = name.GetIndex();
TextureReplacementMap& dest_map = (type.value() == TextureReplacementType::TextureFromVRAMWrite) ?
s_state.vram_write_texture_replacements :
s_state.texture_page_texture_replacements;
// Multiple replacements in the same write are fine. But they should have different rects.
const auto range = dest_map.equal_range(index);
bool duplicate = false;
for (auto it = range.first; it != range.second; ++it)
{
if (it->second.first == name) [[unlikely]]
{
WARNING_LOG("Duplicate texture replacement: '{}' and '{}'", Path::GetFileName(it->second.second),
Path::GetFileName(fd.FileName));
duplicate = true;
}
}
if (duplicate) [[unlikely]]
continue;
dest_map.emplace(index, std::make_pair(name, std::move(fd.FileName)));
}
}
break;
@ -3121,6 +3125,52 @@ void GPUTextureCache::FindTextureReplacements(bool load_vram_write_replacements,
if (g_gpu_settings.texture_replacements.enable_vram_write_replacements)
INFO_LOG("Found {} replacement VRAM for '{}'", s_state.vram_replacements.size(), GPUThread::GetGameSerial());
// if we're dumping, need to prefill the dumped list with those in the dumps directory as well
if (prefill_dumped_texture_list || prefill_dumped_vram_list)
{
FileSystem::FindFiles(GetTextureDumpDirectory().c_str(), "*", FILESYSTEM_FIND_FILES | FILESYSTEM_FIND_RECURSIVE,
&files);
for (FILESYSTEM_FIND_DATA& fd : files)
{
if ((fd.Attributes & FILESYSTEM_FILE_ATTRIBUTE_DIRECTORY) || !HasValidReplacementExtension(fd.FileName))
continue;
const std::string_view file_title = Path::GetFileTitle(fd.FileName);
const std::optional<TextureReplacementType> type = GetTextureReplacementTypeFromFileTitle(file_title);
if (!type.has_value())
continue;
switch (type.value())
{
case TextureReplacementType::VRAMReplacement:
{
VRAMReplacementName name;
if (!name.Parse(file_title))
continue;
if (prefill_dumped_vram_list)
s_state.dumped_vram_writes.insert(name);
}
break;
case TextureReplacementType::TextureFromVRAMWrite:
case TextureReplacementType::TextureFromPage:
{
TextureReplacementName name;
if (!name.Parse(file_title))
continue;
if (prefill_dumped_texture_list)
s_state.dumped_textures.insert(DumpedTextureKey::FromName(name));
}
break;
DefaultCaseIsUnreachable()
}
}
}
}
void GPUTextureCache::LoadTextureReplacementAliases(const ryml::ConstNodeRef& root,
@ -3526,6 +3576,8 @@ bool GPUTextureCache::LoadLocalConfiguration(bool load_vram_write_replacement_al
void GPUTextureCache::ReloadTextureReplacements(bool show_info)
{
s_state.dumped_textures.clear();
s_state.dumped_vram_writes.clear();
s_state.vram_replacements.clear();
s_state.vram_write_texture_replacements.clear();
s_state.texture_page_texture_replacements.clear();
@ -3533,8 +3585,16 @@ void GPUTextureCache::ReloadTextureReplacements(bool show_info)
const bool load_vram_write_replacements = (g_gpu_settings.texture_replacements.enable_vram_write_replacements);
const bool load_texture_replacements =
(g_gpu_settings.gpu_texture_cache && g_gpu_settings.texture_replacements.enable_texture_replacements);
if (load_vram_write_replacements || load_texture_replacements)
FindTextureReplacements(load_vram_write_replacements, load_texture_replacements);
const bool prefill_dumped_texture_list =
(g_gpu_settings.texture_replacements.dump_vram_writes || g_gpu_settings.texture_replacements.dump_textures);
const bool prefill_dumped_vram_list =
(g_gpu_settings.texture_replacements.dump_vram_writes || g_gpu_settings.texture_replacements.dump_textures);
if (load_vram_write_replacements || load_texture_replacements || prefill_dumped_texture_list ||
prefill_dumped_vram_list)
{
FindTextureReplacements(load_vram_write_replacements, load_texture_replacements, prefill_dumped_texture_list,
prefill_dumped_vram_list);
}
LoadLocalConfiguration(load_vram_write_replacements, load_texture_replacements);