fix: replace runtime waitIdle calls with a deletion queue

This commit is contained in:
2026-10-19 00:45:24 +02:00
parent 36341bb5e0
commit 997844eaa7
29 changed files with 290 additions and 101 deletions
@@ -4,6 +4,7 @@
#pragma once
#include <filesystem>
#include <memory>
#include <unordered_map>
#include <vector>
@@ -28,6 +29,7 @@ public:
ImageID addImage(GPUImage image);
ImageID addImage(ImageID id, GPUImage image);
[[nodiscard]] const GPUImage& getImage(ImageID id) const;
void removeImage(ImageID id);
[[nodiscard]] ImageID getFreeImageId() const;
[[nodiscard]] std::uint32_t getMaxImageCount() const {
@@ -52,6 +54,7 @@ public:
private:
std::vector<GPUImage> images;
std::shared_ptr<std::vector<ImageID>> freeIds = std::make_shared<std::vector<ImageID>>();
GfxDevice& gfxDevice;
struct LoadedImageInfo {
@@ -47,7 +47,7 @@ public:
Material& getMaterialMutable(MaterialID id);
void updateMaterialGPU(MaterialID id);
[[nodiscard]] MaterialData getMaterialData(MaterialID id) const;
private:
[[nodiscard]] MaterialData toMaterialData(const Material& material) const;
@@ -0,0 +1,29 @@
#ifndef DELETIONQUEUE_H
#define DELETIONQUEUE_H
#include <cstddef>
#include <cstdint>
#include <deque>
#include <functional>
class DeletionQueue {
public:
void push(std::uint64_t retiredInFrame, std::function<void()>&& deleter);
void flush(std::uint64_t lastCompletedFrame);
void flushAll();
[[nodiscard]] std::size_t size() const { return entries.size(); }
[[nodiscard]] bool empty() const { return entries.empty(); }
private:
struct Entry {
std::uint64_t frame;
std::function<void()> deleter;
};
std::deque<Entry> entries;
};
#endif // DELETIONQUEUE_H
@@ -0,0 +1,8 @@
#ifndef FRAMECONFIG_H
#define FRAMECONFIG_H
#include <cstdint>
inline constexpr std::uint32_t FRAMES_IN_FLIGHT = 2;
#endif // FRAMECONFIG_H
+18 -2
View File
@@ -16,6 +16,7 @@
#include <glm/vec2.hpp>
#include <glm/vec4.hpp>
#include <destrum/Graphics/DeletionQueue.h>
#include <destrum/Graphics/GPUImage.h>
#include <destrum/Graphics/Swapchain.h>
#include <destrum/Graphics/Resources/Buffer.h>
@@ -113,7 +114,8 @@ public:
return memoryManager.createBuffer(allocSize, usage, memoryUsage);
}
void destroyBuffer(GPUBuffer& buffer) const
void destroyBuffer(GPUBuffer& buffer);
void destroyBufferNow(GPUBuffer& buffer) const
{
memoryManager.destroyBuffer(buffer);
}
@@ -148,11 +150,24 @@ public:
imageManager.uploadImageData(image, pixelData, byteSize, layer);
}
void destroyImage(GPUImage& image) const
void destroyImage(GPUImage& image);
void destroyImageNow(GPUImage& image) const
{
imageManager.destroyImage(image);
}
void deferDestroy(std::function<void()>&& deleter);
[[nodiscard]] std::uint64_t getFrameNumber() const
{
return frameManager.getFrameNumber();
}
[[nodiscard]] std::size_t getPendingDeletionCount() const
{
return deletionQueue.size();
}
[[nodiscard]] VkDevice getVkDevice() const
{
return instanceManager.getDevice();
@@ -228,6 +243,7 @@ private:
ImageManager imageManager;
VulkanImmediateExecutor executor;
DeletionQueue deletionQueue;
Swapchain swapchain;
VkFormat swapchainFormat{VK_FORMAT_UNDEFINED};
@@ -6,6 +6,8 @@
#include <vulkan/vulkan.h>
#include <destrum/Graphics/FrameConfig.h>
class FrameManager {
public:
struct FrameData {
@@ -27,10 +29,12 @@ public:
[[nodiscard]] VkCommandBuffer beginFrame();
void endFrame(VkCommandBuffer cmd);
void waitIdle() const;
[[nodiscard]] std::uint32_t getCurrentFrameIndex() const {
return frameNumber % 2;
return static_cast<std::uint32_t>(frameNumber % FRAMES_IN_FLIGHT);
}
[[nodiscard]] std::uint64_t getFrameNumber() const {
return frameNumber;
}
[[nodiscard]] FrameData& getCurrentFrame() {
@@ -48,9 +52,8 @@ public:
void nextFrame();
private:
static constexpr std::size_t FRAMES_IN_FLIGHT = 2;
std::array<FrameData, FRAMES_IN_FLIGHT> frames{};
std::uint32_t frameNumber{0};
std::uint64_t frameNumber{0};
VkDevice device{VK_NULL_HANDLE};
};
@@ -46,6 +46,7 @@ public:
TextureIntent intent = TextureIntent::ColorSrgb);
ImageID addImageToCache(GPUImage image);
void destroyImage(ImageID id);
// Imports a file-backed model and uploads its mesh/material resources.
// References are keyed as "source#subresource" in the resource caches.
+2 -1
View File
@@ -65,7 +65,6 @@ public:
void setSkyboxTexture(ImageID skyboxImageId);
void flushMaterialUpdates(GfxDevice& gfxDevice);
[[nodiscard]] SkinningPipeline& getSkinningPipeline() const
{
@@ -119,6 +118,8 @@ private:
RenderResources* resources = nullptr;
void recordMaterialUpdates(VkCommandBuffer cmd);
std::vector<MaterialID> pendingMaterialUploads;
+1 -1
View File
@@ -8,7 +8,7 @@
#include <VkBootstrap.h>
static constexpr int FRAMES_IN_FLIGHT = 2;
#include <destrum/Graphics/FrameConfig.h>
class Swapchain {
public:
+12
View File
@@ -83,6 +83,18 @@ namespace vkutil {
VkDeviceSize offset = 0,
VkDeviceSize size = VK_WHOLE_SIZE);
void bufferShaderReadToTransferWriteBarrier(
VkCommandBuffer cmd,
VkBuffer buffer,
VkDeviceSize offset = 0,
VkDeviceSize size = VK_WHOLE_SIZE);
void bufferHostAndTransferWriteToShaderReadBarrier(
VkCommandBuffer cmd,
VkBuffer buffer,
VkDeviceSize offset = 0,
VkDeviceSize size = VK_WHOLE_SIZE);
void bufferHostWriteToTransferReadBarrier(
VkCommandBuffer cmd,
VkBuffer buffer,