diff --git a/rpcs3/Emu/RSX/VK/VKGSRenderTypes.hpp b/rpcs3/Emu/RSX/VK/VKGSRenderTypes.hpp index 8f38378f52..429e428a18 100644 --- a/rpcs3/Emu/RSX/VK/VKGSRenderTypes.hpp +++ b/rpcs3/Emu/RSX/VK/VKGSRenderTypes.hpp @@ -74,7 +74,7 @@ namespace vk } ++reset_id; - CHECK_RESULT(vkResetCommandBuffer(commands, 0)); + vk::command_buffer::reset(); } bool poke() diff --git a/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp b/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp index d54fa8f2c1..e3afc26cfd 100644 --- a/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp +++ b/rpcs3/Emu/RSX/VK/VKProgramPipeline.cpp @@ -414,8 +414,8 @@ namespace vk bind_sets[count++] = set.commit(); // Commit variable changes and return handle to the new set } - vkCmdBindPipeline(cmd, bind_point, m_pipeline); - vkCmdBindDescriptorSets(cmd, bind_point, m_pipeline_layout, 0, count, bind_sets, 0, nullptr); + cmd.bind_pipeline(m_pipeline, bind_point); + cmd.bind_descriptor_sets({ bind_sets, count }, bind_point, m_pipeline_layout); return *this; } diff --git a/rpcs3/Emu/RSX/VK/VKTextureCache.cpp b/rpcs3/Emu/RSX/VK/VKTextureCache.cpp index 45094cf4e3..4505528a34 100644 --- a/rpcs3/Emu/RSX/VK/VKTextureCache.cpp +++ b/rpcs3/Emu/RSX/VK/VKTextureCache.cpp @@ -1339,7 +1339,7 @@ namespace vk cmd.submit(submit_info, VK_TRUE); vk::wait_for_fence(&submit_fence, GENERAL_WAIT_TIMEOUT); - CHECK_RESULT(vkResetCommandBuffer(cmd, 0)); + cmd.reset(); cmd.begin(); } else diff --git a/rpcs3/Emu/RSX/VK/vkutils/commands.cpp b/rpcs3/Emu/RSX/VK/vkutils/commands.cpp index c66c63f893..3886ee811f 100644 --- a/rpcs3/Emu/RSX/VK/vkutils/commands.cpp +++ b/rpcs3/Emu/RSX/VK/vkutils/commands.cpp @@ -70,6 +70,16 @@ namespace vk } } + void command_buffer::reset() + { + // Nuke the state cache + m_bound_pipeline = VK_NULL_HANDLE; + m_bound_descriptor_sets[0] = VK_NULL_HANDLE; + + // Do the driver reset + CHECK_RESULT(vkResetCommandBuffer(commands, 0)); + } + void command_buffer::begin() { if (m_submit_fence && is_pending) @@ -79,7 +89,7 @@ namespace vk //CHECK_RESULT(vkResetFences(pool->get_owner(), 1, &m_submit_fence)); m_submit_fence->reset(); - CHECK_RESULT(vkResetCommandBuffer(commands, 0)); + reset(); } if (is_open) @@ -129,4 +139,51 @@ namespace vk queue_submit(submit_info, flush); clear_flags(); } + + void command_buffer::bind_pipeline(VkPipeline pipeline, VkPipelineBindPoint bind_point) const + { + if (m_bound_pipeline == pipeline) + { + return; + } + + m_bound_pipeline = pipeline; + vkCmdBindPipeline(commands, bind_point, pipeline); + } + + void command_buffer::bind_descriptor_sets( + const std::span& sets, + const std::span& dynamic_offsets, + VkPipelineBindPoint bind_point, + VkPipelineLayout pipe_layout) const + { + const u32 num_sets = ::size32(sets); + ensure(num_sets <= 2); + + if (dynamic_offsets.empty() && + !memcmp(sets.data(), m_bound_descriptor_sets.data(), sets.size_bytes())) + { + return; + } + + std::memcpy(m_bound_descriptor_sets.data(), sets.data(), sets.size_bytes()); + vkCmdBindDescriptorSets(commands, bind_point, pipe_layout, 0, num_sets, sets.data(), ::size32(dynamic_offsets), dynamic_offsets.data()); + } + + void command_buffer::bind_descriptor_sets( + const std::span& sets, + VkPipelineBindPoint bind_point, + VkPipelineLayout pipe_layout) const + { + const u32 num_sets = ::size32(sets); + ensure(num_sets <= 2); + + if (!memcmp(sets.data(), m_bound_descriptor_sets.data(), sets.size_bytes())) + { + return; + } + + std::memcpy(m_bound_descriptor_sets.data(), sets.data(), sets.size_bytes()); + vkCmdBindDescriptorSets(commands, bind_point, pipe_layout, 0, num_sets, sets.data(), 0, nullptr); + } } diff --git a/rpcs3/Emu/RSX/VK/vkutils/commands.h b/rpcs3/Emu/RSX/VK/vkutils/commands.h index 65ebfe95b2..cde281264e 100644 --- a/rpcs3/Emu/RSX/VK/vkutils/commands.h +++ b/rpcs3/Emu/RSX/VK/vkutils/commands.h @@ -71,6 +71,10 @@ namespace vk command_pool* pool = nullptr; VkCommandBuffer commands = nullptr; + // State cache + mutable std::array m_bound_descriptor_sets {{ VK_NULL_HANDLE }}; + mutable VkPipeline m_bound_pipeline = VK_NULL_HANDLE; + public: enum access_type_hint { @@ -97,40 +101,28 @@ namespace vk void create(command_pool& cmd_pool); void destroy(); + void reset(); void begin(); void end(); void submit(queue_submit_t& submit_info, VkBool32 flush = VK_FALSE); + // Abstractions with caching + void bind_pipeline(VkPipeline pipeline, VkPipelineBindPoint bind_point) const; + void bind_descriptor_sets(const std::span& sets, VkPipelineBindPoint bind_point, VkPipelineLayout pipe_layout) const; + void bind_descriptor_sets(const std::span& sets, const std::span& dynamic_offsets, VkPipelineBindPoint bind_point, VkPipelineLayout pipe_layout) const; + // Properties - command_pool& get_command_pool() const - { - return *pool; - } + command_pool& get_command_pool() const { return *pool; } + u32 get_queue_family() const { return pool->get_queue_family(); } + bool is_recording() const { return is_open; } - u32 get_queue_family() const - { - return pool->get_queue_family(); - } - - void clear_flags() - { - flags = 0; - } - - void set_flag(command_buffer_data_flag flag) - { - flags |= flag; - } + void clear_flags() { flags = 0; } + void set_flag(command_buffer_data_flag flag) { flags |= flag; } operator VkCommandBuffer() const { return commands; } - - bool is_recording() const - { - return is_open; - } }; } diff --git a/rpcs3/Emu/RSX/VK/vkutils/descriptors.cpp b/rpcs3/Emu/RSX/VK/vkutils/descriptors.cpp index 3b0b8f2f5a..b7224934b4 100644 --- a/rpcs3/Emu/RSX/VK/vkutils/descriptors.cpp +++ b/rpcs3/Emu/RSX/VK/vkutils/descriptors.cpp @@ -453,7 +453,8 @@ namespace vk // Notify on_bind(); - vkCmdBindDescriptorSets(cmd, bind_point, layout, 0, 1, &m_handle, ::size32(m_dynamic_offsets), m_dynamic_offsets.data()); + VkDescriptorSet sets[1] = { m_handle }; + cmd.bind_descriptor_sets(sets, m_dynamic_offsets, bind_point, layout); } void descriptor_set::flush()