diff options
| author | Irene Knapp <ireneista@irenes.space> | 2026-07-09 12:22:37 -0700 |
|---|---|---|
| committer | Irene Knapp <ireneista@irenes.space> | 2026-07-09 12:22:37 -0700 |
| commit | 2f24a8f0916f71df2b48e59cea2b4643b88b11fb (patch) | |
| tree | 8823834b0b1afc3abada141095a7093d800df950 /src | |
| parent | 07822896b727b8327045dcb43b2e28cb1b368fea (diff) | |
new Permanent struct
almost everything in Surreality that isn't in WindowDressing is now in Permanent Force-Push: yes Change-Id: I994427668030ed2ebf5f159fa4d5d665ca07b372
Diffstat (limited to 'src')
| -rw-r--r-- | src/main.rs | 114 |
1 files changed, 56 insertions, 58 deletions
diff --git a/src/main.rs b/src/main.rs index 15f38e8..53c8c09 100644 --- a/src/main.rs +++ b/src/main.rs @@ -70,39 +70,53 @@ struct QueueFamilyIndices { struct Surreality { + permanent: RefCell<Option<PermanentGraphicsState>>, + window_dressing: RefCell<Option<WindowDressing>>, + frame_index: usize, +} + +// The PermanentGraphicsState collects the various windowing-system and +// Vulkan objects which never need to be regenerated once they're created. The +// ones which do need that are collected below, in WindowDressing. +struct PermanentGraphicsState { // The "window" is the usual operating-system concept of a window; it's // provided by winit, and may be X11, Wayland, or some more curious thing. // The way we initialize Vulkan requires us to have at least one of these; // we could have more, but for now, we don't. - window: RefCell<Option<Window>>, + window: Window, // The Vulkan "entry" is the part of the Vulkan library ecosystem that's // responsible for finding and loading the other parts. Once we have the // instance, the entry is never directly used again, but we retain it // because doing otherwise would segfault. - entry: RefCell<Option<Entry>>, + #[allow(unused)] + entry: Entry, // The Vulkan "instance" is the bulk of the Vulkan library, with most of // the high-level responsibilities around lifecycle management. - instance: RefCell<Option<Instance>>, + instance: Instance, // The debug messager is a Vulkan object representing our callback which // Vulkan uses to tell us things. // // Vulkan spells "messager" as "messenger", but this is absurd // over-formality and we don't indulge it. - debug_messager: RefCell<Option<vk::DebugUtilsMessengerEXT>>, + // + // Once we've created this, we never actually need to do anything with + // it, but we do need to retain it, so here it is. + debug_messager: Option<vk::DebugUtilsMessengerEXT>, // The Vulkan "surface" is the destination that rendering happens into. - // It is connected to the window but distinct from it. - surface: RefCell<Option<vk::SurfaceKHR>>, + // It is connected to the window but distinct from it. Since we always have + // exactly one window, this is permanent state. + surface: vk::SurfaceKHR, // The Vulkan "device" is the abstraction for a GPU. A physical one is the // actual GPU, and a logical one is our connection to it. We pick a physical // device during initialization, but only the logical one is used later, so // it's all we track. We'll be referencing the logical device a lot, so we // follow Vulkan's lead and let it have a short variable name. - device: RefCell<Option<Device>>, + device: Device, // Vulkan has a first-class concept of command queues. We have two of // them, one for graphics drawing commands and one for presentation. @@ -114,18 +128,15 @@ struct Surreality { // find a family that does both. // // Yes, this means the compiler has to deal with pointer aliasing - // concerns, which have a tendency to defeat optimizations. - graphics_queue: RefCell<Option<vk::Queue>>, - presentation_queue: RefCell<Option<vk::Queue>>, - - window_dressing: RefCell<Option<WindowDressing>>, - - frame_index: usize, + // concerns, which have a tendency to defeat optimizations. Alas. + graphics_queue: vk::Queue, + presentation_queue: vk::Queue, } -// Of the various Vulkan graphics objects, the WindowDressing consists of -// the ones which need to be regenerated or modified when the window changes -// in certain ways, such as resizing. +// The WindowDressing collects the Vulkan graphics objects which need to be +// regenerated or modified when the window changes in certain ways, such as +// resizing. The ones which don't need that are collected above, in +// PermanentGraphicsState. #[derive(Debug)] struct WindowDressing { swapchain: Swapchain, @@ -187,14 +198,7 @@ struct EnableSwapchain(bool); impl Surreality { fn new() -> Self { Surreality { - window: RefCell::new(None), - entry: RefCell::new(None), - instance: RefCell::new(None), - debug_messager: RefCell::new(None), - surface: RefCell::new(None), - device: RefCell::new(None), - graphics_queue: RefCell::new(None), - presentation_queue: RefCell::new(None), + permanent: RefCell::new(None), window_dressing: RefCell::new(None), frame_index: 0, } @@ -267,14 +271,16 @@ impl Surreality { }); } - *self.window.get_mut() = Some(window); - *self.entry.get_mut() = Some(entry); - *self.instance.get_mut() = Some(instance); - *self.debug_messager.get_mut() = debug_messager; - *self.surface.get_mut() = Some(surface); - *self.device.get_mut() = Some(device); - *self.graphics_queue.get_mut() = Some(graphics_queue); - *self.presentation_queue.get_mut() = Some(presentation_queue); + *self.permanent.get_mut() = Some(PermanentGraphicsState { + window, + entry, + instance, + debug_messager, + surface, + device, + graphics_queue, + presentation_queue, + }); Ok(()) } @@ -1274,19 +1280,12 @@ impl Surreality { #[allow(unsafe_code)] fn render(&mut self, window_id: WindowId) -> Result<()> { - if let Some(window) = self.window.borrow().as_ref() - && window_id == window.id() + if let Some(permanent) = self.permanent.borrow().as_ref() + && let Some(window_dressing) + = self.window_dressing.borrow_mut().as_mut() + && window_id == permanent.window.id() { - let device = self.device.borrow(); - let device = device.as_ref().unwrap(); - let graphics_queue = self.graphics_queue.borrow(); - let graphics_queue = graphics_queue.as_ref().unwrap(); - let presentation_queue = self.presentation_queue.borrow(); - let presentation_queue = presentation_queue.as_ref().unwrap(); - let mut window_dressing = self.window_dressing.borrow_mut(); - let window_dressing = window_dressing.as_mut().unwrap(); - let swapchain = &window_dressing.swapchain.swapchain; - let command_buffers = &window_dressing.command_buffers; + let device = &permanent.device; let frame_index = self.frame_index; let concurrency = &mut window_dressing.concurrency; let image_available_semaphore @@ -1298,8 +1297,8 @@ impl Surreality { unsafe { device.wait_for_fences(&[*frame_fence], true, u64::MAX) }?; let image_index = unsafe { - device.acquire_next_image_khr(*swapchain, u64::MAX, - *image_available_semaphore, + device.acquire_next_image_khr(window_dressing.swapchain.swapchain, + u64::MAX, *image_available_semaphore, vk::Fence::null()) }?.0 as usize; @@ -1314,7 +1313,7 @@ impl Surreality { let second_semaphores = [*rendering_finished_semaphore]; let wait_stages = [vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT]; - let command_buffers = [command_buffers[image_index]]; + let command_buffers = [window_dressing.command_buffers[image_index]]; let submit_info = vk::SubmitInfo::builder() .wait_semaphores(&first_semaphores) .wait_dst_stage_mask(&wait_stages) @@ -1322,12 +1321,12 @@ impl Surreality { .signal_semaphores(&second_semaphores); unsafe { device.reset_fences(&[*frame_fence]) }?; unsafe { - device.queue_submit(*graphics_queue, + device.queue_submit(permanent.graphics_queue, &[submit_info], *frame_fence) }?; - let swapchains = [*swapchain]; + let swapchains = [window_dressing.swapchain.swapchain]; let image_indices = [image_index as u32]; let present_info = vk::PresentInfoKHR::builder() .wait_semaphores(&second_semaphores) @@ -1335,7 +1334,7 @@ impl Surreality { .image_indices(&image_indices); unsafe { - device.queue_present_khr(*presentation_queue, &present_info) + device.queue_present_khr(permanent.presentation_queue, &present_info) }?; self.frame_index = (frame_index + 1) % N_SIMULTANEOUS_FRAMES; @@ -1348,7 +1347,10 @@ impl Surreality { impl Drop for Surreality { #[allow(unsafe_code)] fn drop(&mut self) { - if let Some(device) = self.device.replace(None) { + if let Some(permanent) = self.permanent.replace(None) { + let device = permanent.device; + let instance = permanent.instance; + unsafe { device.device_wait_idle() }.unwrap(); if let Some(window_dressing) = self.window_dressing.replace(None) { @@ -1396,19 +1398,15 @@ impl Drop for Surreality { } unsafe { device.destroy_device(None) }; - } - if let Some(instance) = self.instance.replace(None) { - if let Some(surface) = self.surface.replace(None) { - unsafe { instance.destroy_surface_khr(surface, None) }; - } + unsafe { instance.destroy_surface_khr(permanent.surface, None) }; // Everything but the instance itself should already be destroyed, // before we destroy the debug messager. The special hook to get debug // messages while destroying the instance itself only applies to the // instance and the messager, so if we were to destroy anything we // shouldn't after this point, we'd miss out on diagnostics. - if let Some(debug_messager) = self.debug_messager.replace(None) { + if let Some(debug_messager) = permanent.debug_messager { unsafe { instance.destroy_debug_utils_messenger_ext(debug_messager, None); } |