diff options
Diffstat (limited to '')
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_resource_manager.cpp | 51 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_resource_manager.h | 32 |
2 files changed, 83 insertions, 0 deletions
diff --git a/src/video_core/renderer_vulkan/vk_resource_manager.cpp b/src/video_core/renderer_vulkan/vk_resource_manager.cpp index 39c33c8cc..e98ddba58 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 @@ | |||
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <algorithm> | 5 | #include <algorithm> |
| 6 | #include <optional> | ||
| 6 | #include "common/assert.h" | 7 | #include "common/assert.h" |
| 7 | #include "common/logging/log.h" | 8 | #include "common/logging/log.h" |
| 8 | #include "video_core/renderer_vulkan/declarations.h" | 9 | #include "video_core/renderer_vulkan/declarations.h" |
| @@ -121,6 +122,56 @@ void VKFenceWatch::OnFenceRemoval(VKFence* signaling_fence) { | |||
| 121 | fence = nullptr; | 122 | fence = nullptr; |
| 122 | } | 123 | } |
| 123 | 124 | ||
| 125 | VKFencedPool::VKFencedPool(std::size_t grow_step) : grow_step{grow_step} {} | ||
| 126 | |||
| 127 | VKFencedPool::~VKFencedPool() = default; | ||
| 128 | |||
| 129 | std::size_t VKFencedPool::CommitResource(VKFence& fence) { | ||
| 130 | const auto Search = [&](std::size_t begin, std::size_t end) -> std::optional<std::size_t> { | ||
| 131 | for (std::size_t iterator = begin; iterator < end; ++iterator) { | ||
| 132 | if (watches[iterator]->TryWatch(fence)) { | ||
| 133 | // The resource is now being watched, a free resource was successfully found. | ||
| 134 | return iterator; | ||
| 135 | } | ||
| 136 | } | ||
| 137 | return {}; | ||
| 138 | }; | ||
| 139 | // Try to find a free resource from the hinted position to the end. | ||
| 140 | auto found = Search(free_iterator, watches.size()); | ||
| 141 | if (!found) { | ||
| 142 | // Search from beginning to the hinted position. | ||
| 143 | found = Search(0, free_iterator); | ||
| 144 | if (!found) { | ||
| 145 | // Both searches failed, the pool is full; handle it. | ||
| 146 | const std::size_t free_resource = ManageOverflow(); | ||
| 147 | |||
| 148 | // Watch will wait for the resource to be free. | ||
| 149 | watches[free_resource]->Watch(fence); | ||
| 150 | found = free_resource; | ||
| 151 | } | ||
| 152 | } | ||
| 153 | // Free iterator is hinted to the resource after the one that's been commited. | ||
| 154 | free_iterator = (*found + 1) % watches.size(); | ||
| 155 | return *found; | ||
| 156 | } | ||
| 157 | |||
| 158 | std::size_t VKFencedPool::ManageOverflow() { | ||
| 159 | const std::size_t old_capacity = watches.size(); | ||
| 160 | Grow(); | ||
| 161 | |||
| 162 | // The last entry is guaranted to be free, since it's the first element of the freshly | ||
| 163 | // allocated resources. | ||
| 164 | return old_capacity; | ||
| 165 | } | ||
| 166 | |||
| 167 | void VKFencedPool::Grow() { | ||
| 168 | const std::size_t old_capacity = watches.size(); | ||
| 169 | watches.resize(old_capacity + grow_step); | ||
| 170 | std::generate(watches.begin() + old_capacity, watches.end(), | ||
| 171 | []() { return std::make_unique<VKFenceWatch>(); }); | ||
| 172 | Allocate(old_capacity, old_capacity + grow_step); | ||
| 173 | } | ||
| 174 | |||
| 124 | VKResourceManager::VKResourceManager(const VKDevice& device) : device{device} { | 175 | VKResourceManager::VKResourceManager(const VKDevice& device) : device{device} { |
| 125 | GrowFences(FENCES_GROW_STEP); | 176 | GrowFences(FENCES_GROW_STEP); |
| 126 | } | 177 | } |
diff --git a/src/video_core/renderer_vulkan/vk_resource_manager.h b/src/video_core/renderer_vulkan/vk_resource_manager.h index c8759f779..1fd68bb4c 100644 --- a/src/video_core/renderer_vulkan/vk_resource_manager.h +++ b/src/video_core/renderer_vulkan/vk_resource_manager.h | |||
| @@ -119,6 +119,38 @@ private: | |||
| 119 | }; | 119 | }; |
| 120 | 120 | ||
| 121 | /** | 121 | /** |
| 122 | * Handles a pool of resources protected by fences. Manages resource overflow allocating more | ||
| 123 | * resources. | ||
| 124 | */ | ||
| 125 | class VKFencedPool { | ||
| 126 | public: | ||
| 127 | explicit VKFencedPool(std::size_t grow_step); | ||
| 128 | virtual ~VKFencedPool(); | ||
| 129 | |||
| 130 | protected: | ||
| 131 | /** | ||
| 132 | * Commits a free resource and protects it with a fence. It may allocate new resources. | ||
| 133 | * @param fence Fence that protects the commited resource. | ||
| 134 | * @returns Index of the resource commited. | ||
| 135 | */ | ||
| 136 | std::size_t CommitResource(VKFence& fence); | ||
| 137 | |||
| 138 | /// Called when a chunk of resources have to be allocated. | ||
| 139 | virtual void Allocate(std::size_t begin, std::size_t end) = 0; | ||
| 140 | |||
| 141 | private: | ||
| 142 | /// Manages pool overflow allocating new resources. | ||
| 143 | std::size_t ManageOverflow(); | ||
| 144 | |||
| 145 | /// Allocates a new page of resources. | ||
| 146 | void Grow(); | ||
| 147 | |||
| 148 | std::size_t grow_step = 0; ///< Number of new resources created after an overflow | ||
| 149 | std::size_t free_iterator = 0; ///< Hint to where the next free resources is likely to be found | ||
| 150 | std::vector<std::unique_ptr<VKFenceWatch>> watches; ///< Set of watched resources | ||
| 151 | }; | ||
| 152 | |||
| 153 | /** | ||
| 122 | * The resource manager handles all resources that can be protected with a fence avoiding | 154 | * The resource manager handles all resources that can be protected with a fence avoiding |
| 123 | * driver-side or GPU-side concurrent usage. Usage is documented in VKFence. | 155 | * driver-side or GPU-side concurrent usage. Usage is documented in VKFence. |
| 124 | */ | 156 | */ |