diff --git a/rpcs3/Emu/RSX/VK/VKDraw.cpp b/rpcs3/Emu/RSX/VK/VKDraw.cpp index c3191a2b90..c0869ddce6 100644 --- a/rpcs3/Emu/RSX/VK/VKDraw.cpp +++ b/rpcs3/Emu/RSX/VK/VKDraw.cpp @@ -285,8 +285,14 @@ void VKGSRender::load_texture_env() 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, - min_filter.filter, mag_filter, min_filter.mipmap_mode, border_color, compare_enabled, depth_compare_mode); + fs_sampler_handles[i] = vk::get_resource_manager()->get_sampler( + *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 @@ -338,8 +344,9 @@ void VKGSRender::load_texture_env() if (replace) { - vs_sampler_handles[i] = vk::get_resource_manager()->find_sampler( + vs_sampler_handles[i] = vk::get_resource_manager()->get_sampler( *m_device, + vs_sampler_handles[i], VK_SAMPLER_ADDRESS_MODE_REPEAT, VK_SAMPLER_ADDRESS_MODE_REPEAT, VK_SAMPLER_ADDRESS_MODE_REPEAT, unnormalized_coords, 0.f, 1.f, min_lod, max_lod, diff --git a/rpcs3/Emu/RSX/VK/VKPresent.cpp b/rpcs3/Emu/RSX/VK/VKPresent.cpp index 85f482896e..128133e936 100644 --- a/rpcs3/Emu/RSX/VK/VKPresent.cpp +++ b/rpcs3/Emu/RSX/VK/VKPresent.cpp @@ -223,6 +223,8 @@ void VKGSRender::frame_context_cleanup(vk::frame_context_t *ctx, bool free_resou m_overlay_manager->dispose(uids_to_dispose); } + vk::get_resource_manager()->trim(); + vk::reset_global_resources(); ctx->buffer_views_to_clean.clear(); diff --git a/rpcs3/Emu/RSX/VK/VKResourceManager.cpp b/rpcs3/Emu/RSX/VK/VKResourceManager.cpp index 58c9198725..a75ed8657d 100644 --- a/rpcs3/Emu/RSX/VK/VKResourceManager.cpp +++ b/rpcs3/Emu/RSX/VK/VKResourceManager.cpp @@ -31,6 +31,34 @@ namespace vk 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() { return g_event_ctr++; @@ -212,4 +240,16 @@ namespace vk 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]--; + } } diff --git a/rpcs3/Emu/RSX/VK/VKResourceManager.h b/rpcs3/Emu/RSX/VK/VKResourceManager.h index 9c194ce4d8..8920fb4f94 100644 --- a/rpcs3/Emu/RSX/VK/VKResourceManager.h +++ b/rpcs3/Emu/RSX/VK/VKResourceManager.h @@ -23,6 +23,7 @@ namespace vk std::vector> m_disposed_images; std::vector> m_disposed_events; std::vector> m_disposed_query_pools; + std::vector> m_disposed_samplers; eid_scope_t(u64 _eid): eid(_eid), m_device(g_render_device) @@ -40,13 +41,19 @@ namespace vk m_disposed_image_views.clear(); m_disposed_images.clear(); m_disposed_query_pools.clear(); + m_disposed_samplers.clear(); } }; class resource_manager { private: - std::unordered_map> m_sampler_pool; + struct cached_sampler_object_t : public vk::sampler, public rsx::ref_counted + { + using vk::sampler::sampler; + }; + + std::unordered_map> m_sampler_pool; std::deque m_eid_map; eid_scope_t& get_current_eid_scope() @@ -98,7 +105,8 @@ namespace vk 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, 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) @@ -115,20 +123,30 @@ namespace vk key |= u64(encode_fxp(mipLodBias)) << 44; // 13 bits key |= u64(max_anisotropy) << 57; // 4 bits + if (previous) + { + auto as_cached_object = static_cast(previous); + ensure(as_cached_object->has_refs()); + as_cached_object->release(); + } + if (const auto found = m_sampler_pool.find(key); found != m_sampler_pool.end()) { + found->second->add_ref(); return found->second.get(); } - auto result = std::make_unique( + auto result = std::make_unique( dev, clamp_u, clamp_v, clamp_w, unnormalized_coordinates, mipLodBias, max_anisotropy, min_lod, max_lod, min_filter, mag_filter, mipmap_mode, border_color, depth_compare, depth_compare_mode); 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& buf) @@ -162,6 +180,11 @@ namespace vk get_current_eid_scope().m_disposed_query_pools.emplace_back(std::move(pool)); } + void dispose(std::unique_ptr& sampler) + { + get_current_eid_scope().m_disposed_samplers.emplace_back(std::move(sampler)); + } + void eid_completed(u64 eid) { while (!m_eid_map.empty()) @@ -177,6 +200,8 @@ namespace vk } } } + + void trim(); }; struct vmm_allocation_t diff --git a/rpcs3/Emu/RSX/VK/vkutils/memory.h b/rpcs3/Emu/RSX/VK/vkutils/memory.h index 427763180f..10c1a3c6f3 100644 --- a/rpcs3/Emu/RSX/VK/vkutils/memory.h +++ b/rpcs3/Emu/RSX/VK/vkutils/memory.h @@ -18,6 +18,7 @@ namespace vk VMM_ALLOCATION_POOL_TEXTURE_CACHE, VMM_ALLOCATION_POOL_SWAPCHAIN, VMM_ALLOCATION_POOL_SCRATCH, + VMM_ALLOCATION_POOL_SAMPLER, }; } @@ -173,6 +174,7 @@ namespace vk 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_freed(void* handle); void vmm_reset(); @@ -182,5 +184,9 @@ namespace vk bool vmm_handle_memory_pressure(rsx::problem_severity 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(); } diff --git a/rpcs3/Emu/RSX/VK/vkutils/sampler.cpp b/rpcs3/Emu/RSX/VK/vkutils/sampler.cpp index 9a7f6ddb93..9ffce40e00 100644 --- a/rpcs3/Emu/RSX/VK/vkutils/sampler.cpp +++ b/rpcs3/Emu/RSX/VK/vkutils/sampler.cpp @@ -1,3 +1,4 @@ +#include "memory.h" #include "sampler.h" #include "../../rsx_utils.h" @@ -27,11 +28,13 @@ namespace vk info.borderColor = border_color; CHECK_RESULT(vkCreateSampler(m_device, &info, nullptr, &value)); + vmm_notify_object_allocated(VMM_ALLOCATION_POOL_SAMPLER); } sampler::~sampler() { 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,