Move to bindless design
Replaced DrawIndexed with DrawIndexedIndirect function. This way less parameters are passed from CPU and are store in GPU mapped memory. Multiple meshes with multiple instances also work.
This commit is contained in:
1 parent
3a58bd8756
commit
252a0820ed
6 files changed
+175
-102
No files matched your search
@@ -10,13 +10,14 @@
|
||||
#include <string.h>
|
||||
|
||||
#define MAX_VERTEX_BUFFER_SIZE 33554432 /* 32 MB*/
|
||||
|
||||
#define MAX_VULKAN_BUFFERS_COUNT 1
|
||||
#define MAX_INSTANCE_BUFFER_SIZE 8192 /* 8 MB*/
|
||||
|
||||
/* 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];
|
||||
size_t g_vertex_offset = 0;
|
||||
struct rse_vulkan_buffer_t g_vertex_buffer;
|
||||
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;
|
||||
|
||||
@@ -49,7 +50,6 @@ static uint8_t create_buffer(const VkDeviceSize size,
|
||||
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;
|
||||
@@ -175,12 +175,12 @@ static uint8_t create_vertex_buffer()
|
||||
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)) {
|
||||
&g_vertex_buffer)) {
|
||||
LOGF(vulkan_error_messages[VULKAN_BUFFER_CREATION_FAILED]);
|
||||
return VULKAN_ERROR_BUFFER_CREATION_FAILED;
|
||||
}
|
||||
|
||||
g_vertex_buffers->allocated_size = 0;
|
||||
g_vertex_buffer.allocated_size = 0;
|
||||
return VULKAN_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
@@ -200,32 +200,46 @@ static uint8_t 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)) {
|
||||
&g_index_buffer)) {
|
||||
LOGF(vulkan_error_messages[VULKAN_BUFFER_CREATION_FAILED]);
|
||||
return VULKAN_ERROR_BUFFER_CREATION_FAILED;
|
||||
}
|
||||
|
||||
g_index_buffers->allocated_size = 0;
|
||||
g_index_buffer.allocated_size = 0;
|
||||
return VULKAN_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
static uint8_t create_instance_buffer()
|
||||
static uint8_t create_instance_buffers()
|
||||
{
|
||||
size_t iter = 0U;
|
||||
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)) {
|
||||
for (iter = 0; iter < MAX_MESH_NUMBER; ++iter) {
|
||||
/* 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[iter])) {
|
||||
LOGF(vulkan_error_messages[VULKAN_BUFFER_CREATION_FAILED]);
|
||||
return VULKAN_ERROR_BUFFER_CREATION_FAILED;
|
||||
}
|
||||
|
||||
g_instance_buffers[iter].allocated_size = 0;
|
||||
|
||||
}
|
||||
|
||||
if (VK_SUCCESS != create_buffer(sizeof(VkDrawIndexedIndirectCommand) * MAX_MESH_NUMBER,
|
||||
VK_BUFFER_USAGE_TRANSFER_DST_BIT
|
||||
| VK_BUFFER_USAGE_STORAGE_BUFFER_BIT
|
||||
| VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT,
|
||||
VMA_MEMORY_USAGE_AUTO_PREFER_HOST,
|
||||
VMA_ALLOCATION_CREATE_MAPPED_BIT | VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT,
|
||||
&g_draw_indirect_command_buffer)) {
|
||||
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;
|
||||
|
||||
}
|
||||
@@ -301,17 +315,18 @@ void update_uniform_buffers()
|
||||
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)
|
||||
uint8_t rse_add_vertices(uint16_t mesh_id,
|
||||
const struct rse_vertex_t* vertices,
|
||||
const uint16_t* indices,
|
||||
struct rse_buffer_data_t* vertex_data,
|
||||
struct rse_buffer_data_t* index_data)
|
||||
{
|
||||
VkDrawIndexedIndirectCommand draw_indirect_command;
|
||||
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;
|
||||
size_t vertices_size = sizeof(vertices[0]) * vertex_data->count;
|
||||
size_t indices_size = sizeof(indices[0]) * index_data->count;
|
||||
|
||||
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];
|
||||
struct rse_vulkan_buffer_t* index_buffer = &g_index_buffer;
|
||||
|
||||
/* Creating staging buffer*/
|
||||
if (VK_SUCCESS != create_buffer(MAX_VERTEX_BUFFER_SIZE,
|
||||
@@ -328,28 +343,42 @@ uint8_t update_mesh_buffers(const struct rse_vertex_t* vertices,
|
||||
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,
|
||||
g_vertex_buffer.buffer,
|
||||
vertices_size,
|
||||
last_vertex_buffer->allocated_size);
|
||||
g_vertex_buffer.allocated_size);
|
||||
|
||||
vertex_data->buffer_offset = g_vertex_offset;
|
||||
g_vertex_offset += vertex_data->count;
|
||||
g_vertex_buffer.allocated_size += vertices_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,
|
||||
index_buffer->buffer,
|
||||
indices_size,
|
||||
last_index_buffer->allocated_size);
|
||||
index_buffer->allocated_size);
|
||||
index_data->buffer_offset = index_buffer->allocated_size;
|
||||
index_buffer->allocated_size += indices_size;
|
||||
|
||||
vmaDestroyBuffer(g_vulkan_state.allocator, staging_buffer.buffer, staging_buffer.allocation);
|
||||
|
||||
draw_indirect_command.indexCount = 6;
|
||||
draw_indirect_command.instanceCount = 0;
|
||||
draw_indirect_command.firstIndex = 0;
|
||||
draw_indirect_command.vertexOffset = vertex_data->buffer_offset;
|
||||
draw_indirect_command.firstInstance = 0;
|
||||
|
||||
memcpy(g_draw_indirect_command_buffer.allocation_info.pMappedData + (mesh_id * sizeof(VkDrawIndexedIndirectCommand)), &draw_indirect_command, sizeof(VkDrawIndexedIndirectCommand));
|
||||
|
||||
return VULKAN_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
uint8_t update_mesh_instances(struct rse_instance_data_t* instance_data)
|
||||
uint8_t update_mesh_instances(uint16_t mesh_id, struct rse_instance_data_t* instance_data)
|
||||
{
|
||||
VkDrawIndexedIndirectCommand draw_indirect_command;
|
||||
struct rse_vulkan_buffer_t staging_buffer;
|
||||
|
||||
struct rse_vulkan_buffer_t* last_instance_buffer = &g_instance_buffers[MAX_VULKAN_BUFFERS_COUNT - 1];
|
||||
struct rse_vulkan_buffer_t* instance_buffer = &g_instance_buffers[mesh_id];
|
||||
size_t instance_size = sizeof(struct rse_instance_data_t);
|
||||
|
||||
/* Creating staging buffer*/
|
||||
@@ -363,15 +392,20 @@ uint8_t update_mesh_instances(struct rse_instance_data_t* instance_data)
|
||||
return VULKAN_ERROR_BUFFER_CREATION_FAILED;
|
||||
}
|
||||
|
||||
/* Copy transformation information about instance */
|
||||
memcpy(staging_buffer.allocation_info.pMappedData, instance_data, instance_size);
|
||||
copy_buffer(staging_buffer.buffer,
|
||||
last_instance_buffer->buffer,
|
||||
instance_buffer->buffer,
|
||||
instance_size,
|
||||
last_instance_buffer->allocated_size);
|
||||
instance_buffer->allocated_size);
|
||||
|
||||
vmaDestroyBuffer(g_vulkan_state.allocator, staging_buffer.buffer, staging_buffer.allocation);
|
||||
|
||||
last_instance_buffer->allocated_size += instance_size;
|
||||
instance_buffer->allocated_size += instance_size;
|
||||
|
||||
memcpy(&draw_indirect_command, g_draw_indirect_command_buffer.allocation_info.pMappedData + (mesh_id * sizeof(VkDrawIndexedIndirectCommand)), sizeof(VkDrawIndexedIndirectCommand));
|
||||
draw_indirect_command.instanceCount++;
|
||||
memcpy(g_draw_indirect_command_buffer.allocation_info.pMappedData + (mesh_id * sizeof(VkDrawIndexedIndirectCommand)), &draw_indirect_command, sizeof(VkDrawIndexedIndirectCommand));
|
||||
|
||||
return VULKAN_ERROR_NO_ERROR;
|
||||
}
|
||||
@@ -429,19 +463,21 @@ uint8_t record_command_buffer(uint32_t image_index)
|
||||
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};
|
||||
vkCmdBindVertexBuffers(command_buffer, 0, 1, &g_vertex_buffer.buffer, offsets);
|
||||
vkCmdBindIndexBuffer(command_buffer, g_index_buffer.buffer, 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);
|
||||
|
||||
/* 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);
|
||||
for (i = 0; i < 2; ++i) {
|
||||
VkBuffer instance_buffer = {g_instance_buffers[i].buffer};
|
||||
|
||||
vkCmdDrawIndexed(command_buffer, (uint32_t)(get_indices_count(0)+3), get_instances_count(0), 0, 0, 0);
|
||||
vkCmdBindVertexBuffers(command_buffer, 1, 1, &instance_buffer, offsets);
|
||||
|
||||
vkCmdDrawIndexedIndirect(command_buffer,
|
||||
g_draw_indirect_command_buffer.buffer,
|
||||
sizeof(VkDrawIndexedIndirectCommand) * i,
|
||||
1,
|
||||
0); /* Can be 0 since we are not doing multiple draws each loop */
|
||||
}
|
||||
|
||||
vkCmdEndRenderPass(command_buffer);
|
||||
@@ -461,7 +497,7 @@ uint8_t create_buffers()
|
||||
STATUS_CHECK(create_command_pools());
|
||||
STATUS_CHECK(create_vertex_buffer());
|
||||
STATUS_CHECK(create_index_buffer());
|
||||
STATUS_CHECK(create_instance_buffer());
|
||||
STATUS_CHECK(create_instance_buffers());
|
||||
STATUS_CHECK(create_uniform_buffer());
|
||||
STATUS_CHECK(allocate_command_buffers());
|
||||
|
||||
@@ -483,10 +519,13 @@ void destroy_buffers()
|
||||
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_vertex_buffer.buffer, g_vertex_buffer.allocation);
|
||||
vmaDestroyBuffer(g_vulkan_state.allocator, g_index_buffer.buffer, g_index_buffer.allocation);
|
||||
vmaDestroyBuffer(g_vulkan_state.allocator, g_draw_indirect_command_buffer.buffer, g_draw_indirect_command_buffer.allocation);
|
||||
|
||||
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);
|
||||
}
|
||||
Reference in new issue
Block a user