create buffers with VMA

This commit is contained in:
Gregory Wells
2025-08-12 14:10:25 -04:00
parent bddc4dfb0d
commit 88aa38adbf
8 changed files with 114 additions and 94 deletions

View File

@@ -14,6 +14,8 @@ find_package(Vulkan REQUIRED)
add_library(GryphnVulkanImpl STATIC ${SOURCE_FILES} ${METAL_FILES} ${LOADER_FILES} depends/memory_allocator/vk_mem_alloc.cpp) add_library(GryphnVulkanImpl STATIC ${SOURCE_FILES} ${METAL_FILES} ${LOADER_FILES} depends/memory_allocator/vk_mem_alloc.cpp)
target_link_libraries(GryphnVulkanImpl ${Vulkan_LIBRARY}) target_link_libraries(GryphnVulkanImpl ${Vulkan_LIBRARY})
target_compile_options(GryphnVulkanImpl PRIVATE -Wno-nullability-completeness)
target_include_directories(GryphnVulkanImpl PUBLIC target_include_directories(GryphnVulkanImpl PUBLIC
${Vulkan_INCLUDE_DIRS} ${Vulkan_INCLUDE_DIRS}
${CMAKE_CURRENT_SOURCE_DIR}/src/ ${CMAKE_CURRENT_SOURCE_DIR}/src/

View File

@@ -37,7 +37,7 @@ gnDeviceFunctions loadVulkanDeviceFunctions(void) {
._gnCreateBuffer = createBuffer, ._gnCreateBuffer = createBuffer,
._gnBufferData = vulkanBufferData, ._gnBufferData = vulkanBufferData,
._gnBufferSubData = vulkanBufferSubData, ._gnBufferSubData = vulkanBufferSubData,
._gnMapBuffer = mapBuffer, ._gnMapBuffer = vulkanMapBuffer,
._gnDestroyBuffer = destroyBuffer, ._gnDestroyBuffer = destroyBuffer,
._gnCreateUniformPool = createUniformPool, ._gnCreateUniformPool = createUniformPool,

View File

@@ -7,57 +7,13 @@
VkBufferUsageFlags vkGryphnBufferType(gnBufferType type) { VkBufferUsageFlags vkGryphnBufferType(gnBufferType type) {
VkBufferUsageFlags usageFlags = 0; VkBufferUsageFlags usageFlags = 0;
switch (type) { if ((type & GN_VERTEX_BUFFER) == GN_VERTEX_BUFFER) usageFlags |= VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
case GN_VERTEX_BUFFER: usageFlags |= VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; break; if ((type & GN_INDEX_BUFFER) == GN_INDEX_BUFFER) usageFlags |= VK_BUFFER_USAGE_INDEX_BUFFER_BIT;
case GN_INDEX_BUFFER: usageFlags |= VK_BUFFER_USAGE_INDEX_BUFFER_BIT; break; if ((type & GN_UNIFORM_BUFFER) == GN_UNIFORM_BUFFER) usageFlags |= VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
case GN_UNIFORM_BUFFER: usageFlags |= VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; break; if ((type & GN_STORAGE_BUFFER) == GN_STORAGE_BUFFER) usageFlags |= VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
case GN_STORAGE_BUFFER: usageFlags |= VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; break;
}
return usageFlags; return usageFlags;
} }
uint32_t VkMemoryIndex(VkPhysicalDevice device, uint32_t memoryType, VkMemoryPropertyFlags flags, gnBool* foundMemory) {
VkPhysicalDeviceMemoryProperties memoryProperties;
vkGetPhysicalDeviceMemoryProperties(device, &memoryProperties);
for (uint32_t i = 0; i < memoryProperties.memoryTypeCount; i++) {
if ((memoryType & (1 << i)) && (memoryProperties.memoryTypes[i].propertyFlags & flags) == flags) {
*foundMemory = GN_TRUE;
return i;
}
} // this whole thing was adapted from vulkan-tutorial.com
return 0;
}
gnReturnCode VkCreateBuffer(
VkGryphnBuffer* buffer, size_t size, gnDevice device,
VkMemoryPropertyFlags flags, VkBufferUsageFlags usage
) {
VkBufferCreateInfo bufferInfo = {
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
.size = size,
.usage = usage,
.sharingMode = VK_SHARING_MODE_EXCLUSIVE
};
VkResult created_buffer = vkCreateBuffer(device->outputDevice->device, &bufferInfo, NULL, &buffer->buffer);
if (created_buffer != VK_SUCCESS)
return VkResultToGnReturnCode(created_buffer);
VkMemoryRequirements bufferRequirements;
vkGetBufferMemoryRequirements(device->outputDevice->device, buffer->buffer, &bufferRequirements);
gnBool foundMemory = GN_FALSE;
VkMemoryAllocateInfo memoryAllocateInfo = {
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
.allocationSize = bufferRequirements.size,
.memoryTypeIndex = VkMemoryIndex(device->outputDevice->physicalDevice, bufferRequirements.memoryTypeBits, flags, &foundMemory)
};
if (!foundMemory) return GN_FAILED_TO_ALLOCATE_MEMORY;
VkResult memoryFound = vkAllocateMemory(device->outputDevice->device, &memoryAllocateInfo, NULL, &buffer->memory);
if (memoryFound == VK_SUCCESS) vkBindBufferMemory(device->outputDevice->device, buffer->buffer, buffer->memory, 0);
return VkResultToGnReturnCode(memoryFound);
}
void VkCopyBuffer(gnDevice device, VkBuffer source, VkBuffer destination, VkBufferCopy copy) { void VkCopyBuffer(gnDevice device, VkBuffer source, VkBuffer destination, VkBufferCopy copy) {
VkCommandBuffer transferBuffer = gnBeginVulkanTransferOperation(device); VkCommandBuffer transferBuffer = gnBeginVulkanTransferOperation(device);
vkCmdCopyBuffer(transferBuffer, source, destination, 1, &copy); vkCmdCopyBuffer(transferBuffer, source, destination, 1, &copy);
@@ -68,19 +24,41 @@ gnReturnCode createBuffer(gnBufferHandle buffer, gnOutputDeviceHandle device, gn
buffer->buffer = malloc(sizeof(struct gnPlatformBuffer_t)); buffer->buffer = malloc(sizeof(struct gnPlatformBuffer_t));
buffer->buffer->useStagingBuffer = (info.usage == GN_STATIC_DRAW); buffer->buffer->useStagingBuffer = (info.usage == GN_STATIC_DRAW);
if (info.usage == GN_STATIC_DRAW) { if (info.usage == GN_STATIC_DRAW) {
return VkCreateBuffer( VkBufferCreateInfo bufferCreateInfo = {
&buffer->buffer->buffer, .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
info.size, device, .pNext = NULL,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, .flags = 0,
vkGryphnBufferType(info.type) | VK_BUFFER_USAGE_TRANSFER_DST_BIT .queueFamilyIndexCount = 0,
); .size = info.size,
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
.usage = vkGryphnBufferType(info.type) | VK_BUFFER_USAGE_TRANSFER_DST_BIT
};
VmaAllocationCreateInfo bufferAllocationInfo = {
.usage = VMA_MEMORY_USAGE_AUTO,
.flags = 0,
.requiredFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
};
return VkResultToGnReturnCode(vmaCreateBuffer(device->outputDevice->allocator, &bufferCreateInfo, &bufferAllocationInfo, &buffer->buffer->buffer.buffer, &buffer->buffer->buffer.allocation, NULL));
} else { } else {
return VkCreateBuffer( VkBufferCreateInfo bufferCreateInfo = {
&buffer->buffer->buffer, .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
info.size, device, .pNext = NULL,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, .flags = 0,
vkGryphnBufferType(info.type) .queueFamilyIndexCount = 0,
); .size = info.size,
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
.usage = vkGryphnBufferType(info.type)
};
VmaAllocationCreateInfo bufferAllocationInfo = {
.usage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE,
.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT,
.requiredFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
};
return VkResultToGnReturnCode(vmaCreateBuffer(device->outputDevice->allocator, &bufferCreateInfo, &bufferAllocationInfo, &buffer->buffer->buffer.buffer, &buffer->buffer->buffer.allocation, NULL));
} }
return GN_SUCCESS; return GN_SUCCESS;
@@ -95,9 +73,9 @@ void vulkanBufferSubData(gnBufferHandle buffer, size_t offset, size_t dataSize,
VkDeviceSize sizeLeft = dataSize; VkDeviceSize sizeLeft = dataSize;
while (sizeLeft > 0) { while (sizeLeft > 0) {
VkDeviceSize chunkSize = (buffer->device->outputDevice->stagingBufferSize < sizeLeft) ? buffer->device->outputDevice->stagingBufferSize : sizeLeft; VkDeviceSize chunkSize = (buffer->device->outputDevice->stagingBufferSize < sizeLeft) ? buffer->device->outputDevice->stagingBufferSize : sizeLeft;
vkMapMemory(buffer->device->outputDevice->device, stagingBuffer->memory, 0, chunkSize, 0, &bufferData); vulkanMapBufferInternal(buffer->device, *stagingBuffer, &bufferData);
memcpy(bufferData, (char*)data + (dataSize - sizeLeft), chunkSize); memcpy(bufferData, (char*)data + (dataSize - sizeLeft), chunkSize);
vkUnmapMemory(buffer->device->outputDevice->device, stagingBuffer->memory); vulkanUnmapBufferInternal(buffer->device, *stagingBuffer);
VkBufferCopy copyRegion = { VkBufferCopy copyRegion = {
.srcOffset = 0, .srcOffset = 0,
@@ -108,24 +86,35 @@ void vulkanBufferSubData(gnBufferHandle buffer, size_t offset, size_t dataSize,
sizeLeft -= chunkSize; sizeLeft -= chunkSize;
} }
} else { } else {
vkMapMemory(buffer->device->outputDevice->device, buffer->buffer->buffer.memory, 0, dataSize, 0, &bufferData); bufferData = vulkanMapBuffer(buffer);
memcpy((char*)bufferData + offset, data, dataSize); memcpy((char*)bufferData + offset, data, dataSize);
vkUnmapMemory(buffer->device->outputDevice->device, buffer->buffer->buffer.memory); vulkanUnmapBuffer(buffer);
} }
} }
void* mapBuffer(gnBufferHandle buffer) {
void vulkanMapBufferInternal(gnDevice device, VkGryphnBuffer buffer, void* data) {
vmaMapMemory(device->outputDevice->allocator, buffer.allocation, data);
}
void vulkanUnmapBufferInternal(gnDevice device, VkGryphnBuffer buffer) {
vmaUnmapMemory(device->outputDevice->allocator, buffer.allocation);
}
void* vulkanMapBuffer(gnBufferHandle buffer) {
void* data; void* data;
vkMapMemory(buffer->device->outputDevice->device, buffer->buffer->buffer.memory, 0, buffer->info.size, 0, &data); vulkanMapBufferInternal(buffer->device, buffer->buffer->buffer, &data);
return data; return data;
} }
void gnDestroyVulkanBuffer(VkGryphnBuffer* buffer, VkDevice device) { void vulkanUnmapBuffer(gnBufferHandle buffer) {
vkDestroyBuffer(device, buffer->buffer, NULL); vulkanUnmapBufferInternal(buffer->device, buffer->buffer->buffer);
vkFreeMemory(device, buffer->memory, NULL); }
void gnDestroyVulkanBuffer(VkGryphnBuffer* buffer, gnDevice device) {
vmaDestroyBuffer(device->outputDevice->allocator, buffer->buffer, buffer->allocation);
} }
void destroyBuffer(gnBufferHandle buffer) { void destroyBuffer(gnBufferHandle buffer) {
// if (buffer->buffer->useStagingBuffer == gnTrue) gnDestroyVulkanBuffer(&buffer->buffer->stagingBuffer, buffer->device->outputDevice->device); gnDestroyVulkanBuffer(&buffer->buffer->buffer, buffer->device);
gnDestroyVulkanBuffer(&buffer->buffer->buffer, buffer->device->outputDevice->device);
free(buffer->buffer); free(buffer->buffer);
} }

View File

@@ -2,27 +2,32 @@
#include <vulkan/vulkan.h> #include <vulkan/vulkan.h>
#include "utils/gryphn_bool.h" #include "utils/gryphn_bool.h"
#include <buffers/gryphn_buffer.h> #include <buffers/gryphn_buffer.h>
#include <memory_allocator/vk_mem_alloc.h>
typedef struct VkGryphnBuffer { typedef struct VkGryphnBuffer {
VkBuffer buffer; VkBuffer buffer;
VkDeviceMemory memory; VmaAllocation allocation;
} VkGryphnBuffer; } VkGryphnBuffer;
void gnDestroyVulkanBuffer(VkGryphnBuffer* buffer, VkDevice device);
struct gnPlatformBuffer_t { struct gnPlatformBuffer_t {
VkGryphnBuffer buffer; VkGryphnBuffer buffer;
gnBool useStagingBuffer; gnBool useStagingBuffer;
}; };
gnReturnCode VkCreateBuffer( // gnReturnCode VkCreateBuffer(
VkGryphnBuffer* buffer, size_t size, gnDevice device, // VkGryphnBuffer* buffer, size_t size, gnDevice device,
VkMemoryPropertyFlags flags, VkBufferUsageFlags usage // VkMemoryPropertyFlags flags, VkBufferUsageFlags usage
); // );
void gnDestroyVulkanBuffer(VkGryphnBuffer* buffer, VkDevice device); // void gnDestroyVulkanBuffer(VkGryphnBuffer* buffer, gnDevice device);
uint32_t VkMemoryIndex(VkPhysicalDevice device, uint32_t memoryType, VkMemoryPropertyFlags flags, gnBool* foundMemory); // uint32_t VkMemoryIndex(VkPhysicalDevice device, uint32_t memoryType, VkMemoryPropertyFlags flags, gnBool* foundMemory);
gnReturnCode createBuffer(gnBufferHandle buffer, gnOutputDeviceHandle device, gnBufferInfo info); gnReturnCode createBuffer(gnBufferHandle buffer, gnOutputDeviceHandle device, gnBufferInfo info);
void vulkanBufferData(gnBufferHandle buffer, size_t dataSize, void* data); void vulkanBufferData(gnBufferHandle buffer, size_t dataSize, void* data);
void vulkanBufferSubData(gnBufferHandle buffer, size_t offset, size_t dataSize, void* data); void vulkanBufferSubData(gnBufferHandle buffer, size_t offset, size_t dataSize, void* data);
void* mapBuffer(gnBufferHandle buffer);
void vulkanMapBufferInternal(gnDevice device, VkGryphnBuffer buffer, void* data);
void vulkanUnmapBufferInternal(gnDevice device, VkGryphnBuffer buffer);
void* vulkanMapBuffer(gnBufferHandle buffer);
void vulkanUnmapBuffer(gnBufferHandle buffer);
void destroyBuffer(gnBufferHandle buffer); void destroyBuffer(gnBufferHandle buffer);

View File

@@ -4,6 +4,7 @@
#include "vulkan_device_extensions.h" #include "vulkan_device_extensions.h"
#include "instance/gryphn_instance.h" #include "instance/gryphn_instance.h"
#include "commands/command_buffer/vulkan_command_buffer.h" #include "commands/command_buffer/vulkan_command_buffer.h"
#include "instance/vulkan_instance.h"
#include "vulkan_result_converter.h" #include "vulkan_result_converter.h"
#include "string.h" #include "string.h"
@@ -95,15 +96,34 @@ gnReturnCode createVulkanOutputDevice(gnInstanceHandle instance, gnOutputDeviceH
VkResult fence_result = vkCreateFence(device->outputDevice->device, &fenceInfo, NULL, &device->outputDevice->barrierFence); VkResult fence_result = vkCreateFence(device->outputDevice->device, &fenceInfo, NULL, &device->outputDevice->barrierFence);
if (fence_result != VK_SUCCESS) VkResultToGnReturnCode(fence_result); if (fence_result != VK_SUCCESS) VkResultToGnReturnCode(fence_result);
VmaAllocatorCreateInfo allocatorCreateInfo = {
.device = device->outputDevice->device,
.physicalDevice = device->outputDevice->physicalDevice,
.instance = instance->instance->vk_instance,
};
if (vmaCreateAllocator(&allocatorCreateInfo, &device->outputDevice->allocator) != VK_SUCCESS)
return GN_FAILED_CREATE_ALLOCATOR;
// create the massive staging buffer // create the massive staging buffer
device->outputDevice->stagingBufferSize = 128 * 1024 * 1024; device->outputDevice->stagingBufferSize = 128 * 1024 * 1024;
gnReturnCode code = VkCreateBuffer(
&device->outputDevice->stagingBuffer, VkBufferCreateInfo bufferCreateInfo = {
device->outputDevice->stagingBufferSize, device, .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, .pNext = NULL,
VK_BUFFER_USAGE_TRANSFER_SRC_BIT .flags = 0,
); .queueFamilyIndexCount = 0,
return code; // lowkey is a hack .size = device->outputDevice->stagingBufferSize,
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT
};
VmaAllocationCreateInfo bufferAllocationInfo = {
.usage = VMA_MEMORY_USAGE_CPU_ONLY,
.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT,
.requiredFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
};
return VkResultToGnReturnCode(vmaCreateBuffer(device->outputDevice->allocator, &bufferCreateInfo, &bufferAllocationInfo, &device->outputDevice->stagingBuffer.buffer, &device->outputDevice->stagingBuffer.allocation, NULL)); // lowkey is a hack
} }
void waitForDevice(const gnOutputDeviceHandle device) { void waitForDevice(const gnOutputDeviceHandle device) {
@@ -112,9 +132,10 @@ void waitForDevice(const gnOutputDeviceHandle device) {
void destroyVulkanOutputDevice(gnOutputDeviceHandle device) { void destroyVulkanOutputDevice(gnOutputDeviceHandle device) {
vkDestroyFence(device->outputDevice->device, device->outputDevice->barrierFence, NULL); vkDestroyFence(device->outputDevice->device, device->outputDevice->barrierFence, NULL);
gnDestroyVulkanBuffer(&device->outputDevice->stagingBuffer, device->outputDevice->device); vmaDestroyBuffer(device->outputDevice->allocator, device->outputDevice->stagingBuffer.buffer, device->outputDevice->stagingBuffer.allocation);
vkDestroyCommandPool(device->outputDevice->device, device->outputDevice->transferCommandPool, NULL); vkDestroyCommandPool(device->outputDevice->device, device->outputDevice->transferCommandPool, NULL);
vkDestroyDevice(device->outputDevice->device, NULL); vkDestroyDevice(device->outputDevice->device, NULL);
vmaDestroyAllocator(device->outputDevice->allocator);
free(device->outputDevice); free(device->outputDevice);
} }

View File

@@ -3,6 +3,7 @@
#include <output_device/gryphn_output_device.h> #include <output_device/gryphn_output_device.h>
#include "buffers/vulkan_buffer.h" #include "buffers/vulkan_buffer.h"
#include "vulkan_physical_device.h" #include "vulkan_physical_device.h"
#include <memory_allocator/vk_mem_alloc.h>
typedef struct vulkanQueue { typedef struct vulkanQueue {
VkQueue queue; VkQueue queue;
@@ -24,6 +25,8 @@ typedef struct gnPlatformOutputDevice_t {
VkFence barrierFence; VkFence barrierFence;
gnBool enabledOversizedDescriptorPools; gnBool enabledOversizedDescriptorPools;
VmaAllocator allocator;
} gnPlatformOutputDevice; } gnPlatformOutputDevice;
VkCommandBuffer gnBeginVulkanTransferOperation(gnDevice device); VkCommandBuffer gnBeginVulkanTransferOperation(gnDevice device);

View File

@@ -12,7 +12,7 @@ typedef enum gnReturnCode {
GN_FAILED_TO_FIND_ENTRY_POINT, GN_FAILED_TO_LOAD_FUNCTION, GN_INCOMPLETE, GN_FAILED_TO_FIND_ENTRY_POINT, GN_FAILED_TO_LOAD_FUNCTION, GN_INCOMPLETE,
GN_NOT_READY, GN_TIMEOUT, GN_DEVICE_LOST, GN_FAILED_MEMORY_MAP, GN_UNSUPPORTED_FEATURE, GN_NOT_READY, GN_TIMEOUT, GN_DEVICE_LOST, GN_FAILED_MEMORY_MAP, GN_UNSUPPORTED_FEATURE,
GN_OVERALLOCATION, GN_FRAGMENTATION, GN_INVALID_HANDLE, GN_SURFACE_LOST, GN_WINDOW_IN_USE, GN_OVERALLOCATION, GN_FRAGMENTATION, GN_INVALID_HANDLE, GN_SURFACE_LOST, GN_WINDOW_IN_USE,
GN_INCOMPATIBLE_DISPLAY, GN_UNSUPPORTED_IMAGE_USE, GN_INCOMPATIBLE_DISPLAY, GN_UNSUPPORTED_IMAGE_USE, GN_FAILED_CREATE_ALLOCATOR,
GN_UNLOADED_EXTENSION = -1, GN_UNLOADED_EXTENSION = -1,
GN_UNLOADED_LAYER = -2, GN_UNLOADED_LAYER = -2,

View File

@@ -9,10 +9,10 @@ typedef enum gnIndexType {
} gnIndexType; } gnIndexType;
typedef enum gnBufferType { typedef enum gnBufferType {
GN_VERTEX_BUFFER = 0x00000001, GN_VERTEX_BUFFER = 1 << 0,
GN_INDEX_BUFFER = 0x00000002, GN_INDEX_BUFFER = 1 << 2,
GN_UNIFORM_BUFFER = 0x00000004, GN_UNIFORM_BUFFER = 1 << 3,
GN_STORAGE_BUFFER = 0x00000008 GN_STORAGE_BUFFER = 1 << 4
} gnBufferType; // I need to support more buffer types } gnBufferType; // I need to support more buffer types
// i love that OpenGL does this so im stealing it // i love that OpenGL does this so im stealing it