diff --git a/rpcs3/Emu/RSX/VK/VKResourceManager.cpp b/rpcs3/Emu/RSX/VK/VKResourceManager.cpp index 96e7a4698e..370f869e02 100644 --- a/rpcs3/Emu/RSX/VK/VKResourceManager.cpp +++ b/rpcs3/Emu/RSX/VK/VKResourceManager.cpp @@ -98,6 +98,14 @@ namespace vk g_last_completed_event = std::max(event_id, g_last_completed_event.load()); } + void print_debug_markers() + { + for (const auto marker : g_resource_manager.gather_debug_markers()) + { + marker->dump(); + } + } + static constexpr f32 size_in_GiB(u64 size) { return size / (1024.f * 1024.f * 1024.f); diff --git a/rpcs3/Emu/RSX/VK/VKResourceManager.h b/rpcs3/Emu/RSX/VK/VKResourceManager.h index 9c624fe2c3..ac0280ba0d 100644 --- a/rpcs3/Emu/RSX/VK/VKResourceManager.h +++ b/rpcs3/Emu/RSX/VK/VKResourceManager.h @@ -57,6 +57,7 @@ namespace vk u64 eid; const vk::render_device* m_device; std::vector m_disposables; + std::vector> m_debug_markers; eid_scope_t(u64 _eid): eid(_eid), m_device(g_render_device) @@ -72,11 +73,13 @@ namespace vk std::swap(eid, other.eid); std::swap(m_device, other.m_device); std::swap(m_disposables, other.m_disposables); + std::swap(m_debug_markers, other.m_debug_markers); } void discard() { m_disposables.clear(); + m_debug_markers.clear(); } }; @@ -187,6 +190,13 @@ namespace vk get_current_eid_scope().m_disposables.emplace_back(std::move(disposable)); } + inline void dispose(std::unique_ptr& object) + { + // Special case as we may need to read these out. + // FIXME: We can manage these markers better and remove this exception. + get_current_eid_scope().m_debug_markers.emplace_back(std::move(object)); + } + template inline void dispose(std::unique_ptr& object) { @@ -221,6 +231,19 @@ namespace vk } void trim(); + + std::vector gather_debug_markers() const + { + std::vector result; + for (const auto& scope : m_eid_map) + { + for (const auto& item : scope.m_debug_markers) + { + result.push_back(item.get()); + } + } + return result; + } }; struct vmm_allocation_t diff --git a/rpcs3/Emu/RSX/VK/vkutils/shared.cpp b/rpcs3/Emu/RSX/VK/vkutils/shared.cpp index e9580bd23f..aab9e789ff 100644 --- a/rpcs3/Emu/RSX/VK/vkutils/shared.cpp +++ b/rpcs3/Emu/RSX/VK/vkutils/shared.cpp @@ -7,6 +7,8 @@ namespace vk { + extern void print_debug_markers(); + void die_with_error(VkResult error_code, std::string message, const char* file, const char* func, @@ -103,6 +105,8 @@ namespace vk { default: case 0: + print_debug_markers(); + if (!message.empty()) message += "\n\n"; fmt::throw_exception("%sAssertion Failed! Vulkan API call failed with unrecoverable error: %s%s", message, error_message, src_loc{line, col, file, func}); case 1: diff --git a/rpcs3/Emu/RSX/VK/vkutils/sync.cpp b/rpcs3/Emu/RSX/VK/vkutils/sync.cpp index 420178bcb2..f638b3e68b 100644 --- a/rpcs3/Emu/RSX/VK/vkutils/sync.cpp +++ b/rpcs3/Emu/RSX/VK/vkutils/sync.cpp @@ -10,6 +10,9 @@ #include "util/sysinfo.hpp" #include "util/asm.hpp" +// FIXME: namespace pollution +#include "../VKResourceManager.h" + namespace vk { fence::fence(VkDevice dev) @@ -169,6 +172,135 @@ namespace vk } } + device_marker_pool::device_marker_pool(const vk::render_device& dev, u32 count) + : pdev(&dev), m_count(count) + {} + + std::tuple device_marker_pool::allocate() + { + if (!m_buffer || m_offset >= m_count) + { + create_impl(); + } + + const auto out_offset = m_offset; + m_offset ++; + return { m_buffer->value, out_offset * 4, m_mapped + out_offset }; + } + + void device_marker_pool::create_impl() + { + if (m_buffer) + { + m_buffer->unmap(); + vk::get_resource_manager()->dispose(m_buffer); + } + + m_buffer = std::make_unique + ( + *pdev, + m_count * 4, + pdev->get_memory_mapping().host_visible_coherent, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, + VK_BUFFER_USAGE_TRANSFER_DST_BIT, + 0, + VMM_ALLOCATION_POOL_SYSTEM + ); + + m_mapped = reinterpret_cast(m_buffer->map(0, VK_WHOLE_SIZE)); + m_offset = 0; + } + + device_debug_marker::device_debug_marker(device_marker_pool& pool, std::string message) + : m_device(*pool.pdev), m_message(std::move(message)) + { + std::tie(m_buffer, m_buffer_offset, m_value) = pool.allocate(); + *m_value = 0xCAFEBABE; + } + + device_debug_marker::~device_debug_marker() + { + if (!m_printed) + { + dump(); + } + + m_value = nullptr; + } + + void device_debug_marker::signal(const command_buffer& cmd, VkPipelineStageFlags stages, VkAccessFlags access) + { + insert_global_memory_barrier(cmd, stages, VK_PIPELINE_STAGE_TRANSFER_BIT, access, VK_ACCESS_TRANSFER_WRITE_BIT); + vkCmdFillBuffer(cmd, m_buffer, m_buffer_offset, 4, 0xDEADBEEF); + } + + void device_debug_marker::dump() + { + if (*m_value == 0xCAFEBABE) + { + rsx_log.error("DEBUG MARKER NOT REACHED: %s", m_message); + } + + m_printed = true; + } + + void device_debug_marker::dump() const + { + if (*m_value == 0xCAFEBABE) + { + rsx_log.error("DEBUG MARKER NOT REACHED: %s", m_message); + } + else + { + rsx_log.error("DEBUG MARKER: %s", m_message); + } + } + + // FIXME + static std::unique_ptr g_device_marker_pool; + + device_marker_pool& get_shared_marker_pool(const vk::render_device& dev) + { + if (!g_device_marker_pool) + { + g_device_marker_pool = std::make_unique(dev, 65536); + } + return *g_device_marker_pool; + } + + void device_debug_marker::insert( + const vk::render_device& dev, + const vk::command_buffer& cmd, + std::string message, + VkPipelineStageFlags stages, + VkAccessFlags access) + { + auto result = std::make_unique(get_shared_marker_pool(dev), message); + result->signal(cmd, stages, access); + vk::get_resource_manager()->dispose(result); + } + + debug_marker_scope::debug_marker_scope(const vk::command_buffer& cmd, const std::string& message) + : dev(&cmd.get_command_pool().get_owner()), cb(&cmd), message(message) + { + vk::device_debug_marker::insert( + *dev, + *cb, + fmt::format("0x%x: Enter %s", rsx::get_shared_tag(), message) + ); + } + + debug_marker_scope::~debug_marker_scope() + { + ensure(cb && cb->is_recording()); + + vk::device_debug_marker::insert( + *dev, + *cb, + fmt::format("0x%x: Exit %s", rsx::get_shared_tag(), message) + ); + } + VkResult wait_for_fence(fence* pFence, u64 timeout) { pFence->wait_flush(); diff --git a/rpcs3/Emu/RSX/VK/vkutils/sync.h b/rpcs3/Emu/RSX/VK/vkutils/sync.h index 489d0189dc..1680cda8ad 100644 --- a/rpcs3/Emu/RSX/VK/vkutils/sync.h +++ b/rpcs3/Emu/RSX/VK/vkutils/sync.h @@ -87,6 +87,60 @@ namespace vk operator VkSemaphore() const; }; + class device_marker_pool + { + std::unique_ptr m_buffer; + volatile u32* m_mapped = nullptr; + u64 m_offset = 0; + u32 m_count = 0; + + void create_impl(); + + public: + device_marker_pool(const vk::render_device& dev, u32 count); + std::tuple allocate(); + + const vk::render_device* pdev = nullptr; + }; + + class device_debug_marker + { + std::string m_message; + bool m_printed = false; + + VkDevice m_device = VK_NULL_HANDLE; + VkBuffer m_buffer = VK_NULL_HANDLE; + u64 m_buffer_offset = 0; + volatile u32* m_value = nullptr; + + public: + device_debug_marker(device_marker_pool& pool, std::string message); + ~device_debug_marker(); + device_debug_marker(const event&) = delete; + + void signal(const command_buffer& cmd, VkPipelineStageFlags stages, VkAccessFlags access); + void dump(); + void dump() const; + + static void insert( + const vk::render_device& dev, + const vk::command_buffer& cmd, + std::string message, + VkPipelineStageFlags stages = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, + VkAccessFlags access = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT); + }; + + class debug_marker_scope + { + const vk::render_device* dev; + const vk::command_buffer* cb; + std::string message; + + public: + debug_marker_scope(const vk::command_buffer& cmd, const std::string& text); + ~debug_marker_scope(); + }; + VkResult wait_for_fence(fence* pFence, u64 timeout = 0ull); VkResult wait_for_event(event* pEvent, u64 timeout = 0ull); }