mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2026-07-17 23:30:42 +00:00
texture_cache: Add sampler garbage collection (#4700)
This commit is contained in:
@@ -400,6 +400,17 @@ public:
|
||||
return properties.limits.maxFramebufferHeight;
|
||||
}
|
||||
|
||||
/// Returns the maximum number of samplers that can be allocated at once.
|
||||
u32 GetMaxSamplerAllocationCount() const {
|
||||
if (driver_id == vk::DriverId::eMesaKosmickrisp) {
|
||||
// FIXME: KosmicKrisp has an internal 1024 unique sampler limit before
|
||||
// vkCreateSampler starts returning VK_ERROR_OUT_OF_HOST_MEMORY. Work
|
||||
// around this for now by reducing the value to 1024.
|
||||
return 1024;
|
||||
}
|
||||
return properties.limits.maxSamplerAllocationCount;
|
||||
}
|
||||
|
||||
/// Returns the sample count flags supported by color buffers.
|
||||
vk::SampleCountFlags GetColorSampleCounts() const {
|
||||
return properties.limits.framebufferColorSampleCounts;
|
||||
|
||||
@@ -29,6 +29,8 @@ public:
|
||||
return *handle;
|
||||
}
|
||||
|
||||
size_t lru_id{};
|
||||
|
||||
private:
|
||||
vk::UniqueSampler handle;
|
||||
};
|
||||
|
||||
@@ -33,6 +33,11 @@ TextureCache::TextureCache(const Vulkan::Instance& instance_, Vulkan::Scheduler&
|
||||
const auto null_id = GetNullImage(vk::Format::eR8G8B8A8Unorm);
|
||||
ASSERT(null_id.index == NULL_IMAGE_ID.index);
|
||||
|
||||
u32 max_samplers = instance.GetMaxSamplerAllocationCount();
|
||||
trigger_gc_samplers = max_samplers * 3 / 4;
|
||||
pressure_gc_samplers = max_samplers * 7 / 8;
|
||||
critical_gc_samplers = max_samplers * 15 / 16;
|
||||
|
||||
// Set up garbage collection parameters.
|
||||
if (!instance.CanReportMemoryUsage()) {
|
||||
trigger_gc_memory = 0;
|
||||
@@ -820,7 +825,15 @@ void TextureCache::RefreshImage(Image& image) {
|
||||
vk::Sampler TextureCache::GetSampler(const AmdGpu::Sampler& sampler,
|
||||
AmdGpu::BorderColorBuffer border_color_base) {
|
||||
const u64 hash = XXH3_64bits(&sampler, sizeof(sampler));
|
||||
|
||||
std::scoped_lock lock{samplers_mutex};
|
||||
const auto [it, new_sampler] = samplers.try_emplace(hash, instance, sampler, border_color_base);
|
||||
if (new_sampler) {
|
||||
samplers.at(hash).lru_id = sampler_lru_cache.Insert(hash, gc_tick);
|
||||
} else {
|
||||
sampler_lru_cache.Touch(it->second.lru_id, gc_tick);
|
||||
}
|
||||
|
||||
return it->second.Handle();
|
||||
}
|
||||
|
||||
@@ -966,10 +979,7 @@ void TextureCache::UntrackImageTail(ImageId image_id) {
|
||||
tracker.UpdatePageWatchers<false>(addr, size);
|
||||
}
|
||||
|
||||
void TextureCache::RunGarbageCollector() {
|
||||
SCOPE_EXIT {
|
||||
++gc_tick;
|
||||
};
|
||||
void TextureCache::GarbageCollectImages() {
|
||||
if (instance.CanReportMemoryUsage()) {
|
||||
total_used_memory = instance.GetDeviceMemoryUsage();
|
||||
}
|
||||
@@ -1033,6 +1043,55 @@ void TextureCache::RunGarbageCollector() {
|
||||
}
|
||||
}
|
||||
|
||||
void TextureCache::GarbageCollectSamplers() {
|
||||
total_used_samplers = samplers.size();
|
||||
if (total_used_samplers < trigger_gc_samplers) {
|
||||
return;
|
||||
}
|
||||
std::scoped_lock lock{samplers_mutex};
|
||||
bool pressured = false;
|
||||
bool aggresive = false;
|
||||
u64 ticks_to_destroy = 0;
|
||||
size_t num_deletions = 0;
|
||||
|
||||
const auto configure = [&](bool allow_aggressive) {
|
||||
pressured = total_used_samplers >= pressure_gc_samplers;
|
||||
aggresive = allow_aggressive && total_used_samplers >= critical_gc_samplers;
|
||||
ticks_to_destroy = aggresive ? 160 : pressured ? 80 : 16;
|
||||
ticks_to_destroy = std::min(ticks_to_destroy, gc_tick);
|
||||
num_deletions = aggresive ? 40 : pressured ? 20 : 10;
|
||||
};
|
||||
const auto clean_up = [&](u64 hash) {
|
||||
if (num_deletions == 0) {
|
||||
return true;
|
||||
}
|
||||
--num_deletions;
|
||||
const size_t lru_id = samplers.at(hash).lru_id;
|
||||
samplers.erase(hash);
|
||||
sampler_lru_cache.Free(lru_id);
|
||||
return false;
|
||||
};
|
||||
|
||||
// Try to remove anything old enough and not high priority.
|
||||
configure(false);
|
||||
sampler_lru_cache.ForEachItemBelow(gc_tick - ticks_to_destroy, clean_up);
|
||||
|
||||
if (total_used_samplers >= critical_gc_samplers) {
|
||||
// If we are still over the critical limit, run an aggressive GC
|
||||
configure(true);
|
||||
sampler_lru_cache.ForEachItemBelow(gc_tick - ticks_to_destroy, clean_up);
|
||||
}
|
||||
}
|
||||
|
||||
void TextureCache::RunGarbageCollector() {
|
||||
SCOPE_EXIT {
|
||||
++gc_tick;
|
||||
};
|
||||
|
||||
GarbageCollectImages();
|
||||
GarbageCollectSamplers();
|
||||
}
|
||||
|
||||
void TextureCache::TouchImage(const Image& image) {
|
||||
lru_cache.Touch(image.lru_id, gc_tick);
|
||||
}
|
||||
|
||||
@@ -310,6 +310,9 @@ private:
|
||||
DeleteImage(image_id);
|
||||
}
|
||||
|
||||
void GarbageCollectImages();
|
||||
void GarbageCollectSamplers();
|
||||
|
||||
private:
|
||||
const Vulkan::Instance& instance;
|
||||
Vulkan::Scheduler& scheduler;
|
||||
@@ -327,11 +330,17 @@ private:
|
||||
u64 trigger_gc_memory = 0;
|
||||
u64 pressure_gc_memory = 0;
|
||||
u64 critical_gc_memory = 0;
|
||||
u64 total_used_samplers = 0;
|
||||
u64 trigger_gc_samplers = 0;
|
||||
u64 pressure_gc_samplers = 0;
|
||||
u64 critical_gc_samplers = 0;
|
||||
u64 gc_tick = 0;
|
||||
Common::LeastRecentlyUsedCache<ImageId, u64> lru_cache;
|
||||
Common::LeastRecentlyUsedCache<u64, u64> sampler_lru_cache;
|
||||
bool readback_linear_images;
|
||||
PageTable page_table;
|
||||
std::mutex mutex;
|
||||
std::mutex samplers_mutex;
|
||||
struct MetaDataInfo {
|
||||
enum class Type {
|
||||
CMask,
|
||||
|
||||
Reference in New Issue
Block a user