diff --git a/shader_src/texture.frag b/shader_src/texture.frag index 9bbc581..e4fa5f1 100644 --- a/shader_src/texture.frag +++ b/shader_src/texture.frag @@ -1,5 +1,7 @@ #version 450 +layout(binding = 0) uniform sampler2D texSampler; + layout(location = 0) in vec3 fragColor; layout(location = 1) in vec2 fragTex; diff --git a/src/main.c b/src/main.c index 75620d3..16ed748 100644 --- a/src/main.c +++ b/src/main.c @@ -65,20 +65,36 @@ typedef struct TextureStruct { } Texture; typedef struct MeshStruct { - uint32_t vertex_count; + uint32_t vertex_count; AllocatedBuffer vertex_buffer; - uint32_t index_count; + uint32_t index_count; AllocatedBuffer index_buffer; - - VkDescriptorSet mesh_descriptors; } 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 pipeline_layout; VkPipeline pipeline; - - VkDescriptorPool descriptor_pool; } Material; typedef struct VulkanContextStruct { @@ -248,6 +264,122 @@ 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) { @@ -444,16 +576,12 @@ VkDebugUtilsMessengerEXT create_debug_messenger(VkInstance instance) { return debug_messenger; } -VkDescriptorPool create_descriptor_pool(VkDevice device, VkDescriptorType type, uint32_t size) { - VkDescriptorPoolSize pool_size = {}; - pool_size.type = type; - pool_size.descriptorCount = size; - +VkDescriptorPool create_descriptor_pool(VkDevice device, VkDescriptorPoolSize* sizes, uint32_t num_sizes, uint32_t max_sets) { VkDescriptorPoolCreateInfo pool_info = {}; pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; - pool_info.poolSizeCount = 1; - pool_info.pPoolSizes = &pool_size; - pool_info.maxSets = size; + pool_info.poolSizeCount = num_sizes; + pool_info.pPoolSizes = sizes; + pool_info.maxSets = max_sets; VkDescriptorPool pool; VkResult result = vkCreateDescriptorPool(device, &pool_info, 0, &pool); @@ -1502,7 +1630,6 @@ void record_command_buffer_mesh(Mesh mesh, VkCommandBuffer command_buffer) { void record_command_buffer_material(Material material, uint32_t mesh_count, Mesh* meshes, VkDescriptorSet scene_ubo_descriptor, VkCommandBuffer command_buffer) { vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, material.pipeline); vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, material.pipeline_layout, 0, 1, &scene_ubo_descriptor, 0, 0); - for(uint32_t i = 0; i < mesh_count; i++) { record_command_buffer_mesh(meshes[i], command_buffer); } @@ -1674,6 +1801,8 @@ 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, @@ -1681,8 +1810,10 @@ Material create_material( uint32_t shader_stage_count, VkPipelineShaderStageCreateInfo* shader_stages, VkDescriptorSetLayout scene_ubo_layout, - uint32_t set_count, - VkDescriptorSetLayout* set_layouts, + uint32_t material_set_bindings_count, + VkDescriptorSetLayoutBinding* material_set_bindings, + uint32_t mesh_set_bindings_count, + VkDescriptorSetLayoutBinding* mesh_set_bindings, uint32_t pcr_count, VkPushConstantRange* pcrs, uint32_t bindings_count, @@ -1694,19 +1825,45 @@ Material create_material( .pipeline = VK_NULL_HANDLE, }; - VkDescriptorSetLayout* all_layouts = malloc(sizeof(VkDescriptorSetLayout)*(1+set_count)); - if(all_layouts == 0) { - return zero_material; + VkDescriptorSetLayout material_set_layout; + VkDescriptorSetLayout mesh_set_layout; + VkDescriptorSetLayout all_layouts[3] = {scene_ubo_layout, VK_NULL_HANDLE, VK_NULL_HANDLE}; + uint32_t num_layouts = 1; + + if(material_set_bindings_count > 0) { + VkDescriptorSetLayoutCreateInfo layout_info = { + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, + .bindingCount = material_set_bindings_count, + .pBindings = material_set_bindings, + }; + + VkResult result = vkCreateDescriptorSetLayout(device, &layout_info, 0, &material_set_layout); + if(result != VK_SUCCESS) { + return zero_material; + } + + all_layouts[num_layouts] = material_set_layout; + num_layouts += 1; } - all_layouts[0] = scene_ubo_layout; - for(uint32_t i = 0; i < set_count; i++) { - all_layouts[i+1] = set_layouts[i]; + if(mesh_set_bindings_count > 0) { + VkDescriptorSetLayoutCreateInfo layout_info = { + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, + .bindingCount = mesh_set_bindings_count, + .pBindings = mesh_set_bindings, + }; + + VkResult result = vkCreateDescriptorSetLayout(device, &layout_info, 0, &mesh_set_layout); + if(result != VK_SUCCESS) { + return zero_material; + } + + all_layouts[num_layouts] = mesh_set_layout; + num_layouts += 1; } VkPushConstantRange* all_pcrs = malloc(sizeof(VkPushConstantRange)*(0+pcr_count)); if((all_pcrs == 0) && (pcr_count != 0)) { - free(all_layouts); return zero_material; } @@ -1714,9 +1871,8 @@ Material create_material( all_pcrs[i] = pcrs[i]; } - VkPipelineLayout pipeline_layout = create_pipeline_layout(device, 1+set_count, all_layouts, 0+pcr_count, all_pcrs); + VkPipelineLayout pipeline_layout = create_pipeline_layout(device, num_layouts, all_layouts, pcr_count, all_pcrs); if(pipeline_layout == VK_NULL_HANDLE) { - free(all_layouts); free(all_pcrs); return zero_material; } @@ -1729,6 +1885,9 @@ Material create_material( Material material = { .pipeline_layout = pipeline_layout, .pipeline = pipeline, + + .material_set_layout = material_set_layout, + .mesh_set_layout = mesh_set_layout, }; return material; @@ -1771,7 +1930,7 @@ Material create_simple_mesh_material(VkDevice device, VkExtent2D extent, VkRende }, }; - return create_material(device, extent, render_pass, 2, shader_stages, scene_ubo_layout, 0, 0, 0, 0, 1, bindings, 2, attributes); + return create_material(device, extent, render_pass, 2, shader_stages, scene_ubo_layout, 0, 0, 0, 0, 0, 0, 1, bindings, 2, attributes); } Material create_texture_mesh_material(VkDevice device, VkExtent2D extent, VkRenderPass render_pass, VkDescriptorSetLayout scene_ubo_layout) { @@ -1796,7 +1955,7 @@ Material create_texture_mesh_material(VkDevice device, VkExtent2D extent, VkRend shader_stages[1].module = frag_shader; shader_stages[1].pName = "main"; - VkVertexInputBindingDescription bindings[1] = { + VkVertexInputBindingDescription bindings[] = { { .binding = 0, .stride = sizeof(struct TextureVertex), @@ -1804,7 +1963,7 @@ Material create_texture_mesh_material(VkDevice device, VkExtent2D extent, VkRend }, }; - VkVertexInputAttributeDescription attributes[3] = { + VkVertexInputAttributeDescription attributes[] = { { .binding = 0, .location = 0, @@ -1825,7 +1984,17 @@ Material create_texture_mesh_material(VkDevice device, VkExtent2D extent, VkRend }, }; - return create_material(device, extent, render_pass, 2, shader_stages, scene_ubo_layout, 0, 0, 0, 0, 1, bindings, 3, attributes); + VkDescriptorSetLayoutBinding mesh_set_bindings[] = { + { + .binding = 1, + .descriptorCount = 1, + .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, + .pImmutableSamplers = 0, + .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT, + }, + }; + + return create_material(device, extent, render_pass, 2, shader_stages, scene_ubo_layout, 0, 0, 1, mesh_set_bindings, 0, 0, 1, bindings, 3, attributes); } VulkanContext* init_vulkan(GLFWwindow* window, uint32_t max_frames_in_flight) { @@ -1985,7 +2154,13 @@ VulkanContext* init_vulkan(GLFWwindow* window, uint32_t max_frames_in_flight) { context->in_flight_fences = if_fences; } - VkDescriptorPool scene_ubo_pool = create_descriptor_pool(device, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, max_frames_in_flight); + VkDescriptorPoolSize ubo_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) { fprintf(stderr, "failed to create vulkan scene descriptor pool\n"); return 0; @@ -2314,7 +2489,6 @@ VkResult update_scene_ubo(void** buffers, uint32_t frame_index, vec3 world_posit glm_perspective(90.0f, aspect_ratio, 0.1, 100, ubo.proj); glm_quat_look(world_position, world_rotation, ubo.view); - //glm_look(world_position, dir, up, ubo.view); memcpy(buffers[frame_index], (void*)&ubo, sizeof(ubo));