working mesh shader

This commit is contained in:
Jorijn van der Graaf 2025-04-19 23:59:27 +02:00
commit 97ca634108
18 changed files with 2591 additions and 340 deletions

View file

@ -9,6 +9,8 @@ module;
#include <cstring>
#include <print>
#include <cstdio>
#include "VulkanInitializers.hpp"
#include "VulkanBuffer.h"
#define GET_EXTENSION_FUNCTION(_id) ((PFN_##_id)(vkGetInstanceProcAddr(instance, #_id)))
@ -23,7 +25,8 @@ const char* const deviceExtensionNames[] = {
"VK_KHR_swapchain",
"VK_KHR_spirv_1_4",
"VK_EXT_mesh_shader",
"VK_KHR_shader_float_controls"
"VK_KHR_shader_float_controls",
"VK_KHR_dynamic_rendering"
};
const char* const layerNames[] = {
"VK_LAYER_KHRONOS_validation"
@ -182,6 +185,7 @@ void VulkanDevice::CreateDevice() {
break;
}
}
float priority = 1;
@ -191,8 +195,13 @@ void VulkanDevice::CreateDevice() {
queueCreateInfo.queueCount = 1;
queueCreateInfo.pQueuePriorities = &priority;
VkPhysicalDeviceDynamicRenderingFeaturesKHR dynamicRenderingFeature = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES_KHR};
dynamicRenderingFeature.dynamicRendering = VK_TRUE;
VkPhysicalDeviceMeshShaderFeaturesEXT ext_feature = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_FEATURES_EXT};
ext_feature.meshShader = VK_TRUE;
ext_feature.pNext = &dynamicRenderingFeature;
VkPhysicalDeviceFeatures2 physical_features2 = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2};
physical_features2.pNext = &ext_feature;
@ -237,4 +246,134 @@ void VulkanDevice::CreateDevice() {
commandPoolcreateInfo.queueFamilyIndex = queueFamilyIndex;
commandPoolcreateInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
CHECK_VK_RESULT(vkCreateCommandPool(device, &commandPoolcreateInfo, NULL, &commandPool));
vkGetPhysicalDeviceMemoryProperties(physDevice, &memoryProperties);
std::vector<VkFormat> formatList = {
VK_FORMAT_D32_SFLOAT,
};
for (auto& format : formatList) {
VkFormatProperties formatProps;
vkGetPhysicalDeviceFormatProperties(physDevice, format, &formatProps);
if (formatProps.optimalTilingFeatures)
{
depthFormat = format;
break;
}
}
vkCmdDrawMeshTasksEXTProc = reinterpret_cast<PFN_vkCmdDrawMeshTasksEXT>(vkGetDeviceProcAddr(device, "vkCmdDrawMeshTasksEXT"));
vkCmdBeginRenderingKHRProc = reinterpret_cast<PFN_vkCmdBeginRenderingKHR>(vkGetInstanceProcAddr(instance, "vkCmdBeginRenderingKHR"));
vkCmdEndRenderingKHRProc = reinterpret_cast<PFN_vkCmdEndRenderingKHR>(vkGetInstanceProcAddr(instance, "vkCmdEndRenderingKHR"));
}
std::uint32_t VulkanDevice::GetMemoryType(uint32_t typeBits, VkMemoryPropertyFlags properties) {
for (uint32_t i = 0; i < memoryProperties.memoryTypeCount; i++)
{
if ((typeBits & 1) == 1)
{
if ((memoryProperties.memoryTypes[i].propertyFlags & properties) == properties)
{
return i;
}
}
typeBits >>= 1;
}
throw std::runtime_error("Could not find a matching memory type");
}
void VulkanDevice::CreateBuffer(VkBufferUsageFlags usageFlags, VkMemoryPropertyFlags memoryPropertyFlags, VkDeviceSize size, VkBuffer *buffer, VkDeviceMemory *memory, void *data)
{
// Create the buffer handle
VkBufferCreateInfo bufferCreateInfo = vks::initializers::bufferCreateInfo(usageFlags, size);
bufferCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
CHECK_VK_RESULT(vkCreateBuffer(device, &bufferCreateInfo, nullptr, buffer));
// Create the memory backing up the buffer handle
VkMemoryRequirements memReqs;
VkMemoryAllocateInfo memAlloc = vks::initializers::memoryAllocateInfo();
vkGetBufferMemoryRequirements(device, *buffer, &memReqs);
memAlloc.allocationSize = memReqs.size;
// Find a memory type index that fits the properties of the buffer
memAlloc.memoryTypeIndex = GetMemoryType(memReqs.memoryTypeBits, memoryPropertyFlags);
// If the buffer has VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT set we also need to enable the appropriate flag during allocation
VkMemoryAllocateFlagsInfoKHR allocFlagsInfo{};
if (usageFlags & VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT) {
allocFlagsInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO_KHR;
allocFlagsInfo.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT_KHR;
memAlloc.pNext = &allocFlagsInfo;
}
CHECK_VK_RESULT(vkAllocateMemory(device, &memAlloc, nullptr, memory));
// If a pointer to the buffer data has been passed, map the buffer and copy over the data
if (data != nullptr)
{
void *mapped;
CHECK_VK_RESULT(vkMapMemory(device, *memory, 0, size, 0, &mapped));
memcpy(mapped, data, size);
// If host coherency hasn't been requested, do a manual flush to make writes visible
if ((memoryPropertyFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) == 0)
{
VkMappedMemoryRange mappedRange = vks::initializers::mappedMemoryRange();
mappedRange.memory = *memory;
mappedRange.offset = 0;
mappedRange.size = size;
vkFlushMappedMemoryRanges(device, 1, &mappedRange);
}
vkUnmapMemory(device, *memory);
}
// Attach the memory to the buffer object
CHECK_VK_RESULT(vkBindBufferMemory(device, *buffer, *memory, 0));
}
void VulkanDevice::CreateBuffer(VkBufferUsageFlags usageFlags, VkMemoryPropertyFlags memoryPropertyFlags, vks::Buffer *buffer, VkDeviceSize size, void *data)
{
buffer->device = device;
// Create the buffer handle
VkBufferCreateInfo bufferCreateInfo = vks::initializers::bufferCreateInfo(usageFlags, size);
CHECK_VK_RESULT(vkCreateBuffer(device, &bufferCreateInfo, nullptr, &buffer->buffer));
// Create the memory backing up the buffer handle
VkMemoryRequirements memReqs;
VkMemoryAllocateInfo memAlloc = vks::initializers::memoryAllocateInfo();
vkGetBufferMemoryRequirements(device, buffer->buffer, &memReqs);
memAlloc.allocationSize = memReqs.size;
// Find a memory type index that fits the properties of the buffer
memAlloc.memoryTypeIndex = GetMemoryType(memReqs.memoryTypeBits, memoryPropertyFlags);
// If the buffer has VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT set we also need to enable the appropriate flag during allocation
VkMemoryAllocateFlagsInfoKHR allocFlagsInfo{};
if (usageFlags & VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT) {
allocFlagsInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO_KHR;
allocFlagsInfo.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT_KHR;
memAlloc.pNext = &allocFlagsInfo;
}
CHECK_VK_RESULT(vkAllocateMemory(device, &memAlloc, nullptr, &buffer->memory));
buffer->alignment = memReqs.alignment;
buffer->size = size;
buffer->usageFlags = usageFlags;
buffer->memoryPropertyFlags = memoryPropertyFlags;
// If a pointer to the buffer data has been passed, map the buffer and copy over the data
if (data != nullptr)
{
CHECK_VK_RESULT(buffer->map());
memcpy(buffer->mapped, data, size);
if ((memoryPropertyFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) == 0) {
buffer->flush();
}
buffer->unmap();
}
// Initialize a default descriptor that covers the whole buffer size
buffer->setupDescriptor();
// Attach the memory to the buffer object
CHECK_VK_RESULT(buffer->bind());
}