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; u64 t = 0;
while (true) while (true)
{ {
switch (const auto status = vkGetEventStatus(*g_current_renderer, event)) switch (const auto status = pEvent->status())
{ {
case VK_EVENT_SET: case VK_EVENT_SET:
return VK_SUCCESS; return VK_SUCCESS;

View file

@ -115,6 +115,7 @@ namespace vk
struct gpu_formats_support; struct gpu_formats_support;
struct fence; struct fence;
struct pipeline_binding_table; struct pipeline_binding_table;
class event;
const vk::context *get_current_thread_ctx(); const vk::context *get_current_thread_ctx();
void set_current_thread_ctx(const vk::context &ctx); void set_current_thread_ctx(const vk::context &ctx);
@ -227,7 +228,7 @@ namespace vk
// Fence reset with driver workarounds in place // Fence reset with driver workarounds in place
void reset_fence(fence* pFence); void reset_fence(fence* pFence);
VkResult wait_for_fence(fence* pFence, u64 timeout = 0ull); 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 // Handle unexpected submit with dangling occlusion query
// TODO: Move queries out of the renderer! // TODO: Move queries out of the renderer!
@ -1736,6 +1737,86 @@ private:
VkDevice m_device; 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 struct sampler
{ {
VkSampler value; 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::buffer>> m_disposed_buffers;
std::vector<std::unique_ptr<vk::image_view>> m_disposed_image_views; std::vector<std::unique_ptr<vk::image_view>> m_disposed_image_views;
std::vector<std::unique_ptr<vk::image>> m_disposed_images; 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_scope_t(u64 _eid):
eid(_eid), m_device(vk::get_current_renderer()) eid(_eid), m_device(vk::get_current_renderer())
@ -27,17 +27,8 @@ namespace vk
void discard() 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_buffers.clear();
m_disposed_events.clear();
m_disposed_image_views.clear(); m_disposed_image_views.clear();
m_disposed_images.clear(); m_disposed_images.clear();
} }
@ -146,9 +137,9 @@ namespace vk
get_current_eid_scope().m_disposed_images.emplace_back(std::move(img)); 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; event = VK_NULL_HANDLE;
} }

View file

@ -36,7 +36,7 @@ namespace vk
std::unique_ptr<vk::viewable_image> managed_texture = nullptr; std::unique_ptr<vk::viewable_image> managed_texture = nullptr;
//DMA relevant data //DMA relevant data
VkEvent dma_fence = VK_NULL_HANDLE; std::unique_ptr<vk::event> dma_fence;
vk::render_device* m_device = nullptr; vk::render_device* m_device = nullptr;
vk::viewable_image *vram_texture = nullptr; vk::viewable_image *vram_texture = nullptr;
@ -169,16 +169,15 @@ namespace vk
{ {
verify(HERE), src->samples() == 1; verify(HERE), src->samples() == 1;
if (m_device == nullptr) if (!m_device)
{ {
m_device = &cmd.get_command_pool().get_owner(); m_device = &cmd.get_command_pool().get_owner();
} }
if (dma_fence == VK_NULL_HANDLE) if (dma_fence)
{ {
VkEventCreateInfo createInfo = {}; verify(HERE), synchronized;
createInfo.sType = VK_STRUCTURE_TYPE_EVENT_CREATE_INFO; vk::get_resource_manager()->dispose(dma_fence);
vkCreateEvent(*m_device, &createInfo, nullptr, &dma_fence);
} }
src->push_layout(cmd, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); src->push_layout(cmd, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
@ -284,23 +283,12 @@ namespace vk
src->pop_layout(cmd); src->pop_layout(cmd);
if (synchronized) [[unlikely]] // Create event object for this transfer and queue signal op
{ dma_fence = std::make_unique<vk::event>(*m_device);
// Replace the wait event with a new one to avoid premature signaling! dma_fence->signal(cmd, VK_PIPELINE_STAGE_TRANSFER_BIT);
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;
}
// Set cb flag for queued dma operations
cmd.set_flag(vk::command_buffer::cb_has_dma_transfer); 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; synchronized = true;
sync_timestamp = get_system_time(); sync_timestamp = get_system_time();
@ -396,8 +384,7 @@ namespace vk
AUDIT(synchronized); AUDIT(synchronized);
// Synchronize, reset dma_fence after waiting // Synchronize, reset dma_fence after waiting
vk::wait_for_event(dma_fence, GENERAL_WAIT_TIMEOUT); vk::wait_for_event(dma_fence.get(), GENERAL_WAIT_TIMEOUT);
vkResetEvent(*m_device, dma_fence);
const auto range = get_confirmed_range(); const auto range = get_confirmed_range();
vk::flush_dma(range.start, range.length()); vk::flush_dma(range.start, range.length());