refactor overlay windowing

This commit is contained in:
galister
2025-10-05 18:49:59 +09:00
parent 40cc27f7b0
commit aa64310d96
46 changed files with 1329 additions and 1342 deletions

View File

@@ -1,7 +1,7 @@
use libmonado::{ClientState, Monado};
use log::{info, warn};
use crate::{backend::overlay::OverlayID, state::AppState};
use crate::{state::AppState, windowing::OverlayID};
pub(super) struct InputBlocker {
hovered_last_frame: bool,

View File

@@ -17,11 +17,10 @@ use vulkano::{Handle, VulkanObject};
use crate::{
backend::{
common::{BackendError, OverlayContainer},
input::interact,
openxr::{lines::LinePool, overlay::OpenXrOverlayData},
overlay::{OverlayData, ShouldRender},
task::{SystemTask, TaskType},
BackendError,
},
graphics::{init_openxr_graphics, CommandBuffers},
overlays::{
@@ -30,6 +29,7 @@ use crate::{
},
state::AppState,
subsystem::notifications::NotificationManager,
windowing::{backend::ShouldRender, manager::OverlayWindowManager, window::OverlayWindowData},
};
#[cfg(feature = "wayvr")]
@@ -94,7 +94,7 @@ pub fn openxr_run(
);
}
let mut overlays = OverlayContainer::<OpenXrOverlayData>::new(&mut app, headless)?;
let mut overlays = OverlayWindowManager::<OpenXrOverlayData>::new(&mut app, headless)?;
let mut lines = LinePool::new(&app)?;
let mut notifications = NotificationManager::new();
@@ -336,7 +336,7 @@ pub fn openxr_run(
overlays
.values_mut()
.for_each(|o| o.state.auto_movement(&mut app));
.for_each(|o| o.config.auto_movement(&mut app));
let lengths_haptics = interact(&mut overlays, &mut app);
for (idx, (len, haptics)) in lengths_haptics.iter().enumerate() {
@@ -355,10 +355,11 @@ pub fn openxr_run(
app.hid_provider.inner.commit();
let watch = overlays.mut_by_id(watch_id).unwrap(); // want panic
let watch_transform = watch.state.transform;
if !watch.state.want_visible {
watch.state.want_visible = true;
watch.state.transform = Affine3A::from_scale(Vec3 {
let watch_state = watch.config.active_state.as_mut().unwrap();
let watch_transform = watch_state.transform;
if watch_state.alpha < 0.05 {
//FIXME: Temporary workaround for Monado bug
watch_state.transform = Affine3A::from_scale(Vec3 {
x: 0.001,
y: 0.001,
z: 0.001,
@@ -381,9 +382,9 @@ pub fn openxr_run(
for o in overlays.values_mut() {
o.data.cur_visible = false;
if !o.state.want_visible {
let Some(alpha) = o.config.active_state.as_ref().map(|x| x.alpha) else {
continue;
}
};
if !o.data.init {
o.init(&mut app)?;
@@ -392,7 +393,7 @@ pub fn openxr_run(
let should_render = match o.should_render(&mut app)? {
ShouldRender::Should => true,
ShouldRender::Can => (o.data.last_alpha - o.state.alpha).abs() > f32::EPSILON,
ShouldRender::Can => (o.data.last_alpha - alpha).abs() > f32::EPSILON,
ShouldRender::Unable => false, //try show old image if exists
};
@@ -401,11 +402,11 @@ pub fn openxr_run(
continue;
}
let tgt = o.data.swapchain.as_mut().unwrap().acquire_wait_image()?; // want
if !o.render(&mut app, tgt, &mut buffers, o.state.alpha)? {
if !o.render(&mut app, tgt, &mut buffers, alpha)? {
o.data.swapchain.as_mut().unwrap().ensure_image_released()?; // want
continue;
}
o.data.last_alpha = o.state.alpha;
o.data.last_alpha = alpha;
} else if o.data.swapchain.is_none() {
continue;
}
@@ -435,9 +436,11 @@ pub fn openxr_run(
if !o.data.cur_visible {
continue;
}
let dist_sq = (app.input_state.hmd.translation - o.state.transform.translation)
// unwrap: above if only passes if active_state is some
let active_state = o.config.active_state.as_ref().unwrap();
let dist_sq = (app.input_state.hmd.translation - active_state.transform.translation)
.length_squared()
+ (100f32 - o.state.z_order as f32);
+ (100f32 - o.config.z_order as f32);
if !dist_sq.is_normal() {
o.data.swapchain.as_mut().unwrap().ensure_image_released()?;
continue;
@@ -489,7 +492,7 @@ pub fn openxr_run(
match task {
TaskType::Overlay(sel, f) => {
if let Some(o) = overlays.mut_by_selector(&sel) {
f(&mut app, &mut o.state);
f(&mut app, &mut o.config);
} else {
log::warn!("Overlay not found for task: {sel:?}");
}
@@ -498,22 +501,22 @@ pub fn openxr_run(
let None = overlays.mut_by_selector(&sel) else {
continue;
};
let Some((mut overlay_state, overlay_backend)) = f(&mut app) else {
let Some(overlay_config) = f(&mut app) else {
continue;
};
overlay_state.birthframe = cur_frame;
overlays.add(OverlayData {
state: overlay_state,
..OverlayData::from_backend(overlay_backend)
});
overlays.add(
OverlayWindowData {
birthframe: cur_frame,
..OverlayWindowData::from_config(overlay_config)
},
&mut app,
);
}
TaskType::DropOverlay(sel) => {
if let Some(o) = overlays.mut_by_selector(&sel)
&& o.state.birthframe < cur_frame
&& o.birthframe < cur_frame
{
log::debug!("{}: destroy", o.state.name);
log::debug!("{}: destroy", o.config.name);
if let Some(o) = overlays.remove_by_selector(&sel) {
// set for deletion after all images are done showing
delete_queue.push((o, cur_frame + 5));
@@ -539,6 +542,9 @@ pub fn openxr_run(
}
_ => {}
},
TaskType::ToggleSet(set) => {
overlays.switch_or_toggle_set(&mut app, set);
}
#[cfg(feature = "wayvr")]
TaskType::WayVR(action) => {
wayvr_action(&mut app, &mut overlays, &action);
@@ -548,8 +554,9 @@ pub fn openxr_run(
delete_queue.retain(|(_, frame)| *frame > cur_frame);
//FIXME: Temporary workaround for Monado bug
let watch = overlays.mut_by_id(watch_id).unwrap(); // want panic
watch.state.transform = watch_transform;
watch.config.active_state.as_mut().unwrap().transform = watch_transform;
}
Ok(())

View File

@@ -5,11 +5,9 @@ use xr::EyeVisibility;
use super::{CompositionLayer, XrState, helpers, swapchain::WlxSwapchain};
use crate::{
backend::{
openxr::swapchain::{SwapchainOpts, create_swapchain},
overlay::OverlayData,
},
backend::openxr::swapchain::{SwapchainOpts, create_swapchain},
state::AppState,
windowing::window::OverlayWindowData,
};
#[derive(Default)]
@@ -21,7 +19,7 @@ pub struct OpenXrOverlayData {
pub(super) last_alpha: f32,
}
impl OverlayData<OpenXrOverlayData> {
impl OverlayWindowData<OpenXrOverlayData> {
pub(super) fn ensure_swapchain<'a>(
&'a mut self,
app: &AppState,
@@ -30,7 +28,7 @@ impl OverlayData<OpenXrOverlayData> {
let Some(meta) = self.frame_meta() else {
log::warn!(
"{}: swapchain cannot be created due to missing metadata",
self.state.name
self.config.name
);
return Ok(false);
};
@@ -46,7 +44,7 @@ impl OverlayData<OpenXrOverlayData> {
log::debug!(
"{}: recreating swapchain at {}x{}",
self.state.name,
self.config.name,
meta.extent[0],
meta.extent[1],
);
@@ -64,17 +62,20 @@ impl OverlayData<OpenXrOverlayData> {
xr: &'a XrState,
) -> anyhow::Result<CompositionLayer<'a>> {
let Some(swapchain) = self.data.swapchain.as_mut() else {
log::warn!("{}: swapchain not ready", self.state.name);
log::warn!("{}: swapchain not ready", self.config.name);
return Ok(CompositionLayer::None);
};
if !swapchain.ever_acquired {
log::warn!("{}: swapchain not rendered", self.state.name);
log::warn!("{}: swapchain not rendered", self.config.name);
return Ok(CompositionLayer::None);
}
swapchain.ensure_image_released()?;
// overlays without active_state don't get queued for present
let state = self.config.active_state.as_ref().unwrap();
let sub_image = swapchain.get_subimage();
let transform = self.state.transform * self.backend.frame_meta().unwrap().transform; // contract
let transform = state.transform * self.config.backend.frame_meta().unwrap().transform; // contract
let aspect_ratio = swapchain.extent[1] as f32 / swapchain.extent[0] as f32;
let (scale_x, scale_y) = if aspect_ratio < 1.0 {
@@ -85,7 +86,7 @@ impl OverlayData<OpenXrOverlayData> {
(major / aspect_ratio, major)
};
if let Some(curvature) = self.state.curvature {
if let Some(curvature) = state.curvature {
let radius = scale_x / (2.0 * PI * curvature);
let quat = helpers::transform_to_norm_quat(&transform);
let center_point = transform.translation + quat.mul_vec3a(Vec3A::Z * radius);
@@ -120,14 +121,21 @@ impl OverlayData<OpenXrOverlayData> {
}
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)?;
let want_visible = self
.config
.active_state
.as_ref()
.map(|x| x.alpha > 0.05)
.unwrap_or(false);
if self.data.last_visible != want_visible {
if want_visible {
self.config.backend.resume(app)?;
} else {
self.backend.pause(app)?;
self.config.backend.pause(app)?;
}
}
self.data.last_visible = self.state.want_visible;
self.data.last_visible = want_visible;
Ok(())
}
}

View File

@@ -2,8 +2,7 @@ use glam::{Affine3A, Quat, Vec3A};
use libmonado::{Monado, Pose, ReferenceSpaceType};
use crate::{
backend::{common::OverlayContainer, input::InputState},
state::AppState,
backend::input::InputState, state::AppState, windowing::manager::OverlayWindowManager,
};
use super::overlay::OpenXrOverlayData;
@@ -44,7 +43,7 @@ impl PlayspaceMover {
pub fn update(
&mut self,
overlays: &mut OverlayContainer<OpenXrOverlayData>,
overlays: &mut OverlayWindowManager<OpenXrOverlayData>,
state: &AppState,
monado: &mut Monado,
) {
@@ -129,10 +128,13 @@ impl PlayspaceMover {
let overlay_offset = data.pose.inverse().transform_vector3a(relative_pos) * -1.0;
overlays.values_mut().for_each(|overlay| {
if overlay.state.grabbable {
overlay.state.dirty = true;
overlay.state.transform.translation += overlay_offset;
let Some(state) = overlay.config.active_state.as_mut() else {
return;
};
if state.positioning.moves_with_space() {
state.transform.translation += overlay_offset;
}
overlay.config.dirty = true;
});
data.pose.translation += relative_pos;