From b4c2198ab70e6cb7113c4173c25024ef2448af92 Mon Sep 17 00:00:00 2001 From: John Wells Date: Sat, 16 Dec 2023 15:46:16 -0500 Subject: [PATCH] Improve swapchain format API --- contrib/screen-13-hot/examples/glsl.rs | 4 +- examples/imgui.rs | 5 +- examples/rt_triangle.rs | 4 +- examples/transitions.rs | 1 + src/event_loop.rs | 68 ++++++++++++++------------ 5 files changed, 47 insertions(+), 35 deletions(-) diff --git a/contrib/screen-13-hot/examples/glsl.rs b/contrib/screen-13-hot/examples/glsl.rs index 56dd5d42..9e844bb1 100644 --- a/contrib/screen-13-hot/examples/glsl.rs +++ b/contrib/screen-13-hot/examples/glsl.rs @@ -13,7 +13,9 @@ lazy_static! { fn main() -> Result<(), DisplayError> { pretty_env_logger::init(); - let event_loop = EventLoop::new().build()?; + let event_loop = EventLoop::new() + .desired_surface_format(|formats| EventLoopBuilder::linear_surface_format(formats).unwrap()) + .build()?; // Create a compute pipeline - the same as normal except for "Hot" prefixes and we provide the // shader source code path instead of the shader source code bytes diff --git a/examples/imgui.rs b/examples/imgui.rs index 9c4cc2e8..d909748e 100644 --- a/examples/imgui.rs +++ b/examples/imgui.rs @@ -9,7 +9,10 @@ fn main() -> Result<(), DisplayError> { pretty_env_logger::init(); // Screen 13 things we need for this demo - let event_loop = EventLoop::new().desired_swapchain_image_count(2).build()?; + let event_loop = EventLoop::new() + .desired_surface_format(|formats| EventLoopBuilder::linear_surface_format(formats).unwrap()) + .desired_swapchain_image_count(2) + .build()?; let display = ComputePresenter::new(&event_loop.device)?; let mut imgui = ImGui::new(&event_loop.device); let mut pool = LazyPool::new(&event_loop.device); diff --git a/examples/rt_triangle.rs b/examples/rt_triangle.rs index e3aa89e3..916556d6 100644 --- a/examples/rt_triangle.rs +++ b/examples/rt_triangle.rs @@ -94,7 +94,9 @@ fn create_ray_trace_pipeline(device: &Arc) -> Result anyhow::Result<()> { pretty_env_logger::init(); - let event_loop = EventLoop::new().build()?; + let event_loop = EventLoop::new() + .desired_surface_format(|formats| EventLoopBuilder::linear_surface_format(formats).unwrap()) + .build()?; let mut pool = HashPool::new(&event_loop.device); // ------------------------------------------------------------------------------------------ // diff --git a/examples/transitions.rs b/examples/transitions.rs index fc9ef935..cde31a14 100644 --- a/examples/transitions.rs +++ b/examples/transitions.rs @@ -12,6 +12,7 @@ fn main() -> anyhow::Result<()> { // Create Screen 13 things any similar program might need let event_loop = EventLoop::new() .window(|builder| builder.with_inner_size(LogicalSize::new(1024.0f64, 768.0f64))) + .desired_surface_format(|formats| EventLoopBuilder::linear_surface_format(formats).unwrap()) .build()?; let display = ComputePresenter::new(&event_loop.device)?; let mut imgui = ImGui::new(&event_loop.device); diff --git a/src/event_loop.rs b/src/event_loop.rs index 96ba08c7..554170f4 100644 --- a/src/event_loop.rs +++ b/src/event_loop.rs @@ -28,7 +28,7 @@ use { }; /// Function type for selection of swapchain surface image format. -pub type SelectSurfaceFormatFn = dyn FnOnce(&[vk::SurfaceFormatKHR]) -> usize; +pub type SelectSurfaceFormatFn = dyn FnOnce(&[vk::SurfaceFormatKHR]) -> vk::SurfaceFormatKHR; /// Describes a screen mode for display. pub enum FullscreenMode { @@ -279,11 +279,13 @@ impl EventLoopBuilder { } /// A function to select the desired swapchain surface image format. - pub fn desired_surface_format( - mut self, - surface_format_fn: impl Into>, - ) -> Self { - let surface_format_fn = surface_format_fn.into(); + /// + /// By default sRGB will be selected unless it is not available. + pub fn desired_surface_format(mut self, surface_format_fn: F) -> Self + where + F: 'static + FnOnce(&[vk::SurfaceFormatKHR]) -> vk::SurfaceFormatKHR, + { + let surface_format_fn = Box::new(surface_format_fn); self.surface_format_fn = Some(surface_format_fn); self } @@ -473,18 +475,14 @@ impl EventLoopBuilder { ); } - let surface_format_fn = self - .surface_format_fn - .unwrap_or_else(|| Box::new(Self::select_swapchain_format)); - let mut surface_format_idx = surface_format_fn(&surface_formats); - - if surface_format_idx >= surface_formats.len() { - warn!("invalid surface format selected"); - - surface_format_idx = 0; - } - - let surface_format = surface_formats[surface_format_idx]; + let surface_format_fn = self.surface_format_fn.unwrap_or_else(|| { + Box::new(|formats| { + Self::srgb_surface_format(formats) + .or_else(|| Self::linear_surface_format(formats)) + .unwrap_or(formats[0]) + }) + }); + let surface_format = surface_format_fn(&surface_formats); let swapchain = Swapchain::new( &device, surface, @@ -507,29 +505,35 @@ impl EventLoopBuilder { }) } - fn select_swapchain_format(formats: &[vk::SurfaceFormatKHR]) -> usize { - for (idx, format) in formats.iter().copied().enumerate() { - if format.color_space != vk::ColorSpaceKHR::SRGB_NONLINEAR { - continue; - } - + /// Helper function to automatically select the best UNORM format. + pub fn linear_surface_format(formats: &[vk::SurfaceFormatKHR]) -> Option { + for swapchain in formats.iter().copied() { if matches!( - format.format, - vk::Format::R8G8B8A8_SRGB | vk::Format::B8G8R8A8_SRGB + swapchain.format, + vk::Format::R8G8B8A8_UNORM | vk::Format::B8G8R8A8_UNORM ) { - return idx; + return Some(swapchain); } } - for (idx, format) in formats.iter().copied().enumerate() { + None + } + + /// Helper function to automatically select the best sRGB format. + pub fn srgb_surface_format(formats: &[vk::SurfaceFormatKHR]) -> Option { + for swapchain in formats.iter().copied() { + if swapchain.color_space != vk::ColorSpaceKHR::SRGB_NONLINEAR { + continue; + } + if matches!( - format.format, - vk::Format::R8G8B8A8_UNORM | vk::Format::B8G8R8A8_UNORM + swapchain.format, + vk::Format::R8G8B8A8_SRGB | vk::Format::B8G8R8A8_SRGB ) { - return idx; + return Some(swapchain); } } - 0 + None } }