mirror of https://github.com/wayvr-org/wayvr.git
protobuf parser, read metrics, move async executor to wlx_common
This commit is contained in:
parent
41c6f43a3c
commit
0f6f344c97
|
|
@ -2855,8 +2855,7 @@ checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de"
|
|||
[[package]]
|
||||
name = "libmonado"
|
||||
version = "1.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0df3183760954d877b894d42f5c6954837d8a7d7bd5f042409c4175afeaf24ea"
|
||||
source = "git+https://github.com/oo8dev/libmonado-rs.git?rev=fc39940a64dea2df080a0d2c974c7d651006241f#fc39940a64dea2df080a0d2c974c7d651006241f"
|
||||
dependencies = [
|
||||
"dlopen2",
|
||||
"flagset",
|
||||
|
|
@ -3108,6 +3107,12 @@ dependencies = [
|
|||
"pxfm",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "multimap"
|
||||
version = "0.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d87ecb2933e8aeadb3e3a02b828fed80a7528047e68b4f424523a0981a3a084"
|
||||
|
||||
[[package]]
|
||||
name = "native-tls"
|
||||
version = "0.2.14"
|
||||
|
|
@ -3905,6 +3910,17 @@ dependencies = [
|
|||
"sha2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "petgraph"
|
||||
version = "0.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8701b58ea97060d5e5b155d383a69952a60943f0e6dfe30b04c287beb0b27455"
|
||||
dependencies = [
|
||||
"fixedbitset",
|
||||
"hashbrown 0.15.5",
|
||||
"indexmap 2.12.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "phf"
|
||||
version = "0.12.1"
|
||||
|
|
@ -4167,6 +4183,64 @@ dependencies = [
|
|||
"syn 2.0.113",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "prost"
|
||||
version = "0.14.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2ea70524a2f82d518bce41317d0fae74151505651af45faf1ffbd6fd33f0568"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"prost-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "prost-build"
|
||||
version = "0.14.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "343d3bd7056eda839b03204e68deff7d1b13aba7af2b2fd16890697274262ee7"
|
||||
dependencies = [
|
||||
"heck 0.5.0",
|
||||
"itertools 0.14.0",
|
||||
"log",
|
||||
"multimap",
|
||||
"petgraph",
|
||||
"prettyplease",
|
||||
"prost",
|
||||
"prost-types",
|
||||
"regex",
|
||||
"syn 2.0.113",
|
||||
"tempfile",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "prost-derive"
|
||||
version = "0.14.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "27c6023962132f4b30eb4c172c91ce92d933da334c59c23cddee82358ddafb0b"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"itertools 0.14.0",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.113",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "prost-types"
|
||||
version = "0.14.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8991c4cbdb8bc5b11f0b074ffe286c30e523de90fee5ba8132f1399f23cb3dd7"
|
||||
dependencies = [
|
||||
"prost",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "prost_build"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"prost-build",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pure-rust-locales"
|
||||
version = "0.8.2"
|
||||
|
|
@ -6293,6 +6367,7 @@ dependencies = [
|
|||
"mint",
|
||||
"openxr",
|
||||
"ovr_overlay",
|
||||
"prost",
|
||||
"pure-rust-locales",
|
||||
"regex",
|
||||
"rosc",
|
||||
|
|
@ -6305,6 +6380,7 @@ dependencies = [
|
|||
"slotmap",
|
||||
"smallvec",
|
||||
"smithay",
|
||||
"smol",
|
||||
"strum",
|
||||
"sysinfo",
|
||||
"thiserror 2.0.17",
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ members = [
|
|||
"dash-frontend",
|
||||
"wayvr-ipc",
|
||||
"wayvrctl",
|
||||
"scripts/prost_build",
|
||||
]
|
||||
resolver = "3"
|
||||
|
||||
|
|
@ -38,6 +39,7 @@ vulkano = { git = "https://github.com/galister/vulkano.git", rev = "cf7f92867928
|
|||
|
||||
[workspace.dependencies]
|
||||
anyhow = "1.0.100"
|
||||
smol = "2.0.2"
|
||||
glam = { version = "0.30.9", features = ["mint", "serde"] }
|
||||
clap = { version = "4.5.53", features = ["derive"] }
|
||||
xdg = "3.0.0"
|
||||
|
|
|
|||
|
|
@ -23,12 +23,12 @@ strum.workspace = true
|
|||
|
||||
chrono = "0.4.42"
|
||||
keyvalues-parser = { git = "https://github.com/CosmicHorrorDev/vdf-rs.git", rev = "fc6dcbea9eb13cacb98dea40063f6f56cde6e145" }
|
||||
smol = "2.0.2"
|
||||
smol = { workspace = true }
|
||||
hyper = { version = "1.8.1", features = ["client", "http1", "http2"] }
|
||||
http-body-util = "0.1.3"
|
||||
async-native-tls = "0.5.0"
|
||||
smol-hyper = "0.1.1"
|
||||
|
||||
[features]
|
||||
default = ["monado" ]
|
||||
default = ["monado"]
|
||||
monado = []
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ use wgui::{
|
|||
windowing::window::{WguiWindow, WguiWindowParams, WguiWindowParamsExtra, WguiWindowPlacement},
|
||||
};
|
||||
use wlx_common::{
|
||||
async_executor::AsyncExecutor,
|
||||
audio,
|
||||
dash_interface::{BoxDashInterface, RecenterMode},
|
||||
locale::WayVRLangProvider,
|
||||
|
|
@ -29,7 +30,6 @@ use crate::{
|
|||
util::{
|
||||
popup_manager::{MountPopupParams, PopupManager, PopupManagerParams},
|
||||
toast_manager::ToastManager,
|
||||
various::AsyncExecutor,
|
||||
},
|
||||
views,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
use anyhow::Context;
|
||||
use serde::Deserialize;
|
||||
use wlx_common::cache_dir;
|
||||
use wlx_common::{async_executor::AsyncExecutor, cache_dir};
|
||||
|
||||
use crate::util::{http_client, steam_utils::AppID, various::AsyncExecutor};
|
||||
use crate::util::{http_client, steam_utils::AppID};
|
||||
|
||||
pub struct CoverArt {
|
||||
// can be empty in case if data couldn't be fetched (use a fallback image then)
|
||||
|
|
|
|||
|
|
@ -13,8 +13,7 @@ use smol::{net::TcpStream, prelude::*};
|
|||
use std::convert::TryInto;
|
||||
use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
|
||||
use crate::util::various::AsyncExecutor;
|
||||
use wlx_common::async_executor::AsyncExecutor;
|
||||
pub struct HttpClientResponse {
|
||||
pub data: Vec<u8>,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,5 +4,4 @@ pub mod pactl_wrapper;
|
|||
pub mod popup_manager;
|
||||
pub mod steam_utils;
|
||||
pub mod toast_manager;
|
||||
pub mod various;
|
||||
pub mod wgui_simple;
|
||||
|
|
|
|||
|
|
@ -25,11 +25,11 @@ use wgui::{
|
|||
util::WLength,
|
||||
},
|
||||
};
|
||||
use wlx_common::async_executor::AsyncExecutor;
|
||||
|
||||
use crate::util::{
|
||||
cached_fetcher::{self, CoverArt},
|
||||
steam_utils::{self, AppID},
|
||||
various::AsyncExecutor,
|
||||
};
|
||||
|
||||
pub struct ViewCommon {
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ use crate::{
|
|||
util::{
|
||||
cached_fetcher::{self, CoverArt},
|
||||
steam_utils::{self, AppID, AppManifest},
|
||||
various::AsyncExecutor,
|
||||
},
|
||||
views::game_cover,
|
||||
};
|
||||
|
|
@ -19,6 +18,7 @@ use wgui::{
|
|||
task::Tasks,
|
||||
widget::{ConstructEssentials, label::WidgetLabel},
|
||||
};
|
||||
use wlx_common::async_executor::AsyncExecutor;
|
||||
|
||||
#[derive(Clone)]
|
||||
enum Task {
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ use wgui::{
|
|||
label::{WidgetLabel, WidgetLabelParams},
|
||||
},
|
||||
};
|
||||
use wlx_common::async_executor::AsyncExecutor;
|
||||
|
||||
use crate::{
|
||||
frontend::{FrontendTask, FrontendTasks},
|
||||
|
|
@ -20,7 +21,6 @@ use crate::{
|
|||
cached_fetcher::CoverArt,
|
||||
popup_manager::{MountPopupParams, PopupHandle},
|
||||
steam_utils::{self, AppID, SteamUtils},
|
||||
various::AsyncExecutor,
|
||||
},
|
||||
views::{self, game_cover, game_launcher},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,7 @@
|
|||
[package]
|
||||
name = "prost_build"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
prost-build = "0.14.3"
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
use std::io::Result;
|
||||
fn main() -> Result<()> {
|
||||
prost_build::compile_protos(&["src/monado_metrics.proto"], &["src/"])?;
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -0,0 +1,174 @@
|
|||
syntax = "proto3";
|
||||
|
||||
package monado_metrics;
|
||||
|
||||
|
||||
message Version
|
||||
{
|
||||
uint32 major = 1;
|
||||
uint32 minor = 2;
|
||||
}
|
||||
|
||||
message SessionFrame
|
||||
{
|
||||
//! Which session this frame belongs to.
|
||||
int64 session_id = 1;
|
||||
|
||||
//! ID of frame.
|
||||
int64 frame_id = 2;
|
||||
|
||||
//! How long we thought the frame would take.
|
||||
uint64 predicted_frame_time_ns = 3;
|
||||
|
||||
//! When we predicted the app should wake up.
|
||||
uint64 predicted_wake_up_time_ns = 4;
|
||||
|
||||
//! When the client's GPU work should have completed.
|
||||
uint64 predicted_gpu_done_time_ns = 5;
|
||||
|
||||
//! When we predicted this frame to be shown.
|
||||
uint64 predicted_display_time_ns = 6;
|
||||
|
||||
//! The selected display period.
|
||||
uint64 predicted_display_period_ns = 7;
|
||||
|
||||
/*!
|
||||
* When the app told us to display this frame, can be different
|
||||
* then the predicted display time so we track that separately.
|
||||
*/
|
||||
uint64 display_time_ns = 8;
|
||||
|
||||
//! When the predict call was made (inside of xrWaitFrame).
|
||||
uint64 when_predicted_ns = 9;
|
||||
|
||||
//! When the waiting thread was woken up.
|
||||
uint64 when_wait_woke_ns = 10;
|
||||
|
||||
//! When xrBeginFrame was called.
|
||||
uint64 when_begin_ns = 11;
|
||||
|
||||
//! When the layer information was delivered, (inside of xrEndFrame).
|
||||
uint64 when_delivered_ns = 12;
|
||||
|
||||
//! When the scheduled GPU work was completed.
|
||||
uint64 when_gpu_done_ns = 13;
|
||||
|
||||
//! Was this frame discarded.
|
||||
bool discarded = 14;
|
||||
}
|
||||
|
||||
message Used
|
||||
{
|
||||
//! Owning session of the frame.
|
||||
int64 session_id = 1;
|
||||
|
||||
//! Which session frame was used by the compositor.
|
||||
int64 session_frame_id = 2;
|
||||
|
||||
//! The system frame that the session was used by.
|
||||
int64 system_frame_id = 3;
|
||||
|
||||
//! When the frame was latched.
|
||||
uint64 when_ns = 4;
|
||||
}
|
||||
|
||||
message SystemFrame
|
||||
{
|
||||
//! ID of frame.
|
||||
int64 frame_id = 1;
|
||||
|
||||
//! Projected pixels to photon time.
|
||||
uint64 predicted_display_time_ns = 2;
|
||||
|
||||
//! Current period of displaying of frames.
|
||||
uint64 predicted_display_period_ns = 3;
|
||||
|
||||
//! When the compositor should hand pixels to display hardware.
|
||||
uint64 desired_present_time_ns = 4;
|
||||
|
||||
//! The time that the compositor should wake up.
|
||||
uint64 wake_up_time_ns = 5;
|
||||
uint64 present_slop_ns = 6;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Out of band info about a GPU timing from a system compositor.
|
||||
*/
|
||||
message SystemGpuInfo
|
||||
{
|
||||
//! ID of frame.
|
||||
int64 frame_id = 1;
|
||||
|
||||
//! Start of GPU work.
|
||||
uint64 gpu_start_ns = 2;
|
||||
|
||||
//! End of GPU work.
|
||||
uint64 gpu_end_ns = 3;
|
||||
|
||||
//! When the information was gathered.
|
||||
uint64 when_ns = 4;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Information that comes from the vulkan present timing.
|
||||
*/
|
||||
message SystemPresentInfo
|
||||
{
|
||||
//! ID of frame.
|
||||
int64 frame_id = 1;
|
||||
|
||||
//! The total expected time for the compositor to complete a frame.
|
||||
uint64 expected_comp_time_ns = 2;
|
||||
|
||||
//! The time we predicted the compositor to wake up time.
|
||||
uint64 predicted_wake_up_time_ns = 3;
|
||||
|
||||
//! Predicted time for completion of the GPU work.
|
||||
uint64 predicted_done_time_ns = 4;
|
||||
|
||||
//! Predicted display time.
|
||||
uint64 predicted_display_time_ns = 5;
|
||||
|
||||
//! When was this frame predicted.
|
||||
uint64 when_predict_ns = 6;
|
||||
|
||||
//! When we last woke up the compositor after its equivalent of wait_frame.
|
||||
uint64 when_woke_ns = 7;
|
||||
|
||||
//! When the compositor started rendering a frame
|
||||
uint64 when_began_ns = 8;
|
||||
|
||||
//! When the compositor finished rendering a frame
|
||||
uint64 when_submitted_ns = 9;
|
||||
|
||||
//! When new frame timing info was last added.
|
||||
uint64 when_infoed_ns = 10;
|
||||
|
||||
//! When we wanted to start presenting.
|
||||
uint64 desired_present_time_ns = 11;
|
||||
|
||||
//! The slop used for this frame.
|
||||
uint64 present_slop_ns = 12;
|
||||
|
||||
//! Margin of GPU to present time.
|
||||
uint64 present_margin_ns = 13;
|
||||
|
||||
//! When the present time actually happened.
|
||||
uint64 actual_present_time_ns = 14;
|
||||
|
||||
//! The earliest we could have presented.
|
||||
uint64 earliest_present_time_ns = 15;
|
||||
}
|
||||
|
||||
|
||||
message Record
|
||||
{
|
||||
oneof record {
|
||||
Version version = 1;
|
||||
SessionFrame session_frame = 2;
|
||||
Used used = 3;
|
||||
SystemFrame system_frame = 4;
|
||||
SystemGpuInfo system_gpu_info = 5;
|
||||
SystemPresentInfo system_present_info = 6;
|
||||
};
|
||||
}
|
||||
|
|
@ -58,7 +58,8 @@ interprocess = { version = "2.2.3" }
|
|||
json = { version = "0.12.4", optional = true }
|
||||
json5 = "1.3.0"
|
||||
libc = "0.2.178"
|
||||
libmonado = { version = "1.6.0", optional = true }
|
||||
smol = { workspace = true }
|
||||
libmonado = { git = "https://github.com/oo8dev/libmonado-rs.git", rev = "fc39940a64dea2df080a0d2c974c7d651006241f", optional = true }
|
||||
log-panics = { version = "2.1.0", features = ["with-backtrace"] }
|
||||
mint = "0.5.9"
|
||||
openxr = { version = "0.21.0", features = ["linked", "mint"], optional = true }
|
||||
|
|
@ -88,6 +89,7 @@ xcb = { version = "1.6.0", optional = true, features = [
|
|||
"as-raw-xcb-connection",
|
||||
] }
|
||||
xkbcommon = { version = "0.8.0" } # 0.9.0 breaks keymap import on some distros
|
||||
prost = { version = "0.14.3", optional = true }
|
||||
|
||||
[build-dependencies]
|
||||
regex.workspace = true
|
||||
|
|
@ -95,7 +97,7 @@ regex.workspace = true
|
|||
[features]
|
||||
default = ["openvr", "openxr", "osc", "x11", "wayland"]
|
||||
openvr = ["dep:ovr_overlay", "dep:json"]
|
||||
openxr = ["dep:openxr", "dep:libmonado"]
|
||||
openxr = ["dep:openxr", "dep:libmonado", "dep:prost"]
|
||||
osc = ["dep:rosc"]
|
||||
x11 = ["dep:xcb", "wlx-capture/xshm", "xkbcommon/x11"]
|
||||
wayland = ["pipewire", "wlx-capture/wlr", "xkbcommon/wayland"]
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ impl InputBlocker {
|
|||
}
|
||||
|
||||
pub fn update(&mut self, app: &mut AppState) {
|
||||
let Some(monado) = &mut app.monado else {
|
||||
let Some(monado) = &mut app.monado_state else {
|
||||
return; // monado not available
|
||||
};
|
||||
|
||||
|
|
@ -50,7 +50,7 @@ impl InputBlocker {
|
|||
} else {
|
||||
trace!("Unblocking input");
|
||||
}
|
||||
self.block_inputs(monado, should_block_inputs, should_block_poses);
|
||||
self.block_inputs(&mut monado.ipc, should_block_inputs, should_block_poses);
|
||||
}
|
||||
|
||||
self.inputs_blocked_last_frame = should_block_inputs;
|
||||
|
|
|
|||
|
|
@ -272,7 +272,7 @@ impl OpenXrInputSource {
|
|||
}
|
||||
|
||||
pub fn update_devices(app: &mut AppState) -> bool {
|
||||
let Some(monado) = &mut app.monado else {
|
||||
let Some(monado) = &mut app.monado_state else {
|
||||
return false; // monado not available
|
||||
};
|
||||
|
||||
|
|
@ -297,7 +297,7 @@ impl OpenXrInputSource {
|
|||
let mut seen = Vec::<u32>::with_capacity(32);
|
||||
|
||||
for (mnd_role, wlx_role) in roles {
|
||||
let device = monado.device_from_role(mnd_role);
|
||||
let device = monado.ipc.device_from_role(mnd_role);
|
||||
if let Ok(mut device) = device
|
||||
&& !seen.contains(&device.index)
|
||||
{
|
||||
|
|
@ -305,7 +305,7 @@ impl OpenXrInputSource {
|
|||
Self::update_device_battery_status(&mut device, wlx_role, &mut app.input_state);
|
||||
}
|
||||
}
|
||||
if let Ok(devices) = monado.devices() {
|
||||
if let Ok(devices) = monado.ipc.devices() {
|
||||
for mut device in devices {
|
||||
if !seen.contains(&device.index) {
|
||||
let role = if device.name_id >= 4 && device.name_id <= 8 {
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ mod blocker;
|
|||
mod helpers;
|
||||
mod input;
|
||||
mod lines;
|
||||
pub mod monado_state;
|
||||
mod overlay;
|
||||
mod playspace;
|
||||
mod skybox;
|
||||
|
|
@ -85,15 +86,18 @@ pub fn openxr_run(show_by_default: bool, headless: bool) -> Result<(), BackendEr
|
|||
|
||||
let mut delete_queue = vec![];
|
||||
|
||||
app.monado_init();
|
||||
app.monado_state_init();
|
||||
|
||||
let mut playspace = app.monado.as_mut().and_then(|m| {
|
||||
playspace::PlayspaceMover::new(m)
|
||||
let mut playspace = app.monado_state.as_mut().and_then(|m| {
|
||||
playspace::PlayspaceMover::new(&mut m.ipc)
|
||||
.map_err(|e| log::warn!("Will not use Monado playspace mover: {e}"))
|
||||
.ok()
|
||||
});
|
||||
|
||||
let mut blocker = app.monado.as_ref().map(blocker::InputBlocker::new);
|
||||
let mut blocker = app
|
||||
.monado_state
|
||||
.as_ref()
|
||||
.map(|m| blocker::InputBlocker::new(&m.ipc));
|
||||
|
||||
let (session, mut frame_wait, mut frame_stream) = unsafe {
|
||||
let raw_session = helpers::create_overlay_session(
|
||||
|
|
@ -211,7 +215,7 @@ pub fn openxr_run(show_by_default: bool, headless: bool) -> Result<(), BackendEr
|
|||
}
|
||||
}
|
||||
|
||||
if app.monado.is_some() && next_device_update <= Instant::now() {
|
||||
if app.monado_state.is_some() && next_device_update <= Instant::now() {
|
||||
let changed = OpenXrInputSource::update_devices(&mut app);
|
||||
if changed {
|
||||
overlays.devices_changed(&mut app)?;
|
||||
|
|
@ -403,6 +407,10 @@ pub fn openxr_run(show_by_default: bool, headless: bool) -> Result<(), BackendEr
|
|||
futures.wait()?;
|
||||
// End rendering
|
||||
|
||||
if let Some(monado_state) = &mut app.monado_state {
|
||||
monado_state.update();
|
||||
}
|
||||
|
||||
// Layer composition
|
||||
let mut layers = vec![];
|
||||
if !main_session_visible && let Some(skybox) = skybox.as_mut() {
|
||||
|
|
@ -499,8 +507,8 @@ pub fn openxr_run(show_by_default: bool, headless: bool) -> Result<(), BackendEr
|
|||
watch.config.active_state.as_mut().unwrap().transform = watch_transform;
|
||||
} // main_loop
|
||||
|
||||
if let (Some(blocker), Some(monado)) = (blocker, app.monado.as_mut()) {
|
||||
blocker.unblock(monado);
|
||||
if let (Some(blocker), Some(monado)) = (blocker, app.monado_state.as_mut()) {
|
||||
blocker.unblock(&mut monado.ipc);
|
||||
}
|
||||
|
||||
overlays.persist_layout(&mut app);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,25 @@
|
|||
use crate::subsystem::monado_metrics::{self, metrics_fd::MonadoMetricsFd};
|
||||
|
||||
pub struct MonadoState {
|
||||
pub ipc: libmonado::Monado,
|
||||
pub metrics: Option<MonadoMetricsFd>,
|
||||
}
|
||||
|
||||
impl MonadoState {
|
||||
pub fn new() -> anyhow::Result<Self> {
|
||||
let mut ipc = libmonado::Monado::auto_connect().map_err(|s| anyhow::anyhow!("{s}"))?;
|
||||
|
||||
let metrics = monado_metrics::metrics_fd::MonadoMetricsFd::new(&mut ipc)?;
|
||||
|
||||
Ok(Self {
|
||||
ipc,
|
||||
metrics: Some(metrics),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn update(&mut self) {
|
||||
if let Some(metrics) = &mut self.metrics {
|
||||
metrics.update();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -44,19 +44,19 @@ impl PlayspaceMover {
|
|||
}
|
||||
|
||||
pub fn handle_task(&mut self, app: &mut AppState, task: PlayspaceTask) {
|
||||
let Some(monado) = &mut app.monado else {
|
||||
let Some(monado) = &mut app.monado_state else {
|
||||
return; // monado not available
|
||||
};
|
||||
|
||||
match task {
|
||||
PlayspaceTask::FixFloor => {
|
||||
self.fix_floor(&app.input_state, monado);
|
||||
self.fix_floor(&app.input_state, &mut monado.ipc);
|
||||
}
|
||||
PlayspaceTask::Reset => {
|
||||
self.reset_offset(monado);
|
||||
self.reset_offset(&mut monado.ipc);
|
||||
}
|
||||
PlayspaceTask::Recenter => {
|
||||
self.recenter(&app.input_state, monado);
|
||||
self.recenter(&app.input_state, &mut monado.ipc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -66,7 +66,7 @@ impl PlayspaceMover {
|
|||
overlays: &mut OverlayWindowManager<OpenXrOverlayData>,
|
||||
app: &mut AppState,
|
||||
) {
|
||||
let Some(monado) = &mut app.monado else {
|
||||
let Some(monado) = &mut app.monado_state else {
|
||||
return; // monado not available
|
||||
};
|
||||
|
||||
|
|
@ -74,7 +74,7 @@ impl PlayspaceMover {
|
|||
if pointer.now.space_reset {
|
||||
if !pointer.before.space_reset {
|
||||
log::info!("Space reset");
|
||||
self.reset_offset(monado);
|
||||
self.reset_offset(&mut monado.ipc);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
@ -111,7 +111,7 @@ impl PlayspaceMover {
|
|||
data.pose *= space_transform;
|
||||
data.hand_pose = new_hand;
|
||||
|
||||
apply_offset(data.pose, monado);
|
||||
apply_offset(data.pose, &mut monado.ipc);
|
||||
self.rotate = Some(data);
|
||||
} else {
|
||||
for (i, pointer) in app.input_state.pointers.iter().enumerate() {
|
||||
|
|
@ -167,7 +167,7 @@ impl PlayspaceMover {
|
|||
data.pose.translation += relative_pos;
|
||||
data.hand_pose = new_hand;
|
||||
|
||||
apply_offset(data.pose, monado);
|
||||
apply_offset(data.pose, &mut monado.ipc);
|
||||
self.drag = Some(data);
|
||||
} else {
|
||||
for (i, pointer) in app.input_state.pointers.iter().enumerate() {
|
||||
|
|
|
|||
|
|
@ -471,11 +471,11 @@ impl DashInterface<AppState> for DashInterfaceLive {
|
|||
&mut self,
|
||||
app: &mut AppState,
|
||||
) -> anyhow::Result<Vec<dash_interface::MonadoClient>> {
|
||||
let Some(monado) = &mut app.monado else {
|
||||
let Some(monado) = &mut app.monado_state else {
|
||||
return Ok(Vec::new()); // no monado available
|
||||
};
|
||||
|
||||
let clients = monado_list_clients_filtered(monado)?;
|
||||
let clients = monado_list_clients_filtered(&mut monado.ipc)?;
|
||||
|
||||
let mut res = Vec::<dash_interface::MonadoClient>::new();
|
||||
|
||||
|
|
@ -499,29 +499,29 @@ impl DashInterface<AppState> for DashInterfaceLive {
|
|||
|
||||
#[cfg(feature = "openxr")]
|
||||
fn monado_client_focus(&mut self, app: &mut AppState, name: &str) -> anyhow::Result<()> {
|
||||
let Some(monado) = &mut app.monado else {
|
||||
let Some(monado) = &mut app.monado_state else {
|
||||
return Ok(()); // no monado available
|
||||
};
|
||||
|
||||
monado_client_focus(monado, name)
|
||||
monado_client_focus(&mut monado.ipc, name)
|
||||
}
|
||||
|
||||
#[cfg(feature = "openxr")]
|
||||
fn monado_brightness_get(&mut self, app: &mut AppState) -> Option<f32> {
|
||||
let Some(monado) = &mut app.monado else {
|
||||
let Some(monado) = &mut app.monado_state else {
|
||||
return None;
|
||||
};
|
||||
|
||||
monado_get_brightness(monado)
|
||||
monado_get_brightness(&mut monado.ipc)
|
||||
}
|
||||
|
||||
#[cfg(feature = "openxr")]
|
||||
fn monado_brightness_set(&mut self, app: &mut AppState, brightness: f32) -> Option<()> {
|
||||
let Some(monado) = &mut app.monado else {
|
||||
let Some(monado) = &mut app.monado_state else {
|
||||
return None;
|
||||
};
|
||||
|
||||
monado_set_brightness(monado, brightness).ok()
|
||||
monado_set_brightness(&mut monado.ipc, brightness).ok()
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "openxr"))]
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ use wgui::{
|
|||
drawing, font_config::WguiFontConfig, gfx::WGfx, globals::WguiGlobals, parser::parse_color_hex,
|
||||
renderer_vk::context::SharedContext as WSharedContext,
|
||||
};
|
||||
use wlx_common::async_executor::AsyncExecutor;
|
||||
use wlx_common::locale::WayVRLangProvider;
|
||||
use wlx_common::{
|
||||
audio,
|
||||
|
|
@ -18,7 +19,10 @@ use wlx_common::{
|
|||
overlays::{ToastDisplayMethod, ToastTopic},
|
||||
};
|
||||
|
||||
#[cfg(feature = "openxr")]
|
||||
use crate::backend;
|
||||
use crate::backend::wayvr::WvrServerState;
|
||||
|
||||
#[cfg(feature = "osc")]
|
||||
use crate::subsystem::osc::OscSender;
|
||||
|
||||
|
|
@ -34,6 +38,7 @@ use crate::{
|
|||
pub struct AppState {
|
||||
pub session: AppSession,
|
||||
pub tasks: TaskContainer,
|
||||
pub executor: AsyncExecutor,
|
||||
|
||||
pub gfx: Arc<WGfx>,
|
||||
pub gfx_extras: WGfxExtras,
|
||||
|
|
@ -67,7 +72,7 @@ pub struct AppState {
|
|||
pub wvr_server: Option<WvrServerState>,
|
||||
|
||||
#[cfg(feature = "openxr")]
|
||||
pub monado: Option<libmonado::Monado>,
|
||||
pub monado_state: Option<backend::openxr::monado_state::MonadoState>,
|
||||
}
|
||||
|
||||
#[allow(unused_mut)]
|
||||
|
|
@ -152,9 +157,12 @@ impl AppState {
|
|||
|
||||
let lang_provider = WayVRLangProvider::from_config(&session.config);
|
||||
|
||||
let executor = Rc::new(smol::LocalExecutor::new());
|
||||
|
||||
Ok(Self {
|
||||
session,
|
||||
tasks,
|
||||
executor,
|
||||
gfx,
|
||||
gfx_extras,
|
||||
hid_provider,
|
||||
|
|
@ -184,17 +192,25 @@ impl AppState {
|
|||
wvr_server,
|
||||
|
||||
#[cfg(feature = "openxr")]
|
||||
monado: None,
|
||||
monado_state: None,
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "openxr")]
|
||||
pub fn monado_init(&mut self) {
|
||||
pub fn monado_state_init(&mut self) {
|
||||
use crate::backend::openxr::monado_state::MonadoState;
|
||||
|
||||
log::debug!("Connecting to Monado IPC");
|
||||
self.monado = None; // stop connection first
|
||||
self.monado = libmonado::Monado::auto_connect()
|
||||
.map_err(|e| log::warn!("Will not use libmonado: {e}"))
|
||||
.ok();
|
||||
self.monado_state = None; // stop connection first
|
||||
|
||||
match MonadoState::new() {
|
||||
Ok(m) => {
|
||||
self.monado_state = Some(m);
|
||||
}
|
||||
Err(e) => {
|
||||
log::error!("Will not use libmonado: {e:?}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,3 +5,6 @@ pub mod notifications;
|
|||
|
||||
#[cfg(feature = "osc")]
|
||||
pub mod osc;
|
||||
|
||||
#[cfg(feature = "openxr")]
|
||||
pub mod monado_metrics;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
`proto.rs` can be generated via prost_build tool.
|
||||
|
||||
To generate a new version of protobuf file:
|
||||
|
||||
```
|
||||
cd scripts/prost_build
|
||||
OUT_DIR=your_directory cargo run
|
||||
```
|
||||
|
||||
new protobuf files will be generated in `your_directory` directory.
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
use std::{
|
||||
io::Read,
|
||||
os::{fd::AsFd, unix::net::UnixStream},
|
||||
};
|
||||
|
||||
use crate::subsystem::monado_metrics::proto;
|
||||
|
||||
pub struct MonadoMetricsFd {
|
||||
stream_reader: UnixStream,
|
||||
stream_writer: UnixStream,
|
||||
}
|
||||
|
||||
impl MonadoMetricsFd {
|
||||
pub fn new(monado: &mut libmonado::Monado) -> anyhow::Result<Self> {
|
||||
let (stream_reader, stream_writer) = std::os::unix::net::UnixStream::pair()?;
|
||||
stream_writer.set_nonblocking(true)?;
|
||||
stream_reader.set_nonblocking(true)?;
|
||||
|
||||
monado.push_metrics_fd(stream_writer.as_fd(), true)?;
|
||||
|
||||
Ok(Self {
|
||||
stream_reader,
|
||||
stream_writer,
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_message(&self, record: proto::Record) {
|
||||
log::debug!("metrics message: {record:?}");
|
||||
}
|
||||
|
||||
// called every frame
|
||||
pub fn update(&mut self) {
|
||||
let mut buf: [u8; 1024] = [0; 1024];
|
||||
|
||||
while let Ok(byte_count) = self.stream_reader.read(&mut buf) {
|
||||
if byte_count == 0 {
|
||||
debug_assert!(false);
|
||||
break;
|
||||
}
|
||||
|
||||
let res: Result<proto::Record, _> = prost::Message::decode_length_delimited(&buf[..]);
|
||||
match res {
|
||||
Ok(record) => {
|
||||
self.parse_message(record);
|
||||
}
|
||||
Err(e) => {
|
||||
log::error!("decode error: {e}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
pub mod metrics_fd;
|
||||
pub mod proto;
|
||||
|
|
@ -0,0 +1,180 @@
|
|||
// This file is @generated by prost-build.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)]
|
||||
pub struct Version {
|
||||
#[prost(uint32, tag = "1")]
|
||||
pub major: u32,
|
||||
#[prost(uint32, tag = "2")]
|
||||
pub minor: u32,
|
||||
}
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)]
|
||||
pub struct SessionFrame {
|
||||
/// ! Which session this frame belongs to.
|
||||
#[prost(int64, tag = "1")]
|
||||
pub session_id: i64,
|
||||
/// ! ID of frame.
|
||||
#[prost(int64, tag = "2")]
|
||||
pub frame_id: i64,
|
||||
/// ! How long we thought the frame would take.
|
||||
#[prost(uint64, tag = "3")]
|
||||
pub predicted_frame_time_ns: u64,
|
||||
/// ! When we predicted the app should wake up.
|
||||
#[prost(uint64, tag = "4")]
|
||||
pub predicted_wake_up_time_ns: u64,
|
||||
/// ! When the client's GPU work should have completed.
|
||||
#[prost(uint64, tag = "5")]
|
||||
pub predicted_gpu_done_time_ns: u64,
|
||||
/// ! When we predicted this frame to be shown.
|
||||
#[prost(uint64, tag = "6")]
|
||||
pub predicted_display_time_ns: u64,
|
||||
/// ! The selected display period.
|
||||
#[prost(uint64, tag = "7")]
|
||||
pub predicted_display_period_ns: u64,
|
||||
/// !
|
||||
/// When the app told us to display this frame, can be different
|
||||
/// then the predicted display time so we track that separately.
|
||||
#[prost(uint64, tag = "8")]
|
||||
pub display_time_ns: u64,
|
||||
/// ! When the predict call was made (inside of xrWaitFrame).
|
||||
#[prost(uint64, tag = "9")]
|
||||
pub when_predicted_ns: u64,
|
||||
/// ! When the waiting thread was woken up.
|
||||
#[prost(uint64, tag = "10")]
|
||||
pub when_wait_woke_ns: u64,
|
||||
/// ! When xrBeginFrame was called.
|
||||
#[prost(uint64, tag = "11")]
|
||||
pub when_begin_ns: u64,
|
||||
/// ! When the layer information was delivered, (inside of xrEndFrame).
|
||||
#[prost(uint64, tag = "12")]
|
||||
pub when_delivered_ns: u64,
|
||||
/// ! When the scheduled GPU work was completed.
|
||||
#[prost(uint64, tag = "13")]
|
||||
pub when_gpu_done_ns: u64,
|
||||
/// ! Was this frame discarded.
|
||||
#[prost(bool, tag = "14")]
|
||||
pub discarded: bool,
|
||||
}
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)]
|
||||
pub struct Used {
|
||||
/// ! Owning session of the frame.
|
||||
#[prost(int64, tag = "1")]
|
||||
pub session_id: i64,
|
||||
/// ! Which session frame was used by the compositor.
|
||||
#[prost(int64, tag = "2")]
|
||||
pub session_frame_id: i64,
|
||||
/// ! The system frame that the session was used by.
|
||||
#[prost(int64, tag = "3")]
|
||||
pub system_frame_id: i64,
|
||||
/// ! When the frame was latched.
|
||||
#[prost(uint64, tag = "4")]
|
||||
pub when_ns: u64,
|
||||
}
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)]
|
||||
pub struct SystemFrame {
|
||||
/// ! ID of frame.
|
||||
#[prost(int64, tag = "1")]
|
||||
pub frame_id: i64,
|
||||
/// ! Projected pixels to photon time.
|
||||
#[prost(uint64, tag = "2")]
|
||||
pub predicted_display_time_ns: u64,
|
||||
/// ! Current period of displaying of frames.
|
||||
#[prost(uint64, tag = "3")]
|
||||
pub predicted_display_period_ns: u64,
|
||||
/// ! When the compositor should hand pixels to display hardware.
|
||||
#[prost(uint64, tag = "4")]
|
||||
pub desired_present_time_ns: u64,
|
||||
/// ! The time that the compositor should wake up.
|
||||
#[prost(uint64, tag = "5")]
|
||||
pub wake_up_time_ns: u64,
|
||||
#[prost(uint64, tag = "6")]
|
||||
pub present_slop_ns: u64,
|
||||
}
|
||||
/// !
|
||||
/// Out of band info about a GPU timing from a system compositor.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)]
|
||||
pub struct SystemGpuInfo {
|
||||
/// ! ID of frame.
|
||||
#[prost(int64, tag = "1")]
|
||||
pub frame_id: i64,
|
||||
/// ! Start of GPU work.
|
||||
#[prost(uint64, tag = "2")]
|
||||
pub gpu_start_ns: u64,
|
||||
/// ! End of GPU work.
|
||||
#[prost(uint64, tag = "3")]
|
||||
pub gpu_end_ns: u64,
|
||||
/// ! When the information was gathered.
|
||||
#[prost(uint64, tag = "4")]
|
||||
pub when_ns: u64,
|
||||
}
|
||||
/// !
|
||||
/// Information that comes from the vulkan present timing.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)]
|
||||
pub struct SystemPresentInfo {
|
||||
/// ! ID of frame.
|
||||
#[prost(int64, tag = "1")]
|
||||
pub frame_id: i64,
|
||||
/// ! The total expected time for the compositor to complete a frame.
|
||||
#[prost(uint64, tag = "2")]
|
||||
pub expected_comp_time_ns: u64,
|
||||
/// ! The time we predicted the compositor to wake up time.
|
||||
#[prost(uint64, tag = "3")]
|
||||
pub predicted_wake_up_time_ns: u64,
|
||||
/// ! Predicted time for completion of the GPU work.
|
||||
#[prost(uint64, tag = "4")]
|
||||
pub predicted_done_time_ns: u64,
|
||||
/// ! Predicted display time.
|
||||
#[prost(uint64, tag = "5")]
|
||||
pub predicted_display_time_ns: u64,
|
||||
/// ! When was this frame predicted.
|
||||
#[prost(uint64, tag = "6")]
|
||||
pub when_predict_ns: u64,
|
||||
/// ! When we last woke up the compositor after its equivalent of wait_frame.
|
||||
#[prost(uint64, tag = "7")]
|
||||
pub when_woke_ns: u64,
|
||||
/// ! When the compositor started rendering a frame
|
||||
#[prost(uint64, tag = "8")]
|
||||
pub when_began_ns: u64,
|
||||
/// ! When the compositor finished rendering a frame
|
||||
#[prost(uint64, tag = "9")]
|
||||
pub when_submitted_ns: u64,
|
||||
/// ! When new frame timing info was last added.
|
||||
#[prost(uint64, tag = "10")]
|
||||
pub when_infoed_ns: u64,
|
||||
/// ! When we wanted to start presenting.
|
||||
#[prost(uint64, tag = "11")]
|
||||
pub desired_present_time_ns: u64,
|
||||
/// ! The slop used for this frame.
|
||||
#[prost(uint64, tag = "12")]
|
||||
pub present_slop_ns: u64,
|
||||
/// ! Margin of GPU to present time.
|
||||
#[prost(uint64, tag = "13")]
|
||||
pub present_margin_ns: u64,
|
||||
/// ! When the present time actually happened.
|
||||
#[prost(uint64, tag = "14")]
|
||||
pub actual_present_time_ns: u64,
|
||||
/// ! The earliest we could have presented.
|
||||
#[prost(uint64, tag = "15")]
|
||||
pub earliest_present_time_ns: u64,
|
||||
}
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)]
|
||||
pub struct Record {
|
||||
#[prost(oneof = "record::Record", tags = "1, 2, 3, 4, 5, 6")]
|
||||
pub record: ::core::option::Option<record::Record>,
|
||||
}
|
||||
/// Nested message and enum types in `Record`.
|
||||
pub mod record {
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Oneof)]
|
||||
pub enum Record {
|
||||
#[prost(message, tag = "1")]
|
||||
Version(super::Version),
|
||||
#[prost(message, tag = "2")]
|
||||
SessionFrame(super::SessionFrame),
|
||||
#[prost(message, tag = "3")]
|
||||
Used(super::Used),
|
||||
#[prost(message, tag = "4")]
|
||||
SystemFrame(super::SystemFrame),
|
||||
#[prost(message, tag = "5")]
|
||||
SystemGpuInfo(super::SystemGpuInfo),
|
||||
#[prost(message, tag = "6")]
|
||||
SystemPresentInfo(super::SystemPresentInfo),
|
||||
}
|
||||
}
|
||||
|
|
@ -22,7 +22,7 @@ strum.workspace = true
|
|||
xdg.workspace = true
|
||||
|
||||
chrono = "0.4.42"
|
||||
smol = "2.0.2"
|
||||
smol = { workspace = true }
|
||||
wgui = { path = "../wgui/" }
|
||||
rodio = { version = "0.21.1", default-features = false, features = [
|
||||
"playback",
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
pub mod astr_containers;
|
||||
pub mod async_executor;
|
||||
pub mod audio;
|
||||
pub mod cache_dir;
|
||||
pub mod common;
|
||||
|
|
|
|||
Loading…
Reference in New Issue