Moved scene UBO to a descriptor in the vulkan context. Need to figure out how to deal with materials that give out descriptors per loaded mesh.

main
noah metz 2024-01-08 16:44:14 -07:00
parent 4b7a2b9d37
commit 04618af2fb
2 changed files with 151 additions and 127 deletions

@ -1,7 +1,6 @@
#version 450 #version 450
layout(binding = 0) uniform UniformBufferObject { layout(binding = 0) uniform UniformBufferObject {
mat4 model;
mat4 view; mat4 view;
mat4 proj; mat4 proj;
} ubo; } ubo;
@ -12,6 +11,6 @@ layout(location = 1) in vec3 inColor;
layout(location = 0) out vec3 fragColor; layout(location = 0) out vec3 fragColor;
void main() { void main() {
gl_Position = ubo.proj * ubo.view * ubo.model * vec4(inPosition, 0.0, 1.0); gl_Position = ubo.proj * ubo.view * vec4(inPosition, 0.0, 1.0);
fragColor = inColor; fragColor = inColor;
} }

@ -51,20 +51,8 @@ typedef struct AllocatedBufferStruct {
} AllocatedBuffer; } AllocatedBuffer;
typedef struct MaterialStruct { typedef struct MaterialStruct {
uint32_t descriptor_set_layouts_count;
VkDescriptorSetLayout* descriptor_set_layouts;
uint32_t push_constant_ranges_count;
VkPushConstantRange* push_constant_ranges;
VkPipelineLayout pipeline_layout; VkPipelineLayout pipeline_layout;
VkPipeline pipeline; VkPipeline pipeline;
VkDescriptorPool descriptor_pool;
uint32_t frame_count;
VkDescriptorSet* descriptor_sets;
AllocatedBuffer* uniform_buffers;
void** uniform_buffer_ptrs;
} Material; } Material;
typedef struct MeshStruct { typedef struct MeshStruct {
@ -110,6 +98,12 @@ typedef struct VulkanContextStruct {
VkCommandPool graphics_command_pool; VkCommandPool graphics_command_pool;
VkCommandPool transfer_command_pool; VkCommandPool transfer_command_pool;
VkDescriptorPool scene_ubo_pool;
VkDescriptorSetLayout scene_ubo_layout;
VkDescriptorSet* scene_ubo_descriptors;
AllocatedBuffer* scene_ubos;
void** scene_ubo_ptrs;
Mesh triangle_mesh; Mesh triangle_mesh;
Material simple_mesh_material; Material simple_mesh_material;
@ -121,8 +115,7 @@ struct Vertex{
vec3 color; vec3 color;
}; };
struct ShaderUBO { struct SceneUBO {
mat4 model;
mat4 view; mat4 view;
mat4 proj; mat4 proj;
}; };
@ -441,9 +434,9 @@ VkDebugUtilsMessengerEXT create_debug_messenger(VkInstance instance) {
return debug_messenger; return debug_messenger;
} }
VkDescriptorPool create_descriptor_pool(VkDevice device, uint32_t size) { VkDescriptorPool create_descriptor_pool(VkDevice device, VkDescriptorType type, uint32_t size) {
VkDescriptorPoolSize pool_size = {}; VkDescriptorPoolSize pool_size = {};
pool_size.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; pool_size.type = type;
pool_size.descriptorCount = size; pool_size.descriptorCount = size;
VkDescriptorPoolCreateInfo pool_info = {}; VkDescriptorPoolCreateInfo pool_info = {};
@ -1062,21 +1055,7 @@ AllocatedBuffer create_populated_buffer(VkPhysicalDevice physical_device, VkDevi
return vertex_buffer; return vertex_buffer;
} }
VkPipeline create_graphics_pipeline(VkDevice device, VkExtent2D extent, VkPipelineLayout layout, VkRenderPass render_pass) { VkPipeline create_graphics_pipeline(VkDevice device, VkExtent2D extent, VkPipelineLayout layout, VkRenderPass render_pass, uint32_t shader_stage_count, VkPipelineShaderStageCreateInfo* shader_stages) {
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] = {};
shader_stages[0].sType = VK_STRUCTURE_TYPE_SHADER_CREATE_INFO_EXT;
shader_stages[0].stage = VK_SHADER_STAGE_VERTEX_BIT;
shader_stages[0].module = vert_shader;
shader_stages[0].pName = "main";
shader_stages[1].sType = VK_STRUCTURE_TYPE_SHADER_CREATE_INFO_EXT;
shader_stages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT;
shader_stages[1].module = frag_shader;
shader_stages[1].pName = "main";
VkDynamicState dynamic_states[] = { VkDynamicState dynamic_states[] = {
VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_VIEWPORT,
VK_DYNAMIC_STATE_SCISSOR, VK_DYNAMIC_STATE_SCISSOR,
@ -1165,7 +1144,7 @@ VkPipeline create_graphics_pipeline(VkDevice device, VkExtent2D extent, VkPipeli
VkGraphicsPipelineCreateInfo pipeline_info = {}; VkGraphicsPipelineCreateInfo pipeline_info = {};
pipeline_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; pipeline_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
pipeline_info.stageCount = 2; pipeline_info.stageCount = shader_stage_count;
pipeline_info.pStages = shader_stages; pipeline_info.pStages = shader_stages;
pipeline_info.pVertexInputState = &vertex_input_info; pipeline_info.pVertexInputState = &vertex_input_info;
pipeline_info.pInputAssemblyState = &input_assemvly_info; pipeline_info.pInputAssemblyState = &input_assemvly_info;
@ -1205,7 +1184,26 @@ VkCommandPool create_command_pool(VkDevice device, uint32_t queue_family) {
return command_pool; return command_pool;
} }
VkResult record_command_buffer_mesh(VkCommandBuffer command_buffer, VkRenderPass render_pass, VkFramebuffer framebuffer, VkExtent2D extent, Material material, Mesh mesh, uint32_t current_frame) { void record_command_buffer_mesh(Mesh mesh, VkCommandBuffer command_buffer) {
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);
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_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);
}
}
VkResult record_command_buffer_scene(uint32_t materials_count, Material* materials, uint32_t* mesh_counts, Mesh** meshes, VkDescriptorSet scene_ubo_descriptor, VkCommandBuffer command_buffer, VkRenderPass render_pass, VkFramebuffer framebuffer, VkExtent2D extent) {
VkCommandBufferBeginInfo begin_info = {}; VkCommandBufferBeginInfo begin_info = {};
begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
begin_info.flags = 0; begin_info.flags = 0;
@ -1228,12 +1226,6 @@ VkResult record_command_buffer_mesh(VkCommandBuffer command_buffer, VkRenderPass
render_pass_info.pClearValues = &clear_color; render_pass_info.pClearValues = &clear_color;
vkCmdBeginRenderPass(command_buffer, &render_pass_info, VK_SUBPASS_CONTENTS_INLINE); vkCmdBeginRenderPass(command_buffer, &render_pass_info, VK_SUBPASS_CONTENTS_INLINE);
vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, material.pipeline);
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);
VkViewport viewport = {}; VkViewport viewport = {};
viewport.x = 0.0f; viewport.x = 0.0f;
@ -1250,8 +1242,10 @@ VkResult record_command_buffer_mesh(VkCommandBuffer command_buffer, VkRenderPass
scissor.extent = extent; scissor.extent = extent;
vkCmdSetScissor(command_buffer, 0, 1, &scissor); vkCmdSetScissor(command_buffer, 0, 1, &scissor);
vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, material.pipeline_layout, 0, 1, &material.descriptor_sets[current_frame], 0, 0); for(uint i = 0; i < materials_count; i++) {
vkCmdDrawIndexed(command_buffer, mesh.index_count, 1, 0, 0, 0); record_command_buffer_material(materials[i], mesh_counts[i], meshes[i], scene_ubo_descriptor, command_buffer);
}
vkCmdEndRenderPass(command_buffer); vkCmdEndRenderPass(command_buffer);
return vkEndCommandBuffer(command_buffer); return vkEndCommandBuffer(command_buffer);
@ -1346,106 +1340,48 @@ Mesh load_mesh(VkPhysicalDevice physical_device, VkDevice device, struct Vertex*
return mesh; return mesh;
} }
Material create_simple_mesh_material(VkPhysicalDevice physical_device, VkDevice device, VkExtent2D extent, VkRenderPass render_pass, uint32_t num_frames) { Material create_material(VkDevice device, VkExtent2D extent, VkRenderPass render_pass, uint32_t shader_stage_count, VkPipelineShaderStageCreateInfo* shader_stages, VkDescriptorSetLayout scene_ubo_layout, uint32_t set_count, VkDescriptorSetLayout* set_layouts, uint32_t pcr_count, VkPushConstantRange* pcrs) {
Material zero_material = { Material zero_material = {
.pipeline = VK_NULL_HANDLE, .pipeline = VK_NULL_HANDLE,
}; };
AllocatedBuffer* uniform_buffers = allocate_buffers(physical_device, device, sizeof(struct ShaderUBO), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, num_frames); VkDescriptorSetLayout* all_layouts = malloc(sizeof(VkDescriptorSetLayout)*(1+set_count));
if(uniform_buffers == 0) { if(all_layouts == 0) {
return zero_material; return zero_material;
} }
void** uniform_buffer_ptrs = malloc(sizeof(void*)*num_frames); all_layouts[0] = scene_ubo_layout;
if(uniform_buffer_ptrs == 0) { for(uint32_t i = 0; i < set_count; i++) {
free(uniform_buffers); all_layouts[i+1] = set_layouts[i];
return zero_material;
}
for(uint32_t i = 0; i < num_frames; i++) {
VkResult result = vkMapMemory(device, uniform_buffers[i].memory, 0, sizeof(struct ShaderUBO), 0, &uniform_buffer_ptrs[i]);
if(result != VK_SUCCESS) {
for(uint32_t j = 0; j < i; j++) {
vkUnmapMemory(device, uniform_buffers[j].memory);
}
free(uniform_buffers);
free(uniform_buffer_ptrs);
return zero_material;
}
}
VkDescriptorPool descriptor_pool = create_descriptor_pool(device, num_frames);
if(descriptor_pool == VK_NULL_HANDLE) {
for(uint32_t i = 0; i < num_frames; i++) {
vkUnmapMemory(device, uniform_buffers[i].memory);
}
free(uniform_buffers);
free(uniform_buffer_ptrs);
return zero_material;
} }
VkDescriptorSetLayoutBinding ubo_layout_binding = { VkPushConstantRange* all_pcrs = malloc(sizeof(VkPushConstantRange)*(0+pcr_count));
.binding = 0, if((all_pcrs == 0) && (pcr_count != 0)) {
.stageFlags = VK_SHADER_STAGE_VERTEX_BIT, free(all_layouts);
.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
.descriptorCount = 1,
.pImmutableSamplers = 0,
};
VkDescriptorSetLayout descriptor_set_layout = create_descriptor_set_layout(device, &ubo_layout_binding, 1);
if(descriptor_set_layout == VK_NULL_HANDLE) {
return zero_material; return zero_material;
} }
VkDescriptorSet* descriptor_sets = create_descriptor_sets(device, descriptor_set_layout, descriptor_pool, num_frames); for(uint32_t i = 0; i < pcr_count; i++) {
if(descriptor_sets == 0) { all_pcrs[i] = pcrs[i];
return zero_material;
} }
for(uint32_t i = 0; i < num_frames; i++) { VkPipelineLayout pipeline_layout = create_pipeline_layout(device, 1+set_count, all_layouts, 0+pcr_count, all_pcrs);
VkDescriptorBufferInfo buffer_info = {};
buffer_info.buffer = uniform_buffers[i].buffer;
buffer_info.offset = 0;
buffer_info.range = sizeof(struct ShaderUBO);
VkWriteDescriptorSet descriptor_write = {};
descriptor_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
descriptor_write.dstSet = descriptor_sets[i];
descriptor_write.dstBinding = 0;
descriptor_write.dstArrayElement = 0;
descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
descriptor_write.descriptorCount = 1;
descriptor_write.pBufferInfo = &buffer_info;
descriptor_write.pImageInfo = 0;
descriptor_write.pTexelBufferView = 0;
vkUpdateDescriptorSets(device, 1, &descriptor_write, 0, 0);
}
VkPipelineLayout pipeline_layout = create_pipeline_layout(device, 1, &descriptor_set_layout, 0, 0);
if(pipeline_layout == VK_NULL_HANDLE) { if(pipeline_layout == VK_NULL_HANDLE) {
free(all_layouts);
free(all_pcrs);
return zero_material; return zero_material;
} }
free(all_layouts);
free(all_pcrs);
VkPipeline pipeline = create_graphics_pipeline(device, extent, pipeline_layout, render_pass); VkPipeline pipeline = create_graphics_pipeline(device, extent, pipeline_layout, render_pass, shader_stage_count, shader_stages);
if(pipeline == VK_NULL_HANDLE) { if(pipeline == VK_NULL_HANDLE) {
return zero_material; return zero_material;
} }
Material material = { Material material = {
.descriptor_set_layouts_count = 1,
.descriptor_set_layouts = &descriptor_set_layout,
.push_constant_ranges_count = 0,
.push_constant_ranges = 0,
.pipeline_layout = pipeline_layout, .pipeline_layout = pipeline_layout,
.pipeline = pipeline, .pipeline = pipeline,
.descriptor_pool = descriptor_pool,
.frame_count = num_frames,
.descriptor_sets = descriptor_sets,
.uniform_buffers = uniform_buffers,
.uniform_buffer_ptrs = uniform_buffer_ptrs,
}; };
return material; return material;
@ -1608,7 +1544,99 @@ VulkanContext* init_vulkan(GLFWwindow* window, uint32_t max_frames_in_flight) {
context->in_flight_fences = if_fences; context->in_flight_fences = if_fences;
} }
Material simple_mesh_material = create_simple_mesh_material(context->physical_device, context->device, context->swapchain_extent, context->render_pass, max_frames_in_flight); VkDescriptorPool scene_ubo_pool = create_descriptor_pool(device, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, max_frames_in_flight);
if(scene_ubo_pool == VK_NULL_HANDLE) {
fprintf(stderr, "failed to create vulkan scene descriptor pool\n");
return 0;
} else {
context->scene_ubo_pool = scene_ubo_pool;
}
VkDescriptorSetLayoutBinding scene_ubo_layout_binding = {
.binding = 0,
.stageFlags = VK_SHADER_STAGE_VERTEX_BIT,
.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
.descriptorCount = 1,
.pImmutableSamplers = 0,
};
VkDescriptorSetLayout scene_ubo_layout = create_descriptor_set_layout(device, &scene_ubo_layout_binding, 1);
if(scene_ubo_layout == VK_NULL_HANDLE) {
fprintf(stderr, "failed to create vulkan scene descriptor layout\n");
return 0;
} else {
context->scene_ubo_layout = scene_ubo_layout;
}
VkDescriptorSet* scene_ubo_descriptors = create_descriptor_sets(context->device, context->scene_ubo_layout, context->scene_ubo_pool, max_frames_in_flight);
if(scene_ubo_descriptors == 0) {
fprintf(stderr, "failed to create vulkan scene descriptore\n");
return 0;
} else {
context->scene_ubo_descriptors = scene_ubo_descriptors;
}
AllocatedBuffer* scene_ubos = allocate_buffers(context->physical_device, context->device, sizeof(struct SceneUBO), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, max_frames_in_flight);
if(scene_ubos == 0) {
fprintf(stderr, "failed to create vulkan scnene ubo buffers\n");
return 0;
} else {
context->scene_ubos = scene_ubos;
}
void** scene_ubo_ptrs = malloc(sizeof(void*)*max_frames_in_flight);
if(scene_ubo_ptrs == 0) {
return 0;
} else {
context->scene_ubo_ptrs = scene_ubo_ptrs;
}
for(uint32_t i = 0; i < max_frames_in_flight; i++) {
VkResult result = vkMapMemory(device, context->scene_ubos[i].memory, 0, sizeof(struct SceneUBO), 0, &context->scene_ubo_ptrs[i]);
if(result != VK_SUCCESS) {
for(uint32_t j = 0; j < i; j++) {
vkUnmapMemory(device, context->scene_ubos[j].memory);
}
fprintf(stderr, "failed to map vulkan buffers to pointers for scene ubos\n");
return 0;
}
}
for(uint32_t i = 0; i < max_frames_in_flight; i++) {
VkDescriptorBufferInfo buffer_info = {};
buffer_info.buffer = context->scene_ubos[i].buffer;
buffer_info.offset = 0;
buffer_info.range = sizeof(struct SceneUBO);
VkWriteDescriptorSet descriptor_write = {};
descriptor_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
descriptor_write.dstSet = context->scene_ubo_descriptors[i];
descriptor_write.dstBinding = 0;
descriptor_write.dstArrayElement = 0;
descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
descriptor_write.descriptorCount = 1;
descriptor_write.pBufferInfo = &buffer_info;
descriptor_write.pImageInfo = 0;
descriptor_write.pTexelBufferView = 0;
vkUpdateDescriptorSets(device, 1, &descriptor_write, 0, 0);
}
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] = {};
shader_stages[0].sType = VK_STRUCTURE_TYPE_SHADER_CREATE_INFO_EXT;
shader_stages[0].stage = VK_SHADER_STAGE_VERTEX_BIT;
shader_stages[0].module = vert_shader;
shader_stages[0].pName = "main";
shader_stages[1].sType = VK_STRUCTURE_TYPE_SHADER_CREATE_INFO_EXT;
shader_stages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT;
shader_stages[1].module = frag_shader;
shader_stages[1].pName = "main";
Material simple_mesh_material = create_material(context->device, context->swapchain_extent, context->render_pass, 2, shader_stages, context->scene_ubo_layout, 0, 0, 0, 0);
if(simple_mesh_material.pipeline == VK_NULL_HANDLE) { if(simple_mesh_material.pipeline == VK_NULL_HANDLE) {
fprintf(stderr, "failed to create simple mesh material\n"); fprintf(stderr, "failed to create simple mesh material\n");
return 0; return 0;
@ -1626,23 +1654,18 @@ VulkanContext* init_vulkan(GLFWwindow* window, uint32_t max_frames_in_flight) {
return context; return context;
} }
uint32_t counter = 0;
VkResult update_ubo(void** buffers, uint32_t frame_index) { VkResult update_ubo(void** buffers, uint32_t frame_index) {
struct ShaderUBO ubo = {}; struct SceneUBO ubo = {};
glm_mat4_identity(ubo.proj); glm_mat4_identity(ubo.proj);
glm_mat4_identity(ubo.view); glm_mat4_identity(ubo.view);
vec3 axis = {0.0f, 0.0f, 1.0f};
glm_rotate_make(ubo.model, counter/100.0f, axis);
memcpy(buffers[frame_index], (void*)&ubo, sizeof(ubo)); memcpy(buffers[frame_index], (void*)&ubo, sizeof(ubo));
counter += 1;
return VK_SUCCESS; return VK_SUCCESS;
} }
VkResult draw_frame(VulkanContext* context) { VkResult draw_frame(VulkanContext* context) {
update_ubo(context->simple_mesh_material.uniform_buffer_ptrs, context->current_frame); update_ubo(context->scene_ubo_ptrs, context->current_frame);
VkResult result; VkResult result;
result = vkWaitForFences(context->device, 1, &context->in_flight_fences[context->current_frame], VK_TRUE, UINT64_MAX); result = vkWaitForFences(context->device, 1, &context->in_flight_fences[context->current_frame], VK_TRUE, UINT64_MAX);
@ -1666,7 +1689,9 @@ VkResult draw_frame(VulkanContext* context) {
return result; return result;
} }
result = record_command_buffer_mesh(context->swapchain_command_buffers[context->current_frame], context->render_pass, context->swapchain_framebuffers[image_index], context->swapchain_extent, context->simple_mesh_material, context->triangle_mesh, context->current_frame); uint32_t mesh_counts[] = {1};
Mesh* meshes[] = {&context->triangle_mesh};
result = record_command_buffer_scene(1, &context->simple_mesh_material, (uint32_t*)&mesh_counts, (Mesh**)meshes, context->scene_ubo_descriptors[context->current_frame], context->swapchain_command_buffers[context->current_frame], context->render_pass, context->swapchain_framebuffers[image_index], context->swapchain_extent);
if(result != VK_SUCCESS) { if(result != VK_SUCCESS) {
return result; return result;
} }