diff --git a/src/main.c b/src/main.c index 6f84693..178bce5 100644 --- a/src/main.c +++ b/src/main.c @@ -207,8 +207,11 @@ void map_destroy(Map map) { free(map.bucket_usage); } +#define ATTRIBUTE_ID_MESH 0x00000001 +#define ATTRIBUTE_ID_MATERIAL 0x00000002 + typedef struct ObjectStruct { - Map attributes; + Map attributes; } Object; // Defines how a mesh is read from a buffer into a graphics pipeline @@ -237,29 +240,16 @@ typedef struct MeshStruct { AllocatedBuffer index_buffer; } Mesh; -typedef struct DescriptorPoolStruct { - VkDescriptorPool handle; - uint32_t allocated; -} DescriptorPool; - -typedef struct GrowingDescriptorPoolStruct { - uint32_t num_pool_sizes; - VkDescriptorPoolSize* pool_sizes; - - uint32_t sets_per_pool; - VkDescriptorPoolCreateInfo pool_info; - VkDescriptorSetLayout set_layout; - - uint32_t num_pools; - DescriptorPool* pools; -} GrowingDescriptorPool; - typedef struct MaterialStruct { VkDescriptorSetLayout material_set_layout; VkDescriptorSetLayout mesh_set_layout; VkPipelineLayout layout; VkPipeline pipeline; + + VkDescriptorPool material_descriptor_pool; + VkDescriptorSet* material_descriptors; + uint32_t material_descriptors_count; } Material; typedef struct VulkanContextStruct { @@ -302,8 +292,8 @@ typedef struct VulkanContextStruct { VkCommandPool graphics_command_pool; VkCommandPool transfer_command_pool; - VkDescriptorPool scene_ubo_pool; - VkDescriptorSetLayout scene_ubo_layout; + VkDescriptorPool scene_pool; + VkDescriptorSetLayout scene_descriptor_layout; VkDescriptorSet* scene_descriptors; AllocatedBuffer* scene_ubos; void** scene_ubo_ptrs; @@ -312,6 +302,8 @@ typedef struct VulkanContextStruct { Mesh triangle_mesh_textured; Material simple_mesh_material; Material texture_mesh_material; + Object triangle_object; + Object triangle_object_textured; uint32_t current_frame; } VulkanContext; @@ -447,122 +439,6 @@ static VKAPI_ATTR VkBool32 VKAPI_CALL debug_callback( return VK_FALSE; } -GrowingDescriptorPool create_growing_descriptor_pool(VkDevice device, uint32_t num_bindings, VkDescriptorSetLayoutBinding* bindings, uint32_t sets_per_pool) { - GrowingDescriptorPool ret = { - .sets_per_pool = sets_per_pool, - }; - - VkDescriptorSetLayoutCreateInfo layout_info = { - .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, - .bindingCount = num_bindings, - .pBindings = bindings, - }; - - VkDescriptorSetLayout layout; - VkResult result = vkCreateDescriptorSetLayout(device, &layout_info, 0, &layout); - if(result != VK_SUCCESS) { - return ret; - } - - VkDescriptorPoolSize* pool_sizes = malloc(sizeof(VkDescriptorPoolSize)*num_bindings); - if(pool_sizes == 0) { - return ret; - } - - for(uint32_t i = 0; i < num_bindings; i++) { - VkDescriptorPoolSize size = { - .type = bindings[i].descriptorType, - .descriptorCount = bindings[i].descriptorCount * sets_per_pool, - }; - pool_sizes[i] = size; - } - - VkDescriptorPoolCreateInfo pool_info = { - .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, - .poolSizeCount = num_bindings, - .pPoolSizes = pool_sizes, - .maxSets = sets_per_pool, - }; - - DescriptorPool* pools = malloc(sizeof(DescriptorPool)); - if(pools == 0) { - free(pool_sizes); - return ret; - } - - result = vkCreateDescriptorPool(device, &pool_info, 0, &pools[0].handle); - if(result != VK_SUCCESS) { - free(pool_sizes); - free(pools); - } - - ret.set_layout = layout; - ret.pool_info = pool_info; - ret.pools = pools; - ret.num_pools = 1; - ret.pool_info = pool_info; - ret.pool_sizes = pool_sizes; - - return ret; -} - -DescriptorPool* grow_descriptor_pool(VkDevice device, GrowingDescriptorPool* pool) { - VkDescriptorPool handle; - VkResult result = vkCreateDescriptorPool(device, &pool->pool_info, 0, &handle); - if(result != VK_SUCCESS) { - return 0; - } - - uint32_t new_size = pool->num_pools + 1; - DescriptorPool* new_pools = realloc(pool->pools, sizeof(DescriptorPool)*new_size); - if(new_pools == 0) { - return 0; - } - - new_pools[new_size-1].allocated = 0; - new_pools[new_size-1].handle = handle; - pool->pools = new_pools; - pool->num_pools = new_size; - - return &new_pools[new_size-1]; -} - -VkDescriptorSet allocate_descriptor_set(VkDevice device, GrowingDescriptorPool* pool) { - DescriptorPool* selected_pool = 0; - uint32_t index = 0; - for(uint32_t i = 0; i < pool->num_pools; i++) { - if(pool->pools[i].allocated < pool->sets_per_pool) { - selected_pool = &pool->pools[i]; - index = i; - break; - } - } - - if(selected_pool == 0) { - selected_pool = grow_descriptor_pool(device, pool); - index = pool->num_pools - 1; - if(selected_pool == 0) { - return VK_NULL_HANDLE; - } - } - - VkDescriptorSetAllocateInfo alloc_info = { - .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, - .descriptorPool = selected_pool->handle, - .pSetLayouts = &pool->set_layout, - .descriptorSetCount = 1, - }; - - VkDescriptorSet new_set; - VkResult result = vkAllocateDescriptorSets(device, &alloc_info, &new_set); - if(result != VK_SUCCESS) { - return VK_NULL_HANDLE; - } - - pool->pools[index].allocated += 1; - return new_set; -} - VkDescriptorSet* create_descriptor_sets(VkDevice device, VkDescriptorSetLayout layout, VkDescriptorPool pool, uint32_t count) { VkDescriptorSetLayout* layouts = malloc(sizeof(VkDescriptorSetLayout)*count); if(layouts == 0) { @@ -1819,25 +1695,35 @@ VkResult recreate_swap_chain(VulkanContext* context, VkExtent2D new_extent) { return VK_SUCCESS; } -void record_command_buffer_mesh(Mesh mesh, VkCommandBuffer command_buffer) { - VkBuffer vertex_buffers[] = {mesh.vertex_buffer.buffer}; +void command_draw_mesh(Object object, VkCommandBuffer command_buffer) { + MaybeValue maybe_mesh = map_lookup(object.attributes, ATTRIBUTE_ID_MESH); + if(maybe_mesh.has_value == false) { + return; + } + + Mesh* mesh = maybe_mesh.value; + + VkBuffer vertex_buffers[] = {mesh->vertex_buffer.buffer}; VkDeviceSize offsets[] = {0}; vkCmdBindVertexBuffers(command_buffer, 0, 1, vertex_buffers, offsets); - vkCmdBindIndexBuffer(command_buffer, mesh.index_buffer.buffer, 0, VK_INDEX_TYPE_UINT16); + vkCmdBindIndexBuffer(command_buffer, mesh->index_buffer.buffer, 0, VK_INDEX_TYPE_UINT16); - vkCmdDrawIndexed(command_buffer, mesh.index_count, 1, 0, 0, 0); + vkCmdDrawIndexed(command_buffer, mesh->index_count, 1, 0, 0, 0); } -void record_command_buffer_material(Material material, uint32_t mesh_count, Mesh* meshes, VkDescriptorSet scene_descriptor, VkCommandBuffer command_buffer) { +void command_draw_material(Material material, uint32_t mesh_count, Object* objects, uint32_t frame_num, VkDescriptorSet* scene_descriptors, VkCommandBuffer command_buffer) { vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, material.pipeline); - vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, material.layout, 0, 1, &scene_descriptor, 0, 0); + vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, material.layout, 0, 1, &scene_descriptors[frame_num], 0, 0); + if(material.material_descriptors != 0) { + vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, material.layout, 1, 1, &material.material_descriptors[frame_num], 0, 0); + } for(uint32_t i = 0; i < mesh_count; i++) { - record_command_buffer_mesh(meshes[i], command_buffer); + command_draw_mesh(objects[i], command_buffer); } } -VkResult record_command_buffer_scene(uint32_t materials_count, Material* materials, uint32_t* mesh_counts, Mesh** meshes, VkDescriptorSet scene_descriptor, VkCommandBuffer command_buffer, VkRenderPass render_pass, VkFramebuffer framebuffer, VkExtent2D extent) { +VkResult command_draw_scene(uint32_t materials_count, Material* materials, uint32_t* mesh_counts, Object** objects, uint32_t frame_num, VkDescriptorSet* scene_descriptors, VkCommandBuffer command_buffer, VkRenderPass render_pass, VkFramebuffer framebuffer, VkExtent2D extent) { VkCommandBufferBeginInfo begin_info = {}; begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; begin_info.flags = 0; @@ -1886,7 +1772,7 @@ VkResult record_command_buffer_scene(uint32_t materials_count, Material* materia vkCmdSetScissor(command_buffer, 0, 1, &scissor); for(uint i = 0; i < materials_count; i++) { - record_command_buffer_material(materials[i], mesh_counts[i], meshes[i], scene_descriptor, command_buffer); + command_draw_material(materials[i], mesh_counts[i], objects[i], frame_num, scene_descriptors, command_buffer); } vkCmdEndRenderPass(command_buffer); @@ -1983,6 +1869,58 @@ Mesh load_texture_mesh(VkPhysicalDevice physical_device, VkDevice device, struct return mesh; } +Object create_object() { + Object ret = { + .attributes = { + .buckets = 0, + }, + }; + + Map attributes = map_create(8, 2); + if(attributes.buckets == 0) { + return ret; + } + + ret.attributes = attributes; + + return ret; +} + +Object create_renderable(Mesh* mesh, Material* material) { + Object zero = { + .attributes = { + .buckets = 0, + }, + }; + + if(mesh == 0 || material == 0) { + return zero; + } + + Map attributes = map_create(8, 2); + if(attributes.buckets == 0) { + return zero; + } + + bool result = map_add(&attributes, ATTRIBUTE_ID_MESH, mesh); + if(result == false) { + map_destroy(attributes); + return zero; + } + + result = map_add(&attributes, ATTRIBUTE_ID_MATERIAL, material); + if(result == false) { + map_destroy(attributes); + return zero; + } + + Object ret = { + .attributes = attributes, + }; + + return ret; +} + Mesh load_simple_mesh(VkPhysicalDevice physical_device, VkDevice device, struct Vertex* vertices, uint32_t vertex_count, uint16_t* indices, uint32_t index_count, VkCommandPool transfer_pool, VkQueue transfer_queue) { Mesh mesh = {}; mesh.vertex_buffer.buffer = VK_NULL_HANDLE; @@ -2012,8 +1950,6 @@ Mesh load_simple_mesh(VkPhysicalDevice physical_device, VkDevice device, struct return mesh; } -uint32_t HARDCODED_SETS_PER_POOL = 10; - Material create_material( VkDevice device, VkExtent2D extent, @@ -2022,7 +1958,8 @@ Material create_material( VkPipelineShaderStageCreateInfo* shader_stages, VkDescriptorSetLayout scene_ubo_layout, PipelineLayout pipeline_layout, - MeshType mesh_type + MeshType mesh_type, + uint32_t max_frames_in_flight ) { Material zero_material = { .pipeline = VK_NULL_HANDLE, @@ -2033,6 +1970,9 @@ Material create_material( VkDescriptorSetLayout all_layouts[3] = {scene_ubo_layout, VK_NULL_HANDLE, VK_NULL_HANDLE}; uint32_t num_layouts = 1; + VkDescriptorPool material_descriptor_pool = VK_NULL_HANDLE; + VkDescriptorSet* material_descriptors = 0; + if(pipeline_layout.material_bindings_count > 0) { VkDescriptorSetLayoutCreateInfo layout_info = { .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, @@ -2045,6 +1985,61 @@ Material create_material( return zero_material; } + material_descriptors = malloc(sizeof(VkDescriptorSet)*max_frames_in_flight); + if(material_descriptors == 0) { + return zero_material; + } + + VkDescriptorPoolSize* pool_sizes = malloc(sizeof(VkDescriptorPool)*pipeline_layout.material_bindings_count); + if(pool_sizes == 0) { + return zero_material; + } + + for(uint32_t i = 0; i < pipeline_layout.material_bindings_count; i++) { + VkDescriptorPoolSize pool_size = { + .type = pipeline_layout.material_bindings[i].descriptorType, + .descriptorCount = pipeline_layout.material_bindings[i].descriptorCount, + }; + pool_sizes[i] = pool_size; + } + + VkDescriptorPoolCreateInfo pool_info = { + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, + .poolSizeCount = pipeline_layout.material_bindings_count, + .maxSets = max_frames_in_flight, + .pPoolSizes = pool_sizes, + }; + + result = vkCreateDescriptorPool(device, &pool_info, 0, &material_descriptor_pool); + free(pool_sizes); + if(result != VK_SUCCESS) { + return zero_material; + } + + VkDescriptorSetLayout* set_layouts = malloc(sizeof(VkDescriptorSetLayout)*max_frames_in_flight); + if(set_layouts == 0) { + vkDestroyDescriptorPool(device, material_descriptor_pool, 0); + return zero_material; + } + + for(uint32_t i = 0; i < max_frames_in_flight; i++) { + set_layouts[i] = material_set_layout; + } + + VkDescriptorSetAllocateInfo alloc_info = { + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, + .descriptorSetCount = max_frames_in_flight, + .descriptorPool = material_descriptor_pool, + .pSetLayouts = set_layouts, + }; + + result = vkAllocateDescriptorSets(device, &alloc_info, material_descriptors); + free(set_layouts); + if(result != VK_SUCCESS) { + vkDestroyDescriptorPool(device, material_descriptor_pool, 0); + return zero_material; + } + all_layouts[num_layouts] = material_set_layout; num_layouts += 1; } @@ -2090,12 +2085,16 @@ Material create_material( .material_set_layout = material_set_layout, .mesh_set_layout = mesh_set_layout, + + .material_descriptors = material_descriptors, + .material_descriptor_pool = material_descriptor_pool, + .material_descriptors_count = max_frames_in_flight, }; return material; } -Material create_simple_mesh_material(VkDevice device, VkExtent2D extent, VkRenderPass render_pass, VkDescriptorSetLayout scene_ubo_layout) { +Material create_simple_mesh_material(VkDevice device, VkExtent2D extent, VkRenderPass render_pass, VkDescriptorSetLayout scene_ubo_layout, uint32_t max_frames_in_flight) { VkShaderModule vert_shader = load_shader_file(2048, "shader_src/basic.vert.spv", device); VkShaderModule frag_shader = load_shader_file(2048, "shader_src/basic.frag.spv", device); VkPipelineShaderStageCreateInfo shader_stages[2] = {}; @@ -2143,10 +2142,10 @@ Material create_simple_mesh_material(VkDevice device, VkExtent2D extent, VkRende }; - return create_material(device, extent, render_pass, 2, shader_stages, scene_ubo_layout, simple_layout, simple_mesh_type); + return create_material(device, extent, render_pass, 2, shader_stages, scene_ubo_layout, simple_layout, simple_mesh_type, max_frames_in_flight); } -Material create_texture_mesh_material(VkDevice device, VkExtent2D extent, VkRenderPass render_pass, VkDescriptorSetLayout scene_ubo_layout) { +Material create_texture_mesh_material(VkDevice device, VkExtent2D extent, VkRenderPass render_pass, VkDescriptorSetLayout scene_ubo_layout, uint32_t max_frames_in_flight) { VkShaderModule vert_shader = load_shader_file(2048, "shader_src/texture.vert.spv", device); if(vert_shader == VK_NULL_HANDLE) { Material tmp = {}; @@ -2219,7 +2218,7 @@ Material create_texture_mesh_material(VkDevice device, VkExtent2D extent, VkRend .mesh_bindings = mesh_set_bindings, }; - return create_material(device, extent, render_pass, 2, shader_stages, scene_ubo_layout, texture_layout, textured_mesh_type); + return create_material(device, extent, render_pass, 2, shader_stages, scene_ubo_layout, texture_layout, textured_mesh_type, max_frames_in_flight); } VulkanContext* init_vulkan(GLFWwindow* window, uint32_t max_frames_in_flight) { @@ -2434,18 +2433,18 @@ VulkanContext* init_vulkan(GLFWwindow* window, uint32_t max_frames_in_flight) { context->in_flight_fences = if_fences; } - VkDescriptorPoolSize ubo_pool_sizes[] = { + VkDescriptorPoolSize scene_pool_sizes[] = { { .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, .descriptorCount = max_frames_in_flight, } }; - VkDescriptorPool scene_ubo_pool = create_descriptor_pool(device, ubo_pool_sizes, 1, max_frames_in_flight); - if(scene_ubo_pool == VK_NULL_HANDLE) { + VkDescriptorPool scene_pool = create_descriptor_pool(device, scene_pool_sizes, 1, max_frames_in_flight); + if(scene_pool == VK_NULL_HANDLE) { fprintf(stderr, "failed to create vulkan scene descriptor pool\n"); return 0; } else { - context->scene_ubo_pool = scene_ubo_pool; + context->scene_pool = scene_pool; } VkDescriptorSetLayoutBinding scene_ubo_layout_binding = { @@ -2456,15 +2455,15 @@ VulkanContext* init_vulkan(GLFWwindow* window, uint32_t max_frames_in_flight) { .pImmutableSamplers = 0, }; - VkDescriptorSetLayout scene_ubo_layout = create_descriptor_set_layout(device, &scene_ubo_layout_binding, 1); - if(scene_ubo_layout == VK_NULL_HANDLE) { + VkDescriptorSetLayout scene_descriptor_layout = create_descriptor_set_layout(device, &scene_ubo_layout_binding, 1); + if(scene_descriptor_layout == VK_NULL_HANDLE) { fprintf(stderr, "failed to create vulkan scene descriptor layout\n"); return 0; } else { - context->scene_ubo_layout = scene_ubo_layout; + context->scene_descriptor_layout = scene_descriptor_layout; } - VkDescriptorSet* scene_descriptors = create_descriptor_sets(context->device, context->scene_ubo_layout, context->scene_ubo_pool, max_frames_in_flight); + VkDescriptorSet* scene_descriptors = create_descriptor_sets(context->device, context->scene_descriptor_layout, context->scene_pool, max_frames_in_flight); if(scene_descriptors == 0) { fprintf(stderr, "failed to create vulkan scene descriptore\n"); return 0; @@ -2519,7 +2518,7 @@ VulkanContext* init_vulkan(GLFWwindow* window, uint32_t max_frames_in_flight) { vkUpdateDescriptorSets(device, 1, &descriptor_write, 0, 0); } - Material simple_mesh_material = create_simple_mesh_material(context->device, context->swapchain_extent, context->render_pass, context->scene_ubo_layout); + Material simple_mesh_material = create_simple_mesh_material(context->device, context->swapchain_extent, context->render_pass, context->scene_descriptor_layout, max_frames_in_flight); if(simple_mesh_material.pipeline == VK_NULL_HANDLE) { fprintf(stderr, "failed to create simple mesh material\n"); return 0; @@ -2527,14 +2526,6 @@ VulkanContext* init_vulkan(GLFWwindow* window, uint32_t max_frames_in_flight) { context->simple_mesh_material = simple_mesh_material; } - Material texture_mesh_material = create_texture_mesh_material(context->device, context->swapchain_extent, context->render_pass, context->scene_ubo_layout); - if(texture_mesh_material.pipeline == VK_NULL_HANDLE) { - fprintf(stderr, "failed to create texture mesh material\n"); - return 0; - } else { - context->texture_mesh_material = texture_mesh_material; - } - Mesh triangle_mesh = load_simple_mesh(context->physical_device, context->device, (struct Vertex*)vertices, 4, (uint16_t*)indices, 6, context->transfer_command_pool, context->queues.transfer); if(triangle_mesh.vertex_buffer.buffer == VK_NULL_HANDLE) { fprintf(stderr, "failed to load triangle mesh\n"); @@ -2543,6 +2534,22 @@ VulkanContext* init_vulkan(GLFWwindow* window, uint32_t max_frames_in_flight) { context->triangle_mesh = triangle_mesh; } + Object triangle_object = create_renderable(&context->triangle_mesh, &context->simple_mesh_material); + if(triangle_object.attributes.buckets == 0) { + fprintf(stderr, "failed to create renderable triangle object\n"); + return 0; + } else { + context->triangle_object = triangle_object; + } + + Material texture_mesh_material = create_texture_mesh_material(context->device, context->swapchain_extent, context->render_pass, context->scene_descriptor_layout, max_frames_in_flight); + if(texture_mesh_material.pipeline == VK_NULL_HANDLE) { + fprintf(stderr, "failed to create texture mesh material\n"); + return 0; + } else { + context->texture_mesh_material = texture_mesh_material; + } + Mesh triangle_mesh_textured = load_texture_mesh(context->physical_device, context->device, (struct TextureVertex*)texture_vertices, 4, (uint16_t*)indices, 6, context->transfer_command_pool, context->queues.transfer); if(triangle_mesh_textured.vertex_buffer.buffer == VK_NULL_HANDLE) { fprintf(stderr, "failed to load textured triangle mesh\n"); @@ -2551,6 +2558,14 @@ VulkanContext* init_vulkan(GLFWwindow* window, uint32_t max_frames_in_flight) { context->triangle_mesh_textured = triangle_mesh_textured; } + Object triangle_object_textured = create_renderable(&context->triangle_mesh_textured, &context->texture_mesh_material); + if(triangle_object_textured.attributes.buckets == 0) { + fprintf(stderr, "failed to create renderable textured triangle object\n"); + return 0; + } else { + context->triangle_object_textured = triangle_object_textured; + } + return context; } @@ -2801,8 +2816,8 @@ VkResult draw_frame(VulkanContext* context) { } uint32_t mesh_counts[] = {1}; - Mesh* meshes[] = {&context->triangle_mesh_textured}; - result = record_command_buffer_scene(1, &context->texture_mesh_material, (uint32_t*)&mesh_counts, (Mesh**)meshes, context->scene_descriptors[context->current_frame], context->swapchain_command_buffers[context->current_frame], context->render_pass, context->swapchain_framebuffers[image_index], context->swapchain_extent); + Object* objects[] = {&context->triangle_object_textured}; + result = command_draw_scene(1, &context->texture_mesh_material, (uint32_t*)&mesh_counts, (Object**)objects, context->current_frame, context->scene_descriptors, context->swapchain_command_buffers[context->current_frame], context->render_pass, context->swapchain_framebuffers[image_index], context->swapchain_extent); if(result != VK_SUCCESS) { return result; }