diff --git a/wayvr/src/backend/openvr/lines.rs b/wayvr/src/backend/openvr/lines.rs index 8545d9f..2c99fdb 100644 --- a/wayvr/src/backend/openvr/lines.rs +++ b/wayvr/src/backend/openvr/lines.rs @@ -24,6 +24,7 @@ use wgui::gfx::WGfx; use wlx_common::overlays::{BackendAttrib, BackendAttribValue}; use crate::backend::input::{HoverResult, PointerHit}; +use crate::graphics::ExtentExt; use crate::state::AppState; use crate::subsystem::hid::WheelDelta; use crate::windowing::Z_ORDER_LINES; @@ -200,7 +201,7 @@ impl OverlayBackend for LineBackend { } fn frame_meta(&mut self) -> Option { Some(FrameMeta { - extent: self.view.image().extent(), + extent: self.view.extent_u32arr(), ..Default::default() }) } diff --git a/wayvr/src/backend/openvr/overlay.rs b/wayvr/src/backend/openvr/overlay.rs index ce5356c..ba769f4 100644 --- a/wayvr/src/backend/openvr/overlay.rs +++ b/wayvr/src/backend/openvr/overlay.rs @@ -13,7 +13,7 @@ use vulkano::{ }; use wgui::gfx::WGfx; -use crate::{state::AppState, windowing::window::OverlayWindowData}; +use crate::{graphics::ExtentExt, state::AppState, windowing::window::OverlayWindowData}; use super::helpers::Affine3AConvert; @@ -65,10 +65,10 @@ impl OverlayWindowData { pub(super) fn ensure_staging_image( &mut self, app: &mut AppState, - extent: [u32; 3], + extent: [u32; 2], ) -> anyhow::Result> { if let Some(image_view) = self.data.image_view.as_ref() - && image_view.image().extent() == extent + && image_view.extent_u32arr() == extent { return Ok(image_view.clone()); } diff --git a/wayvr/src/backend/openxr/lines.rs b/wayvr/src/backend/openxr/lines.rs index d73b717..3856d9e 100644 --- a/wayvr/src/backend/openxr/lines.rs +++ b/wayvr/src/backend/openxr/lines.rs @@ -83,7 +83,7 @@ impl LinePool { &Default::default(), )?; - let srd = create_swapchain(xr, app.gfx.clone(), [1, 1, 1], SwapchainOpts::new())?; + let srd = create_swapchain(xr, app.gfx.clone(), [1, 1], 1, SwapchainOpts::new())?; self.lines.insert( id, LineContainer { diff --git a/wayvr/src/backend/openxr/mod.rs b/wayvr/src/backend/openxr/mod.rs index 9d93742..799db9b 100644 --- a/wayvr/src/backend/openxr/mod.rs +++ b/wayvr/src/backend/openxr/mod.rs @@ -10,7 +10,7 @@ use input::OpenXrInputSource; use openxr as xr; use skybox::create_skybox; use vulkano::{Handle, VulkanObject}; -use wlx_common::overlays::ToastTopic; +use wlx_common::overlays::{StereoMode, ToastTopic}; use crate::{ FRAME_COUNTER, RUNNING, @@ -391,7 +391,8 @@ pub fn openxr_run(show_by_default: bool, headless: bool) -> Result<(), BackendEr if should_render { log::trace!("{}: render new frame", o.config.name); let meta = o.config.backend.frame_meta().unwrap(); // want panic - let wsi = o.ensure_swapchain_acquire(&app, &xr_state, meta.extent)?; + let stereo = !matches!(meta.stereo, StereoMode::None); + let wsi = o.ensure_swapchain_acquire(&app, &xr_state, meta.extent, stereo)?; let tgt = RenderTarget { views: wsi.views }; let mut rdr = RenderResources::new(app.gfx.clone(), tgt, &meta, alpha)?; o.render(&mut app, &mut rdr)?; diff --git a/wayvr/src/backend/openxr/overlay.rs b/wayvr/src/backend/openxr/overlay.rs index db4c253..00fc738 100644 --- a/wayvr/src/backend/openxr/overlay.rs +++ b/wayvr/src/backend/openxr/overlay.rs @@ -25,10 +25,14 @@ impl OverlayWindowData { &'a mut self, app: &AppState, xr: &'a XrState, - extent: [u32; 3], + extent: [u32; 2], + stereo: bool, ) -> anyhow::Result { + let array_size = if stereo { 2 } else { 1 }; + if let Some(swapchain) = self.data.swapchain.as_mut() && swapchain.extent == extent + && swapchain.array_size == array_size { return swapchain.acquire_wait_image(); } @@ -38,9 +42,15 @@ impl OverlayWindowData { self.config.name, extent[0], extent[1], - extent[2], + array_size, ); - let mut swapchain = create_swapchain(xr, app.gfx.clone(), extent, SwapchainOpts::new())?; + let mut swapchain = create_swapchain( + xr, + app.gfx.clone(), + extent, + array_size, + SwapchainOpts::new(), + )?; let tgt = swapchain.acquire_wait_image()?; self.data.swapchain = Some(swapchain); Ok(tgt) @@ -65,7 +75,7 @@ impl OverlayWindowData { // overlays without active_state don't get queued for present let state = self.config.active_state.as_ref().unwrap(); - let sub_images: SmallVec<[_; 2]> = if swapchain.extent[2] > 1 { + let sub_images: SmallVec<[_; 2]> = if swapchain.array_size > 1 { smallvec![ (swapchain.get_subimage(0), EyeVisibility::LEFT), (swapchain.get_subimage(1), EyeVisibility::RIGHT), diff --git a/wayvr/src/backend/openxr/skybox.rs b/wayvr/src/backend/openxr/skybox.rs index 839bb17..2d60e91 100644 --- a/wayvr/src/backend/openxr/skybox.rs +++ b/wayvr/src/backend/openxr/skybox.rs @@ -92,8 +92,8 @@ impl Skybox { } let opts = SwapchainOpts::new().immutable(); - let extent = self.view.image().extent(); - let mut swapchain = create_swapchain(xr, app.gfx.clone(), extent, opts)?; + let extent = self.view.extent_u32arr(); + let mut swapchain = create_swapchain(xr, app.gfx.clone(), extent, 1, opts)?; let tgt = swapchain .acquire_wait_image()? .views @@ -141,11 +141,12 @@ impl Skybox { return Ok(()); } - let extent = [1024, 1024, 1]; + let extent = [1024, 1024]; let mut swapchain = create_swapchain( xr, app.gfx.clone(), extent, + 1, SwapchainOpts::new().immutable(), )?; let pipeline = app.gfx.create_pipeline( diff --git a/wayvr/src/backend/openxr/swapchain.rs b/wayvr/src/backend/openxr/swapchain.rs index 2a1ab26..0211456 100644 --- a/wayvr/src/backend/openxr/swapchain.rs +++ b/wayvr/src/backend/openxr/swapchain.rs @@ -35,7 +35,8 @@ impl SwapchainOpts { pub(super) fn create_swapchain( xr: &XrState, gfx: Arc, - extent: [u32; 3], + extent: [u32; 2], + array_size: u32, opts: SwapchainOpts, ) -> anyhow::Result { let create_flags = if opts.immutable { @@ -52,7 +53,7 @@ pub(super) fn create_swapchain( width: extent[0], height: extent[1], face_count: 1, - array_size: extent[2], + array_size, mip_count: 1, })?; @@ -69,7 +70,7 @@ pub(super) fn create_swapchain( ImageCreateInfo { format: gfx.surface_format as _, extent: [extent[0], extent[1], 1], - array_layers: extent[2], + array_layers: array_size, usage: ImageUsage::COLOR_ATTACHMENT, ..Default::default() }, @@ -78,7 +79,7 @@ pub(super) fn create_swapchain( // SAFETY: OpenXR guarantees that the image is a swapchain image, thus has memory backing it. let image = Arc::new(unsafe { raw_image.assume_bound() }); let mut wsi = WlxSwapchainImage::default(); - for d in 0..extent[2] { + for d in 0..array_size { let mut create_info = ImageViewCreateInfo::from_image(&image); create_info.subresource_range.array_layers = d..d + 1; wsi.views.push(ImageView::new(image.clone(), create_info)?); @@ -93,6 +94,7 @@ pub(super) fn create_swapchain( swapchain, images, extent, + array_size, }) } @@ -105,7 +107,8 @@ pub(super) struct WlxSwapchain { acquired: bool, pub(super) ever_acquired: bool, pub(super) swapchain: xr::Swapchain, - pub(super) extent: [u32; 3], + pub(super) extent: [u32; 2], + pub(super) array_size: u32, pub(super) images: SmallVec<[WlxSwapchainImage; 4]>, } diff --git a/wayvr/src/gui/panel/mod.rs b/wayvr/src/gui/panel/mod.rs index 88fe379..32da3d2 100644 --- a/wayvr/src/gui/panel/mod.rs +++ b/wayvr/src/gui/panel/mod.rs @@ -1,4 +1,4 @@ -use std::{cell::RefCell, collections::HashMap, rc::Rc}; +use std::{cell::RefCell, rc::Rc}; use anyhow::Context; use button::setup_custom_button; @@ -353,7 +353,6 @@ impl OverlayBackend for GuiPanel { extent: [ self.max_size.x.min(self.layout.content_size.x) as _, self.max_size.y.min(self.layout.content_size.y) as _, - 1, ], ..Default::default() }) diff --git a/wayvr/src/overlays/dashboard.rs b/wayvr/src/overlays/dashboard.rs index da86741..548c1a2 100644 --- a/wayvr/src/overlays/dashboard.rs +++ b/wayvr/src/overlays/dashboard.rs @@ -185,7 +185,7 @@ impl OverlayBackend for DashFrontend { fn frame_meta(&mut self) -> Option { Some(FrameMeta { clear: WGfxClearMode::Clear([0., 0., 0., 0.]), - extent: [DASH_RES_U32A[0], DASH_RES_U32A[1], 1], + extent: [DASH_RES_U32A[0], DASH_RES_U32A[1]], ..Default::default() }) } diff --git a/wayvr/src/overlays/screen/backend.rs b/wayvr/src/overlays/screen/backend.rs index 227c246..c84cdfd 100644 --- a/wayvr/src/overlays/screen/backend.rs +++ b/wayvr/src/overlays/screen/backend.rs @@ -11,7 +11,6 @@ use crate::{ XrBackend, input::{HoverResult, PointerHit, PointerMode}, }, - graphics::ExtentExt, overlays::screen::capture::MyFirstDmaExporter, state::AppState, subsystem::hid::{MOUSE_LEFT, MOUSE_MIDDLE, MOUSE_RIGHT, WheelDelta}, @@ -208,31 +207,22 @@ impl OverlayBackend for ScreenBackend { } if let Some(frame) = self.capture.receive() { - let mut meta = frame.get_frame_meta(&app.session.config); + let stereo = self.stereo.unwrap_or(StereoMode::None); + let meta = frame.get_frame_meta(&app.session.config, stereo); if let Some(pipeline) = self.pipeline.as_mut() { - meta.extent[2] = pipeline.get_depth(); - if self - .meta - .is_some_and(|old| old.extent[..2] != meta.extent[..2]) - { + if self.meta.is_some_and(|old| old.extent != meta.extent) { pipeline.set_extent( app, [meta.extent[0] as _, meta.extent[1] as _], [0., 0.], )?; - self.interaction_transform = Some(ui_transform(meta.extent.extent_u32arr())); + self.interaction_transform = Some(ui_transform(meta.extent)); } } else { - let pipeline = ScreenPipeline::new( - &meta, - app, - self.stereo.unwrap_or(StereoMode::None), - [0., 0.], - )?; - meta.extent[2] = pipeline.get_depth(); + let pipeline = ScreenPipeline::new(&meta, app, stereo, [0., 0.])?; self.pipeline = Some(pipeline); - self.interaction_transform = Some(ui_transform(meta.extent.extent_u32arr())); + self.interaction_transform = Some(ui_transform(meta.extent)); } self.meta = Some(meta); @@ -344,14 +334,14 @@ impl OverlayBackend for ScreenBackend { _ => None, } } - fn set_attrib(&mut self, app: &mut AppState, value: BackendAttribValue) -> bool { + fn set_attrib(&mut self, _app: &mut AppState, value: BackendAttribValue) -> bool { match value { BackendAttribValue::Stereo(new) => { if let Some(stereo) = self.stereo.as_mut() { log::debug!("{}: stereo: {stereo:?} → {new:?}", self.name); *stereo = new; if let Some(pipeline) = self.pipeline.as_mut() { - pipeline.set_stereo(app, new).unwrap(); // only panics if gfx is dead + pipeline.ensure_stereo(new); } true } else { diff --git a/wayvr/src/overlays/screen/capture.rs b/wayvr/src/overlays/screen/capture.rs index 7c6a726..d3d0af5 100644 --- a/wayvr/src/overlays/screen/capture.rs +++ b/wayvr/src/overlays/screen/capture.rs @@ -101,20 +101,21 @@ impl ScreenPipeline { buf_alpha, stereo, }; - me.set_stereo(app, stereo)?; + me.ensure_stereo(stereo); Ok(me) } - pub fn set_stereo(&mut self, app: &mut AppState, stereo: StereoMode) -> anyhow::Result<()> { + pub fn ensure_stereo(&mut self, stereo: StereoMode) { + if self.stereo == stereo { + return; + } + self.stereo = stereo; + self.pass.clear(); // ensure_depth will repopulate + } - let depth = if matches!(stereo, StereoMode::None) { - 1 - } else { - 2 - }; - - if self.pass.len() < depth { + fn ensure_depth(&mut self, app: &mut AppState, depth: usize) -> anyhow::Result<()> { + while self.pass.len() < depth { self.pass.push(Self::create_pass( app, self.pipeline.clone(), @@ -124,21 +125,17 @@ impl ScreenPipeline { )?); } - if self.pass.len() > depth { + while self.pass.len() > depth { self.pass.pop(); } for (eye, current) in self.pass.iter_mut().enumerate() { - let verts = stereo_mode_to_verts(stereo, eye); + let verts = stereo_mode_to_verts(self.stereo, eye); current.buf_vert.write()?.copy_from_slice(&verts); } Ok(()) } - pub fn get_depth(&self) -> u32 { - self.pass.len() as _ - } - pub fn set_extent( &mut self, app: &mut AppState, @@ -147,18 +144,7 @@ impl ScreenPipeline { ) -> anyhow::Result<()> { self.extentf = extentf; self.offsetf = offsetf; - - for (eye, pass) in self.pass.iter_mut().enumerate() { - *pass = Self::create_pass( - app, - self.pipeline.clone(), - extentf, - offsetf, - self.buf_alpha.clone(), - )?; - let verts = stereo_mode_to_verts(self.stereo, eye); - pass.buf_vert.write()?.copy_from_slice(&verts); - } + self.pass.clear(); self.mouse = Self::create_mouse_pass( app, @@ -251,6 +237,8 @@ impl ScreenPipeline { app: &mut AppState, rdr: &mut RenderResources, ) -> anyhow::Result<()> { + self.ensure_depth(app, rdr.cmd_bufs.len())?; + self.buf_alpha.write()?[0] = rdr.alpha; for (eye, cmd_buf) in rdr.cmd_bufs.iter_mut().enumerate() { @@ -503,12 +491,13 @@ pub(super) struct WlxCaptureOut { } impl WlxCaptureOut { - pub(super) fn get_frame_meta(&self, config: &GeneralConfig) -> FrameMeta { + pub(super) fn get_frame_meta(&self, config: &GeneralConfig, stereo: StereoMode) -> FrameMeta { FrameMeta { clear: WGfxClearMode::DontCare, extent: extent_from_format(self.format, config), transform: affine_from_format(&self.format), format: self.image.format(), + stereo, } } } @@ -721,7 +710,7 @@ const fn receive_callback_dummy(_: &DummyDrmExporter, frame: WlxFrame) -> Option Some(frame) } -fn extent_from_format(fmt: FrameFormat, config: &GeneralConfig) -> [u32; 3] { +fn extent_from_format(fmt: FrameFormat, config: &GeneralConfig) -> [u32; 2] { // screens above a certain resolution will have severe aliasing let height_limit = if config.screen_render_down { u32::from(config.screen_max_height.min(2560)) @@ -731,7 +720,7 @@ fn extent_from_format(fmt: FrameFormat, config: &GeneralConfig) -> [u32; 3] { let h = fmt.height.min(height_limit); let w = (fmt.width as f32 / fmt.height as f32 * h as f32) as u32; - [w, h, 1] + [w, h] } fn affine_from_format(format: &FrameFormat) -> Affine3A { diff --git a/wayvr/src/overlays/screen/mirror.rs b/wayvr/src/overlays/screen/mirror.rs index 0cc5f5a..0feabf8 100644 --- a/wayvr/src/overlays/screen/mirror.rs +++ b/wayvr/src/overlays/screen/mirror.rs @@ -49,7 +49,7 @@ pub struct MirrorBackend { name: Arc, renderer: Option, selector: Option, - last_extent: [u32; 3], + last_extent: [u32; 2], interaction_transform: Option, } impl MirrorBackend { @@ -59,7 +59,7 @@ impl MirrorBackend { name, renderer: None, selector: Some(selector), - last_extent: [0; 3], + last_extent: [0; 2], interaction_transform: None, } } @@ -131,7 +131,7 @@ impl OverlayBackend for MirrorBackend { let extent = meta.extent; if self.last_extent != extent { self.last_extent = extent; - self.interaction_transform = Some(ui_transform([extent[0], extent[1]])); + self.interaction_transform = Some(ui_transform(extent)); } } diff --git a/wayvr/src/overlays/wayvr.rs b/wayvr/src/overlays/wayvr.rs index 6ddf6fe..a00e954 100644 --- a/wayvr/src/overlays/wayvr.rs +++ b/wayvr/src/overlays/wayvr.rs @@ -111,7 +111,7 @@ pub struct WvrWindowBackend { stereo: Option, cur_image: Option>, panel: GuiPanel, - inner_extent: [u32; 3], + inner_extent: [u32; 2], mouse_transform: Affine2, uv_range: RangeInclusive, panel_hovered: bool, @@ -208,7 +208,7 @@ impl WvrWindowBackend { None }, cur_image: None, - inner_extent: [0, 0, 1], + inner_extent: [0, 0], panel, mouse_transform: Affine2::ZERO, uv_range: 0.0..=1.0, @@ -217,7 +217,7 @@ impl WvrWindowBackend { } fn apply_extent(&mut self, app: &mut AppState, meta: &FrameMeta) -> anyhow::Result<()> { - self.interaction_transform = Some(ui_transform(meta.extent.extent_u32arr())); + self.interaction_transform = Some(ui_transform(meta.extent)); let scale = vec2( ((meta.extent[0] + BORDER_SIZE * 2) as f32) / (meta.extent[0] as f32), @@ -300,7 +300,7 @@ impl OverlayBackend for WvrWindowBackend { with_states(toplevel.wl_surface(), |states| { if let Some(surf) = SurfaceBufWithImage::get_from_surface(states) { let mut meta = FrameMeta { - extent: surf.image.image().extent(), + extent: surf.image.extent_u32arr(), format: surf.image.format(), clear: WGfxClearMode::Clear([0.0, 0.0, 0.0, 0.0]), ..Default::default() @@ -310,8 +310,7 @@ impl OverlayBackend for WvrWindowBackend { meta.extent[1] += BORDER_SIZE * 2 + BAR_SIZE; if let Some(pipeline) = self.pipeline.as_mut() { - meta.extent[2] = pipeline.get_depth(); - if self.inner_extent[..2] != inner_extent[..2] { + if self.inner_extent != inner_extent { pipeline.set_extent( app, [inner_extent[0] as _, inner_extent[1] as _], @@ -327,7 +326,6 @@ impl OverlayBackend for WvrWindowBackend { self.stereo.unwrap_or(StereoMode::None), [BORDER_SIZE as _, (BAR_SIZE + BORDER_SIZE) as _], )?; - meta.extent[2] = pipeline.get_depth(); self.apply_extent(app, &meta)?; self.pipeline = Some(pipeline); } @@ -388,7 +386,8 @@ impl OverlayBackend for WvrWindowBackend { .render(image, self.mouse.as_ref(), app, rdr)?; for (popup_img, point) in &self.popups { - let extentf = self.meta.as_ref().unwrap().extent.extent_f32(); + let meta = self.meta.as_ref().unwrap(); + let extentf = [meta.extent[0] as f32, meta.extent[1] as f32]; let popup_extentf = popup_img.extent_f32(); let mut buf_vert = app .gfx @@ -551,14 +550,14 @@ impl OverlayBackend for WvrWindowBackend { _ => None, } } - fn set_attrib(&mut self, app: &mut AppState, value: BackendAttribValue) -> bool { + fn set_attrib(&mut self, _app: &mut AppState, value: BackendAttribValue) -> bool { match value { BackendAttribValue::Stereo(new) => { if let Some(stereo) = self.stereo.as_mut() { log::debug!("{}: stereo: {stereo:?} → {new:?}", self.name); *stereo = new; if let Some(pipeline) = self.pipeline.as_mut() { - pipeline.set_stereo(app, new).unwrap(); // only panics if gfx is dead + pipeline.ensure_stereo(new); } true } else { diff --git a/wayvr/src/windowing/backend.rs b/wayvr/src/windowing/backend.rs index 985ae29..7b30803 100644 --- a/wayvr/src/windowing/backend.rs +++ b/wayvr/src/windowing/backend.rs @@ -7,7 +7,7 @@ use wgui::gfx::{ cmd::{GfxCommandBuffer, WGfxClearMode}, }; use wlx_common::{ - overlays::{BackendAttrib, BackendAttribValue}, + overlays::{BackendAttrib, BackendAttribValue, StereoMode}, windowing::Positioning, }; @@ -16,7 +16,7 @@ use crate::{ input::{HoverResult, PointerHit}, task::ModifyPanelCommand, }, - graphics::{ExtentExt, RenderResult}, + graphics::RenderResult, overlays::wayvr::WvrCommand, state::AppState, subsystem::hid::WheelDelta, @@ -25,10 +25,11 @@ use crate::{ #[derive(Default, Clone, Copy)] pub struct FrameMeta { - pub extent: [u32; 3], + pub extent: [u32; 2], pub transform: Affine3A, pub format: Format, pub clear: WGfxClearMode, + pub stereo: StereoMode, } #[derive(Debug, Clone, Copy)] @@ -70,7 +71,7 @@ impl RenderResources { Ok(Self { cmd_bufs, alpha, - extent: meta.extent.extent_u32arr(), + extent: meta.extent, }) } diff --git a/wlx-common/src/overlays.rs b/wlx-common/src/overlays.rs index 4544648..f2b8c25 100644 --- a/wlx-common/src/overlays.rs +++ b/wlx-common/src/overlays.rs @@ -34,7 +34,7 @@ pub enum BackendAttribValue { Icon(Arc), } -#[derive(Default, Debug, Clone, Copy, Serialize, Deserialize)] +#[derive(Default, Debug, Clone, Copy, Serialize, Deserialize, PartialEq)] pub enum StereoMode { #[default] None,