diff --git a/rpcs3/Emu/RSX/VK/VKHelpers.cpp b/rpcs3/Emu/RSX/VK/VKHelpers.cpp index 4170b41a29..a6bc046b38 100644 --- a/rpcs3/Emu/RSX/VK/VKHelpers.cpp +++ b/rpcs3/Emu/RSX/VK/VKHelpers.cpp @@ -902,12 +902,12 @@ namespace vk } } - VkResult wait_for_event(VkEvent event, u64 timeout) + VkResult wait_for_event(event* pEvent, u64 timeout) { u64 t = 0; while (true) { - switch (const auto status = vkGetEventStatus(*g_current_renderer, event)) + switch (const auto status = pEvent->status()) { case VK_EVENT_SET: return VK_SUCCESS; diff --git a/rpcs3/Emu/RSX/VK/VKHelpers.h b/rpcs3/Emu/RSX/VK/VKHelpers.h index ac9608bc44..5acfd8eee1 100644 --- a/rpcs3/Emu/RSX/VK/VKHelpers.h +++ b/rpcs3/Emu/RSX/VK/VKHelpers.h @@ -115,6 +115,7 @@ namespace vk struct gpu_formats_support; struct fence; struct pipeline_binding_table; + class event; const vk::context *get_current_thread_ctx(); void set_current_thread_ctx(const vk::context &ctx); @@ -227,7 +228,7 @@ namespace vk // Fence reset with driver workarounds in place void reset_fence(fence* pFence); VkResult wait_for_fence(fence* pFence, u64 timeout = 0ull); - VkResult wait_for_event(VkEvent pEvent, u64 timeout = 0ull); + VkResult wait_for_event(event* pEvent, u64 timeout = 0ull); // Handle unexpected submit with dangling occlusion query // TODO: Move queries out of the renderer! @@ -1736,6 +1737,86 @@ private: VkDevice m_device; }; + class event + { + VkDevice m_device = VK_NULL_HANDLE; + VkEvent m_vk_event = VK_NULL_HANDLE; + + std::unique_ptr m_buffer; + volatile uint32_t* m_value = nullptr; + + public: + event(const render_device& dev) + { + m_device = dev; + if (dev.gpu().get_driver_vendor() != driver_vendor::AMD) + { + VkEventCreateInfo info + { + .sType = VK_STRUCTURE_TYPE_EVENT_CREATE_INFO, + .pNext = nullptr, + .flags = 0 + }; + vkCreateEvent(dev, &info, nullptr, &m_vk_event); + } + else + { + // Work around AMD's broken event signals + m_buffer = std::make_unique + ( + dev, + 4, + dev.get_memory_mapping().host_visible_coherent, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, + VK_BUFFER_USAGE_TRANSFER_DST_BIT, + 0 + ); + + m_value = reinterpret_cast(m_buffer->map(0, 4)); + *m_value = 0xCAFEBABE; + } + } + + ~event() + { + if (m_vk_event) [[likely]] + { + vkDestroyEvent(m_device, m_vk_event, nullptr); + } + else + { + m_buffer->unmap(); + m_buffer.reset(); + m_value = nullptr; + } + } + + void signal(const command_buffer& cmd, VkPipelineStageFlags stages) + { + if (m_vk_event) [[likely]] + { + vkCmdSetEvent(cmd, m_vk_event, stages); + } + else + { + insert_execution_barrier(cmd, stages, VK_PIPELINE_STAGE_TRANSFER_BIT); + vkCmdFillBuffer(cmd, m_buffer->value, 0, 4, 0xDEADBEEF); + } + } + + VkResult status() const + { + if (m_vk_event) [[likely]] + { + return vkGetEventStatus(m_device, m_vk_event); + } + else + { + return (*m_value == 0xDEADBEEF)? VK_EVENT_SET : VK_EVENT_RESET; + } + } + }; + struct sampler { VkSampler value; diff --git a/rpcs3/Emu/RSX/VK/VKResourceManager.h b/rpcs3/Emu/RSX/VK/VKResourceManager.h index 3a4877e647..aeb058cab0 100644 --- a/rpcs3/Emu/RSX/VK/VKResourceManager.h +++ b/rpcs3/Emu/RSX/VK/VKResourceManager.h @@ -14,7 +14,7 @@ namespace vk std::vector> m_disposed_buffers; std::vector> m_disposed_image_views; std::vector> m_disposed_images; - rsx::simple_array m_disposed_events; + std::vector> m_disposed_events; eid_scope_t(u64 _eid): eid(_eid), m_device(vk::get_current_renderer()) @@ -27,17 +27,8 @@ namespace vk void discard() { - if (!m_disposed_events.empty()) - { - for (auto &ev : m_disposed_events) - { - vkDestroyEvent(*m_device, ev, nullptr); - } - - m_disposed_events.clear(); - } - m_disposed_buffers.clear(); + m_disposed_events.clear(); m_disposed_image_views.clear(); m_disposed_images.clear(); } @@ -146,9 +137,9 @@ namespace vk get_current_eid_scope().m_disposed_images.emplace_back(std::move(img)); } - void dispose(VkEvent& event) + void dispose(std::unique_ptr& event) { - get_current_eid_scope().m_disposed_events.push_back(event); + get_current_eid_scope().m_disposed_events.emplace_back(std::move(event)); event = VK_NULL_HANDLE; } diff --git a/rpcs3/Emu/RSX/VK/VKTextureCache.h b/rpcs3/Emu/RSX/VK/VKTextureCache.h index f1959640bc..cc2bf8c95c 100644 --- a/rpcs3/Emu/RSX/VK/VKTextureCache.h +++ b/rpcs3/Emu/RSX/VK/VKTextureCache.h @@ -36,7 +36,7 @@ namespace vk std::unique_ptr managed_texture = nullptr; //DMA relevant data - VkEvent dma_fence = VK_NULL_HANDLE; + std::unique_ptr dma_fence; vk::render_device* m_device = nullptr; vk::viewable_image *vram_texture = nullptr; @@ -169,16 +169,15 @@ namespace vk { verify(HERE), src->samples() == 1; - if (m_device == nullptr) + if (!m_device) { m_device = &cmd.get_command_pool().get_owner(); } - if (dma_fence == VK_NULL_HANDLE) + if (dma_fence) { - VkEventCreateInfo createInfo = {}; - createInfo.sType = VK_STRUCTURE_TYPE_EVENT_CREATE_INFO; - vkCreateEvent(*m_device, &createInfo, nullptr, &dma_fence); + verify(HERE), synchronized; + vk::get_resource_manager()->dispose(dma_fence); } src->push_layout(cmd, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); @@ -284,23 +283,12 @@ namespace vk src->pop_layout(cmd); - if (synchronized) [[unlikely]] - { - // Replace the wait event with a new one to avoid premature signaling! - vk::get_resource_manager()->dispose(dma_fence); - - VkEventCreateInfo createInfo = {}; - createInfo.sType = VK_STRUCTURE_TYPE_EVENT_CREATE_INFO; - vkCreateEvent(*m_device, &createInfo, nullptr, &dma_fence); - } - else - { - // If this is speculated, it should only occur once - verify(HERE), vkGetEventStatus(*m_device, dma_fence) == VK_EVENT_RESET; - } + // Create event object for this transfer and queue signal op + dma_fence = std::make_unique(*m_device); + dma_fence->signal(cmd, VK_PIPELINE_STAGE_TRANSFER_BIT); + // Set cb flag for queued dma operations cmd.set_flag(vk::command_buffer::cb_has_dma_transfer); - vkCmdSetEvent(cmd, dma_fence, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT); synchronized = true; sync_timestamp = get_system_time(); @@ -396,8 +384,7 @@ namespace vk AUDIT(synchronized); // Synchronize, reset dma_fence after waiting - vk::wait_for_event(dma_fence, GENERAL_WAIT_TIMEOUT); - vkResetEvent(*m_device, dma_fence); + vk::wait_for_event(dma_fence.get(), GENERAL_WAIT_TIMEOUT); const auto range = get_confirmed_range(); vk::flush_dma(range.start, range.length());