Преглед изворни кода

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.
ReinUsesLisp пре 7 година
родитељ
комит
a2b6de7e9f

+ 51 - 0
src/video_core/renderer_vulkan/vk_resource_manager.cpp

@@ -3,6 +3,7 @@
 // Refer to the license.txt file included.
 
 #include <algorithm>
+#include <optional>
 #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<std::size_t> {
+        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<VKFenceWatch>(); });
+    Allocate(old_capacity, old_capacity + grow_step);
+}
+
 VKResourceManager::VKResourceManager(const VKDevice& device) : device{device} {
     GrowFences(FENCES_GROW_STEP);
 }

+ 32 - 0
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<std::unique_ptr<VKFenceWatch>> 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.