Skip to content

Commit

Permalink
GPU/TextureCache: Prefill dumped texture list with replacements
Browse files Browse the repository at this point in the history
Allows skipping dumping replaced textures without replacements enabled.
  • Loading branch information
stenzek committed Jan 31, 2025
1 parent b5925ab commit d65c4ef
Showing 1 changed file with 134 additions and 74 deletions.
208 changes: 134 additions & 74 deletions src/core/gpu_hw_texture_cache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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,
Expand All @@ -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");

Expand Down Expand Up @@ -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;
Expand All @@ -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))
Expand All @@ -3060,50 +3052,62 @@ 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;

case TextureReplacementType::TextureFromVRAMWrite:
case TextureReplacementType::TextureFromPage:
{
TextureReplacementName name;
if (!load_texture_replacements || !name.Parse(file_title))
if (!name.Parse(file_title))
continue;

DebugAssert(name.type == type.value());

const TextureReplacementIndex index = name.GetIndex();
TextureReplacementMap& dest_map = (type.value() == TextureReplacementType::TextureFromVRAMWrite) ?
s_state.vram_write_texture_replacements :
s_state.texture_page_texture_replacements;
if (add_texture_replacements_to_dumped)
s_state.dumped_textures.insert(DumpedTextureKey::FromName(name));

// 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]]
DebugAssert(name.type == type.value());

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)
{
WARNING_LOG("Duplicate texture replacement: '{}' and '{}'", Path::GetFileName(it->second.second),
Path::GetFileName(fd.FileName));
duplicate = true;
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;
if (duplicate) [[unlikely]]
continue;

dest_map.emplace(index, std::make_pair(name, std::move(fd.FileName)));
dest_map.emplace(index, std::make_pair(name, std::move(fd.FileName)));
}
}
break;

Expand All @@ -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,
Expand Down Expand Up @@ -3526,15 +3576,25 @@ 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();

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);

Expand Down

0 comments on commit d65c4ef

Please sign in to comment.