From f8b32717f345c1987be0b8bb8ef788f222b369f3 Mon Sep 17 00:00:00 2001 From: Piotr Krygier Date: Sat, 17 Dec 2022 20:04:09 +0100 Subject: [PATCH] Add staging buffer --- include/localeVulkan.hpp | 4 +- src/vulkanBase.cpp | 187 +++++++++++++++++++++++++++++++-------- 2 files changed, 150 insertions(+), 41 deletions(-) diff --git a/include/localeVulkan.hpp b/include/localeVulkan.hpp index b04fc08a..dfbb7358 100644 --- a/include/localeVulkan.hpp +++ b/include/localeVulkan.hpp @@ -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, 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", diff --git a/src/vulkanBase.cpp b/src/vulkanBase.cpp index aa0de27a..c4593726 100644 --- a/src/vulkanBase.cpp +++ b/src/vulkanBase.cpp @@ -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 gShaderModules; VkRenderPass gRenderPass = VK_NULL_HANDLE; VkPipelineLayout gPipelineLayout = VK_NULL_HANDLE; VkPipeline gGraphicsPipeline = VK_NULL_HANDLE; -std::vector gSwapchainFramebuffers; -std::vector gImageAvailableSemaphores; -std::vector gRenderFinishedSemaphores; -std::vector gInFlightFences; -Buffer gVertexBuffer; +std::vector gSwapchainFramebuffers = {}; +std::vector gImageAvailableSemaphores = {}; +std::vector gRenderFinishedSemaphores = {}; +std::vector 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 = ©CommandBuffer; + submitInfo.signalSemaphoreCount = 0; + submitInfo.pSignalSemaphores = nullptr; + + // FIXME: At result checks + vkAllocateCommandBuffers(gDevice, &allocInfo, ©CommandBuffer); + vkBeginCommandBuffer(copyCommandBuffer, &beginInfo); + vkCmdCopyBuffer(copyCommandBuffer, src, dst, 1, ©Region); + vkEndCommandBuffer(copyCommandBuffer); + vkQueueSubmit(gGraphicsQueue, 1, &submitInfo, VK_NULL_HANDLE); + /* TODO: Use fences to wait instead of idle */ + vkQueueWaitIdle(gGraphicsQueue); + vkFreeCommandBuffers(gDevice, gCommandPool, 1, ©CommandBuffer); + + 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);