60 lines
2.2 KiB
C++
60 lines
2.2 KiB
C++
|
|
//SPDX-License-Identifier: LGPL-3.0-only
|
||
|
|
//SPDX-FileCopyrightText: Copyright (C) 2026 Catcrafts®
|
||
|
|
|
||
|
|
// The deletion queue takes handles from any thread. Every Vulkan handle
|
||
|
|
// owner's destructor queues its handles, and owners go where they're made: a
|
||
|
|
// loader thread drops the buffers of a model it built while the render loop
|
||
|
|
// reclaims the queue each frame. The queue was a plain deque, so those
|
||
|
|
// pushes and pops raced and corrupted it.
|
||
|
|
//
|
||
|
|
// Four threads make and drop buffers while this one steps frames and
|
||
|
|
// reclaims, as Window::Render does; then everything has to drain cleanly.
|
||
|
|
//
|
||
|
|
// Needs a Vulkan device and no window.
|
||
|
|
|
||
|
|
#include <cstdlib>
|
||
|
|
#include "vulkan/vulkan.h"
|
||
|
|
|
||
|
|
import Crafter.Graphics;
|
||
|
|
import std;
|
||
|
|
|
||
|
|
using namespace Crafter;
|
||
|
|
|
||
|
|
int main() {
|
||
|
|
Device::Initialize();
|
||
|
|
Device::framesInFlight = 2;
|
||
|
|
Device::frameCounter = 0;
|
||
|
|
|
||
|
|
// Each round, every thread makes its buffers, then all drop theirs at
|
||
|
|
// once, so the queue's pushes overlap each other and the reclaims.
|
||
|
|
constexpr int kThreads = 4;
|
||
|
|
constexpr int kBuffers = 400;
|
||
|
|
constexpr int kRounds = 5;
|
||
|
|
for (int round = 0; round < kRounds; ++round) {
|
||
|
|
std::latch made(kThreads + 1);
|
||
|
|
std::atomic<int> dropping = kThreads;
|
||
|
|
std::vector<std::thread> makers;
|
||
|
|
for (int t = 0; t < kThreads; ++t) {
|
||
|
|
makers.emplace_back([&] {
|
||
|
|
std::vector<VulkanBuffer<std::uint32_t, false>> buffers(kBuffers);
|
||
|
|
for (VulkanBuffer<std::uint32_t, false>& buffer : buffers) {
|
||
|
|
buffer.Create(VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, 16);
|
||
|
|
}
|
||
|
|
made.arrive_and_wait();
|
||
|
|
buffers.clear();
|
||
|
|
--dropping;
|
||
|
|
});
|
||
|
|
}
|
||
|
|
made.arrive_and_wait();
|
||
|
|
while (dropping > 0) {
|
||
|
|
++Device::frameCounter;
|
||
|
|
Device::ReclaimDeletions();
|
||
|
|
}
|
||
|
|
for (std::thread& maker : makers) maker.join();
|
||
|
|
}
|
||
|
|
Device::DrainDeletions();
|
||
|
|
|
||
|
|
const bool empty = Device::deletionQueue.empty();
|
||
|
|
std::println("{} {} buffers dropped at once on {} threads while frames were reclaimed, {} times, and drained", empty ? "PASS" : "FAIL", kThreads * kBuffers, kThreads, kRounds);
|
||
|
|
return empty ? EXIT_SUCCESS : EXIT_FAILURE;
|
||
|
|
}
|