Added swapchain recreation when out of date

main
noah metz 2024-01-08 19:48:09 -07:00
parent 6906e4fc38
commit 3bb460d05c
1 changed files with 146 additions and 17 deletions

@ -52,18 +52,37 @@ typedef struct AllocatedBufferStruct {
VkDeviceMemory memory;
} AllocatedBuffer;
typedef struct MaterialStruct {
VkPipelineLayout pipeline_layout;
VkPipeline pipeline;
} Material;
typedef struct MeshStruct {
uint32_t vertex_count;
AllocatedBuffer vertex_buffer;
uint32_t index_count;
AllocatedBuffer index_buffer;
void* data;
} Mesh;
typedef void (*MaterialBindFunc)(VkCommandBuffer, void*);
typedef void (*MeshBindFunc)(Mesh, VkCommandBuffer, void*);
typedef struct MaterialStruct {
VkPipelineLayout pipeline_layout;
VkPipeline pipeline;
MaterialBindFunc material_bind;
MeshBindFunc mesh_bind;
void* data;
} Material;
typedef struct TextureMaterialDataStruct {
// Store pool to allocate new texture descriptor sets
} TextureMaterialData;
typedef struct TextureMeshDataStruct {
// Store allocated texture descriptor set
} TextureMeshData;
typedef struct VulkanContextStruct {
VkInstance instance;
VkDebugUtilsMessengerEXT debug_messenger;
@ -190,7 +209,7 @@ GLFWwindow* init_window(int width, int height) {
glfwSetErrorCallback(glfw_error);
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE);
GLFWwindow* window = glfwCreateWindow(width, height, "Vulkan window", 0, 0);
@ -1188,18 +1207,84 @@ VkCommandPool create_command_pool(VkDevice device, uint32_t queue_family) {
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);
}
VkResult recreate_swap_chain(VulkanContext* context, VkExtent2D new_extent) {
for(uint32_t i = 0; i < context->swapchain_image_count; i++) {
vkDestroyFramebuffer(context->device, context->swapchain_framebuffers[i], 0);
vkDestroyImageView(context->device, context->swapchain_image_views[i], 0);
}
vkDestroySwapchainKHR(context->device, context->swapchain, 0);
free(context->swapchain_images);
free(context->swapchain_image_views);
free(context->swapchain_framebuffers);
free(context->swapchain_details.formats);
free(context->swapchain_details.present_modes);
context->swapchain_extent = new_extent;
SwapchainDetails swapchain_details = get_swapchain_details(context->physical_device, context->surface);
if(swapchain_details.formats == 0) {
return 0;
} else {
context->swapchain_details = swapchain_details;
}
context->swapchain_format = choose_swapchain_format(context->swapchain_details);
context->swapchain_present_mode = choose_present_mode(context->swapchain_details);
context->swapchain_extent = choose_swapchain_extent(context->swapchain_details);
VkSwapchainKHR swapchain = create_swapchain(context->device, context->swapchain_format, context->swapchain_present_mode, context->swapchain_extent, context->surface, context->swapchain_details.capabilities, context->queue_indices, context->swapchain);
if(swapchain == VK_NULL_HANDLE) {
context->swapchain = VK_NULL_HANDLE;
return VK_ERROR_INITIALIZATION_FAILED;
} else {
context->swapchain = swapchain;
}
SwapchainImages swapchain_images = get_swapchain_images(context->device, context->swapchain);
if(swapchain_images.count == 0) {
return VK_ERROR_INITIALIZATION_FAILED;
} else {
context->swapchain_images = swapchain_images.images;
context->swapchain_image_count = swapchain_images.count;
}
VkImageView* image_views = create_image_views(context->device, context->swapchain_image_count, context->swapchain_images, context->swapchain_format);
if(image_views == 0) {
return VK_ERROR_INITIALIZATION_FAILED;
} else {
context->swapchain_image_views = image_views;
}
VkFramebuffer* framebuffers = create_swapchain_framebuffers(context->device, context->swapchain_image_count, context->swapchain_image_views, context->render_pass, context->swapchain_extent);
if(framebuffers == 0) {
return VK_ERROR_INITIALIZATION_FAILED;
} else {
context->swapchain_framebuffers = framebuffers;
}
return VK_SUCCESS;
}
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);
if(material.material_bind != 0) {
material.material_bind(command_buffer, material.data);
}
for(uint32_t i = 0; i < mesh_count; i++) {
if(material.mesh_bind != 0) {
material.mesh_bind(meshes[i], command_buffer, material.data);
}
record_command_buffer_mesh(meshes[i], command_buffer);
}
}
@ -1341,7 +1426,21 @@ Mesh load_mesh(VkPhysicalDevice physical_device, VkDevice device, struct Vertex*
return mesh;
}
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 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,
MaterialBindFunc material_bind,
MeshBindFunc mesh_bind,
void* data
) {
Material zero_material = {
.pipeline = VK_NULL_HANDLE,
};
@ -1372,8 +1471,6 @@ Material create_material(VkDevice device, VkExtent2D extent, VkRenderPass render
free(all_pcrs);
return zero_material;
}
free(all_layouts);
free(all_pcrs);
VkPipeline pipeline = create_graphics_pipeline(device, extent, pipeline_layout, render_pass, shader_stage_count, shader_stages);
if(pipeline == VK_NULL_HANDLE) {
@ -1383,6 +1480,9 @@ Material create_material(VkDevice device, VkExtent2D extent, VkRenderPass render
Material material = {
.pipeline_layout = pipeline_layout,
.pipeline = pipeline,
.material_bind = material_bind,
.mesh_bind = mesh_bind,
.data = data,
};
return material;
@ -1637,7 +1737,7 @@ VulkanContext* init_vulkan(GLFWwindow* window, uint32_t max_frames_in_flight) {
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);
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, 0, 0, 0);
if(simple_mesh_material.pipeline == VK_NULL_HANDLE) {
fprintf(stderr, "failed to create simple mesh material\n");
return 0;
@ -1666,11 +1766,18 @@ struct {
bool down: 1;
bool turn_left: 1;
bool turn_right: 1;
bool turn_up: 1;
bool turn_down: 1;
} key_flags = {
.forward = false,
.backward = false,
.left = false,
.right = false,
.turn_left = false,
.turn_right = false,
.turn_up = false,
.turn_down = false,
};
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) {
@ -1742,6 +1849,22 @@ void key_callback(GLFWwindow* window, int key, int scancode, int action, int mod
key_flags.turn_left = false;
}
break;
case GLFW_KEY_UP:
if(action == GLFW_PRESS) {
key_flags.turn_up = true;
} else if(action == GLFW_RELEASE) {
key_flags.turn_up = false;
}
break;
case GLFW_KEY_DOWN:
if(action == GLFW_PRESS) {
key_flags.turn_down = true;
} else if(action == GLFW_RELEASE) {
key_flags.turn_down = false;
}
break;
}
}
@ -1801,7 +1924,7 @@ VkResult update_scene_ubo(void** buffers, uint32_t frame_index, vec3 world_posit
return VK_SUCCESS;
}
VkResult draw_frame(VulkanContext* context) {
VkResult draw_frame(GLFWwindow* window, VulkanContext* context) {
update_scene_ubo(context->scene_ubo_ptrs, context->current_frame, world_position, &rotation, (float)context->swapchain_extent.width/(float)context->swapchain_extent.height, 0.01);
VkResult result;
@ -1810,13 +1933,19 @@ VkResult draw_frame(VulkanContext* context) {
return result;
}
result = vkResetFences(context->device, 1, &context->in_flight_fences[context->current_frame]);
if(result != VK_SUCCESS) {
uint32_t image_index;
result = vkAcquireNextImageKHR(context->device, context->swapchain, UINT64_MAX, context->image_available_semaphores[context->current_frame], VK_NULL_HANDLE, &image_index);
if(result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR) {
int width, height;
glfwGetWindowSize(window, &width, &height);
VkExtent2D window_extent = {width, height};
recreate_swap_chain(context, window_extent);
return result;
} else if(result != VK_SUCCESS) {
return result;
}
uint32_t image_index;
result = vkAcquireNextImageKHR(context->device, context->swapchain, UINT64_MAX, context->image_available_semaphores[context->current_frame], VK_NULL_HANDLE, &image_index);
result = vkResetFences(context->device, 1, &context->in_flight_fences[context->current_frame]);
if(result != VK_SUCCESS) {
return result;
}
@ -1866,7 +1995,7 @@ void main_loop(GLFWwindow* window, VulkanContext* context) {
while(!glfwWindowShouldClose(window)) {
glfwPollEvents();
draw_frame(context);
draw_frame(window, context);
context->current_frame += 1;
if(context->current_frame >= context->max_frames_in_flight) {
context->current_frame = 0;