From 530a034ed1f29aaa9aea1da29984bf0cd04fb403 Mon Sep 17 00:00:00 2001 From: Noah Metz Date: Sun, 3 Nov 2024 14:25:59 -0700 Subject: [PATCH] Added window resizing --- client/include/gpu.h | 9 +- client/src/draw.c | 14 ++- client/src/gpu.c | 256 +++++++++++++++++++++++++++++++++++++------ client/src/main.c | 11 +- 4 files changed, 251 insertions(+), 39 deletions(-) diff --git a/client/include/gpu.h b/client/include/gpu.h index a49d408..b805a5c 100644 --- a/client/include/gpu.h +++ b/client/include/gpu.h @@ -150,6 +150,8 @@ typedef struct RenderContextStruct { uint32_t current_frame; vec2 window_scale; + + bool framebuffer_recreated; } RenderContext; GLFWwindow* init_window(); @@ -229,6 +231,11 @@ VkResult command_transition_image_layout( uint32_t dest_family, VkImageAspectFlags aspect_flags); -VkShaderModule load_shader_file(const char* path, VkDevice device); +VkShaderModule load_shader_file( + const char* path, + VkDevice device); + +VkResult recreate_framebuffer( + RenderContext* gpu); #endif diff --git a/client/src/draw.c b/client/src/draw.c index 86f4f59..2c91c4f 100644 --- a/client/src/draw.c +++ b/client/src/draw.c @@ -153,7 +153,12 @@ VkResult draw_frame( } uint32_t image_index; - VK_RESULT(vkAcquireNextImageKHR(context->device, context->swapchain, UINT64_MAX, frame->image, VK_NULL_HANDLE, &image_index)); + result = vkAcquireNextImageKHR(context->device, context->swapchain, UINT64_MAX, frame->image, VK_NULL_HANDLE, &image_index); + if(result == VK_ERROR_OUT_OF_DATE_KHR) { + VK_RESULT(recreate_framebuffer(context)); + } else if(result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) { + return result; + } VkCommandBuffer command_buffer = context->swapchain_command_buffers[image_index]; VK_RESULT(vkResetCommandBuffer(command_buffer, 0)); @@ -227,7 +232,12 @@ VkResult draw_frame( .pResults = 0, }; - VK_RESULT(vkQueuePresentKHR(context->present_queue.handle, &present_info)); + result = vkQueuePresentKHR(context->present_queue.handle, &present_info); + if(result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR) { + VK_RESULT(recreate_framebuffer(context)); + } else if(result != VK_SUCCESS) { + return result; + } context->current_frame = (context->current_frame + 1) % MAX_FRAMES_IN_FLIGHT; diff --git a/client/src/gpu.c b/client/src/gpu.c index b3ab65c..eb14e9c 100644 --- a/client/src/gpu.c +++ b/client/src/gpu.c @@ -52,7 +52,6 @@ GLFWwindow* init_window() { glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); - // TODO: recreate the framebuffer on resize glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); GLFWwindow* window = glfwCreateWindow(WINDOW_MIN_WIDTH, WINDOW_MIN_HEIGHT, "roleplay", 0, 0); @@ -61,7 +60,9 @@ GLFWwindow* init_window() { return window; } -VkShaderModule load_shader_file(const char* path, VkDevice device) { +VkShaderModule load_shader_file( + const char* path, + VkDevice device) { FILE* file; file = fopen(path, "rb"); if(file == 0) { @@ -104,7 +105,9 @@ VkShaderModule load_shader_file(const char* path, VkDevice device) { } -bool check_validation_layers(const char ** layers, uint32_t num_layers) { +bool check_validation_layers( + const char ** layers, + uint32_t num_layers) { uint32_t layer_count; VkResult result; @@ -195,7 +198,9 @@ static VKAPI_ATTR VkBool32 VKAPI_CALL debug_callback( return VK_FALSE; } -VkResult create_debug_messenger(VkInstance instance, VkDebugUtilsMessengerEXT* debug_messenger) { +VkResult create_debug_messenger( + VkInstance instance, + VkDebugUtilsMessengerEXT* debug_messenger) { VkDebugUtilsMessengerCreateInfoEXT messenger_info = { .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT, .messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT, @@ -212,7 +217,9 @@ VkResult create_debug_messenger(VkInstance instance, VkDebugUtilsMessengerEXT* d return VK_SUCCESS; } -VkResult get_best_physical_device(VkInstance instance, VkPhysicalDevice* device) { +VkResult get_best_physical_device( + VkInstance instance, + VkPhysicalDevice* device) { uint32_t device_count = 0; VkResult result; VK_RESULT(vkEnumeratePhysicalDevices(instance, &device_count, 0)); @@ -262,7 +269,13 @@ VkResult get_best_physical_device(VkInstance instance, VkPhysicalDevice* device) return VK_SUCCESS; } -VkResult create_logical_device(VkPhysicalDevice physical_device, VkSurfaceKHR surface, GPUQueue* graphics_queue, GPUQueue* present_queue, GPUQueue* transfer_queue, VkDevice* device) { +VkResult create_logical_device( + VkPhysicalDevice physical_device, + VkSurfaceKHR surface, + GPUQueue* graphics_queue, + GPUQueue* present_queue, + GPUQueue* transfer_queue, + VkDevice* device) { if(graphics_queue == NULL || present_queue == NULL || transfer_queue == NULL || device == NULL) { return VK_ERROR_VALIDATION_FAILED_EXT; } @@ -422,7 +435,11 @@ VkResult create_logical_device(VkPhysicalDevice physical_device, VkSurfaceKHR su return VK_SUCCESS; } -VkResult create_memory_allocator(VkInstance instance, VkPhysicalDevice physical_device, VkDevice device, VmaAllocator* allocator) { +VkResult create_memory_allocator( + VkInstance instance, + VkPhysicalDevice physical_device, + VkDevice device, + VmaAllocator* allocator) { VmaAllocatorCreateInfo allocator_create_info = { .vulkanApiVersion = VK_API_VERSION_1_2, .instance = instance, @@ -437,7 +454,10 @@ VkResult create_memory_allocator(VkInstance instance, VkPhysicalDevice physical_ return VK_SUCCESS; } -VkResult get_swapchain_details(VkPhysicalDevice physical_device, VkSurfaceKHR surface, SwapchainDetails* details) { +VkResult get_swapchain_details( + VkPhysicalDevice physical_device, + VkSurfaceKHR surface, + SwapchainDetails* details) { details->formats = 0; details->present_modes = 0; @@ -495,13 +515,24 @@ VkExtent2D choose_swapchain_extent(SwapchainDetails swapchain_details) { return swapchain_details.capabilities.currentExtent; } -VkResult create_swapchain(VkDevice device, VkSurfaceFormatKHR format, VkPresentModeKHR present_mode, VkExtent2D extent, VkSurfaceKHR surface, VkSurfaceCapabilitiesKHR capabilities, uint32_t graphics_family_index, uint32_t present_family_index, VkSwapchainKHR* swapchain) { +VkResult create_swapchain( + VkDevice device, + VkSurfaceFormatKHR format, + VkPresentModeKHR present_mode, + VkExtent2D extent, + VkSurfaceKHR surface, + VkSurfaceCapabilitiesKHR capabilities, + uint32_t graphics_family_index, + uint32_t present_family_index, + VkSwapchainKHR* swapchain) { uint32_t image_count = capabilities.minImageCount + 1; uint32_t max_images = capabilities.maxImageCount; if((max_images > 0) && (image_count > max_images)) { image_count = max_images; } + VkSwapchainKHR old_swapchain = *swapchain; + VkSwapchainCreateInfoKHR swapchain_info = { .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, .surface = surface, @@ -515,7 +546,7 @@ VkResult create_swapchain(VkDevice device, VkSurfaceFormatKHR format, VkPresentM .compositeAlpha = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR, .presentMode = present_mode, .clipped = VK_TRUE, - .oldSwapchain = *swapchain, + .oldSwapchain = old_swapchain, }; uint32_t queue_families[2] = {graphics_family_index, present_family_index}; @@ -536,7 +567,11 @@ VkResult create_swapchain(VkDevice device, VkSurfaceFormatKHR format, VkPresentM return VK_SUCCESS; } -VkResult get_swapchain_images(VkDevice device, VkSwapchainKHR swapchain, VkImage** images, uint32_t* image_count) { +VkResult get_swapchain_images( + VkDevice device, + VkSwapchainKHR swapchain, + VkImage** images, + uint32_t* image_count) { VkResult result; VK_RESULT(vkGetSwapchainImagesKHR(device, swapchain, image_count, 0)); @@ -554,7 +589,12 @@ VkResult get_swapchain_images(VkDevice device, VkSwapchainKHR swapchain, VkImage return VK_SUCCESS; } -VkResult create_image_views(VkDevice device, uint32_t image_count, VkImage* images, VkSurfaceFormatKHR format, VkImageView** image_views) { +VkResult create_image_views( + VkDevice device, + uint32_t image_count, + VkImage* images, + VkSurfaceFormatKHR format, + VkImageView** image_views) { *image_views = malloc(sizeof(VkImageView)*image_count); if(*image_views == 0) { return VK_ERROR_OUT_OF_HOST_MEMORY; @@ -591,7 +631,11 @@ VkResult create_image_views(VkDevice device, uint32_t image_count, VkImage* imag return VK_SUCCESS; } -VkResult find_depth_format(VkPhysicalDevice physical_device, VkImageTiling tiling, VkFormatFeatureFlags features, VkFormat* format) { +VkResult find_depth_format( + VkPhysicalDevice physical_device, + VkImageTiling tiling, + VkFormatFeatureFlags features, + VkFormat* format) { for(uint32_t i = 0; i < depth_format_count; i++) { VkFormatProperties properties; vkGetPhysicalDeviceFormatProperties(physical_device, depth_formats[i], &properties); @@ -607,7 +651,11 @@ VkResult find_depth_format(VkPhysicalDevice physical_device, VkImageTiling tilin return VK_ERROR_VALIDATION_FAILED_EXT; } -VkResult create_render_pass(VkDevice device, VkSurfaceFormatKHR format, VkFormat depth_format, VkRenderPass* render_pass) { +VkResult create_render_pass( + VkDevice device, + VkSurfaceFormatKHR format, + VkFormat depth_format, + VkRenderPass* render_pass) { VkAttachmentDescription attachments[] = { { .format = format.format, @@ -710,7 +758,14 @@ VkResult create_render_pass(VkDevice device, VkSurfaceFormatKHR format, VkFormat return VK_SUCCESS; } -VkResult create_swapchain_framebuffers(VkDevice device, uint32_t image_count, VkImageView* image_views, VkImageView depth_image_view, VkRenderPass render_pass, VkExtent2D extent, VkFramebuffer** framebuffers) { +VkResult create_swapchain_framebuffers( + VkDevice device, + uint32_t image_count, + VkImageView* image_views, + VkImageView depth_image_view, + VkRenderPass render_pass, + VkExtent2D extent, + VkFramebuffer** framebuffers) { *framebuffers = malloc(sizeof(VkFramebuffer)*image_count); if(*framebuffers == 0) { return 0; @@ -778,7 +833,9 @@ VkSemaphore create_semaphore(VkDevice device) { return semaphore; } -VkFence create_fence(VkDevice device, VkFenceCreateFlags flags) { +VkFence create_fence( + VkDevice device, + VkFenceCreateFlags flags) { VkFenceCreateInfo fence_info = { .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, .flags = flags, @@ -793,7 +850,10 @@ VkFence create_fence(VkDevice device, VkFenceCreateFlags flags) { return fence; } -VkCommandBuffer* create_command_buffers(VkDevice device, VkCommandPool command_pool, uint32_t image_count) { +VkCommandBuffer* create_command_buffers( + VkDevice device, + VkCommandPool command_pool, + uint32_t image_count) { VkCommandBufferAllocateInfo alloc_info = { .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, .commandPool = command_pool, @@ -814,7 +874,11 @@ VkCommandBuffer* create_command_buffers(VkDevice device, VkCommandPool command_p return command_buffers; } -VkResult create_frame_context(VkDevice device, VmaAllocator allocator, VkCommandPool transfer_pool, FrameContext* frame) { +VkResult create_frame_context( + VkDevice device, + VmaAllocator allocator, + VkCommandPool transfer_pool, + FrameContext* frame) { VkResult result; frame->ready = create_fence(device, VK_FENCE_CREATE_SIGNALED_BIT); @@ -852,7 +916,16 @@ VkResult create_frame_context(VkDevice device, VmaAllocator allocator, VkCommand return VK_SUCCESS; } -VkResult create_depth_image(VkDevice device, VkFormat depth_format, VkExtent2D swapchain_extent, VmaAllocator allocator, VkCommandPool extra_graphics_pool, GPUQueue graphics_queue, VkImage* depth_image, VmaAllocation* depth_image_memory, VkImageView* depth_image_view) { +VkResult create_depth_image( + VkDevice device, + VkFormat depth_format, + VkExtent2D swapchain_extent, + VmaAllocator allocator, + VkCommandPool extra_graphics_pool, + GPUQueue graphics_queue, + VkImage* depth_image, + VmaAllocation* depth_image_memory, + VkImageView* depth_image_view) { VkExtent3D depth_extent = { .width = swapchain_extent.width, @@ -956,30 +1029,76 @@ VkResult init_vulkan(GLFWwindow* window, RenderContext* context) { VK_RESULT(create_frame_context(context->device, context->allocator, context->transfer_pool, &context->frame[i])); } - VK_RESULT(get_swapchain_details(context->physical_device, context->surface, &context->swapchain_details)); + VK_RESULT(get_swapchain_details( + context->physical_device, + context->surface, + &context->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); + context->framebuffer_recreated = true; context->swapchain = VK_NULL_HANDLE; - VK_RESULT(create_swapchain(context->device, context->swapchain_format, context->swapchain_present_mode, context->swapchain_extent, context->surface, context->swapchain_details.capabilities, context->graphics_queue.family, context->present_queue.family, &context->swapchain)); - - VK_RESULT(get_swapchain_images(context->device, context->swapchain, &context->swapchain_images, &context->swapchain_image_count)); + VK_RESULT(create_swapchain( + context->device, + context->swapchain_format, + context->swapchain_present_mode, + context->swapchain_extent, + context->surface, + context->swapchain_details.capabilities, + context->graphics_queue.family, + context->present_queue.family, + &context->swapchain)); + + VK_RESULT(get_swapchain_images( + context->device, + context->swapchain, + &context->swapchain_images, + &context->swapchain_image_count)); context->swapchain_command_buffers = create_command_buffers(context->device, context->graphics_pool, context->swapchain_image_count); if(context->swapchain_command_buffers == NULL) { return VK_ERROR_VALIDATION_FAILED_EXT; } - VK_RESULT(create_image_views(context->device, context->swapchain_image_count, context->swapchain_images, context->swapchain_format, &context->swapchain_image_views)); - - VK_RESULT(find_depth_format(context->physical_device, VK_IMAGE_TILING_OPTIMAL, VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT, &context->depth_format)); - - VK_RESULT(create_render_pass(context->device, context->swapchain_format, context->depth_format, &context->render_pass)); - - VK_RESULT(create_depth_image(context->device, context->depth_format, context->swapchain_extent, context->allocator, context->extra_graphics_pool, context->graphics_queue, &context->depth_image, &context->depth_image_memory, &context->depth_image_view)); - - VK_RESULT(create_swapchain_framebuffers(context->device, context->swapchain_image_count, context->swapchain_image_views, context->depth_image_view, context->render_pass, context->swapchain_extent, &context->swapchain_framebuffers)); + VK_RESULT(create_image_views( + context->device, + context->swapchain_image_count, + context->swapchain_images, + context->swapchain_format, + &context->swapchain_image_views)); + + VK_RESULT(find_depth_format( + context->physical_device, + VK_IMAGE_TILING_OPTIMAL, + VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT, + &context->depth_format)); + + VK_RESULT(create_render_pass( + context->device, + context->swapchain_format, + context->depth_format, + &context->render_pass)); + + VK_RESULT(create_depth_image( + context->device, + context->depth_format, + context->swapchain_extent, + context->allocator, + context->extra_graphics_pool, + context->graphics_queue, + &context->depth_image, + &context->depth_image_memory, + &context->depth_image_view)); + + VK_RESULT(create_swapchain_framebuffers( + context->device, + context->swapchain_image_count, + context->swapchain_image_views, + context->depth_image_view, + context->render_pass, + context->swapchain_extent, + &context->swapchain_framebuffers)); context->current_frame = 0; return VK_SUCCESS; @@ -1211,3 +1330,76 @@ VkResult add_transfer( return VK_SUCCESS; } + +VkResult recreate_framebuffer(RenderContext* gpu) { + VkResult result; + + vkDeviceWaitIdle(gpu->device); + + for(uint32_t i = 0; i < gpu->swapchain_image_count; i++) { + vkDestroyFramebuffer(gpu->device, gpu->swapchain_framebuffers[i], NULL); + vkDestroyImageView(gpu->device, gpu->swapchain_image_views[i], NULL); + } + + vkDestroyImageView(gpu->device, gpu->depth_image_view, NULL); + vmaDestroyImage(gpu->allocator, gpu->depth_image, gpu->depth_image_memory); + + free(gpu->swapchain_images); + free(gpu->swapchain_image_views); + free(gpu->swapchain_framebuffers); + + VK_RESULT(get_swapchain_details( + gpu->physical_device, + gpu->surface, + &gpu->swapchain_details)) + gpu->swapchain_format = choose_swapchain_format(gpu->swapchain_details); + gpu->swapchain_present_mode = choose_present_mode(gpu->swapchain_details); + gpu->swapchain_extent = choose_swapchain_extent(gpu->swapchain_details); + VK_RESULT(create_swapchain( + gpu->device, + gpu->swapchain_format, + gpu->swapchain_present_mode, + gpu->swapchain_extent, + gpu->surface, + gpu->swapchain_details.capabilities, + gpu->graphics_queue.family, + gpu->present_queue.family, + &gpu->swapchain)); + + VK_RESULT(get_swapchain_images( + gpu->device, + gpu->swapchain, + &gpu->swapchain_images, + &gpu->swapchain_image_count)); + + VK_RESULT(create_image_views( + gpu->device, + gpu->swapchain_image_count, + gpu->swapchain_images, + gpu->swapchain_format, + &gpu->swapchain_image_views)); + + VK_RESULT(create_depth_image( + gpu->device, + gpu->depth_format, + gpu->swapchain_extent, + gpu->allocator, + gpu->extra_graphics_pool, + gpu->graphics_queue, + &gpu->depth_image, + &gpu->depth_image_memory, + &gpu->depth_image_view)); + + VK_RESULT(create_swapchain_framebuffers( + gpu->device, + gpu->swapchain_image_count, + gpu->swapchain_image_views, + gpu->depth_image_view, + gpu->render_pass, + gpu->swapchain_extent, + &gpu->swapchain_framebuffers)); + + gpu->framebuffer_recreated = true; + + return VK_SUCCESS; +} diff --git a/client/src/main.c b/client/src/main.c index 6d6353a..74ef7f5 100644 --- a/client/src/main.c +++ b/client/src/main.c @@ -136,8 +136,8 @@ VkResult main_thread(ClientContext* context) { GPUString* mapped_string = context->ui.containers[0].layers[0].strings_buffer; char str[51]; - double last_frame_time = 0; int frame = 0; + double last_frame_time = 0; while(glfwWindowShouldClose(context->window) == 0) { double frame_time = glfwGetTime(); double delta_time = (frame_time - last_frame_time); @@ -152,9 +152,12 @@ VkResult main_thread(ClientContext* context) { glfwPollEvents(); - if(context->key_spin[0] != 0 || context->key_spin[1] != 0 || + if((context->key_spin[0] != 0 || context->key_spin[1] != 0 || context->zoom != 0 || - context->cur_spin[0] != 0 || context->cur_spin[1] != 0 || frame == 1) { + context->cur_spin[0] != 0 || context->cur_spin[1] != 0 || + context->render.framebuffer_recreated == true) && frame > 0) { + // signal it as handled + context->render.framebuffer_recreated = false; context->rotation[0] += (float)context->key_spin[0]*delta_time*context->key_spin_speed; context->rotation[0] += (float)context->cur_spin[0]*delta_time*context->cur_spin_speed; @@ -214,7 +217,6 @@ VkResult main_thread(ClientContext* context) { &context->render)); } - frame += 1; // VkResult result = draw_frame(&context->render, &context->ui, &context->hex, frame_time); @@ -222,6 +224,7 @@ VkResult main_thread(ClientContext* context) { fprintf(stderr, "draw_frame error: %s\n", string_VkResult(result)); glfwDestroyWindow(context->window); } + frame += 1; last_frame_time = frame_time; }