vk: Fix CPU frame misalignment bug
- This one has been around for a really long time. - The frame-based structure was due to translating the original vulkan tutorial to working code. - While it is not feasible to throw the arch away, we don't need a rigid 2-frame set for acquire-submit semaphores.
This commit is contained in:
@@ -505,9 +505,6 @@ VKGSRender::VKGSRender(utils::serial* ar) noexcept : GSRender(ar)
|
|||||||
m_occlusion_query_manager->set_control_flags(VK_QUERY_CONTROL_PRECISE_BIT, 0);
|
m_occlusion_query_manager->set_control_flags(VK_QUERY_CONTROL_PRECISE_BIT, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
VkSemaphoreCreateInfo semaphore_info = {};
|
|
||||||
semaphore_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
|
|
||||||
|
|
||||||
// VRAM allocation
|
// VRAM allocation
|
||||||
// This first set is bound persistently, so grow notifications are enabled.
|
// This first set is bound persistently, so grow notifications are enabled.
|
||||||
m_attrib_ring_info.create(VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT, VK_ATTRIB_RING_BUFFER_SIZE_M * 0x100000, vk::heap_pool_default, "attrib buffer", 0x400000, VK_TRUE);
|
m_attrib_ring_info.create(VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT, VK_ATTRIB_RING_BUFFER_SIZE_M * 0x100000, vk::heap_pool_default, "attrib buffer", 0x400000, VK_TRUE);
|
||||||
@@ -570,10 +567,13 @@ VKGSRender::VKGSRender(utils::serial* ar) noexcept : GSRender(ar)
|
|||||||
rsx_log.warning("Current driver may crash due to memory limitations (%uk)", m_texbuffer_view_size / 1024);
|
rsx_log.warning("Current driver may crash due to memory limitations (%uk)", m_texbuffer_view_size / 1024);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto &ctx : frame_context_storage)
|
m_max_async_frames = m_swapchain->get_swap_image_count();
|
||||||
|
m_frame_context_storage.resize(m_max_async_frames);
|
||||||
|
m_current_frame = &m_frame_context_storage[0];
|
||||||
|
|
||||||
|
for (auto& ctx : m_frame_context_storage)
|
||||||
{
|
{
|
||||||
vkCreateSemaphore((*m_device), &semaphore_info, nullptr, &ctx.present_wait_semaphore);
|
ctx.init(*m_device);
|
||||||
vkCreateSemaphore((*m_device), &semaphore_info, nullptr, &ctx.acquire_signal_semaphore);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto& memory_map = m_device->get_memory_mapping();
|
const auto& memory_map = m_device->get_memory_mapping();
|
||||||
@@ -612,8 +612,6 @@ VKGSRender::VKGSRender(utils::serial* ar) noexcept : GSRender(ar)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_current_frame = &frame_context_storage[0];
|
|
||||||
|
|
||||||
m_texture_cache.initialize((*m_device), m_device->get_graphics_queue(),
|
m_texture_cache.initialize((*m_device), m_device->get_graphics_queue(),
|
||||||
m_texture_upload_buffer_ring_info);
|
m_texture_upload_buffer_ring_info);
|
||||||
|
|
||||||
@@ -830,16 +828,17 @@ VKGSRender::~VKGSRender()
|
|||||||
if (m_current_frame == &m_aux_frame_context)
|
if (m_current_frame == &m_aux_frame_context)
|
||||||
{
|
{
|
||||||
// Return resources back to the owner
|
// Return resources back to the owner
|
||||||
m_current_frame = &frame_context_storage[m_current_queue_index];
|
m_current_frame = &m_frame_context_storage[m_current_queue_index];
|
||||||
m_current_frame->grab_resources(m_aux_frame_context);
|
m_current_frame->grab_resources(m_aux_frame_context);
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: aux_context uses descriptor pools borrowed from the main queues and any allocations will be automatically freed when pool is destroyed
|
// CPU frame contexts
|
||||||
for (auto &ctx : frame_context_storage)
|
for (auto &ctx : m_frame_context_storage)
|
||||||
{
|
{
|
||||||
vkDestroySemaphore((*m_device), ctx.present_wait_semaphore, nullptr);
|
ctx.destroy(*m_device);
|
||||||
vkDestroySemaphore((*m_device), ctx.acquire_signal_semaphore, nullptr);
|
|
||||||
}
|
}
|
||||||
|
m_current_frame = nullptr;
|
||||||
|
m_frame_context_storage.clear();
|
||||||
|
|
||||||
// Textures
|
// Textures
|
||||||
m_rtts.destroy();
|
m_rtts.destroy();
|
||||||
|
|||||||
@@ -159,8 +159,9 @@ private:
|
|||||||
u64 m_texture_parameters_dynamic_offset = 0;
|
u64 m_texture_parameters_dynamic_offset = 0;
|
||||||
u64 m_stipple_array_dynamic_offset = 0;
|
u64 m_stipple_array_dynamic_offset = 0;
|
||||||
|
|
||||||
std::array<vk::frame_context_t, VK_MAX_ASYNC_FRAMES> frame_context_storage;
|
std::vector<vk::frame_context_t> m_frame_context_storage;
|
||||||
//Temp frame context to use if the real frame queue is overburdened. Only used for storage
|
u32 m_max_async_frames = 0u;
|
||||||
|
// Temp frame context to use if the real frame queue is overburdened. Only used for storage
|
||||||
vk::frame_context_t m_aux_frame_context;
|
vk::frame_context_t m_aux_frame_context;
|
||||||
|
|
||||||
u32 m_current_queue_index = 0;
|
u32 m_current_queue_index = 0;
|
||||||
|
|||||||
@@ -23,7 +23,6 @@
|
|||||||
#define VK_INDEX_RING_BUFFER_SIZE_M 16
|
#define VK_INDEX_RING_BUFFER_SIZE_M 16
|
||||||
|
|
||||||
#define VK_MAX_ASYNC_CB_COUNT 512
|
#define VK_MAX_ASYNC_CB_COUNT 512
|
||||||
#define VK_MAX_ASYNC_FRAMES 2
|
|
||||||
|
|
||||||
#define FRAME_PRESENT_TIMEOUT 10000000ull // 10 seconds
|
#define FRAME_PRESENT_TIMEOUT 10000000ull // 10 seconds
|
||||||
#define GENERAL_WAIT_TIMEOUT 2000000ull // 2 seconds
|
#define GENERAL_WAIT_TIMEOUT 2000000ull // 2 seconds
|
||||||
@@ -186,6 +185,20 @@ namespace vk
|
|||||||
data_heap_manager::managed_heap_snapshot_t heap_snapshot;
|
data_heap_manager::managed_heap_snapshot_t heap_snapshot;
|
||||||
u64 last_frame_sync_time = 0;
|
u64 last_frame_sync_time = 0;
|
||||||
|
|
||||||
|
void init(VkDevice dev)
|
||||||
|
{
|
||||||
|
VkSemaphoreCreateInfo semaphore_info = {};
|
||||||
|
semaphore_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
|
||||||
|
vkCreateSemaphore(dev, &semaphore_info, nullptr, &present_wait_semaphore);
|
||||||
|
vkCreateSemaphore(dev, &semaphore_info, nullptr, &acquire_signal_semaphore);
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy(VkDevice dev)
|
||||||
|
{
|
||||||
|
vkDestroySemaphore(dev, present_wait_semaphore, nullptr);
|
||||||
|
vkDestroySemaphore(dev, acquire_signal_semaphore, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
// Copy shareable information
|
// Copy shareable information
|
||||||
void grab_resources(frame_context_t& other)
|
void grab_resources(frame_context_t& other)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ void VKGSRender::reinitialize_swapchain()
|
|||||||
m_current_command_buffer->reset();
|
m_current_command_buffer->reset();
|
||||||
m_current_command_buffer->begin();
|
m_current_command_buffer->begin();
|
||||||
|
|
||||||
for (auto &ctx : frame_context_storage)
|
for (auto &ctx : m_frame_context_storage)
|
||||||
{
|
{
|
||||||
if (ctx.present_image == umax)
|
if (ctx.present_image == umax)
|
||||||
continue;
|
continue;
|
||||||
@@ -67,6 +67,16 @@ void VKGSRender::reinitialize_swapchain()
|
|||||||
// Drain all the queues
|
// Drain all the queues
|
||||||
vkDeviceWaitIdle(*m_device);
|
vkDeviceWaitIdle(*m_device);
|
||||||
|
|
||||||
|
// Reset frame context storage
|
||||||
|
for (auto& ctx : m_frame_context_storage)
|
||||||
|
{
|
||||||
|
ctx.destroy(*m_device);
|
||||||
|
}
|
||||||
|
m_current_frame = nullptr;
|
||||||
|
m_max_async_frames = 0;
|
||||||
|
m_current_queue_index = 0;
|
||||||
|
m_frame_context_storage.clear();
|
||||||
|
|
||||||
// Rebuild swapchain. Old swapchain destruction is handled by the init_swapchain call
|
// Rebuild swapchain. Old swapchain destruction is handled by the init_swapchain call
|
||||||
if (!m_swapchain->init(m_swapchain_dims.width, m_swapchain_dims.height))
|
if (!m_swapchain->init(m_swapchain_dims.width, m_swapchain_dims.height))
|
||||||
{
|
{
|
||||||
@@ -75,6 +85,16 @@ void VKGSRender::reinitialize_swapchain()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Re-initialize CPU frame contexts
|
||||||
|
m_max_async_frames = m_swapchain->get_swap_image_count();
|
||||||
|
m_frame_context_storage.resize(m_max_async_frames);
|
||||||
|
for (auto& ctx : m_frame_context_storage)
|
||||||
|
{
|
||||||
|
ctx.init(*m_device);
|
||||||
|
}
|
||||||
|
m_current_queue_index = 0;
|
||||||
|
m_current_frame = &m_frame_context_storage[0];
|
||||||
|
|
||||||
// Prepare new swapchain images for use
|
// Prepare new swapchain images for use
|
||||||
for (u32 i = 0; i < m_swapchain->get_swap_image_count(); ++i)
|
for (u32 i = 0; i < m_swapchain->get_swap_image_count(); ++i)
|
||||||
{
|
{
|
||||||
@@ -158,10 +178,10 @@ void VKGSRender::advance_queued_frames()
|
|||||||
m_current_frame->tag_frame_end();
|
m_current_frame->tag_frame_end();
|
||||||
|
|
||||||
m_queued_frames.push_back(m_current_frame);
|
m_queued_frames.push_back(m_current_frame);
|
||||||
ensure(m_queued_frames.size() <= VK_MAX_ASYNC_FRAMES);
|
ensure(m_queued_frames.size() <= m_max_async_frames);
|
||||||
|
|
||||||
m_current_queue_index = (m_current_queue_index + 1) % VK_MAX_ASYNC_FRAMES;
|
m_current_queue_index = (m_current_queue_index + 1) % m_max_async_frames;
|
||||||
m_current_frame = &frame_context_storage[m_current_queue_index];
|
m_current_frame = &m_frame_context_storage[m_current_queue_index];
|
||||||
m_current_frame->flags |= frame_context_state::dirty;
|
m_current_frame->flags |= frame_context_state::dirty;
|
||||||
|
|
||||||
vk::advance_frame_counter();
|
vk::advance_frame_counter();
|
||||||
@@ -398,7 +418,7 @@ void VKGSRender::flip(const rsx::display_flip_info_t& info)
|
|||||||
|
|
||||||
if (m_current_frame == &m_aux_frame_context)
|
if (m_current_frame == &m_aux_frame_context)
|
||||||
{
|
{
|
||||||
m_current_frame = &frame_context_storage[m_current_queue_index];
|
m_current_frame = &m_frame_context_storage[m_current_queue_index];
|
||||||
if (m_current_frame->swap_command_buffer)
|
if (m_current_frame->swap_command_buffer)
|
||||||
{
|
{
|
||||||
// Its possible this flip request is triggered by overlays and the flip queue is in undefined state
|
// Its possible this flip request is triggered by overlays and the flip queue is in undefined state
|
||||||
@@ -520,7 +540,7 @@ void VKGSRender::flip(const rsx::display_flip_info_t& info)
|
|||||||
ensure(m_current_frame->present_image == umax);
|
ensure(m_current_frame->present_image == umax);
|
||||||
ensure(m_current_frame->swap_command_buffer == nullptr);
|
ensure(m_current_frame->swap_command_buffer == nullptr);
|
||||||
|
|
||||||
u64 timeout = m_swapchain->get_swap_image_count() <= VK_MAX_ASYNC_FRAMES? 0ull: 100000000ull;
|
u64 timeout = m_swapchain->get_swap_image_count() <= 2? 0ull: 100000000ull;
|
||||||
while (VkResult status = m_swapchain->acquire_next_swapchain_image(m_current_frame->acquire_signal_semaphore, timeout, &m_current_frame->present_image))
|
while (VkResult status = m_swapchain->acquire_next_swapchain_image(m_current_frame->acquire_signal_semaphore, timeout, &m_current_frame->present_image))
|
||||||
{
|
{
|
||||||
switch (status)
|
switch (status)
|
||||||
|
|||||||
Reference in New Issue
Block a user