From 210a5504abb5b3eeb271d4f81fc36fea24d1369e Mon Sep 17 00:00:00 2001 From: Florian RICHER Date: Sun, 17 Nov 2024 14:07:37 +0100 Subject: [PATCH] Refactor --- Cargo.lock | 36 ++++----- src/display/window.rs | 7 +- src/vulkan/vk_device.rs | 23 ++++-- src/vulkan/vk_instance.rs | 13 ++-- src/vulkan/vk_surface.rs | 20 +++-- src/vulkan/vk_swapchain.rs | 153 ++++++++++++++++++++++++------------- 6 files changed, 162 insertions(+), 90 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6b96949..fe73f51 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -242,9 +242,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.1.36" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baee610e9452a8f6f0a1b6194ec09ff9e2d85dea54432acdae41aa0761c95d70" +checksum = "fd9de9f2205d5ef3fd67e685b0df337994ddd4495e2a28d185500d0e1edfea47" dependencies = [ "jobserver", "libc", @@ -566,9 +566,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.161" +version = "0.2.164" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" +checksum = "433bfe06b8c75da9b2e3fbea6e5329ff87748f0b144ef75306e674c3f6f7c13f" [[package]] name = "libloading" @@ -954,9 +954,9 @@ checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" [[package]] name = "polling" -version = "3.7.3" +version = "3.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc2790cd301dec6cd3b7a025e4815cf825724a51c98dccfe6a3e55f05ffb6511" +checksum = "a604568c3202727d1507653cb121dbd627a58684eb09a820fd746bee38b4442f" dependencies = [ "cfg-if", "concurrent-queue", @@ -1053,9 +1053,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", @@ -1082,9 +1082,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.39" +version = "0.38.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "375116bee2be9ed569afe2154ea6a99dfdffd257f533f187498c2a8f5feaf4ee" +checksum = "99e4ea3e1cdc4b559b8e5650f9c8e5998e3e5c1343b4eaf034565f32318d63c0" dependencies = [ "bitflags 2.6.0", "errno", @@ -1123,18 +1123,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.214" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f55c3193aca71c12ad7890f1785d2b73e1b9f63a0bbc353c08ef26fe03fc56b5" +checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.214" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de523f781f095e28fa605cdce0f8307e451cc0fd14e2eb4cd2e98a355b147766" +checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" dependencies = [ "proc-macro2", "quote", @@ -1215,18 +1215,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.68" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02dd99dc800bbb97186339685293e1cc5d9df1f8fae2d0aecd9ff1c77efea892" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.68" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7c61ec9a6f64d2793d8a45faba21efbe3ced62a886d44c36a009b2b519b4c7e" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", diff --git a/src/display/window.rs b/src/display/window.rs index 0fe7dd3..803fd35 100644 --- a/src/display/window.rs +++ b/src/display/window.rs @@ -1,4 +1,5 @@ use std::ffi::c_char; +use winit::dpi::Pixel; use winit::event_loop::ActiveEventLoop; use winit::raw_window_handle::HasDisplayHandle; @@ -49,8 +50,10 @@ impl Window { self.handle.as_ref() } - pub fn size(&self) -> Option { - self.window_attributes.inner_size + pub fn physical_size(&self) -> Option> { + self.window_attributes + .inner_size + .and_then(|size| Some(size.to_physical::

(1.0))) } pub fn request_redraw(&self) { diff --git a/src/vulkan/vk_device.rs b/src/vulkan/vk_device.rs index cf96d68..1b25e0b 100644 --- a/src/vulkan/vk_device.rs +++ b/src/vulkan/vk_device.rs @@ -7,7 +7,12 @@ pub struct VkDevice { instance: Arc, pub(super) handle: ash::Device, pub(super) swapchain_loader: ash::khr::swapchain::Device, + queue_family_index: u32, + + // Arc not used because vk::Queue is destroyed with Device automatically + // so any references of vk::Queue must be destroyed with VkDevice + queues: Vec, } impl VkDevice { @@ -25,11 +30,11 @@ impl VkDevice { shader_clip_distance: 1, ..Default::default() }; - let priorities = [1.0]; + let queues_priorities = [1.0]; let queue_info = vk::DeviceQueueCreateInfo::default() .queue_family_index(queue_family_index) - .queue_priorities(&priorities); + .queue_priorities(&queues_priorities); let device_create_info = vk::DeviceCreateInfo::default() .queue_create_infos(std::slice::from_ref(&queue_info)) @@ -43,6 +48,12 @@ impl VkDevice { }; log::debug!(target: LOG_TARGET, "Device created ({:?})", device.handle()); + let queues = queues_priorities + .iter() + .enumerate() + .map(|(index, _)| unsafe { device.get_device_queue(queue_family_index, index as u32) }) + .collect::>(); + let swapchain_loader = ash::khr::swapchain::Device::new(&instance.handle, &device); Ok(Self { @@ -50,14 +61,12 @@ impl VkDevice { handle: device, swapchain_loader, queue_family_index, + queues, }) } - pub(super) fn get_device_queue(&self, queue_index: u32) -> vk::Queue { - unsafe { - self.handle - .get_device_queue(self.queue_family_index, queue_index) - } + pub(super) fn get_device_queue(&self, queue_index: u32) -> Option<&vk::Queue> { + self.queues.get(queue_index as usize) } pub(super) fn create_image_view( diff --git a/src/vulkan/vk_instance.rs b/src/vulkan/vk_instance.rs index 59f84e9..4f77f31 100644 --- a/src/vulkan/vk_instance.rs +++ b/src/vulkan/vk_instance.rs @@ -41,14 +41,17 @@ impl VkInstance { } // Layers - let layers = use_layers( - &entry, - LayersSelector::SpecificLayers(vec![ + #[allow(unused)] + let mut layer_selector = LayersSelector::Nothing; + #[cfg(debug_assertions)] + { + layer_selector = LayersSelector::SpecificLayers(vec![ "VK_LAYER_KHRONOS_validation", "VK_LAYER_MANGOHUD_overlay_x86_64", "VK_LAYER_NV_optimus", - ]), - ); + ]); + } + let layers = use_layers(&entry, layer_selector); { let layers = layers diff --git a/src/vulkan/vk_surface.rs b/src/vulkan/vk_surface.rs index 4116353..50e0d8c 100644 --- a/src/vulkan/vk_surface.rs +++ b/src/vulkan/vk_surface.rs @@ -4,6 +4,12 @@ use ash::vk; use std::sync::Arc; use winit::raw_window_handle::{HasDisplayHandle, HasWindowHandle}; +pub struct SwapchainSupportDetails( + pub Vec, + pub vk::SurfaceCapabilitiesKHR, + pub Vec, +); + pub struct VkSurface { instance: Arc, pub(super) surface: vk::SurfaceKHR, @@ -46,14 +52,10 @@ impl VkSurface { } } - pub fn get_physical_device_surface_infos( + pub fn get_physical_device_swapchain_support_details( &self, physical_device: &VkPhysicalDevice, - ) -> VkResult<( - Vec, - vk::SurfaceCapabilitiesKHR, - Vec, - )> { + ) -> VkResult { unsafe { let formats = self .instance @@ -70,7 +72,11 @@ impl VkSurface { .surface_loader .get_physical_device_surface_present_modes(physical_device.handle, self.surface)?; - Ok((formats, capabilities, present_modes)) + Ok(SwapchainSupportDetails( + formats, + capabilities, + present_modes, + )) } } } diff --git a/src/vulkan/vk_swapchain.rs b/src/vulkan/vk_swapchain.rs index c26c62f..6845bf3 100644 --- a/src/vulkan/vk_swapchain.rs +++ b/src/vulkan/vk_swapchain.rs @@ -1,4 +1,5 @@ use crate::display::Window; +use crate::vulkan::vk_surface::SwapchainSupportDetails; use crate::vulkan::{VkDevice, VkPhysicalDevice, VkSurface, LOG_TARGET}; use ash::prelude::VkResult; use ash::vk; @@ -8,10 +9,11 @@ pub struct VkSwapchain { surface: Arc, device: Arc, swapchain: Option, + swapchain_support_details: SwapchainSupportDetails, pub(super) desired_image_count: u32, pub(super) surface_format: vk::SurfaceFormatKHR, - pub(super) surface_resolution: vk::Extent2D, + pub(super) swapchain_extent: vk::Extent2D, pub(super) present_mode: vk::PresentModeKHR, pub(super) pre_transform: vk::SurfaceTransformFlagsKHR, @@ -28,64 +30,42 @@ impl VkSwapchain { ) -> anyhow::Result { log::debug!(target: LOG_TARGET, "Creating swapchain"); - let (surface_formats, surface_capabilities, present_modes) = - surface.get_physical_device_surface_infos(physical_device)?; + let window_size = window + .physical_size::() + .and_then(|size| { + Some(vk::Extent2D { + width: size.width, + height: size.height, + }) + }) + .ok_or_else(|| anyhow::anyhow!("Failed to get swapchain extent"))?; + log::debug!(target: LOG_TARGET, "Window size ({}x{})", window_size.width, window_size.height); + + let swapchain_support_details = + surface.get_physical_device_swapchain_support_details(physical_device)?; + let SwapchainSupportDetails(surface_formats, surface_capabilities, present_modes) = + &swapchain_support_details; log::debug!(target: LOG_TARGET, "Supported surface formats by physical device: {surface_formats:#?}"); log::debug!(target: LOG_TARGET, "Surface capabilities: {surface_capabilities:#?}"); + log::debug!(target: LOG_TARGET, "Present modes: {present_modes:#?}"); - let surface_format = surface_formats - .first() - .and_then(|f| Some(*f)) + let surface_format = Self::choose_surface_format(surface_formats) .ok_or_else(|| anyhow::anyhow!("No available surface formats"))?; - log::debug!(target: LOG_TARGET, "Selected surface format: {surface_format:?}"); - - let mut desired_image_count = surface_capabilities.min_image_count + 1; - if surface_capabilities.max_image_count > 0 - && desired_image_count > surface_capabilities.max_image_count - { - desired_image_count = surface_capabilities.max_image_count; - } - log::debug!(target: LOG_TARGET, "Selected surface image count: {desired_image_count}"); - - let window_size = window - .size() - .ok_or_else(|| anyhow::anyhow!("Window size is not valid"))? - .to_physical::(1.0); - log::debug!(target: LOG_TARGET, "Window size: {window_size:?}"); - - let surface_resolution = match surface_capabilities.current_extent.width { - u32::MAX => vk::Extent2D { - width: window_size.width, - height: window_size.height, - }, - _ => surface_capabilities.current_extent, - }; - log::debug!(target: LOG_TARGET, "Surface resolution: {surface_resolution:?}"); - - let pre_transform = if surface_capabilities - .supported_transforms - .contains(vk::SurfaceTransformFlagsKHR::IDENTITY) - { - vk::SurfaceTransformFlagsKHR::IDENTITY - } else { - surface_capabilities.current_transform - }; - - let present_mode = present_modes - .iter() - .cloned() - .find(|&mode| mode == vk::PresentModeKHR::MAILBOX) - .unwrap_or(vk::PresentModeKHR::FIFO); + let desired_image_count = Self::choose_desired_image_count(surface_capabilities); + let swapchain_extent = Self::choose_swapchain_extent(window_size, surface_capabilities); + let pre_transform = Self::choose_pre_transform(surface_capabilities); + let present_mode = Self::choose_present_mode(present_modes); let mut swapchain = Self { surface, device, + swapchain: None, + swapchain_support_details, desired_image_count, surface_format, - surface_resolution, + swapchain_extent, present_mode, pre_transform, - swapchain: None, present_images: None, present_image_views: None, }; @@ -138,10 +118,22 @@ impl VkSwapchain { } pub(super) fn update_resolution(&mut self, width: u32, height: u32) -> VkResult<()> { - log::debug!(target: LOG_TARGET, "New resolution requested for swapchain {width}x{height}"); - self.surface_resolution = vk::Extent2D { width, height }; + log::debug!(target: LOG_TARGET, "New resolution requested ({width}x{height})"); - self.create_swapchain()?; + let chosen_extent = Self::choose_swapchain_extent( + vk::Extent2D { width, height }, + &self.swapchain_support_details.1, + ); + if chosen_extent.width != self.swapchain_extent.width + || chosen_extent.height != self.swapchain_extent.height + { + self.swapchain_extent = chosen_extent; + log::debug!(target: LOG_TARGET, "New resolution applied ({}x{})", chosen_extent.width, chosen_extent.height); + + self.create_swapchain()?; + } else { + log::debug!(target: LOG_TARGET, "New resolution skipped ({width}x{height}) : Same resolution"); + } Ok(()) } @@ -152,7 +144,7 @@ impl VkSwapchain { .min_image_count(self.desired_image_count) .image_color_space(self.surface_format.color_space) .image_format(self.surface_format.format) - .image_extent(self.surface_resolution) + .image_extent(self.swapchain_extent) .image_usage(vk::ImageUsageFlags::COLOR_ATTACHMENT) .image_sharing_mode(vk::SharingMode::EXCLUSIVE) .pre_transform(self.pre_transform) @@ -161,6 +153,65 @@ impl VkSwapchain { .clipped(true) .image_array_layers(1) } + + fn choose_swapchain_extent( + window_size: vk::Extent2D, + surface_capabilities: &vk::SurfaceCapabilitiesKHR, + ) -> vk::Extent2D { + vk::Extent2D { + width: window_size + .width + .max(surface_capabilities.min_image_extent.width) + .min(surface_capabilities.max_image_extent.width), + height: window_size + .height + .max(surface_capabilities.min_image_extent.height) + .min(surface_capabilities.max_image_extent.height), + } + } + + fn choose_surface_format( + surface_formats: &Vec + ) -> Option { + surface_formats + .first() + .and_then(|f| Some(*f)) + } + + fn choose_desired_image_count( + surface_capabilities: &vk::SurfaceCapabilitiesKHR + ) -> u32 { + let mut desired_image_count = surface_capabilities.min_image_count + 1; + if surface_capabilities.max_image_count > 0 + && desired_image_count > surface_capabilities.max_image_count + { + desired_image_count = surface_capabilities.max_image_count; + } + desired_image_count + } + + fn choose_pre_transform( + surface_capabilities: &vk::SurfaceCapabilitiesKHR + ) -> vk::SurfaceTransformFlagsKHR { + if surface_capabilities + .supported_transforms + .contains(vk::SurfaceTransformFlagsKHR::IDENTITY) + { + vk::SurfaceTransformFlagsKHR::IDENTITY + } else { + surface_capabilities.current_transform + } + } + + fn choose_present_mode( + present_modes: &Vec + ) -> vk::PresentModeKHR { + present_modes + .iter() + .cloned() + .find(|&mode| mode == vk::PresentModeKHR::MAILBOX) + .unwrap_or(vk::PresentModeKHR::FIFO) + } } impl Drop for VkSwapchain {