diff --git a/gpu.c b/gpu.c index f468ed3..9a2bac1 100644 --- a/gpu.c +++ b/gpu.c @@ -409,6 +409,78 @@ void gpu_init(gpu_ctx_t *ctx, const gpu_config_t *config, model_t model) }, }; + // Create descriptor set layout + const VkDescriptorSetLayoutCreateInfo desc_set_layout_config = { + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, + .bindingCount = 1, + .pBindings = &(VkDescriptorSetLayoutBinding) { + .binding = 0, + .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + .descriptorCount = 1, + .stageFlags = VK_SHADER_STAGE_VERTEX_BIT, + }, + }; + result = vkCreateDescriptorSetLayout( + ctx->dev, &desc_set_layout_config, nullptr, &ctx->desc_set_layout); + assert(result == VK_SUCCESS); + + // Create descriptor pool + const VkDescriptorPoolCreateInfo desc_pool_config = { + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, + .poolSizeCount = 1, + .pPoolSizes = &(VkDescriptorPoolSize) { + .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + .descriptorCount = swapchain_img_count, + }, + .maxSets = 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[swapchain_img_count]; + for (unsigned i = 0; i < 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 = 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 = 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); + + // Configure descriptor sets to use MVP buffer + for (unsigned i = 0; i < swapchain_img_count; ++i) { + const VkWriteDescriptorSet desc_write = { + .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), + }, + }; + vkUpdateDescriptorSets(ctx->dev, 1, &desc_write, 0, nullptr); + } + // Set up input configuration const VkVertexInputBindingDescription input_binding_descs[] = { { @@ -490,15 +562,10 @@ void gpu_init(gpu_ctx_t *ctx, const gpu_config_t *config, model_t model) }; // Create pipeline layout - const VkPushConstantRange mvp_range = { - .stageFlags = VK_SHADER_STAGE_VERTEX_BIT, - .offset = 0, - .size = sizeof(mvp_t), - }; const VkPipelineLayoutCreateInfo pipeline_layout_config = { .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, - .pushConstantRangeCount = 1, - .pPushConstantRanges = &mvp_range, + .setLayoutCount = 1, + .pSetLayouts = &ctx->desc_set_layout, }; result = vkCreatePipelineLayout( ctx->dev, &pipeline_layout_config, nullptr, &ctx->pipeline_layout); @@ -723,6 +790,14 @@ void gpu_cleanup(const gpu_ctx_t *ctx) vkDestroyPipeline(ctx->dev, ctx->pipeline, nullptr); vkDestroyRenderPass(ctx->dev, ctx->render_pass, nullptr); vkDestroyPipelineLayout(ctx->dev, ctx->pipeline_layout, 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); + vkDestroyShaderModule(ctx->dev, ctx->vert_shader, nullptr); vkDestroyShaderModule(ctx->dev, ctx->frag_shader, nullptr); @@ -756,6 +831,9 @@ void gpu_render(const gpu_ctx_t *ctx, const mvp_t *mvp) &img_index); assert(result == VK_SUCCESS); + // Copy MVP matricies into uniform buffer for this image + memcpy(ctx->mvps + img_index, mvp, sizeof(mvp_t)); + // Reset command buffer, then begin writing vkResetCommandBuffer(ctx->cmd_buf, 0); const VkCommandBufferBeginInfo cmd_begin = { @@ -782,16 +860,18 @@ void gpu_render(const gpu_ctx_t *ctx, const mvp_t *mvp) vkCmdBindPipeline( ctx->cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS, ctx->pipeline); - // Push MVP - vkCmdPushConstants( - ctx->cmd_buf, ctx->pipeline_layout, VK_SHADER_STAGE_VERTEX_BIT, 0, - sizeof(mvp_t), mvp); - - // Bind vertex and index buffers then draw + // Bind vertex and index buffers vkCmdBindVertexBuffers( ctx->cmd_buf, 0, 1, &ctx->vertex_buf, &(VkDeviceSize) { 0 }); vkCmdBindIndexBuffer( ctx->cmd_buf, ctx->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); + + // Draw vkCmdDrawIndexed(ctx->cmd_buf, ctx->index_count, 1, 0, 0, 0); // Finish render pass and end writing to command buffer diff --git a/gpu.h b/gpu.h index 916f9de..ec37bda 100644 --- a/gpu.h +++ b/gpu.h @@ -31,6 +31,12 @@ typedef struct { VkFramebuffer framebuffers[SWAPCHAIN_IMG_BUFFER_SIZE]; VkShaderModule vert_shader; VkShaderModule frag_shader; + VkDescriptorSetLayout desc_set_layout; + VkDescriptorPool desc_pool; + VkDescriptorSet desc_sets[SWAPCHAIN_IMG_BUFFER_SIZE]; + VkBuffer mvp_buffer; + VkDeviceMemory mvp_buffer_mem; + mvp_t *mvps; VkPipelineLayout pipeline_layout; VkRenderPass render_pass; VkPipeline pipeline; diff --git a/vert.glsl b/vert.glsl index ae7dbd7..60496e3 100644 --- a/vert.glsl +++ b/vert.glsl @@ -5,7 +5,7 @@ layout(location = 1) in vec3 normal; layout(location = 0) out vec3 frag_normal; -layout(push_constant) uniform MVP { +layout(binding = 0) uniform mvp_t { mat4 model; mat4 view; mat4 proj;