diff --git a/src/display/window.rs b/src/display/window.rs index 98976f9..e6cf12f 100644 --- a/src/display/window.rs +++ b/src/display/window.rs @@ -35,6 +35,7 @@ impl Window { let mut extension_names = ash_window::enumerate_required_extensions(display_handle.as_raw())? .to_vec(); + // TODO: Move this because is not related to Window extensions #[cfg(any(target_os = "macos", target_os = "ios"))] { extension_names.push(ash::khr::portability_enumeration::NAME.as_ptr()); @@ -48,6 +49,10 @@ impl Window { pub fn handle(&self) -> Option<&winit::window::Window> { self.handle.as_ref() } + + pub fn size(&self) -> Option { + self.window_attributes.inner_size + } pub fn window_event(&mut self, _event_loop: &ActiveEventLoop, _id: WindowId, event: WindowEvent) { match event { diff --git a/src/vulkan/mod.rs b/src/vulkan/mod.rs index 74c1e64..c46ae48 100644 --- a/src/vulkan/mod.rs +++ b/src/vulkan/mod.rs @@ -15,4 +15,7 @@ pub use vk_physical_device::VkPhysicalDevice; pub(self) mod vk_device; pub use vk_device::VkDevice; +pub(self) mod vk_swapchain; +pub use vk_swapchain::VkSwapchain; + mod utils; diff --git a/src/vulkan/vk_device.rs b/src/vulkan/vk_device.rs index af6d0ca..f0fd6ca 100644 --- a/src/vulkan/vk_device.rs +++ b/src/vulkan/vk_device.rs @@ -2,7 +2,7 @@ use ash::vk; use crate::vulkan::{VkInstance, VkPhysicalDevice}; pub struct VkDevice { - handle: ash::Device, + pub(crate) handle: ash::Device, queue_family_index: u32 } diff --git a/src/vulkan/vk_instance.rs b/src/vulkan/vk_instance.rs index f72e681..23b892c 100644 --- a/src/vulkan/vk_instance.rs +++ b/src/vulkan/vk_instance.rs @@ -11,8 +11,8 @@ use std::fmt::{Display, Formatter}; use winit::raw_window_handle::{HasDisplayHandle, HasWindowHandle}; pub struct VkInstance { - entry: Entry, - handle: Instance, + pub(super) entry: Entry, + pub(super) handle: Instance, } impl VkInstance { diff --git a/src/vulkan/vk_render_context.rs b/src/vulkan/vk_render_context.rs index f594402..d7d6541 100644 --- a/src/vulkan/vk_render_context.rs +++ b/src/vulkan/vk_render_context.rs @@ -1,9 +1,11 @@ -use crate::vulkan::{VkDevice, VkInstance, VkPhysicalDevice, VkSurface}; +use crate::vulkan::{VkDevice, VkInstance, VkPhysicalDevice, VkSurface, VkSwapchain}; use ash::vk::QueueFlags; pub struct VkRenderContext { instance: VkInstance, surface: VkSurface, + device: VkDevice, + swapchain: VkSwapchain } impl VkRenderContext { @@ -26,19 +28,20 @@ impl VkRenderContext { let device = VkDevice::new_graphics_device(&instance, &physical_device, queue_family_index) .expect("Unable to create device"); - let present_queue = device.get_device_queue(0); + let swapchain = surface.create_swapchain( + &window, + &instance, + &device, + &physical_device + ).expect("Unable to create swapchain"); - let surface_format = surface.get_physical_device_surface_formats(physical_device) - .unwrap_or_default() - .first() - .expect("Unable to get surface format"); - - let surface_capabilities = surface.get_physical_device_surface_capabilities(physical_device) - .expect("Unable to get surface capabilities"); + // let present_queue = device.get_device_queue(0); Ok(Self { instance, surface, + device, + swapchain }) } } \ No newline at end of file diff --git a/src/vulkan/vk_surface.rs b/src/vulkan/vk_surface.rs index a28ba22..3540999 100644 --- a/src/vulkan/vk_surface.rs +++ b/src/vulkan/vk_surface.rs @@ -1,6 +1,7 @@ -use crate::vulkan::{VkPhysicalDevice, LOG_TARGET}; +use crate::vulkan::{VkDevice, VkInstance, VkPhysicalDevice, VkSwapchain, LOG_TARGET}; use ash::prelude::VkResult; use ash::vk; +use crate::display::Window; pub struct VkSurface { surface_loader: ash::khr::surface::Instance, @@ -54,6 +55,92 @@ impl VkSurface { ) } } + + pub fn create_swapchain( + &self, + window: &Window, + instance: &VkInstance, + device: &VkDevice, + physical_device: &VkPhysicalDevice, + ) -> anyhow::Result { + log::debug!(target: LOG_TARGET, "Creating swapchain"); + + let surface_formats = self.get_physical_device_surface_formats(physical_device)?; + log::debug!(target: LOG_TARGET, "Supported surface formats by physical device: {surface_formats:#?}"); + + let surface_format = surface_formats.first() + .ok_or_else(|| anyhow::anyhow!("No available surface formats"))?; + log::debug!(target: LOG_TARGET, "Selected surface format: {surface_format:?}"); + + let surface_capabilities = self.get_physical_device_surface_capabilities(physical_device)?; + log::debug!(target: LOG_TARGET, "Surface capabilities: {surface_capabilities:#?}"); + + 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_modes = self + .get_physical_device_surface_present_modes(physical_device)?; + + let present_mode = present_modes + .iter() + .cloned() + .find(|&mode| mode == vk::PresentModeKHR::MAILBOX) + .unwrap_or(vk::PresentModeKHR::FIFO); + let swapchain_loader = ash::khr::swapchain::Device::new(&instance.handle, &device.handle); + + let swapchain_create_info = vk::SwapchainCreateInfoKHR::default() + .surface(self.surface) + .min_image_count(desired_image_count) + .image_color_space(surface_format.color_space) + .image_format(surface_format.format) + .image_extent(surface_resolution) + .image_usage(vk::ImageUsageFlags::COLOR_ATTACHMENT) + .image_sharing_mode(vk::SharingMode::EXCLUSIVE) + .pre_transform(pre_transform) + .composite_alpha(vk::CompositeAlphaFlagsKHR::OPAQUE) + .present_mode(present_mode) + .clipped(true) + .image_array_layers(1); + log::debug!(target: LOG_TARGET, "Swapchain info: {swapchain_create_info:#?}"); + + let swapchain = unsafe { + swapchain_loader.create_swapchain(&swapchain_create_info, None)? + }; + log::debug!(target: LOG_TARGET, "Swapchain created"); + + Ok(VkSwapchain::new( + swapchain_loader, + Some(swapchain) + )) + } } impl Drop for VkSurface { diff --git a/src/vulkan/vk_swapchain.rs b/src/vulkan/vk_swapchain.rs new file mode 100644 index 0000000..f0eff16 --- /dev/null +++ b/src/vulkan/vk_swapchain.rs @@ -0,0 +1,28 @@ +use ash::vk; + +pub struct VkSwapchain { + swapchain_loader: ash::khr::swapchain::Device, + swapchain: Option, +} + +impl VkSwapchain { + pub fn new( + swapchain_loader: ash::khr::swapchain::Device, + swapchain: Option, + ) -> Self { + Self { + swapchain_loader, + swapchain + } + } +} + +impl Drop for VkSwapchain { + fn drop(&mut self) { + if let Some(swapchain) = self.swapchain { + unsafe { + self.swapchain_loader.destroy_swapchain(swapchain, None); + } + } + } +} \ No newline at end of file