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.
This commit is contained in:
parent
0ffdd0a683
commit
a2b6de7e9f
|
@ -3,6 +3,7 @@
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <optional>
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "video_core/renderer_vulkan/declarations.h"
|
#include "video_core/renderer_vulkan/declarations.h"
|
||||||
|
@ -121,6 +122,56 @@ void VKFenceWatch::OnFenceRemoval(VKFence* signaling_fence) {
|
||||||
fence = nullptr;
|
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} {
|
VKResourceManager::VKResourceManager(const VKDevice& device) : device{device} {
|
||||||
GrowFences(FENCES_GROW_STEP);
|
GrowFences(FENCES_GROW_STEP);
|
||||||
}
|
}
|
||||||
|
|
|
@ -118,6 +118,38 @@ 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.
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
* 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.
|
* driver-side or GPU-side concurrent usage. Usage is documented in VKFence.
|
||||||
|
|
Reference in New Issue