diff options
| -rw-r--r-- | src/main.c | 7 | ||||
| -rw-r--r-- | src/platform.h | 7 | ||||
| -rw-r--r-- | src/platform_sdl.c | 10 | ||||
| -rw-r--r-- | src/renderer.c | 104 | ||||
| -rw-r--r-- | src/renderer.h | 4 | 
5 files changed, 97 insertions, 35 deletions
@@ -22,12 +22,15 @@ int main(void) {            (event.type == VGLTF_EVENT_KEY_DOWN &&             event.key.key == VGLTF_KEY_ESCAPE)) {          goto out_main_loop; +      } else if (event.type == VGLTF_EVENT_WINDOW_RESIZED) { +        vgltf_renderer_on_window_resized( +            &renderer, +            (struct vgltf_window_size){.width = event.window_resized.width, +                                       .height = event.window_resized.height});        }      }      vgltf_renderer_triangle_pass(&renderer); -    renderer.current_frame = -        (renderer.current_frame + 1) % VGLTF_RENDERER_MAX_FRAME_IN_FLIGHT_COUNT;    }  out_main_loop:    vgltf_renderer_deinit(&renderer); diff --git a/src/platform.h b/src/platform.h index 2f8bc19..fe719d3 100644 --- a/src/platform.h +++ b/src/platform.h @@ -14,6 +14,7 @@  enum vgltf_event_type {    VGLTF_EVENT_QUIT,    VGLTF_EVENT_KEY_DOWN, +  VGLTF_EVENT_WINDOW_RESIZED,    VGLTF_EVENT_UNKNOWN,  }; @@ -52,10 +53,16 @@ struct vgltf_key_event {    enum vgltf_key key;  }; +struct vgltf_window_resized_event { +  int32_t width; +  int32_t height; +}; +  struct vgltf_event {    enum vgltf_event_type type;    union {      struct vgltf_key_event key; +    struct vgltf_window_resized_event window_resized;    };  }; diff --git a/src/platform_sdl.c b/src/platform_sdl.c index 281ccb5..5cc6032 100644 --- a/src/platform_sdl.c +++ b/src/platform_sdl.c @@ -12,8 +12,9 @@ bool vgltf_platform_init(struct vgltf_platform *platform) {    constexpr char WINDOW_TITLE[] = "VisibleGLTF";    constexpr int WINDOW_WIDTH = 800;    constexpr int WINDOW_HEIGHT = 600; -  SDL_Window *window = SDL_CreateWindow(WINDOW_TITLE, WINDOW_WIDTH, -                                        WINDOW_HEIGHT, SDL_WINDOW_VULKAN); +  SDL_Window *window = +      SDL_CreateWindow(WINDOW_TITLE, WINDOW_WIDTH, WINDOW_HEIGHT, +                       SDL_WINDOW_VULKAN | SDL_WINDOW_RESIZABLE);    if (!window) {      VGLTF_LOG_ERR("SDL window creation failed: %s", SDL_GetError());      goto quit_sdl; @@ -105,6 +106,11 @@ bool vgltf_platform_poll_event(struct vgltf_platform *platform,        event->type = VGLTF_EVENT_KEY_DOWN;        event->key.key = vgltf_key_from_sdl_keycode(sdl_event.key.key);        break; +    case SDL_EVENT_WINDOW_RESIZED: +      event->type = VGLTF_EVENT_WINDOW_RESIZED; +      event->window_resized.width = sdl_event.display.data1; +      event->window_resized.height = sdl_event.display.data2; +      break;      default:        event->type = VGLTF_EVENT_UNKNOWN;        break; diff --git a/src/renderer.c b/src/renderer.c index d95cf99..7022af6 100644 --- a/src/renderer.c +++ b/src/renderer.c @@ -734,9 +734,7 @@ choose_swapchain_extent(const VkSurfaceCapabilitiesKHR *capabilities, int width,    }  } -static bool vgltf_renderer_create_swapchain(struct vgltf_renderer *renderer, -                                            int window_width_px, -                                            int window_height_px) { +static bool vgltf_renderer_create_swapchain(struct vgltf_renderer *renderer) {    struct swapchain_support_details swapchain_support_details = {};    swapchain_support_details_query_from_device(        &swapchain_support_details, renderer->physical_device, renderer->surface); @@ -748,9 +746,9 @@ static bool vgltf_renderer_create_swapchain(struct vgltf_renderer *renderer,        swapchain_support_details.present_modes,        swapchain_support_details.present_mode_count); -  VkExtent2D extent = -      choose_swapchain_extent(&swapchain_support_details.capabilities, -                              window_width_px, window_height_px); +  VkExtent2D extent = choose_swapchain_extent( +      &swapchain_support_details.capabilities, renderer->window_size.width, +      renderer->window_size.height);    uint32_t image_count =        swapchain_support_details.capabilities.minImageCount + 1;    if (swapchain_support_details.capabilities.maxImageCount > 0 && @@ -1181,18 +1179,59 @@ err:    return false;  } +static void vgltf_renderer_cleanup_swapchain(struct vgltf_renderer *renderer) { +  for (uint32_t framebuffer_index = 0; +       framebuffer_index < renderer->swapchain_image_count; +       framebuffer_index++) { +    vkDestroyFramebuffer(renderer->device, +                         renderer->swapchain_framebuffers[framebuffer_index], +                         nullptr); +  } + +  for (uint32_t image_view_index = 0; +       image_view_index < renderer->swapchain_image_count; image_view_index++) { +    vkDestroyImageView(renderer->device, +                       renderer->swapchain_image_views[image_view_index], +                       nullptr); +  } + +  vkDestroySwapchainKHR(renderer->device, renderer->swapchain, nullptr); +} + +static bool vgltf_renderer_recreate_swapchain(struct vgltf_renderer *renderer) { +  vkDeviceWaitIdle(renderer->device); +  vgltf_renderer_cleanup_swapchain(renderer); + +  // TODO add error handling +  vgltf_renderer_create_swapchain(renderer); +  vgltf_renderer_create_image_views(renderer); +  vgltf_renderer_create_framebuffers(renderer); +  return true; +} +  bool vgltf_renderer_triangle_pass(struct vgltf_renderer *renderer) {    vkWaitForFences(renderer->device, 1,                    &renderer->in_flight_fences[renderer->current_frame], VK_TRUE,                    UINT64_MAX); -  vkResetFences(renderer->device, 1, -                &renderer->in_flight_fences[renderer->current_frame]);    uint32_t image_index; -  vkAcquireNextImageKHR( +  VkResult acquire_swapchain_image_result = vkAcquireNextImageKHR(        renderer->device, renderer->swapchain, UINT64_MAX,        renderer->image_available_semaphores[renderer->current_frame],        VK_NULL_HANDLE, &image_index); +  if (acquire_swapchain_image_result == VK_ERROR_OUT_OF_DATE_KHR || +      acquire_swapchain_image_result == VK_SUBOPTIMAL_KHR || +      renderer->framebuffer_resized) { +    renderer->framebuffer_resized = false; +    vgltf_renderer_recreate_swapchain(renderer); +    return true; +  } else if (acquire_swapchain_image_result != VK_SUCCESS) { +    VGLTF_LOG_ERR("Failed to acquire a swapchain image"); +    goto err; +  } + +  vkResetFences(renderer->device, 1, +                &renderer->in_flight_fences[renderer->current_frame]);    vkResetCommandBuffer(renderer->command_buffer[renderer->current_frame], 0);    VkCommandBufferBeginInfo begin_info = { @@ -1277,7 +1316,15 @@ bool vgltf_renderer_triangle_pass(struct vgltf_renderer *renderer) {    present_info.swapchainCount = 1;    present_info.pSwapchains = swapchains;    present_info.pImageIndices = &image_index; -  vkQueuePresentKHR(renderer->present_queue, &present_info); +  VkResult result = vkQueuePresentKHR(renderer->present_queue, &present_info); +  if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR) { +    vgltf_renderer_recreate_swapchain(renderer); +  } else if (acquire_swapchain_image_result != VK_SUCCESS) { +    VGLTF_LOG_ERR("Failed to acquire a swapchain image"); +    goto err; +  } +  renderer->current_frame = +      (renderer->current_frame + 1) % VGLTF_RENDERER_MAX_FRAME_IN_FLIGHT_COUNT;    return true;  err:    return false; @@ -1308,9 +1355,9 @@ bool vgltf_renderer_init(struct vgltf_renderer *renderer,      VGLTF_LOG_ERR("Couldn't get window size");      goto destroy_device;    } +  renderer->window_size = window_size; -  if (!vgltf_renderer_create_swapchain(renderer, window_size.width, -                                       window_size.height)) { +  if (!vgltf_renderer_create_swapchain(renderer)) {      VGLTF_LOG_ERR("Couldn't create swapchain");      goto destroy_device;    } @@ -1392,6 +1439,10 @@ err:  }  void vgltf_renderer_deinit(struct vgltf_renderer *renderer) {    vkDeviceWaitIdle(renderer->device); +  vgltf_renderer_cleanup_swapchain(renderer); +  vkDestroyPipeline(renderer->device, renderer->graphics_pipeline, nullptr); +  vkDestroyPipelineLayout(renderer->device, renderer->pipeline_layout, nullptr); +  vkDestroyRenderPass(renderer->device, renderer->render_pass, nullptr);    for (int i = 0; i < VGLTF_RENDERER_MAX_FRAME_IN_FLIGHT_COUNT; i++) {      vkDestroySemaphore(renderer->device,                         renderer->image_available_semaphores[i], nullptr); @@ -1400,29 +1451,20 @@ void vgltf_renderer_deinit(struct vgltf_renderer *renderer) {      vkDestroyFence(renderer->device, renderer->in_flight_fences[i], nullptr);    }    vkDestroyCommandPool(renderer->device, renderer->command_pool, nullptr); -  for (uint32_t swapchain_framebuffer_index = 0; -       swapchain_framebuffer_index < renderer->swapchain_image_count; -       swapchain_framebuffer_index++) { -    vkDestroyFramebuffer( -        renderer->device, -        renderer->swapchain_framebuffers[swapchain_framebuffer_index], nullptr); -  } -  vkDestroyPipeline(renderer->device, renderer->graphics_pipeline, nullptr); -  vkDestroyPipelineLayout(renderer->device, renderer->pipeline_layout, nullptr); -  vkDestroyRenderPass(renderer->device, renderer->render_pass, nullptr); -  for (uint32_t swapchain_image_view_index = 0; -       swapchain_image_view_index < renderer->swapchain_image_count; -       swapchain_image_view_index++) { -    vkDestroyImageView( -        renderer->device, -        renderer->swapchain_image_views[swapchain_image_view_index], nullptr); -  } -  vkDestroySwapchainKHR(renderer->device, renderer->swapchain, nullptr);    vkDestroyDevice(renderer->device, nullptr); -  vkDestroySurfaceKHR(renderer->instance, renderer->surface, nullptr);    if (enable_validation_layers) {      destroy_debug_utils_messenger_ext(renderer->instance,                                        renderer->debug_messenger, nullptr);    } +  vkDestroySurfaceKHR(renderer->instance, renderer->surface, nullptr);    vkDestroyInstance(renderer->instance, nullptr);  } +void vgltf_renderer_on_window_resized(struct vgltf_renderer *renderer, +                                      struct vgltf_window_size size) { +  if (size.width > 0 && size.height > 0 && +      size.width != renderer->window_size.width && +      size.height != renderer->window_size.height) { +    renderer->window_size = size; +    renderer->framebuffer_resized = true; +  } +} diff --git a/src/renderer.h b/src/renderer.h index 17897b6..a0417aa 100644 --- a/src/renderer.h +++ b/src/renderer.h @@ -32,10 +32,14 @@ struct vgltf_renderer {    VkSemaphore        render_finished_semaphores[VGLTF_RENDERER_MAX_FRAME_IN_FLIGHT_COUNT];    VkFence in_flight_fences[VGLTF_RENDERER_MAX_FRAME_IN_FLIGHT_COUNT]; +  struct vgltf_window_size window_size;    uint32_t current_frame; +  bool framebuffer_resized;  };  bool vgltf_renderer_init(struct vgltf_renderer *renderer,                           struct vgltf_platform *platform);  void vgltf_renderer_deinit(struct vgltf_renderer *renderer);  bool vgltf_renderer_triangle_pass(struct vgltf_renderer *renderer); +void vgltf_renderer_on_window_resized(struct vgltf_renderer *renderer, +                                      struct vgltf_window_size size);  #endif // VGLTF_RENDERER_H  | 
