Started proper descriptor management system

This commit is contained in:
antopilo
2025-04-27 23:26:26 -04:00
parent b77ff499a0
commit 53150dd787
9 changed files with 346 additions and 5 deletions

View File

@@ -0,0 +1,138 @@
#include "BindlessDescriptor.h"
#include "VulkanAllocator.h"
#include "VulkanRenderer.h"
#include "VulkanInit.h"
#include "DescriptorLayoutBuilder.h"
using namespace Nuake;
std::string GetResourceTypeName(ResourceType type)
{
switch (type)
{
case ResourceType::View: return "View";
case ResourceType::Material: return "Material";
case ResourceType::Texture: return "Texture";
case ResourceType::Light: return "Light";
case ResourceType::Sampler: return "Sampler";
default: return "Unknown";
}
}
int32_t Descriptor::LoadResource(const UUID& id)
{
// Check if we have already loaded this resource
if (SlotMapping.find(id) != SlotMapping.end())
{
return SlotMapping[id];
}
// Find an empty slot
for (int i = 0; i < Slots.size(); i++)
{
if (!Slots[i].Active)
{
DescriptorSlot& slot = Slots[i];
slot.Active = true;
slot.Slot = i;
SlotMapping[id] = i;
return i;
}
}
return -1;
}
int32_t Descriptor::GetResourceSlot(const UUID& id) const
{
auto it = SlotMapping.find(id);
if (it != SlotMapping.end())
{
return it->second;
}
return 0; // Resource not found
}
Descriptor::Descriptor(Ref<AllocatedBuffer> buffer, VkDescriptorSetLayout layout, uint8_t* ptr, size_t offset, size_t size, BindlessInfo& info)
: DataPtr(ptr), Offset(offset), Size(size), Info(info)
{
auto& vk = VkRenderer::Get();
auto& allocator = VkRenderer::Get().GetDescriptorAllocator();
DescriptorSet = allocator.Allocate(vk.GetDevice(), layout);
// Offset since we are splitting the buffer by N frames in flight
// Each partition is a frame in flight
VkDescriptorBufferInfo bufferInfo{};
bufferInfo.buffer = buffer->GetBuffer();
bufferInfo.offset = offset;
bufferInfo.range = size;
VkWriteDescriptorSet write{};
write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
write.dstSet = DescriptorSet;
write.dstBinding = 0;
write.dstArrayElement = 0;
write.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
write.descriptorCount = 1;
write.pBufferInfo = &bufferInfo;
vkUpdateDescriptorSets(vk.GetDevice(), 1, &write, 0, nullptr);
}
BindlessDescriptor::BindlessDescriptor(ResourceType type, BindlessInfo& info)
{
// Create a buffer that holds for N frame in flights of data
const std::string& resourceName = GetResourceTypeName(type);
// Build descriptor layout
DescriptorLayoutBuilder builder;
switch (type)
{
case ResourceType::View:
case ResourceType::Material:
case ResourceType::Light:
builder.AddBinding(0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
break;
case ResourceType::Texture:
builder.AddBinding(0, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE);
break;
}
DescriptorLayout = builder.Build(VkRenderer::Get().GetDevice(), VK_SHADER_STAGE_ALL_GRAPHICS);
VulkanUtil::SetDebugName(DescriptorLayout, resourceName + "DescriptorLayout");
// Create buffer and map, CPU -> GPU since we will writing to it directly
// Size of buffer is: size_of(ResourceType) * FRAME_OVERLAP since 1 buffer will hold N Frames in flight
// TODO(antopilo): move mapped pointer inside buffer directly
const BufferUsage usage = BufferUsage::STORAGE_BUFFER | BufferUsage::TRANSFER_DST;
const MemoryUsage memoryUsage = MemoryUsage::CPU_TO_GPU;
const size_t size = info.ResourceElementSize[type] * info.ResourceCount[type];
const size_t totalSize = size * FRAME_OVERLAP;
Buffer = CreateRef<AllocatedBuffer>(resourceName + "GPUBuffer", totalSize, usage, memoryUsage);
// Map to a host-visible pointer
void* mappedData;
vmaMapMemory(VulkanAllocator::Get().GetAllocator(), (Buffer->GetAllocation()), &mappedData);
for (int i = 0; i < FRAME_OVERLAP; i++)
{
const size_t offset = i * size;
uint8_t* partitionStart = static_cast<uint8_t*>(mappedData) + offset;
Descriptors.emplace_back(Descriptor(Buffer, DescriptorLayout, partitionStart, offset, size));
}
}
ResourceDescriptors::ResourceDescriptors(const ResourceDescriptorsLimits& limits)
{
struct View
{
int myView;
int dat2;
};
AddResourceDescriptors<ResourceType::View, View>(limits.MaxView);
//AddResourceDescriptors<ResourceType::Material>(limits.MaxMaterial);
//AddResourceDescriptors<ResourceType::Texture>(limits.MaxTexture);
//AddResourceDescriptors<ResourceType::Light>(limits.MaxLight);
//AddResourceDescriptors<ResourceType::Sampler>(limits.MaxSampler);
}

View File

@@ -0,0 +1,104 @@
#pragma once
#include "Nuake/Core/Core.h"
#include "VulkanAllocatedBuffer.h"
#include "VulkanRenderer.h"
#include <volk/volk.h>
#include <map>
namespace Nuake
{
enum class ResourceType
{
View,
Material,
Texture,
Light,
Sampler
};
struct BindlessInfo
{
std::map<ResourceType, size_t> ResourceElementSize;
std::map<ResourceType, size_t> ResourceCount;
std::map<ResourceType, AllocatedBuffer> ResourceBuffers;
};
class DescriptorSlot
{
public:
bool Active;
int32_t Slot;
UUID RID;
};
// A partition of the buffer in BindlessDescriptor
class Descriptor
{
private:
uint8_t* DataPtr;
size_t Size;
size_t Offset;
private:
BindlessInfo& Info;
VkDescriptorSet DescriptorSet;
std::map<UUID, int> SlotMapping;
std::vector<DescriptorSlot> Slots;
public:
Descriptor(Ref<AllocatedBuffer> buffer, VkDescriptorSetLayout layout, uint8_t* ptr, size_t offset, size_t size, BindlessInfo& info);
~Descriptor() = default;
int32_t LoadResource(const UUID& id);
int32_t GetResourceSlot(const UUID& id);
};
// Contains buffer for N frames of a resource type
class BindlessDescriptor
{
private:
Ref<AllocatedBuffer> Buffer;
std::vector<Descriptor> Descriptors;
VkDescriptorSetLayout DescriptorLayout;
public:
BindlessDescriptor(ResourceType type, BindlessInfo& info);
BindlessDescriptor() = default;
~BindlessDescriptor() = default;
void QueueCopy(const size_t frameIndex, const size_t offset, const size_t size, const void* data);
};
struct ResourceDescriptorsLimits
{
size_t MaxView;
size_t MaxMaterial;
size_t MaxTexture;
size_t MaxLight;
size_t MaxSampler;
};
// Contains all buffers per resource
class ResourceDescriptors
{
private:
std::map<ResourceType, BindlessDescriptor> Descriptors;
BindlessInfo Info;
public:
ResourceDescriptors(const ResourceDescriptorsLimits& limits);
~ResourceDescriptors() = default;
template<ResourceType T, typename S>
void AddResourceDescriptors(const size_t size)
{
Info.ResourceElementSize[T] = sizeof(S);
Info.ResourceCount[T] = size;
Descriptors[T] = BindlessDescriptor(T, (size_t)sizeof(S) * size);
}
};
}

View File

@@ -113,6 +113,8 @@ void Cmd::CopyBuffer(VkBuffer src, VkBuffer dst, size_t size) const
copy.size = size;
vkCmdCopyBuffer(CmdBuffer, src, dst, 1, &copy);
}
void Cmd::TransitionImageLayout(Ref<VulkanImage> img, VkImageLayout layout) const
@@ -177,6 +179,8 @@ void Cmd::CopyImageToBuffer(Ref<VulkanImage> src, Ref<AllocatedBuffer> dst, cons
1,
&copyRegion
);
dst->Update();
}
void Cmd::SetLineRasterizationMode(VkLineRasterizationMode mode) const

View File

@@ -156,6 +156,8 @@ SceneRenderPipeline::SceneRenderPipeline()
copy.size = buffer->GetSize();
vkCmdCopyBuffer(cmd, staging.GetBuffer(), buffer->GetBuffer(), 1, &copy);
buffer->Update();
});
vmaUnmapMemory(VulkanAllocator::Get().GetAllocator(), staging.GetAllocation());

View File

@@ -53,7 +53,7 @@ namespace Nuake
// This is the *whole* buffer
struct MaterialData
{
std::array<MaterialBufferStruct, 3000> Data;
std::array<MaterialBufferStruct, 2000> Data;
};
struct LightData
@@ -92,14 +92,22 @@ namespace Nuake
};
constexpr uint32_t MAX_MODEL_MATRIX = 3000;
constexpr uint32_t MAX_MATERIAL = 3000;
constexpr uint32_t MAX_MATERIAL = 2000;
constexpr uint32_t MAX_TEXTURES = 3000;
constexpr uint32_t MAX_CAMERAS = 1000;
constexpr uint32_t MAX_LIGHTS = 100;
class GPUResources
{
Ref<AllocatedBuffer> AllBuffer;
struct FrameData
{
VkDescriptorSet TestDescriptorSet;
};
private:
FrameData frameData[FRAME_OVERLAP];
bool isDirty = false;
std::map<UUID, Ref<AllocatedBuffer>> Buffers;
std::map<UUID, Ref<VkMesh>> Meshes;

View File

@@ -9,6 +9,10 @@
#include "VkResources.h"
using namespace Nuake;
void AllocatedBuffer::Update()
{
LastUpdatedFrame = VkRenderer::Get().FrameNumber;
}
AllocatedBuffer::AllocatedBuffer(size_t inSize, BufferUsage inFlags, MemoryUsage inUsage)
: ID(UUID()),
@@ -25,9 +29,13 @@ AllocatedBuffer::AllocatedBuffer(size_t inSize, BufferUsage inFlags, MemoryUsage
vmaallocInfo.usage = static_cast<VmaMemoryUsage>(inUsage);
vmaallocInfo.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT;
MemUsage = inUsage;
// allocate the buffer
VK_CALL(vmaCreateBuffer(VulkanAllocator::Get().GetAllocator(), &bufferInfo, &vmaallocInfo, &Buffer, &Allocation,
&Info));
LastUpdatedFrame = VkRenderer::Get().FrameNumber;
}
AllocatedBuffer::AllocatedBuffer(const std::string& name, size_t inSize, BufferUsage inFlags, MemoryUsage inUsage) :

View File

@@ -43,6 +43,7 @@ namespace Nuake
VmaAllocation Allocation;
VmaAllocationInfo Info;
size_t Size;
int LastUpdatedFrame = 0;
public:
AllocatedBuffer(size_t size, BufferUsage flags, MemoryUsage usage);
@@ -50,11 +51,17 @@ namespace Nuake
AllocatedBuffer() = default;
~AllocatedBuffer();
MemoryUsage MemUsage;
BufferUsage BufUsage;
VkBuffer GetBuffer() const { return Buffer; }
VmaAllocation GetAllocation() const { return Allocation; }
UUID GetID() const { return ID; }
size_t GetSize() const { return Size; }
int GetLastUpdated() const { return LastUpdatedFrame; }
std::string GetName() const { return Name; }
void Update();
};
// push constants for our mesh object draws

View File

@@ -36,6 +36,7 @@
#include <array>
#include <mutex>
#include <algorithm>
#include <implot-0.16/implot.h>
#ifdef NK_DEBUG
bool NKUseValidationLayer = true;
@@ -606,6 +607,7 @@ void VkRenderer::InitImgui()
// 2: initialize imgui library
ImGui::CreateContext();
ImPlot::CreateContext();
{
ImGuiIO& io = ImGui::GetIO(); (void)io;
io.Fonts->AddFontFromMemoryTTF(StaticResources::Data_Fonts_Poppins_Regular_ttf, StaticResources::Data_Fonts_Poppins_Regular_ttf_len, 16.0);

View File

@@ -4,6 +4,7 @@
#include "GPUManaged.h"
#include "VulkanInit.h"
#include "BindlessDescriptor.h"
using namespace Nuake;
@@ -33,6 +34,54 @@ void GPUResources::Init()
ModelBuffer = CreateBuffer(sizeof(Matrix4) * MAX_MODEL_MATRIX, BufferUsage::STORAGE_BUFFER | BufferUsage::TRANSFER_DST, MemoryUsage::GPU_ONLY, "TransformBuffer");
MaterialBuffer = CreateBuffer(sizeof(MaterialBufferStruct) * MAX_MATERIAL, BufferUsage::STORAGE_BUFFER | BufferUsage::TRANSFER_DST, MemoryUsage::GPU_ONLY, "MaterialBuffer");
LightBuffer = CreateBuffer(sizeof(LightData) * MAX_LIGHTS, BufferUsage::STORAGE_BUFFER | BufferUsage::TRANSFER_DST, MemoryUsage::GPU_ONLY, "LightBuffer");
auto& vk = VkRenderer::Get();
auto device = vk.GetDevice();
{
DescriptorLayoutBuilder builder;
builder.AddBinding(0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
ModelDescriptorLayout = builder.Build(device, VK_SHADER_STAGE_ALL_GRAPHICS);
VulkanUtil::SetDebugName(ModelDescriptorLayout, "ModelDescriptorLayout");
}
VkDescriptorSet descriptorSets[FRAME_OVERLAP];
Ref<AllocatedBuffer> bigBuffer = CreateBuffer(sizeof(Matrix4) * MAX_MODEL_MATRIX * FRAME_OVERLAP, BufferUsage::STORAGE_BUFFER | BufferUsage::TRANSFER_DST, MemoryUsage::CPU_TO_GPU, "BigBuffer");
for (int i = 0; i < FRAME_OVERLAP; i++)
{
auto& allocator = vk.GetDescriptorAllocator();
descriptorSets[i] = allocator.Allocate(device, ModelDescriptorLayout);
VkDescriptorBufferInfo bufferInfo{};
bufferInfo.buffer = bigBuffer->GetBuffer();
bufferInfo.offset = sizeof(Matrix4) * MAX_MODEL_MATRIX * i;
bufferInfo.range = sizeof(Matrix4) * MAX_MODEL_MATRIX;
VkWriteDescriptorSet write{};
write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
write.dstSet = descriptorSets[i];
write.dstBinding = 0;
write.dstArrayElement = 0;
write.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
write.descriptorCount = 1;
write.pBufferInfo = &bufferInfo;
vkUpdateDescriptorSets(device, 1, &write, 0, nullptr);
}
//// Update the relevant part
//void* mappedData;
//vmaMapMemory(VulkanAllocator::Get().GetAllocator(), (bigBuffer->GetAllocation()), &mappedData);
//void* mappedPointer = 0;
//int frameIndex = 1;
////uint8_t* frameData = static_cast<uint8_t*>(bigBuffer) + (frameIndex * sizeof(Matrix4) * MAX_MODEL_MATRIX);
//int data = 2;
//// Now copy into the correct frame
//memcpy(frameData, &data, sizeof(Matrix4) * MAX_MODEL_MATRIX);
//vmaUnmapMemory(VulkanAllocator::Get().GetAllocator(), bigBuffer->GetAllocation());
}
Ref<AllocatedBuffer> GPUResources::CreateBuffer(size_t size, BufferUsage flags, MemoryUsage usage, const std::string& name)
@@ -56,6 +105,8 @@ void GPUResources::CopyIntoBuffer(Ref<AllocatedBuffer> buffer, void* data, size_
copy.size = size;
vkCmdCopyBuffer(cmd, buffer->GetBuffer(), buffer->GetBuffer(), 1, &copy);
buffer->Update();
});
vmaUnmapMemory(VulkanAllocator::Get().GetAllocator(), buffer->GetAllocation());
@@ -288,6 +339,16 @@ void GPUResources::CreateBindlessLayout()
VulkanUtil::SetDebugName(CamerasDescriptorLayout, "CamerasDescriptorLayout");
}
ResourceDescriptorsLimits limits
{
.MaxView = 10,
.MaxMaterial = 1,
.MaxTexture = 20,
.MaxLight = 10,
.MaxSampler = 2,
};
ResourceDescriptors descriptors = ResourceDescriptors(limits);
auto allocator = vk.GetDescriptorAllocator();
TexturesDescriptor = allocator.Allocate(device, TexturesDescriptorLayout);
CamerasDescriptor = allocator.Allocate(device, CamerasDescriptorLayout);
@@ -394,7 +455,7 @@ void GPUResources::RecreateBindlessCameras()
auto allocator = VulkanAllocator::Get().GetAllocator();
vmaMapMemory(allocator, (VkRenderer::Get().GetCurrentFrame().CamerasStagingBuffer->GetAllocation()), &mappedData);
memcpy(mappedData, Cameras.data(), sizeof(CameraView) * Cameras.size());
VkRenderer::Get().GetCurrentFrame().CamerasStagingBuffer->Update();
VkRenderer::Get().ImmediateSubmit([&](VkCommandBuffer cmd) {
VkBufferCopy copy{ 0 };
copy.dstOffset = 0;
@@ -402,6 +463,7 @@ void GPUResources::RecreateBindlessCameras()
copy.size = sizeof(CameraView) * MAX_CAMERAS;
vkCmdCopyBuffer(cmd, VkRenderer::Get().GetCurrentFrame().CamerasStagingBuffer->GetBuffer(), CamerasBuffer->GetBuffer(), 1, &copy);
CamerasBuffer->Update();
});
vmaUnmapMemory(allocator, VkRenderer::Get().GetCurrentFrame().CamerasStagingBuffer->GetAllocation());
@@ -431,6 +493,7 @@ void GPUResources::UpdateBuffers()
vmaMapMemory(VulkanAllocator::Get().GetAllocator(), (VkRenderer::Get().GetCurrentFrame().ModelStagingBuffer->GetAllocation()), &mappedData);
memcpy(mappedData, &ModelTransforms, sizeof(ModelData));
VkRenderer::Get().GetCurrentFrame().ModelStagingBuffer->Update();
VkRenderer::Get().ImmediateSubmit([&](VkCommandBuffer cmd) {
VkBufferCopy copy{ 0 };
copy.dstOffset = 0;
@@ -438,6 +501,8 @@ void GPUResources::UpdateBuffers()
copy.size = sizeof(ModelData);
vkCmdCopyBuffer(cmd, VkRenderer::Get().GetCurrentFrame().ModelStagingBuffer->GetBuffer(), ModelBuffer->GetBuffer(), 1, &copy);
ModelBuffer->Update();
});
vmaUnmapMemory(VulkanAllocator::Get().GetAllocator(), VkRenderer::Get().GetCurrentFrame().ModelStagingBuffer->GetAllocation());
@@ -464,7 +529,7 @@ void GPUResources::UpdateBuffers()
void* mappedData;
vmaMapMemory(VulkanAllocator::Get().GetAllocator(), (VkRenderer::Get().GetCurrentFrame().MaterialStagingBuffer->GetAllocation()), &mappedData);
memcpy(mappedData, &MaterialDataContainer, sizeof(MaterialData));
VkRenderer::Get().GetCurrentFrame().MaterialStagingBuffer->Update();
VkRenderer::Get().ImmediateSubmit([&](VkCommandBuffer cmd) {
VkBufferCopy copy{ 0 };
copy.dstOffset = 0;
@@ -472,6 +537,8 @@ void GPUResources::UpdateBuffers()
copy.size = sizeof(MaterialData);
vkCmdCopyBuffer(cmd, VkRenderer::Get().GetCurrentFrame().MaterialStagingBuffer->GetBuffer(), MaterialBuffer->GetBuffer(), 1, &copy);
MaterialBuffer->Update();
});
vmaUnmapMemory(VulkanAllocator::Get().GetAllocator(), VkRenderer::Get().GetCurrentFrame().MaterialStagingBuffer->GetAllocation());
@@ -499,7 +566,7 @@ void GPUResources::UpdateBuffers()
void* mappedData;
vmaMapMemory(VulkanAllocator::Get().GetAllocator(), (VkRenderer::Get().GetCurrentFrame().LightStagingBuffer->GetAllocation()), &mappedData);
memcpy(mappedData, &LightDataContainerArray, sizeof(LightDataContainer));
VkRenderer::Get().GetCurrentFrame().LightStagingBuffer->Update();
VkRenderer::Get().ImmediateSubmit([&](VkCommandBuffer cmd) {
VkBufferCopy copy{ 0 };
copy.dstOffset = 0;
@@ -507,6 +574,7 @@ void GPUResources::UpdateBuffers()
copy.size = sizeof(LightDataContainer);
vkCmdCopyBuffer(cmd, VkRenderer::Get().GetCurrentFrame().LightStagingBuffer->GetBuffer(), LightBuffer->GetBuffer(), 1, &copy);
LightBuffer->Update();
});
vmaUnmapMemory(VulkanAllocator::Get().GetAllocator(), VkRenderer::Get().GetCurrentFrame().LightStagingBuffer->GetAllocation());