[TEST] Refinements on RAII

This commit is contained in:
CamilleLaVey
2026-07-28 21:31:24 -04:00
parent b38556d4f6
commit 9289f5f55a
6 changed files with 86 additions and 5 deletions
@@ -770,6 +770,7 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
Device::~Device() {
ShutdownGPULogging();
vk::FlushDeletionQueue();
vmaDestroyAllocator(allocator);
}
@@ -5,7 +5,10 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include <algorithm>
#include <atomic>
#include <limits>
#include <memory>
#include <mutex>
#include <optional>
#include <thread>
#include <utility>
@@ -24,6 +27,58 @@ namespace {
std::thread::id allocator_owner_thread;
template <typename HandleType>
struct PendingRelease {
VmaAllocator allocator;
HandleType handle;
VmaAllocation allocation;
u64 timeline;
};
std::mutex deletion_mutex;
std::atomic<u64> deletion_timeline{1};
std::vector<PendingRelease<VkImage>> pending_images;
std::vector<PendingRelease<VkBuffer>> pending_buffers;
template <typename HandleType>
void PushPendingRelease(std::vector<PendingRelease<HandleType>>& pending, VmaAllocator allocator,
HandleType handle, VmaAllocation allocation) noexcept {
std::scoped_lock lock{deletion_mutex};
pending.push_back(PendingRelease<HandleType>{
.allocator = allocator,
.handle = handle,
.allocation = allocation,
.timeline = deletion_timeline.load(std::memory_order_acquire),
});
}
template <typename HandleType>
void ExtractReleased(std::vector<PendingRelease<HandleType>>& pending,
std::vector<PendingRelease<HandleType>>& released, u64 completed_value) {
const auto split = std::partition(pending.begin(), pending.end(),
[completed_value](const PendingRelease<HandleType>& entry) {
return entry.timeline > completed_value;
});
released.assign(split, pending.end());
pending.erase(split, pending.end());
}
void DrainDeletionQueue(u64 completed_value) noexcept {
std::vector<PendingRelease<VkImage>> images;
std::vector<PendingRelease<VkBuffer>> buffers;
{
std::scoped_lock lock{deletion_mutex};
ExtractReleased(pending_images, images, completed_value);
ExtractReleased(pending_buffers, buffers, completed_value);
}
for (const auto& entry : images) {
vmaDestroyImage(entry.allocator, entry.handle, entry.allocation);
}
for (const auto& entry : buffers) {
vmaDestroyBuffer(entry.allocator, entry.handle, entry.allocation);
}
}
template <typename Func>
void SortPhysicalDevices(std::vector<VkPhysicalDevice>& devices, const InstanceDispatch& dld,
Func&& func) {
@@ -515,14 +570,26 @@ bool OnAllocatorOwnerThread() noexcept {
allocator_owner_thread == std::this_thread::get_id();
}
void SetDeletionTimeline(u64 value) noexcept {
deletion_timeline.store(value, std::memory_order_release);
}
void TickDeletionQueue(u64 completed_value) noexcept {
DEBUG_ASSERT(OnAllocatorOwnerThread());
DrainDeletionQueue(completed_value);
}
void FlushDeletionQueue() noexcept {
DrainDeletionQueue((std::numeric_limits<u64>::max)());
}
void Image::SetObjectNameEXT(const char* name) const {
SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_IMAGE, name);
}
void Image::Release() const noexcept {
if (handle) {
DEBUG_ASSERT(OnAllocatorOwnerThread());
vmaDestroyImage(allocator, handle, allocation);
PushPendingRelease(pending_images, allocator, handle, allocation);
}
}
@@ -544,8 +611,7 @@ void Buffer::SetObjectNameEXT(const char* name) const {
void Buffer::Release() const noexcept {
if (handle) {
DEBUG_ASSERT(OnAllocatorOwnerThread());
vmaDestroyBuffer(allocator, handle, allocation);
PushPendingRelease(pending_buffers, allocator, handle, allocation);
}
}
@@ -135,6 +135,12 @@ void SetAllocatorOwnerThread();
[[nodiscard]] bool OnAllocatorOwnerThread() noexcept;
void SetDeletionTimeline(u64 value) noexcept;
void TickDeletionQueue(u64 completed_value) noexcept;
void FlushDeletionQueue() noexcept;
/// Throws a Vulkan exception if result is not success.
inline void Check(VkResult result) {
if (result != VK_SUCCESS) {