diff --git a/src/backend/common.rs b/src/backend/common.rs index 9985a85..811b063 100644 --- a/src/backend/common.rs +++ b/src/backend/common.rs @@ -55,11 +55,11 @@ where crate::overlays::screen::get_screens_x11(&app.session)? }; - let mut watch = create_watch::(&app, &screens); + let mut watch = create_watch::(&app, &screens)?; watch.state.want_visible = true; overlays.insert(watch.state.id, watch); - let mut keyboard = create_keyboard(&app); + let mut keyboard = create_keyboard(&app)?; keyboard.state.show_hide = true; keyboard.state.want_visible = false; overlays.insert(keyboard.state.id, keyboard); diff --git a/src/backend/openvr/lines.rs b/src/backend/openvr/lines.rs index 970e448..2158cc1 100644 --- a/src/backend/openvr/lines.rs +++ b/src/backend/openvr/lines.rs @@ -25,26 +25,26 @@ pub(super) struct LinePool { } impl LinePool { - pub fn new(graphics: Arc) -> Self { - let mut command_buffer = graphics.create_command_buffer(CommandBufferUsage::OneTimeSubmit); + pub fn new(graphics: Arc) -> anyhow::Result { + let mut command_buffer = + graphics.create_command_buffer(CommandBufferUsage::OneTimeSubmit)?; let buf = vec![255; 16]; - let texture = command_buffer.texture2d(2, 2, Format::R8G8B8A8_UNORM, &buf); - command_buffer.build_and_execute_now(); + let texture = command_buffer.texture2d(2, 2, Format::R8G8B8A8_UNORM, &buf)?; + command_buffer.build_and_execute_now()?; graphics .transition_layout( texture.clone(), ImageLayout::ShaderReadOnlyOptimal, ImageLayout::TransferSrcOptimal, - ) - .wait(None) - .unwrap(); + )? + .wait(None)?; - let view = ImageView::new_default(texture).unwrap(); + let view = ImageView::new_default(texture)?; - LinePool { + Ok(LinePool { lines: IdMap::new(), view, colors: [ @@ -54,7 +54,7 @@ impl LinePool { Vec4::new(0.375, 0., 0.5, 1.), Vec4::new(1., 0., 0., 1.), ], - } + }) } pub fn allocate(&mut self) -> usize { @@ -140,9 +140,13 @@ impl LinePool { } } - pub fn update(&mut self, overlay: &mut OverlayManager, app: &mut AppState) { + pub fn update( + &mut self, + overlay: &mut OverlayManager, + app: &mut AppState, + ) -> anyhow::Result<()> { for data in self.lines.values_mut() { - data.after_input(overlay, app); + data.after_input(overlay, app)?; if data.state.want_visible { if data.state.dirty { data.upload_texture(overlay, &app.graphics); @@ -153,6 +157,7 @@ impl LinePool { data.upload_color(overlay); } } + Ok(()) } } @@ -161,10 +166,18 @@ struct StaticRenderer { } impl OverlayRenderer for StaticRenderer { - fn init(&mut self, _app: &mut AppState) {} - fn pause(&mut self, _app: &mut AppState) {} - fn resume(&mut self, _app: &mut AppState) {} - fn render(&mut self, _app: &mut AppState) {} + fn init(&mut self, _app: &mut AppState) -> anyhow::Result<()> { + Ok(()) + } + fn pause(&mut self, _app: &mut AppState) -> anyhow::Result<()> { + Ok(()) + } + fn resume(&mut self, _app: &mut AppState) -> anyhow::Result<()> { + Ok(()) + } + fn render(&mut self, _app: &mut AppState) -> anyhow::Result<()> { + Ok(()) + } fn view(&mut self) -> Option> { Some(self.view.clone()) } diff --git a/src/backend/openvr/mod.rs b/src/backend/openvr/mod.rs index adcd5af..2719fde 100644 --- a/src/backend/openvr/mod.rs +++ b/src/backend/openvr/mod.rs @@ -83,7 +83,7 @@ pub fn openvr_run(running: Arc) -> Result<(), BackendError> { }; let mut state = { - let graphics = WlxGraphics::new_openvr(instance_extensions, device_extensions_fn); + let graphics = WlxGraphics::new_openvr(instance_extensions, device_extensions_fn)?; AppState::from_graphics(graphics)? }; @@ -119,7 +119,7 @@ pub fn openvr_run(running: Arc) -> Result<(), BackendError> { let mut next_device_update = Instant::now(); let mut due_tasks = VecDeque::with_capacity(4); - let mut lines = LinePool::new(state.graphics.clone()); + let mut lines = LinePool::new(state.graphics.clone())?; let pointer_lines = [lines.allocate(), lines.allocate()]; 'main_loop: loop { @@ -198,11 +198,11 @@ pub fn openvr_run(running: Arc) -> Result<(), BackendError> { } } - lines.update(&mut overlay_mngr, &mut state); + lines.update(&mut overlay_mngr, &mut state)?; - overlays - .iter_mut() - .for_each(|o| o.after_input(&mut overlay_mngr, &mut state)); + for o in overlays.iter_mut() { + o.after_input(&mut overlay_mngr, &mut state)?; + } #[cfg(feature = "osc")] if let Some(ref mut sender) = osc_sender { @@ -211,10 +211,11 @@ pub fn openvr_run(running: Arc) -> Result<(), BackendError> { log::debug!("Rendering frame"); - overlays - .iter_mut() - .filter(|o| o.state.want_visible) - .for_each(|o| o.render(&mut state)); + for o in overlays.iter_mut() { + if o.state.want_visible { + o.render(&mut state)?; + } + } log::debug!("Rendering overlays"); diff --git a/src/backend/openvr/overlay.rs b/src/backend/openvr/overlay.rs index dd5c40a..d4577a4 100644 --- a/src/backend/openvr/overlay.rs +++ b/src/backend/openvr/overlay.rs @@ -32,7 +32,7 @@ impl OverlayData { &mut self, overlay: &mut OverlayManager, app: &mut AppState, - ) -> OverlayHandle { + ) -> anyhow::Result { let key = format!("wlx-{}", self.state.name); log::debug!("Create overlay with key: {}", &key); let handle = match overlay.create_overlay(&key, &key) { @@ -51,7 +51,7 @@ impl OverlayData { self.data.handle = Some(handle); self.data.color = Vec4::ONE; - self.init(app); + self.init(app)?; if self.data.width < f32::EPSILON { self.data.width = 1.0; @@ -63,15 +63,20 @@ impl OverlayData { self.upload_curvature(overlay); self.upload_sort_order(overlay); - handle + Ok(handle) } - pub(super) fn after_input(&mut self, overlay: &mut OverlayManager, app: &mut AppState) { + pub(super) fn after_input( + &mut self, + overlay: &mut OverlayManager, + app: &mut AppState, + ) -> anyhow::Result<()> { if self.state.want_visible && !self.data.visible { - self.show_internal(overlay, app); + self.show_internal(overlay, app)?; } else if !self.state.want_visible && self.data.visible { - self.hide_internal(overlay, app); + self.hide_internal(overlay, app)?; } + Ok(()) } pub(super) fn after_render(&mut self, overlay: &mut OverlayManager, graphics: &WlxGraphics) { @@ -85,29 +90,37 @@ impl OverlayData { } } - fn show_internal(&mut self, overlay: &mut OverlayManager, app: &mut AppState) { + fn show_internal( + &mut self, + overlay: &mut OverlayManager, + app: &mut AppState, + ) -> anyhow::Result<()> { let handle = match self.data.handle { Some(handle) => handle, - None => self.initialize(overlay, app), + None => self.initialize(overlay, app)?, }; log::debug!("{}: show", self.state.name); if let Err(e) = overlay.set_visibility(handle, true) { log::error!("{}: Failed to show overlay: {}", self.state.name, e); } self.data.visible = true; - self.backend.resume(app); + self.backend.resume(app) } - fn hide_internal(&mut self, overlay: &mut OverlayManager, app: &mut AppState) { + fn hide_internal( + &mut self, + overlay: &mut OverlayManager, + app: &mut AppState, + ) -> anyhow::Result<()> { let Some(handle) = self.data.handle else { - return; + return Ok(()); }; log::debug!("{}: hide", self.state.name); if let Err(e) = overlay.set_visibility(handle, false) { log::error!("{}: Failed to hide overlay: {}", self.state.name, e); } self.data.visible = false; - self.backend.pause(app); + self.backend.pause(app) } pub(super) fn upload_alpha(&self, overlay: &mut OverlayManager) { diff --git a/src/backend/openxr/lines.rs b/src/backend/openxr/lines.rs index c457882..c1d4f51 100644 --- a/src/backend/openxr/lines.rs +++ b/src/backend/openxr/lines.rs @@ -31,8 +31,9 @@ pub(super) struct LinePool { } impl LinePool { - pub(super) fn new(graphics: Arc) -> Self { - let mut command_buffer = graphics.create_command_buffer(CommandBufferUsage::OneTimeSubmit); + pub(super) fn new(graphics: Arc) -> anyhow::Result { + let mut command_buffer = + graphics.create_command_buffer(CommandBufferUsage::OneTimeSubmit)?; // TODO customizable colors let colors = [ @@ -43,20 +44,22 @@ impl LinePool { [0xff, 0x00, 0x00, 0xff], ]; - let views = colors + let views: anyhow::Result>> = colors .into_iter() - .map(|color| { - let tex = command_buffer.texture2d(1, 1, Format::R8G8B8A8_UNORM, &color); - ImageView::new_default(tex).unwrap() - }) + .map( + |color| match command_buffer.texture2d(1, 1, Format::R8G8B8A8_UNORM, &color) { + Ok(tex) => ImageView::new_default(tex).map_err(|e| anyhow::anyhow!(e)), + Err(e) => Err(e), + }, + ) .collect(); - command_buffer.build_and_execute_now(); + command_buffer.build_and_execute_now()?; - LinePool { + Ok(LinePool { lines: IdMap::new(), - colors: views, - } + colors: views?, + }) } pub(super) fn allocate( @@ -132,7 +135,7 @@ impl LinePool { &'a mut self, xr: &'a XrState, command_buffer: &mut WlxCommandBuffer, - ) -> Result>, xr::sys::Result> { + ) -> anyhow::Result>> { let mut quads = Vec::new(); for line in self.lines.values_mut() { diff --git a/src/backend/openxr/mod.rs b/src/backend/openxr/mod.rs index b3d846d..a615c33 100644 --- a/src/backend/openxr/mod.rs +++ b/src/backend/openxr/mod.rs @@ -55,12 +55,12 @@ pub fn openxr_run(running: Arc) -> Result<(), BackendError> { log::info!("Using environment blend mode: {:?}", environment_blend_mode); let mut app_state = { - let graphics = WlxGraphics::new_openxr(xr_instance.clone(), system); + let graphics = WlxGraphics::new_openxr(xr_instance.clone(), system)?; AppState::from_graphics(graphics)? }; let mut overlays = OverlayContainer::::new(&mut app_state)?; - let mut lines = LinePool::new(app_state.graphics.clone()); + let mut lines = LinePool::new(app_state.graphics.clone())?; #[cfg(feature = "osc")] let mut osc_sender = @@ -211,9 +211,9 @@ pub fn openxr_run(running: Arc) -> Result<(), BackendError> { watch_fade(&mut app_state, overlays.mut_by_id(watch_id).unwrap()); // want panic - overlays - .iter_mut() - .for_each(|o| o.after_input(&mut app_state)); + for o in overlays.iter_mut() { + o.after_input(&mut app_state)?; + } #[cfg(feature = "osc")] if let Some(ref mut sender) = osc_sender { @@ -260,7 +260,7 @@ pub fn openxr_run(running: Arc) -> Result<(), BackendError> { let mut layers = vec![]; let mut command_buffer = app_state .graphics - .create_command_buffer(CommandBufferUsage::OneTimeSubmit); + .create_command_buffer(CommandBufferUsage::OneTimeSubmit)?; for o in overlays.iter_mut() { if !o.state.want_visible { @@ -268,11 +268,11 @@ pub fn openxr_run(running: Arc) -> Result<(), BackendError> { } if !o.data.init { - o.init(&mut app_state); + o.init(&mut app_state)?; o.data.init = true; } - o.render(&mut app_state); + o.render(&mut app_state)?; let dist_sq = (app_state.input_state.hmd.translation - o.state.transform.translation) .length_squared(); @@ -290,7 +290,7 @@ pub fn openxr_run(running: Arc) -> Result<(), BackendError> { layers.push((0.0, quad)); } - command_buffer.build_and_execute_now(); + command_buffer.build_and_execute_now()?; layers.sort_by(|a, b| b.0.total_cmp(&a.0)); diff --git a/src/backend/openxr/overlay.rs b/src/backend/openxr/overlay.rs index 043ded0..9f207c4 100644 --- a/src/backend/openxr/overlay.rs +++ b/src/backend/openxr/overlay.rs @@ -77,14 +77,15 @@ impl OverlayData { Ok(Some(quad)) } - pub(super) fn after_input(&mut self, app: &mut AppState) { + pub(super) fn after_input(&mut self, app: &mut AppState) -> anyhow::Result<()> { if self.data.last_visible != self.state.want_visible { if self.state.want_visible { - self.backend.resume(app); + self.backend.resume(app)?; } else { - self.backend.pause(app); + self.backend.pause(app)?; } } self.data.last_visible = self.state.want_visible; + Ok(()) } } diff --git a/src/backend/openxr/swapchain.rs b/src/backend/openxr/swapchain.rs index c6ea1ab..0ae1792 100644 --- a/src/backend/openxr/swapchain.rs +++ b/src/backend/openxr/swapchain.rs @@ -1,5 +1,6 @@ use std::sync::Arc; +use anyhow::bail; use ash::vk; use openxr as xr; @@ -30,16 +31,17 @@ pub(super) fn create_swapchain_render_data( mip_count: 1, })?; - let shaders = graphics.shared_shaders.read().unwrap(); + let Ok(shaders) = graphics.shared_shaders.read() else { + bail!("Failed to lock shared shaders for reading"); + }; let pipeline = graphics.create_pipeline_dynamic( - shaders.get("vert_common").unwrap().clone(), - shaders.get("frag_srgb").unwrap().clone(), + shaders.get("vert_common").unwrap().clone(), // want panic + shaders.get("frag_srgb").unwrap().clone(), // want panic graphics.native_format, - ); + )?; let images = swapchain - .enumerate_images() - .unwrap() + .enumerate_images()? .into_iter() .map(|handle| { let vk_image = vk::Image::from_raw(handle); @@ -83,29 +85,29 @@ impl SwapchainRenderData { command_buffer: &mut WlxCommandBuffer, view: Arc, alpha: f32, - ) -> Result, xr::sys::Result> { + ) -> anyhow::Result> { let idx = self.swapchain.acquire_image()? as usize; self.swapchain.wait_image(xr::Duration::INFINITE)?; let render_target = &mut self.images[idx]; - command_buffer.begin_rendering(render_target.clone()); + command_buffer.begin_rendering(render_target.clone())?; let target_extent = render_target.image().extent(); let set0 = self .pipeline - .uniform_sampler(0, view.clone(), Filter::Linear); + .uniform_sampler(0, view.clone(), Filter::Linear)?; - let set1 = self.pipeline.uniform_buffer(1, vec![alpha]); + let set1 = self.pipeline.uniform_buffer(1, vec![alpha])?; let pass = self.pipeline.create_pass( [target_extent[0] as _, target_extent[1] as _], command_buffer.graphics.quad_verts.clone(), command_buffer.graphics.quad_indices.clone(), vec![set0, set1], - ); - command_buffer.run_ref(&pass); - command_buffer.end_rendering(); + )?; + command_buffer.run_ref(&pass)?; + command_buffer.end_rendering()?; self.swapchain.release_image()?; diff --git a/src/backend/overlay.rs b/src/backend/overlay.rs index 451d7db..be74b68 100644 --- a/src/backend/overlay.rs +++ b/src/backend/overlay.rs @@ -6,6 +6,7 @@ use std::{ }, }; +use anyhow::Ok; use glam::{Affine2, Affine3A, Mat3A, Quat, Vec3, Vec3A}; use vulkano::image::view::ImageView; @@ -177,34 +178,35 @@ impl OverlayData where T: Default, { - pub fn init(&mut self, app: &mut AppState) { + pub fn init(&mut self, app: &mut AppState) -> anyhow::Result<()> { self.state.reset(app, true); - self.backend.init(app); + self.backend.init(app) } - pub fn render(&mut self, app: &mut AppState) { - self.backend.render(app); + pub fn render(&mut self, app: &mut AppState) -> anyhow::Result<()> { + self.backend.render(app) } pub fn view(&mut self) -> Option> { self.backend.view() } - pub fn set_visible(&mut self, app: &mut AppState, visible: bool) { + pub fn set_visible(&mut self, app: &mut AppState, visible: bool) -> anyhow::Result<()> { let old_visible = self.state.want_visible; self.state.want_visible = visible; if visible != old_visible { if visible { - self.backend.resume(app); + self.backend.resume(app)?; } else { - self.backend.pause(app); + self.backend.pause(app)?; } } + Ok(()) } } pub trait OverlayRenderer { - fn init(&mut self, app: &mut AppState); - fn pause(&mut self, app: &mut AppState); - fn resume(&mut self, app: &mut AppState); - fn render(&mut self, app: &mut AppState); + fn init(&mut self, app: &mut AppState) -> anyhow::Result<()>; + fn pause(&mut self, app: &mut AppState) -> anyhow::Result<()>; + fn resume(&mut self, app: &mut AppState) -> anyhow::Result<()>; + fn render(&mut self, app: &mut AppState) -> anyhow::Result<()>; fn view(&mut self) -> Option>; fn extent(&self) -> [u32; 3]; } @@ -212,10 +214,18 @@ pub trait OverlayRenderer { pub struct FallbackRenderer; impl OverlayRenderer for FallbackRenderer { - fn init(&mut self, _app: &mut AppState) {} - fn pause(&mut self, _app: &mut AppState) {} - fn resume(&mut self, _app: &mut AppState) {} - fn render(&mut self, _app: &mut AppState) {} + fn init(&mut self, _app: &mut AppState) -> anyhow::Result<()> { + Ok(()) + } + fn pause(&mut self, _app: &mut AppState) -> anyhow::Result<()> { + Ok(()) + } + fn resume(&mut self, _app: &mut AppState) -> anyhow::Result<()> { + Ok(()) + } + fn render(&mut self, _app: &mut AppState) -> anyhow::Result<()> { + Ok(()) + } fn view(&mut self) -> Option> { None } @@ -249,17 +259,17 @@ impl Default for SplitOverlayBackend { impl OverlayBackend for SplitOverlayBackend {} impl OverlayRenderer for SplitOverlayBackend { - fn init(&mut self, app: &mut AppState) { - self.renderer.init(app); + fn init(&mut self, app: &mut AppState) -> anyhow::Result<()> { + self.renderer.init(app) } - fn pause(&mut self, app: &mut AppState) { - self.renderer.pause(app); + fn pause(&mut self, app: &mut AppState) -> anyhow::Result<()> { + self.renderer.pause(app) } - fn resume(&mut self, app: &mut AppState) { - self.renderer.resume(app); + fn resume(&mut self, app: &mut AppState) -> anyhow::Result<()> { + self.renderer.resume(app) } - fn render(&mut self, app: &mut AppState) { - self.renderer.render(app); + fn render(&mut self, app: &mut AppState) -> anyhow::Result<()> { + self.renderer.render(app) } fn view(&mut self) -> Option> { self.renderer.view() diff --git a/src/graphics.rs b/src/graphics.rs index 7b01184..25019cb 100644 --- a/src/graphics.rs +++ b/src/graphics.rs @@ -1,6 +1,5 @@ use std::{ collections::HashMap, - error::Error, io::Cursor, os::{ fd::{FromRawFd, IntoRawFd}, @@ -10,6 +9,7 @@ use std::{ sync::{Arc, OnceLock, RwLock}, }; +use anyhow::{anyhow, bail}; use ash::vk::{self, SubmitInfo}; use smallvec::smallvec; use vulkano::{ @@ -118,7 +118,7 @@ pub struct WlxGraphics { static VULKAN_LIBRARY: OnceLock> = OnceLock::new(); fn get_vulkan_library() -> &'static Arc { - VULKAN_LIBRARY.get_or_init(|| vulkano::VulkanLibrary::new().unwrap()) + VULKAN_LIBRARY.get_or_init(|| vulkano::VulkanLibrary::new().unwrap()) // want panic } #[cfg(feature = "openxr")] @@ -134,15 +134,18 @@ unsafe extern "system" fn get_instance_proc_addr( impl WlxGraphics { #[cfg(feature = "openxr")] - pub fn new_openxr(xr_instance: openxr::Instance, system: openxr::SystemId) -> Arc { + pub fn new_openxr( + xr_instance: openxr::Instance, + system: openxr::SystemId, + ) -> anyhow::Result> { use std::ffi::{self, c_char, CString}; use ash::vk::PhysicalDeviceDynamicRenderingFeatures; use vulkano::{Handle, Version}; use winit::event_loop::EventLoop; - let event_loop = EventLoop::new().unwrap(); - let mut instance_extensions = Surface::required_extensions(&event_loop).unwrap(); + let event_loop = EventLoop::new()?; + let mut instance_extensions = Surface::required_extensions(&event_loop)?; instance_extensions.khr_get_physical_device_properties2 = true; @@ -152,6 +155,7 @@ impl WlxGraphics { .filter_map(|(name, enabled)| { if enabled { Some(ffi::CString::new(name).unwrap().into_raw() as *const c_char) + // want panic } else { None } @@ -198,13 +202,11 @@ impl WlxGraphics { PhysicalDevice::from_handle( instance.clone(), vk::PhysicalDevice::from_raw( - xr_instance - .vulkan_graphics_device(system, instance.handle().as_raw() as _) - .unwrap() as _, + xr_instance.vulkan_graphics_device(system, instance.handle().as_raw() as _)? + as _, ), ) - } - .unwrap(); + }?; let vk_device_properties = physical_device.properties(); if vk_device_properties.api_version < target_version { @@ -241,6 +243,7 @@ impl WlxGraphics { .filter_map(|(name, enabled)| { if enabled { Some(ffi::CString::new(name).unwrap().into_raw() as *const c_char) + // want panic } else { None } @@ -306,7 +309,9 @@ impl WlxGraphics { let _ = CString::from_raw(c_string as _); }); - let queue = queues.next().unwrap(); + let queue = queues + .next() + .ok_or_else(|| anyhow::anyhow!("no GPU queues available"))?; let memory_allocator = memory_allocator(device.clone()); let command_buffer_allocator = Arc::new(StandardCommandBufferAllocator::new( @@ -321,7 +326,7 @@ impl WlxGraphics { Default::default(), )); - let (quad_verts, quad_indices) = Self::default_quad(memory_allocator.clone()); + let (quad_verts, quad_indices) = Self::default_quad(memory_allocator.clone())?; let me = Self { instance, @@ -336,14 +341,14 @@ impl WlxGraphics { shared_shaders: RwLock::new(HashMap::new()), }; - Arc::new(me) + Ok(Arc::new(me)) } #[cfg(feature = "openvr")] pub fn new_openvr( mut vk_instance_extensions: InstanceExtensions, mut vk_device_extensions_fn: impl FnMut(&PhysicalDevice) -> DeviceExtensions, - ) -> Arc { + ) -> anyhow::Result> { //#[cfg(debug_assertions)] //let layers = vec!["VK_LAYER_KHRONOS_validation".to_owned()]; //#[cfg(not(debug_assertions))] @@ -361,8 +366,7 @@ impl WlxGraphics { enabled_layers: layers, ..Default::default() }, - ) - .unwrap(); + )?; let device_extensions = DeviceExtensions { khr_external_memory: true, @@ -375,8 +379,7 @@ impl WlxGraphics { log::debug!("Device exts for app: {:?}", &device_extensions); let (physical_device, my_extensions, queue_family_index) = instance - .enumerate_physical_devices() - .unwrap() + .enumerate_physical_devices()? .filter_map(|p| { let runtime_extensions = vk_device_extensions_fn(&p); log::debug!( @@ -427,10 +430,11 @@ impl WlxGraphics { }], ..Default::default() }, - ) - .unwrap(); + )?; - let queue = queues.next().unwrap(); + let queue = queues + .next() + .ok_or_else(|| anyhow::anyhow!("no GPU queues available"))?; let memory_allocator = memory_allocator(device.clone()); let command_buffer_allocator = Arc::new(StandardCommandBufferAllocator::new( @@ -445,7 +449,7 @@ impl WlxGraphics { Default::default(), )); - let (quad_verts, quad_indices) = Self::default_quad(memory_allocator.clone()); + let (quad_verts, quad_indices) = Self::default_quad(memory_allocator.clone())?; let me = Self { instance, @@ -460,12 +464,12 @@ impl WlxGraphics { shared_shaders: RwLock::new(HashMap::new()), }; - Arc::new(me) + Ok(Arc::new(me)) } fn default_quad( memory_allocator: Arc, - ) -> (Subbuffer<[Vert2Uv]>, Subbuffer<[u16]>) { + ) -> anyhow::Result<(Subbuffer<[Vert2Uv]>, Subbuffer<[u16]>)> { let vertices = [ Vert2Uv { in_pos: [0., 0.], @@ -496,8 +500,7 @@ impl WlxGraphics { ..Default::default() }, vertices.into_iter(), - ) - .unwrap(); + )?; let quad_indices = Buffer::from_iter( memory_allocator, @@ -511,10 +514,9 @@ impl WlxGraphics { ..Default::default() }, INDICES.iter().cloned(), - ) - .unwrap(); + )?; - (quad_verts, quad_indices) + Ok((quad_verts, quad_indices)) } pub fn upload_verts( @@ -525,7 +527,7 @@ impl WlxGraphics { y: f32, w: f32, h: f32, - ) -> Subbuffer<[Vert2Uv]> { + ) -> anyhow::Result> { let rw = width; let rh = height; @@ -556,11 +558,15 @@ impl WlxGraphics { self.upload_buffer(BufferUsage::VERTEX_BUFFER, vertices.iter()) } - pub fn upload_buffer(&self, usage: BufferUsage, contents: Iter<'_, T>) -> Subbuffer<[T]> + pub fn upload_buffer( + &self, + usage: BufferUsage, + contents: Iter<'_, T>, + ) -> anyhow::Result> where T: BufferContents + Clone, { - Buffer::from_iter( + Ok(Buffer::from_iter( self.memory_allocator.clone(), BufferCreateInfo { usage, @@ -572,14 +578,13 @@ impl WlxGraphics { ..Default::default() }, contents.cloned(), - ) - .unwrap() + )?) } - pub fn dmabuf_texture(&self, frame: DmabufFrame) -> Option> { + pub fn dmabuf_texture(&self, frame: DmabufFrame) -> anyhow::Result> { let extent = [frame.format.width, frame.format.height, 1]; - let format = fourcc_to_vk(frame.format.fourcc); + let format = fourcc_to_vk(frame.format.fourcc)?; let layouts: Vec = (0..frame.num_planes) .into_iter() @@ -608,8 +613,7 @@ impl WlxGraphics { drm_format_modifier_plane_layouts: layouts, ..Default::default() }, - ) - .unwrap() + )? }; let requirements = image.memory_requirements()[0]; @@ -622,7 +626,7 @@ impl WlxGraphics { ..Default::default() }, ) - .unwrap(); + .ok_or_else(|| anyhow!("failed to get memory type index"))?; debug_assert!(self.device.enabled_extensions().khr_external_memory_fd); debug_assert!(self.device.enabled_extensions().khr_external_memory); @@ -631,12 +635,11 @@ impl WlxGraphics { // only do the 1st unsafe { let Some(fd) = frame.planes[0].fd else { - log::error!("DMA-buf plane has no FD"); - return None; + bail!("DMA-buf plane has no FD"); }; let file = std::fs::File::from_raw_fd(fd); - let new_file = file.try_clone().unwrap(); + let new_file = file.try_clone()?; file.into_raw_fd(); let memory = DeviceMemory::allocate_unchecked( @@ -651,28 +654,31 @@ impl WlxGraphics { file: new_file, handle_type: ExternalMemoryHandleType::DmaBuf, }), - ) - .unwrap(); + )?; let mem_alloc = ResourceMemory::new_dedicated(memory); match image.bind_memory_unchecked([mem_alloc]) { - Ok(image) => Some(Arc::new(image)), + Ok(image) => Ok(Arc::new(image)), Err(e) => { - log::error!("Failed to bind memory to image: {}", e.0); - return None; + bail!("Failed to bind memory to image: {}", e.0); } } } } - pub fn render_texture(&self, width: u32, height: u32, format: Format) -> Arc { + pub fn render_texture( + &self, + width: u32, + height: u32, + format: Format, + ) -> anyhow::Result> { log::debug!( "Render texture: {}x{} {}MB", width, height, (width * height * 4) / (1024 * 1024) ); - Image::new( + Ok(Image::new( self.memory_allocator.clone(), ImageCreateInfo { image_type: ImageType::Dim2d, @@ -684,8 +690,7 @@ impl WlxGraphics { ..Default::default() }, AllocationCreateInfo::default(), - ) - .unwrap() + )?) } pub fn create_pipeline( @@ -694,14 +699,14 @@ impl WlxGraphics { vert: Arc, frag: Arc, format: Format, - ) -> Arc> { - Arc::new(WlxPipeline::::new( + ) -> anyhow::Result>> { + Ok(Arc::new(WlxPipeline::::new( render_target, self.clone(), vert, frag, format, - )) + )?)) } pub fn create_pipeline_with_layouts( @@ -712,8 +717,8 @@ impl WlxGraphics { format: Format, initial_layout: ImageLayout, final_layout: ImageLayout, - ) -> Arc> { - Arc::new(WlxPipeline::::new_with_layout( + ) -> anyhow::Result>> { + Ok(Arc::new(WlxPipeline::::new_with_layout( render_target, self.clone(), vert, @@ -721,7 +726,7 @@ impl WlxGraphics { format, initial_layout, final_layout, - )) + )?)) } pub fn create_pipeline_dynamic( @@ -729,16 +734,19 @@ impl WlxGraphics { vert: Arc, frag: Arc, format: Format, - ) -> Arc> { - Arc::new(WlxPipeline::::new( + ) -> anyhow::Result>> { + Ok(Arc::new(WlxPipeline::::new( self.clone(), vert, frag, format, - )) + )?)) } - pub fn create_command_buffer(self: &Arc, usage: CommandBufferUsage) -> WlxCommandBuffer { + pub fn create_command_buffer( + self: &Arc, + usage: CommandBufferUsage, + ) -> anyhow::Result { let command_buffer = RecordingCommandBuffer::new( self.command_buffer_allocator.clone(), self.queue.queue_family_index(), @@ -748,12 +756,11 @@ impl WlxGraphics { inheritance_info: None, ..Default::default() }, - ) - .unwrap(); - WlxCommandBuffer { + )?; + Ok(WlxCommandBuffer { graphics: self.clone(), command_buffer, - } + }) } pub fn transition_layout( @@ -761,7 +768,7 @@ impl WlxGraphics { image: Arc, old_layout: ImageLayout, new_layout: ImageLayout, - ) -> Fence { + ) -> anyhow::Result { let barrier = ImageMemoryBarrier { src_stages: PipelineStages::ALL_TRANSFER, src_access: AccessFlags::TRANSFER_WRITE, @@ -783,23 +790,19 @@ impl WlxGraphics { inheritance_info: None, ..Default::default() }, - ) - .unwrap(); + )?; - builder - .pipeline_barrier(&DependencyInfo { - image_memory_barriers: smallvec![barrier], - ..Default::default() - }) - .unwrap(); - builder.end().unwrap() + builder.pipeline_barrier(&DependencyInfo { + image_memory_barriers: smallvec![barrier], + ..Default::default() + })?; + builder.end()? }; let fence = vulkano::sync::fence::Fence::new( self.device.clone(), vulkano::sync::fence::FenceCreateInfo::default(), - ) - .unwrap(); + )?; let fns = self.device.fns(); unsafe { @@ -813,10 +816,9 @@ impl WlxGraphics { fence.handle(), ) } - .result() - .unwrap(); + .result()?; - fence + Ok(fence) } } @@ -826,42 +828,41 @@ pub struct WlxCommandBuffer { } impl WlxCommandBuffer { - pub fn begin_render_pass(&mut self, pipeline: &WlxPipeline) { - self.command_buffer - .begin_render_pass( - RenderPassBeginInfo { - clear_values: vec![Some([0.0, 0.0, 0.0, 1.0].into())], - ..RenderPassBeginInfo::framebuffer(pipeline.data.framebuffer.clone()) - }, - SubpassBeginInfo { - contents: SubpassContents::SecondaryCommandBuffers, - ..Default::default() - }, - ) - .unwrap(); - } - - pub fn begin_rendering(&mut self, render_target: Arc) { - self.command_buffer - .begin_rendering(RenderingInfo { + pub fn begin_render_pass( + &mut self, + pipeline: &WlxPipeline, + ) -> anyhow::Result<()> { + self.command_buffer.begin_render_pass( + RenderPassBeginInfo { + clear_values: vec![Some([0.0, 0.0, 0.0, 1.0].into())], + ..RenderPassBeginInfo::framebuffer(pipeline.data.framebuffer.clone()) + }, + SubpassBeginInfo { contents: SubpassContents::SecondaryCommandBuffers, - color_attachments: vec![Some(RenderingAttachmentInfo { - load_op: AttachmentLoadOp::Clear, - store_op: AttachmentStoreOp::Store, - clear_value: Some([0.0, 0.0, 0.0, 1.0].into()), - ..RenderingAttachmentInfo::image_view(render_target.clone()) - })], ..Default::default() - }) - .unwrap(); + }, + )?; + Ok(()) } - pub fn run_ref(&mut self, pass: &WlxPass) -> &mut Self { - let _ = self - .command_buffer - .execute_commands(pass.command_buffer.clone()) - .unwrap(); - self + pub fn begin_rendering(&mut self, render_target: Arc) -> anyhow::Result<()> { + self.command_buffer.begin_rendering(RenderingInfo { + contents: SubpassContents::SecondaryCommandBuffers, + color_attachments: vec![Some(RenderingAttachmentInfo { + load_op: AttachmentLoadOp::Clear, + store_op: AttachmentStoreOp::Store, + clear_value: Some([0.0, 0.0, 0.0, 1.0].into()), + ..RenderingAttachmentInfo::image_view(render_target.clone()) + })], + ..Default::default() + })?; + Ok(()) + } + + pub fn run_ref(&mut self, pass: &WlxPass) -> anyhow::Result<()> { + self.command_buffer + .execute_commands(pass.command_buffer.clone())?; + Ok(()) } pub fn texture2d( @@ -870,7 +871,7 @@ impl WlxCommandBuffer { height: u32, format: Format, data: &[u8], - ) -> Arc { + ) -> anyhow::Result> { log::debug!( "Texture2D: {}x{} {}MB", width, @@ -887,8 +888,7 @@ impl WlxCommandBuffer { ..Default::default() }, AllocationCreateInfo::default(), - ) - .unwrap(); + )?; let buffer: Subbuffer<[u8]> = Buffer::new_slice( self.graphics.memory_allocator.clone(), @@ -902,57 +902,57 @@ impl WlxCommandBuffer { ..Default::default() }, data.len() as DeviceSize, - ) - .unwrap(); + )?; - buffer.write().unwrap().copy_from_slice(data); + buffer.write()?.copy_from_slice(data); self.command_buffer - .copy_buffer_to_image(CopyBufferToImageInfo::buffer_image(buffer, image.clone())) - .unwrap(); + .copy_buffer_to_image(CopyBufferToImageInfo::buffer_image(buffer, image.clone()))?; - image + Ok(image) } #[allow(dead_code)] - pub fn texture2d_png(&mut self, bytes: Vec) -> Arc { + pub fn texture2d_png(&mut self, bytes: Vec) -> anyhow::Result> { let cursor = Cursor::new(bytes); let decoder = png::Decoder::new(cursor); - let mut reader = decoder.read_info().unwrap(); + let mut reader = decoder.read_info()?; let info = reader.info(); let width = info.width; let height = info.height; let mut image_data = Vec::new(); image_data.resize((info.width * info.height * 4) as usize, 0); - reader.next_frame(&mut image_data).unwrap(); + reader.next_frame(&mut image_data)?; self.texture2d(width, height, Format::R8G8B8A8_UNORM, &image_data) } } impl WlxCommandBuffer { - pub fn end_render_pass(&mut self) { + pub fn end_render_pass(&mut self) -> anyhow::Result<()> { self.command_buffer - .end_render_pass(SubpassEndInfo::default()) - .unwrap(); + .end_render_pass(SubpassEndInfo::default())?; + Ok(()) } - pub fn end_rendering(&mut self) { - self.command_buffer.end_rendering().unwrap(); + pub fn end_rendering(&mut self) -> anyhow::Result<()> { + self.command_buffer.end_rendering()?; + Ok(()) } - pub fn build(self) -> Arc { - self.command_buffer.end().unwrap() + pub fn build(self) -> anyhow::Result> { + Ok(self.command_buffer.end()?) } - pub fn build_and_execute(self) -> CommandBufferExecFuture { + pub fn build_and_execute(self) -> anyhow::Result> { let queue = self.graphics.queue.clone(); - self.build().execute(queue).unwrap() + Ok(self.build()?.execute(queue)?) } - pub fn build_and_execute_now(self) { - let mut exec = self.build_and_execute(); - exec.flush().unwrap(); + pub fn build_and_execute_now(self) -> anyhow::Result<()> { + let mut exec = self.build_and_execute()?; + exec.flush()?; exec.cleanup_finished(); + Ok(()) } } @@ -977,13 +977,11 @@ impl WlxPipeline { vert: Arc, frag: Arc, format: Format, - ) -> Self { - let vep = vert.entry_point("main").unwrap(); - let fep = frag.entry_point("main").unwrap(); + ) -> anyhow::Result { + let vep = vert.entry_point("main").unwrap(); // want panic + let fep = frag.entry_point("main").unwrap(); // want panic - let vertex_input_state = Vert2Uv::per_vertex() - .definition(&vep.info().input_interface) - .unwrap(); + let vertex_input_state = Vert2Uv::per_vertex().definition(&vep.info().input_interface)?; let stages = smallvec![ vulkano::pipeline::PipelineShaderStageCreateInfo::new(vep), @@ -993,10 +991,8 @@ impl WlxPipeline { let layout = PipelineLayout::new( graphics.device.clone(), PipelineDescriptorSetLayoutCreateInfo::from_stages(&stages) - .into_pipeline_layout_create_info(graphics.device.clone()) - .unwrap(), - ) - .unwrap(); + .into_pipeline_layout_create_info(graphics.device.clone())?, + )?; let subpass = PipelineRenderingCreateInfo { color_attachment_formats: vec![Some(format)], @@ -1024,15 +1020,14 @@ impl WlxPipeline { subpass: Some(subpass.into()), ..GraphicsPipelineCreateInfo::layout(layout) }, - ) - .unwrap(); + )?; - Self { + Ok(Self { graphics, pipeline, format, data: WlxPipelineDynamic {}, - } + }) } pub fn create_pass( self: &Arc, @@ -1040,7 +1035,7 @@ impl WlxPipeline { vertex_buffer: Subbuffer<[Vert2Uv]>, index_buffer: Subbuffer<[u16]>, descriptor_sets: Vec>, - ) -> WlxPass { + ) -> anyhow::Result> { WlxPass::::new( self.clone(), dimensions, @@ -1058,7 +1053,7 @@ impl WlxPipeline { vert: Arc, frag: Arc, format: Format, - ) -> Self { + ) -> anyhow::Result { let render_pass = vulkano::single_pass_renderpass!( graphics.device.clone(), attachments: { @@ -1073,8 +1068,7 @@ impl WlxPipeline { color: [color], depth_stencil: {}, }, - ) - .unwrap(); + )?; Self::new_from_pass(render_target, render_pass, graphics, vert, frag, format) } @@ -1087,7 +1081,7 @@ impl WlxPipeline { format: Format, initial_layout: ImageLayout, final_layout: ImageLayout, - ) -> Self { + ) -> anyhow::Result { let render_pass_description = RenderPassCreateInfo { attachments: vec![AttachmentDescription { format, @@ -1109,8 +1103,7 @@ impl WlxPipeline { ..Default::default() }; - let render_pass = - RenderPass::new(graphics.device.clone(), render_pass_description).unwrap(); + let render_pass = RenderPass::new(graphics.device.clone(), render_pass_description)?; Self::new_from_pass(render_target, render_pass, graphics, vert, frag, format) } @@ -1122,13 +1115,11 @@ impl WlxPipeline { vert: Arc, frag: Arc, format: Format, - ) -> Self { - let vep = vert.entry_point("main").unwrap(); - let fep = frag.entry_point("main").unwrap(); + ) -> anyhow::Result { + let vep = vert.entry_point("main").unwrap(); // want panic + let fep = frag.entry_point("main").unwrap(); // want panic - let vertex_input_state = Vert2Uv::per_vertex() - .definition(&vep.info().input_interface) - .unwrap(); + let vertex_input_state = Vert2Uv::per_vertex().definition(&vep.info().input_interface)?; let stages = smallvec![ vulkano::pipeline::PipelineShaderStageCreateInfo::new(vep), @@ -1138,10 +1129,8 @@ impl WlxPipeline { let layout = PipelineLayout::new( graphics.device.clone(), PipelineDescriptorSetLayoutCreateInfo::from_stages(&stages) - .into_pipeline_layout_create_info(graphics.device.clone()) - .unwrap(), - ) - .unwrap(); + .into_pipeline_layout_create_info(graphics.device.clone())?, + )?; let framebuffer = Framebuffer::new( render_pass.clone(), @@ -1149,8 +1138,7 @@ impl WlxPipeline { attachments: vec![render_target.clone()], ..Default::default() }, - ) - .unwrap(); + )?; let pipeline = GraphicsPipeline::new( graphics.device.clone(), @@ -1170,13 +1158,16 @@ impl WlxPipeline { rasterization_state: Some(RasterizationState::default()), multisample_state: Some(MultisampleState::default()), dynamic_state: [DynamicState::Viewport].into_iter().collect(), - subpass: Some(Subpass::from(render_pass.clone(), 0).unwrap().into()), + subpass: Some( + Subpass::from(render_pass.clone(), 0) + .ok_or_else(|| anyhow!("Failed to create subpass"))? + .into(), + ), ..GraphicsPipelineCreateInfo::layout(layout) }, - ) - .unwrap(); + )?; - Self { + Ok(Self { graphics, pipeline, format, @@ -1185,7 +1176,7 @@ impl WlxPipeline { framebuffer, view: render_target, }, - } + }) } pub fn create_pass( @@ -1194,7 +1185,7 @@ impl WlxPipeline { vertex_buffer: Subbuffer<[Vert2Uv]>, index_buffer: Subbuffer<[u16]>, descriptor_sets: Vec>, - ) -> WlxPass { + ) -> anyhow::Result> { WlxPass::::new( self.clone(), dimensions, @@ -1215,7 +1206,7 @@ impl WlxPipeline { set: usize, texture: Arc, filter: Filter, - ) -> Arc { + ) -> anyhow::Result> { let sampler = Sampler::new( self.graphics.device.clone(), SamplerCreateInfo { @@ -1224,21 +1215,19 @@ impl WlxPipeline { address_mode: [SamplerAddressMode::Repeat; 3], ..Default::default() }, - ) - .unwrap(); + )?; - let layout = self.pipeline.layout().set_layouts().get(set).unwrap(); + let layout = self.pipeline.layout().set_layouts().get(set).unwrap(); // want panic - DescriptorSet::new( + Ok(DescriptorSet::new( self.graphics.descriptor_set_allocator.clone(), layout.clone(), [WriteDescriptorSet::image_view_sampler(0, texture, sampler)], [], - ) - .unwrap() + )?) } - pub fn uniform_buffer(&self, set: usize, data: Vec) -> Arc + pub fn uniform_buffer(&self, set: usize, data: Vec) -> anyhow::Result> where T: BufferContents + Copy, { @@ -1253,19 +1242,18 @@ impl WlxPipeline { ); let uniform_buffer_subbuffer = { - let subbuffer = uniform_buffer.allocate_slice(data.len() as _).unwrap(); - subbuffer.write().unwrap().copy_from_slice(data.as_slice()); + let subbuffer = uniform_buffer.allocate_slice(data.len() as _)?; + subbuffer.write()?.copy_from_slice(data.as_slice()); subbuffer }; - let layout = self.pipeline.layout().set_layouts().get(set).unwrap(); - DescriptorSet::new( + let layout = self.pipeline.layout().set_layouts().get(set).unwrap(); // want panic + Ok(DescriptorSet::new( self.graphics.descriptor_set_allocator.clone(), layout.clone(), [WriteDescriptorSet::buffer(0, uniform_buffer_subbuffer)], [], - ) - .unwrap() + )?) } } @@ -1285,7 +1273,7 @@ impl WlxPass { vertex_buffer: Subbuffer<[Vert2Uv]>, index_buffer: Subbuffer<[u16]>, descriptor_sets: Vec>, - ) -> Self { + ) -> anyhow::Result { let viewport = Viewport { offset: [0.0, 0.0], extent: dimensions, @@ -1302,7 +1290,8 @@ impl WlxPass { inheritance_info: Some(CommandBufferInheritanceInfo { render_pass: Some(CommandBufferInheritanceRenderPassType::BeginRenderPass( CommandBufferInheritanceRenderPassInfo { - subpass: Subpass::from(pipeline.data.render_pass.clone(), 0).unwrap(), + subpass: Subpass::from(pipeline.data.render_pass.clone(), 0) + .ok_or_else(|| anyhow!("Failed to get subpass"))?, framebuffer: None, }, )), @@ -1310,43 +1299,30 @@ impl WlxPass { }), ..Default::default() }, - ) - .unwrap(); + )?; unsafe { command_buffer - .set_viewport(0, smallvec![viewport]) - .unwrap() - .bind_pipeline_graphics(pipeline_inner) - .unwrap() + .set_viewport(0, smallvec![viewport])? + .bind_pipeline_graphics(pipeline_inner)? .bind_descriptor_sets( PipelineBindPoint::Graphics, pipeline.inner().layout().clone(), 0, descriptor_sets.clone(), - ) - .unwrap() - .bind_vertex_buffers(0, vertex_buffer.clone()) - .unwrap() - .bind_index_buffer(index_buffer.clone()) - .unwrap() - .draw_indexed(index_buffer.len() as u32, 1, 0, 0, 0) - .or_else(|err| { - if let Some(source) = err.source() { - log::error!("Failed to draw: {}", source); - } - Err(err) - }) - .unwrap() + )? + .bind_vertex_buffers(0, vertex_buffer.clone())? + .bind_index_buffer(index_buffer.clone())? + .draw_indexed(index_buffer.len() as u32, 1, 0, 0, 0)? }; - Self { + Ok(Self { pipeline, vertex_buffer, index_buffer, descriptor_sets, - command_buffer: command_buffer.end().unwrap(), - } + command_buffer: command_buffer.end()?, + }) } } @@ -1357,7 +1333,7 @@ impl WlxPass { vertex_buffer: Subbuffer<[Vert2Uv]>, index_buffer: Subbuffer<[u16]>, descriptor_sets: Vec>, - ) -> Self { + ) -> anyhow::Result { let viewport = Viewport { offset: [0.0, 0.0], extent: dimensions, @@ -1381,53 +1357,40 @@ impl WlxPass { }), ..Default::default() }, - ) - .unwrap(); + )?; unsafe { command_buffer - .set_viewport(0, smallvec![viewport]) - .unwrap() - .bind_pipeline_graphics(pipeline_inner) - .unwrap() + .set_viewport(0, smallvec![viewport])? + .bind_pipeline_graphics(pipeline_inner)? .bind_descriptor_sets( PipelineBindPoint::Graphics, pipeline.inner().layout().clone(), 0, descriptor_sets.clone(), - ) - .unwrap() - .bind_vertex_buffers(0, vertex_buffer.clone()) - .unwrap() - .bind_index_buffer(index_buffer.clone()) - .unwrap() - .draw_indexed(index_buffer.len() as u32, 1, 0, 0, 0) - .or_else(|err| { - if let Some(source) = err.source() { - log::error!("Failed to draw: {}", source); - } - Err(err) - }) - .unwrap() + )? + .bind_vertex_buffers(0, vertex_buffer.clone())? + .bind_index_buffer(index_buffer.clone())? + .draw_indexed(index_buffer.len() as u32, 1, 0, 0, 0)? }; - Self { + Ok(Self { pipeline, vertex_buffer, index_buffer, descriptor_sets, - command_buffer: command_buffer.end().unwrap(), - } + command_buffer: command_buffer.end()?, + }) } } -pub fn fourcc_to_vk(fourcc: FourCC) -> Format { +pub fn fourcc_to_vk(fourcc: FourCC) -> anyhow::Result { match fourcc.value { - DRM_FORMAT_ABGR8888 => Format::R8G8B8A8_UNORM, - DRM_FORMAT_XBGR8888 => Format::R8G8B8A8_UNORM, - DRM_FORMAT_ARGB8888 => Format::B8G8R8A8_UNORM, - DRM_FORMAT_XRGB8888 => Format::B8G8R8A8_UNORM, - _ => panic!("Unsupported memfd format {}", fourcc), + DRM_FORMAT_ABGR8888 => Ok(Format::R8G8B8A8_UNORM), + DRM_FORMAT_XBGR8888 => Ok(Format::R8G8B8A8_UNORM), + DRM_FORMAT_ARGB8888 => Ok(Format::B8G8R8A8_UNORM), + DRM_FORMAT_XRGB8888 => Ok(Format::B8G8R8A8_UNORM), + _ => bail!("Unsupported format {}", fourcc), } } diff --git a/src/gui/font.rs b/src/gui/font.rs index f45aa57..5d10f73 100644 --- a/src/gui/font.rs +++ b/src/gui/font.rs @@ -35,15 +35,15 @@ pub struct Glyph { } impl FontCache { - pub fn new() -> Self { - let ft = Library::init().expect("Failed to initialize freetype"); + pub fn new() -> anyhow::Result { + let ft = Library::init()?; let fc = FontConfig::default(); - FontCache { + Ok(FontCache { fc, ft, collections: IdMap::new(), - } + }) } pub fn get_text_size( @@ -51,7 +51,7 @@ impl FontCache { text: &str, size: isize, graphics: Arc, - ) -> (f32, f32) { + ) -> anyhow::Result<(f32, f32)> { let sizef = size as f32; let height = sizef + ((text.lines().count() as f32) - 1f32) * (sizef * 1.5); @@ -60,9 +60,10 @@ impl FontCache { for line in text.lines() { let w: f32 = line .chars() - .map(|c| { + .filter_map(|c| { self.get_glyph_for_cp(c as usize, size, graphics.clone()) - .advance + .map(|glyph| glyph.advance) + .ok() }) .sum(); @@ -70,7 +71,7 @@ impl FontCache { max_w = w; } } - (max_w, height) + Ok((max_w, height)) } pub fn get_glyphs( @@ -78,14 +79,14 @@ impl FontCache { text: &str, size: isize, graphics: Arc, - ) -> Vec> { + ) -> anyhow::Result>> { let mut glyphs = Vec::new(); for line in text.lines() { for c in line.chars() { - glyphs.push(self.get_glyph_for_cp(c as usize, size, graphics.clone())); + glyphs.push(self.get_glyph_for_cp(c as usize, size, graphics.clone())?); } } - glyphs + Ok(glyphs) } fn get_font_for_cp(&mut self, cp: usize, size: isize) -> usize { @@ -98,7 +99,7 @@ impl FontCache { }, ); } - let coll = self.collections.get_mut(size).unwrap(); + let coll = self.collections.get_mut(size).unwrap(); // safe because of the insert above if let Some(font) = coll.cp_map.get(cp) { return *font; @@ -167,28 +168,28 @@ impl FontCache { cp: usize, size: isize, graphics: Arc, - ) -> Rc { + ) -> anyhow::Result> { let key = self.get_font_for_cp(cp, size); let font = &mut self.collections[size].fonts[key]; if let Some(glyph) = font.glyphs.get(cp) { - return glyph.clone(); + return Ok(glyph.clone()); } if font.face.load_char(cp, LoadFlag::DEFAULT).is_err() { - return font.glyphs[0].clone(); + return Ok(font.glyphs[0].clone()); } let glyph = font.face.glyph(); if glyph.render_glyph(freetype::RenderMode::Normal).is_err() { - return font.glyphs[0].clone(); + return Ok(font.glyphs[0].clone()); } let bmp = glyph.bitmap(); let buf = bmp.buffer().to_vec(); if buf.len() == 0 { - return font.glyphs[0].clone(); + return Ok(font.glyphs[0].clone()); } let metrics = glyph.metrics(); @@ -197,12 +198,12 @@ impl FontCache { Ok(PixelMode::Gray) => Format::R8_UNORM, Ok(PixelMode::Gray2) => Format::R16_SFLOAT, Ok(PixelMode::Gray4) => Format::R32_SFLOAT, - _ => return font.glyphs[0].clone(), + _ => return Ok(font.glyphs[0].clone()), }; - let mut cmd_buffer = graphics.create_command_buffer(CommandBufferUsage::OneTimeSubmit); - let texture = cmd_buffer.texture2d(bmp.width() as _, bmp.rows() as _, format, &buf); - cmd_buffer.build_and_execute_now(); + let mut cmd_buffer = graphics.create_command_buffer(CommandBufferUsage::OneTimeSubmit)?; + let texture = cmd_buffer.texture2d(bmp.width() as _, bmp.rows() as _, format, &buf)?; + cmd_buffer.build_and_execute_now()?; let g = Glyph { tex: Some(texture), @@ -214,6 +215,6 @@ impl FontCache { }; font.glyphs.insert(cp, Rc::new(g)); - font.glyphs[cp].clone() + Ok(font.glyphs[cp].clone()) } } diff --git a/src/gui/mod.rs b/src/gui/mod.rs index 48ea1f9..8c2243b 100644 --- a/src/gui/mod.rs +++ b/src/gui/mod.rs @@ -60,13 +60,13 @@ impl CanvasBuilder { graphics: Arc, format: Format, data: D, - ) -> Self { - Self { - canvas: Canvas::new(width, height, graphics, format, data), + ) -> anyhow::Result { + Ok(Self { + canvas: Canvas::new(width, height, graphics, format, data)?, bg_color: Vec3::ZERO, fg_color: Vec3::ONE, font_size: 16, - } + }) } pub fn build(self) -> Canvas { @@ -225,62 +225,64 @@ impl Canvas { graphics: Arc, format: Format, data: D, - ) -> Self { - let tex_fg = graphics.render_texture(width as _, height as _, format); - let tex_bg = graphics.render_texture(width as _, height as _, format); - let tex_final = graphics.render_texture(width as _, height as _, format); + ) -> anyhow::Result { + let tex_fg = graphics.render_texture(width as _, height as _, format)?; + let tex_bg = graphics.render_texture(width as _, height as _, format)?; + let tex_final = graphics.render_texture(width as _, height as _, format)?; - let view_fg = ImageView::new_default(tex_fg.clone()).unwrap(); - let view_bg = ImageView::new_default(tex_bg.clone()).unwrap(); - let view_final = ImageView::new_default(tex_final.clone()).unwrap(); + let view_fg = ImageView::new_default(tex_fg.clone())?; + let view_bg = ImageView::new_default(tex_bg.clone())?; + let view_final = ImageView::new_default(tex_final.clone())?; - let shaders = graphics.shared_shaders.read().unwrap(); + let Ok(shaders) = graphics.shared_shaders.read() else { + bail!("Failed to lock shared shaders for reading"); + }; let pipeline_bg_color = graphics.create_pipeline( view_bg.clone(), - shaders.get("vert_common").unwrap().clone(), - shaders.get("frag_color").unwrap().clone(), + shaders.get("vert_common").unwrap().clone(), // want panic + shaders.get("frag_color").unwrap().clone(), // want panic format, - ); + )?; let pipeline_fg_glyph = graphics.create_pipeline( view_fg.clone(), - shaders.get("vert_common").unwrap().clone(), - shaders.get("frag_glyph").unwrap().clone(), + shaders.get("vert_common").unwrap().clone(), // want panic + shaders.get("frag_glyph").unwrap().clone(), // want panic format, - ); + )?; let vertex_buffer = - graphics.upload_verts(width as _, height as _, 0., 0., width as _, height as _); + graphics.upload_verts(width as _, height as _, 0., 0., width as _, height as _)?; let pipeline_final = graphics.create_pipeline_with_layouts( view_final.clone(), - shaders.get("vert_common").unwrap().clone(), - shaders.get("frag_sprite").unwrap().clone(), + shaders.get("vert_common").unwrap().clone(), // want panic + shaders.get("frag_sprite").unwrap().clone(), // want panic format, ImageLayout::TransferSrcOptimal, ImageLayout::TransferSrcOptimal, - ); + )?; - let set_fg = pipeline_final.uniform_sampler(0, view_fg.clone(), Filter::Linear); - let set_bg = pipeline_final.uniform_sampler(0, view_bg.clone(), Filter::Linear); + let set_fg = pipeline_final.uniform_sampler(0, view_fg.clone(), Filter::Linear)?; + let set_bg = pipeline_final.uniform_sampler(0, view_bg.clone(), Filter::Linear)?; let pass_fg = pipeline_final.create_pass( [width as _, height as _], vertex_buffer.clone(), graphics.quad_indices.clone(), vec![set_fg], - ); + )?; let pass_bg = pipeline_final.create_pass( [width as _, height as _], vertex_buffer.clone(), graphics.quad_indices.clone(), vec![set_bg], - ); + )?; let stride = width / RES_DIVIDER; let rows = height / RES_DIVIDER; - Self { + Ok(Self { canvas: CanvasData { data, width, @@ -299,7 +301,7 @@ impl Canvas { view_final, pass_fg, pass_bg, - } + }) } fn interactive_set_idx(&mut self, x: f32, y: f32, w: f32, h: f32, idx: usize) { @@ -325,34 +327,34 @@ impl Canvas { self.interact_map[y * self.interact_stride + x].map(|x| x as usize) } - fn render_bg(&mut self, app: &mut AppState) { + fn render_bg(&mut self, app: &mut AppState) -> anyhow::Result<()> { let mut cmd_buffer = self .canvas .graphics - .create_command_buffer(CommandBufferUsage::OneTimeSubmit); - cmd_buffer.begin_render_pass(&self.canvas.pipeline_bg_color); + .create_command_buffer(CommandBufferUsage::OneTimeSubmit)?; + cmd_buffer.begin_render_pass(&self.canvas.pipeline_bg_color)?; for c in self.controls.iter_mut() { if let Some(fun) = c.on_render_bg { - fun(c, &self.canvas, app, &mut cmd_buffer); + fun(c, &self.canvas, app, &mut cmd_buffer)?; } } - cmd_buffer.end_render_pass(); - cmd_buffer.build_and_execute_now(); + cmd_buffer.end_render_pass()?; + cmd_buffer.build_and_execute_now() } - fn render_fg(&mut self, app: &mut AppState) { + fn render_fg(&mut self, app: &mut AppState) -> anyhow::Result<()> { let mut cmd_buffer = self .canvas .graphics - .create_command_buffer(CommandBufferUsage::OneTimeSubmit); - cmd_buffer.begin_render_pass(&self.canvas.pipeline_fg_glyph); + .create_command_buffer(CommandBufferUsage::OneTimeSubmit)?; + cmd_buffer.begin_render_pass(&self.canvas.pipeline_fg_glyph)?; for c in self.controls.iter_mut() { if let Some(fun) = c.on_render_fg { - fun(c, &self.canvas, app, &mut cmd_buffer); + fun(c, &self.canvas, app, &mut cmd_buffer)?; } } - cmd_buffer.end_render_pass(); - cmd_buffer.build_and_execute_now(); + cmd_buffer.end_render_pass()?; + cmd_buffer.build_and_execute_now() } } @@ -410,13 +412,17 @@ impl InteractionHandler for Canvas { } impl OverlayRenderer for Canvas { - fn init(&mut self, app: &mut AppState) { - self.render_bg(app); - self.render_fg(app); + fn init(&mut self, app: &mut AppState) -> anyhow::Result<()> { + self.render_bg(app)?; + self.render_fg(app) } - fn pause(&mut self, _app: &mut AppState) {} - fn resume(&mut self, _app: &mut AppState) {} - fn render(&mut self, app: &mut AppState) { + fn pause(&mut self, _app: &mut AppState) -> anyhow::Result<()> { + Ok(()) + } + fn resume(&mut self, _app: &mut AppState) -> anyhow::Result<()> { + Ok(()) + } + fn render(&mut self, app: &mut AppState) -> anyhow::Result<()> { let mut dirty = false; for c in self.controls.iter_mut() { @@ -430,8 +436,8 @@ impl OverlayRenderer for Canvas { } if dirty { - self.render_bg(app); - self.render_fg(app); + self.render_bg(app)?; + self.render_fg(app)?; } /* @@ -454,17 +460,17 @@ impl OverlayRenderer for Canvas { let mut cmd_buffer = self .canvas .graphics - .create_command_buffer(CommandBufferUsage::OneTimeSubmit); - cmd_buffer.begin_render_pass(&self.canvas.pipeline_final); + .create_command_buffer(CommandBufferUsage::OneTimeSubmit)?; + cmd_buffer.begin_render_pass(&self.canvas.pipeline_final)?; // static background - cmd_buffer.run_ref(&self.pass_bg); + cmd_buffer.run_ref(&self.pass_bg)?; for (i, c) in self.controls.iter_mut().enumerate() { if let Some(render) = c.on_render_hl { if let Some(test) = c.test_highlight { if let Some(hl_color) = test(c, &mut self.canvas.data, app) { - render(c, &self.canvas, app, &mut cmd_buffer, hl_color); + render(c, &self.canvas, app, &mut cmd_buffer, hl_color)?; } } if self.hover_controls.contains(&Some(i)) { @@ -474,16 +480,16 @@ impl OverlayRenderer for Canvas { app, &mut cmd_buffer, Vec4::new(1., 1., 1., 0.3), - ); + )?; } } } // mostly static text - cmd_buffer.run_ref(&self.pass_fg); + cmd_buffer.run_ref(&self.pass_fg)?; - cmd_buffer.end_render_pass(); - cmd_buffer.build_and_execute_now(); + cmd_buffer.end_render_pass()?; + cmd_buffer.build_and_execute_now() /* self.canvas @@ -523,9 +529,15 @@ pub struct Control { pub on_scroll: Option, pub test_highlight: Option Option>, - on_render_bg: Option, &mut AppState, &mut WlxCommandBuffer)>, - on_render_hl: Option, &mut AppState, &mut WlxCommandBuffer, Vec4)>, - on_render_fg: Option, &mut AppState, &mut WlxCommandBuffer)>, + on_render_bg: Option< + fn(&Self, &CanvasData, &mut AppState, &mut WlxCommandBuffer) -> anyhow::Result<()>, + >, + on_render_hl: Option< + fn(&Self, &CanvasData, &mut AppState, &mut WlxCommandBuffer, Vec4) -> anyhow::Result<()>, + >, + on_render_fg: Option< + fn(&Self, &CanvasData, &mut AppState, &mut WlxCommandBuffer) -> anyhow::Result<()>, + >, } impl Control { @@ -577,7 +589,7 @@ impl Control { canvas: &CanvasData, _: &mut AppState, cmd_buffer: &mut WlxCommandBuffer, - ) { + ) -> anyhow::Result<()> { let pass = { let vertex_buffer = canvas.graphics.upload_verts( canvas.width as _, @@ -586,20 +598,20 @@ impl Control { self.rect.y, self.rect.w, self.rect.h, - ); + )?; let set0 = canvas.pipeline_bg_color.uniform_buffer( 0, vec![self.bg_color.x, self.bg_color.y, self.bg_color.z, 1.], - ); + )?; canvas.pipeline_bg_color.create_pass( [canvas.width as _, canvas.height as _], vertex_buffer, canvas.graphics.quad_indices.clone(), vec![set0], - ) + )? }; - cmd_buffer.run_ref(&pass); + cmd_buffer.run_ref(&pass) } fn render_highlight( @@ -608,7 +620,7 @@ impl Control { _: &mut AppState, cmd_buffer: &mut WlxCommandBuffer, color: Vec4, - ) { + ) -> anyhow::Result<()> { let vertex_buffer = canvas.graphics.upload_verts( canvas.width as _, canvas.height as _, @@ -616,20 +628,20 @@ impl Control { self.rect.y, self.rect.w, self.rect.h, - ); + )?; let set0 = canvas .pipeline_bg_color - .uniform_buffer(0, color.to_array().to_vec()); + .uniform_buffer(0, color.to_array().to_vec())?; let pass = canvas.pipeline_bg_color.create_pass( [canvas.width as _, canvas.height as _], vertex_buffer.clone(), canvas.graphics.quad_indices.clone(), vec![set0], - ); + )?; - cmd_buffer.run_ref(&pass); + cmd_buffer.run_ref(&pass) } fn render_text( @@ -637,11 +649,14 @@ impl Control { canvas: &CanvasData, app: &mut AppState, cmd_buffer: &mut WlxCommandBuffer, - ) { + ) -> anyhow::Result<()> { let mut cur_y = self.rect.y; for line in self.text.lines() { let mut cur_x = self.rect.x; - for glyph in app.fc.get_glyphs(line, self.size, canvas.graphics.clone()) { + for glyph in app + .fc + .get_glyphs(line, self.size, canvas.graphics.clone())? + { if let Some(tex) = glyph.tex.clone() { let vertex_buffer = canvas.graphics.upload_verts( canvas.width as _, @@ -650,43 +665,47 @@ impl Control { cur_y - glyph.top, glyph.width, glyph.height, - ); + )?; let set0 = canvas.pipeline_fg_glyph.uniform_sampler( 0, ImageView::new_default(tex).unwrap(), Filter::Linear, - ); + )?; let set1 = canvas.pipeline_fg_glyph.uniform_buffer( 1, vec![self.fg_color.x, self.fg_color.y, self.fg_color.z, 1.], - ); + )?; let pass = canvas.pipeline_fg_glyph.create_pass( [canvas.width as _, canvas.height as _], vertex_buffer, canvas.graphics.quad_indices.clone(), vec![set0, set1], - ); - cmd_buffer.run_ref(&pass); + )?; + cmd_buffer.run_ref(&pass)?; } cur_x += glyph.advance; } cur_y += (self.size as f32) * 1.5; } + Ok(()) } fn render_text_centered( &self, canvas: &CanvasData, app: &mut AppState, cmd_buffer: &mut WlxCommandBuffer, - ) { + ) -> anyhow::Result<()> { let (w, h) = app .fc - .get_text_size(&self.text, self.size, canvas.graphics.clone()); + .get_text_size(&self.text, self.size, canvas.graphics.clone())?; let mut cur_y = self.rect.y + (self.rect.h) - (h * 0.5); for line in self.text.lines() { let mut cur_x = self.rect.x + (self.rect.w * 0.5) - (w * 0.5); - for glyph in app.fc.get_glyphs(line, self.size, canvas.graphics.clone()) { + for glyph in app + .fc + .get_glyphs(line, self.size, canvas.graphics.clone())? + { if let Some(tex) = glyph.tex.clone() { let vertex_buffer = canvas.graphics.upload_verts( canvas.width as _, @@ -695,27 +714,28 @@ impl Control { cur_y - glyph.top, glyph.width, glyph.height, - ); + )?; let set0 = canvas.pipeline_fg_glyph.uniform_sampler( 0, ImageView::new_default(tex).unwrap(), Filter::Linear, - ); + )?; let set1 = canvas.pipeline_fg_glyph.uniform_buffer( 1, vec![self.fg_color.x, self.fg_color.y, self.fg_color.z, 1.], - ); + )?; let pass = canvas.pipeline_fg_glyph.create_pass( [canvas.width as _, canvas.height as _], vertex_buffer, canvas.graphics.quad_indices.clone(), vec![set0, set1], - ); - cmd_buffer.run_ref(&pass); + )?; + cmd_buffer.run_ref(&pass)?; } cur_x += glyph.advance; } cur_y += (self.size as f32) * 1.5; } + Ok(()) } } diff --git a/src/overlays/keyboard.rs b/src/overlays/keyboard.rs index 6967190..488e000 100644 --- a/src/overlays/keyboard.rs +++ b/src/overlays/keyboard.rs @@ -27,7 +27,7 @@ const AUTO_RELEASE_MODS: [KeyModifier; 5] = [SHIFT, CTRL, ALT, SUPER, META]; pub const KEYBOARD_NAME: &str = "kbd"; -pub fn create_keyboard(app: &AppState) -> OverlayData +pub fn create_keyboard(app: &AppState) -> anyhow::Result> where O: Default, { @@ -50,7 +50,7 @@ where app.graphics.clone(), app.format, data, - ); + )?; canvas.bg_color = color_parse("#101010").unwrap(); //safe canvas.panel(0., 0., size.x, size.y); @@ -118,7 +118,7 @@ where let width = LAYOUT.row_size * 0.05 * app.session.config.keyboard_scale; - OverlayData { + Ok(OverlayData { state: OverlayState { name: KEYBOARD_NAME.into(), size: (size.x as _, size.y as _), @@ -132,7 +132,7 @@ where }, backend: Box::new(canvas), ..Default::default() - } + }) } fn key_press( diff --git a/src/overlays/screen.rs b/src/overlays/screen.rs index 7146e18..4709680 100644 --- a/src/overlays/screen.rs +++ b/src/overlays/screen.rs @@ -129,9 +129,9 @@ struct ScreenPipeline { impl ScreenPipeline { fn new(extent: &[u32; 3], app: &mut AppState) -> anyhow::Result { - let texture = app - .graphics - .render_texture(extent[0], extent[1], app.graphics.native_format); + let texture = + app.graphics + .render_texture(extent[0], extent[1], app.graphics.native_format)?; let view = ImageView::new_default(texture)?; @@ -144,7 +144,7 @@ impl ScreenPipeline { shaders.get("vert_common").unwrap().clone(), // want panic shaders.get("frag_sprite").unwrap().clone(), // want panic app.graphics.native_format, - ); + )?; let extentf = [extent[0] as f32, extent[1] as f32]; @@ -156,9 +156,9 @@ impl ScreenPipeline { }) } - fn ensure_mouse_initialized(&mut self, uploads: &mut WlxCommandBuffer) { + fn ensure_mouse_initialized(&mut self, uploads: &mut WlxCommandBuffer) -> anyhow::Result<()> { if self.mouse.is_some() { - return; + return Ok(()); } #[rustfmt::skip] @@ -170,26 +170,32 @@ impl ScreenPipeline { ]; let mouse_tex = - uploads.texture2d(4, 4, vulkano::format::Format::R8G8B8A8_UNORM, &mouse_bytes); - self.mouse = Some(ImageView::new_default(mouse_tex).unwrap()); + uploads.texture2d(4, 4, vulkano::format::Format::R8G8B8A8_UNORM, &mouse_bytes)?; + self.mouse = Some(ImageView::new_default(mouse_tex)?); + Ok(()) } - fn render(&mut self, image: Arc, mouse: Option<&MouseMeta>, app: &mut AppState) { + fn render( + &mut self, + image: Arc, + mouse: Option<&MouseMeta>, + app: &mut AppState, + ) -> anyhow::Result<()> { let mut cmd = app .graphics - .create_command_buffer(CommandBufferUsage::OneTimeSubmit); - let view = ImageView::new_default(image).unwrap(); - let set0 = self.pipeline.uniform_sampler(0, view, Filter::Linear); + .create_command_buffer(CommandBufferUsage::OneTimeSubmit)?; + let view = ImageView::new_default(image)?; + let set0 = self.pipeline.uniform_sampler(0, view, Filter::Linear)?; let pass = self.pipeline.create_pass( self.extentf, app.graphics.quad_verts.clone(), app.graphics.quad_indices.clone(), vec![set0], - ); + )?; - cmd.begin_render_pass(&self.pipeline); - cmd.run_ref(&pass); + cmd.begin_render_pass(&self.pipeline)?; + cmd.run_ref(&pass)?; if let (Some(mouse), Some(mouse_view)) = (mouse, self.mouse.clone()) { let vertex_buffer = app.graphics.upload_verts( @@ -199,25 +205,24 @@ impl ScreenPipeline { mouse.y * self.extentf[1] - 2., 4.0, 4.0, - ); + )?; let set0 = self .pipeline - .uniform_sampler(0, mouse_view.clone(), Filter::Linear); + .uniform_sampler(0, mouse_view.clone(), Filter::Linear)?; let pass = self.pipeline.create_pass( self.extentf, vertex_buffer, app.graphics.quad_indices.clone(), vec![set0], - ); + )?; - cmd.run_ref(&pass); + cmd.run_ref(&pass)?; } - cmd.end_render_pass(); - - cmd.build_and_execute_now(); + cmd.end_render_pass()?; + cmd.build_and_execute_now() } } @@ -289,8 +294,10 @@ impl ScreenRenderer { } impl OverlayRenderer for ScreenRenderer { - fn init(&mut self, _app: &mut AppState) {} - fn render(&mut self, app: &mut AppState) { + fn init(&mut self, _app: &mut AppState) -> anyhow::Result<()> { + Ok(()) + } + fn render(&mut self, app: &mut AppState) -> anyhow::Result<()> { let receiver = self.receiver.get_or_insert_with(|| { let allow_dmabuf = &*app.session.config.capture_method != "pw_fallback"; @@ -313,7 +320,9 @@ impl OverlayRenderer for ScreenRenderer { let mut final_formats = vec![]; for &f in &possible_formats { - let vk_fmt = fourcc_to_vk(f); + let Ok(vk_fmt) = fourcc_to_vk(f) else { + continue; + }; let Ok(props) = graphics.device.physical_device().format_properties(vk_fmt) else { continue; @@ -347,8 +356,8 @@ impl OverlayRenderer for ScreenRenderer { log::error!("Invalid frame"); continue; } - if let Some(new) = app.graphics.dmabuf_texture(frame) { - let view = ImageView::new_default(new.clone()).unwrap(); + if let Ok(new) = app.graphics.dmabuf_texture(frame) { + let view = ImageView::new_default(new.clone())?; self.last_view = Some(view); } else { @@ -358,14 +367,14 @@ impl OverlayRenderer for ScreenRenderer { WlxFrame::MemFd(frame) => { let mut upload = app .graphics - .create_command_buffer(CommandBufferUsage::OneTimeSubmit); + .create_command_buffer(CommandBufferUsage::OneTimeSubmit)?; let Some(fd) = frame.plane.fd else { log::error!("No fd"); continue; }; log::debug!("{}: New MemFd frame", self.name); - let format = fourcc_to_vk(frame.format.fourcc); + let format = fourcc_to_vk(frame.format.fourcc)?; let len = frame.plane.stride as usize * frame.format.height as usize; let offset = frame.plane.offset as i64; @@ -384,42 +393,42 @@ impl OverlayRenderer for ScreenRenderer { let data = unsafe { slice::from_raw_parts(map, len) }; let image = - upload.texture2d(frame.format.width, frame.format.height, format, &data); - upload.build_and_execute_now(); + upload.texture2d(frame.format.width, frame.format.height, format, &data)?; + upload.build_and_execute_now()?; unsafe { libc::munmap(map as *mut _, len) }; - self.last_view = Some(ImageView::new_default(image).unwrap()); + self.last_view = Some(ImageView::new_default(image)?); self.capture.request_new_frame(); } WlxFrame::MemPtr(frame) => { log::debug!("{}: New MemPtr frame", self.name); let mut upload = app .graphics - .create_command_buffer(CommandBufferUsage::OneTimeSubmit); + .create_command_buffer(CommandBufferUsage::OneTimeSubmit)?; - let format = fourcc_to_vk(frame.format.fourcc); + let format = fourcc_to_vk(frame.format.fourcc)?; let data = unsafe { slice::from_raw_parts(frame.ptr as *const u8, frame.size) }; let image = - upload.texture2d(frame.format.width, frame.format.height, format, &data); + upload.texture2d(frame.format.width, frame.format.height, format, &data)?; let mut pipeline = None; if mouse.is_some() { let new_pipeline = self.pipeline.get_or_insert_with(|| { let mut pipeline = ScreenPipeline::new(&self.extent, app).unwrap(); self.last_view = Some(pipeline.view.clone()); - pipeline.ensure_mouse_initialized(&mut upload); + pipeline.ensure_mouse_initialized(&mut upload).unwrap(); // TODO pipeline }); pipeline = Some(new_pipeline); } - upload.build_and_execute_now(); + upload.build_and_execute_now()?; if let Some(pipeline) = pipeline { - pipeline.render(image, mouse.as_ref(), app); + pipeline.render(image, mouse.as_ref(), app)?; } else { let view = ImageView::new_default(image).unwrap(); self.last_view = Some(view); @@ -431,12 +440,15 @@ impl OverlayRenderer for ScreenRenderer { } }; } + Ok(()) } - fn pause(&mut self, _app: &mut AppState) { + fn pause(&mut self, _app: &mut AppState) -> anyhow::Result<()> { self.capture.pause(); + Ok(()) } - fn resume(&mut self, _app: &mut AppState) { + fn resume(&mut self, _app: &mut AppState) -> anyhow::Result<()> { self.capture.resume(); + Ok(()) } fn view(&mut self) -> Option> { self.last_view.clone() diff --git a/src/overlays/watch.rs b/src/overlays/watch.rs index b8ea3ed..1483962 100644 --- a/src/overlays/watch.rs +++ b/src/overlays/watch.rs @@ -33,7 +33,10 @@ const FALLBACK_COLOR: Vec3 = Vec3 { pub const WATCH_NAME: &str = "watch"; pub const WATCH_SCALE: f32 = 0.11; -pub fn create_watch(state: &AppState, screens: &[OverlayData]) -> OverlayData +pub fn create_watch( + state: &AppState, + screens: &[OverlayData], +) -> anyhow::Result> where O: Default, { @@ -45,7 +48,7 @@ where state.graphics.clone(), state.format, (), - ); + )?; let empty_str: Arc = Arc::from(""); for elem in config.watch_elements.into_iter() { @@ -275,7 +278,7 @@ where let relative_to = RelativeTo::Hand(state.session.watch_hand); - OverlayData { + Ok(OverlayData { state: OverlayState { name: WATCH_NAME.into(), size: (400, 200), @@ -290,7 +293,7 @@ where }, backend: Box::new(canvas.build()), ..Default::default() - } + }) } enum ElemState { diff --git a/src/state.rs b/src/state.rs index ad37ffb..0715819 100644 --- a/src/state.rs +++ b/src/state.rs @@ -52,7 +52,7 @@ impl AppState { } Ok(AppState { - fc: FontCache::new(), + fc: FontCache::new()?, session: AppSession::load(), tasks: TaskContainer::new(), graphics,