writing ui descriptors

This commit is contained in:
Jorijn van der Graaf 2026-04-10 22:26:15 +02:00
commit 3fcea6a3d7
8 changed files with 108 additions and 69 deletions

View file

@ -821,9 +821,9 @@ void Window::Render() {
.sType = VK_STRUCTURE_TYPE_BIND_HEAP_INFO_EXT, .sType = VK_STRUCTURE_TYPE_BIND_HEAP_INFO_EXT,
.heapRange = { .heapRange = {
.address = descriptorHeap->resourceHeap[currentBuffer].address, .address = descriptorHeap->resourceHeap[currentBuffer].address,
.size = static_cast<std::uint32_t>(descriptorHeap->resourceHeap[currentBuffer].descriptor.range) .size = static_cast<std::uint32_t>(descriptorHeap->resourceHeap[currentBuffer].size)
}, },
.reservedRangeOffset = (descriptorHeap->resourceHeap[currentBuffer].descriptor.range - Device::descriptorHeapProperties.minResourceHeapReservedRange) & ~(Device::descriptorHeapProperties.imageDescriptorAlignment - 1), .reservedRangeOffset = (descriptorHeap->resourceHeap[currentBuffer].size - Device::descriptorHeapProperties.minResourceHeapReservedRange) & ~(Device::descriptorHeapProperties.imageDescriptorAlignment - 1),
.reservedRangeSize = Device::descriptorHeapProperties.minResourceHeapReservedRange .reservedRangeSize = Device::descriptorHeapProperties.minResourceHeapReservedRange
}; };
Device::vkCmdBindResourceHeapEXT(drawCmdBuffers[currentBuffer], &resourceHeapInfo); Device::vkCmdBindResourceHeapEXT(drawCmdBuffers[currentBuffer], &resourceHeapInfo);
@ -832,9 +832,9 @@ void Window::Render() {
.sType = VK_STRUCTURE_TYPE_BIND_HEAP_INFO_EXT, .sType = VK_STRUCTURE_TYPE_BIND_HEAP_INFO_EXT,
.heapRange = { .heapRange = {
.address = descriptorHeap->samplerHeap[currentBuffer].address, .address = descriptorHeap->samplerHeap[currentBuffer].address,
.size = static_cast<std::uint32_t>(descriptorHeap->samplerHeap[currentBuffer].descriptor.range) .size = static_cast<std::uint32_t>(descriptorHeap->samplerHeap[currentBuffer].size)
}, },
.reservedRangeOffset = descriptorHeap->samplerHeap[currentBuffer].descriptor.range - Device::descriptorHeapProperties.minSamplerHeapReservedRange, .reservedRangeOffset = descriptorHeap->samplerHeap[currentBuffer].size - Device::descriptorHeapProperties.minSamplerHeapReservedRange,
.reservedRangeSize = Device::descriptorHeapProperties.minSamplerHeapReservedRange .reservedRangeSize = Device::descriptorHeapProperties.minSamplerHeapReservedRange
}; };
Device::vkCmdBindSamplerHeapEXT(drawCmdBuffers[currentBuffer], &samplerHeapInfo); Device::vkCmdBindSamplerHeapEXT(drawCmdBuffers[currentBuffer], &samplerHeapInfo);

View file

@ -31,8 +31,8 @@ import :VulkanBuffer;
export namespace Crafter { export namespace Crafter {
struct DescriptorHeapVulkan { struct DescriptorHeapVulkan {
VulkanBuffer<std::uint8_t, true, true> resourceHeap[Window::numFrames]; VulkanBuffer<std::uint8_t, true> resourceHeap[Window::numFrames];
VulkanBuffer<std::uint8_t, true, true> samplerHeap[Window::numFrames]; VulkanBuffer<std::uint8_t, true> samplerHeap[Window::numFrames];
std::uint32_t bufferStartOffset; std::uint32_t bufferStartOffset;
std::uint16_t bufferStartElement; std::uint16_t bufferStartElement;

View file

@ -37,7 +37,7 @@ export namespace Crafter {
std::uint8_t mipLevels; std::uint8_t mipLevels;
VkImage image; VkImage image;
VkDeviceMemory imageMemory; VkDeviceMemory imageMemory;
VulkanBuffer<PixelType, true, false> buffer; VulkanBuffer<PixelType, true> buffer;
VkImageView imageView; VkImageView imageView;
VkDescriptorImageInfo descriptor; VkDescriptorImageInfo descriptor;

View file

@ -32,10 +32,10 @@ export namespace Crafter {
#ifdef CRAFTER_GRAPHICS_RENDERER_VULKAN #ifdef CRAFTER_GRAPHICS_RENDERER_VULKAN
class Mesh { class Mesh {
public: public:
VulkanBuffer<char, false, true> scratchBuffer; VulkanBuffer<char, false> scratchBuffer;
VulkanBuffer<char, false, true> blasBuffer; VulkanBuffer<char, false> blasBuffer;
VulkanBuffer<Vector<float, 3, 3>, true, true> vertexBuffer; VulkanBuffer<Vector<float, 3, 3>, true> vertexBuffer;
VulkanBuffer<std::uint32_t, true, true> indexBuffer; VulkanBuffer<std::uint32_t, true> indexBuffer;
VkAccelerationStructureGeometryTrianglesDataKHR blasData; VkAccelerationStructureGeometryTrianglesDataKHR blasData;
VkAccelerationStructureGeometryKHR blas; VkAccelerationStructureGeometryKHR blas;
VkAccelerationStructureKHR accelerationStructure; VkAccelerationStructureKHR accelerationStructure;

View file

@ -33,7 +33,7 @@ export namespace Crafter {
struct PipelineRTVulkan { struct PipelineRTVulkan {
VkPipeline pipeline; VkPipeline pipeline;
std::vector<std::uint8_t> shaderHandles; std::vector<std::uint8_t> shaderHandles;
VulkanBuffer<std::uint8_t, true, true> sbtBuffer; VulkanBuffer<std::uint8_t, true> sbtBuffer;
VkStridedDeviceAddressRegionKHR raygenRegion; VkStridedDeviceAddressRegionKHR raygenRegion;
VkStridedDeviceAddressRegionKHR missRegion; VkStridedDeviceAddressRegionKHR missRegion;
VkStridedDeviceAddressRegionKHR hitRegion; VkStridedDeviceAddressRegionKHR hitRegion;

View file

@ -30,6 +30,7 @@ import :Transform2D;
import :VulkanBuffer; import :VulkanBuffer;
import :Types; import :Types;
import :Window; import :Window;
import :DescriptorHeapVulkan;
export namespace Crafter { export namespace Crafter {
struct __attribute__((packed)) RenderingElement2DVulkanTransformInfo { struct __attribute__((packed)) RenderingElement2DVulkanTransformInfo {
@ -43,32 +44,35 @@ export namespace Crafter {
std::uint16_t index; std::uint16_t index;
std::uint16_t bufferX; std::uint16_t bufferX;
std::uint16_t bufferY; std::uint16_t bufferY;
std::array<VulkanBufferBase*, Window::numFrames> buffers;
RenderingElement2DVulkanBase(Anchor2D anchor, std::uint16_t bufferX, std::uint16_t bufferY) : bufferX(bufferX), bufferY(bufferY), Transform2D(anchor) { RenderingElement2DVulkanBase(Anchor2D anchor, std::uint16_t bufferX, std::uint16_t bufferY) : bufferX(bufferX), bufferY(bufferY), Transform2D(anchor) {
}
RenderingElement2DVulkanBase(Anchor2D anchor, std::uint16_t bufferX, std::uint16_t bufferY, std::array<VulkanBufferBase*, Window::numFrames>&& buffers) : bufferX(bufferX), bufferY(bufferY), buffers(std::move(buffers)), Transform2D(anchor) {
} }
}; };
std::vector<RenderingElement2DVulkanBase*> renderingElement2DVulkans; std::vector<RenderingElement2DVulkanBase*> renderingElement2DVulkans;
VulkanBuffer<RenderingElement2DVulkanTransformInfo, true, true> renderingElement2DVulkanTransformBuffer[Window::numFrames]; VulkanBuffer<RenderingElement2DVulkanTransformInfo, true> renderingElement2DVulkanTransformBuffer[Window::numFrames];
template<bool Owning, bool Mapped> template<bool Owning, bool Mapped>
struct RenderingElement2DVulkan : RenderingElement2DVulkanBase { struct RenderingElement2DVulkan : RenderingElement2DVulkanBase {
std::array<VulkanBuffer<Vector<_Float16, 4, 4>, Mapped, true>*, Window::numFrames> buffers;
RenderingElement2DVulkan(Anchor2D anchor, std::uint16_t bufferX, std::uint16_t bufferY) requires(Owning) : RenderingElement2DVulkanBase(anchor, bufferX, bufferY) { RenderingElement2DVulkan(Anchor2D anchor, std::uint16_t bufferX, std::uint16_t bufferY) requires(Owning) : RenderingElement2DVulkanBase(anchor, bufferX, bufferY) {
renderingElement2DVulkans.push_back(this); renderingElement2DVulkans.push_back(this);
for(std::uint8_t i = 0; i < Window::numFrames; i++) { for(std::uint8_t i = 0; i < Window::numFrames; i++) {
buffers[i] = new VulkanBuffer<Vector<_Float16, 4, 4>, Mapped, true>(); buffers[i] = new VulkanBuffer<Vector<_Float16, 4, 4>, Mapped>();
buffers[i]->Create(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_2_SHADER_DEVICE_ADDRESS_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, bufferX * bufferY); reinterpret_cast<VulkanBuffer<Vector<_Float16, 4, 4>, Mapped>*>(buffers[i])->Create(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_2_SHADER_DEVICE_ADDRESS_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, bufferX * bufferY);
} }
} }
RenderingElement2DVulkan(Anchor2D anchor, std::uint16_t bufferX, std::uint16_t bufferY, std::array<VulkanBuffer<_Float16, Mapped, true>*, Window::numFrames> buffers) requires(!Owning) : buffers(buffers), RenderingElement2DVulkanBase(anchor, bufferX, bufferY) { RenderingElement2DVulkan(Anchor2D anchor, std::uint16_t bufferX, std::uint16_t bufferY, std::array<VulkanBufferBase*, Window::numFrames>&& buffers) requires(!Owning) : RenderingElement2DVulkanBase(anchor, bufferX, bufferY, std::move(buffers)) {
renderingElement2DVulkans.push_back(this); renderingElement2DVulkans.push_back(this);
} }
~RenderingElement2DVulkan() { ~RenderingElement2DVulkan() {
if constexpr(Owning) { if constexpr(Owning) {
for(VulkanBuffer<Vector<_Float16, 4, 4>, Mapped, true>* buffer : buffers) { for(VulkanBufferBase* buffer : buffers) {
delete buffer; delete reinterpret_cast<VulkanBuffer<Vector<_Float16, 4, 4>, Mapped>*>(buffer);
} }
} }
auto it = std::find(renderingElement2DVulkans.begin(), renderingElement2DVulkans.end(), this); auto it = std::find(renderingElement2DVulkans.begin(), renderingElement2DVulkans.end(), this);
@ -90,6 +94,68 @@ export namespace Crafter {
} }
}; };
void WriteRenderingElement2DVulkanDescriptors(std::span<VkResourceDescriptorInfoEXT> infos, std::span<VkHostAddressRangeEXT> ranges, std::uint16_t start, std::uint32_t bufferOffset, DescriptorHeapVulkan& descriptorHeap) {
VkDeviceAddressRangeKHR transformRanges[Window::numFrames] = {
{
.address = renderingElement2DVulkanTransformBuffer[0].address,
.size = renderingElement2DVulkanTransformBuffer[0].size
},
{
.address = renderingElement2DVulkanTransformBuffer[1].address,
.size = renderingElement2DVulkanTransformBuffer[1].size
},
{
.address = renderingElement2DVulkanTransformBuffer[2].address,
.size = renderingElement2DVulkanTransformBuffer[2].size
}
};
for(std::uint8_t i = 0; i < Window::numFrames; i++) {
ranges[start + i] = {
.address = descriptorHeap.resourceHeap[i].value + bufferOffset,
.size = Device::descriptorHeapProperties.bufferDescriptorSize
};
infos[start + i] = {
.sType = VK_STRUCTURE_TYPE_RESOURCE_DESCRIPTOR_INFO_EXT,
.type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
.data = { .pAddressRange = &transformRanges[i]}
};
}
start += 3;
bufferOffset += Device::descriptorHeapProperties.bufferDescriptorSize;
std::vector<VkDeviceAddressRangeKHR> bufferRanges(renderingElement2DVulkans.size() * Window::numFrames);
std::uint16_t rangeOffset = 0;
for(std::uint8_t i2 = 0; i2 < Window::numFrames; i2++) {
for(std::uint16_t i = 0; i < renderingElement2DVulkans.size(); i++) {
ranges[start + i] = {
.address = descriptorHeap.resourceHeap[i2].value + bufferOffset + Device::descriptorHeapProperties.bufferDescriptorSize * i,
.size = Device::descriptorHeapProperties.bufferDescriptorSize
};
infos[start + i] = {
.sType = VK_STRUCTURE_TYPE_RESOURCE_DESCRIPTOR_INFO_EXT,
.type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
.data = { .pAddressRange = &bufferRanges[i]}
};
bufferRanges[rangeOffset + i] = {
.address = renderingElement2DVulkans[i]->buffers[i2]->address,
.size = renderingElement2DVulkans[i]->buffers[i2]->size
};
}
start += renderingElement2DVulkans.size();
rangeOffset += renderingElement2DVulkans.size();
}
Device::vkWriteResourceDescriptorsEXT(Device::device, start, infos.data(), ranges.data());
for(std::uint8_t i = 0; i < Window::numFrames; i++) {
descriptorHeap.resourceHeap[i].FlushDevice();
}
}
void InitializeRenderingElement2DVulkanBuffer() { void InitializeRenderingElement2DVulkanBuffer() {
for(std::uint8_t frame = 0; frame < Window::numFrames; frame++) { for(std::uint8_t frame = 0; frame < Window::numFrames; frame++) {
renderingElement2DVulkanTransformBuffer[frame].Create(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_2_SHADER_DEVICE_ADDRESS_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, renderingElement2DVulkans.size()+1); renderingElement2DVulkanTransformBuffer[frame].Create(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_2_SHADER_DEVICE_ADDRESS_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, renderingElement2DVulkans.size()+1);

View file

@ -32,16 +32,16 @@ import :Window;
export namespace Crafter { export namespace Crafter {
struct TlasWithBuffer { struct TlasWithBuffer {
VkDeviceAddress address; VkDeviceAddress address;
VulkanBuffer<char, false, true> buffer; VulkanBuffer<char, false> buffer;
VkAccelerationStructureKHR accelerationStructure; VkAccelerationStructureKHR accelerationStructure;
VulkanBuffer<VkAccelerationStructureInstanceKHR, true, true> instanceBuffer; VulkanBuffer<VkAccelerationStructureInstanceKHR, true> instanceBuffer;
}; };
class RenderingElement3D { class RenderingElement3D {
public: public:
VkAccelerationStructureInstanceKHR instance; VkAccelerationStructureInstanceKHR instance;
static std::vector<RenderingElement3D*> elements; static std::vector<RenderingElement3D*> elements;
inline static VulkanBuffer<char, false, true> scratchBuffer; inline static VulkanBuffer<char, false> scratchBuffer;
inline static TlasWithBuffer tlases[Window::numFrames]; inline static TlasWithBuffer tlases[Window::numFrames];
static void BuildTLAS(VkCommandBuffer cmd, std::uint32_t index); static void BuildTLAS(VkCommandBuffer cmd, std::uint32_t index);
}; };

View file

@ -31,24 +31,12 @@ import :Device;
namespace Crafter { namespace Crafter {
export class VulkanBufferBase { export class VulkanBufferBase {
public: public:
VkDescriptorBufferInfo descriptor; VkDeviceAddress address;
std::uint32_t size;
VkBuffer buffer = VK_NULL_HANDLE; VkBuffer buffer = VK_NULL_HANDLE;
VkDeviceMemory memory; VkDeviceMemory memory;
}; };
export class VulkanBufferAdressable {
public:
VkDeviceAddress address;
};
export class VulkanBufferAdressableEmpty {};
template<bool Adressable>
using VulkanBufferAdressableConditional =
std::conditional_t<
Adressable,
VulkanBufferAdressable,
VulkanBufferAdressableEmpty
>;
export template<typename T> export template<typename T>
class VulkanBufferMapped { class VulkanBufferMapped {
public: public:
@ -63,16 +51,12 @@ namespace Crafter {
VulkanBufferMappedEmpty VulkanBufferMappedEmpty
>; >;
export template <typename T, bool Mapped>
export template <typename T, bool Mapped, bool Adressable> class VulkanBuffer : public VulkanBufferBase, public VulkanBufferMappedConditional<T, Mapped> {
class VulkanBuffer;
export template <typename T, bool Mapped, bool Adressable>
class VulkanBuffer : public VulkanBufferBase, public VulkanBufferMappedConditional<T, Mapped>, public VulkanBufferAdressableConditional<Adressable> {
public: public:
VulkanBuffer() = default; VulkanBuffer() = default;
void Create(VkBufferUsageFlags usageFlags, VkMemoryPropertyFlags memoryPropertyFlags, std::uint32_t count) { void Create(VkBufferUsageFlags usageFlags, VkMemoryPropertyFlags memoryPropertyFlags, std::uint32_t count) {
size = count * sizeof(T);
VkBufferCreateInfo bufferCreateInfo {}; VkBufferCreateInfo bufferCreateInfo {};
bufferCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; bufferCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
@ -87,30 +71,21 @@ namespace Crafter {
.allocationSize = memReqs.size, .allocationSize = memReqs.size,
.memoryTypeIndex = Device::GetMemoryType(memReqs.memoryTypeBits, memoryPropertyFlags) .memoryTypeIndex = Device::GetMemoryType(memReqs.memoryTypeBits, memoryPropertyFlags)
}; };
if constexpr(Adressable) {
VkMemoryAllocateFlagsInfoKHR allocFlagsInfo { VkMemoryAllocateFlagsInfoKHR allocFlagsInfo {
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO_KHR, .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO_KHR,
.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT_KHR, .flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT_KHR,
}; };
memAlloc.pNext = &allocFlagsInfo; memAlloc.pNext = &allocFlagsInfo;
Device::CheckVkResult(vkAllocateMemory(Device::device, &memAlloc, nullptr, &memory)); Device::CheckVkResult(vkAllocateMemory(Device::device, &memAlloc, nullptr, &memory));
} else {
Device::CheckVkResult(vkAllocateMemory(Device::device, &memAlloc, nullptr, &memory));
}
descriptor.offset = 0;
descriptor.buffer = buffer;
descriptor.range = sizeof(T)*count;
Device::CheckVkResult(vkBindBufferMemory(Device::device, buffer, memory, 0)); Device::CheckVkResult(vkBindBufferMemory(Device::device, buffer, memory, 0));
if constexpr(Adressable) { VkBufferDeviceAddressInfo addressInfo = {
VkBufferDeviceAddressInfo addressInfo = { .sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO,
.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO, .buffer = buffer
.buffer = buffer };
}; address = vkGetBufferDeviceAddress(Device::device, &addressInfo);
VulkanBufferAdressableConditional<true>::address = vkGetBufferDeviceAddress(Device::device, &addressInfo);
}
if constexpr(Mapped) { if constexpr(Mapped) {
Device::CheckVkResult(vkMapMemory(Device::device, memory, 0, memReqs.size, 0, reinterpret_cast<void**>(&(VulkanBufferMappedConditional<T, true>::value)))); Device::CheckVkResult(vkMapMemory(Device::device, memory, 0, memReqs.size, 0, reinterpret_cast<void**>(&(VulkanBufferMappedConditional<T, true>::value))));
@ -137,7 +112,7 @@ namespace Crafter {
VkBufferCopy copyRegion = { VkBufferCopy copyRegion = {
.srcOffset = 0, .srcOffset = 0,
.dstOffset = 0, .dstOffset = 0,
.size = descriptor.range .size = size
}; };
vkCmdCopyBuffer( vkCmdCopyBuffer(
@ -219,13 +194,11 @@ namespace Crafter {
} }
VulkanBuffer(VulkanBuffer&& other) { VulkanBuffer(VulkanBuffer&& other) {
descriptor = other.descriptor;
buffer = other.buffer; buffer = other.buffer;
memory = other.memory; memory = other.memory;
size = other.size;
other.buffer = VK_NULL_HANDLE; other.buffer = VK_NULL_HANDLE;
if constexpr(Adressable) { address = other.address;
VulkanBufferAdressableConditional<true>::address = other.VulkanBufferAdressableConditional<true>::address;
}
if constexpr(Mapped) { if constexpr(Mapped) {
VulkanBufferMappedConditional<T, true>::value = other.VulkanBufferMappedConditional<T, true>::value; VulkanBufferMappedConditional<T, true>::value = other.VulkanBufferMappedConditional<T, true>::value;
} }