diff options
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_resource_manager.cpp | 68 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_resource_manager.h | 63 |
2 files changed, 131 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 46563748e..1875bcf54 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 @@ | |||
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <algorithm> | ||
| 5 | #include "video_core/renderer_vulkan/declarations.h" | 6 | #include "video_core/renderer_vulkan/declarations.h" |
| 7 | #include "video_core/renderer_vulkan/vk_device.h" | ||
| 6 | #include "video_core/renderer_vulkan/vk_resource_manager.h" | 8 | #include "video_core/renderer_vulkan/vk_resource_manager.h" |
| 7 | 9 | ||
| 8 | namespace Vulkan { | 10 | namespace Vulkan { |
| @@ -11,4 +13,70 @@ VKResource::VKResource() = default; | |||
| 11 | 13 | ||
| 12 | VKResource::~VKResource() = default; | 14 | VKResource::~VKResource() = default; |
| 13 | 15 | ||
| 16 | VKFence::VKFence(const VKDevice& device, UniqueFence handle) | ||
| 17 | : device{device}, handle{std::move(handle)} {} | ||
| 18 | |||
| 19 | VKFence::~VKFence() = default; | ||
| 20 | |||
| 21 | void VKFence::Wait() { | ||
| 22 | const auto dev = device.GetLogical(); | ||
| 23 | const auto& dld = device.GetDispatchLoader(); | ||
| 24 | dev.waitForFences({*handle}, true, std::numeric_limits<u64>::max(), dld); | ||
| 25 | } | ||
| 26 | |||
| 27 | void VKFence::Release() { | ||
| 28 | is_owned = false; | ||
| 29 | } | ||
| 30 | |||
| 31 | void VKFence::Commit() { | ||
| 32 | is_owned = true; | ||
| 33 | is_used = true; | ||
| 34 | } | ||
| 35 | |||
| 36 | bool VKFence::Tick(bool gpu_wait, bool owner_wait) { | ||
| 37 | if (!is_used) { | ||
| 38 | // If a fence is not used it's always free. | ||
| 39 | return true; | ||
| 40 | } | ||
| 41 | if (is_owned && !owner_wait) { | ||
| 42 | // The fence is still being owned (Release has not been called) and ownership wait has | ||
| 43 | // not been asked. | ||
| 44 | return false; | ||
| 45 | } | ||
| 46 | |||
| 47 | const auto dev = device.GetLogical(); | ||
| 48 | const auto& dld = device.GetDispatchLoader(); | ||
| 49 | if (gpu_wait) { | ||
| 50 | // Wait for the fence if it has been requested. | ||
| 51 | dev.waitForFences({*handle}, true, std::numeric_limits<u64>::max(), dld); | ||
| 52 | } else { | ||
| 53 | if (dev.getFenceStatus(*handle, dld) != vk::Result::eSuccess) { | ||
| 54 | // Vulkan fence is not ready, not much it can do here | ||
| 55 | return false; | ||
| 56 | } | ||
| 57 | } | ||
| 58 | |||
| 59 | // Broadcast resources their free state. | ||
| 60 | for (auto* resource : protected_resources) { | ||
| 61 | resource->OnFenceRemoval(this); | ||
| 62 | } | ||
| 63 | protected_resources.clear(); | ||
| 64 | |||
| 65 | // Prepare fence for reusage. | ||
| 66 | dev.resetFences({*handle}, dld); | ||
| 67 | is_used = false; | ||
| 68 | return true; | ||
| 69 | } | ||
| 70 | |||
| 71 | void VKFence::Protect(VKResource* resource) { | ||
| 72 | protected_resources.push_back(resource); | ||
| 73 | } | ||
| 74 | |||
| 75 | void VKFence::Unprotect(const VKResource* resource) { | ||
| 76 | const auto it = std::find(protected_resources.begin(), protected_resources.end(), resource); | ||
| 77 | if (it != protected_resources.end()) { | ||
| 78 | protected_resources.erase(it); | ||
| 79 | } | ||
| 80 | } | ||
| 81 | |||
| 14 | } // namespace Vulkan | 82 | } // 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 21a53abcd..aa52007c8 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 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <vector> | ||
| 7 | #include "video_core/renderer_vulkan/declarations.h" | 8 | #include "video_core/renderer_vulkan/declarations.h" |
| 8 | 9 | ||
| 9 | namespace Vulkan { | 10 | namespace Vulkan { |
| 10 | 11 | ||
| 12 | class VKDevice; | ||
| 11 | class VKFence; | 13 | class VKFence; |
| 14 | class VKResourceManager; | ||
| 12 | 15 | ||
| 13 | /// Interface for a Vulkan resource | 16 | /// Interface for a Vulkan resource |
| 14 | class VKResource { | 17 | class VKResource { |
| @@ -23,4 +26,64 @@ public: | |||
| 23 | virtual void OnFenceRemoval(VKFence* signaling_fence) = 0; | 26 | virtual void OnFenceRemoval(VKFence* signaling_fence) = 0; |
| 24 | }; | 27 | }; |
| 25 | 28 | ||
| 29 | /** | ||
| 30 | * Fences take ownership of objects, protecting them from GPU-side or driver-side concurrent access. | ||
| 31 | * They must be commited from the resource manager. Their usage flow is: commit the fence from the | ||
| 32 | * resource manager, protect resources with it and use them, send the fence to an execution queue | ||
| 33 | * and Wait for it if needed and then call Release. Used resources will automatically be signaled | ||
| 34 | * when they are free to be reused. | ||
| 35 | * @brief Protects resources for concurrent usage and signals its release. | ||
| 36 | */ | ||
| 37 | class VKFence { | ||
| 38 | friend class VKResourceManager; | ||
| 39 | |||
| 40 | public: | ||
| 41 | explicit VKFence(const VKDevice& device, UniqueFence handle); | ||
| 42 | ~VKFence(); | ||
| 43 | |||
| 44 | /** | ||
| 45 | * Waits for the fence to be signaled. | ||
| 46 | * @warning You must have ownership of the fence and it has to be previously sent to a queue to | ||
| 47 | * call this function. | ||
| 48 | */ | ||
| 49 | void Wait(); | ||
| 50 | |||
| 51 | /** | ||
| 52 | * Releases ownership of the fence. Pass after it has been sent to an execution queue. | ||
| 53 | * Unmanaged usage of the fence after the call will result in undefined behavior because it may | ||
| 54 | * be being used for something else. | ||
| 55 | */ | ||
| 56 | void Release(); | ||
| 57 | |||
| 58 | /// Protects a resource with this fence. | ||
| 59 | void Protect(VKResource* resource); | ||
| 60 | |||
| 61 | /// Removes protection for a resource. | ||
| 62 | void Unprotect(const VKResource* resource); | ||
| 63 | |||
| 64 | /// Retreives the fence. | ||
| 65 | operator vk::Fence() const { | ||
| 66 | return *handle; | ||
| 67 | } | ||
| 68 | |||
| 69 | private: | ||
| 70 | /// Take ownership of the fence. | ||
| 71 | void Commit(); | ||
| 72 | |||
| 73 | /** | ||
| 74 | * Updates the fence status. | ||
| 75 | * @warning Waiting for the owner might soft lock the execution. | ||
| 76 | * @param gpu_wait Wait for the fence to be signaled by the driver. | ||
| 77 | * @param owner_wait Wait for the owner to signal its freedom. | ||
| 78 | * @returns True if the fence is free. Waiting for gpu and owner will always return true. | ||
| 79 | */ | ||
| 80 | bool Tick(bool gpu_wait, bool owner_wait); | ||
| 81 | |||
| 82 | const VKDevice& device; ///< Device handler | ||
| 83 | UniqueFence handle; ///< Vulkan fence | ||
| 84 | std::vector<VKResource*> protected_resources; ///< List of resources protected by this fence | ||
| 85 | bool is_owned = false; ///< The fence has been commited but not released yet. | ||
| 86 | bool is_used = false; ///< The fence has been commited but it has not been checked to be free. | ||
| 87 | }; | ||
| 88 | |||
| 26 | } // namespace Vulkan | 89 | } // namespace Vulkan |