Added GPUManged interface for resource deletion

This commit is contained in:
antopilo
2025-01-31 20:56:58 -05:00
parent f54fe85d09
commit cd6eb2a682
10 changed files with 178 additions and 35 deletions

View File

@@ -0,0 +1,23 @@
#include "GPUManaged.h"
using namespace Nuake;
void GPUManaged::SetDebugName(const std::string& inDebugName)
{
this->debugName = inDebugName;
}
std::string_view GPUManaged::GetDebugName() const
{
return this->debugName;
}
void GPUManaged::AddGPUCleanUpFunc(CleanUpFunc cleanUpFunc)
{
this->cleanUpQueue.push(cleanUpFunc);
}
CleanUpStack GPUManaged::GetGPUCleanUpStack()
{
return this->cleanUpQueue;
}

View File

@@ -0,0 +1,25 @@
#pragma once
#include <functional>
#include <stack>
#include <string>
namespace Nuake
{
using CleanUpFunc = std::function<void()>;
using CleanUpStack = std::stack<CleanUpFunc>;
class GPUManaged
{
protected:
std::string debugName;
CleanUpStack cleanUpQueue;
public:
virtual void SetDebugName(const std::string& inName);
std::string_view GetDebugName() const;
void AddGPUCleanUpFunc(CleanUpFunc cleanUpFunc);
CleanUpStack GetGPUCleanUpStack();
};
}

View File

@@ -87,13 +87,22 @@ SceneRenderPipeline::SceneRenderPipeline()
// Initialize render targets
const Vector2 defaultSize = { 1, 1 };
GBufferAlbedo = CreateRef<VulkanImage>(ImageFormat::RGBA16F, defaultSize);
GBufferAlbedo->SetDebugName("GBufferAlbedo");
GBufferNormal = CreateRef<VulkanImage>(ImageFormat::RGBA16F, defaultSize);
GBufferNormal->SetDebugName("GBufferNormal");
GBufferMaterial = CreateRef<VulkanImage>(ImageFormat::RGBA8, defaultSize);
GBufferMaterial->SetDebugName("GBufferMaterial");
GBufferDepth = CreateRef<VulkanImage>(ImageFormat::D32F, defaultSize, ImageUsage::Depth);
GBufferDepth->SetDebugName("GBufferDepth");
ShadingOutput = CreateRef<VulkanImage>(ImageFormat::RGBA16F, defaultSize);
GBufferDepth->SetDebugName("ShadingOutput");
TonemappedOutput = CreateRef<VulkanImage>(ImageFormat::RGBA8, defaultSize);
TonemappedOutput->SetDebugName("TonemappedOutput");
// Setup bloom targets
BloomOutput = CreateRef<VulkanImage>(ImageFormat::RGBA16F, defaultSize);
@@ -264,12 +273,12 @@ void SceneRenderPipeline::SetCamera(UUID camera)
void SceneRenderPipeline::Render(PassRenderContext& ctx)
{
// Resize textures
GBufferAlbedo = ResizeImage(GBufferAlbedo, ctx.resolution);
GBufferDepth = ResizeImage(GBufferDepth, ctx.resolution);
GBufferNormal = ResizeImage(GBufferNormal, ctx.resolution);
GBufferMaterial = ResizeImage(GBufferMaterial, ctx.resolution);
ShadingOutput = ResizeImage(ShadingOutput, ctx.resolution);
TonemappedOutput = ResizeImage(TonemappedOutput, ctx.resolution);
GBufferAlbedo = ResizeImage(ctx, GBufferAlbedo, ctx.resolution);
GBufferDepth = ResizeImage(ctx, GBufferDepth, ctx.resolution);
GBufferNormal = ResizeImage(ctx, GBufferNormal, ctx.resolution);
GBufferMaterial = ResizeImage(ctx, GBufferMaterial, ctx.resolution);
ShadingOutput = ResizeImage(ctx, ShadingOutput, ctx.resolution);
TonemappedOutput = ResizeImage(ctx, TonemappedOutput, ctx.resolution);
PipelineAttachments pipelineInputs
{
@@ -285,7 +294,7 @@ void SceneRenderPipeline::Render(PassRenderContext& ctx)
OnDebugDraw().Broadcast(debugCmd);
}
Ref<VulkanImage> SceneRenderPipeline::ResizeImage(Ref<VulkanImage> image, const Vector2& size)
Ref<VulkanImage> SceneRenderPipeline::ResizeImage(PassRenderContext& ctx, Ref<VulkanImage> image, const Vector2& size)
{
if (image->GetSize() == size)
{
@@ -293,12 +302,14 @@ Ref<VulkanImage> SceneRenderPipeline::ResizeImage(Ref<VulkanImage> image, const
}
Ref<VulkanImage> newAttachment = std::make_shared<VulkanImage>(image->GetFormat(), size, image->GetUsage());
newAttachment->SetDebugName(image->GetDebugName().data());
// Register to resource manager
GPUResources& gpuResources = GPUResources::Get();
gpuResources.AddTexture(newAttachment);
gpuResources.RemoveTexture(image);
// We might need to do this?
//newAttachment->TransitionLayout(ctx.commandBuffer, VK_IMAGE_LAYOUT_GENERAL);
ctx.commandBuffer.TransitionImageLayout(newAttachment, VK_IMAGE_LAYOUT_GENERAL);
return newAttachment;
}

View File

@@ -113,6 +113,6 @@ namespace Nuake
MulticastDelegate<DebugCmd&>& OnDebugDraw() { return DebugDrawDelegate; }
private:
Ref<VulkanImage> ResizeImage(Ref<VulkanImage> image, const Vector2& size);
Ref<VulkanImage> ResizeImage(PassRenderContext& ctx, Ref<VulkanImage> image, const Vector2& size);
};
}

View File

@@ -3,13 +3,13 @@
#include "Nuake/Core/Logger.h"
#include "Nuake/Resource/UUID.h"
#include "Nuake/Rendering/Textures/TextureManager.h"
#include "Nuake/Rendering/Vertex.h"
#include "Nuake/Rendering/Vulkan/DescriptorLayoutBuilder.h"
#include "Nuake/Rendering/Vulkan/GPUManaged.h"
#include "Nuake/Rendering/Vulkan/VkMesh.h"
#include "Nuake/Rendering/Vulkan/VulkanAllocatedBuffer.h"
#include "Nuake/Rendering/Vulkan/VulkanImage/VulkanImage.h"
#include "Nuake/Rendering/Vulkan/VkMesh.h"
#include "Nuake/Rendering/Textures/TextureManager.h"
#include "Nuake/Rendering/Vulkan/VulkanAllocatedBuffer.h"
#include "Nuake/Rendering/Vulkan/DescriptorLayoutBuilder.h"
#include "Nuake/Rendering/Vulkan/VulkanRenderer.h"
#include <volk/volk.h>
@@ -166,6 +166,7 @@ namespace Nuake
Ref<VkMesh> GetMesh(const UUID& id);
bool AddTexture(Ref<VulkanImage> image);
void RemoveTexture(Ref<VulkanImage> image);
Ref<VulkanImage> GetTexture(const UUID& id);
std::vector<Ref<VulkanImage>> GetAllTextures();
@@ -185,7 +186,7 @@ namespace Nuake
void RecreateBindlessCameras();
void UpdateBuffers();
void QueueDeletion(std::function<void()> func);
void QueueDeletion(CleanUpStack func);
void CleanUp();
private:
void CreateBindlessLayout();

View File

@@ -15,6 +15,7 @@ using namespace Nuake;
#include "vk_mem_alloc.h"
#include <stb_image/stb_image.h>
#include <Nuake/Rendering/Vulkan/VkResources.h>
VulkanImage::VulkanImage(const std::string & path) :
ImGuiDescriptorSetGenerated(false),
@@ -126,7 +127,7 @@ VulkanImage::VulkanImage(ImageFormat inFormat, Vector2 inSize, ImageUsage usage)
imgAllocInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
imgAllocInfo.requiredFlags = VkMemoryPropertyFlags(VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
vmaCreateImage(VulkanAllocator::Get().GetAllocator(), &imgCreateInfo, &imgAllocInfo, &Image, &Allocation, nullptr);
VK_CALL(vmaCreateImage(VulkanAllocator::Get().GetAllocator(), &imgCreateInfo, &imgAllocInfo, &Image, &Allocation, nullptr));
VkImageViewCreateInfo imageViewCreateInfo = {};
if (usage == ImageUsage::Depth)
@@ -140,7 +141,27 @@ VulkanImage::VulkanImage(ImageFormat inFormat, Vector2 inSize, ImageUsage usage)
VK_CALL(vkCreateImageView(VkRenderer::Get().GetDevice(), &imageViewCreateInfo, nullptr, &ImageView));
Logger::Log("Image created", "vulkan", VERBOSE);
VulkanImageCleanUpData cleanUpData
{
Allocation,
ImageView,
Image
};
AddGPUCleanUpFunc([=]() {
VulkanImageCleanUpData dataCopy = cleanUpData;
VmaAllocationInfo info;
vmaGetAllocationInfo(VulkanAllocator::Get().GetAllocator(), dataCopy.Allocation, &info);
if (info.pName)
{
Logger::Log("Deleting " + std::string(info.pName), "Vulkan", VERBOSE);
}
vkDestroyImageView(VkRenderer::Get().GetDevice(), dataCopy.ImageView, nullptr);
vmaDestroyImage(VulkanAllocator::Get().GetAllocator(), dataCopy.Image, dataCopy.Allocation);
});
}
VulkanImage::VulkanImage(void* inData, ImageFormat inFormat, Vector2 inSize) : VulkanImage(inFormat, inSize)
@@ -206,7 +227,10 @@ VulkanImage::VulkanImage(void* inData, ImageFormat inFormat, Vector2 inSize) : V
}
);
// TODO: Clean up temporary buffer! we leak memory here
AddGPUCleanUpFunc([=]() {
//vkDestroyImageView(VkRenderer::Get().GetDevice(), ImageView, nullptr);
//vmaDestroyImage(VulkanAllocator::Get().GetAllocator(), Image, Allocation);
});
}
VulkanImage::VulkanImage(void* inData, size_t inSize) :
@@ -253,6 +277,7 @@ VulkanImage::VulkanImage(void* inData, size_t inSize) :
imgAllocInfo.requiredFlags = VkMemoryPropertyFlags(VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
vmaCreateImage(VulkanAllocator::Get().GetAllocator(), &imgCreateInfo, &imgAllocInfo, &Image, &Allocation, nullptr);
VkImageViewCreateInfo imageViewCreateInfo = VulkanInit::ImageviewCreateInfo(static_cast<VkFormat>(Format), Image, VK_IMAGE_ASPECT_COLOR_BIT);
@@ -278,12 +303,24 @@ VulkanImage::VulkanImage(void* inData, size_t inSize) :
TransitionLayout(cmd, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
//VulkanUtil::TransitionImage(cmd, Image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
});
AddGPUCleanUpFunc([=]() {
//vkDestroyImageView(VkRenderer::Get().GetDevice(), ImageView, nullptr);
//vmaDestroyImage(VulkanAllocator::Get().GetAllocator(), Image, Allocation);
});
}
VulkanImage::~VulkanImage()
{
// TODO: deletion of image
Logger::Log("Deleting VulkanImage", "vulkan", VERBOSE);
GPUResources::Get().QueueDeletion(GetGPUCleanUpStack());
}
void VulkanImage::SetDebugName(const std::string& name)
{
GPUManaged::SetDebugName(name);
vmaSetAllocationName(VulkanAllocator::Get().GetAllocator(), Allocation, GetDebugName().data());
}
void VulkanImage::TransitionLayout(VkCommandBuffer cmd, VkImageLayout layout)
@@ -345,6 +382,24 @@ VkDescriptorSet& VulkanImage::GetImGuiDescriptorSet()
ImGuiDescriptorSet = ImGui_ImplVulkan_AddTexture(Sampler, ImageView, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
ImGuiDescriptorSetGenerated = true;
struct cleanUpData
{
VkDescriptorSet descriptorSet;
VkSampler sampler;
};
cleanUpData dataToCleanUp
{
ImGuiDescriptorSet,
Sampler
};
AddGPUCleanUpFunc([=]() {
cleanUpData data = dataToCleanUp;
ImGui_ImplVulkan_RemoveTexture(data.descriptorSet);
vkDestroySampler(VkRenderer::Get().GetDevice(), data.sampler, nullptr);
});
}
return ImGuiDescriptorSet;

View File

@@ -3,8 +3,11 @@
#include "Nuake/Core/Maths.h"
#include "Nuake/Resource/UUID.h"
#include "Nuake/Rendering/Vulkan/GPUManaged.h"
#include "volk/volk.h"
#include "vk_mem_alloc.h"
#include <string>
namespace Nuake
@@ -32,7 +35,14 @@ namespace Nuake
Default
};
class VulkanImage
struct VulkanImageCleanUpData
{
VmaAllocation Allocation;
VkImageView ImageView;
VkImage Image;
};
class VulkanImage : public GPUManaged
{
private:
UUID ID;
@@ -46,6 +56,7 @@ namespace Nuake
bool ImGuiDescriptorSetGenerated;
VkDescriptorSet ImGuiDescriptorSet;
ImageUsage Usage;
public:
VulkanImage(const std::string& path);
VulkanImage(ImageFormat format, Vector2 size, ImageUsage usage = ImageUsage::Default);
@@ -54,6 +65,9 @@ namespace Nuake
~VulkanImage();
public:
void SetDebugName(const std::string& name) override;
void TransitionLayout(VkCommandBuffer cmd, VkImageLayout layout);
Vector2 GetSize() const { return Vector2(Extent.x, Extent.y); }

View File

@@ -251,16 +251,6 @@ void VkRenderer::CreateSwapchain(const Vector2& size)
SwapchainImageViews = vkbSwapchain.get_image_views().value();
SurfaceSize = size;
//draw image size will match the window
VkExtent3D drawImageExtent = {
size.x,
size.y,
1
};
DrawImage = CreateRef<VulkanImage>(ImageFormat::RGBA16F, size);
DepthImage = CreateRef<VulkanImage>(ImageFormat::D32F, size, ImageUsage::Depth);
}
void VkRenderer::DestroySwapchain()
@@ -378,6 +368,8 @@ void VkRenderer::DrawScenes()
Ref<Viewport> viewport = Viewports[view];
assert(viewport && "Viewport is null");
viewport->Resize();
ctx.CameraID = viewport->GetViewID();
ctx.Size = viewport->GetRenderTarget()->GetSize();
ctx.ViewportImage = viewport->GetRenderTarget();
@@ -675,12 +667,9 @@ bool VkRenderer::Draw()
// Begin the command buffer recording. We will use this command buffer exactly once, so we want to let vulkan know that
// Note: We might reuse them later!!!
VkCommandBufferBeginInfo cmdBeginInfo = VulkanInit::CommandBufferBeginInfo(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT);
DrawExtent.width = DrawImage->GetSize().x;
DrawExtent.height = DrawImage->GetSize().y;
// Create commands
VK_CALL(vkBeginCommandBuffer(cmd, &cmdBeginInfo));
// Transfer rendering image to general layout
for (auto& [_id, viewport] : Viewports)
{

View File

@@ -2,6 +2,8 @@
#include "VulkanAllocator.h"
#include "GPUManaged.h"
using namespace Nuake;
GPUResources::GPUResources()
@@ -102,6 +104,17 @@ bool GPUResources::AddTexture(Ref<VulkanImage> image)
return false;
}
void GPUResources::RemoveTexture(Ref<VulkanImage> image)
{
const UUID id = image->GetID();
if (Images.find(id) == Images.end())
{
return;
}
Images.erase(id);
}
Ref<VulkanImage> GPUResources::GetTexture(const UUID& id)
{
if (Images.find(id) != Images.end())
@@ -492,13 +505,23 @@ uint32_t GPUResources::GetBindlessMaterialID(const UUID& id)
return MeshMaterialMapping[id];
}
void GPUResources::QueueDeletion(std::function<void()> func)
void GPUResources::QueueDeletion(CleanUpStack cleanUpStack)
{
DeletionQueue.push(func);
// Push content of cleanUpStack into deletionQueue
while (!cleanUpStack.empty())
{
DeletionQueue.push(cleanUpStack.top());
cleanUpStack.pop();
}
}
void GPUResources::CleanUp()
{
if (!DeletionQueue.empty())
{
vkQueueWaitIdle(VkRenderer::Get().GPUQueue);
}
while (!DeletionQueue.empty())
{
DeletionQueue.top()();

View File

@@ -323,6 +323,8 @@ void VkSceneRenderer::DrawSceneView(RenderContext inContext)
inContext.CommandBuffer.CopyImageToImage(sceneRenderPipeline->GetOutput(), inContext.ViewportImage);
inContext.CommandBuffer.TransitionImageLayout(inContext.ViewportImage, VK_IMAGE_LAYOUT_GENERAL);
inContext.CommandBuffer.TransitionImageLayout(sceneRenderPipeline->GetOutput(), VK_IMAGE_LAYOUT_GENERAL);
inContext.CommandBuffer.TransitionImageLayout(inContext.ViewportImage, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
}
// This will prepare all the data and upload it to the GPU before rendering the scene.