vk: Keep the total number of allocated samplers under control

This commit is contained in:
kd-11 2022-01-19 00:47:50 +03:00 committed by kd-11
commit 2331dc3256
6 changed files with 90 additions and 7 deletions

View file

@ -285,8 +285,14 @@ void VKGSRender::load_texture_env()
if (replace) if (replace)
{ {
fs_sampler_handles[i] = vk::get_resource_manager()->find_sampler(*m_device, wrap_s, wrap_t, wrap_r, false, lod_bias, af_level, min_lod, max_lod, fs_sampler_handles[i] = vk::get_resource_manager()->get_sampler(
min_filter.filter, mag_filter, min_filter.mipmap_mode, border_color, compare_enabled, depth_compare_mode); *m_device,
fs_sampler_handles[i],
wrap_s, wrap_t, wrap_r,
false,
lod_bias, af_level, min_lod, max_lod,
min_filter.filter, mag_filter, min_filter.mipmap_mode,
border_color, compare_enabled, depth_compare_mode);
} }
} }
else else
@ -338,8 +344,9 @@ void VKGSRender::load_texture_env()
if (replace) if (replace)
{ {
vs_sampler_handles[i] = vk::get_resource_manager()->find_sampler( vs_sampler_handles[i] = vk::get_resource_manager()->get_sampler(
*m_device, *m_device,
vs_sampler_handles[i],
VK_SAMPLER_ADDRESS_MODE_REPEAT, VK_SAMPLER_ADDRESS_MODE_REPEAT, VK_SAMPLER_ADDRESS_MODE_REPEAT, VK_SAMPLER_ADDRESS_MODE_REPEAT, VK_SAMPLER_ADDRESS_MODE_REPEAT, VK_SAMPLER_ADDRESS_MODE_REPEAT,
unnormalized_coords, unnormalized_coords,
0.f, 1.f, min_lod, max_lod, 0.f, 1.f, min_lod, max_lod,

View file

@ -223,6 +223,8 @@ void VKGSRender::frame_context_cleanup(vk::frame_context_t *ctx, bool free_resou
m_overlay_manager->dispose(uids_to_dispose); m_overlay_manager->dispose(uids_to_dispose);
} }
vk::get_resource_manager()->trim();
vk::reset_global_resources(); vk::reset_global_resources();
ctx->buffer_views_to_clean.clear(); ctx->buffer_views_to_clean.clear();

View file

@ -31,6 +31,34 @@ namespace vk
return &g_resource_manager; return &g_resource_manager;
} }
void resource_manager::trim()
{
// For any managed resources, try to keep the number of unused/idle resources as low as possible.
// Improves search times as well as keeping us below the hardware limit.
const auto limits = get_current_renderer()->gpu().get_limits();
const auto allocated_sampler_count = vmm_get_application_pool_usage(VMM_ALLOCATION_POOL_SAMPLER);
const auto max_allowed_samplers = std::min((limits.maxSamplerAllocationCount * 3u) / 4u, 2048u);
if (allocated_sampler_count > max_allowed_samplers)
{
ensure(max_allowed_samplers);
rsx_log.warning("Trimming allocated samplers. Allocated = %u, Max = %u", allocated_sampler_count, limits.maxSamplerAllocationCount);
auto& disposed_samplers_pool = get_current_eid_scope().m_disposed_samplers;
for (auto It = m_sampler_pool.begin(); It != m_sampler_pool.end();)
{
if (!It->second->has_refs())
{
disposed_samplers_pool.emplace_back(std::move(It->second));
It = m_sampler_pool.erase(It);
continue;
}
++It;
}
}
}
u64 get_event_id() u64 get_event_id()
{ {
return g_event_ctr++; return g_event_ctr++;
@ -212,4 +240,16 @@ namespace vk
vmm_handle_memory_pressure(load_severity); vmm_handle_memory_pressure(load_severity);
} }
} }
void vmm_notify_object_allocated(vmm_allocation_pool pool)
{
ensure(pool >= VMM_ALLOCATION_POOL_SAMPLER);
g_vmm_stats.pool_usage[pool]++;
}
void vmm_notify_object_freed(vmm_allocation_pool pool)
{
ensure(pool >= VMM_ALLOCATION_POOL_SAMPLER);
g_vmm_stats.pool_usage[pool]--;
}
} }

View file

@ -23,6 +23,7 @@ namespace vk
std::vector<std::unique_ptr<vk::image>> m_disposed_images; std::vector<std::unique_ptr<vk::image>> m_disposed_images;
std::vector<std::unique_ptr<vk::event>> m_disposed_events; std::vector<std::unique_ptr<vk::event>> m_disposed_events;
std::vector<std::unique_ptr<vk::query_pool>> m_disposed_query_pools; std::vector<std::unique_ptr<vk::query_pool>> m_disposed_query_pools;
std::vector<std::unique_ptr<vk::sampler>> m_disposed_samplers;
eid_scope_t(u64 _eid): eid_scope_t(u64 _eid):
eid(_eid), m_device(g_render_device) eid(_eid), m_device(g_render_device)
@ -40,13 +41,19 @@ namespace vk
m_disposed_image_views.clear(); m_disposed_image_views.clear();
m_disposed_images.clear(); m_disposed_images.clear();
m_disposed_query_pools.clear(); m_disposed_query_pools.clear();
m_disposed_samplers.clear();
} }
}; };
class resource_manager class resource_manager
{ {
private: private:
std::unordered_map<u64, std::unique_ptr<vk::sampler>> m_sampler_pool; struct cached_sampler_object_t : public vk::sampler, public rsx::ref_counted
{
using vk::sampler::sampler;
};
std::unordered_map<u64, std::unique_ptr<cached_sampler_object_t>> m_sampler_pool;
std::deque<eid_scope_t> m_eid_map; std::deque<eid_scope_t> m_eid_map;
eid_scope_t& get_current_eid_scope() eid_scope_t& get_current_eid_scope()
@ -98,7 +105,8 @@ namespace vk
m_sampler_pool.clear(); m_sampler_pool.clear();
} }
vk::sampler* find_sampler(const vk::render_device& dev, VkSamplerAddressMode clamp_u, VkSamplerAddressMode clamp_v, VkSamplerAddressMode clamp_w, vk::sampler* get_sampler(const vk::render_device& dev, vk::sampler* previous,
VkSamplerAddressMode clamp_u, VkSamplerAddressMode clamp_v, VkSamplerAddressMode clamp_w,
VkBool32 unnormalized_coordinates, float mipLodBias, float max_anisotropy, float min_lod, float max_lod, VkBool32 unnormalized_coordinates, float mipLodBias, float max_anisotropy, float min_lod, float max_lod,
VkFilter min_filter, VkFilter mag_filter, VkSamplerMipmapMode mipmap_mode, VkBorderColor border_color, VkFilter min_filter, VkFilter mag_filter, VkSamplerMipmapMode mipmap_mode, VkBorderColor border_color,
VkBool32 depth_compare = VK_FALSE, VkCompareOp depth_compare_mode = VK_COMPARE_OP_NEVER) VkBool32 depth_compare = VK_FALSE, VkCompareOp depth_compare_mode = VK_COMPARE_OP_NEVER)
@ -115,20 +123,30 @@ namespace vk
key |= u64(encode_fxp<true>(mipLodBias)) << 44; // 13 bits key |= u64(encode_fxp<true>(mipLodBias)) << 44; // 13 bits
key |= u64(max_anisotropy) << 57; // 4 bits key |= u64(max_anisotropy) << 57; // 4 bits
if (previous)
{
auto as_cached_object = static_cast<cached_sampler_object_t*>(previous);
ensure(as_cached_object->has_refs());
as_cached_object->release();
}
if (const auto found = m_sampler_pool.find(key); if (const auto found = m_sampler_pool.find(key);
found != m_sampler_pool.end()) found != m_sampler_pool.end())
{ {
found->second->add_ref();
return found->second.get(); return found->second.get();
} }
auto result = std::make_unique<vk::sampler>( auto result = std::make_unique<cached_sampler_object_t>(
dev, clamp_u, clamp_v, clamp_w, unnormalized_coordinates, dev, clamp_u, clamp_v, clamp_w, unnormalized_coordinates,
mipLodBias, max_anisotropy, min_lod, max_lod, mipLodBias, max_anisotropy, min_lod, max_lod,
min_filter, mag_filter, mipmap_mode, border_color, min_filter, mag_filter, mipmap_mode, border_color,
depth_compare, depth_compare_mode); depth_compare, depth_compare_mode);
auto It = m_sampler_pool.emplace(key, std::move(result)); auto It = m_sampler_pool.emplace(key, std::move(result));
return It.first->second.get(); auto ret = It.first->second.get();
ret->add_ref();
return ret;
} }
void dispose(std::unique_ptr<vk::buffer>& buf) void dispose(std::unique_ptr<vk::buffer>& buf)
@ -162,6 +180,11 @@ namespace vk
get_current_eid_scope().m_disposed_query_pools.emplace_back(std::move(pool)); get_current_eid_scope().m_disposed_query_pools.emplace_back(std::move(pool));
} }
void dispose(std::unique_ptr<vk::sampler>& sampler)
{
get_current_eid_scope().m_disposed_samplers.emplace_back(std::move(sampler));
}
void eid_completed(u64 eid) void eid_completed(u64 eid)
{ {
while (!m_eid_map.empty()) while (!m_eid_map.empty())
@ -177,6 +200,8 @@ namespace vk
} }
} }
} }
void trim();
}; };
struct vmm_allocation_t struct vmm_allocation_t

View file

@ -18,6 +18,7 @@ namespace vk
VMM_ALLOCATION_POOL_TEXTURE_CACHE, VMM_ALLOCATION_POOL_TEXTURE_CACHE,
VMM_ALLOCATION_POOL_SWAPCHAIN, VMM_ALLOCATION_POOL_SWAPCHAIN,
VMM_ALLOCATION_POOL_SCRATCH, VMM_ALLOCATION_POOL_SCRATCH,
VMM_ALLOCATION_POOL_SAMPLER,
}; };
} }
@ -173,6 +174,7 @@ namespace vk
void* m_host_pointer; void* m_host_pointer;
}; };
// Tracking for memory usage. Constrained largely by amount of VRAM + shared video memory.
void vmm_notify_memory_allocated(void* handle, u32 memory_type, u64 memory_size, vmm_allocation_pool pool); void vmm_notify_memory_allocated(void* handle, u32 memory_type, u64 memory_size, vmm_allocation_pool pool);
void vmm_notify_memory_freed(void* handle); void vmm_notify_memory_freed(void* handle);
void vmm_reset(); void vmm_reset();
@ -182,5 +184,9 @@ namespace vk
bool vmm_handle_memory_pressure(rsx::problem_severity severity); bool vmm_handle_memory_pressure(rsx::problem_severity severity);
rsx::problem_severity vmm_determine_memory_load_severity(); rsx::problem_severity vmm_determine_memory_load_severity();
// Tracking for host memory objects. Allocated count is more important than actual memory amount.
void vmm_notify_object_allocated(vmm_allocation_pool pool);
void vmm_notify_object_freed(vmm_allocation_pool pool);
mem_allocator_base* get_current_mem_allocator(); mem_allocator_base* get_current_mem_allocator();
} }

View file

@ -1,3 +1,4 @@
#include "memory.h"
#include "sampler.h" #include "sampler.h"
#include "../../rsx_utils.h" #include "../../rsx_utils.h"
@ -27,11 +28,13 @@ namespace vk
info.borderColor = border_color; info.borderColor = border_color;
CHECK_RESULT(vkCreateSampler(m_device, &info, nullptr, &value)); CHECK_RESULT(vkCreateSampler(m_device, &info, nullptr, &value));
vmm_notify_object_allocated(VMM_ALLOCATION_POOL_SAMPLER);
} }
sampler::~sampler() sampler::~sampler()
{ {
vkDestroySampler(m_device, value, nullptr); vkDestroySampler(m_device, value, nullptr);
vmm_notify_object_freed(VMM_ALLOCATION_POOL_SAMPLER);
} }
bool sampler::matches(VkSamplerAddressMode clamp_u, VkSamplerAddressMode clamp_v, VkSamplerAddressMode clamp_w, bool sampler::matches(VkSamplerAddressMode clamp_u, VkSamplerAddressMode clamp_v, VkSamplerAddressMode clamp_w,