Move back to C

I'm insane and as such I have moved to C AGAIN! Without any reason.
This commit is contained in:
Piotr Krygier committed 2023-08-14 13:48:29 +02:00
1 parent bf31b96a2e
commit 3d538eaa2c
43 files changed
+2645 -2649

No files matched your search

+525
View File
@@ -0,0 +1,525 @@
#include "vulkan_buffers.h"
#include "vulkan_errors.h"
#include "locale_vulkan.h"
#include "utilities/logger.h"
#include "mesh_controller.h"
#include "rse_math.h"
#include <stdint.h>
#include <string.h>
#define MAX_VERTEX_BUFFER_SIZE 33554432 /* 32 MB*/
#define MAX_VULKAN_BUFFERS_COUNT 1
// // FIXME: Temporary array of vertices, for testing purposes
// const std::vector<Vertex> vertices = {{{-0.5f, -0.5f, 0.0f}, {1.0f, 0.0f, 1.0f}},
// {{0.5f, -0.5f, 0.0f}, {0.0f, 1.0f, 1.0f}},
// {{0.5f, 0.5f, 0.0f}, {0.0f, 0.0f, 1.0f}},
// {{-0.5f, 0.5f, 0.0f}, {1.0f, 0.0f, 1.0f}}};
// // FIXME: Temporary array of vertices, for testing purposes
// std::vector<uint16_t> indices = {0, 1, 2, 2, 3, 0};
/* GPU visible buffer */
struct rse_vulkan_buffer_t g_vertex_buffers[MAX_VULKAN_BUFFERS_COUNT];
struct rse_vulkan_buffer_t g_index_buffers[MAX_VULKAN_BUFFERS_COUNT];
struct rse_vulkan_buffer_t g_instance_buffers[MAX_VULKAN_BUFFERS_COUNT];
VkCommandPool g_command_pool = VK_NULL_HANDLE;
static uint8_t create_buffer(const VkDeviceSize size,
VkBufferUsageFlags buffer_usage,
VmaMemoryUsage memory_usage,
const VmaAllocationCreateFlags allocation_flags,
struct rse_vulkan_buffer_t* buffer);
static uint8_t copy_buffer(VkBuffer src,
VkBuffer dst,
VkDeviceSize size,
VkDeviceSize dest_offset);
static uint8_t create_command_pools();
static uint8_t create_vertex_buffer();
static uint8_t create_index_buffer();
static uint8_t create_uniform_buffer();
static uint8_t allocate_command_buffers();
/**
* @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
*/
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;
/* Disalows random access to memory. TODO: Consider changing to VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT? */
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:
*/
uint8_t 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 = {};
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;
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.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;
// 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
*/
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;
}
/**
* @brief Create a buffer holding all vertex data
*
* @return uint8_t VULKAN_ERROR_NO_ERROR on success. Possible errors:
* VULKAN_ERROR_BUFFER_CREATION_FAILED
* VULKAN_ERROR_VERTEX_BUFFER_MAPPING_FAILED
*/
uint8_t create_vertex_buffer()
{
VkDeviceSize buffer_size;
buffer_size = MAX_VERTEX_BUFFER_SIZE;
/* Create Vertex Buffer*/
if (VK_SUCCESS != create_buffer(buffer_size,
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 */
g_vertex_buffers)) {
LOGF(vulkan_error_messages[VULKAN_BUFFER_CREATION_FAILED]);
return VULKAN_ERROR_BUFFER_CREATION_FAILED;
}
g_vertex_buffers->allocated_size = 0;
return VULKAN_ERROR_NO_ERROR;
}
/**
* @brief Create an index buffer, connected with vertex buffer
*
* @return uint8_t VULKAN_ERROR_NO_ERROR on success. Possible errors:
* VULKAN_ERROR_BUFFER_CREATION_FAILED
*/
uint8_t create_index_buffer()
{
VkDeviceSize buffer_size;
buffer_size = MAX_VERTEX_BUFFER_SIZE;
/* Create Index Buffer*/
if (VK_SUCCESS != create_buffer(buffer_size, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT,
VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE,
0, /* Will not be mapped with vmaMapMemory */
g_index_buffers)) {
LOGF(vulkan_error_messages[VULKAN_BUFFER_CREATION_FAILED]);
return VULKAN_ERROR_BUFFER_CREATION_FAILED;
}
g_index_buffers->allocated_size = 0;
return VULKAN_ERROR_NO_ERROR;
}
uint8_t createInstanceBuffer()
{
VkDeviceSize buffer_size;
buffer_size = MAX_VERTEX_BUFFER_SIZE;
/* Create Instance Buffer*/
if (VK_SUCCESS != create_buffer(buffer_size,
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 */
g_instance_buffers)) {
LOGF(vulkan_error_messages[VULKAN_BUFFER_CREATION_FAILED]);
return VULKAN_ERROR_BUFFER_CREATION_FAILED;
}
g_instance_buffers->allocated_size = 0;
return VULKAN_ERROR_NO_ERROR;
}
/**
* @brief Create a Uniform Buffers
*
* @return uint8_t VULKAN_ERROR_NO_ERROR on success. Possible errors:
*/
uint8_t create_uniform_buffer()
{
VkDeviceSize buffer_size = sizeof(struct rse_uniform_buffer_object_t);
for (size_t i = 0; i < SWAP_BUFFER_COUNT; i++) {
create_buffer(buffer_size, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VMA_MEMORY_USAGE_AUTO_PREFER_HOST,
VMA_ALLOCATION_CREATE_MAPPED_BIT | VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT,
&g_vulkan_state.uniform_buffers[i]);
}
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
*/
uint8_t allocate_command_buffers()
{
VkCommandBufferAllocateInfo allocate_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;
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;
}
return VULKAN_ERROR_NO_ERROR;
}
/**
* @brief Update uniform buffers
*
*/
void update_uniform_buffer()
{
struct rse_uniform_buffer_object_t ubo = {};
struct vec3_t eye = {0};
struct vec3_t center = {0};
struct vec3_t up = {0};
float fovy;
float z_near;
float z_far;
eye.z = 5.0f;
up.y = 1.0f;
fovy = rse_math_deg_to_radians(45.0f);
z_near = 0.1f;
z_far = 20.0f;
ubo.model = rse_math_uniform_mat4();
ubo.view = rse_math_look_at(&eye, &center, &up);
ubo.proj = rse_math_perspective(fovy,
g_vulkan_state.swapchain_extent.width / (float)g_vulkan_state.swapchain_extent.height,
z_near,
z_far);
memcpy(g_vulkan_state.uniform_buffers[g_vulkan_state.current_frame].allocation_info.pMappedData, &ubo, sizeof(ubo));
}
uint8_t update_mesh_buffers(const struct rse_vertex_t* vertices,
const uint16_t* indices,
size_t vertices_num,
size_t indices_num)
{
// void* mapped_data;
struct rse_vulkan_buffer_t staging_buffer;
size_t vertices_size = sizeof(vertices[0]) * vertices_num;
size_t indices_size = sizeof(indices[0]) * indices_num;
struct rse_vulkan_buffer_t* last_vertex_buffer = &g_vertex_buffers[MAX_VULKAN_BUFFERS_COUNT - 1];
struct rse_vulkan_buffer_t* last_index_buffer = &g_index_buffers[MAX_VULKAN_BUFFERS_COUNT - 1];
/* Creating staging buffer*/
if (VK_SUCCESS != create_buffer(MAX_VERTEX_BUFFER_SIZE,
VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
VMA_MEMORY_USAGE_AUTO_PREFER_HOST,
VMA_ALLOCATION_CREATE_MAPPED_BIT
| VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT,
&staging_buffer)) {
LOGF(vulkan_error_messages[VULKAN_BUFFER_CREATION_FAILED]);
return VULKAN_ERROR_BUFFER_CREATION_FAILED;
}
/* Fill staging buffer with vertex data */
memset(staging_buffer.allocation_info.pMappedData, 0, MAX_VERTEX_BUFFER_SIZE);
memcpy(staging_buffer.allocation_info.pMappedData, vertices, vertices_size);
copy_buffer(staging_buffer.buffer,
last_vertex_buffer->buffer,
vertices_size,
last_vertex_buffer->allocated_size);
/* Fill staging buffer with index data */
memset(staging_buffer.allocation_info.pMappedData, 0, MAX_VERTEX_BUFFER_SIZE);
memcpy(staging_buffer.allocation_info.pMappedData, indices, indices_size);
copy_buffer(staging_buffer.buffer,
last_index_buffer->buffer,
indices_size,
last_index_buffer->allocated_size);
vmaDestroyBuffer(g_vulkan_state.allocator, staging_buffer.buffer, staging_buffer.allocation);
return VULKAN_ERROR_NO_ERROR;
}
uint8_t update_mesh_instances(struct rse_instance_data_t* instance_data)
{
struct rse_vulkan_buffer_t staging_buffer;
struct rse_vulkan_buffer_t* last_instance_buffer = &g_instance_buffers[MAX_VULKAN_BUFFERS_COUNT - 1];
size_t instance_size = sizeof(struct rse_instance_data_t);
/* Creating staging buffer*/
if (VK_SUCCESS != create_buffer(MAX_VERTEX_BUFFER_SIZE,
VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
VMA_MEMORY_USAGE_AUTO_PREFER_HOST,
VMA_ALLOCATION_CREATE_MAPPED_BIT
| VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT,
&staging_buffer)) {
LOGF(vulkan_error_messages[VULKAN_BUFFER_CREATION_FAILED]);
return VULKAN_ERROR_BUFFER_CREATION_FAILED;
}
memcpy(staging_buffer.allocation_info.pMappedData, instance_data, instance_size);
copy_buffer(staging_buffer.buffer,
last_instance_buffer->buffer,
instance_size,
last_instance_buffer->allocated_size);
vmaDestroyBuffer(g_vulkan_state.allocator, staging_buffer.buffer, staging_buffer.allocation);
last_instance_buffer->allocated_size += instance_size;
return VULKAN_ERROR_NO_ERROR;
}
/**
* @brief Records commands for provided command buffer
*
* @param command_buffer Command buffer, that will hold commands
* @param image_index Image index
* @return uint8_t VULKAN_ERROR_NO_ERROR on success. Possible errors:
* VULKAN_ERROR_RECORD_COMMAND_BUFFER_FAILED
*/
uint8_t record_command_buffer(uint32_t image_index)
{
VkCommandBuffer command_buffer = g_vulkan_state.command_buffers[g_vulkan_state.current_frame];
VkCommandBufferBeginInfo begin_info = {};
VkClearValue clear_color = {{{0.0f, 0.0f, 0.0f, 1.0f}}};
VkRenderPassBeginInfo render_pass_info = {};
VkViewport viewport = {};
VkRect2D scissor = {};
VkDeviceSize offsets[] = {0};
size_t i = 0U;
begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
begin_info.flags = 0;
begin_info.pInheritanceInfo = NULL;
if (vkBeginCommandBuffer(command_buffer, &begin_info) != VK_SUCCESS) {
LOGF(vulkan_error_messages[VULKAN_RECORD_COMMAND_BEGIN_FAILED]);
return VULKAN_ERROR_RECORD_COMMAND_BEGIN_FAILED;
}
render_pass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
render_pass_info.renderPass = g_vulkan_state.render_pass;
render_pass_info.framebuffer = g_vulkan_state.swapchain_framebuffers[image_index];
render_pass_info.renderArea.offset.x = 0;
render_pass_info.renderArea.offset.y = 0;
render_pass_info.renderArea.extent = g_vulkan_state.swapchain_extent;
render_pass_info.clearValueCount = 1;
render_pass_info.pClearValues = &clear_color;
vkCmdBeginRenderPass(command_buffer, &render_pass_info, VK_SUBPASS_CONTENTS_INLINE);
vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, g_vulkan_state.graphics_pipeline);
viewport.x = 0.0f;
viewport.y = 0.0f;
viewport.width = (float)(g_vulkan_state.swapchain_extent.width);
viewport.height = (float)(g_vulkan_state.swapchain_extent.height);
viewport.minDepth = 0.0f;
viewport.maxDepth = 1.0f;
vkCmdSetViewport(command_buffer, 0, 1, &viewport);
scissor.offset.x = 0;
scissor.offset.y = 0;
scissor.extent = g_vulkan_state.swapchain_extent;
vkCmdSetScissor(command_buffer, 0, 1, &scissor);
for (i = 0; i < MAX_VULKAN_BUFFERS_COUNT; ++i) {
VkBuffer vertex_buffers[] = {g_vertex_buffers[i].buffer};
VkBuffer index_buffers = {g_index_buffers[i].buffer};
VkBuffer instance_buffers[] = {g_instance_buffers[i].buffer};
uint16_t* indices = get_mesh_indices(0); /* TODO: We need to take care of ALL meshes */
struct rse_instance_data_t* instances = get_instance_data_for_mesh(0);
/* TODO: Figure out the offset */
vkCmdBindVertexBuffers(command_buffer, 0, 1, vertex_buffers, offsets);
vkCmdBindVertexBuffers(command_buffer, 1, 1, instance_buffers, offsets);
vkCmdBindIndexBuffer(command_buffer, index_buffers, 0, VK_INDEX_TYPE_UINT16);
vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, g_vulkan_state.pipeline_layout, 0, 1,
&g_vulkan_state.descriptor_sets[g_vulkan_state.current_frame], 0, NULL);
vkCmdDrawIndexed(command_buffer, (uint32_t)(get_indices_count(0)+3), get_instances_count(0), 0, 0, 0);
}
vkCmdEndRenderPass(command_buffer);
if (VK_SUCCESS != vkEndCommandBuffer(command_buffer)) {
LOGF(vulkan_error_messages[VULKAN_RECORD_COMMAND_BUFFER_FAILED]);
return VULKAN_ERROR_RECORD_COMMAND_BUFFER_FAILED;
}
return VULKAN_ERROR_NO_ERROR;
}
uint8_t create_buffers()
{
uint8_t status = VULKAN_ERROR_NO_ERROR;\
STATUS_CHECK(create_command_pools());
STATUS_CHECK(create_vertex_buffer());
STATUS_CHECK(create_index_buffer());
STATUS_CHECK(createInstanceBuffer());
STATUS_CHECK(create_uniform_buffer());
STATUS_CHECK(allocate_command_buffers());
return status;
}
void reset_command_buffer()
{
vkResetCommandBuffer(g_vulkan_state.command_buffers[g_vulkan_state.current_frame], /*VkCommandBufferResetFlagBits*/ 0);
}
void destroy_buffers()
{
size_t i = 0U;
for (i = 0; i < SWAP_BUFFER_COUNT; ++i) {
vmaDestroyBuffer(g_vulkan_state.allocator,
g_vulkan_state.uniform_buffers[i].buffer,
g_vulkan_state.uniform_buffers[i].allocation);
}
for (i = 0; i < MAX_VULKAN_BUFFERS_COUNT; ++i) {
vmaDestroyBuffer(g_vulkan_state.allocator, g_vertex_buffers[i].buffer, g_vertex_buffers[i].allocation);
vmaDestroyBuffer(g_vulkan_state.allocator, g_index_buffers[i].buffer, g_index_buffers[i].allocation);
vmaDestroyBuffer(g_vulkan_state.allocator, g_instance_buffers[i].buffer, g_instance_buffers[i].allocation);
}
vkDestroyCommandPool(g_vulkan_state.device, g_command_pool, NULL);
}