From f3aa7435ec442fd5faef1cfdd9a0bd698b72be8f Mon Sep 17 00:00:00 2001 From: Camden Dixie O'Brien Date: Fri, 3 Oct 2025 22:33:11 +0100 Subject: [PATCH] Restructure things a little to enable multiple models --- gpu.c | 324 ++++++++++++++++++++++++++++++--------------------------- gpu.h | 50 +++++---- main.c | 45 ++++++-- 3 files changed, 235 insertions(+), 184 deletions(-) diff --git a/gpu.c b/gpu.c index 013a3d2..573f621 100644 --- a/gpu.c +++ b/gpu.c @@ -9,6 +9,10 @@ #define SURFACE_FMT_BUFFER_SIZE 64 #define PRESENT_MODE_BUFFER_SIZE 8 +#define STAGING_BUFFER_SIZE 0x4'0000 // 256 KiB + +#define MAX_MODEL_COUNT 4 + #define NELEMS(arr) (sizeof(arr) / sizeof(arr[0])) #define MIN(a, b) ((a) < (b) ? (a) : (b)) @@ -98,22 +102,17 @@ static void create_buffer( } 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) + const gpu_ctx_t *ctx, VkBuffer dest_buf, const void *data, size_t size) { 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); + memcpy(ctx->staging_ptr, data, size); // Allocate command buffer const VkCommandBufferAllocateInfo cmd_buf_config = { .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, - .commandPool = cmd_pool, + .commandPool = ctx->transient_cmd_pool, .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY, .commandBufferCount = 1, }; @@ -128,7 +127,7 @@ static void load_buffer( }; vkBeginCommandBuffer(cmd_buf, &cmd_begin); VkBufferCopy cmd_copy = { .size = size }; - vkCmdCopyBuffer(cmd_buf, staging_buf, dest_buf, 1, &cmd_copy); + vkCmdCopyBuffer(cmd_buf, ctx->staging_buf, dest_buf, 1, &cmd_copy); vkEndCommandBuffer(cmd_buf); // Send copy command @@ -140,18 +139,15 @@ static void load_buffer( vkQueueSubmit(ctx->queue, 1, ©_submit, VK_NULL_HANDLE); vkQueueWaitIdle(ctx->queue); - vkFreeCommandBuffers(ctx->dev, cmd_pool, 1, &cmd_buf); + vkFreeCommandBuffers(ctx->dev, ctx->transient_cmd_pool, 1, &cmd_buf); } -void gpu_init(gpu_ctx_t *ctx, const gpu_config_t *config, model_t model) +void gpu_init(gpu_ctx_t *ctx, GLFWwindow *window, const char *name) { - ctx->index_count = model.index_count; - ctx->bone_count = model.bone_count; - // Initialise Vulkan instance. const VkApplicationInfo app_info = { .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, - .pApplicationName = config->application_name, + .pApplicationName = name, .applicationVersion = VK_MAKE_VERSION(1, 0, 0), .pEngineName = "No Engine", .engineVersion = VK_MAKE_VERSION(1, 0, 0), @@ -173,8 +169,8 @@ void gpu_init(gpu_ctx_t *ctx, const gpu_config_t *config, model_t model) assert(result == VK_SUCCESS); // Create surface - result = glfwCreateWindowSurface( - ctx->inst, config->window, nullptr, &ctx->surface); + result + = glfwCreateWindowSurface(ctx->inst, window, nullptr, &ctx->surface); assert(result == VK_SUCCESS); // Select a physical device @@ -273,7 +269,7 @@ void gpu_init(gpu_ctx_t *ctx, const gpu_config_t *config, model_t model) // Select swap chain extent if (surface_caps.currentExtent.width == UINT32_MAX) { int width, height; - glfwGetFramebufferSize(config->window, &width, &height); + glfwGetFramebufferSize(window, &width, &height); ctx->swapchain_extent.width = CLAMP( (uint32_t)width, surface_caps.minImageExtent.width, surface_caps.maxImageExtent.width); @@ -441,85 +437,15 @@ void gpu_init(gpu_ctx_t *ctx, const gpu_config_t *config, model_t model) .poolSizeCount = 1, .pPoolSizes = &(VkDescriptorPoolSize) { .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, - .descriptorCount = 2 * ctx->swapchain_img_count, + .descriptorCount + = MAX_MODEL_COUNT * 2 * ctx->swapchain_img_count, }, - .maxSets = 2 * ctx->swapchain_img_count, + .maxSets = MAX_MODEL_COUNT * 2 * ctx->swapchain_img_count, }; result = vkCreateDescriptorPool( ctx->dev, &desc_pool_config, nullptr, &ctx->desc_pool); assert(result == VK_SUCCESS); - // Create and configure descriptor sets - VkDescriptorSetLayout desc_set_layouts[ctx->swapchain_img_count]; - for (unsigned i = 0; i < ctx->swapchain_img_count; ++i) - desc_set_layouts[i] = ctx->desc_set_layout; - const VkDescriptorSetAllocateInfo desc_sets_alloc_config = { - .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, - .descriptorPool = ctx->desc_pool, - .descriptorSetCount = ctx->swapchain_img_count, - .pSetLayouts = desc_set_layouts, - }; - result = vkAllocateDescriptorSets( - ctx->dev, &desc_sets_alloc_config, ctx->desc_sets); - assert(result == VK_SUCCESS); - - // Create and map MVP buffer - const size_t mvp_buffer_size = ctx->swapchain_img_count * sizeof(mvp_t); - create_buffer( - ctx, mvp_buffer_size, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT - | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, - &ctx->mvp_buffer, &ctx->mvp_buffer_mem); - vkMapMemory( - ctx->dev, ctx->mvp_buffer_mem, 0, mvp_buffer_size, 0, - (void **)&ctx->mvps); - - // Create and map bone matrix buffer - const size_t bone_matrix_buffer_size - = ctx->swapchain_img_count * model.bone_count * sizeof(mat4_t); - create_buffer( - ctx, bone_matrix_buffer_size, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT - | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, - &ctx->bone_matrix_buffer, &ctx->bone_matrix_buffer_mem); - vkMapMemory( - ctx->dev, ctx->bone_matrix_buffer_mem, 0, bone_matrix_buffer_size, 0, - (void **)&ctx->bone_matrices); - - // Configure descriptor sets to use MVP and bone matrix buffers - for (unsigned i = 0; i < ctx->swapchain_img_count; ++i) { - const VkWriteDescriptorSet desc_writes[] = { - { - .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, - .dstSet = ctx->desc_sets[i], - .dstBinding = 0, - .dstArrayElement = 0, - .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, - .descriptorCount = 1, - .pBufferInfo = &(VkDescriptorBufferInfo) { - .buffer = ctx->mvp_buffer, - .offset = i * sizeof(mvp_t), - .range = sizeof(mvp_t), - }, - }, - { - .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, - .dstSet = ctx->desc_sets[i], - .dstBinding = 1, - .dstArrayElement = 0, - .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, - .descriptorCount = 1, - .pBufferInfo = &(VkDescriptorBufferInfo) { - .buffer = ctx->bone_matrix_buffer, - .offset = i * model.bone_count * sizeof(mat4_t), - .range = model.bone_count * sizeof(mat4_t), - }, - }, - }; - vkUpdateDescriptorSets( - ctx->dev, NELEMS(desc_writes), desc_writes, 0, nullptr); - } - // Set up input configuration const VkVertexInputBindingDescription input_binding_descs[] = { { @@ -776,27 +702,15 @@ void gpu_init(gpu_ctx_t *ctx, const gpu_config_t *config, model_t model) = vkCreateFence(ctx->dev, &fence_config, nullptr, &ctx->in_flight); assert(result == VK_SUCCESS); - // Set up staging, vertex and index buffers - const size_t vertex_data_size = model.vertex_count * sizeof(vertex_t); - const size_t index_data_size = model.index_count * sizeof(index_t); - VkBuffer staging_buf; - VkDeviceMemory staging_buf_mem; - const size_t staging_buf_size = MAX(vertex_data_size, index_data_size); + // Create and map staging buffer create_buffer( - ctx, staging_buf_size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, + ctx, STAGING_BUFFER_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, 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, 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); + &ctx->staging_buf, &ctx->staging_mem); + vkMapMemory( + ctx->dev, ctx->staging_mem, 0, STAGING_BUFFER_SIZE, 0, + &ctx->staging_ptr); // Create transient command pool const VkCommandPoolCreateInfo transient_cmd_pool_config = { @@ -804,33 +718,21 @@ void gpu_init(gpu_ctx_t *ctx, const gpu_config_t *config, model_t model) .flags = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, .queueFamilyIndex = queue_family, }; - VkCommandPool transient_cmd_pool; result = vkCreateCommandPool( - ctx->dev, &transient_cmd_pool_config, nullptr, &transient_cmd_pool); + ctx->dev, &transient_cmd_pool_config, nullptr, + &ctx->transient_cmd_pool); assert(result == VK_SUCCESS); - // Load vertex and index data - load_buffer( - ctx, ctx->vertex_buf, model.vertices, vertex_data_size, staging_buf, - staging_buf_mem, transient_cmd_pool); - load_buffer( - ctx, ctx->index_buf, model.indices, 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); + ctx->active_img_index = UINT32_MAX; } 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); + vkDestroyCommandPool(ctx->dev, ctx->transient_cmd_pool, nullptr); + vkDestroyBuffer(ctx->dev, ctx->staging_buf, nullptr); + vkFreeMemory(ctx->dev, ctx->staging_mem, nullptr); vkDestroySemaphore(ctx->dev, ctx->img_avail, nullptr); vkDestroySemaphore(ctx->dev, ctx->render_fin, nullptr); @@ -842,14 +744,6 @@ void gpu_cleanup(const gpu_ctx_t *ctx) vkDestroyRenderPass(ctx->dev, ctx->render_pass, nullptr); vkDestroyPipelineLayout(ctx->dev, ctx->pipeline_layout, nullptr); - vkUnmapMemory(ctx->dev, ctx->bone_matrix_buffer_mem); - vkDestroyBuffer(ctx->dev, ctx->bone_matrix_buffer, nullptr); - vkFreeMemory(ctx->dev, ctx->bone_matrix_buffer_mem, nullptr); - - vkUnmapMemory(ctx->dev, ctx->mvp_buffer_mem); - vkDestroyBuffer(ctx->dev, ctx->mvp_buffer, nullptr); - vkFreeMemory(ctx->dev, ctx->mvp_buffer_mem, nullptr); - vkDestroyDescriptorPool(ctx->dev, ctx->desc_pool, nullptr); vkDestroyDescriptorSetLayout(ctx->dev, ctx->desc_set_layout, nullptr); @@ -871,8 +765,121 @@ void gpu_cleanup(const gpu_ctx_t *ctx) vkDestroyInstance(ctx->inst, nullptr); } -void gpu_render( - const gpu_ctx_t *ctx, const mvp_t *mvp, const mat4_t *bone_matrices) +void gpu_model_load( + const gpu_ctx_t *ctx, const model_t *model, gpu_model_t *out) +{ + VkResult result; + + out->bone_count = model->bone_count; + out->index_count = model->index_count; + + // Create buffers + const size_t vertex_size = model->vertex_count * sizeof(vertex_t); + assert(vertex_size < STAGING_BUFFER_SIZE); + create_buffer( + ctx, vertex_size, + VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &out->vertex_buf, + &out->vertex_mem); + load_buffer(ctx, out->vertex_buf, model->vertices, vertex_size); + + // Load data into buffers + const size_t index_size = model->index_count * sizeof(index_t); + assert(index_size < STAGING_BUFFER_SIZE); + create_buffer( + ctx, index_size, + VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &out->index_buf, + &out->index_mem); + load_buffer(ctx, out->index_buf, model->indices, index_size); + + // Create and configure descriptor sets + VkDescriptorSetLayout desc_set_layouts[ctx->swapchain_img_count]; + for (unsigned i = 0; i < ctx->swapchain_img_count; ++i) + desc_set_layouts[i] = ctx->desc_set_layout; + const VkDescriptorSetAllocateInfo desc_sets_alloc_config = { + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, + .descriptorPool = ctx->desc_pool, + .descriptorSetCount = ctx->swapchain_img_count, + .pSetLayouts = desc_set_layouts, + }; + result = vkAllocateDescriptorSets( + ctx->dev, &desc_sets_alloc_config, out->desc_sets); + assert(result == VK_SUCCESS); + + // Create and map MVP buffer + const size_t mvp_size = ctx->swapchain_img_count * sizeof(mvp_t); + create_buffer( + ctx, mvp_size, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT + | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, + &out->mvp_buf, &out->mvp_mem); + vkMapMemory( + ctx->dev, out->mvp_mem, 0, mvp_size, 0, (void **)&out->mvp_ptr); + + // Create and map bone matrix buffer + const size_t bone_size + = ctx->swapchain_img_count * model->bone_count * sizeof(mat4_t); + create_buffer( + ctx, bone_size, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT + | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, + &out->bone_buf, &out->bone_mem); + vkMapMemory( + ctx->dev, out->bone_mem, 0, bone_size, 0, (void **)&out->bone_ptr); + + // Configure descriptor sets to use MVP and bone matrix buffers + for (unsigned i = 0; i < ctx->swapchain_img_count; ++i) { + const VkWriteDescriptorSet desc_writes[] = { + { + .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + .dstSet = out->desc_sets[i], + .dstBinding = 0, + .dstArrayElement = 0, + .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + .descriptorCount = 1, + .pBufferInfo = &(VkDescriptorBufferInfo) { + .buffer = out->mvp_buf, + .offset = i * sizeof(mvp_t), + .range = sizeof(mvp_t), + }, + }, + { + .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + .dstSet = out->desc_sets[i], + .dstBinding = 1, + .dstArrayElement = 0, + .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + .descriptorCount = 1, + .pBufferInfo = &(VkDescriptorBufferInfo) { + .buffer = out->bone_buf, + .offset = i * model->bone_count * sizeof(mat4_t), + .range = model->bone_count * sizeof(mat4_t), + }, + }, + }; + vkUpdateDescriptorSets( + ctx->dev, NELEMS(desc_writes), desc_writes, 0, nullptr); + } +} + +void gpu_model_cleanup(const gpu_ctx_t *ctx, const gpu_model_t *model) +{ + vkDeviceWaitIdle(ctx->dev); + + vkDestroyBuffer(ctx->dev, model->bone_buf, nullptr); + vkFreeMemory(ctx->dev, model->bone_mem, nullptr); + + vkDestroyBuffer(ctx->dev, model->mvp_buf, nullptr); + vkFreeMemory(ctx->dev, model->mvp_mem, nullptr); + + vkDestroyBuffer(ctx->dev, model->index_buf, nullptr); + vkFreeMemory(ctx->dev, model->index_mem, nullptr); + vkDestroyBuffer(ctx->dev, model->vertex_buf, nullptr); + vkFreeMemory(ctx->dev, model->vertex_mem, nullptr); +} + +void gpu_render_begin(gpu_ctx_t *ctx) { VkResult result; @@ -881,18 +888,11 @@ void gpu_render( vkResetFences(ctx->dev, 1, &ctx->in_flight); // Aquire image from swapchain - uint32_t img_index; result = vkAcquireNextImageKHR( ctx->dev, ctx->swapchain, UINT64_MAX, ctx->img_avail, VK_NULL_HANDLE, - &img_index); + &ctx->active_img_index); assert(result == VK_SUCCESS); - // Copy MVP and bone matricies into uniform buffer for this image - memcpy(ctx->mvps + img_index, mvp, sizeof(mvp_t)); - memcpy( - ctx->bone_matrices + (ctx->bone_count * img_index), bone_matrices, - ctx->bone_count * sizeof(mat4_t)); - // Reset command buffer, then begin writing vkResetCommandBuffer(ctx->cmd_buf, 0); const VkCommandBufferBeginInfo cmd_begin = { @@ -909,7 +909,7 @@ void gpu_render( VkRenderPassBeginInfo render_pass_begin = { .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, .renderPass = ctx->render_pass, - .framebuffer = ctx->framebuffers[img_index], + .framebuffer = ctx->framebuffers[ctx->active_img_index], .renderArea.extent = ctx->swapchain_extent, .clearValueCount = 2, .pClearValues = clear_values, @@ -918,20 +918,34 @@ void gpu_render( ctx->cmd_buf, &render_pass_begin, VK_SUBPASS_CONTENTS_INLINE); vkCmdBindPipeline( ctx->cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS, ctx->pipeline); +} + +void gpu_render_model( + const gpu_ctx_t *ctx, const gpu_model_t *model, const mvp_t *mvp, + const mat4_t *bone_matrices) +{ + assert(ctx->active_img_index < ctx->swapchain_img_count); + + memcpy(model->mvp_ptr + ctx->active_img_index, mvp, sizeof(mvp_t)); + memcpy( + model->bone_ptr + (model->bone_count * ctx->active_img_index), + bone_matrices, model->bone_count * sizeof(mat4_t)); - // Bind vertex and index buffers vkCmdBindVertexBuffers( - ctx->cmd_buf, 0, 1, &ctx->vertex_buf, &(VkDeviceSize) { 0 }); + ctx->cmd_buf, 0, 1, &model->vertex_buf, &(VkDeviceSize) { 0 }); vkCmdBindIndexBuffer( - ctx->cmd_buf, ctx->index_buf, 0, VK_INDEX_TYPE_UINT16); + ctx->cmd_buf, model->index_buf, 0, VK_INDEX_TYPE_UINT16); - // Bind descriptor set for this frame vkCmdBindDescriptorSets( ctx->cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS, ctx->pipeline_layout, - 0, 1, ctx->desc_sets + img_index, 0, nullptr); + 0, 1, model->desc_sets + ctx->active_img_index, 0, nullptr); - // Draw - vkCmdDrawIndexed(ctx->cmd_buf, ctx->index_count, 1, 0, 0, 0); + vkCmdDrawIndexed(ctx->cmd_buf, model->index_count, 1, 0, 0, 0); +} + +void gpu_render_submit(gpu_ctx_t *ctx) +{ + VkResult result; // Finish render pass and end writing to command buffer vkCmdEndRenderPass(ctx->cmd_buf); @@ -961,8 +975,10 @@ void gpu_render( .pWaitSemaphores = &ctx->render_fin, .swapchainCount = 1, .pSwapchains = &ctx->swapchain, - .pImageIndices = &img_index, + .pImageIndices = &ctx->active_img_index, }; result = vkQueuePresentKHR(ctx->queue, &present_info); assert(result == VK_SUCCESS); + + ctx->active_img_index = UINT32_MAX; } diff --git a/gpu.h b/gpu.h index 497824f..c181fbc 100644 --- a/gpu.h +++ b/gpu.h @@ -33,13 +33,6 @@ typedef struct { VkShaderModule frag_shader; VkDescriptorSetLayout desc_set_layout; VkDescriptorPool desc_pool; - VkDescriptorSet desc_sets[MAX_FRAMES_IN_FLIGHT]; - VkBuffer mvp_buffer; - VkDeviceMemory mvp_buffer_mem; - mvp_t *mvps; - VkBuffer bone_matrix_buffer; - VkDeviceMemory bone_matrix_buffer_mem; - mat4_t *bone_matrices; VkPipelineLayout pipeline_layout; VkRenderPass render_pass; VkPipeline pipeline; @@ -48,22 +41,41 @@ typedef struct { VkFence in_flight; VkSemaphore render_fin; VkSemaphore img_avail; - VkBuffer vertex_buf; - VkDeviceMemory vertex_buf_mem; - VkBuffer index_buf; - VkDeviceMemory index_buf_mem; - size_t index_count; - size_t bone_count; + VkBuffer staging_buf; + VkDeviceMemory staging_mem; + void *staging_ptr; + VkCommandPool transient_cmd_pool; + uint32_t active_img_index; } gpu_ctx_t; typedef struct { - const char *application_name; - GLFWwindow *window; -} gpu_config_t; + mvp_t *mvp_ptr; + mat4_t *bone_ptr; + VkBuffer vertex_buf; + VkDeviceMemory vertex_mem; + VkBuffer index_buf; + VkDeviceMemory index_mem; + VkDescriptorSet desc_sets[MAX_FRAMES_IN_FLIGHT]; + VkBuffer mvp_buf; + VkDeviceMemory mvp_mem; + VkBuffer bone_buf; + VkDeviceMemory bone_mem; + size_t index_count; + size_t bone_count; +} gpu_model_t; -void gpu_init(gpu_ctx_t *ctx, const gpu_config_t *config, model_t model); +void gpu_init(gpu_ctx_t *ctx, GLFWwindow *window, const char *name); void gpu_cleanup(const gpu_ctx_t *ctx); -void gpu_render( - const gpu_ctx_t *ctx, const mvp_t *mvp, const mat4_t *bone_matrices); + +void gpu_model_load( + const gpu_ctx_t *ctx, const model_t *model, gpu_model_t *out); +void gpu_model_cleanup(const gpu_ctx_t *ctx, const gpu_model_t *model); + +void gpu_render_begin(gpu_ctx_t *ctx); +void gpu_render_model( + const gpu_ctx_t *ctx, const gpu_model_t *model, const mvp_t *mvp, + + const mat4_t *bone_matrices); +void gpu_render_submit(gpu_ctx_t *ctx); #endif diff --git a/main.c b/main.c index 5168357..868261b 100644 --- a/main.c +++ b/main.c @@ -12,6 +12,8 @@ #define DT (1'000'000 / 60) // Assume 60 Hz for now +#define LIL_GUY_COUNT 2 + static void key_callback(GLFWwindow *window, int key, int scancode, int action, int mods) { @@ -48,22 +50,21 @@ int main(int argc, char *argv[]) // Register input callbacks glfwSetKeyCallback(window, key_callback); - // Initialise GPU - const gpu_config_t gpu_config = { - .application_name = "Foo", - .window = window, - }; + // Initialise GPU and load model gpu_ctx_t gpu; - gpu_init(&gpu, &gpu_config, model); + gpu_model_t gpu_model1, gpu_model2; + gpu_init(&gpu, window, "Foo"); + gpu_model_load(&gpu, &model, &gpu_model1); + gpu_model_load(&gpu, &model, &gpu_model2); // Initialise animation animation_state_t anim = animation_init(&model); const vec3_t cam = { 0, 4, -4 }; const vec3_t tgt = { 0, 0.5, 0 }; - mvp_t mvp = { + mvp_t mvp1 = { .model = mat4_mul( - MAT4_TRANSLATE(1, 0, 0), + MAT4_TRANSLATE(1, 0, 0), (mat4_t) { { 0, 0, -1, 0 }, { -1, 0, 0, 0 }, @@ -73,20 +74,42 @@ int main(int argc, char *argv[]) .view = mat4_lookat(cam, tgt, (vec3_t) { 0, 1, 0 }), .proj = mat4_perspective((float)W / H, PI / 8, 0.1, 10.0), }; + mvp_t mvp2 = { + .model = mat4_mul( + MAT4_TRANSLATE(2, 0, 0), + mat4_mul( + MAT4_ROTATE_Y(PI), + (mat4_t) { + { 0, 0, -1, 0 }, + { -1, 0, 0, 0 }, + { 0, 1, 0, 0 }, + { 0, 0, 0, 1 }, + })), + .view = mat4_lookat(cam, tgt, (vec3_t) { 0, 1, 0 }), + .proj = mat4_perspective((float)W / H, PI / 8, 0.1, 10.0), + }; - const mat4_t rot = MAT4_ROTATE_Y(PI / 170); + const mat4_t rot1 = MAT4_ROTATE_Y(PI / 170); + const mat4_t rot2 = MAT4_ROTATE_Y(-PI / 340); animation_start(&anim, &model, 0); while (!glfwWindowShouldClose(window)) { glfwPollEvents(); - mvp.model = mat4_mul(rot, mvp.model); + mvp1.model = mat4_mul(rot1, mvp1.model); + mvp2.model = mat4_mul(rot2, mvp2.model); animation_update(&anim, &model, DT); - gpu_render(&gpu, &mvp, anim.bone_matrices); + + gpu_render_begin(&gpu); + gpu_render_model(&gpu, &gpu_model1, &mvp1, anim.bone_matrices); + gpu_render_model(&gpu, &gpu_model2, &mvp2, anim.bone_matrices); + gpu_render_submit(&gpu); } // Clean up animation_cleanup(&anim); + gpu_model_cleanup(&gpu, &gpu_model1); + gpu_model_cleanup(&gpu, &gpu_model2); gpu_cleanup(&gpu); model_cleanup(&model); glfwDestroyWindow(window);