1
0
mirror of https://github.com/RPCS3/rpcs3.git synced 2024-11-22 18:53:28 +01:00

vk: Improve events

- Make events properly managed objects.
- Add a workaround for AMD's broken event status query
This commit is contained in:
kd-11 2020-02-29 17:44:21 +03:00 committed by Ivan
parent 5eb314fbbb
commit 9af52d12a8
4 changed files with 98 additions and 39 deletions

View File

@ -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;

View File

@ -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<buffer> 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<buffer>
(
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<uint32_t*>(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;

View File

@ -14,7 +14,7 @@ namespace vk
std::vector<std::unique_ptr<vk::buffer>> m_disposed_buffers;
std::vector<std::unique_ptr<vk::image_view>> m_disposed_image_views;
std::vector<std::unique_ptr<vk::image>> m_disposed_images;
rsx::simple_array<VkEvent> m_disposed_events;
std::vector<std::unique_ptr<vk::event>> 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<vk::event>& 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;
}

View File

@ -36,7 +36,7 @@ namespace vk
std::unique_ptr<vk::viewable_image> managed_texture = nullptr;
//DMA relevant data
VkEvent dma_fence = VK_NULL_HANDLE;
std::unique_ptr<vk::event> 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<vk::event>(*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());