From 33a4cebc225454dfd8dc9a7263fe1f4bfb8a9748 Mon Sep 17 00:00:00 2001 From: ReinUsesLisp Date: Thu, 14 Feb 2019 12:52:46 -0300 Subject: [PATCH 1/6] vk_resource_manager: Add VKResource interface VKResource is an interface that gets signaled by a fence when it is free to be reused. --- src/video_core/CMakeLists.txt | 4 ++- .../renderer_vulkan/vk_resource_manager.cpp | 14 ++++++++++ .../renderer_vulkan/vk_resource_manager.h | 26 +++++++++++++++++++ 3 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 src/video_core/renderer_vulkan/vk_resource_manager.cpp create mode 100644 src/video_core/renderer_vulkan/vk_resource_manager.h diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index d35a738d59..59319f2064 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt @@ -105,7 +105,9 @@ if (ENABLE_VULKAN) target_sources(video_core PRIVATE renderer_vulkan/declarations.h renderer_vulkan/vk_device.cpp - renderer_vulkan/vk_device.h) + renderer_vulkan/vk_device.h + renderer_vulkan/vk_resource_manager.cpp + renderer_vulkan/vk_resource_manager.h) target_include_directories(video_core PRIVATE ../../externals/Vulkan-Headers/include) target_compile_definitions(video_core PRIVATE HAS_VULKAN) diff --git a/src/video_core/renderer_vulkan/vk_resource_manager.cpp b/src/video_core/renderer_vulkan/vk_resource_manager.cpp new file mode 100644 index 0000000000..46563748ea --- /dev/null +++ b/src/video_core/renderer_vulkan/vk_resource_manager.cpp @@ -0,0 +1,14 @@ +// Copyright 2018 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "video_core/renderer_vulkan/declarations.h" +#include "video_core/renderer_vulkan/vk_resource_manager.h" + +namespace Vulkan { + +VKResource::VKResource() = default; + +VKResource::~VKResource() = default; + +} // namespace Vulkan diff --git a/src/video_core/renderer_vulkan/vk_resource_manager.h b/src/video_core/renderer_vulkan/vk_resource_manager.h new file mode 100644 index 0000000000..21a53abcd1 --- /dev/null +++ b/src/video_core/renderer_vulkan/vk_resource_manager.h @@ -0,0 +1,26 @@ +// Copyright 2018 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "video_core/renderer_vulkan/declarations.h" + +namespace Vulkan { + +class VKFence; + +/// Interface for a Vulkan resource +class VKResource { +public: + explicit VKResource(); + virtual ~VKResource(); + + /** + * Signals the object that an owning fence has been signaled. + * @param signaling_fence Fence that signals its usage end. + */ + virtual void OnFenceRemoval(VKFence* signaling_fence) = 0; +}; + +} // namespace Vulkan From 25c2fe1c6b7b2ff7164fad0d915fb178d6d68770 Mon Sep 17 00:00:00 2001 From: ReinUsesLisp Date: Thu, 14 Feb 2019 12:57:56 -0300 Subject: [PATCH 2/6] vk_resource_manager: Implement VKFence Fences take ownership of objects, protecting them from GPU-side or driver-side concurrent access. They must be commited from the resource manager. Their usage flow is: commit the fence from the resource manager, protect resources with it and use them, send the fence to an execution queue and Wait for it if needed and then call Release. Used resources will automatically be signaled when they are free to be reused. --- .../renderer_vulkan/vk_resource_manager.cpp | 68 +++++++++++++++++++ .../renderer_vulkan/vk_resource_manager.h | 63 +++++++++++++++++ 2 files changed, 131 insertions(+) diff --git a/src/video_core/renderer_vulkan/vk_resource_manager.cpp b/src/video_core/renderer_vulkan/vk_resource_manager.cpp index 46563748ea..1875bcf547 100644 --- a/src/video_core/renderer_vulkan/vk_resource_manager.cpp +++ b/src/video_core/renderer_vulkan/vk_resource_manager.cpp @@ -2,7 +2,9 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include #include "video_core/renderer_vulkan/declarations.h" +#include "video_core/renderer_vulkan/vk_device.h" #include "video_core/renderer_vulkan/vk_resource_manager.h" namespace Vulkan { @@ -11,4 +13,70 @@ VKResource::VKResource() = default; VKResource::~VKResource() = default; +VKFence::VKFence(const VKDevice& device, UniqueFence handle) + : device{device}, handle{std::move(handle)} {} + +VKFence::~VKFence() = default; + +void VKFence::Wait() { + const auto dev = device.GetLogical(); + const auto& dld = device.GetDispatchLoader(); + dev.waitForFences({*handle}, true, std::numeric_limits::max(), dld); +} + +void VKFence::Release() { + is_owned = false; +} + +void VKFence::Commit() { + is_owned = true; + is_used = true; +} + +bool VKFence::Tick(bool gpu_wait, bool owner_wait) { + if (!is_used) { + // If a fence is not used it's always free. + return true; + } + if (is_owned && !owner_wait) { + // The fence is still being owned (Release has not been called) and ownership wait has + // not been asked. + return false; + } + + const auto dev = device.GetLogical(); + const auto& dld = device.GetDispatchLoader(); + if (gpu_wait) { + // Wait for the fence if it has been requested. + dev.waitForFences({*handle}, true, std::numeric_limits::max(), dld); + } else { + if (dev.getFenceStatus(*handle, dld) != vk::Result::eSuccess) { + // Vulkan fence is not ready, not much it can do here + return false; + } + } + + // Broadcast resources their free state. + for (auto* resource : protected_resources) { + resource->OnFenceRemoval(this); + } + protected_resources.clear(); + + // Prepare fence for reusage. + dev.resetFences({*handle}, dld); + is_used = false; + return true; +} + +void VKFence::Protect(VKResource* resource) { + protected_resources.push_back(resource); +} + +void VKFence::Unprotect(const VKResource* resource) { + const auto it = std::find(protected_resources.begin(), protected_resources.end(), resource); + if (it != protected_resources.end()) { + protected_resources.erase(it); + } +} + } // namespace Vulkan diff --git a/src/video_core/renderer_vulkan/vk_resource_manager.h b/src/video_core/renderer_vulkan/vk_resource_manager.h index 21a53abcd1..aa52007c86 100644 --- a/src/video_core/renderer_vulkan/vk_resource_manager.h +++ b/src/video_core/renderer_vulkan/vk_resource_manager.h @@ -4,11 +4,14 @@ #pragma once +#include #include "video_core/renderer_vulkan/declarations.h" namespace Vulkan { +class VKDevice; class VKFence; +class VKResourceManager; /// Interface for a Vulkan resource class VKResource { @@ -23,4 +26,64 @@ public: virtual void OnFenceRemoval(VKFence* signaling_fence) = 0; }; +/** + * Fences take ownership of objects, protecting them from GPU-side or driver-side concurrent access. + * They must be commited from the resource manager. Their usage flow is: commit the fence from the + * resource manager, protect resources with it and use them, send the fence to an execution queue + * and Wait for it if needed and then call Release. Used resources will automatically be signaled + * when they are free to be reused. + * @brief Protects resources for concurrent usage and signals its release. + */ +class VKFence { + friend class VKResourceManager; + +public: + explicit VKFence(const VKDevice& device, UniqueFence handle); + ~VKFence(); + + /** + * Waits for the fence to be signaled. + * @warning You must have ownership of the fence and it has to be previously sent to a queue to + * call this function. + */ + void Wait(); + + /** + * Releases ownership of the fence. Pass after it has been sent to an execution queue. + * Unmanaged usage of the fence after the call will result in undefined behavior because it may + * be being used for something else. + */ + void Release(); + + /// Protects a resource with this fence. + void Protect(VKResource* resource); + + /// Removes protection for a resource. + void Unprotect(const VKResource* resource); + + /// Retreives the fence. + operator vk::Fence() const { + return *handle; + } + +private: + /// Take ownership of the fence. + void Commit(); + + /** + * Updates the fence status. + * @warning Waiting for the owner might soft lock the execution. + * @param gpu_wait Wait for the fence to be signaled by the driver. + * @param owner_wait Wait for the owner to signal its freedom. + * @returns True if the fence is free. Waiting for gpu and owner will always return true. + */ + bool Tick(bool gpu_wait, bool owner_wait); + + const VKDevice& device; ///< Device handler + UniqueFence handle; ///< Vulkan fence + std::vector protected_resources; ///< List of resources protected by this fence + bool is_owned = false; ///< The fence has been commited but not released yet. + bool is_used = false; ///< The fence has been commited but it has not been checked to be free. +}; + } // namespace Vulkan From aa0b6babdad588d176fc67784f9905709845aa07 Mon Sep 17 00:00:00 2001 From: ReinUsesLisp Date: Thu, 14 Feb 2019 13:06:05 -0300 Subject: [PATCH 3/6] vk_resource_manager: Implement VKFenceWatch A fence watch is used to keep track of the usage of a fence and protect a resource or set of resources without having to inherit from their handlers. --- .../renderer_vulkan/vk_resource_manager.cpp | 38 +++++++++++++++++++ .../renderer_vulkan/vk_resource_manager.h | 30 +++++++++++++++ 2 files changed, 68 insertions(+) diff --git a/src/video_core/renderer_vulkan/vk_resource_manager.cpp b/src/video_core/renderer_vulkan/vk_resource_manager.cpp index 1875bcf547..2e9c6ef34d 100644 --- a/src/video_core/renderer_vulkan/vk_resource_manager.cpp +++ b/src/video_core/renderer_vulkan/vk_resource_manager.cpp @@ -3,6 +3,7 @@ // Refer to the license.txt file included. #include +#include "common/assert.h" #include "video_core/renderer_vulkan/declarations.h" #include "video_core/renderer_vulkan/vk_device.h" #include "video_core/renderer_vulkan/vk_resource_manager.h" @@ -79,4 +80,41 @@ void VKFence::Unprotect(const VKResource* resource) { } } +VKFenceWatch::VKFenceWatch() = default; + +VKFenceWatch::~VKFenceWatch() { + if (fence) { + fence->Unprotect(this); + } +} + +void VKFenceWatch::Wait() { + if (!fence) { + return; + } + fence->Wait(); + fence->Unprotect(this); + fence = nullptr; +} + +void VKFenceWatch::Watch(VKFence& new_fence) { + Wait(); + fence = &new_fence; + fence->Protect(this); +} + +bool VKFenceWatch::TryWatch(VKFence& new_fence) { + if (fence) { + return false; + } + fence = &new_fence; + fence->Protect(this); + return true; +} + +void VKFenceWatch::OnFenceRemoval(VKFence* signaling_fence) { + ASSERT_MSG(signaling_fence == fence, "Removing the wrong fence"); + fence = nullptr; +} + } // namespace Vulkan diff --git a/src/video_core/renderer_vulkan/vk_resource_manager.h b/src/video_core/renderer_vulkan/vk_resource_manager.h index aa52007c86..5345ba46e9 100644 --- a/src/video_core/renderer_vulkan/vk_resource_manager.h +++ b/src/video_core/renderer_vulkan/vk_resource_manager.h @@ -86,4 +86,34 @@ private: bool is_used = false; ///< The fence has been commited but it has not been checked to be free. }; +/** + * A fence watch is used to keep track of the usage of a fence and protect a resource or set of + * resources without having to inherit VKResource from their handlers. + */ +class VKFenceWatch final : public VKResource { +public: + explicit VKFenceWatch(); + ~VKFenceWatch(); + + /// Waits for the fence to be released. + void Wait(); + + /** + * Waits for a previous fence and watches a new one. + * @param new_fence New fence to wait to. + */ + void Watch(VKFence& new_fence); + + /** + * Checks if it's currently being watched and starts watching it if it's available. + * @returns True if a watch has started, false if it's being watched. + */ + bool TryWatch(VKFence& new_fence); + + void OnFenceRemoval(VKFence* signaling_fence) override; + +private: + VKFence* fence{}; ///< Fence watching this resource. nullptr when the watch is free. +}; + } // namespace Vulkan From 0ffdd0a68367770a42455c2a523766d3d57210d1 Mon Sep 17 00:00:00 2001 From: ReinUsesLisp Date: Thu, 14 Feb 2019 13:11:32 -0300 Subject: [PATCH 4/6] vk_resource_manager: Implement VKResourceManager and fence allocator CommitFence iterates a pool of fences until one is found. If all fences are being used at the same time, allocate more. --- .../renderer_vulkan/vk_resource_manager.cpp | 62 +++++++++++++++++++ .../renderer_vulkan/vk_resource_manager.h | 23 +++++++ 2 files changed, 85 insertions(+) diff --git a/src/video_core/renderer_vulkan/vk_resource_manager.cpp b/src/video_core/renderer_vulkan/vk_resource_manager.cpp index 2e9c6ef34d..39c33c8cc6 100644 --- a/src/video_core/renderer_vulkan/vk_resource_manager.cpp +++ b/src/video_core/renderer_vulkan/vk_resource_manager.cpp @@ -4,12 +4,16 @@ #include #include "common/assert.h" +#include "common/logging/log.h" #include "video_core/renderer_vulkan/declarations.h" #include "video_core/renderer_vulkan/vk_device.h" #include "video_core/renderer_vulkan/vk_resource_manager.h" namespace Vulkan { +// TODO(Rodrigo): Fine tune these numbers. +constexpr std::size_t FENCES_GROW_STEP = 0x40; + VKResource::VKResource() = default; VKResource::~VKResource() = default; @@ -117,4 +121,62 @@ void VKFenceWatch::OnFenceRemoval(VKFence* signaling_fence) { fence = nullptr; } +VKResourceManager::VKResourceManager(const VKDevice& device) : device{device} { + GrowFences(FENCES_GROW_STEP); +} + +VKResourceManager::~VKResourceManager() = default; + +VKFence& VKResourceManager::CommitFence() { + const auto StepFences = [&](bool gpu_wait, bool owner_wait) -> VKFence* { + const auto Tick = [=](auto& fence) { return fence->Tick(gpu_wait, owner_wait); }; + const auto hinted = fences.begin() + fences_iterator; + + auto it = std::find_if(hinted, fences.end(), Tick); + if (it == fences.end()) { + it = std::find_if(fences.begin(), hinted, Tick); + if (it == hinted) { + return nullptr; + } + } + fences_iterator = std::distance(fences.begin(), it) + 1; + if (fences_iterator >= fences.size()) + fences_iterator = 0; + + auto& fence = *it; + fence->Commit(); + return fence.get(); + }; + + VKFence* found_fence = StepFences(false, false); + if (!found_fence) { + // Try again, this time waiting. + found_fence = StepFences(true, false); + + if (!found_fence) { + // Allocate new fences and try again. + LOG_INFO(Render_Vulkan, "Allocating new fences {} -> {}", fences.size(), + fences.size() + FENCES_GROW_STEP); + + GrowFences(FENCES_GROW_STEP); + found_fence = StepFences(true, false); + ASSERT(found_fence != nullptr); + } + } + return *found_fence; +} + +void VKResourceManager::GrowFences(std::size_t new_fences_count) { + const auto dev = device.GetLogical(); + const auto& dld = device.GetDispatchLoader(); + const vk::FenceCreateInfo fence_ci; + + const std::size_t previous_size = fences.size(); + fences.resize(previous_size + new_fences_count); + + std::generate(fences.begin() + previous_size, fences.end(), [&]() { + return std::make_unique(device, dev.createFenceUnique(fence_ci, nullptr, dld)); + }); +} + } // namespace Vulkan diff --git a/src/video_core/renderer_vulkan/vk_resource_manager.h b/src/video_core/renderer_vulkan/vk_resource_manager.h index 5345ba46e9..c8759f779f 100644 --- a/src/video_core/renderer_vulkan/vk_resource_manager.h +++ b/src/video_core/renderer_vulkan/vk_resource_manager.h @@ -4,6 +4,8 @@ #pragma once +#include +#include #include #include "video_core/renderer_vulkan/declarations.h" @@ -116,4 +118,25 @@ private: VKFence* fence{}; ///< Fence watching this resource. nullptr when the watch is free. }; +/** + * The resource manager handles all resources that can be protected with a fence avoiding + * driver-side or GPU-side concurrent usage. Usage is documented in VKFence. + */ +class VKResourceManager final { +public: + explicit VKResourceManager(const VKDevice& device); + ~VKResourceManager(); + + /// Commits a fence. It has to be sent to a queue and released. + VKFence& CommitFence(); + +private: + /// Allocates new fences. + void GrowFences(std::size_t new_fences_count); + + const VKDevice& device; ///< Device handler. + std::size_t fences_iterator = 0; ///< Index where a free fence is likely to be found. + std::vector> fences; ///< Pool of fences. +}; + } // namespace Vulkan From a2b6de7e9fd2a2e4956a83a16ded12f3ccfa0ed6 Mon Sep 17 00:00:00 2001 From: ReinUsesLisp Date: Thu, 14 Feb 2019 13:35:03 -0300 Subject: [PATCH 5/6] vk_resource_manager: Add VKFencedPool interface Handles a pool of resources protected by fences. Manages resource overflow allocating more resources. This class is intended to be used through inheritance. --- .../renderer_vulkan/vk_resource_manager.cpp | 51 +++++++++++++++++++ .../renderer_vulkan/vk_resource_manager.h | 32 ++++++++++++ 2 files changed, 83 insertions(+) diff --git a/src/video_core/renderer_vulkan/vk_resource_manager.cpp b/src/video_core/renderer_vulkan/vk_resource_manager.cpp index 39c33c8cc6..e98ddba58a 100644 --- a/src/video_core/renderer_vulkan/vk_resource_manager.cpp +++ b/src/video_core/renderer_vulkan/vk_resource_manager.cpp @@ -3,6 +3,7 @@ // Refer to the license.txt file included. #include +#include #include "common/assert.h" #include "common/logging/log.h" #include "video_core/renderer_vulkan/declarations.h" @@ -121,6 +122,56 @@ void VKFenceWatch::OnFenceRemoval(VKFence* signaling_fence) { fence = nullptr; } +VKFencedPool::VKFencedPool(std::size_t grow_step) : grow_step{grow_step} {} + +VKFencedPool::~VKFencedPool() = default; + +std::size_t VKFencedPool::CommitResource(VKFence& fence) { + const auto Search = [&](std::size_t begin, std::size_t end) -> std::optional { + for (std::size_t iterator = begin; iterator < end; ++iterator) { + if (watches[iterator]->TryWatch(fence)) { + // The resource is now being watched, a free resource was successfully found. + return iterator; + } + } + return {}; + }; + // Try to find a free resource from the hinted position to the end. + auto found = Search(free_iterator, watches.size()); + if (!found) { + // Search from beginning to the hinted position. + found = Search(0, free_iterator); + if (!found) { + // Both searches failed, the pool is full; handle it. + const std::size_t free_resource = ManageOverflow(); + + // Watch will wait for the resource to be free. + watches[free_resource]->Watch(fence); + found = free_resource; + } + } + // Free iterator is hinted to the resource after the one that's been commited. + free_iterator = (*found + 1) % watches.size(); + return *found; +} + +std::size_t VKFencedPool::ManageOverflow() { + const std::size_t old_capacity = watches.size(); + Grow(); + + // The last entry is guaranted to be free, since it's the first element of the freshly + // allocated resources. + return old_capacity; +} + +void VKFencedPool::Grow() { + const std::size_t old_capacity = watches.size(); + watches.resize(old_capacity + grow_step); + std::generate(watches.begin() + old_capacity, watches.end(), + []() { return std::make_unique(); }); + Allocate(old_capacity, old_capacity + grow_step); +} + VKResourceManager::VKResourceManager(const VKDevice& device) : device{device} { GrowFences(FENCES_GROW_STEP); } diff --git a/src/video_core/renderer_vulkan/vk_resource_manager.h b/src/video_core/renderer_vulkan/vk_resource_manager.h index c8759f779f..1fd68bb4c8 100644 --- a/src/video_core/renderer_vulkan/vk_resource_manager.h +++ b/src/video_core/renderer_vulkan/vk_resource_manager.h @@ -118,6 +118,38 @@ private: VKFence* fence{}; ///< Fence watching this resource. nullptr when the watch is free. }; +/** + * Handles a pool of resources protected by fences. Manages resource overflow allocating more + * resources. + */ +class VKFencedPool { +public: + explicit VKFencedPool(std::size_t grow_step); + virtual ~VKFencedPool(); + +protected: + /** + * Commits a free resource and protects it with a fence. It may allocate new resources. + * @param fence Fence that protects the commited resource. + * @returns Index of the resource commited. + */ + std::size_t CommitResource(VKFence& fence); + + /// Called when a chunk of resources have to be allocated. + virtual void Allocate(std::size_t begin, std::size_t end) = 0; + +private: + /// Manages pool overflow allocating new resources. + std::size_t ManageOverflow(); + + /// Allocates a new page of resources. + void Grow(); + + std::size_t grow_step = 0; ///< Number of new resources created after an overflow + std::size_t free_iterator = 0; ///< Hint to where the next free resources is likely to be found + std::vector> watches; ///< Set of watched resources +}; + /** * The resource manager handles all resources that can be protected with a fence avoiding * driver-side or GPU-side concurrent usage. Usage is documented in VKFence. From ae6c052ed9f7e3baed13e1e88e759a3a11d2c928 Mon Sep 17 00:00:00 2001 From: ReinUsesLisp Date: Thu, 14 Feb 2019 13:39:12 -0300 Subject: [PATCH 6/6] vk_resource_manager: Implement a command buffer pool with VKFencedPool --- .../renderer_vulkan/vk_resource_manager.cpp | 52 +++++++++++++++++++ .../renderer_vulkan/vk_resource_manager.h | 8 ++- 2 files changed, 59 insertions(+), 1 deletion(-) diff --git a/src/video_core/renderer_vulkan/vk_resource_manager.cpp b/src/video_core/renderer_vulkan/vk_resource_manager.cpp index e98ddba58a..1678463c7a 100644 --- a/src/video_core/renderer_vulkan/vk_resource_manager.cpp +++ b/src/video_core/renderer_vulkan/vk_resource_manager.cpp @@ -13,8 +13,55 @@ namespace Vulkan { // TODO(Rodrigo): Fine tune these numbers. +constexpr std::size_t COMMAND_BUFFER_POOL_SIZE = 0x1000; constexpr std::size_t FENCES_GROW_STEP = 0x40; +class CommandBufferPool final : public VKFencedPool { +public: + CommandBufferPool(const VKDevice& device) + : VKFencedPool(COMMAND_BUFFER_POOL_SIZE), device{device} {} + + void Allocate(std::size_t begin, std::size_t end) { + const auto dev = device.GetLogical(); + const auto& dld = device.GetDispatchLoader(); + const u32 graphics_family = device.GetGraphicsFamily(); + + auto pool = std::make_unique(); + + // Command buffers are going to be commited, recorded, executed every single usage cycle. + // They are also going to be reseted when commited. + const auto pool_flags = vk::CommandPoolCreateFlagBits::eTransient | + vk::CommandPoolCreateFlagBits::eResetCommandBuffer; + const vk::CommandPoolCreateInfo cmdbuf_pool_ci(pool_flags, graphics_family); + pool->handle = dev.createCommandPoolUnique(cmdbuf_pool_ci, nullptr, dld); + + const vk::CommandBufferAllocateInfo cmdbuf_ai(*pool->handle, + vk::CommandBufferLevel::ePrimary, + static_cast(COMMAND_BUFFER_POOL_SIZE)); + pool->cmdbufs = + dev.allocateCommandBuffersUnique>(cmdbuf_ai, dld); + + pools.push_back(std::move(pool)); + } + + vk::CommandBuffer Commit(VKFence& fence) { + const std::size_t index = CommitResource(fence); + const auto pool_index = index / COMMAND_BUFFER_POOL_SIZE; + const auto sub_index = index % COMMAND_BUFFER_POOL_SIZE; + return *pools[pool_index]->cmdbufs[sub_index]; + } + +private: + struct Pool { + UniqueCommandPool handle; + std::vector cmdbufs; + }; + + const VKDevice& device; + + std::vector> pools; +}; + VKResource::VKResource() = default; VKResource::~VKResource() = default; @@ -174,6 +221,7 @@ void VKFencedPool::Grow() { VKResourceManager::VKResourceManager(const VKDevice& device) : device{device} { GrowFences(FENCES_GROW_STEP); + command_buffer_pool = std::make_unique(device); } VKResourceManager::~VKResourceManager() = default; @@ -217,6 +265,10 @@ VKFence& VKResourceManager::CommitFence() { return *found_fence; } +vk::CommandBuffer VKResourceManager::CommitCommandBuffer(VKFence& fence) { + return command_buffer_pool->Commit(fence); +} + void VKResourceManager::GrowFences(std::size_t new_fences_count) { const auto dev = device.GetLogical(); const auto& dld = device.GetDispatchLoader(); diff --git a/src/video_core/renderer_vulkan/vk_resource_manager.h b/src/video_core/renderer_vulkan/vk_resource_manager.h index 1fd68bb4c8..5018dfa449 100644 --- a/src/video_core/renderer_vulkan/vk_resource_manager.h +++ b/src/video_core/renderer_vulkan/vk_resource_manager.h @@ -15,6 +15,8 @@ class VKDevice; class VKFence; class VKResourceManager; +class CommandBufferPool; + /// Interface for a Vulkan resource class VKResource { public: @@ -162,13 +164,17 @@ public: /// Commits a fence. It has to be sent to a queue and released. VKFence& CommitFence(); + /// Commits an unused command buffer and protects it with a fence. + vk::CommandBuffer CommitCommandBuffer(VKFence& fence); + private: /// Allocates new fences. void GrowFences(std::size_t new_fences_count); const VKDevice& device; ///< Device handler. std::size_t fences_iterator = 0; ///< Index where a free fence is likely to be found. - std::vector> fences; ///< Pool of fences. + std::vector> fences; ///< Pool of fences. + std::unique_ptr command_buffer_pool; ///< Pool of command buffers. }; } // namespace Vulkan