diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/main.rs | 773 |
1 files changed, 383 insertions, 390 deletions
diff --git a/src/main.rs b/src/main.rs index f8f44a6..5411bc9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -238,19 +238,13 @@ impl Surreality { enable_validation, enable_portability)?; let permanent = PermanentGraphicsState { - window, - entry, - instance, - debug_messager, - surface, - device, - graphics_queue, - presentation_queue, + window, entry, instance, debug_messager, surface, device, + graphics_queue, presentation_queue, }; if enable_swapchain.0 { - *self.window_dressing.get_mut() = Some(Self::init_window_dressing( - &permanent, physical_device, indices)?); + *self.window_dressing.get_mut() + = Some(WindowDressing::new(&permanent, physical_device, indices)?); } *self.permanent.get_mut() = Some(permanent); @@ -555,10 +549,348 @@ impl Surreality { enable_swapchain)) } - fn init_window_dressing(permanent: &PermanentGraphicsState, - physical_device: vk::PhysicalDevice, - indices: QueueFamilyIndices) - -> Result<WindowDressing> + // To Vulkan, a "physical" device is the actual GPU, and a "logical" + // device is per-process state that represents a connection to the GPU. + // Before we can create a logical device, we must choose which physical + // device to connect it to. + #[allow(unsafe_code)] + fn pick_vulkan_device(instance: &Instance, surface: &vk::SurfaceKHR) + -> Result<(vk::PhysicalDevice, QueueFamilyIndices)> + { + let mut best_device = None; + let mut best_score = None; + let mut best_indices = None; + let mut rejected = BTreeMap::new(); + + for device in unsafe { instance.enumerate_physical_devices() }? { + match Self::score_vulkan_device(instance, surface, &device)? { + Acceptable::Accepted((new_score, new_indices)) => { + if let Some(old_score) = best_score { + if new_score > old_score { + best_device = Some(device); + best_score = Some(new_score); + best_indices = Some(new_indices); + } + } else { + best_device = Some(device); + best_score = Some(new_score); + best_indices = Some(new_indices); + } + } + Acceptable::Rejected(reason) => { + let properties = unsafe { + instance.get_physical_device_properties(device) + }; + + let name = properties.device_name.to_string_lossy().into_owned(); + + rejected.insert(properties.device_id, (name, reason)); + } + } + } + + if let (Some(device), Some(indices)) = (best_device, best_indices) { + Ok((device, indices)) + } else if rejected.is_empty() { + Err(Error { + message: "The system has no GPUs of any kind.".to_string() + }) + } else { + for (_, (name, reason)) in rejected { + eprintln!("Can't run on {} because: {}", name, reason); + } + + Err(Error { + message: "The system has GPUs, but none are acceptable (see above)." + .to_string() + }) + } + } + + // We're doing two tasks: Quantifying how strongly we prefer a device, and + // deciding whether it's acceptable at all. If it's unacceptable, it's + // possible there will be no acceptable devices, and in that case our caller + // will want to print explanations, but otherwise it'll want to be quiet. So + // the outer Result is whether we successfully evaluated the device, and the + // inner Acceptable is whether we approve of it. + // + // In the event that we find the device acceptable, we also return the + // queue family indices we'd be using if we ultimately go with it. While + // this is not strictly necessary, it's better to return them from here + // than to recompute them later on the assumption it'll work out the same. + #[allow(unsafe_code)] + fn score_vulkan_device(instance: &Instance, surface: &vk::SurfaceKHR, + physical_device: &vk::PhysicalDevice) + -> Result<Acceptable<(u64, QueueFamilyIndices)>> + { + // Not all devices support graphics, and not all devices support + // presenting to any given surface. We check whether this one is suitable + // by looking up the indices of the queue families we would use. If we + // ultimately use this device, we'll need these, so we make sure to return + // them. + let indices = match Self::find_device_queue_family_indices( + instance, surface, physical_device)? + { + Acceptable::Rejected(rationale) => { + return Ok(Acceptable::Rejected(rationale)); + } + Acceptable::Accepted(indices) => indices + }; + + // At this point we know the device meets our high-level requirements, + // so it's just a question of scoring. + let properties = unsafe { + instance.get_physical_device_properties(*physical_device) + }; + + let mut score = 0; + if properties.device_type == vk::PhysicalDeviceType::DISCRETE_GPU { + // If the user has a fancy GPU, they prefer it. + score += 128; + } else if properties.device_type + == vk::PhysicalDeviceType::INTEGRATED_GPU + { + // It's still hardware rendering. + score += 96; + } else if properties.device_type == vk::PhysicalDeviceType::VIRTUAL_GPU { + // Whatever it is, the user went to some trouble to set it up. + score += 64; + } else if properties.device_type == vk::PhysicalDeviceType::CPU { + // Software rendering is slow, but at least it's a known quantity. + score += 32; + } + // If it's none of those, we don't have enough information to know if + // that's good or bad, so we assume it's bad. + + // Some of our scoring will depend on what extensions the device + // supports, so we enumerate those. + let mut available_extensions = HashSet::new(); + for extension in unsafe { + instance.enumerate_device_extension_properties(*physical_device, None) + }? { + available_extensions.insert(extension.extension_name); + } + let available_extensions = available_extensions; + + if available_extensions.contains(&vk::KHR_SWAPCHAIN_EXTENSION.name) { + // Double buffering is both quite a nice feature to have, and a good + // indicator that this is a "real" graphics card rather than some + // trivial weird thing. + // + // With that said, however, it only counts if we're able to actually + // use it on the surface we have. Let's find out... + if let Acceptable::Accepted(_) = Self::find_device_swapchain_features( + instance, surface, physical_device)? + { + // We don't count it for enough points to override a device type + // bracket, but it's good for a lot within the bracket. + score += 16; + } + + // This isn't disqualifying, so we don't worry about tracking the + // rationale. We'll deal with that later, if the device actually gets + // selected. + } + + Ok(Acceptable::Accepted((score, indices))) + } + + #[allow(unsafe_code)] + fn find_device_queue_family_indices(instance: &Instance, + surface: &vk::SurfaceKHR, + device: &vk::PhysicalDevice) + -> Result<Acceptable<QueueFamilyIndices>> + { + // We need a queue family that supports graphics drawing commands, and a + // queue family that supports presentation commands. These may or may not + // be the same family. + let mut graphics = None; + let mut presentation = None; + + for (index, queue_family) in (unsafe { + instance.get_physical_device_queue_family_properties(*device) + }).into_iter().enumerate() { + if graphics.is_none() + && queue_family.queue_flags.contains(vk::QueueFlags::GRAPHICS) + { + graphics = Some(index as u32); + } + + if presentation.is_none() && unsafe { + instance.get_physical_device_surface_support_khr( + *device, index as u32, *surface) + }? { + presentation = Some(index as u32); + } + } + + if let Some(graphics) = graphics { + if let Some(presentation) = presentation { + Ok(Acceptable::Accepted(QueueFamilyIndices { + graphics, presentation + })) + } else { + Ok(Acceptable::Rejected( + "Doesn't support presenting to our window.".to_string())) + } + } else { + Ok(Acceptable::Rejected("Doesn't support graphics.".to_string())) + } + } + + // We expect our caller to have already verified that the device supports + // the swapchain extension. + #[allow(unsafe_code)] + fn find_device_swapchain_features(instance: &Instance, + surface: &vk::SurfaceKHR, + physical_device: &vk::PhysicalDevice) + -> Result<Acceptable<(vk::SurfaceCapabilitiesKHR, + Vec<vk::SurfaceFormatKHR>, + Vec<vk::PresentModeKHR>)>> + { + let capabilities = unsafe { + instance.get_physical_device_surface_capabilities_khr( + *physical_device, *surface) + }?; + let formats = unsafe { + instance.get_physical_device_surface_formats_khr( + *physical_device, *surface) + }?; + let presentation_modes = unsafe { + instance.get_physical_device_surface_present_modes_khr( + *physical_device, *surface) + }?; + + if formats.is_empty() { + Ok(Acceptable::Rejected("No matching surface formats.".to_string())) + } else if presentation_modes.is_empty() { + Ok(Acceptable::Rejected("No matching presentation modes.".to_string())) + } else { + Ok(Acceptable::Accepted((capabilities, formats, presentation_modes))) + } + } + + #[allow(unsafe_code)] + fn load_spirv_shader_module(device: &Device, binary: &[u8]) + -> Result<vk::ShaderModule> + { + let bytecode = Bytecode::new(binary)?; + + let module_info = vk::ShaderModuleCreateInfo::builder() + .code(bytecode.code()) + .code_size(bytecode.code_size()); + + let module = unsafe { + device.create_shader_module(&module_info, None) + }?; + + Ok(module) + } + + #[allow(unsafe_code)] + fn render(&mut self, window_id: WindowId) -> Result<()> { + 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 = &permanent.device; + let frame_index = self.frame_index; + let concurrency = &mut window_dressing.concurrency; + let image_available_semaphore + = &concurrency.image_available_semaphores[frame_index]; + let rendering_finished_semaphore + = &concurrency.rendering_finished_semaphores[frame_index]; + let frame_fence = &concurrency.frame_fences[frame_index]; + + unsafe { device.wait_for_fences(&[*frame_fence], true, u64::MAX) }?; + + let image_index = unsafe { + device.acquire_next_image_khr(window_dressing.swapchain.swapchain, + u64::MAX, *image_available_semaphore, + vk::Fence::null()) + }?.0 as usize; + + let image_fence = &concurrency.image_fences[image_index]; + if !image_fence.is_null() { + unsafe { device.wait_for_fences(&[*image_fence], true, u64::MAX) }?; + } + + concurrency.image_fences[image_index] = *frame_fence; + + let first_semaphores = [*image_available_semaphore]; + let second_semaphores = [*rendering_finished_semaphore]; + + let wait_stages = [vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT]; + 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) + .command_buffers(&command_buffers) + .signal_semaphores(&second_semaphores); + unsafe { device.reset_fences(&[*frame_fence]) }?; + unsafe { + device.queue_submit(permanent.graphics_queue, + &[submit_info], + *frame_fence) + }?; + + let swapchains = [window_dressing.swapchain.swapchain]; + let image_indices = [image_index as u32]; + let present_info = vk::PresentInfoKHR::builder() + .wait_semaphores(&second_semaphores) + .swapchains(&swapchains) + .image_indices(&image_indices); + + unsafe { + device.queue_present_khr(permanent.presentation_queue, &present_info) + }?; + + self.frame_index = (frame_index + 1) % N_SIMULTANEOUS_FRAMES; + } + + Ok(()) + } +} + +impl Drop for Surreality { + #[allow(unsafe_code)] + fn drop(&mut self) { + if let Some(permanent) = self.permanent.replace(None) { + unsafe { permanent.device.device_wait_idle() }.unwrap(); + + if let Some(window_dressing) = self.window_dressing.replace(None) { + window_dressing.destroy(&permanent); + } + + let device = permanent.device; + let instance = permanent.instance; + + unsafe { device.destroy_device(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) = permanent.debug_messager { + unsafe { + instance.destroy_debug_utils_messenger_ext(debug_messager, None); + } + } + + unsafe { instance.destroy_instance(None) }; + } + } +} + +impl WindowDressing { + fn new(permanent: &PermanentGraphicsState, + physical_device: vk::PhysicalDevice, + indices: QueueFamilyIndices) + -> Result<Self> { let window = &permanent.window; let instance = &permanent.instance; @@ -568,8 +900,7 @@ impl Surreality { let swapchain = Self::init_swapchain( window, instance, surface, &physical_device, device, &indices)?; - let render_pass = Surreality::init_render_pass(device, - &swapchain.format)?; + let render_pass = Self::init_render_pass(device, &swapchain.format)?; let (pipeline_layout, pipeline) = Self::init_pipeline(device, &swapchain.extent, &render_pass)?; @@ -596,6 +927,39 @@ impl Surreality { } #[allow(unsafe_code)] + fn destroy(self, permanent: &PermanentGraphicsState) { + let device = &permanent.device; + + for semaphore in self.concurrency.image_available_semaphores { + unsafe { device.destroy_semaphore(semaphore, None) }; + } + + for semaphore in self.concurrency.rendering_finished_semaphores { + unsafe { device.destroy_semaphore(semaphore, None) }; + } + + for fence in self.concurrency.frame_fences { + unsafe { device.destroy_fence(fence, None) }; + } + + unsafe { device.destroy_command_pool(self.command_pool, None) }; + + for framebuffer in self.framebuffers { + unsafe { device.destroy_framebuffer(framebuffer, None) }; + } + + 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) }; + + for view in self.swapchain.image_views { + unsafe { device.destroy_image_view(view, None) }; + } + + unsafe { device.destroy_swapchain_khr(self.swapchain.swapchain, None) }; + } + + #[allow(unsafe_code)] fn init_swapchain(window: &Window, instance: &Instance, surface: &vk::SurfaceKHR, physical_device: &vk::PhysicalDevice, device: &Device, @@ -603,7 +967,7 @@ impl Surreality { -> Result<Swapchain> { let (capabilities, formats, presentation_modes) - = Self::find_device_swapchain_features( + = Surreality::find_device_swapchain_features( instance, surface, physical_device)?.require()?; let format = Self::pick_surface_format(&formats)?; @@ -756,9 +1120,9 @@ impl Surreality { concat!(env!("OUT_DIR"), "/shader.frag.spv")); let vertex_module - = Self::load_spirv_shader_module(device, vertex_binary)?; + = Surreality::load_spirv_shader_module(device, vertex_binary)?; let fragment_module - = Self::load_spirv_shader_module(device, fragment_binary)?; + = Surreality::load_spirv_shader_module(device, fragment_binary)?; let vertex_stage_info = vk::PipelineShaderStageCreateInfo::builder() .stage(vk::ShaderStageFlags::VERTEX) @@ -1010,227 +1374,6 @@ impl Surreality { }) } - // To Vulkan, a "physical" device is the actual GPU, and a "logical" - // device is per-process state that represents a connection to the GPU. - // Before we can create a logical device, we must choose which physical - // device to connect it to. - #[allow(unsafe_code)] - fn pick_vulkan_device(instance: &Instance, surface: &vk::SurfaceKHR) - -> Result<(vk::PhysicalDevice, QueueFamilyIndices)> - { - let mut best_device = None; - let mut best_score = None; - let mut best_indices = None; - let mut rejected = BTreeMap::new(); - - for device in unsafe { instance.enumerate_physical_devices() }? { - match Self::score_vulkan_device(instance, surface, &device)? { - Acceptable::Accepted((new_score, new_indices)) => { - if let Some(old_score) = best_score { - if new_score > old_score { - best_device = Some(device); - best_score = Some(new_score); - best_indices = Some(new_indices); - } - } else { - best_device = Some(device); - best_score = Some(new_score); - best_indices = Some(new_indices); - } - } - Acceptable::Rejected(reason) => { - let properties = unsafe { - instance.get_physical_device_properties(device) - }; - - let name = properties.device_name.to_string_lossy().into_owned(); - - rejected.insert(properties.device_id, (name, reason)); - } - } - } - - if let (Some(device), Some(indices)) = (best_device, best_indices) { - Ok((device, indices)) - } else if rejected.is_empty() { - Err(Error { - message: "The system has no GPUs of any kind.".to_string() - }) - } else { - for (_, (name, reason)) in rejected { - eprintln!("Can't run on {} because: {}", name, reason); - } - - Err(Error { - message: "The system has GPUs, but none are acceptable (see above)." - .to_string() - }) - } - } - - // We're doing two tasks: Quantifying how strongly we prefer a device, and - // deciding whether it's acceptable at all. If it's unacceptable, it's - // possible there will be no acceptable devices, and in that case our caller - // will want to print explanations, but otherwise it'll want to be quiet. So - // the outer Result is whether we successfully evaluated the device, and the - // inner Acceptable is whether we approve of it. - // - // In the event that we find the device acceptable, we also return the - // queue family indices we'd be using if we ultimately go with it. While - // this is not strictly necessary, it's better to return them from here - // than to recompute them later on the assumption it'll work out the same. - #[allow(unsafe_code)] - fn score_vulkan_device(instance: &Instance, surface: &vk::SurfaceKHR, - physical_device: &vk::PhysicalDevice) - -> Result<Acceptable<(u64, QueueFamilyIndices)>> - { - // Not all devices support graphics, and not all devices support - // presenting to any given surface. We check whether this one is suitable - // by looking up the indices of the queue families we would use. If we - // ultimately use this device, we'll need these, so we make sure to return - // them. - let indices = match Self::find_device_queue_family_indices( - instance, surface, physical_device)? - { - Acceptable::Rejected(rationale) => { - return Ok(Acceptable::Rejected(rationale)); - } - Acceptable::Accepted(indices) => indices - }; - - // At this point we know the device meets our high-level requirements, - // so it's just a question of scoring. - let properties = unsafe { - instance.get_physical_device_properties(*physical_device) - }; - - let mut score = 0; - if properties.device_type == vk::PhysicalDeviceType::DISCRETE_GPU { - // If the user has a fancy GPU, they prefer it. - score += 128; - } else if properties.device_type - == vk::PhysicalDeviceType::INTEGRATED_GPU - { - // It's still hardware rendering. - score += 96; - } else if properties.device_type == vk::PhysicalDeviceType::VIRTUAL_GPU { - // Whatever it is, the user went to some trouble to set it up. - score += 64; - } else if properties.device_type == vk::PhysicalDeviceType::CPU { - // Software rendering is slow, but at least it's a known quantity. - score += 32; - } - // If it's none of those, we don't have enough information to know if - // that's good or bad, so we assume it's bad. - - // Some of our scoring will depend on what extensions the device - // supports, so we enumerate those. - let mut available_extensions = HashSet::new(); - for extension in unsafe { - instance.enumerate_device_extension_properties(*physical_device, None) - }? { - available_extensions.insert(extension.extension_name); - } - let available_extensions = available_extensions; - - if available_extensions.contains(&vk::KHR_SWAPCHAIN_EXTENSION.name) { - // Double buffering is both quite a nice feature to have, and a good - // indicator that this is a "real" graphics card rather than some - // trivial weird thing. - // - // With that said, however, it only counts if we're able to actually - // use it on the surface we have. Let's find out... - if let Acceptable::Accepted(_) = Self::find_device_swapchain_features( - instance, surface, physical_device)? - { - // We don't count it for enough points to override a device type - // bracket, but it's good for a lot within the bracket. - score += 16; - } - - // This isn't disqualifying, so we don't worry about tracking the - // rationale. We'll deal with that later, if the device actually gets - // selected. - } - - Ok(Acceptable::Accepted((score, indices))) - } - - #[allow(unsafe_code)] - fn find_device_queue_family_indices(instance: &Instance, - surface: &vk::SurfaceKHR, - device: &vk::PhysicalDevice) - -> Result<Acceptable<QueueFamilyIndices>> - { - // We need a queue family that supports graphics drawing commands, and a - // queue family that supports presentation commands. These may or may not - // be the same family. - let mut graphics = None; - let mut presentation = None; - - for (index, queue_family) in (unsafe { - instance.get_physical_device_queue_family_properties(*device) - }).into_iter().enumerate() { - if graphics.is_none() - && queue_family.queue_flags.contains(vk::QueueFlags::GRAPHICS) - { - graphics = Some(index as u32); - } - - if presentation.is_none() && unsafe { - instance.get_physical_device_surface_support_khr( - *device, index as u32, *surface) - }? { - presentation = Some(index as u32); - } - } - - if let Some(graphics) = graphics { - if let Some(presentation) = presentation { - Ok(Acceptable::Accepted(QueueFamilyIndices { - graphics, presentation - })) - } else { - Ok(Acceptable::Rejected( - "Doesn't support presenting to our window.".to_string())) - } - } else { - Ok(Acceptable::Rejected("Doesn't support graphics.".to_string())) - } - } - - // We expect our caller to have already verified that the device supports - // the swapchain extension. - #[allow(unsafe_code)] - fn find_device_swapchain_features(instance: &Instance, - surface: &vk::SurfaceKHR, - physical_device: &vk::PhysicalDevice) - -> Result<Acceptable<(vk::SurfaceCapabilitiesKHR, - Vec<vk::SurfaceFormatKHR>, - Vec<vk::PresentModeKHR>)>> - { - let capabilities = unsafe { - instance.get_physical_device_surface_capabilities_khr( - *physical_device, *surface) - }?; - let formats = unsafe { - instance.get_physical_device_surface_formats_khr( - *physical_device, *surface) - }?; - let presentation_modes = unsafe { - instance.get_physical_device_surface_present_modes_khr( - *physical_device, *surface) - }?; - - if formats.is_empty() { - Ok(Acceptable::Rejected("No matching surface formats.".to_string())) - } else if presentation_modes.is_empty() { - Ok(Acceptable::Rejected("No matching presentation modes.".to_string())) - } else { - Ok(Acceptable::Accepted((capabilities, formats, presentation_modes))) - } - } - fn pick_surface_format(available_formats: &Vec<vk::SurfaceFormatKHR>) -> Result<vk::SurfaceFormatKHR> { @@ -1273,156 +1416,6 @@ impl Surreality { Ok(vk::Extent2D::builder().width(width).height(height).build()) } } - - #[allow(unsafe_code)] - fn load_spirv_shader_module(device: &Device, binary: &[u8]) - -> Result<vk::ShaderModule> - { - let bytecode = Bytecode::new(binary)?; - - let module_info = vk::ShaderModuleCreateInfo::builder() - .code(bytecode.code()) - .code_size(bytecode.code_size()); - - let module = unsafe { - device.create_shader_module(&module_info, None) - }?; - - Ok(module) - } - - #[allow(unsafe_code)] - fn render(&mut self, window_id: WindowId) -> Result<()> { - 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 = &permanent.device; - let frame_index = self.frame_index; - let concurrency = &mut window_dressing.concurrency; - let image_available_semaphore - = &concurrency.image_available_semaphores[frame_index]; - let rendering_finished_semaphore - = &concurrency.rendering_finished_semaphores[frame_index]; - let frame_fence = &concurrency.frame_fences[frame_index]; - - unsafe { device.wait_for_fences(&[*frame_fence], true, u64::MAX) }?; - - let image_index = unsafe { - device.acquire_next_image_khr(window_dressing.swapchain.swapchain, - u64::MAX, *image_available_semaphore, - vk::Fence::null()) - }?.0 as usize; - - let image_fence = &concurrency.image_fences[image_index]; - if !image_fence.is_null() { - unsafe { device.wait_for_fences(&[*image_fence], true, u64::MAX) }?; - } - - concurrency.image_fences[image_index] = *frame_fence; - - let first_semaphores = [*image_available_semaphore]; - let second_semaphores = [*rendering_finished_semaphore]; - - let wait_stages = [vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT]; - 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) - .command_buffers(&command_buffers) - .signal_semaphores(&second_semaphores); - unsafe { device.reset_fences(&[*frame_fence]) }?; - unsafe { - device.queue_submit(permanent.graphics_queue, - &[submit_info], - *frame_fence) - }?; - - let swapchains = [window_dressing.swapchain.swapchain]; - let image_indices = [image_index as u32]; - let present_info = vk::PresentInfoKHR::builder() - .wait_semaphores(&second_semaphores) - .swapchains(&swapchains) - .image_indices(&image_indices); - - unsafe { - device.queue_present_khr(permanent.presentation_queue, &present_info) - }?; - - self.frame_index = (frame_index + 1) % N_SIMULTANEOUS_FRAMES; - } - - Ok(()) - } -} - -impl Drop for Surreality { - #[allow(unsafe_code)] - fn drop(&mut self) { - if let Some(permanent) = self.permanent.replace(None) { - unsafe { permanent.device.device_wait_idle() }.unwrap(); - - if let Some(window_dressing) = self.window_dressing.replace(None) { - window_dressing.destroy(&permanent); - } - - let device = permanent.device; - let instance = permanent.instance; - - unsafe { device.destroy_device(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) = permanent.debug_messager { - unsafe { - instance.destroy_debug_utils_messenger_ext(debug_messager, None); - } - } - - unsafe { instance.destroy_instance(None) }; - } - } -} - -impl WindowDressing { - #[allow(unsafe_code)] - fn destroy(self, permanent: &PermanentGraphicsState) { - let device = &permanent.device; - - for semaphore in self.concurrency.image_available_semaphores { - unsafe { device.destroy_semaphore(semaphore, None) }; - } - - for semaphore in self.concurrency.rendering_finished_semaphores { - unsafe { device.destroy_semaphore(semaphore, None) }; - } - - for fence in self.concurrency.frame_fences { - unsafe { device.destroy_fence(fence, None) }; - } - - unsafe { device.destroy_command_pool(self.command_pool, None) }; - - for framebuffer in self.framebuffers { - unsafe { device.destroy_framebuffer(framebuffer, None) }; - } - - 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) }; - - for view in self.swapchain.image_views { - unsafe { device.destroy_image_view(view, None) }; - } - - unsafe { device.destroy_swapchain_khr(self.swapchain.swapchain, None) }; - } } impl ApplicationHandler for Surreality { |