diff --git a/gpu.c b/gpu.c index 3404aa1..2cc5359 100644 --- a/gpu.c +++ b/gpu.c @@ -91,6 +91,52 @@ static void create_buffer( vkBindBufferMemory(ctx->dev, *buf_out, *mem_out, 0); } +static void load_buffer( + const gpu_ctx_t *ctx, VkBuffer dest_buf, const void *data, size_t size, + VkBuffer staging_buf, VkDeviceMemory staging_buf_mem, + VkCommandPool cmd_pool) +{ + VkResult result; + + // Copy data to staging buffer + void *staging_buf_ptr; + vkMapMemory(ctx->dev, staging_buf_mem, 0, size, 0, &staging_buf_ptr); + memcpy(staging_buf_ptr, data, size); + vkUnmapMemory(ctx->dev, staging_buf_mem); + + // Allocate command buffer + const VkCommandBufferAllocateInfo cmd_buf_config = { + .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, + .commandPool = cmd_pool, + .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY, + .commandBufferCount = 1, + }; + VkCommandBuffer cmd_buf; + result = vkAllocateCommandBuffers(ctx->dev, &cmd_buf_config, &cmd_buf); + assert(result == VK_SUCCESS); + + // Record copy command + VkCommandBufferBeginInfo cmd_begin = { + .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, + .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, + }; + vkBeginCommandBuffer(cmd_buf, &cmd_begin); + VkBufferCopy cmd_copy = { .size = size }; + vkCmdCopyBuffer(cmd_buf, staging_buf, dest_buf, 1, &cmd_copy); + vkEndCommandBuffer(cmd_buf); + + // Send copy command + VkSubmitInfo copy_submit = { + .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, + .commandBufferCount = 1, + .pCommandBuffers = &cmd_buf, + }; + vkQueueSubmit(ctx->queue, 1, ©_submit, VK_NULL_HANDLE); + vkQueueWaitIdle(ctx->queue); + + vkFreeCommandBuffers(ctx->dev, cmd_pool, 1, &cmd_buf); +} + void gpu_init(gpu_ctx_t *ctx, const gpu_config_t *config) { // Initialise Vulkan instance. @@ -342,7 +388,7 @@ void gpu_init(gpu_ctx_t *ctx, const gpu_config_t *config) }; const VkPipelineInputAssemblyStateCreateInfo input_assembly_config = { .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, - .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, + .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, }; // Set up viewport configuration @@ -516,48 +562,49 @@ void gpu_init(gpu_ctx_t *ctx, const gpu_config_t *config) = vkCreateFence(ctx->dev, &fence_config, nullptr, &ctx->in_flight); assert(result == VK_SUCCESS); - // Set up staging and vertex buffers - ctx->vertex_data_size = config->vertex_data_size; + // Set up staging, vertex and index buffers + ctx->index_count = config->index_data_size / sizeof(*config->index_data); VkBuffer staging_buf; VkDeviceMemory staging_buf_mem; + const size_t staging_buf_size + = MAX(config->vertex_data_size, config->index_data_size); create_buffer( - ctx, ctx->vertex_data_size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, + ctx, staging_buf_size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, &staging_buf, &staging_buf_mem); create_buffer( - ctx, ctx->vertex_data_size, + ctx, config->vertex_data_size, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &ctx->vertex_buf, &ctx->vertex_buf_mem); + create_buffer( + ctx, config->index_data_size, + VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &ctx->index_buf, + &ctx->index_buf_mem); - // Copy vertex data into staging buffer - void *staging_buf_ptr; - vkMapMemory( - ctx->dev, staging_buf_mem, 0, ctx->vertex_data_size, 0, - &staging_buf_ptr); - memcpy(staging_buf_ptr, config->vertex_data, ctx->vertex_data_size); - vkUnmapMemory(ctx->dev, staging_buf_mem); - - // Copy staging buffer to vertex buffer - VkCommandBufferBeginInfo cmd_begin = { - .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, - .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, + // Create transient command pool + const VkCommandPoolCreateInfo transient_cmd_pool_config = { + .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, + .flags = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, + .queueFamilyIndex = queue_family, }; - vkBeginCommandBuffer(ctx->cmd_buf, &cmd_begin); - VkBufferCopy cmd_copy = { .size = ctx->vertex_data_size }; - vkCmdCopyBuffer( - ctx->cmd_buf, staging_buf, ctx->vertex_buf, 1, &cmd_copy); - vkEndCommandBuffer(ctx->cmd_buf); - VkSubmitInfo copy_submit = { - .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, - .commandBufferCount = 1, - .pCommandBuffers = &ctx->cmd_buf, - }; - vkQueueSubmit(ctx->queue, 1, ©_submit, VK_NULL_HANDLE); - vkQueueWaitIdle(ctx->queue); + VkCommandPool transient_cmd_pool; + result = vkCreateCommandPool( + ctx->dev, &transient_cmd_pool_config, nullptr, &transient_cmd_pool); + assert(result == VK_SUCCESS); - // Clean up staging buffer + // Load vertex and index data + load_buffer( + ctx, ctx->vertex_buf, config->vertex_data, config->vertex_data_size, + staging_buf, staging_buf_mem, transient_cmd_pool); + load_buffer( + ctx, ctx->index_buf, config->index_data, config->index_data_size, + staging_buf, staging_buf_mem, transient_cmd_pool); + + // Clean up staging buffer and transient command pool + vkDestroyCommandPool(ctx->dev, transient_cmd_pool, nullptr); vkDestroyBuffer(ctx->dev, staging_buf, nullptr); vkFreeMemory(ctx->dev, staging_buf_mem, nullptr); } @@ -566,22 +613,29 @@ void gpu_cleanup(const gpu_ctx_t *ctx) { vkDeviceWaitIdle(ctx->dev); + vkDestroyBuffer(ctx->dev, ctx->index_buf, nullptr); + vkFreeMemory(ctx->dev, ctx->index_buf_mem, nullptr); vkDestroyBuffer(ctx->dev, ctx->vertex_buf, nullptr); vkFreeMemory(ctx->dev, ctx->vertex_buf_mem, nullptr); + vkDestroySemaphore(ctx->dev, ctx->img_avail, nullptr); vkDestroySemaphore(ctx->dev, ctx->render_fin, nullptr); vkDestroyFence(ctx->dev, ctx->in_flight, nullptr); + vkDestroyCommandPool(ctx->dev, ctx->cmd_pool, nullptr); + vkDestroyPipeline(ctx->dev, ctx->pipeline, nullptr); vkDestroyRenderPass(ctx->dev, ctx->render_pass, nullptr); vkDestroyPipelineLayout(ctx->dev, ctx->pipeline_layout, nullptr); vkDestroyShaderModule(ctx->dev, ctx->vert_shader, nullptr); vkDestroyShaderModule(ctx->dev, ctx->frag_shader, nullptr); + for (unsigned i = 0; i < ctx->swapchain_img_count; ++i) { vkDestroyFramebuffer(ctx->dev, ctx->framebuffers[i], nullptr); vkDestroyImageView(ctx->dev, ctx->swapchain_img_views[i], nullptr); } vkDestroySwapchainKHR(ctx->dev, ctx->swapchain, nullptr); + vkDestroyDevice(ctx->dev, nullptr); vkDestroySurfaceKHR(ctx->inst, ctx->surface, nullptr); vkDestroyInstance(ctx->inst, nullptr); @@ -622,14 +676,15 @@ void gpu_render(const gpu_ctx_t *ctx) }; vkCmdBeginRenderPass( ctx->cmd_buf, &render_pass_begin, VK_SUBPASS_CONTENTS_INLINE); - - // Bind graphics pipeline and vertex buffer, then draw vkCmdBindPipeline( ctx->cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS, ctx->pipeline); + + // Bind vertex and index buffers then draw vkCmdBindVertexBuffers( ctx->cmd_buf, 0, 1, &ctx->vertex_buf, &(VkDeviceSize) { 0 }); - vkCmdDraw( - ctx->cmd_buf, ctx->vertex_data_size / sizeof(vertex_t), 1, 0, 0); + vkCmdBindIndexBuffer( + ctx->cmd_buf, ctx->index_buf, 0, VK_INDEX_TYPE_UINT16); + vkCmdDrawIndexed(ctx->cmd_buf, ctx->index_count, 1, 0, 0, 0); // Finish render pass and end writing to command buffer vkCmdEndRenderPass(ctx->cmd_buf); diff --git a/gpu.h b/gpu.h index f7d5fe0..819ebd7 100644 --- a/gpu.h +++ b/gpu.h @@ -31,9 +31,11 @@ typedef struct { VkFence in_flight; VkSemaphore render_fin; VkSemaphore img_avail; - size_t vertex_data_size; VkBuffer vertex_buf; VkDeviceMemory vertex_buf_mem; + VkBuffer index_buf; + VkDeviceMemory index_buf_mem; + size_t index_count; } gpu_ctx_t; typedef struct { @@ -41,6 +43,8 @@ typedef struct { GLFWwindow *window; const vertex_t *vertex_data; size_t vertex_data_size; + const uint16_t *index_data; + size_t index_data_size; } gpu_config_t; void gpu_init(gpu_ctx_t *ctx, const gpu_config_t *config); diff --git a/main.c b/main.c index c4f2dc8..b824e34 100644 --- a/main.c +++ b/main.c @@ -4,11 +4,14 @@ #include static const vertex_t vertices[] = { - { { 0.0, -0.5 }, { 1.0, 0.0, 0.0 } }, - { { 0.5, 0.5 }, { 0.0, 1.0, 0.0 } }, - { { -0.5, 0.5 }, { 0.0, 0.0, 1.0 } }, + { { -0.5, -0.5 }, { 1.0, 0.0, 0.0 } }, + { { 0.5, -0.5 }, { 0.0, 1.0, 0.0 } }, + { { 0.5, 0.5 }, { 0.0, 0.0, 1.0 } }, + { { -0.5, 0.5 }, { 1.0, 1.0, 1.0 } }, }; +static const uint16_t indices[] = { 0, 1, 2, 2, 3, 0 }; + static void key_callback(GLFWwindow *window, int key, int scancode, int action, int mods) { @@ -42,6 +45,8 @@ int main() .window = window, .vertex_data = vertices, .vertex_data_size = sizeof(vertices), + .index_data = indices, + .index_data_size = sizeof(indices), }; gpu_ctx_t gpu; gpu_init(&gpu, &gpu_config);