From aa3c97f9181a3cb0b65eb7bd5b2d63ce7baa155c Mon Sep 17 00:00:00 2001 From: Vincent Lejeune Date: Wed, 23 Mar 2016 23:22:33 +0100 Subject: [PATCH] vulkan: Only submit command buffer at flip and avoid extra sync. --- rpcs3/Emu/RSX/VK/VKGSRender.cpp | 200 +++++++++++--------------------- rpcs3/Emu/RSX/VK/VKGSRender.h | 8 +- rpcs3/Emu/RSX/VK/VKHelpers.h | 2 +- 3 files changed, 73 insertions(+), 137 deletions(-) diff --git a/rpcs3/Emu/RSX/VK/VKGSRender.cpp b/rpcs3/Emu/RSX/VK/VKGSRender.cpp index 05f698d30f..0fd898379f 100644 --- a/rpcs3/Emu/RSX/VK/VKGSRender.cpp +++ b/rpcs3/Emu/RSX/VK/VKGSRender.cpp @@ -381,15 +381,7 @@ VKGSRender::VKGSRender() : GSRender(frame_type::Vulkan) //create command buffer... m_command_buffer_pool.create((*m_device)); m_command_buffer.create(m_command_buffer_pool); - - VkCommandBufferInheritanceInfo inheritance_info = {}; - inheritance_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO; - - VkCommandBufferBeginInfo begin_infos = {}; - begin_infos.pInheritanceInfo = &inheritance_info; - begin_infos.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - - CHECK_RESULT(vkBeginCommandBuffer(m_command_buffer, &begin_infos)); + open_command_buffer(); for (u32 i = 0; i < m_swap_chain->get_swap_image_count(); ++i) { @@ -405,9 +397,6 @@ VKGSRender::VKGSRender() : GSRender(frame_type::Vulkan) vk::get_image_subresource_range(0, 0, 1, 1, VK_IMAGE_ASPECT_COLOR_BIT)); } - - CHECK_RESULT(vkEndCommandBuffer(m_command_buffer)); - execute_command_buffer(false); #define RING_BUFFER_SIZE 16 * 1024 * 1024 @@ -433,16 +422,21 @@ VKGSRender::VKGSRender() : GSRender(frame_type::Vulkan) null_buffer = std::make_unique(*m_device, 32, m_memory_type_mapping.host_visible_coherent, VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT, 0); null_buffer_view = std::make_unique(*m_device, null_buffer->value, VK_FORMAT_R32_SFLOAT, 0, 32); + + VkFenceCreateInfo fence_info = {}; + fence_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; + + CHECK_RESULT(vkCreateFence(*m_device, &fence_info, nullptr, &m_submit_fence)); + + VkSemaphoreCreateInfo semaphore_info = {}; + semaphore_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; + + vkCreateSemaphore((*m_device), &semaphore_info, nullptr, &m_present_semaphore); } VKGSRender::~VKGSRender() { - if (m_submit_fence) - { - vkWaitForFences((*m_device), 1, &m_submit_fence, VK_TRUE, 1000000L); - vkDestroyFence((*m_device), m_submit_fence, nullptr); - m_submit_fence = nullptr; - } + CHECK_RESULT(vkQueueWaitIdle(m_swap_chain->get_present_queue())); if (m_present_semaphore) { @@ -500,8 +494,6 @@ void VKGSRender::begin() //TODO: Fence sync, ring-buffers, etc //CHECK_RESULT(vkDeviceWaitIdle((*m_device))); - if (!recording) - begin_command_buffer_recording(); VkDescriptorSetAllocateInfo alloc_info = {}; alloc_info.descriptorPool = descriptor_pool; alloc_info.descriptorSetCount = 1; @@ -616,9 +608,6 @@ void VKGSRender::end() vkCmdEndRenderPass(m_command_buffer); - end_command_buffer_recording(); - execute_command_buffer(false); - rsx::thread::end(); } @@ -680,11 +669,6 @@ void VKGSRender::clear_surface(u32 mask) if (m_current_present_image== 0xFFFF) return; - bool was_recording = recording; - - if (!was_recording) - begin_command_buffer_recording(); - init_buffers(); float depth_clear = 1.f; @@ -756,13 +740,16 @@ void VKGSRender::clear_surface(u32 mask) change_image_layout(m_command_buffer, depth_stencil_image, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, range); } - if (!was_recording) - { - end_command_buffer_recording(); - execute_command_buffer(false); - } +} - recording = was_recording; +void VKGSRender::sync_at_semaphore_release() +{ + close_and_submit_command_buffer({}, m_submit_fence); + CHECK_RESULT(vkWaitForFences((*m_device), 1, &m_submit_fence, VK_TRUE, ~0ULL)); + + CHECK_RESULT(vkResetFences(*m_device, 1, &m_submit_fence)); + CHECK_RESULT(vkResetCommandPool(*m_device, m_command_buffer_pool, 0)); + open_command_buffer(); } bool VKGSRender::do_method(u32 cmd, u32 arg) @@ -772,6 +759,10 @@ bool VKGSRender::do_method(u32 cmd, u32 arg) case NV4097_CLEAR_SURFACE: clear_surface(arg); return true; + case NV4097_TEXTURE_READ_SEMAPHORE_RELEASE: + case NV4097_BACK_END_WRITE_SEMAPHORE_RELEASE: + sync_at_semaphore_release(); + return false; //call rsx::thread method implementation default: return false; } @@ -978,20 +969,6 @@ static const u32 mr_color_pitch[rsx::limits::color_buffers_count] = void VKGSRender::init_buffers(bool skip_reading) { - if (dirty_frame) - { - //Prepare surface for new frame - VkSemaphoreCreateInfo semaphore_info = {}; - semaphore_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; - - vkCreateSemaphore((*m_device), &semaphore_info, nullptr, &m_present_semaphore); - - VkFence nullFence = VK_NULL_HANDLE; - CHECK_RESULT(vkAcquireNextImageKHR((*m_device), (*m_swap_chain), 0, m_present_semaphore, nullFence, &m_current_present_image)); - - dirty_frame = false; - } - prepare_rtts(); if (!skip_reading) @@ -1010,7 +987,25 @@ void VKGSRender::write_buffers() { } -void VKGSRender::begin_command_buffer_recording() +void VKGSRender::close_and_submit_command_buffer(const std::vector &semaphores, VkFence fence) +{ + CHECK_RESULT(vkEndCommandBuffer(m_command_buffer)); + + VkPipelineStageFlags pipe_stage_flags = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; + VkCommandBuffer cmd = m_command_buffer; + + VkSubmitInfo infos = {}; + infos.commandBufferCount = 1; + infos.pCommandBuffers = &cmd; + infos.pWaitDstStageMask = &pipe_stage_flags; + infos.pWaitSemaphores = semaphores.data(); + infos.waitSemaphoreCount = semaphores.size(); + infos.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + + CHECK_RESULT(vkQueueSubmit(m_swap_chain->get_present_queue(), 1, &infos, fence)); +} + +void VKGSRender::open_command_buffer() { VkCommandBufferInheritanceInfo inheritance_info = {}; inheritance_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO; @@ -1018,25 +1013,10 @@ void VKGSRender::begin_command_buffer_recording() VkCommandBufferBeginInfo begin_infos = {}; begin_infos.pInheritanceInfo = &inheritance_info; begin_infos.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - - if (m_submit_fence) - { - vkWaitForFences(*m_device, 1, &m_submit_fence, VK_TRUE, ~0ULL); - vkDestroyFence(*m_device, m_submit_fence, nullptr); - m_submit_fence = nullptr; - - CHECK_RESULT(vkResetCommandBuffer(m_command_buffer, 0)); - } - + begin_infos.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; CHECK_RESULT(vkBeginCommandBuffer(m_command_buffer, &begin_infos)); - recording = true; } -void VKGSRender::end_command_buffer_recording() -{ - recording = false; - CHECK_RESULT(vkEndCommandBuffer(m_command_buffer)); -} void VKGSRender::prepare_rtts() { @@ -1110,31 +1090,6 @@ void VKGSRender::prepare_rtts() m_framebuffer_to_clean.push_back(std::make_unique(*m_device, current_render_pass, clip_width, clip_height, std::move(fbo_images))); } -void VKGSRender::execute_command_buffer(bool wait) -{ - if (recording) - throw EXCEPTION("execute_command_buffer called before end_command_buffer_recording()!"); - - if (m_submit_fence) - throw EXCEPTION("Synchronization deadlock!"); - - VkFenceCreateInfo fence_info = {}; - fence_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; - - CHECK_RESULT(vkCreateFence(*m_device, &fence_info, nullptr, &m_submit_fence)); - - VkPipelineStageFlags pipe_stage_flags = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; - VkCommandBuffer cmd = m_command_buffer; - - VkSubmitInfo infos = {}; - infos.commandBufferCount = 1; - infos.pCommandBuffers = &cmd; - infos.pWaitDstStageMask = &pipe_stage_flags; - infos.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - - CHECK_RESULT(vkQueueSubmit(m_swap_chain->get_present_queue(), 1, &infos, m_submit_fence)); - CHECK_RESULT(vkQueueWaitIdle(m_swap_chain->get_present_queue())); -} void VKGSRender::flip(int buffer) { @@ -1178,28 +1133,21 @@ void VKGSRender::flip(int buffer) VkSwapchainKHR swap_chain = (VkSwapchainKHR)(*m_swap_chain); uint32_t next_image_temp = 0; - VkPresentInfoKHR present = {}; - present.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; - present.pNext = nullptr; - present.swapchainCount = 1; - present.pSwapchains = &swap_chain; - present.pImageIndices = &m_current_present_image; - present.pWaitSemaphores = &m_present_semaphore; - present.waitSemaphoreCount = 1; + //Prepare surface for new frame + CHECK_RESULT(vkAcquireNextImageKHR((*m_device), (*m_swap_chain), 0, m_present_semaphore, VK_NULL_HANDLE, &m_current_present_image)); - begin_command_buffer_recording(); - if (m_present_semaphore) + //Blit contents to screen.. + VkImage image_to_flip = nullptr; + + if (std::get<1>(m_rtts.m_bound_render_targets[0]) != nullptr) + image_to_flip = std::get<1>(m_rtts.m_bound_render_targets[0])->value; + else if (std::get<1>(m_rtts.m_bound_render_targets[1]) != nullptr) + image_to_flip = std::get<1>(m_rtts.m_bound_render_targets[1])->value; + + VkImage target_image = m_swap_chain->get_swap_chain_image(m_current_present_image); + if (image_to_flip) { - //Blit contents to screen.. - VkImage image_to_flip = nullptr; - - if (std::get<1>(m_rtts.m_bound_render_targets[0]) != nullptr) - image_to_flip = std::get<1>(m_rtts.m_bound_render_targets[0])->value; - else - image_to_flip = std::get<1>(m_rtts.m_bound_render_targets[1])->value; - - VkImage target_image = m_swap_chain->get_swap_chain_image(m_current_present_image); vk::copy_scaled_image(m_command_buffer, image_to_flip, target_image, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, buffer_width, buffer_height, aspect_ratio.width, aspect_ratio.height, 1, VK_IMAGE_ASPECT_COLOR_BIT); } @@ -1212,37 +1160,27 @@ void VKGSRender::flip(int buffer) VkImageSubresourceRange range = vk::get_image_subresource_range(0, 0, 1, 1, VK_IMAGE_ASPECT_COLOR_BIT); VkClearColorValue clear_black = { 0 }; vkCmdClearColorImage(m_command_buffer, m_swap_chain->get_swap_chain_image(next_image_temp), VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, &clear_black, 1, &range); - - present.pImageIndices = &next_image_temp; - present.waitSemaphoreCount = 0; } - end_command_buffer_recording(); - execute_command_buffer(false); - - //Check if anything is waiting in queue and wait for it if possible.. - if (m_submit_fence) - { - CHECK_RESULT(vkWaitForFences((*m_device), 1, &m_submit_fence, VK_TRUE, ~0ULL)); - - vkDestroyFence((*m_device), m_submit_fence, nullptr); - m_submit_fence = nullptr; - - CHECK_RESULT(vkResetCommandBuffer(m_command_buffer, 0)); - } + close_and_submit_command_buffer({ m_present_semaphore }, m_submit_fence); + CHECK_RESULT(vkWaitForFences((*m_device), 1, &m_submit_fence, VK_TRUE, ~0ULL)); + VkPresentInfoKHR present = {}; + present.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; + present.pNext = nullptr; + present.swapchainCount = 1; + present.pSwapchains = &swap_chain; + present.pImageIndices = &m_current_present_image; CHECK_RESULT(m_swap_chain->queuePresentKHR(m_swap_chain->get_present_queue(), &present)); - CHECK_RESULT(vkQueueWaitIdle(m_swap_chain->get_present_queue())); + + CHECK_RESULT(vkResetFences(*m_device, 1, &m_submit_fence)); + CHECK_RESULT(vkResetCommandPool(*m_device, m_command_buffer_pool, 0)); + open_command_buffer(); m_uniform_buffer_ring_info.m_get_pos = m_uniform_buffer_ring_info.get_current_put_pos_minus_one(); m_index_buffer_ring_info.m_get_pos = m_index_buffer_ring_info.get_current_put_pos_minus_one(); m_attrib_ring_info.m_get_pos = m_attrib_ring_info.get_current_put_pos_minus_one(); m_texture_upload_buffer_ring_info.m_get_pos = m_texture_upload_buffer_ring_info.get_current_put_pos_minus_one(); - if (m_present_semaphore) - { - vkDestroySemaphore((*m_device), m_present_semaphore, nullptr); - m_present_semaphore = nullptr; - } //Feed back damaged resources to the main texture cache for management... // m_texture_cache.merge_dirty_textures(m_rtts.invalidated_resources); diff --git a/rpcs3/Emu/RSX/VK/VKGSRender.h b/rpcs3/Emu/RSX/VK/VKGSRender.h index ecc751ed9f..eecd753574 100644 --- a/rpcs3/Emu/RSX/VK/VKGSRender.h +++ b/rpcs3/Emu/RSX/VK/VKGSRender.h @@ -61,7 +61,6 @@ private: vk::command_pool m_command_buffer_pool; vk::command_buffer m_command_buffer; - bool recording = false; bool dirty_frame = true; @@ -85,10 +84,9 @@ public: private: void clear_surface(u32 mask); - void execute_command_buffer(bool wait); - void begin_command_buffer_recording(); - void end_command_buffer_recording(); - + void close_and_submit_command_buffer(const std::vector &semaphores, VkFence fence); + void open_command_buffer(); + void sync_at_semaphore_release(); void prepare_rtts(); /// returns primitive topology, is_indexed, index_count, offset in index buffer, index type std::tuple upload_vertex_data(); diff --git a/rpcs3/Emu/RSX/VK/VKHelpers.h b/rpcs3/Emu/RSX/VK/VKHelpers.h index 6aad024d7d..11aa842a49 100644 --- a/rpcs3/Emu/RSX/VK/VKHelpers.h +++ b/rpcs3/Emu/RSX/VK/VKHelpers.h @@ -899,7 +899,7 @@ namespace vk { owner = &dev; VkCommandPoolCreateInfo infos = {}; - infos.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; + infos.flags = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT; infos.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; CHECK_RESULT(vkCreateCommandPool(dev, &infos, nullptr, &pool));