diff --git a/rpcs3/Emu/RSX/VK/VKGSRender.cpp b/rpcs3/Emu/RSX/VK/VKGSRender.cpp index 128eff295c..dbce568054 100644 --- a/rpcs3/Emu/RSX/VK/VKGSRender.cpp +++ b/rpcs3/Emu/RSX/VK/VKGSRender.cpp @@ -655,9 +655,6 @@ VKGSRender::~VKGSRender() // Upscaler (references some global resources) m_upscaler.reset(); - // Global resources - vk::destroy_global_resources(); - // Heaps m_attrib_ring_info.destroy(); m_fragment_env_ring_info.destroy(); @@ -722,6 +719,9 @@ VKGSRender::~VKGSRender() m_secondary_command_buffer.destroy(); m_secondary_command_buffer_pool.destroy(); + // Global resources + vk::destroy_global_resources(); + // Device handles/contexts m_swapchain->destroy(); m_instance.destroy(); diff --git a/rpcs3/Emu/RSX/VK/VKHelpers.cpp b/rpcs3/Emu/RSX/VK/VKHelpers.cpp index 69a91264d7..5d9bf1c67d 100644 --- a/rpcs3/Emu/RSX/VK/VKHelpers.cpp +++ b/rpcs3/Emu/RSX/VK/VKHelpers.cpp @@ -67,7 +67,6 @@ namespace vk vk::clear_framebuffer_cache(); vk::clear_resolve_helpers(); vk::clear_dma_resources(); - vk::vmm_reset(); vk::clear_scratch_resources(); vk::get_upload_heap()->destroy(); @@ -82,6 +81,9 @@ namespace vk // This must be the last item destroyed vk::get_resource_manager()->destroy(); + + // Statistics counter reset. Also verifies that everything was deleted. + vk::vmm_reset(); } const vk::render_device *get_current_renderer() diff --git a/rpcs3/Emu/RSX/VK/VKResourceManager.cpp b/rpcs3/Emu/RSX/VK/VKResourceManager.cpp index a75ed8657d..96e7a4698e 100644 --- a/rpcs3/Emu/RSX/VK/VKResourceManager.cpp +++ b/rpcs3/Emu/RSX/VK/VKResourceManager.cpp @@ -13,6 +13,16 @@ namespace vk void clear() { + if (!allocations.empty()) + { + rsx_log.error("Leaking memory allocations!"); + for (auto& leak : allocations) + { + rsx_log.error("Memory handle 0x%llx (%llu bytes) allocated from pool %d was not freed.", + leak.first, leak.second.size, static_cast(leak.second.pool)); + } + } + allocations.clear(); memory_usage.clear(); pool_usage.clear(); @@ -44,12 +54,11 @@ namespace vk 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)); + dispose(It->second); It = m_sampler_pool.erase(It); continue; } diff --git a/rpcs3/Emu/RSX/VK/VKResourceManager.h b/rpcs3/Emu/RSX/VK/VKResourceManager.h index a54b90ed23..4538ad63bc 100644 --- a/rpcs3/Emu/RSX/VK/VKResourceManager.h +++ b/rpcs3/Emu/RSX/VK/VKResourceManager.h @@ -3,6 +3,8 @@ #include "vkutils/query_pool.hpp" #include "vkutils/sampler.h" +#include "Utilities/mutex.h" + #include #include #include @@ -14,22 +16,47 @@ namespace vk u64 last_completed_event_id(); void on_event_completed(u64 event_id, bool flush = false); - struct disposable_t + class disposable_t { - virtual void dispose() = 0; + void* ptr; + std::function deleter; + + disposable_t(void* ptr_, std::function deleter_) : + ptr(ptr_), deleter(deleter_) {} + public: + + disposable_t() = delete; + disposable_t(const disposable_t&) = delete; + + disposable_t(disposable_t&& other): + ptr(std::exchange(other.ptr, nullptr)), + deleter(other.deleter) + {} + + ~disposable_t() + { + if (ptr) + { + deleter(ptr); + ptr = nullptr; + } + } + + template + static disposable_t make(T* raw) + { + return disposable_t(raw, [](void *raw) + { + delete static_cast(raw); + }); + } }; struct eid_scope_t { u64 eid; const vk::render_device* m_device; - std::vector> m_disposed_buffers; - std::vector> m_disposed_image_views; - std::vector> m_disposed_images; - std::vector> m_disposed_events; - std::vector> m_disposed_query_pools; - std::vector> m_disposed_samplers; - std::vector> m_disposables; + std::vector m_disposables; eid_scope_t(u64 _eid): eid(_eid), m_device(g_render_device) @@ -40,19 +67,15 @@ namespace vk discard(); } + void swap(eid_scope_t& other) + { + std::swap(eid, other.eid); + std::swap(m_device, other.m_device); + std::swap(m_disposables, other.m_disposables); + } + void discard() { - m_disposed_buffers.clear(); - m_disposed_events.clear(); - m_disposed_image_views.clear(); - m_disposed_images.clear(); - m_disposed_query_pools.clear(); - m_disposed_samplers.clear(); - - for (auto& disposable : m_disposables) - { - disposable->dispose(); - } m_disposables.clear(); } }; @@ -67,20 +90,18 @@ namespace vk std::unordered_map> m_sampler_pool; std::deque m_eid_map; + shared_mutex m_eid_map_lock; - eid_scope_t& get_current_eid_scope() + inline eid_scope_t& get_current_eid_scope() { const auto eid = current_event_id(); - if (!m_eid_map.empty()) { - // Elements are insterted in order, so just check the last entry for a match - if (auto &old = m_eid_map.back(); old.eid == eid) + std::lock_guard lock(m_eid_map_lock); + if (m_eid_map.empty() || m_eid_map.back().eid != eid) { - return old; + m_eid_map.emplace_back(eid); } } - - m_eid_map.emplace_back(eid); return m_eid_map.back(); } @@ -161,47 +182,18 @@ namespace vk return ret; } - void dispose(std::unique_ptr& buf) - { - get_current_eid_scope().m_disposed_buffers.emplace_back(std::move(buf)); - } - - void dispose(std::unique_ptr& view) - { - get_current_eid_scope().m_disposed_image_views.emplace_back(std::move(view)); - } - - void dispose(std::unique_ptr& img) - { - get_current_eid_scope().m_disposed_images.emplace_back(std::move(img)); - } - - void dispose(std::unique_ptr& img) - { - get_current_eid_scope().m_disposed_images.emplace_back(std::move(img)); - } - - void dispose(std::unique_ptr& event) - { - get_current_eid_scope().m_disposed_events.emplace_back(std::move(event)); - event = VK_NULL_HANDLE; - } - - void dispose(std::unique_ptr& pool) - { - 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 dispose(std::unique_ptr& disposable) + inline void dispose(vk::disposable_t& disposable) { get_current_eid_scope().m_disposables.emplace_back(std::move(disposable)); } + template + inline void dispose(std::unique_ptr& object) + { + auto ptr = vk::disposable_t::make(object.release()); + dispose(ptr); + } + void eid_completed(u64 eid) { while (!m_eid_map.empty()) @@ -213,7 +205,12 @@ namespace vk } else { - m_eid_map.pop_front(); + eid_scope_t tmp(0); + { + std::lock_guard lock(m_eid_map_lock); + m_eid_map.front().swap(tmp); + m_eid_map.pop_front(); + } } } } diff --git a/rpcs3/Emu/RSX/VK/VKTextureCache.cpp b/rpcs3/Emu/RSX/VK/VKTextureCache.cpp index 6b3009a78b..8b82ea37d4 100644 --- a/rpcs3/Emu/RSX/VK/VKTextureCache.cpp +++ b/rpcs3/Emu/RSX/VK/VKTextureCache.cpp @@ -26,7 +26,7 @@ namespace vk this->data = std::move(previous); } - void texture_cache::cached_image_reference_t::dispose() + texture_cache::cached_image_reference_t::~cached_image_reference_t() { // Erase layout information to force TOP_OF_PIPE transition next time. data->current_layout = VK_IMAGE_LAYOUT_UNDEFINED; @@ -208,7 +208,7 @@ namespace vk { if (tex.is_managed() && tex.exists()) { - auto disposable = std::unique_ptr(new cached_image_reference_t(this, tex.get_texture())); + auto disposable = vk::disposable_t::make(new cached_image_reference_t(this, tex.get_texture())); vk::get_resource_manager()->dispose(disposable); } } @@ -745,7 +745,7 @@ namespace vk ensure(resource); auto image = std::unique_ptr(resource); - auto disposable = std::unique_ptr(new cached_image_reference_t(this, image)); + auto disposable = vk::disposable_t::make(new cached_image_reference_t(this, image)); vk::get_resource_manager()->dispose(disposable); } @@ -1288,7 +1288,7 @@ namespace vk auto result = image.get(); const auto resource_memory = image->memory->size(); - auto disposable = std::unique_ptr(new cached_image_reference_t(this, image)); + auto disposable = vk::disposable_t::make(new cached_image_reference_t(this, image)); vk::get_resource_manager()->dispose(disposable); return result; diff --git a/rpcs3/Emu/RSX/VK/VKTextureCache.h b/rpcs3/Emu/RSX/VK/VKTextureCache.h index 051d6e13dc..50420ca34d 100644 --- a/rpcs3/Emu/RSX/VK/VKTextureCache.h +++ b/rpcs3/Emu/RSX/VK/VKTextureCache.h @@ -356,13 +356,13 @@ namespace vk using baseclass = rsx::texture_cache; friend baseclass; - struct cached_image_reference_t : vk::disposable_t + struct cached_image_reference_t { std::unique_ptr data; texture_cache* parent; cached_image_reference_t(texture_cache* parent, std::unique_ptr& previous); - void dispose() override; + ~cached_image_reference_t(); }; struct cached_image_t