GPU/TextureCache: Specify max hash cache size/memory in config

This commit is contained in:
Stenzek 2024-11-27 16:58:48 +10:00
parent b28ca2b78a
commit eb390a9b5d
No known key found for this signature in database
3 changed files with 64 additions and 19 deletions

View File

@ -509,7 +509,6 @@ struct GPUTextureCacheState
{ {
Settings::TextureReplacementSettings::Configuration config; Settings::TextureReplacementSettings::Configuration config;
size_t hash_cache_memory_usage = 0; size_t hash_cache_memory_usage = 0;
size_t max_hash_cache_memory_usage = 1ULL * 1024ULL * 1024ULL * 1024ULL; // 2GB
VRAMWrite* last_vram_write = nullptr; VRAMWrite* last_vram_write = nullptr;
bool track_vram_writes = false; bool track_vram_writes = false;
@ -2114,10 +2113,11 @@ void GPUTextureCache::Compact()
static constexpr u32 MAX_HASH_CACHE_AGE = 600; static constexpr u32 MAX_HASH_CACHE_AGE = 600;
// Maximum number of textures which are permitted in the hash cache at the end of the frame. // Maximum number of textures which are permitted in the hash cache at the end of the frame.
static constexpr u32 MAX_HASH_CACHE_SIZE = 500; const u32 max_hash_cache_size = s_state.config.max_hash_cache_entries;
const size_t max_hash_cache_memory = static_cast<size_t>(s_state.config.max_hash_cache_vram_usage_mb) * 1048576;
bool might_need_cache_purge = (s_state.hash_cache.size() > MAX_HASH_CACHE_SIZE || bool might_need_cache_purge =
s_state.hash_cache_memory_usage >= s_state.max_hash_cache_memory_usage); (s_state.hash_cache.size() > max_hash_cache_size || s_state.hash_cache_memory_usage >= max_hash_cache_memory);
if (might_need_cache_purge) if (might_need_cache_purge)
s_state.hash_cache_purge_list.clear(); s_state.hash_cache_purge_list.clear();
@ -2136,8 +2136,8 @@ void GPUTextureCache::Compact()
// We might free up enough just with "normal" removals above. // We might free up enough just with "normal" removals above.
if (might_need_cache_purge) if (might_need_cache_purge)
{ {
might_need_cache_purge = (s_state.hash_cache.size() > MAX_HASH_CACHE_SIZE || might_need_cache_purge =
s_state.hash_cache_memory_usage >= s_state.max_hash_cache_memory_usage); (s_state.hash_cache.size() > max_hash_cache_size || s_state.hash_cache_memory_usage >= max_hash_cache_memory);
if (might_need_cache_purge) if (might_need_cache_purge)
s_state.hash_cache_purge_list.emplace_back(it, static_cast<s32>(e.last_used_frame)); s_state.hash_cache_purge_list.emplace_back(it, static_cast<s32>(e.last_used_frame));
} }
@ -2148,12 +2148,14 @@ void GPUTextureCache::Compact()
// Pushing to a list, sorting, and removing ends up faster than re-iterating the map. // Pushing to a list, sorting, and removing ends up faster than re-iterating the map.
if (might_need_cache_purge) if (might_need_cache_purge)
{ {
DEV_LOG("Force compacting hash cache, count = {}, size = {:.1f} MB", s_state.hash_cache.size(),
static_cast<float>(s_state.hash_cache_memory_usage) / 1048576.0f);
std::sort(s_state.hash_cache_purge_list.begin(), s_state.hash_cache_purge_list.end(), std::sort(s_state.hash_cache_purge_list.begin(), s_state.hash_cache_purge_list.end(),
[](const auto& lhs, const auto& rhs) { return lhs.second < rhs.second; }); [](const auto& lhs, const auto& rhs) { return lhs.second < rhs.second; });
size_t purge_index = 0; size_t purge_index = 0;
while (s_state.hash_cache.size() > MAX_HASH_CACHE_SIZE || while (s_state.hash_cache.size() > max_hash_cache_size || s_state.hash_cache_memory_usage >= max_hash_cache_memory)
s_state.hash_cache_memory_usage >= s_state.max_hash_cache_memory_usage)
{ {
if (purge_index == s_state.hash_cache_purge_list.size()) if (purge_index == s_state.hash_cache_purge_list.size())
{ {
@ -2164,6 +2166,9 @@ void GPUTextureCache::Compact()
RemoveFromHashCache(s_state.hash_cache_purge_list[purge_index++].first); RemoveFromHashCache(s_state.hash_cache_purge_list[purge_index++].first);
} }
DEV_LOG("Finished compacting hash cache, count = {}, size = {:.1f} MB", s_state.hash_cache.size(),
static_cast<float>(s_state.hash_cache_memory_usage) / 1048576.0f);
} }
CompactTextureReplacementGPUImages(); CompactTextureReplacementGPUImages();
@ -3056,9 +3061,9 @@ void GPUTextureCache::CompactTextureReplacementGPUImages()
if (s_state.gpu_replacement_image_cache_vram_usage <= max_usage) if (s_state.gpu_replacement_image_cache_vram_usage <= max_usage)
return; return;
VERBOSE_LOG("Compacting replacement GPU image cache, count = {}, size = {:.1f} MB", DEV_LOG("Compacting replacement GPU image cache, count = {}, size = {:.1f} MB",
s_state.gpu_replacement_image_cache.size(), s_state.gpu_replacement_image_cache.size(),
static_cast<float>(s_state.gpu_replacement_image_cache_vram_usage) / 1048576.0f); static_cast<float>(s_state.gpu_replacement_image_cache_vram_usage) / 1048576.0f);
const u32 frame_number = System::GetFrameNumber(); const u32 frame_number = System::GetFrameNumber();
s_state.gpu_replacement_image_cache_purge_list.reserve(s_state.gpu_replacement_image_cache.size()); s_state.gpu_replacement_image_cache_purge_list.reserve(s_state.gpu_replacement_image_cache.size());
@ -3086,9 +3091,9 @@ void GPUTextureCache::CompactTextureReplacementGPUImages()
s_state.gpu_replacement_image_cache_purge_list.clear(); s_state.gpu_replacement_image_cache_purge_list.clear();
VERBOSE_LOG("Finished compacting replacement GPU image cache, count = {}, size = {:.1f} MB", DEV_LOG("Finished compacting replacement GPU image cache, count = {}, size = {:.1f} MB",
s_state.gpu_replacement_image_cache.size(), s_state.gpu_replacement_image_cache.size(),
static_cast<float>(s_state.gpu_replacement_image_cache_vram_usage) / 1048576.0f); static_cast<float>(s_state.gpu_replacement_image_cache_vram_usage) / 1048576.0f);
} }
void GPUTextureCache::PreloadReplacementTextures() void GPUTextureCache::PreloadReplacementTextures()
@ -3241,9 +3246,6 @@ bool GPUTextureCache::LoadLocalConfiguration(bool load_vram_write_replacement_al
.value_or(static_cast<bool>(s_state.config.reduce_palette_range)); .value_or(static_cast<bool>(s_state.config.reduce_palette_range));
s_state.config.convert_copies_to_writes = GetOptionalTFromObject<bool>(root, "ConvertCopiesToWrites") s_state.config.convert_copies_to_writes = GetOptionalTFromObject<bool>(root, "ConvertCopiesToWrites")
.value_or(static_cast<bool>(s_state.config.convert_copies_to_writes)); .value_or(static_cast<bool>(s_state.config.convert_copies_to_writes));
s_state.config.replacement_scale_linear_filter =
GetOptionalTFromObject<bool>(root, "ReplacementScaleLinearFilter")
.value_or(static_cast<bool>(s_state.config.replacement_scale_linear_filter));
s_state.config.max_vram_write_splits = s_state.config.max_vram_write_splits =
GetOptionalTFromObject<bool>(root, "MaxVRAMWriteSplits").value_or(s_state.config.max_vram_write_splits); GetOptionalTFromObject<bool>(root, "MaxVRAMWriteSplits").value_or(s_state.config.max_vram_write_splits);
s_state.config.max_vram_write_coalesce_width = GetOptionalTFromObject<u32>(root, "MaxVRAMWriteCoalesceWidth") s_state.config.max_vram_write_coalesce_width = GetOptionalTFromObject<u32>(root, "MaxVRAMWriteCoalesceWidth")
@ -3258,6 +3260,15 @@ bool GPUTextureCache::LoadLocalConfiguration(bool load_vram_write_replacement_al
.value_or(s_state.config.vram_write_dump_width_threshold); .value_or(s_state.config.vram_write_dump_width_threshold);
s_state.config.vram_write_dump_height_threshold = GetOptionalTFromObject<u32>(root, "DumpVRAMWriteHeightThreshold") s_state.config.vram_write_dump_height_threshold = GetOptionalTFromObject<u32>(root, "DumpVRAMWriteHeightThreshold")
.value_or(s_state.config.vram_write_dump_height_threshold); .value_or(s_state.config.vram_write_dump_height_threshold);
s_state.config.max_hash_cache_entries =
GetOptionalTFromObject<u32>(root, "MaxHashCacheEntries").value_or(s_state.config.max_hash_cache_entries);
s_state.config.max_hash_cache_vram_usage_mb =
GetOptionalTFromObject<u32>(root, "MaxHashCacheVRAMUsageMB").value_or(s_state.config.max_hash_cache_vram_usage_mb);
s_state.config.max_replacement_cache_vram_usage_mb = GetOptionalTFromObject<u32>(root, "MaxReplacementCacheVRAMUsage")
.value_or(s_state.config.max_replacement_cache_vram_usage_mb);
s_state.config.replacement_scale_linear_filter =
GetOptionalTFromObject<bool>(root, "ReplacementScaleLinearFilter")
.value_or(static_cast<bool>(s_state.config.replacement_scale_linear_filter));
if (load_vram_write_replacement_aliases || load_texture_replacement_aliases) if (load_vram_write_replacement_aliases || load_texture_replacement_aliases)
{ {

View File

@ -454,8 +454,15 @@ void Settings::Load(const SettingsInterface& si, const SettingsInterface& contro
texture_replacements.config.replacement_scale_linear_filter = texture_replacements.config.replacement_scale_linear_filter =
si.GetBoolValue("TextureReplacements", "ReplacementScaleLinearFilter", false); si.GetBoolValue("TextureReplacements", "ReplacementScaleLinearFilter", false);
texture_replacements.config.max_hash_cache_entries =
si.GetUIntValue("TextureReplacements", "MaxHashCacheEntries",
TextureReplacementSettings::Configuration::DEFAULT_MAX_HASH_CACHE_ENTRIES);
texture_replacements.config.max_hash_cache_vram_usage_mb =
si.GetUIntValue("TextureReplacements", "MaxHashCacheVRAMUsageMB",
TextureReplacementSettings::Configuration::DEFAULT_MAX_HASH_CACHE_VRAM_USAGE_MB);
texture_replacements.config.max_replacement_cache_vram_usage_mb = texture_replacements.config.max_replacement_cache_vram_usage_mb =
si.GetUIntValue("TextureReplacements", "MaxReplacementCacheVRAMUsage", 512); si.GetUIntValue("TextureReplacements", "MaxReplacementCacheVRAMUsage",
TextureReplacementSettings::Configuration::DEFAULT_MAX_REPLACEMENT_CACHE_VRAM_USAGE_MB);
texture_replacements.config.max_vram_write_splits = si.GetUIntValue("TextureReplacements", "MaxVRAMWriteSplits", 0u); texture_replacements.config.max_vram_write_splits = si.GetUIntValue("TextureReplacements", "MaxVRAMWriteSplits", 0u);
texture_replacements.config.max_vram_write_coalesce_width = texture_replacements.config.max_vram_write_coalesce_width =
@ -717,6 +724,9 @@ void Settings::Save(SettingsInterface& si, bool ignore_base) const
si.SetBoolValue("TextureReplacements", "ReplacementScaleLinearFilter", si.SetBoolValue("TextureReplacements", "ReplacementScaleLinearFilter",
texture_replacements.config.replacement_scale_linear_filter); texture_replacements.config.replacement_scale_linear_filter);
si.SetUIntValue("TextureReplacements", "MaxHashCacheEntries", texture_replacements.config.max_hash_cache_entries);
si.SetUIntValue("TextureReplacements", "MaxHashCacheVRAMUsageMB",
texture_replacements.config.max_hash_cache_vram_usage_mb);
si.SetUIntValue("TextureReplacements", "MaxReplacementCacheVRAMUsage", si.SetUIntValue("TextureReplacements", "MaxReplacementCacheVRAMUsage",
texture_replacements.config.max_replacement_cache_vram_usage_mb); texture_replacements.config.max_replacement_cache_vram_usage_mb);
@ -870,6 +880,21 @@ std::string Settings::TextureReplacementSettings::Configuration::ExportToYAML(bo
{}DumpVRAMWriteWidthThreshold: {} {}DumpVRAMWriteWidthThreshold: {}
{}DumpVRAMWriteHeightThreshold: {} {}DumpVRAMWriteHeightThreshold: {}
# Sets the maximum size of the hash cache that manages texture replacements.
# Generally the default is sufficient, but some games may require increasing the
# size. Do not set too high, otherwise mobile drivers will break.
{}MaxHashCacheEntries: {}
# Sets the maximum amount of VRAM in megabytes that the hash cache can utilize.
# Keep in mind your target system requirements, using too much VRAM will result
# in swapping and significantly decreased performance.
{}MaxHashCacheVRAMUsageMB: {}
# Sets the maximum amount of VRAM in megabytes that are reserved for the cache of
# replacement textures. The cache usage for any given texture is approximately the
# same size as the uncompressed source image on disk.
{}MaxReplacementCacheVRAMUsage: {}
# Enables the use of a bilinear filter when scaling replacement textures. # Enables the use of a bilinear filter when scaling replacement textures.
# If more than one replacement texture in a 256x256 texture page has a different # If more than one replacement texture in a 256x256 texture page has a different
# scaling over the native resolution, or the texture page is not covered, a # scaling over the native resolution, or the texture page is not covered, a
@ -901,6 +926,9 @@ std::string Settings::TextureReplacementSettings::Configuration::ExportToYAML(bo
comment_str, texture_dump_height_threshold, // DumpTextureHeightThreshold comment_str, texture_dump_height_threshold, // DumpTextureHeightThreshold
comment_str, vram_write_dump_width_threshold, // DumpVRAMWriteWidthThreshold comment_str, vram_write_dump_width_threshold, // DumpVRAMWriteWidthThreshold
comment_str, vram_write_dump_height_threshold, // DumpVRAMWriteHeightThreshold comment_str, vram_write_dump_height_threshold, // DumpVRAMWriteHeightThreshold
comment_str, max_hash_cache_entries, // MaxHashCacheEntries
comment_str, max_hash_cache_vram_usage_mb, // MaxHashCacheVRAMUsageMB
comment_str, max_replacement_cache_vram_usage_mb, // MaxReplacementCacheVRAMUsage
comment_str, replacement_scale_linear_filter); // ReplacementScaleLinearFilter comment_str, replacement_scale_linear_filter); // ReplacementScaleLinearFilter
} }

View File

@ -234,6 +234,10 @@ struct Settings
{ {
struct Configuration struct Configuration
{ {
static constexpr u32 DEFAULT_MAX_HASH_CACHE_ENTRIES = 500;
static constexpr u32 DEFAULT_MAX_HASH_CACHE_VRAM_USAGE_MB = 2048;
static constexpr u32 DEFAULT_MAX_REPLACEMENT_CACHE_VRAM_USAGE_MB = 512;
constexpr Configuration() = default; constexpr Configuration() = default;
bool dump_texture_pages : 1 = false; bool dump_texture_pages : 1 = false;
@ -245,7 +249,9 @@ struct Settings
bool convert_copies_to_writes : 1 = false; bool convert_copies_to_writes : 1 = false;
bool replacement_scale_linear_filter = false; bool replacement_scale_linear_filter = false;
u32 max_replacement_cache_vram_usage_mb = 512; u32 max_hash_cache_entries = DEFAULT_MAX_HASH_CACHE_ENTRIES;
u32 max_hash_cache_vram_usage_mb = DEFAULT_MAX_HASH_CACHE_VRAM_USAGE_MB;
u32 max_replacement_cache_vram_usage_mb = DEFAULT_MAX_REPLACEMENT_CACHE_VRAM_USAGE_MB;
u32 max_vram_write_splits = 0; u32 max_vram_write_splits = 0;
u32 max_vram_write_coalesce_width = 0; u32 max_vram_write_coalesce_width = 0;