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.
This commit is contained in:
parent
aa0b6babda
commit
0ffdd0a683
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
Reference in New Issue