Add staging buffer

This commit is contained in:
Piotr Krygier committed 2022-12-17 21:25:00 +01:00
1 parent f4a6260a5e
commit f8b32717f3
2 files changed
+150 -41

No files matched your search

+2 -2
View File
@@ -33,7 +33,7 @@ enum Errors
VULKAN_FAILED_TO_CREATE_DEVICE,
VULKAN_ALLOCATOR_CREATION_FAILED,
VULKAN_COMMAND_POOL_CREATION_FAILED,
VULKAN_VERTEX_BUFFER_CREATION_FAILED,
VULKAN_BUFFER_CREATION_FAILED,
VULKAN_VERTEX_BUFFER_MAPPING_FAILED,
VULKAN_COMMAND_BUFFER_ALLOCATION_FAILED,
VULKAN_SURFACE_CREATION_FAILED,
@@ -70,7 +70,7 @@ std::array<std::array<const char*, LAST_MESSAGE>, LAST_LANGUAGE> vulkanErrorMess
"Failed to create Vulkan Memory Allocator",
/* VULKAN_COMMAND_POOL_CREATION_FAILED */
"Failed to create command pool",
/* VULKAN_VERTEX_BUFFER_CREATION_FAILED */
/* VULKAN_BUFFER_CREATION_FAILED */
"Failed to create a vertex buffer",
/* VULKAN_VERTEX_BUFFER_MAPPING_FAILED */
"Failed to map vulkan memory buffer",
+148 -39
View File
@@ -72,7 +72,7 @@ enum VULKAN_ERROR
VULKAN_ERROR_DEVICE_CREATION_FAILED,
VULKAN_ERROR_ALLOCATOR_CREATION_FAILED,
VULKAN_ERROR_COMMAND_POOL_CREATION_FAILED,
VULKAN_ERROR_VERTEX_BUFFER_CREATION_FAILED,
VULKAN_ERROR_BUFFER_CREATION_FAILED,
VULKAN_ERROR_VERTEX_BUFFER_MAPPING_FAILED,
VULKAN_ERROR_COMMAND_BUFFER_ALLOCATION_FAILED,
VULKAN_ERROR_SURFACE_CREATION_FAILED,
@@ -202,17 +202,43 @@ std::vector<VkShaderModule> gShaderModules;
VkRenderPass gRenderPass = VK_NULL_HANDLE;
VkPipelineLayout gPipelineLayout = VK_NULL_HANDLE;
VkPipeline gGraphicsPipeline = VK_NULL_HANDLE;
std::vector<VkFramebuffer> gSwapchainFramebuffers;
std::vector<VkSemaphore> gImageAvailableSemaphores;
std::vector<VkSemaphore> gRenderFinishedSemaphores;
std::vector<VkFence> gInFlightFences;
Buffer gVertexBuffer;
std::vector<VkFramebuffer> gSwapchainFramebuffers = {};
std::vector<VkSemaphore> gImageAvailableSemaphores = {};
std::vector<VkSemaphore> gRenderFinishedSemaphores = {};
std::vector<VkFence> gInFlightFences = {};
/* GPU visible buffer */
Buffer gVertexBuffer = {};
/* CPU visible buffer. TODO: Do we need this global? */
Buffer gVertexStagingBuffer = {};
/**
* @brief Helper function. Creates a buffer object
*
* @param size Size of the target buffer
* @param bufferUsage Buffer usage flags
* @param memoryUsage memory usage flags (mostly VMA_MEMORY_USAGE_AUTO)
* @param allocationFlags VMA allocation flags
* @param buffer Buffer, that will be allocated
* @return uint8_t VULKAN_ERROR_NO_ERROR on success. Possible errors:
* VULKAN_ERROR_COMMAND_BUFFER_ALLOCATION_FAILED
*/
static uint8_t createBuffer(const VkDeviceSize size, VkBufferUsageFlags bufferUsage, VmaMemoryUsage memoryUsage,
const VmaAllocationCreateFlags allocationFlags, Buffer& buffer);
/**
* @brief Copy one buffer's data to another
*
* @param src Source buffer
* @param dst Destination buffer
* @param size Size of buffer to copy
* @return uint8_t VULKAN_ERROR_NO_ERROR on success. Possible errors:
*/
static uint8_t copyBuffer(VkBuffer src, VkBuffer dst, VkDeviceSize size);
/**
* @brief Create the Vulkan Instance object
*
* @return int VULKAN_ERROR_NO_ERROR on success. Possible errors:
* @return uint8_t VULKAN_ERROR_NO_ERROR on success. Possible errors:
* VULKAN_ERROR_INSTANCE_INIT_FAILED
*/
static uint8_t createInstance();
@@ -269,7 +295,7 @@ static uint8_t createCommandPools();
* @brief Create a buffer holding all vertex data
*
* @return uint8_t VULKAN_ERROR_NO_ERROR on success. Possible errors:
* VULKAN_ERROR_VERTEX_BUFFER_CREATION_FAILED
* VULKAN_ERROR_BUFFER_CREATION_FAILED
* VULKAN_ERROR_VERTEX_BUFFER_MAPPING_FAILED
*/
static uint8_t createVertexBuffer();
@@ -406,6 +432,92 @@ static uint8_t createFrambuffers();
static void recreateSwapchain();
static uint8_t createBuffer(const VkDeviceSize size, VkBufferUsageFlags bufferUsage, VmaMemoryUsage memoryUsage,
const VmaAllocationCreateFlags allocationFlags, Buffer& buffer)
{
VkBufferCreateInfo vertexBufferInfo;
VmaAllocationCreateInfo allocInfo;
vertexBufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
vertexBufferInfo.pNext = nullptr;
vertexBufferInfo.flags = 0U;
vertexBufferInfo.size = size;
vertexBufferInfo.usage = bufferUsage;
vertexBufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
vertexBufferInfo.queueFamilyIndexCount = 0U;
vertexBufferInfo.pQueueFamilyIndices = nullptr;
/* Disalows random access to memory. TODO: Consider changing to VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT? */
allocInfo.flags = allocationFlags;
allocInfo.usage = memoryUsage;
allocInfo.memoryTypeBits = 0U;
allocInfo.requiredFlags = 0U;
allocInfo.preferredFlags = 0U;
allocInfo.pool = VK_NULL_HANDLE;
allocInfo.pUserData = VK_NULL_HANDLE;
allocInfo.priority = 0.0f;
if (VK_SUCCESS != vmaCreateBuffer(gAllocator,
&vertexBufferInfo,
&allocInfo,
&buffer.buffer,
&buffer.allocation,
nullptr)) {
LOGF << vulkanErrorMesssages[VULKAN_BUFFER_CREATION_FAILED];
return VULKAN_ERROR_BUFFER_CREATION_FAILED;
}
return VULKAN_ERROR_NO_ERROR;
}
static uint8_t copyBuffer(VkBuffer src, VkBuffer dst, VkDeviceSize size)
{
/* Vulkan buffers can only be copied using command buffers */
VkBufferCopy copyRegion;
VkSubmitInfo submitInfo;
VkCommandBuffer copyCommandBuffer;
VkCommandBufferBeginInfo beginInfo;
VkCommandBufferAllocateInfo allocInfo;
allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
allocInfo.pNext = nullptr;
allocInfo.commandPool = gCommandPool;
allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
allocInfo.commandBufferCount = 1;
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
beginInfo.pNext = nullptr;
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
beginInfo.pInheritanceInfo = nullptr;
copyRegion.srcOffset = 0;
copyRegion.dstOffset = 0;
copyRegion.size = size;
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submitInfo.pNext = nullptr;
submitInfo.waitSemaphoreCount = 0;
submitInfo.pWaitSemaphores = nullptr;
submitInfo.pWaitDstStageMask = nullptr;
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &copyCommandBuffer;
submitInfo.signalSemaphoreCount = 0;
submitInfo.pSignalSemaphores = nullptr;
// FIXME: At result checks
vkAllocateCommandBuffers(gDevice, &allocInfo, &copyCommandBuffer);
vkBeginCommandBuffer(copyCommandBuffer, &beginInfo);
vkCmdCopyBuffer(copyCommandBuffer, src, dst, 1, &copyRegion);
vkEndCommandBuffer(copyCommandBuffer);
vkQueueSubmit(gGraphicsQueue, 1, &submitInfo, VK_NULL_HANDLE);
/* TODO: Use fences to wait instead of idle */
vkQueueWaitIdle(gGraphicsQueue);
vkFreeCommandBuffers(gDevice, gCommandPool, 1, &copyCommandBuffer);
return VULKAN_ERROR_NO_ERROR;
}
static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
@@ -738,47 +850,43 @@ static uint8_t createCommandPools()
static uint8_t createVertexBuffer()
{
VkBufferCreateInfo vertexBufferInfo;
VmaAllocationCreateInfo allocInfo;
void* mappedData;
VkDeviceSize bufferSize;
vertexBufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
vertexBufferInfo.pNext = nullptr;
vertexBufferInfo.flags = 0U;
vertexBufferInfo.size = sizeof(vertices[0]) * vertices.size();
vertexBufferInfo.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
vertexBufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
vertexBufferInfo.queueFamilyIndexCount = 0U;
vertexBufferInfo.pQueueFamilyIndices = nullptr;
bufferSize = sizeof(vertices[0]) * vertices.size();
/* Disalows random access to memory. TODO: Consider changing to VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT? */
allocInfo.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT;
allocInfo.usage = VMA_MEMORY_USAGE_AUTO;
allocInfo.memoryTypeBits = 0U;
allocInfo.requiredFlags = 0U;
allocInfo.preferredFlags = 0U;
allocInfo.pool = VK_NULL_HANDLE;
allocInfo.pUserData = VK_NULL_HANDLE;
allocInfo.priority = 0.0f;
if (VK_SUCCESS != vmaCreateBuffer(gAllocator,
&vertexBufferInfo,
&allocInfo,
&gVertexBuffer.buffer,
&gVertexBuffer.allocation,
nullptr)) {
LOGF << vulkanErrorMesssages[VULKAN_VERTEX_BUFFER_CREATION_FAILED];
return VULKAN_ERROR_VERTEX_BUFFER_CREATION_FAILED;
/* Creating staging buffer*/
if (VK_SUCCESS != createBuffer(bufferSize,
VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
VMA_MEMORY_USAGE_AUTO_PREFER_HOST,
VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT,
gVertexStagingBuffer)) {
LOGF << vulkanErrorMesssages[VULKAN_BUFFER_CREATION_FAILED];
return VULKAN_ERROR_BUFFER_CREATION_FAILED;
}
/* Fill vertex buffer */
if (VK_SUCCESS != vmaMapMemory(gAllocator, gVertexBuffer.allocation, &mappedData))
/* Create Vertex Buffer*/
if (VK_SUCCESS != createBuffer(bufferSize,
VK_BUFFER_USAGE_TRANSFER_DST_BIT
| VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE,
0, /* Will not be mapped with vmaMapMemory */
gVertexBuffer)) {
LOGF << vulkanErrorMesssages[VULKAN_BUFFER_CREATION_FAILED];
return VULKAN_ERROR_BUFFER_CREATION_FAILED;
}
/* Fill staging buffer */
if (VK_SUCCESS != vmaMapMemory(gAllocator, gVertexStagingBuffer.allocation, &mappedData))
{
LOGF << vulkanErrorMesssages[VULKAN_VERTEX_BUFFER_MAPPING_FAILED];
return VULKAN_ERROR_VERTEX_BUFFER_MAPPING_FAILED;
}
memcpy(mappedData, vertices.data(), sizeof(Vertex) * vertices.size());
vmaUnmapMemory(gAllocator, gVertexBuffer.allocation);
vmaUnmapMemory(gAllocator, gVertexStagingBuffer.allocation);
copyBuffer(gVertexStagingBuffer.buffer, gVertexBuffer.buffer, bufferSize);
return VULKAN_ERROR_NO_ERROR;
}
@@ -1460,6 +1568,7 @@ void deinitVulkan()
cleanupSwapchain();
vmaDestroyBuffer(gAllocator, gVertexBuffer.buffer, gVertexBuffer.allocation);
vmaDestroyBuffer(gAllocator, gVertexStagingBuffer.buffer, gVertexStagingBuffer.allocation);
for (size_t i = 0; i < SWAP_BUFFER_COUNT; ++i) {
vkDestroySemaphore(gDevice, gImageAvailableSemaphores[i], nullptr);
vkDestroySemaphore(gDevice, gRenderFinishedSemaphores[i], nullptr);