Added GPUManged interface for resource deletion
This commit is contained in:
23
Nuake/Source/Nuake/Rendering/Vulkan/GPUManaged.cpp
Normal file
23
Nuake/Source/Nuake/Rendering/Vulkan/GPUManaged.cpp
Normal 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;
|
||||
}
|
||||
25
Nuake/Source/Nuake/Rendering/Vulkan/GPUManaged.h
Normal file
25
Nuake/Source/Nuake/Rendering/Vulkan/GPUManaged.h
Normal 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();
|
||||
};
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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); }
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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()();
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user