rework stereo mode

This commit is contained in:
galister
2026-01-10 12:20:42 +09:00
parent d11b33a579
commit 5dc6b66cc1
15 changed files with 82 additions and 88 deletions

View File

@@ -24,6 +24,7 @@ use wgui::gfx::WGfx;
use wlx_common::overlays::{BackendAttrib, BackendAttribValue}; use wlx_common::overlays::{BackendAttrib, BackendAttribValue};
use crate::backend::input::{HoverResult, PointerHit}; use crate::backend::input::{HoverResult, PointerHit};
use crate::graphics::ExtentExt;
use crate::state::AppState; use crate::state::AppState;
use crate::subsystem::hid::WheelDelta; use crate::subsystem::hid::WheelDelta;
use crate::windowing::Z_ORDER_LINES; use crate::windowing::Z_ORDER_LINES;
@@ -200,7 +201,7 @@ impl OverlayBackend for LineBackend {
} }
fn frame_meta(&mut self) -> Option<FrameMeta> { fn frame_meta(&mut self) -> Option<FrameMeta> {
Some(FrameMeta { Some(FrameMeta {
extent: self.view.image().extent(), extent: self.view.extent_u32arr(),
..Default::default() ..Default::default()
}) })
} }

View File

@@ -13,7 +13,7 @@ use vulkano::{
}; };
use wgui::gfx::WGfx; use wgui::gfx::WGfx;
use crate::{state::AppState, windowing::window::OverlayWindowData}; use crate::{graphics::ExtentExt, state::AppState, windowing::window::OverlayWindowData};
use super::helpers::Affine3AConvert; use super::helpers::Affine3AConvert;
@@ -65,10 +65,10 @@ impl OverlayWindowData<OpenVrOverlayData> {
pub(super) fn ensure_staging_image( pub(super) fn ensure_staging_image(
&mut self, &mut self,
app: &mut AppState, app: &mut AppState,
extent: [u32; 3], extent: [u32; 2],
) -> anyhow::Result<Arc<ImageView>> { ) -> anyhow::Result<Arc<ImageView>> {
if let Some(image_view) = self.data.image_view.as_ref() 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()); return Ok(image_view.clone());
} }

View File

@@ -83,7 +83,7 @@ impl LinePool {
&Default::default(), &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( self.lines.insert(
id, id,
LineContainer { LineContainer {

View File

@@ -10,7 +10,7 @@ use input::OpenXrInputSource;
use openxr as xr; use openxr as xr;
use skybox::create_skybox; use skybox::create_skybox;
use vulkano::{Handle, VulkanObject}; use vulkano::{Handle, VulkanObject};
use wlx_common::overlays::ToastTopic; use wlx_common::overlays::{StereoMode, ToastTopic};
use crate::{ use crate::{
FRAME_COUNTER, RUNNING, FRAME_COUNTER, RUNNING,
@@ -391,7 +391,8 @@ pub fn openxr_run(show_by_default: bool, headless: bool) -> Result<(), BackendEr
if should_render { if should_render {
log::trace!("{}: render new frame", o.config.name); log::trace!("{}: render new frame", o.config.name);
let meta = o.config.backend.frame_meta().unwrap(); // want panic 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 tgt = RenderTarget { views: wsi.views };
let mut rdr = RenderResources::new(app.gfx.clone(), tgt, &meta, alpha)?; let mut rdr = RenderResources::new(app.gfx.clone(), tgt, &meta, alpha)?;
o.render(&mut app, &mut rdr)?; o.render(&mut app, &mut rdr)?;

View File

@@ -25,10 +25,14 @@ impl OverlayWindowData<OpenXrOverlayData> {
&'a mut self, &'a mut self,
app: &AppState, app: &AppState,
xr: &'a XrState, xr: &'a XrState,
extent: [u32; 3], extent: [u32; 2],
stereo: bool,
) -> anyhow::Result<WlxSwapchainImage> { ) -> anyhow::Result<WlxSwapchainImage> {
let array_size = if stereo { 2 } else { 1 };
if let Some(swapchain) = self.data.swapchain.as_mut() if let Some(swapchain) = self.data.swapchain.as_mut()
&& swapchain.extent == extent && swapchain.extent == extent
&& swapchain.array_size == array_size
{ {
return swapchain.acquire_wait_image(); return swapchain.acquire_wait_image();
} }
@@ -38,9 +42,15 @@ impl OverlayWindowData<OpenXrOverlayData> {
self.config.name, self.config.name,
extent[0], extent[0],
extent[1], 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()?; let tgt = swapchain.acquire_wait_image()?;
self.data.swapchain = Some(swapchain); self.data.swapchain = Some(swapchain);
Ok(tgt) Ok(tgt)
@@ -65,7 +75,7 @@ impl OverlayWindowData<OpenXrOverlayData> {
// overlays without active_state don't get queued for present // overlays without active_state don't get queued for present
let state = self.config.active_state.as_ref().unwrap(); 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![ smallvec![
(swapchain.get_subimage(0), EyeVisibility::LEFT), (swapchain.get_subimage(0), EyeVisibility::LEFT),
(swapchain.get_subimage(1), EyeVisibility::RIGHT), (swapchain.get_subimage(1), EyeVisibility::RIGHT),

View File

@@ -92,8 +92,8 @@ impl Skybox {
} }
let opts = SwapchainOpts::new().immutable(); let opts = SwapchainOpts::new().immutable();
let extent = self.view.image().extent(); let extent = self.view.extent_u32arr();
let mut swapchain = create_swapchain(xr, app.gfx.clone(), extent, opts)?; let mut swapchain = create_swapchain(xr, app.gfx.clone(), extent, 1, opts)?;
let tgt = swapchain let tgt = swapchain
.acquire_wait_image()? .acquire_wait_image()?
.views .views
@@ -141,11 +141,12 @@ impl Skybox {
return Ok(()); return Ok(());
} }
let extent = [1024, 1024, 1]; let extent = [1024, 1024];
let mut swapchain = create_swapchain( let mut swapchain = create_swapchain(
xr, xr,
app.gfx.clone(), app.gfx.clone(),
extent, extent,
1,
SwapchainOpts::new().immutable(), SwapchainOpts::new().immutable(),
)?; )?;
let pipeline = app.gfx.create_pipeline( let pipeline = app.gfx.create_pipeline(

View File

@@ -35,7 +35,8 @@ impl SwapchainOpts {
pub(super) fn create_swapchain( pub(super) fn create_swapchain(
xr: &XrState, xr: &XrState,
gfx: Arc<WGfx>, gfx: Arc<WGfx>,
extent: [u32; 3], extent: [u32; 2],
array_size: u32,
opts: SwapchainOpts, opts: SwapchainOpts,
) -> anyhow::Result<WlxSwapchain> { ) -> anyhow::Result<WlxSwapchain> {
let create_flags = if opts.immutable { let create_flags = if opts.immutable {
@@ -52,7 +53,7 @@ pub(super) fn create_swapchain(
width: extent[0], width: extent[0],
height: extent[1], height: extent[1],
face_count: 1, face_count: 1,
array_size: extent[2], array_size,
mip_count: 1, mip_count: 1,
})?; })?;
@@ -69,7 +70,7 @@ pub(super) fn create_swapchain(
ImageCreateInfo { ImageCreateInfo {
format: gfx.surface_format as _, format: gfx.surface_format as _,
extent: [extent[0], extent[1], 1], extent: [extent[0], extent[1], 1],
array_layers: extent[2], array_layers: array_size,
usage: ImageUsage::COLOR_ATTACHMENT, usage: ImageUsage::COLOR_ATTACHMENT,
..Default::default() ..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. // 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 image = Arc::new(unsafe { raw_image.assume_bound() });
let mut wsi = WlxSwapchainImage::default(); 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); let mut create_info = ImageViewCreateInfo::from_image(&image);
create_info.subresource_range.array_layers = d..d + 1; create_info.subresource_range.array_layers = d..d + 1;
wsi.views.push(ImageView::new(image.clone(), create_info)?); wsi.views.push(ImageView::new(image.clone(), create_info)?);
@@ -93,6 +94,7 @@ pub(super) fn create_swapchain(
swapchain, swapchain,
images, images,
extent, extent,
array_size,
}) })
} }
@@ -105,7 +107,8 @@ pub(super) struct WlxSwapchain {
acquired: bool, acquired: bool,
pub(super) ever_acquired: bool, pub(super) ever_acquired: bool,
pub(super) swapchain: xr::Swapchain<xr::Vulkan>, pub(super) swapchain: xr::Swapchain<xr::Vulkan>,
pub(super) extent: [u32; 3], pub(super) extent: [u32; 2],
pub(super) array_size: u32,
pub(super) images: SmallVec<[WlxSwapchainImage; 4]>, pub(super) images: SmallVec<[WlxSwapchainImage; 4]>,
} }

View File

@@ -1,4 +1,4 @@
use std::{cell::RefCell, collections::HashMap, rc::Rc}; use std::{cell::RefCell, rc::Rc};
use anyhow::Context; use anyhow::Context;
use button::setup_custom_button; use button::setup_custom_button;
@@ -353,7 +353,6 @@ impl<S: 'static> OverlayBackend for GuiPanel<S> {
extent: [ extent: [
self.max_size.x.min(self.layout.content_size.x) as _, self.max_size.x.min(self.layout.content_size.x) as _,
self.max_size.y.min(self.layout.content_size.y) as _, self.max_size.y.min(self.layout.content_size.y) as _,
1,
], ],
..Default::default() ..Default::default()
}) })

View File

@@ -185,7 +185,7 @@ impl OverlayBackend for DashFrontend {
fn frame_meta(&mut self) -> Option<FrameMeta> { fn frame_meta(&mut self) -> Option<FrameMeta> {
Some(FrameMeta { Some(FrameMeta {
clear: WGfxClearMode::Clear([0., 0., 0., 0.]), 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() ..Default::default()
}) })
} }

View File

@@ -11,7 +11,6 @@ use crate::{
XrBackend, XrBackend,
input::{HoverResult, PointerHit, PointerMode}, input::{HoverResult, PointerHit, PointerMode},
}, },
graphics::ExtentExt,
overlays::screen::capture::MyFirstDmaExporter, overlays::screen::capture::MyFirstDmaExporter,
state::AppState, state::AppState,
subsystem::hid::{MOUSE_LEFT, MOUSE_MIDDLE, MOUSE_RIGHT, WheelDelta}, subsystem::hid::{MOUSE_LEFT, MOUSE_MIDDLE, MOUSE_RIGHT, WheelDelta},
@@ -208,31 +207,22 @@ impl OverlayBackend for ScreenBackend {
} }
if let Some(frame) = self.capture.receive() { 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() { if let Some(pipeline) = self.pipeline.as_mut() {
meta.extent[2] = pipeline.get_depth(); if self.meta.is_some_and(|old| old.extent != meta.extent) {
if self
.meta
.is_some_and(|old| old.extent[..2] != meta.extent[..2])
{
pipeline.set_extent( pipeline.set_extent(
app, app,
[meta.extent[0] as _, meta.extent[1] as _], [meta.extent[0] as _, meta.extent[1] as _],
[0., 0.], [0., 0.],
)?; )?;
self.interaction_transform = Some(ui_transform(meta.extent.extent_u32arr())); self.interaction_transform = Some(ui_transform(meta.extent));
} }
} else { } else {
let pipeline = ScreenPipeline::new( let pipeline = ScreenPipeline::new(&meta, app, stereo, [0., 0.])?;
&meta,
app,
self.stereo.unwrap_or(StereoMode::None),
[0., 0.],
)?;
meta.extent[2] = pipeline.get_depth();
self.pipeline = Some(pipeline); 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); self.meta = Some(meta);
@@ -344,14 +334,14 @@ impl OverlayBackend for ScreenBackend {
_ => None, _ => 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 { match value {
BackendAttribValue::Stereo(new) => { BackendAttribValue::Stereo(new) => {
if let Some(stereo) = self.stereo.as_mut() { if let Some(stereo) = self.stereo.as_mut() {
log::debug!("{}: stereo: {stereo:?} → {new:?}", self.name); log::debug!("{}: stereo: {stereo:?} → {new:?}", self.name);
*stereo = new; *stereo = new;
if let Some(pipeline) = self.pipeline.as_mut() { 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 true
} else { } else {

View File

@@ -101,20 +101,21 @@ impl ScreenPipeline {
buf_alpha, buf_alpha,
stereo, stereo,
}; };
me.set_stereo(app, stereo)?; me.ensure_stereo(stereo);
Ok(me) 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.stereo = stereo;
self.pass.clear(); // ensure_depth will repopulate
}
let depth = if matches!(stereo, StereoMode::None) { fn ensure_depth(&mut self, app: &mut AppState, depth: usize) -> anyhow::Result<()> {
1 while self.pass.len() < depth {
} else {
2
};
if self.pass.len() < depth {
self.pass.push(Self::create_pass( self.pass.push(Self::create_pass(
app, app,
self.pipeline.clone(), self.pipeline.clone(),
@@ -124,21 +125,17 @@ impl ScreenPipeline {
)?); )?);
} }
if self.pass.len() > depth { while self.pass.len() > depth {
self.pass.pop(); self.pass.pop();
} }
for (eye, current) in self.pass.iter_mut().enumerate() { 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); current.buf_vert.write()?.copy_from_slice(&verts);
} }
Ok(()) Ok(())
} }
pub fn get_depth(&self) -> u32 {
self.pass.len() as _
}
pub fn set_extent( pub fn set_extent(
&mut self, &mut self,
app: &mut AppState, app: &mut AppState,
@@ -147,18 +144,7 @@ impl ScreenPipeline {
) -> anyhow::Result<()> { ) -> anyhow::Result<()> {
self.extentf = extentf; self.extentf = extentf;
self.offsetf = offsetf; self.offsetf = offsetf;
self.pass.clear();
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.mouse = Self::create_mouse_pass( self.mouse = Self::create_mouse_pass(
app, app,
@@ -251,6 +237,8 @@ impl ScreenPipeline {
app: &mut AppState, app: &mut AppState,
rdr: &mut RenderResources, rdr: &mut RenderResources,
) -> anyhow::Result<()> { ) -> anyhow::Result<()> {
self.ensure_depth(app, rdr.cmd_bufs.len())?;
self.buf_alpha.write()?[0] = rdr.alpha; self.buf_alpha.write()?[0] = rdr.alpha;
for (eye, cmd_buf) in rdr.cmd_bufs.iter_mut().enumerate() { for (eye, cmd_buf) in rdr.cmd_bufs.iter_mut().enumerate() {
@@ -503,12 +491,13 @@ pub(super) struct WlxCaptureOut {
} }
impl 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 { FrameMeta {
clear: WGfxClearMode::DontCare, clear: WGfxClearMode::DontCare,
extent: extent_from_format(self.format, config), extent: extent_from_format(self.format, config),
transform: affine_from_format(&self.format), transform: affine_from_format(&self.format),
format: self.image.format(), format: self.image.format(),
stereo,
} }
} }
} }
@@ -721,7 +710,7 @@ const fn receive_callback_dummy(_: &DummyDrmExporter, frame: WlxFrame) -> Option
Some(frame) 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 // screens above a certain resolution will have severe aliasing
let height_limit = if config.screen_render_down { let height_limit = if config.screen_render_down {
u32::from(config.screen_max_height.min(2560)) 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 h = fmt.height.min(height_limit);
let w = (fmt.width as f32 / fmt.height as f32 * h as f32) as u32; 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 { fn affine_from_format(format: &FrameFormat) -> Affine3A {

View File

@@ -49,7 +49,7 @@ pub struct MirrorBackend {
name: Arc<str>, name: Arc<str>,
renderer: Option<ScreenBackend>, renderer: Option<ScreenBackend>,
selector: Option<PinnedSelectorFuture>, selector: Option<PinnedSelectorFuture>,
last_extent: [u32; 3], last_extent: [u32; 2],
interaction_transform: Option<Affine2>, interaction_transform: Option<Affine2>,
} }
impl MirrorBackend { impl MirrorBackend {
@@ -59,7 +59,7 @@ impl MirrorBackend {
name, name,
renderer: None, renderer: None,
selector: Some(selector), selector: Some(selector),
last_extent: [0; 3], last_extent: [0; 2],
interaction_transform: None, interaction_transform: None,
} }
} }
@@ -131,7 +131,7 @@ impl OverlayBackend for MirrorBackend {
let extent = meta.extent; let extent = meta.extent;
if self.last_extent != extent { if self.last_extent != extent {
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));
} }
} }

View File

@@ -111,7 +111,7 @@ pub struct WvrWindowBackend {
stereo: Option<StereoMode>, stereo: Option<StereoMode>,
cur_image: Option<Arc<ImageView>>, cur_image: Option<Arc<ImageView>>,
panel: GuiPanel<WindowHandle>, panel: GuiPanel<WindowHandle>,
inner_extent: [u32; 3], inner_extent: [u32; 2],
mouse_transform: Affine2, mouse_transform: Affine2,
uv_range: RangeInclusive<f32>, uv_range: RangeInclusive<f32>,
panel_hovered: bool, panel_hovered: bool,
@@ -208,7 +208,7 @@ impl WvrWindowBackend {
None None
}, },
cur_image: None, cur_image: None,
inner_extent: [0, 0, 1], inner_extent: [0, 0],
panel, panel,
mouse_transform: Affine2::ZERO, mouse_transform: Affine2::ZERO,
uv_range: 0.0..=1.0, uv_range: 0.0..=1.0,
@@ -217,7 +217,7 @@ impl WvrWindowBackend {
} }
fn apply_extent(&mut self, app: &mut AppState, meta: &FrameMeta) -> anyhow::Result<()> { 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( let scale = vec2(
((meta.extent[0] + BORDER_SIZE * 2) as f32) / (meta.extent[0] as f32), ((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| { with_states(toplevel.wl_surface(), |states| {
if let Some(surf) = SurfaceBufWithImage::get_from_surface(states) { if let Some(surf) = SurfaceBufWithImage::get_from_surface(states) {
let mut meta = FrameMeta { let mut meta = FrameMeta {
extent: surf.image.image().extent(), extent: surf.image.extent_u32arr(),
format: surf.image.format(), format: surf.image.format(),
clear: WGfxClearMode::Clear([0.0, 0.0, 0.0, 0.0]), clear: WGfxClearMode::Clear([0.0, 0.0, 0.0, 0.0]),
..Default::default() ..Default::default()
@@ -310,8 +310,7 @@ impl OverlayBackend for WvrWindowBackend {
meta.extent[1] += BORDER_SIZE * 2 + BAR_SIZE; meta.extent[1] += BORDER_SIZE * 2 + BAR_SIZE;
if let Some(pipeline) = self.pipeline.as_mut() { if let Some(pipeline) = self.pipeline.as_mut() {
meta.extent[2] = pipeline.get_depth(); if self.inner_extent != inner_extent {
if self.inner_extent[..2] != inner_extent[..2] {
pipeline.set_extent( pipeline.set_extent(
app, app,
[inner_extent[0] as _, inner_extent[1] as _], [inner_extent[0] as _, inner_extent[1] as _],
@@ -327,7 +326,6 @@ impl OverlayBackend for WvrWindowBackend {
self.stereo.unwrap_or(StereoMode::None), self.stereo.unwrap_or(StereoMode::None),
[BORDER_SIZE as _, (BAR_SIZE + BORDER_SIZE) as _], [BORDER_SIZE as _, (BAR_SIZE + BORDER_SIZE) as _],
)?; )?;
meta.extent[2] = pipeline.get_depth();
self.apply_extent(app, &meta)?; self.apply_extent(app, &meta)?;
self.pipeline = Some(pipeline); self.pipeline = Some(pipeline);
} }
@@ -388,7 +386,8 @@ impl OverlayBackend for WvrWindowBackend {
.render(image, self.mouse.as_ref(), app, rdr)?; .render(image, self.mouse.as_ref(), app, rdr)?;
for (popup_img, point) in &self.popups { 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 popup_extentf = popup_img.extent_f32();
let mut buf_vert = app let mut buf_vert = app
.gfx .gfx
@@ -551,14 +550,14 @@ impl OverlayBackend for WvrWindowBackend {
_ => None, _ => 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 { match value {
BackendAttribValue::Stereo(new) => { BackendAttribValue::Stereo(new) => {
if let Some(stereo) = self.stereo.as_mut() { if let Some(stereo) = self.stereo.as_mut() {
log::debug!("{}: stereo: {stereo:?} → {new:?}", self.name); log::debug!("{}: stereo: {stereo:?} → {new:?}", self.name);
*stereo = new; *stereo = new;
if let Some(pipeline) = self.pipeline.as_mut() { 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 true
} else { } else {

View File

@@ -7,7 +7,7 @@ use wgui::gfx::{
cmd::{GfxCommandBuffer, WGfxClearMode}, cmd::{GfxCommandBuffer, WGfxClearMode},
}; };
use wlx_common::{ use wlx_common::{
overlays::{BackendAttrib, BackendAttribValue}, overlays::{BackendAttrib, BackendAttribValue, StereoMode},
windowing::Positioning, windowing::Positioning,
}; };
@@ -16,7 +16,7 @@ use crate::{
input::{HoverResult, PointerHit}, input::{HoverResult, PointerHit},
task::ModifyPanelCommand, task::ModifyPanelCommand,
}, },
graphics::{ExtentExt, RenderResult}, graphics::RenderResult,
overlays::wayvr::WvrCommand, overlays::wayvr::WvrCommand,
state::AppState, state::AppState,
subsystem::hid::WheelDelta, subsystem::hid::WheelDelta,
@@ -25,10 +25,11 @@ use crate::{
#[derive(Default, Clone, Copy)] #[derive(Default, Clone, Copy)]
pub struct FrameMeta { pub struct FrameMeta {
pub extent: [u32; 3], pub extent: [u32; 2],
pub transform: Affine3A, pub transform: Affine3A,
pub format: Format, pub format: Format,
pub clear: WGfxClearMode, pub clear: WGfxClearMode,
pub stereo: StereoMode,
} }
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
@@ -70,7 +71,7 @@ impl RenderResources {
Ok(Self { Ok(Self {
cmd_bufs, cmd_bufs,
alpha, alpha,
extent: meta.extent.extent_u32arr(), extent: meta.extent,
}) })
} }

View File

@@ -34,7 +34,7 @@ pub enum BackendAttribValue {
Icon(Arc<str>), Icon(Arc<str>),
} }
#[derive(Default, Debug, Clone, Copy, Serialize, Deserialize)] #[derive(Default, Debug, Clone, Copy, Serialize, Deserialize, PartialEq)]
pub enum StereoMode { pub enum StereoMode {
#[default] #[default]
None, None,