WayVR: Initial GUI integration
The format of the wayvr.yaml configuration file is subject to change at any time.
This commit is contained in:
@@ -10,43 +10,22 @@ use crate::{
|
||||
wayvr,
|
||||
},
|
||||
graphics::WlxGraphics,
|
||||
state::{self, KeyboardFocus},
|
||||
state::{self, AppState, KeyboardFocus},
|
||||
};
|
||||
|
||||
pub struct WayVRContext {
|
||||
wayvr: Rc<RefCell<wayvr::WayVR>>,
|
||||
display: wayvr::display::DisplayHandle,
|
||||
width: u32,
|
||||
height: u32,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct WayVRProcess<'a> {
|
||||
pub exec_path: &'a str,
|
||||
pub args: &'a [&'a str],
|
||||
pub env: &'a [(&'a str, &'a str)],
|
||||
}
|
||||
|
||||
impl WayVRContext {
|
||||
pub fn new(
|
||||
wvr: Rc<RefCell<wayvr::WayVR>>,
|
||||
width: u32,
|
||||
height: u32,
|
||||
processes: &[WayVRProcess],
|
||||
display: wayvr::display::DisplayHandle,
|
||||
) -> anyhow::Result<Self> {
|
||||
let mut wayvr = wvr.borrow_mut();
|
||||
|
||||
let display = wayvr.create_display(width, height)?;
|
||||
|
||||
for process in processes {
|
||||
wayvr.spawn_process(display, process.exec_path, process.args, process.env)?;
|
||||
}
|
||||
|
||||
Ok(Self {
|
||||
wayvr: wvr.clone(),
|
||||
display,
|
||||
width,
|
||||
height,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -73,14 +52,15 @@ impl InteractionHandler for WayVRInteractionHandler {
|
||||
) -> Option<input::Haptics> {
|
||||
let ctx = self.context.borrow();
|
||||
|
||||
let pos = self.mouse_transform.transform_point2(hit.uv);
|
||||
let x = ((pos.x * ctx.width as f32) as i32).max(0);
|
||||
let y = ((pos.y * ctx.height as f32) as i32).max(0);
|
||||
let mut wayvr = ctx.wayvr.borrow_mut();
|
||||
if let Some(disp) = wayvr.get_display_by_handle(ctx.display) {
|
||||
let pos = self.mouse_transform.transform_point2(hit.uv);
|
||||
let x = ((pos.x * disp.width as f32) as i32).max(0);
|
||||
let y = ((pos.y * disp.height as f32) as i32).max(0);
|
||||
|
||||
let ctx = self.context.borrow();
|
||||
ctx.wayvr
|
||||
.borrow_mut()
|
||||
.send_mouse_move(ctx.display, x as u32, y as u32);
|
||||
let ctx = self.context.borrow();
|
||||
wayvr.send_mouse_move(ctx.display, x as u32, y as u32);
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
@@ -120,24 +100,16 @@ pub struct WayVRRenderer {
|
||||
view: Option<Arc<vulkano::image::view::ImageView>>,
|
||||
context: Rc<RefCell<WayVRContext>>,
|
||||
graphics: Arc<WlxGraphics>,
|
||||
width: u32,
|
||||
height: u32,
|
||||
}
|
||||
|
||||
impl WayVRRenderer {
|
||||
pub fn new(
|
||||
app: &mut state::AppState,
|
||||
wvr: Rc<RefCell<wayvr::WayVR>>,
|
||||
width: u32,
|
||||
height: u32,
|
||||
processes: &[WayVRProcess],
|
||||
display: wayvr::display::DisplayHandle,
|
||||
) -> anyhow::Result<Self> {
|
||||
Ok(Self {
|
||||
context: Rc::new(RefCell::new(WayVRContext::new(
|
||||
wvr, width, height, processes,
|
||||
)?)),
|
||||
width,
|
||||
height,
|
||||
context: Rc::new(RefCell::new(WayVRContext::new(wvr, display)?)),
|
||||
dmabuf_image: None,
|
||||
view: None,
|
||||
graphics: app.graphics.clone(),
|
||||
@@ -154,35 +126,43 @@ impl WayVRRenderer {
|
||||
planes[0].offset = data.offset as u32;
|
||||
planes[0].stride = data.stride;
|
||||
|
||||
let frame = DmabufFrame {
|
||||
format: FrameFormat {
|
||||
width: self.width,
|
||||
height: self.height,
|
||||
fourcc: FourCC {
|
||||
value: data.mod_info.fourcc,
|
||||
let ctx = self.context.borrow_mut();
|
||||
let wayvr = ctx.wayvr.borrow_mut();
|
||||
if let Some(disp) = wayvr.get_display_by_handle(ctx.display) {
|
||||
let frame = DmabufFrame {
|
||||
format: FrameFormat {
|
||||
width: disp.width,
|
||||
height: disp.height,
|
||||
fourcc: FourCC {
|
||||
value: data.mod_info.fourcc,
|
||||
},
|
||||
modifier: data.mod_info.modifiers[0], /* possibly not proper? */
|
||||
},
|
||||
modifier: data.mod_info.modifiers[0], /* possibly not proper? */
|
||||
},
|
||||
num_planes: 1,
|
||||
planes,
|
||||
};
|
||||
num_planes: 1,
|
||||
planes,
|
||||
};
|
||||
|
||||
let layouts: Vec<SubresourceLayout> = vec![SubresourceLayout {
|
||||
offset: data.offset as _,
|
||||
size: 0,
|
||||
row_pitch: data.stride as _,
|
||||
array_pitch: None,
|
||||
depth_pitch: None,
|
||||
}];
|
||||
drop(wayvr);
|
||||
|
||||
let tex = self.graphics.dmabuf_texture_ex(
|
||||
frame,
|
||||
vulkano::image::ImageTiling::DrmFormatModifier,
|
||||
layouts,
|
||||
data.mod_info.modifiers,
|
||||
)?;
|
||||
self.dmabuf_image = Some(tex.clone());
|
||||
self.view = Some(vulkano::image::view::ImageView::new_default(tex).unwrap());
|
||||
let layouts: Vec<SubresourceLayout> = vec![SubresourceLayout {
|
||||
offset: data.offset as _,
|
||||
size: 0,
|
||||
row_pitch: data.stride as _,
|
||||
array_pitch: None,
|
||||
depth_pitch: None,
|
||||
}];
|
||||
|
||||
let tex = self.graphics.dmabuf_texture_ex(
|
||||
frame,
|
||||
vulkano::image::ImageTiling::DrmFormatModifier,
|
||||
layouts,
|
||||
data.mod_info.modifiers,
|
||||
)?;
|
||||
self.dmabuf_image = Some(tex.clone());
|
||||
self.view = Some(vulkano::image::view::ImageView::new_default(tex).unwrap());
|
||||
} else {
|
||||
anyhow::bail!("Failed to fetch WayVR display")
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -232,31 +212,30 @@ impl OverlayRenderer for WayVRRenderer {
|
||||
#[allow(dead_code)]
|
||||
pub fn create_wayvr<O>(
|
||||
app: &mut state::AppState,
|
||||
width: u32,
|
||||
height: u32,
|
||||
processes: &[WayVRProcess],
|
||||
display: &wayvr::display::Display,
|
||||
display_handle: wayvr::display::DisplayHandle,
|
||||
display_scale: f32,
|
||||
) -> anyhow::Result<OverlayData<O>>
|
||||
where
|
||||
O: Default,
|
||||
{
|
||||
let transform = ui_transform(&[width, height]);
|
||||
let transform = ui_transform(&[display.width, display.height]);
|
||||
|
||||
let state = OverlayState {
|
||||
name: format!("WayVR Screen ({}x{})", width, height).into(),
|
||||
name: format!("WayVR Screen ({}x{})", display.width, display.height).into(),
|
||||
keyboard_focus: Some(KeyboardFocus::WayVR),
|
||||
want_visible: true,
|
||||
interactable: true,
|
||||
recenter: true,
|
||||
grabbable: true,
|
||||
spawn_scale: 1.0,
|
||||
spawn_point: vec3a(0.0, -0.5, 0.0),
|
||||
spawn_scale: display_scale,
|
||||
spawn_point: vec3a(0.0, -0.1, -1.0),
|
||||
interaction_transform: transform,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let wayvr = app.get_wayvr()?;
|
||||
|
||||
let renderer = WayVRRenderer::new(app, wayvr, width, height, processes)?;
|
||||
let renderer = WayVRRenderer::new(app, wayvr, display_handle)?;
|
||||
let context = renderer.context.clone();
|
||||
|
||||
let backend = Box::new(SplitOverlayBackend {
|
||||
@@ -270,3 +249,100 @@ where
|
||||
..Default::default()
|
||||
})
|
||||
}
|
||||
|
||||
fn action_wayvr_internal<O>(
|
||||
catalog_name: &Arc<str>,
|
||||
app_name: &Arc<str>,
|
||||
app: &mut AppState,
|
||||
) -> anyhow::Result<Option<OverlayData<O>>>
|
||||
where
|
||||
O: Default,
|
||||
{
|
||||
use crate::overlays::wayvr::create_wayvr;
|
||||
|
||||
let mut created_overlay: Option<OverlayData<O>> = None;
|
||||
|
||||
let wayvr = app.get_wayvr()?.clone();
|
||||
|
||||
let catalog = app
|
||||
.session
|
||||
.wayvr_config
|
||||
.get_catalog(catalog_name)
|
||||
.ok_or(anyhow::anyhow!(
|
||||
"Failed to get catalog \"{}\"",
|
||||
catalog_name
|
||||
))?
|
||||
.clone();
|
||||
|
||||
if let Some(app_entry) = catalog.get_app(app_name) {
|
||||
let mut wayvr = wayvr.borrow_mut();
|
||||
|
||||
let disp_handle = if let Some(disp) = wayvr.get_display_by_name(&app_entry.target_display) {
|
||||
disp
|
||||
} else {
|
||||
let conf_display = app
|
||||
.session
|
||||
.wayvr_config
|
||||
.get_display(&app_entry.target_display)
|
||||
.ok_or(anyhow::anyhow!(
|
||||
"Cannot find display named \"{}\"",
|
||||
app_entry.target_display
|
||||
))?;
|
||||
|
||||
let display_handle = wayvr.create_display(
|
||||
conf_display.width,
|
||||
conf_display.height,
|
||||
&app_entry.target_display,
|
||||
)?;
|
||||
let display = wayvr.get_display_by_handle(display_handle).unwrap(); // Never fails
|
||||
created_overlay = Some(create_wayvr::<O>(
|
||||
app,
|
||||
display,
|
||||
display_handle,
|
||||
conf_display.scale,
|
||||
)?);
|
||||
display_handle
|
||||
};
|
||||
|
||||
// Parse additional args
|
||||
let args_vec: Vec<&str> = if let Some(args) = &app_entry.args {
|
||||
args.as_str().split_whitespace().collect()
|
||||
} else {
|
||||
vec![]
|
||||
};
|
||||
|
||||
// Parse additional env
|
||||
let env_vec: Vec<(&str, &str)> = if let Some(env) = &app_entry.env {
|
||||
// splits "FOO=BAR=TEST,123" into (&"foo", &"bar=test,123")
|
||||
env.iter()
|
||||
.filter_map(|e| e.as_str().split_once('='))
|
||||
.collect()
|
||||
} else {
|
||||
vec![]
|
||||
};
|
||||
|
||||
wayvr.spawn_process(disp_handle, &app_entry.exec, &args_vec, &env_vec)?
|
||||
}
|
||||
|
||||
Ok(created_overlay)
|
||||
}
|
||||
|
||||
// Returns newly created overlay (if needed)
|
||||
pub fn action_wayvr<O>(
|
||||
catalog_name: &Arc<str>,
|
||||
app_name: &Arc<str>,
|
||||
app: &mut AppState,
|
||||
) -> Option<OverlayData<O>>
|
||||
where
|
||||
O: Default,
|
||||
{
|
||||
match action_wayvr_internal(catalog_name, app_name, app) {
|
||||
Ok(res) => res,
|
||||
Err(e) => {
|
||||
// Happens if something went wrong with initialization
|
||||
// or input exec path is invalid. Do nothing, just print an error
|
||||
log::error!("action_wayvr failed: {}", e);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user