Просмотр исходного кода

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.
ReinUsesLisp 7 лет назад
Родитель
Сommit
0ffdd0a683

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

@@ -4,12 +4,16 @@
 
 
 #include <algorithm>
 #include <algorithm>
 #include "common/assert.h"
 #include "common/assert.h"
+#include "common/logging/log.h"
 #include "video_core/renderer_vulkan/declarations.h"
 #include "video_core/renderer_vulkan/declarations.h"
 #include "video_core/renderer_vulkan/vk_device.h"
 #include "video_core/renderer_vulkan/vk_device.h"
 #include "video_core/renderer_vulkan/vk_resource_manager.h"
 #include "video_core/renderer_vulkan/vk_resource_manager.h"
 
 
 namespace Vulkan {
 namespace Vulkan {
 
 
+// TODO(Rodrigo): Fine tune these numbers.
+constexpr std::size_t FENCES_GROW_STEP = 0x40;
+
 VKResource::VKResource() = default;
 VKResource::VKResource() = default;
 
 
 VKResource::~VKResource() = default;
 VKResource::~VKResource() = default;
@@ -117,4 +121,62 @@ void VKFenceWatch::OnFenceRemoval(VKFence* signaling_fence) {
     fence = nullptr;
     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<VKFence>(device, dev.createFenceUnique(fence_ci, nullptr, dld));
+    });
+}
+
 } // namespace Vulkan
 } // namespace Vulkan

+ 23 - 0
src/video_core/renderer_vulkan/vk_resource_manager.h

@@ -4,6 +4,8 @@
 
 
 #pragma once
 #pragma once
 
 
+#include <cstddef>
+#include <memory>
 #include <vector>
 #include <vector>
 #include "video_core/renderer_vulkan/declarations.h"
 #include "video_core/renderer_vulkan/declarations.h"
 
 
@@ -116,4 +118,25 @@ private:
     VKFence* fence{}; ///< Fence watching this resource. nullptr when the watch is free.
     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<std::unique_ptr<VKFence>> fences; ///< Pool of fences.
+};
+
 } // namespace Vulkan
 } // namespace Vulkan