diff --git a/rpcs3/Emu/RSX/VK/VKGSRender.cpp b/rpcs3/Emu/RSX/VK/VKGSRender.cpp index 4a0e6c19ce..cba661a64b 100644 --- a/rpcs3/Emu/RSX/VK/VKGSRender.cpp +++ b/rpcs3/Emu/RSX/VK/VKGSRender.cpp @@ -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(); diff --git a/rpcs3/Emu/RSX/VK/VKGSRender.h b/rpcs3/Emu/RSX/VK/VKGSRender.h index aa62df2122..faae1bb78f 100644 --- a/rpcs3/Emu/RSX/VK/VKGSRender.h +++ b/rpcs3/Emu/RSX/VK/VKGSRender.h @@ -159,8 +159,9 @@ private: u64 m_texture_parameters_dynamic_offset = 0; u64 m_stipple_array_dynamic_offset = 0; - std::array frame_context_storage; - //Temp frame context to use if the real frame queue is overburdened. Only used for storage + std::vector 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; diff --git a/rpcs3/Emu/RSX/VK/VKGSRenderTypes.hpp b/rpcs3/Emu/RSX/VK/VKGSRenderTypes.hpp index 429e428a18..0a400c68d9 100644 --- a/rpcs3/Emu/RSX/VK/VKGSRenderTypes.hpp +++ b/rpcs3/Emu/RSX/VK/VKGSRenderTypes.hpp @@ -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) { diff --git a/rpcs3/Emu/RSX/VK/VKPresent.cpp b/rpcs3/Emu/RSX/VK/VKPresent.cpp index d474af2139..eb30f9f2d6 100644 --- a/rpcs3/Emu/RSX/VK/VKPresent.cpp +++ b/rpcs3/Emu/RSX/VK/VKPresent.cpp @@ -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)