diff --git a/Cargo.lock b/Cargo.lock index 8cf9d19..0b18fdd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -888,6 +888,7 @@ dependencies = [ "librashader-presets", "librashader-reflect", "librashader-runtime", + "num", "raw-window-handle 0.5.0", "rustc-hash", "spirv_cross", @@ -1114,6 +1115,40 @@ dependencies = [ "nom", ] +[[package]] +name = "num" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43db66d1170d347f9a065114077f7dccb00c1b9478c89384490a3425279a4606" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-complex" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ae39348c8bc5fbd7f40c727a9925f03517afd2ab27d46702108b6a7e5414c19" +dependencies = [ + "num-traits", +] + [[package]] name = "num-integer" version = "0.1.45" @@ -1124,6 +1159,17 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-iter" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + [[package]] name = "num-rational" version = "0.4.1" @@ -1131,6 +1177,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" dependencies = [ "autocfg", + "num-bigint", "num-integer", "num-traits", ] diff --git a/librashader-runtime-vk/Cargo.toml b/librashader-runtime-vk/Cargo.toml index 32aec66..0432e92 100644 --- a/librashader-runtime-vk/Cargo.toml +++ b/librashader-runtime-vk/Cargo.toml @@ -25,6 +25,7 @@ bytemuck = "1.12.3" thiserror = "1.0.37" ash = { version = "0.37.1+1.3.235", features = ["linked", "debug"] } +num = "0.4.0" glfw = "0.47.0" winit = "0.27.5" raw-window-handle = "0.5" diff --git a/librashader-runtime-vk/src/hello_triangle/mod.rs b/librashader-runtime-vk/src/hello_triangle/mod.rs index 9dc234a..2e770d6 100644 --- a/librashader-runtime-vk/src/hello_triangle/mod.rs +++ b/librashader-runtime-vk/src/hello_triangle/mod.rs @@ -2,12 +2,14 @@ pub mod vulkan_base; mod debug; mod physicaldevice; mod surface; +mod swapchain; use winit::event::{Event, VirtualKeyCode, ElementState, KeyboardInput, WindowEvent}; use winit::event_loop::{EventLoop, ControlFlow, EventLoopBuilder}; use winit::platform::windows::EventLoopBuilderExtWindows; -use crate::filter_chain::FilterChainVulkan; +use crate::filter_chain::{FilterChainVulkan, Vulkan}; use crate::hello_triangle::surface::VulkanSurface; +use crate::hello_triangle::swapchain::VulkanSwapchain; use crate::hello_triangle::vulkan_base::VulkanBase; // Constants @@ -60,6 +62,7 @@ impl VulkanWindow { pub struct VulkanDraw { surface: VulkanSurface, base: VulkanBase, + pub swapchain: VulkanSwapchain, } pub fn main(vulkan: VulkanBase, filter_chain: FilterChainVulkan) { @@ -72,8 +75,12 @@ pub fn main(vulkan: VulkanBase, filter_chain: FilterChainVulkan) { let surface = VulkanSurface::new(&vulkan, &window) .unwrap(); + let swapchain = VulkanSwapchain::new(&vulkan, &surface, WINDOW_WIDTH, WINDOW_HEIGHT) + .unwrap(); + let vulkan = VulkanDraw { surface, + swapchain, base: vulkan }; diff --git a/librashader-runtime-vk/src/hello_triangle/surface.rs b/librashader-runtime-vk/src/hello_triangle/surface.rs index 02c9627..8d8bf64 100644 --- a/librashader-runtime-vk/src/hello_triangle/surface.rs +++ b/librashader-runtime-vk/src/hello_triangle/surface.rs @@ -5,8 +5,8 @@ use crate::hello_triangle::vulkan_base::VulkanBase; pub struct VulkanSurface { surface_loader: ash::extensions::khr::Surface, - surface: vk::SurfaceKHR, - present_queue: vk::Queue + pub surface: vk::SurfaceKHR, + pub present_queue: vk::Queue } impl VulkanSurface { @@ -56,5 +56,67 @@ impl VulkanSurface { present_queue }) } + + pub fn choose_format(&self, base: &VulkanBase) -> VkResult { + unsafe { + let available_formats = self.surface_loader.get_physical_device_surface_formats(base.physical_device, self.surface)?; + for available_format in available_formats.iter() { + if available_format.format == vk::Format::B8G8R8A8_SRGB + && available_format.color_space == vk::ColorSpaceKHR::SRGB_NONLINEAR + { + return Ok(available_format.clone()); + } + } + + return Ok(available_formats.first().unwrap().clone()); + } + } + + pub fn choose_present_mode(&self, base: &VulkanBase) -> VkResult { + unsafe { + let available_formats = self.surface_loader.get_physical_device_surface_present_modes(base.physical_device, self.surface)?; + + Ok(if available_formats.contains(&vk::PresentModeKHR::MAILBOX) { + vk::PresentModeKHR::MAILBOX + } else { + vk::PresentModeKHR::FIFO + }) + } + } + + pub fn choose_swapchain_extent(&self, base: &VulkanBase, width: u32, height: u32) -> VkResult { + let capabilities = self.get_capabilities(base)?; + if capabilities.current_extent.width != u32::MAX { + Ok(capabilities.current_extent) + } else { + use num::clamp; + + Ok(vk::Extent2D { + width: clamp( + width, + capabilities.min_image_extent.width, + capabilities.max_image_extent.width, + ), + height: clamp( + height, + capabilities.min_image_extent.height, + capabilities.max_image_extent.height, + ), + }) + } + } + + pub fn get_capabilities(&self, base: &VulkanBase) -> VkResult { + unsafe { + self.surface_loader.get_physical_device_surface_capabilities(base.physical_device, self.surface) + } + } } +impl Drop for VulkanSurface { + fn drop(&mut self) { + unsafe { + self.surface_loader.destroy_surface(self.surface, None); + } + } +} \ No newline at end of file diff --git a/librashader-runtime-vk/src/hello_triangle/swapchain.rs b/librashader-runtime-vk/src/hello_triangle/swapchain.rs new file mode 100644 index 0000000..6959c12 --- /dev/null +++ b/librashader-runtime-vk/src/hello_triangle/swapchain.rs @@ -0,0 +1,108 @@ +use ash::prelude::VkResult; +use ash::vk; +use crate::hello_triangle::surface::VulkanSurface; +use crate::hello_triangle::vulkan_base::VulkanBase; + +pub struct VulkanSwapchain { + pub swapchain: vk::SwapchainKHR, + pub loader: ash::extensions::khr::Swapchain, + format: vk::SurfaceFormatKHR, + extent: vk::Extent2D, + mode: vk::PresentModeKHR, + images: Vec, + image_views: Vec, + device: ash::Device, +} + +impl VulkanSwapchain { + pub fn new(base: &VulkanBase, surface: &VulkanSurface, width: u32, height:u32 ) -> VkResult { + let format = surface.choose_format(base)?; + let mode = surface.choose_present_mode(base)?; + let extent = surface.choose_swapchain_extent(base, width, height)?; + let capabilities = surface.get_capabilities(base)?; + + let image_count = capabilities.min_image_count + 1; + let image_count = if capabilities.max_image_count > 0 { + image_count.min(capabilities.max_image_count) + } else { + image_count + }; + + if base.graphics_queue != surface.present_queue { + panic!("exclusive mode only") + } + + let create_info = vk::SwapchainCreateInfoKHR::builder() + .surface(surface.surface) + .present_mode(mode) + .min_image_count(image_count) + .image_color_space(format.color_space) + .image_format(format.format) + .image_extent(extent) + .image_sharing_mode(vk::SharingMode::EXCLUSIVE) + .pre_transform(capabilities.current_transform) + .composite_alpha(vk::CompositeAlphaFlagsKHR::OPAQUE) + .clipped(true) + .image_array_layers(1) + // todo: switch to IMAGE_USAGE_TRANSFER_DST + .image_usage(vk::ImageUsageFlags::COLOR_ATTACHMENT) + .build(); + + let loader = ash::extensions::khr::Swapchain::new(&base.instance, &base.device); + + let swapchain = unsafe { + loader.create_swapchain(&create_info, None)? + }; + + let images = unsafe { loader.get_swapchain_images(swapchain)? }; + + let image_views: VkResult> = images.iter().map(|image| { + let create_info = vk::ImageViewCreateInfo::builder() + .view_type(vk::ImageViewType::TYPE_2D) + .format(format.format) + .components(vk::ComponentMapping { + r: vk::ComponentSwizzle::IDENTITY, + g: vk::ComponentSwizzle::IDENTITY, + b: vk::ComponentSwizzle::IDENTITY, + a: vk::ComponentSwizzle::IDENTITY, + }) + .subresource_range(vk::ImageSubresourceRange { + aspect_mask: vk::ImageAspectFlags::COLOR, + base_mip_level: 0, + level_count: 1, + base_array_layer: 0, + layer_count: 1, + }) + .image(*image) + .build(); + + + let view = unsafe { + base.device.create_image_view(&create_info, None)? + }; + + Ok(view) + }).collect(); + Ok(VulkanSwapchain { + swapchain, + loader, + format, + extent, + mode, + images, + image_views: image_views?, + device: base.device.clone() + }) + } +} + +impl Drop for VulkanSwapchain { + fn drop(&mut self) { + unsafe { + for view in &self.image_views { + self.device.destroy_image_view(*view, None) + } + self.loader.destroy_swapchain(self.swapchain, None) + } + } +} \ No newline at end of file diff --git a/librashader-runtime-vk/src/hello_triangle/vulkan_base.rs b/librashader-runtime-vk/src/hello_triangle/vulkan_base.rs index 06fdb7e..a4b6966 100644 --- a/librashader-runtime-vk/src/hello_triangle/vulkan_base.rs +++ b/librashader-runtime-vk/src/hello_triangle/vulkan_base.rs @@ -151,7 +151,6 @@ impl Drop for VulkanBase { fn drop(&mut self) { unsafe { self.device.destroy_device(None); - self.instance.destroy_instance(None); } } }