Add texture handler

Added functionality to load images as textures and bind them to meshes.
This commit is contained in:
Piotr Krygier committed 2023-10-02 13:21:17 +02:00
1 parent 0e040dd0d5
commit 4fcda01ba2
24 files changed
+897 -200

No files matched your search

+48 -143
View File
@@ -5,6 +5,7 @@
#include "utilities/logger.h"
#include "mesh_controller.h"
#include "rse_math.h"
#include "rse_vulkan_commands.h"
#include <stdint.h>
#include <string.h>
@@ -19,141 +20,28 @@ struct rse_vulkan_buffer_t g_index_buffer;
struct rse_vulkan_buffer_t g_instance_buffers[MAX_MESH_NUMBER];
struct rse_vulkan_buffer_t g_draw_indirect_command_buffer;
VkCommandPool g_command_pool = VK_NULL_HANDLE;
/**
* @brief Helper function. Creates a buffer object
*
* @param size Size of the target buffer
* @param buffer_usage Buffer usage flags
* @param memory_usage memory usage flags (mostly VMA_MEMORY_USAGE_AUTO)
* @param allocation_flags 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 create_buffer(const VkDeviceSize size,
VkBufferUsageFlags buffer_usage,
VmaMemoryUsage memory_usage,
const VmaAllocationCreateFlags allocation_flags,
struct rse_vulkan_buffer_t* buffer)
{
VkBufferCreateInfo vertex_buffer_info = {};
VmaAllocationCreateInfo create_info = {};
vertex_buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
vertex_buffer_info.pNext = NULL;
vertex_buffer_info.flags = 0U;
vertex_buffer_info.size = size;
vertex_buffer_info.usage = buffer_usage;
vertex_buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
vertex_buffer_info.queueFamilyIndexCount = 0U;
vertex_buffer_info.pQueueFamilyIndices = NULL;
create_info.flags = allocation_flags;
create_info.usage = memory_usage;
create_info.memoryTypeBits = 0U;
create_info.requiredFlags = 0U;
create_info.preferredFlags = 0U;
create_info.pool = VK_NULL_HANDLE;
create_info.pUserData = VK_NULL_HANDLE;
create_info.priority = 0.0f;
if (VK_SUCCESS != vmaCreateBuffer(g_vulkan_state.allocator,
&vertex_buffer_info,
&create_info,
&buffer->buffer,
&buffer->allocation,
&buffer->allocation_info)) {
LOGF(vulkan_error_messages[VULKAN_BUFFER_CREATION_FAILED]);
return VULKAN_ERROR_BUFFER_CREATION_FAILED;
}
return VULKAN_ERROR_NO_ERROR;
}
/**
* @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 copy_buffer(VkBuffer src, VkBuffer dst, VkDeviceSize size, VkDeviceSize dest_offset)
static void copy_buffer(VkBuffer src, VkBuffer dst, VkDeviceSize size, VkDeviceSize dest_offset)
{
/* Vulkan buffers can only be copied using command buffers */
VkResult status = VK_FALSE;
VkBufferCopy copy_region = {};
VkSubmitInfo submit_info = {};
VkCommandBuffer copy_command_buffer = NULL;
VkCommandBufferBeginInfo begin_info = {};
VkCommandBufferAllocateInfo alloc_info = {};
VkCommandBuffer command_buffer = {0};
alloc_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
alloc_info.pNext = NULL;
alloc_info.commandPool = g_command_pool;
alloc_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
alloc_info.commandBufferCount = 1;
command_buffer = rse_begin_single_time_command();
begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
begin_info.pNext = NULL;
begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
begin_info.pInheritanceInfo = NULL;
copy_region.srcOffset = 0;
copy_region.srcOffset = 0U;
copy_region.dstOffset = dest_offset;
copy_region.size = size;
submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submit_info.pNext = NULL;
submit_info.waitSemaphoreCount = 0;
submit_info.pWaitSemaphores = NULL;
submit_info.pWaitDstStageMask = NULL;
submit_info.commandBufferCount = 1;
submit_info.pCommandBuffers = &copy_command_buffer;
submit_info.signalSemaphoreCount = 0;
submit_info.pSignalSemaphores = NULL;
vkCmdCopyBuffer(command_buffer, src, dst, 1, &copy_region);
// FIXME: Add result checks
status = vkAllocateCommandBuffers(g_vulkan_state.device, &alloc_info, &copy_command_buffer);
status = vkBeginCommandBuffer(copy_command_buffer, &begin_info);
vkCmdCopyBuffer(copy_command_buffer, src, dst, 1, &copy_region);
status = vkEndCommandBuffer(copy_command_buffer);
status = vkQueueSubmit(g_vulkan_state.graphics_queue, 1, &submit_info, VK_NULL_HANDLE);
/* TODO: Use fences to wait instead of idle */
status = vkQueueWaitIdle(g_vulkan_state.graphics_queue);
vkFreeCommandBuffers(g_vulkan_state.device, g_command_pool, 1, &copy_command_buffer);
if (status != VK_SUCCESS) {
return VULKAN_ERROR_NO_ERROR;
}
return VULKAN_ERROR_NO_ERROR;
}
/**
* @brief Create Command Pools
*
* @return uint8_t VULKAN_ERROR_NO_ERROR on success. Possible errors:
* VULKAN_ERROR_COMMAND_POOL_CREATION_FAILED
*/
static uint8_t create_command_pools()
{
VkCommandPoolCreateInfo create_info;
create_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
create_info.pNext = NULL;
create_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
create_info.queueFamilyIndex = g_vulkan_state.queue_family_indices[0]; /* TODO: Change when more families are needed */
if (VK_SUCCESS != vkCreateCommandPool(g_vulkan_state.device, &create_info, NULL, &g_command_pool)) {
LOGF(vulkan_error_messages[VULKAN_COMMAND_POOL_CREATION_FAILED]);
return VULKAN_ERROR_COMMAND_POOL_CREATION_FAILED;
}
return VULKAN_ERROR_NO_ERROR;
rse_end_single_time_comands(command_buffer);
}
@@ -262,32 +150,52 @@ static uint8_t create_uniform_buffer()
return VULKAN_ERROR_NO_ERROR;
}
/**
* @brief Allocate Command Buffers
*
* @return uint8_t VULKAN_ERROR_NO_ERROR on success. Possible errors:
* VULKAN_ERROR_COMMAND_BUFFER_ALLOCATION_FAILED
*/
static uint8_t allocate_command_buffers()
uint8_t create_buffer(const VkDeviceSize size,
VkBufferUsageFlags buffer_usage,
VmaMemoryUsage memory_usage,
const VmaAllocationCreateFlags allocation_flags,
struct rse_vulkan_buffer_t* buffer)
{
VkCommandBufferAllocateInfo allocate_info;
VkBufferCreateInfo vertex_buffer_info = {};
VmaAllocationCreateInfo create_info = {};
/* Allocate memory for command buffers */
allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
allocate_info.pNext = NULL;
allocate_info.commandPool = g_command_pool;
allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; /* TODO: When needed, add secondary command buffer */
allocate_info.commandBufferCount = SWAP_BUFFER_COUNT;
vertex_buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
vertex_buffer_info.pNext = NULL;
vertex_buffer_info.flags = 0U;
vertex_buffer_info.size = size;
vertex_buffer_info.usage = buffer_usage;
vertex_buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
vertex_buffer_info.queueFamilyIndexCount = 0U;
vertex_buffer_info.pQueueFamilyIndices = NULL;
if (VK_SUCCESS != vkAllocateCommandBuffers(g_vulkan_state.device,
&allocate_info,
g_vulkan_state.command_buffers)) {
LOGF(vulkan_error_messages[VULKAN_COMMAND_BUFFER_ALLOCATION_FAILED]);
return VULKAN_ERROR_COMMAND_BUFFER_ALLOCATION_FAILED;
create_info.flags = allocation_flags;
create_info.usage = memory_usage;
create_info.memoryTypeBits = 0U;
create_info.requiredFlags = 0U;
create_info.preferredFlags = 0U;
create_info.pool = VK_NULL_HANDLE;
create_info.pUserData = VK_NULL_HANDLE;
create_info.priority = 0.0f;
if (VK_SUCCESS != vmaCreateBuffer(g_vulkan_state.allocator,
&vertex_buffer_info,
&create_info,
&buffer->buffer,
&buffer->allocation,
&buffer->allocation_info)) {
LOGF(vulkan_error_messages[VULKAN_BUFFER_CREATION_FAILED]);
return VULKAN_ERROR_BUFFER_CREATION_FAILED;
}
return VULKAN_ERROR_NO_ERROR;
}
void destroy_buffer(struct rse_vulkan_buffer_t* buffer)
{
vmaDestroyBuffer(g_vulkan_state.allocator, buffer->buffer, buffer->allocation);
}
void update_uniform_buffers()
{
struct rse_uniform_buffer_object_t ubo = {};
@@ -492,14 +400,12 @@ uint8_t record_command_buffer(uint32_t image_index)
uint8_t create_buffers()
{
uint8_t status = VULKAN_ERROR_NO_ERROR;\
uint8_t status = VULKAN_ERROR_NO_ERROR;
STATUS_CHECK(create_command_pools());
STATUS_CHECK(create_vertex_buffer());
STATUS_CHECK(create_index_buffer());
STATUS_CHECK(create_instance_buffers());
STATUS_CHECK(create_uniform_buffer());
STATUS_CHECK(allocate_command_buffers());
return status;
}
@@ -509,6 +415,7 @@ void reset_command_buffer()
vkResetCommandBuffer(g_vulkan_state.command_buffers[g_vulkan_state.current_frame], /*VkCommandBufferResetFlagBits*/ 0);
}
void destroy_buffers()
{
size_t i = 0U;
@@ -526,6 +433,4 @@ void destroy_buffers()
for(i = 0; i < MAX_MESH_NUMBER; ++i) {
vmaDestroyBuffer(g_vulkan_state.allocator, g_instance_buffers[i].buffer, g_instance_buffers[i].allocation);
}
vkDestroyCommandPool(g_vulkan_state.device, g_command_pool, NULL);
}