diff options
| author | Irene Knapp <ireneista@irenes.space> | 2026-07-09 17:41:09 -0700 |
|---|---|---|
| committer | Irene Knapp <ireneista@irenes.space> | 2026-07-09 17:41:09 -0700 |
| commit | e547dc5ab4ec1667bcde6368f756f63123eae587 (patch) | |
| tree | 925ce9406b80e8e1567b631f4ef228520b9d34a4 | |
| parent | 05982c6344ec308bcd60fae9457979a20ff18bc8 (diff) | |
okay, reinitializing for window changes works now
yay Force-Push: yes Change-Id: Id8dce4cd4bc696be322fe5b612837e3651437f7e
| -rw-r--r-- | src/graphics_permanent.rs | 17 | ||||
| -rw-r--r-- | src/graphics_window_dressing.rs | 117 | ||||
| -rw-r--r-- | src/main.rs | 74 |
3 files changed, 168 insertions, 40 deletions
diff --git a/src/graphics_permanent.rs b/src/graphics_permanent.rs index d41bbfa..c2225a3 100644 --- a/src/graphics_permanent.rs +++ b/src/graphics_permanent.rs @@ -94,8 +94,7 @@ pub struct EnableSwapchain(pub bool); impl PermanentGraphicsState { #[allow(unsafe_code)] pub fn new(event_loop: &ActiveEventLoop) - -> Result<(Self, vk::PhysicalDevice, QueueFamilyIndices, - EnableSwapchain)> + -> Result<(Self, GraphicsStateForReinit, EnableSwapchain)> { let window = init_window(event_loop)?; @@ -131,7 +130,9 @@ impl PermanentGraphicsState { Ok((PermanentGraphicsState { window, entry, instance, debug_messager, surface, device, graphics_queue, presentation_queue, - }, physical_device, indices, enable_swapchain)) + }, GraphicsStateForReinit { + physical_device, indices + }, enable_swapchain)) } #[allow(unsafe_code)] @@ -206,6 +207,16 @@ impl PermanentGraphicsState { } +// The GraphicsStateForReinit connects Vulkan objects which are only needed +// during the creation of the window-dressing objects. They are used during +// initial startup, and again any time the window-dressing needs to be +// reinitialized. Most notably, they are not needed when rendering. +pub struct GraphicsStateForReinit { + pub physical_device: vk::PhysicalDevice, + pub indices: QueueFamilyIndices, +} + + fn init_window(event_loop: &ActiveEventLoop) -> Result<Window> { // Notice that we do this before having a Vulkan instance. The window is // actually a parameter needed to create the instance; see diff --git a/src/graphics_window_dressing.rs b/src/graphics_window_dressing.rs index e35332f..63fc693 100644 --- a/src/graphics_window_dressing.rs +++ b/src/graphics_window_dressing.rs @@ -1,6 +1,8 @@ #![deny(unsafe_code)] use crate::error::*; -use crate::graphics_permanent::{ PermanentGraphicsState, QueueFamilyIndices }; +use crate::graphics_permanent::{ + PermanentGraphicsState, GraphicsStateForReinit, QueueFamilyIndices +}; use std::collections::BTreeSet; use vulkanalia::{ Device, Instance }; @@ -73,14 +75,15 @@ pub struct Concurrency { impl WindowDressing { pub fn new(permanent: &PermanentGraphicsState, - physical_device: vk::PhysicalDevice, - indices: QueueFamilyIndices) + for_reinit: &GraphicsStateForReinit) -> Result<Self> { let window = &permanent.window; let instance = &permanent.instance; let surface = &permanent.surface; let device = &permanent.device; + let physical_device = &for_reinit.physical_device; + let indices = &for_reinit.indices; let swapchain = init_swapchain( window, instance, surface, &physical_device, device, &indices)?; @@ -93,9 +96,10 @@ impl WindowDressing { let framebuffers = init_framebuffers( device, &swapchain.extent, &swapchain.image_views, &render_pass)?; - let (command_pool, command_buffers) - = init_commands(device, &swapchain.extent, &framebuffers, - &render_pass, &pipeline, &indices)?; + let command_pool = init_command_pool(device, indices)?; + let command_buffers = init_commands(device, &swapchain.extent, + &framebuffers, &render_pass, + &pipeline, &command_pool)?; let concurrency = init_concurrency(device, &swapchain.images)?; @@ -111,9 +115,58 @@ impl WindowDressing { }) } + #[allow(unsafe_code)] - pub fn destroy(self, permanent: &PermanentGraphicsState) { + pub fn reinit(&mut self, permanent: &PermanentGraphicsState, + for_reinit: &GraphicsStateForReinit) + -> Result<()> + { + let window = &permanent.window; + let instance = &permanent.instance; + let surface = &permanent.surface; let device = &permanent.device; + let physical_device = &for_reinit.physical_device; + let indices = &for_reinit.indices; + + unsafe { device.device_wait_idle() }.unwrap(); + + self.destroy_replaceable(device); + + let swapchain = init_swapchain( + window, instance, surface, &physical_device, device, &indices)?; + + let render_pass = init_render_pass(device, &swapchain.format)?; + + let (pipeline_layout, pipeline) + = init_pipeline(device, &swapchain.extent, &render_pass)?; + + let framebuffers = init_framebuffers( + device, &swapchain.extent, &swapchain.image_views, &render_pass)?; + + // Notice that we reused the command pool. + let command_buffers = init_commands( + device, &swapchain.extent, &framebuffers, &render_pass, + &pipeline, &self.command_pool)?; + + self.concurrency.image_fences.resize(swapchain.images.len(), + vk::Fence::null()); + + self.swapchain = swapchain; + self.render_pass = render_pass; + self.pipeline = pipeline; + self.pipeline_layout = pipeline_layout; + self.framebuffers = framebuffers; + self.command_buffers = command_buffers; + + Ok(()) + } + + + // This relies on its caller to have already waited for the device to be + // idle. + #[allow(unsafe_code)] + pub fn destroy(mut self, device: &Device) { + self.destroy_replaceable(device); for semaphore in self.concurrency.image_available_semaphores { unsafe { device.destroy_semaphore(semaphore, None) }; @@ -127,18 +180,28 @@ impl WindowDressing { unsafe { device.destroy_fence(fence, None) }; } + // Notice that destroy_replaceable freed the pool, but did not destroy it. unsafe { device.destroy_command_pool(self.command_pool, None) }; + } - for framebuffer in self.framebuffers { - unsafe { device.destroy_framebuffer(framebuffer, None) }; + + #[allow(unsafe_code)] + fn destroy_replaceable(&mut self, device: &Device) { + for framebuffer in &self.framebuffers { + unsafe { device.destroy_framebuffer(*framebuffer, None) }; } + // Notice that we free the pool, but do not destroy it. + unsafe { + device.free_command_buffers(self.command_pool, &self.command_buffers) + }; + unsafe { device.destroy_pipeline(self.pipeline, None) }; - unsafe { device.destroy_render_pass(self.render_pass, None) }; unsafe { device.destroy_pipeline_layout(self.pipeline_layout, None) }; + unsafe { device.destroy_render_pass(self.render_pass, None) }; - for view in self.swapchain.image_views { - unsafe { device.destroy_image_view(view, None) }; + for view in &self.swapchain.image_views { + unsafe { device.destroy_image_view(*view, None) }; } unsafe { device.destroy_swapchain_khr(self.swapchain.swapchain, None) }; @@ -446,27 +509,31 @@ fn init_framebuffers(device: &Device, extent: &vk::Extent2D, #[allow(unsafe_code)] -fn init_commands(device: &Device, - extent: &vk::Extent2D, - framebuffers: &Vec<vk::Framebuffer>, - render_pass: &vk::RenderPass, - pipeline: &vk::Pipeline, - indices: &QueueFamilyIndices) - -> Result<(vk::CommandPool, Vec<vk::CommandBuffer>)> +fn init_command_pool(device: &Device, indices: &QueueFamilyIndices) + -> Result<vk::CommandPool> { - // We call this one last time. It's kind of a problem. - let command_pool_info = vk::CommandPoolCreateInfo::builder() .flags(vk::CommandPoolCreateFlags::empty()) .queue_family_index(indices.graphics); - let command_pool = unsafe { + Ok(unsafe { device.create_command_pool(&command_pool_info, None) - }?; + }?) +} + +#[allow(unsafe_code)] +fn init_commands(device: &Device, + extent: &vk::Extent2D, + framebuffers: &Vec<vk::Framebuffer>, + render_pass: &vk::RenderPass, + pipeline: &vk::Pipeline, + command_pool: &vk::CommandPool) + -> Result<Vec<vk::CommandBuffer>> +{ let command_buffer_allocation_info = vk::CommandBufferAllocateInfo::builder() - .command_pool(command_pool) + .command_pool(*command_pool) .level(vk::CommandBufferLevel::PRIMARY) .command_buffer_count(framebuffers.len() as u32); let command_buffers = unsafe { @@ -523,7 +590,7 @@ fn init_commands(device: &Device, unsafe { device.end_command_buffer(command_buffer) }?; } - Ok((command_pool, command_buffers)) + Ok(command_buffers) } diff --git a/src/main.rs b/src/main.rs index 5dea456..9beb151 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,8 @@ #![deny(unsafe_code)] use crate::error::*; -use crate::graphics_permanent::PermanentGraphicsState; +use crate::graphics_permanent::{ + PermanentGraphicsState, GraphicsStateForReinit +}; use crate::graphics_window_dressing::{ WindowDressing, N_SIMULTANEOUS_FRAMES }; @@ -20,7 +22,9 @@ mod graphics_window_dressing; struct Surreality { permanent: RefCell<Option<PermanentGraphicsState>>, + for_reinit: RefCell<Option<GraphicsStateForReinit>>, window_dressing: RefCell<Option<WindowDressing>>, + is_reinit_queued: bool, frame_index: usize, } @@ -28,28 +32,56 @@ impl Surreality { fn new() -> Self { Surreality { permanent: RefCell::new(None), + for_reinit: RefCell::new(None), window_dressing: RefCell::new(None), + is_reinit_queued: false, frame_index: 0, } } #[allow(unsafe_code)] fn init(&mut self, event_loop: &ActiveEventLoop) -> Result<()> { - let (permanent, physical_device, indices, enable_swapchain) - = PermanentGraphicsState::new(event_loop)?; + let (permanent, for_reinit, enable_swapchain) + = PermanentGraphicsState::new(event_loop)?; if enable_swapchain.0 { *self.window_dressing.get_mut() - = Some(WindowDressing::new(&permanent, physical_device, indices)?); + = Some(WindowDressing::new(&permanent, &for_reinit)?); } *self.permanent.get_mut() = Some(permanent); + *self.for_reinit.get_mut() = Some(for_reinit); + + Ok(()) + } + + fn reinit(&mut self) -> Result<()> { + if let Some(permanent) = self.permanent.borrow().as_ref() + && let Some(for_reinit) = self.for_reinit.borrow().as_ref() + && let Some(window_dressing) + = self.window_dressing.borrow_mut().as_mut() + { + window_dressing.reinit(permanent, for_reinit)?; + } + + Ok(()) + } + + + fn do_frame(&mut self, window_id: WindowId) -> Result<()> { + if self.render(window_id)? || self.is_reinit_queued { + self.is_reinit_queued = false; + + self.reinit()?; + } Ok(()) } + // This returns true if, and only if, the window dressing should be + // reinitialized. #[allow(unsafe_code)] - fn render(&mut self, window_id: WindowId) -> Result<()> { + fn render(&mut self, window_id: WindowId) -> Result<bool> { if let Some(permanent) = self.permanent.borrow().as_ref() && let Some(window_dressing) = self.window_dressing.borrow_mut().as_mut() @@ -66,11 +98,15 @@ impl Surreality { unsafe { device.wait_for_fences(&[*frame_fence], true, u64::MAX) }?; - let image_index = unsafe { + let image_index = match unsafe { device.acquire_next_image_khr(window_dressing.swapchain.swapchain, u64::MAX, *image_available_semaphore, vk::Fence::null()) - }?.0 as usize; + } { + Ok((image_index, _)) => image_index as usize, + Err(vk::ErrorCode::OUT_OF_DATE_KHR) => return Ok(true), + Err(e) => return Err(Error::from(e)), + }; let image_fence = &concurrency.image_fences[image_index]; if !image_fence.is_null() { @@ -103,14 +139,19 @@ impl Surreality { .swapchains(&swapchains) .image_indices(&image_indices); - unsafe { + match unsafe { device.queue_present_khr(permanent.presentation_queue, &present_info) - }?; + } { + Ok(vk::SuccessCode::SUBOPTIMAL_KHR) => return Ok(true), + Err(vk::ErrorCode::OUT_OF_DATE_KHR) => return Ok(true), + Err(e) => return Err(Error::from(e)), + Ok(_) => (), + } self.frame_index = (frame_index + 1) % N_SIMULTANEOUS_FRAMES; } - Ok(()) + Ok(false) } } @@ -121,7 +162,7 @@ impl Drop for Surreality { unsafe { permanent.device.device_wait_idle() }.unwrap(); if let Some(window_dressing) = self.window_dressing.replace(None) { - window_dressing.destroy(&permanent); + window_dressing.destroy(&permanent.device); } permanent.destroy(); @@ -145,14 +186,23 @@ impl ApplicationHandler for Surreality { match event { WindowEvent::RedrawRequested => { if !event_loop.exiting() { - if let Err(e) = self.render(window_id) { + if let Err(e) = self.do_frame(window_id) { eprintln!("Error: {}", e); } } } + WindowEvent::CloseRequested => { event_loop.exit(); } + + WindowEvent::Resized(_) => { + self.is_reinit_queued = true; + if let Err(e) = self.do_frame(window_id) { + eprintln!("Error: {}", e); + } + } + _ => { } } } |