mirror of
https://github.com/RPCS3/rpcs3.git
synced 2026-01-31 01:25:18 +01:00
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);
|
||||
}
|
||||
|
||||
VkSemaphoreCreateInfo semaphore_info = {};
|
||||
semaphore_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
|
||||
|
||||
// VRAM allocation
|
||||
// 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);
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
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);
|
||||
vkCreateSemaphore((*m_device), &semaphore_info, nullptr, &ctx.acquire_signal_semaphore);
|
||||
ctx.init(*m_device);
|
||||
}
|
||||
|
||||
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_upload_buffer_ring_info);
|
||||
|
||||
@@ -830,16 +828,17 @@ VKGSRender::~VKGSRender()
|
||||
if (m_current_frame == &m_aux_frame_context)
|
||||
{
|
||||
// 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);
|
||||
}
|
||||
|
||||
// NOTE: aux_context uses descriptor pools borrowed from the main queues and any allocations will be automatically freed when pool is destroyed
|
||||
for (auto &ctx : frame_context_storage)
|
||||
// CPU frame contexts
|
||||
for (auto &ctx : m_frame_context_storage)
|
||||
{
|
||||
vkDestroySemaphore((*m_device), ctx.present_wait_semaphore, nullptr);
|
||||
vkDestroySemaphore((*m_device), ctx.acquire_signal_semaphore, nullptr);
|
||||
ctx.destroy(*m_device);
|
||||
}
|
||||
m_current_frame = nullptr;
|
||||
m_frame_context_storage.clear();
|
||||
|
||||
// Textures
|
||||
m_rtts.destroy();
|
||||
|
||||
@@ -159,8 +159,9 @@ private:
|
||||
u64 m_texture_parameters_dynamic_offset = 0;
|
||||
u64 m_stipple_array_dynamic_offset = 0;
|
||||
|
||||
std::array<vk::frame_context_t, VK_MAX_ASYNC_FRAMES> frame_context_storage;
|
||||
//Temp frame context to use if the real frame queue is overburdened. Only used for storage
|
||||
std::vector<vk::frame_context_t> m_frame_context_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;
|
||||
|
||||
u32 m_current_queue_index = 0;
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
#define VK_INDEX_RING_BUFFER_SIZE_M 16
|
||||
|
||||
#define VK_MAX_ASYNC_CB_COUNT 512
|
||||
#define VK_MAX_ASYNC_FRAMES 2
|
||||
|
||||
#define FRAME_PRESENT_TIMEOUT 10000000ull // 10 seconds
|
||||
#define GENERAL_WAIT_TIMEOUT 2000000ull // 2 seconds
|
||||
@@ -186,6 +185,20 @@ namespace vk
|
||||
data_heap_manager::managed_heap_snapshot_t heap_snapshot;
|
||||
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
|
||||
void grab_resources(frame_context_t& other)
|
||||
{
|
||||
|
||||
@@ -52,7 +52,7 @@ void VKGSRender::reinitialize_swapchain()
|
||||
m_current_command_buffer->reset();
|
||||
m_current_command_buffer->begin();
|
||||
|
||||
for (auto &ctx : frame_context_storage)
|
||||
for (auto &ctx : m_frame_context_storage)
|
||||
{
|
||||
if (ctx.present_image == umax)
|
||||
continue;
|
||||
@@ -67,6 +67,16 @@ void VKGSRender::reinitialize_swapchain()
|
||||
// Drain all the queues
|
||||
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
|
||||
if (!m_swapchain->init(m_swapchain_dims.width, m_swapchain_dims.height))
|
||||
{
|
||||
@@ -75,6 +85,16 @@ void VKGSRender::reinitialize_swapchain()
|
||||
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
|
||||
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_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_frame = &frame_context_storage[m_current_queue_index];
|
||||
m_current_queue_index = (m_current_queue_index + 1) % m_max_async_frames;
|
||||
m_current_frame = &m_frame_context_storage[m_current_queue_index];
|
||||
m_current_frame->flags |= frame_context_state::dirty;
|
||||
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
// 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->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))
|
||||
{
|
||||
switch (status)
|
||||
|
||||
Reference in New Issue
Block a user