Handle resizing window

This recreates the swap-chain if the window is resized, as mentioned in
"Swap chain recreation".

(Note that the "Drawing: Frames in flight" step in the tutorial was
skipped.)
This commit is contained in:
Stephen Seo 2024-03-14 13:15:12 +09:00
parent e82aa002c4
commit f52c9029bc

View file

@ -1,7 +1,7 @@
mod ffi;
use std::collections::HashSet;
use std::ffi::{CStr, CString};
use std::ffi::{c_void, CStr, CString};
const WINDOW_WIDTH: i32 = 800;
const WINDOW_HEIGHT: i32 = 600;
@ -77,6 +77,13 @@ extern "C" fn validation_debug_callback(
ffi::VK_FALSE
}
extern "C" fn framebuffer_resize_callback(window: *mut ffi::GLFWwindow, _width: i32, _height: i32) {
unsafe {
let app: *mut VulkanApp = ffi::glfwGetWindowUserPointer(window) as *mut VulkanApp;
(*app).set_resize_flag();
}
}
fn create_debug_utils_messenger_ext(
instance: ffi::VkInstance,
create_info: *const ffi::VkDebugUtilsMessengerCreateInfoEXT,
@ -180,6 +187,7 @@ struct VulkanApp {
image_available_semaphore: ffi::VkSemaphore,
render_finished_semaphore: ffi::VkSemaphore,
in_flight_fence: ffi::VkFence,
framebuffer_resized: bool,
}
impl VulkanApp {
@ -207,6 +215,7 @@ impl VulkanApp {
image_available_semaphore: std::ptr::null_mut(),
render_finished_semaphore: std::ptr::null_mut(),
in_flight_fence: std::ptr::null_mut(),
framebuffer_resized: false,
}
}
@ -215,7 +224,7 @@ impl VulkanApp {
unsafe {
ffi::glfwInit();
ffi::glfwWindowHint(ffi::GLFW_CLIENT_API as i32, ffi::GLFW_NO_API as i32);
ffi::glfwWindowHint(ffi::GLFW_RESIZABLE as i32, ffi::GLFW_FALSE as i32);
ffi::glfwWindowHint(ffi::GLFW_RESIZABLE as i32, ffi::GLFW_TRUE as i32);
self.window = ffi::glfwCreateWindow(
WINDOW_WIDTH,
WINDOW_HEIGHT,
@ -226,6 +235,9 @@ impl VulkanApp {
if self.window.is_null() {
panic!("ERROR: Failed to create glfw window!");
}
ffi::glfwSetWindowUserPointer(self.window, self as *mut Self as *mut c_void);
ffi::glfwSetFramebufferSizeCallback(self.window, Some(framebuffer_resize_callback));
}
}
@ -1395,13 +1407,12 @@ impl VulkanApp {
ffi::VK_TRUE,
u64::MAX,
);
ffi::vkResetFences(self.device, 1, std::ptr::addr_of!(self.in_flight_fence));
}
let mut image_index: u32 = 0;
unsafe {
ffi::vkAcquireNextImageKHR(
let result = ffi::vkAcquireNextImageKHR(
self.device,
self.swap_chain,
u64::MAX,
@ -1409,6 +1420,18 @@ impl VulkanApp {
std::ptr::null_mut(),
std::ptr::addr_of_mut!(image_index),
);
if result == ffi::VkResult_VK_ERROR_OUT_OF_DATE_KHR {
// Recreate swapchain.
self.recreate_swap_chain()?;
return Ok(());
} else if result != ffi::VkResult_VK_SUCCESS
&& result != ffi::VkResult_VK_SUBOPTIMAL_KHR
{
return Err(String::from("Failed to acquire swap chain image!"));
}
ffi::vkResetFences(self.device, 1, std::ptr::addr_of!(self.in_flight_fence));
ffi::vkResetCommandBuffer(self.command_buffer, 0);
self.record_command_buffer(self.command_buffer, image_index as usize)?;
}
@ -1454,7 +1477,17 @@ impl VulkanApp {
present_info.pResults = std::ptr::null_mut();
unsafe {
ffi::vkQueuePresentKHR(self.present_queue, std::ptr::addr_of!(present_info));
let result =
ffi::vkQueuePresentKHR(self.present_queue, std::ptr::addr_of!(present_info));
if result == ffi::VkResult_VK_ERROR_OUT_OF_DATE_KHR
|| result == ffi::VkResult_VK_SUBOPTIMAL_KHR
|| self.framebuffer_resized
{
self.framebuffer_resized = false;
self.recreate_swap_chain()?;
} else if result != ffi::VkResult_VK_SUCCESS {
return Err(String::from("Failed to present swap chain image!"));
}
}
Ok(())
@ -1494,10 +1527,55 @@ impl VulkanApp {
Ok(())
}
fn recreate_swap_chain(&mut self) -> Result<(), String> {
unsafe {
ffi::vkDeviceWaitIdle(self.device);
}
self.cleanup_swap_chain()?;
self.create_swap_chain()?;
self.create_image_views()?;
self.create_framebuffers()?;
Ok(())
}
fn cleanup_swap_chain(&mut self) -> Result<(), String> {
for framebuffer in &self.swap_chain_framebuffers {
unsafe {
ffi::vkDestroyFramebuffer(self.device, *framebuffer, std::ptr::null());
}
}
self.swap_chain_framebuffers.clear();
for view in &self.swap_chain_image_views {
unsafe {
ffi::vkDestroyImageView(self.device, *view, std::ptr::null());
}
}
self.swap_chain_image_views.clear();
if !self.swap_chain.is_null() {
unsafe {
ffi::vkDestroySwapchainKHR(self.device, self.swap_chain, std::ptr::null());
}
}
self.swap_chain = std::ptr::null_mut();
Ok(())
}
pub fn set_resize_flag(&mut self) {
self.framebuffer_resized = true;
}
}
impl Drop for VulkanApp {
fn drop(&mut self) {
self.cleanup_swap_chain().unwrap();
if !self.in_flight_fence.is_null() {
unsafe {
ffi::vkDestroyFence(self.device, self.in_flight_fence, std::ptr::null());
@ -1530,12 +1608,6 @@ impl Drop for VulkanApp {
}
}
for framebuffer in &self.swap_chain_framebuffers {
unsafe {
ffi::vkDestroyFramebuffer(self.device, *framebuffer, std::ptr::null());
}
}
if !self.graphics_pipeline.is_null() {
unsafe {
ffi::vkDestroyPipeline(self.device, self.graphics_pipeline, std::ptr::null());
@ -1554,18 +1626,6 @@ impl Drop for VulkanApp {
}
}
for view in &self.swap_chain_image_views {
unsafe {
ffi::vkDestroyImageView(self.device, *view, std::ptr::null());
}
}
if !self.swap_chain.is_null() {
unsafe {
ffi::vkDestroySwapchainKHR(self.device, self.swap_chain, std::ptr::null());
}
}
if !self.device.is_null() {
unsafe {
ffi::vkDestroyDevice(self.device, std::ptr::null());