mirror of
https://github.com/yuzu-emu/yuzu.git
synced 2024-11-27 08:14:25 +01:00
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.
This commit is contained in:
parent
33a4cebc22
commit
25c2fe1c6b
@ -2,7 +2,9 @@
|
|||||||
// Licensed under GPLv2 or any later version
|
// Licensed under GPLv2 or any later version
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#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_resource_manager.h"
|
#include "video_core/renderer_vulkan/vk_resource_manager.h"
|
||||||
|
|
||||||
namespace Vulkan {
|
namespace Vulkan {
|
||||||
@ -11,4 +13,70 @@ VKResource::VKResource() = default;
|
|||||||
|
|
||||||
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<u64>::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<u64>::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
|
} // namespace Vulkan
|
||||||
|
@ -4,11 +4,14 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
#include "video_core/renderer_vulkan/declarations.h"
|
#include "video_core/renderer_vulkan/declarations.h"
|
||||||
|
|
||||||
namespace Vulkan {
|
namespace Vulkan {
|
||||||
|
|
||||||
|
class VKDevice;
|
||||||
class VKFence;
|
class VKFence;
|
||||||
|
class VKResourceManager;
|
||||||
|
|
||||||
/// Interface for a Vulkan resource
|
/// Interface for a Vulkan resource
|
||||||
class VKResource {
|
class VKResource {
|
||||||
@ -23,4 +26,64 @@ public:
|
|||||||
virtual void OnFenceRemoval(VKFence* signaling_fence) = 0;
|
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<VKResource*> 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
|
} // namespace Vulkan
|
||||||
|
Loading…
Reference in New Issue
Block a user