mirror of https://github.com/wayvr-org/wayvr.git
display debug graphs
This commit is contained in:
parent
d5148e2107
commit
c16c403966
|
|
@ -910,17 +910,6 @@ dependencies = [
|
|||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "chacha20"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6f8d983286843e49675a4b7a2d174efe136dc93a18d69130dd18198a6c167601"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cpufeatures 0.3.0",
|
||||
"rand_core 0.10.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.4.42"
|
||||
|
|
@ -1242,15 +1231,6 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cpufeatures"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crc32fast"
|
||||
version = "1.5.0"
|
||||
|
|
@ -1437,7 +1417,6 @@ dependencies = [
|
|||
"hyper",
|
||||
"keyvalues-parser",
|
||||
"log",
|
||||
"rand 0.10.0",
|
||||
"rust-embed",
|
||||
"serde",
|
||||
"serde_json",
|
||||
|
|
@ -2127,20 +2106,6 @@ dependencies = [
|
|||
"wasip2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "139ef39800118c7683f2fd3c98c1b23c09ae076556b435f8e9064ae108aaeeec"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"r-efi",
|
||||
"rand_core 0.10.0",
|
||||
"wasip2",
|
||||
"wasip3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gif"
|
||||
version = "0.14.1"
|
||||
|
|
@ -2475,12 +2440,6 @@ dependencies = [
|
|||
"zerovec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "id-arena"
|
||||
version = "2.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954"
|
||||
|
||||
[[package]]
|
||||
name = "ident_case"
|
||||
version = "1.0.1"
|
||||
|
|
@ -2616,8 +2575,6 @@ checksum = "0ad4bb2b565bca0645f4d68c5c9af97fba094e9791da685bf83cb5f3ce74acf2"
|
|||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown 0.16.1",
|
||||
"serde",
|
||||
"serde_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -2844,12 +2801,6 @@ version = "1.3.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
|
||||
|
||||
[[package]]
|
||||
name = "leb128fmt"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2"
|
||||
|
||||
[[package]]
|
||||
name = "lebe"
|
||||
version = "0.5.3"
|
||||
|
|
@ -4385,17 +4336,6 @@ dependencies = [
|
|||
"rand_core 0.9.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bc266eb313df6c5c09c1c7b1fbe2510961e5bcd3add930c1e31f7ed9da0feff8"
|
||||
dependencies = [
|
||||
"chacha20",
|
||||
"getrandom 0.4.1",
|
||||
"rand_core 0.10.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.2.2"
|
||||
|
|
@ -4453,12 +4393,6 @@ dependencies = [
|
|||
"getrandom 0.3.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c8d0fd677905edcbeedbf2edb6494d676f0e98d54d5cf9bda0b061cb8fb8aba"
|
||||
|
||||
[[package]]
|
||||
name = "rand_hc"
|
||||
version = "0.2.0"
|
||||
|
|
@ -4676,12 +4610,6 @@ dependencies = [
|
|||
"bytemuck",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ringbuffer"
|
||||
version = "0.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "57b0b88a509053cbfd535726dcaaceee631313cef981266119527a1d110f6d2b"
|
||||
|
||||
[[package]]
|
||||
name = "rodio"
|
||||
version = "0.21.1"
|
||||
|
|
@ -5061,7 +4989,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cpufeatures 0.2.17",
|
||||
"cpufeatures",
|
||||
"digest",
|
||||
]
|
||||
|
||||
|
|
@ -6003,12 +5931,6 @@ version = "0.2.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
|
||||
|
||||
[[package]]
|
||||
name = "unsafe-libyaml"
|
||||
version = "0.2.11"
|
||||
|
|
@ -6210,16 +6132,7 @@ version = "1.0.1+wasi-0.2.4"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7"
|
||||
dependencies = [
|
||||
"wit-bindgen 0.46.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasip3"
|
||||
version = "0.4.0+wasi-0.3.0-rc-2026-01-06"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5"
|
||||
dependencies = [
|
||||
"wit-bindgen 0.51.0",
|
||||
"wit-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -6280,40 +6193,6 @@ dependencies = [
|
|||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-encoder"
|
||||
version = "0.244.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319"
|
||||
dependencies = [
|
||||
"leb128fmt",
|
||||
"wasmparser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-metadata"
|
||||
version = "0.244.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"indexmap 2.12.1",
|
||||
"wasm-encoder",
|
||||
"wasmparser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasmparser"
|
||||
version = "0.244.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"hashbrown 0.15.5",
|
||||
"indexmap 2.12.1",
|
||||
"semver",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wayland-backend"
|
||||
version = "0.3.12"
|
||||
|
|
@ -6599,7 +6478,6 @@ dependencies = [
|
|||
"parking_lot",
|
||||
"regex",
|
||||
"resvg",
|
||||
"ringbuffer",
|
||||
"roxmltree 0.21.1",
|
||||
"rust-embed",
|
||||
"rustc-hash 2.1.1",
|
||||
|
|
@ -7123,94 +7001,6 @@ version = "0.46.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59"
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen"
|
||||
version = "0.51.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5"
|
||||
dependencies = [
|
||||
"wit-bindgen-rust-macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-core"
|
||||
version = "0.51.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"heck 0.5.0",
|
||||
"wit-parser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-rust"
|
||||
version = "0.51.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"heck 0.5.0",
|
||||
"indexmap 2.12.1",
|
||||
"prettyplease",
|
||||
"syn 2.0.113",
|
||||
"wasm-metadata",
|
||||
"wit-bindgen-core",
|
||||
"wit-component",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-rust-macro"
|
||||
version = "0.51.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"prettyplease",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.113",
|
||||
"wit-bindgen-core",
|
||||
"wit-bindgen-rust",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-component"
|
||||
version = "0.244.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bitflags 2.10.0",
|
||||
"indexmap 2.12.1",
|
||||
"log",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"wasm-encoder",
|
||||
"wasm-metadata",
|
||||
"wasmparser",
|
||||
"wit-parser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-parser"
|
||||
version = "0.244.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"id-arena",
|
||||
"indexmap 2.12.1",
|
||||
"log",
|
||||
"semver",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"unicode-xid",
|
||||
"wasmparser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wlx-capture"
|
||||
version = "0.6.0"
|
||||
|
|
|
|||
|
|
@ -28,7 +28,6 @@ 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"
|
||||
rand = "0.10.0"
|
||||
|
||||
[features]
|
||||
default = ["monado"]
|
||||
|
|
|
|||
|
|
@ -1,12 +1,17 @@
|
|||
<layout>
|
||||
<include src="../t_group_box.xml" />
|
||||
|
||||
<elements>
|
||||
<rectangle macro="group_box">
|
||||
<GroupBoxTitle src_builtin="dashboard/not_a_bug.svg" text="Debug timings" />
|
||||
<!-- name, limit_min, limit_max -->
|
||||
<template name="DebugGraph">
|
||||
<rectangle flex_direction="column" align_items="center" gap="8" border="2" color="#ffffff11" color2="#ffffff22" gradient="vertical" border_color="#ffffff33" round="4" padding="4">
|
||||
<label text="${name}" size="9" weight="bold" />
|
||||
<BarGraph id="graph" width="180" height="70" unit="ms" limit_min="${limit_min}" limit_max="${limit_max}" capacity="50" />
|
||||
</rectangle>
|
||||
</template>
|
||||
|
||||
<BarGraph id="graph_first" width="200" height="100" unit="%" limit_min="0" limit_max="50" capacity="100" />
|
||||
<BarGraph id="graph_second" width="300" height="200" unit="ms" capacity="50" />
|
||||
<elements>
|
||||
<rectangle macro="group_box" id="parent" flex_wrap="wrap" flex_direction="row">
|
||||
<GroupBoxTitle src_builtin="dashboard/not_a_bug.svg" text="Debug timings" />
|
||||
</rectangle>
|
||||
</elements>
|
||||
</layout>
|
||||
|
|
@ -8,13 +8,13 @@ use wgui::{
|
|||
slider::ComponentSlider,
|
||||
tabs::ComponentTabs,
|
||||
},
|
||||
drawing,
|
||||
drawing::{self, Color},
|
||||
globals::WguiGlobals,
|
||||
layout::{Layout, WidgetID},
|
||||
parser::{self, Fetchable, ParseDocumentParams, ParserState},
|
||||
parser::{self, Fetchable, ParseDocumentParams, ParserData, ParserState},
|
||||
task::Tasks,
|
||||
};
|
||||
use wlx_common::dash_interface;
|
||||
use wlx_common::dash_interface::{self, DashInterface, MonadoDumpSessionFrame};
|
||||
|
||||
use crate::{
|
||||
frontend::Frontend,
|
||||
|
|
@ -59,12 +59,37 @@ struct SubtabGeneralSettings {
|
|||
state: ParserState,
|
||||
}
|
||||
|
||||
struct DebugGraph {
|
||||
graph: Rc<ComponentBarGraph>,
|
||||
#[allow(dead_code)]
|
||||
data: ParserData,
|
||||
}
|
||||
|
||||
struct TimingsSession {
|
||||
last_frame: MonadoDumpSessionFrame,
|
||||
}
|
||||
|
||||
struct Graphs {
|
||||
predicted_display_time: DebugGraph,
|
||||
predicted_frame_time: DebugGraph,
|
||||
predicted_wake_up_time: DebugGraph,
|
||||
predicted_gpu_done_time: DebugGraph,
|
||||
predicted_display_period: DebugGraph,
|
||||
display_time: DebugGraph,
|
||||
when_predicted: DebugGraph,
|
||||
when_wait_woke: DebugGraph,
|
||||
when_begin: DebugGraph,
|
||||
when_delivered: DebugGraph,
|
||||
when_gpu_done: DebugGraph,
|
||||
}
|
||||
|
||||
struct SubtabDebugTimings {
|
||||
#[allow(dead_code)]
|
||||
state: ParserState,
|
||||
|
||||
graph_first: Rc<ComponentBarGraph>,
|
||||
graph_second: Rc<ComponentBarGraph>,
|
||||
graphs: Graphs,
|
||||
|
||||
sessions: HashMap<i64 /* session id */, TimingsSession>,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
|
|
@ -142,7 +167,7 @@ impl<T> Tab<T> for TabMonado<T> {
|
|||
}
|
||||
}
|
||||
Subtab::DebugTimings(timings) => {
|
||||
timings.update(&mut frontend.layout);
|
||||
timings.update(data, frontend);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -224,36 +249,177 @@ impl SubtabGeneralSettings {
|
|||
}
|
||||
}
|
||||
|
||||
fn mount_graph(
|
||||
state: &mut ParserState,
|
||||
globals: &WguiGlobals,
|
||||
layout: &mut Layout,
|
||||
id_parent: WidgetID,
|
||||
name: &'static str,
|
||||
limits: (f32, f32),
|
||||
) -> anyhow::Result<DebugGraph> {
|
||||
let mut params = HashMap::new();
|
||||
params.insert(Rc::from("name"), Rc::from(name));
|
||||
params.insert(Rc::from("limit_min"), Rc::from(limits.0.to_string()));
|
||||
params.insert(Rc::from("limit_max"), Rc::from(limits.1.to_string()));
|
||||
|
||||
let data = state.parse_template(
|
||||
&doc_params_tab_debug_timings(globals),
|
||||
"DebugGraph",
|
||||
layout,
|
||||
id_parent,
|
||||
params,
|
||||
)?;
|
||||
|
||||
let graph = data.fetch_component_as::<ComponentBarGraph>("graph")?;
|
||||
Ok(DebugGraph { graph, data })
|
||||
}
|
||||
|
||||
fn ns_to_ms(ns: i64) -> f32 {
|
||||
(ns / 1000) as f32 / 1000.0
|
||||
}
|
||||
|
||||
impl SubtabDebugTimings {
|
||||
fn new<T>(parent_id: WidgetID, frontend: &mut Frontend<T>) -> anyhow::Result<Self> {
|
||||
let state = wgui::parser::parse_from_assets(
|
||||
let mut state = wgui::parser::parse_from_assets(
|
||||
&doc_params_tab_debug_timings(&frontend.globals),
|
||||
&mut frontend.layout,
|
||||
parent_id,
|
||||
)?;
|
||||
|
||||
let graph_first = state.fetch_component_as::<ComponentBarGraph>("graph_first")?;
|
||||
let graph_second = state.fetch_component_as::<ComponentBarGraph>("graph_second")?;
|
||||
let id_parent = state.get_widget_id("parent")?;
|
||||
|
||||
let mut graphs: Vec<DebugGraph> = Vec::new();
|
||||
|
||||
let mut graph = |name: &'static str, limits: (f32, f32)| -> anyhow::Result<DebugGraph> {
|
||||
mount_graph(
|
||||
&mut state,
|
||||
&frontend.globals,
|
||||
&mut frontend.layout,
|
||||
id_parent,
|
||||
name,
|
||||
limits,
|
||||
)
|
||||
};
|
||||
|
||||
// populate graphs
|
||||
let graphs = Graphs {
|
||||
predicted_display_time: graph("Predicted display time", (0.0, 30.0))?,
|
||||
predicted_frame_time: graph("Predicted frame time", (0.0, 30.0))?,
|
||||
predicted_wake_up_time: graph("Predicted wake-up time", (0.0, 30.0))?,
|
||||
predicted_gpu_done_time: graph("Predicted GPU done time", (0.0, 30.0))?,
|
||||
predicted_display_period: graph("Predicted display period", (0.0, 30.0))?,
|
||||
display_time: graph("Display time", (0.0, 30.0))?,
|
||||
when_predicted: graph("When predicted", (0.0, 30.0))?,
|
||||
when_wait_woke: graph("When wait woke", (0.0, 30.0))?,
|
||||
when_begin: graph("When begin", (0.0, 30.0))?,
|
||||
when_delivered: graph("When delivered", (0.0, 30.0))?,
|
||||
when_gpu_done: graph("When gpu done", (0.0, 30.0))?,
|
||||
};
|
||||
|
||||
Ok(Self {
|
||||
state,
|
||||
graph_first,
|
||||
graph_second,
|
||||
graphs,
|
||||
sessions: Default::default(),
|
||||
})
|
||||
}
|
||||
|
||||
fn update(&mut self, layout: &mut Layout) {
|
||||
self.graph_first.push_value(ValueCell {
|
||||
value: rand::random_range(0.0..50.0),
|
||||
color: drawing::Color::new(rand::random_range(0.0..1.0), rand::random_range(0.0..1.0), 0.0, 1.0),
|
||||
});
|
||||
fn update<T>(&mut self, data: &mut T, frontend: &mut Frontend<T>) {
|
||||
if !frontend.interface.monado_metrics_set_enabled(data, true) {
|
||||
return;
|
||||
}
|
||||
|
||||
self.graph_second.push_value(ValueCell {
|
||||
value: rand::random_range(0.0..30.0),
|
||||
color: drawing::Color::new(0.0, rand::random_range(0.0..1.0), rand::random_range(0.0..1.0), 1.0),
|
||||
});
|
||||
let frames = frontend.interface.monado_metrics_dump_session_frames(data);
|
||||
if frames.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
layout.mark_redraw();
|
||||
let col_green = Color::new(0.0, 1.0, 0.0, 1.0);
|
||||
|
||||
for frame in frames {
|
||||
log::info!("{:?}", frame);
|
||||
|
||||
match self.sessions.get_mut(&frame.session_id) {
|
||||
Some(session) => {
|
||||
let predicted_display_time = ns_to_ms(session.last_frame.predicted_display_time_ns as i64);
|
||||
let predicted_frame_time = ns_to_ms(frame.predicted_frame_time_ns as i64);
|
||||
let predicted_wake_up_time =
|
||||
ns_to_ms(frame.predicted_wake_up_time_ns as i64 - session.last_frame.predicted_wake_up_time_ns as i64);
|
||||
let predicted_gpu_done_time =
|
||||
ns_to_ms(frame.predicted_gpu_done_time_ns as i64 - session.last_frame.predicted_gpu_done_time_ns as i64);
|
||||
let predicted_display_period = ns_to_ms(session.last_frame.predicted_display_period_ns as i64); // 6.944 ms for 144Hz
|
||||
let display_time = ns_to_ms(frame.display_time_ns as i64 - session.last_frame.display_time_ns as i64);
|
||||
let when_predicted = ns_to_ms(frame.when_predicted_ns as i64 - session.last_frame.when_predicted_ns as i64);
|
||||
let when_wait_woke = ns_to_ms(frame.when_wait_woke_ns as i64 - session.last_frame.when_wait_woke_ns as i64);
|
||||
let when_begin = ns_to_ms(frame.when_begin_ns as i64 - session.last_frame.when_begin_ns as i64);
|
||||
let when_delivered = ns_to_ms(frame.when_delivered_ns as i64 - session.last_frame.when_delivered_ns as i64);
|
||||
let when_gpu_done = ns_to_ms(frame.when_gpu_done_ns as i64 - session.last_frame.when_gpu_done_ns as i64);
|
||||
|
||||
self.graphs.predicted_display_time.graph.push_value(ValueCell {
|
||||
value: predicted_display_time,
|
||||
color: col_green,
|
||||
});
|
||||
|
||||
self.graphs.predicted_frame_time.graph.push_value(ValueCell {
|
||||
value: predicted_frame_time,
|
||||
color: col_green,
|
||||
});
|
||||
|
||||
self.graphs.predicted_wake_up_time.graph.push_value(ValueCell {
|
||||
value: predicted_wake_up_time,
|
||||
color: col_green,
|
||||
});
|
||||
|
||||
self.graphs.predicted_gpu_done_time.graph.push_value(ValueCell {
|
||||
value: predicted_gpu_done_time,
|
||||
color: col_green,
|
||||
});
|
||||
|
||||
self.graphs.predicted_display_period.graph.push_value(ValueCell {
|
||||
value: predicted_display_period,
|
||||
color: col_green,
|
||||
});
|
||||
|
||||
self.graphs.display_time.graph.push_value(ValueCell {
|
||||
value: display_time,
|
||||
color: col_green,
|
||||
});
|
||||
|
||||
self.graphs.when_predicted.graph.push_value(ValueCell {
|
||||
value: when_predicted,
|
||||
color: col_green,
|
||||
});
|
||||
|
||||
self.graphs.when_wait_woke.graph.push_value(ValueCell {
|
||||
value: when_wait_woke,
|
||||
color: col_green,
|
||||
});
|
||||
|
||||
self.graphs.when_begin.graph.push_value(ValueCell {
|
||||
value: when_begin,
|
||||
color: col_green,
|
||||
});
|
||||
|
||||
self.graphs.when_delivered.graph.push_value(ValueCell {
|
||||
value: when_delivered,
|
||||
color: col_green,
|
||||
});
|
||||
|
||||
self.graphs.when_gpu_done.graph.push_value(ValueCell {
|
||||
value: when_gpu_done,
|
||||
color: col_green,
|
||||
});
|
||||
|
||||
session.last_frame = frame;
|
||||
}
|
||||
None => {
|
||||
self
|
||||
.sessions
|
||||
.insert(frame.session_id, TimingsSession { last_frame: frame });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
frontend.layout.mark_redraw();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,23 +8,32 @@ pub struct MonadoState {
|
|||
impl MonadoState {
|
||||
pub fn new() -> anyhow::Result<Self> {
|
||||
let ipc = libmonado::Monado::auto_connect().map_err(|s| anyhow::anyhow!("{s}"))?;
|
||||
let mut res = Self { ipc, metrics: None };
|
||||
res.set_metrics_enabled(true)?;
|
||||
let res = Self { ipc, metrics: None };
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
pub fn update(&mut self) {
|
||||
if let Some(metrics) = &mut self.metrics {
|
||||
metrics.update();
|
||||
|
||||
if metrics.is_full() {
|
||||
let _ = self.set_metrics_enabled(false); // disable metrics if they aren't used
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_metrics_enabled(&mut self, enabled: bool) -> anyhow::Result<()> {
|
||||
if enabled && self.metrics.is_none() {
|
||||
self.metrics = Some(monado_metrics::metrics_fd::MonadoMetricsFd::new(
|
||||
&mut self.ipc,
|
||||
)?);
|
||||
if enabled {
|
||||
if self.metrics.is_none() {
|
||||
log::info!("Starting Monado metrics");
|
||||
self.metrics = Some(monado_metrics::metrics_fd::MonadoMetricsFd::new(
|
||||
&mut self.ipc,
|
||||
)?);
|
||||
}
|
||||
} else {
|
||||
if self.metrics.is_some() {
|
||||
log::info!("Stopping Monado metrics");
|
||||
}
|
||||
self.metrics = None;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -524,6 +524,70 @@ impl DashInterface<AppState> for DashInterfaceLive {
|
|||
monado_set_brightness(&mut monado.ipc, brightness).ok()
|
||||
}
|
||||
|
||||
#[cfg(feature = "openxr")]
|
||||
fn monado_metrics_set_enabled(&mut self, app: &mut AppState, enabled: bool) -> bool {
|
||||
let Some(monado) = &mut app.monado_state else {
|
||||
return false;
|
||||
};
|
||||
|
||||
if let Err(e) = monado.set_metrics_enabled(enabled) {
|
||||
log::error!("failed to enable metrics: {e:?}");
|
||||
return false;
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
#[cfg(feature = "openxr")]
|
||||
#[allow(clippy::match_same_arms)]
|
||||
fn monado_metrics_dump_session_frames(
|
||||
&mut self,
|
||||
app: &mut AppState,
|
||||
) -> Vec<dash_interface::MonadoDumpSessionFrame> {
|
||||
let Some(monado) = &mut app.monado_state else {
|
||||
return Vec::new();
|
||||
};
|
||||
|
||||
let Some(metrics) = &mut monado.metrics else {
|
||||
return Vec::new(); // metrics not enabled or not available
|
||||
};
|
||||
|
||||
metrics
|
||||
.dump_records()
|
||||
.iter()
|
||||
.filter_map(|record| {
|
||||
use crate::subsystem::monado_metrics::proto::record;
|
||||
let record = record.record?;
|
||||
match record {
|
||||
record::Record::SessionFrame(sframe) => {
|
||||
// map it to our struct
|
||||
Some(dash_interface::MonadoDumpSessionFrame {
|
||||
session_id: sframe.session_id,
|
||||
frame_id: sframe.frame_id,
|
||||
predicted_frame_time_ns: sframe.predicted_frame_time_ns,
|
||||
predicted_wake_up_time_ns: sframe.predicted_wake_up_time_ns,
|
||||
predicted_gpu_done_time_ns: sframe.predicted_gpu_done_time_ns,
|
||||
predicted_display_time_ns: sframe.predicted_display_time_ns,
|
||||
predicted_display_period_ns: sframe.predicted_display_period_ns,
|
||||
display_time_ns: sframe.display_time_ns,
|
||||
when_predicted_ns: sframe.when_predicted_ns,
|
||||
when_wait_woke_ns: sframe.when_wait_woke_ns,
|
||||
when_begin_ns: sframe.when_begin_ns,
|
||||
when_delivered_ns: sframe.when_delivered_ns,
|
||||
when_gpu_done_ns: sframe.when_gpu_done_ns,
|
||||
discarded: sframe.discarded,
|
||||
})
|
||||
}
|
||||
record::Record::Version(_) => None,
|
||||
record::Record::Used(_) => None,
|
||||
record::Record::SystemFrame(_) => None,
|
||||
record::Record::SystemGpuInfo(_) => None,
|
||||
record::Record::SystemPresentInfo(_) => None,
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "openxr"))]
|
||||
fn monado_client_list(
|
||||
&mut self,
|
||||
|
|
@ -543,6 +607,19 @@ impl DashInterface<AppState> for DashInterfaceLive {
|
|||
fn monado_brightness_set(&mut self, _: &mut AppState, _: f32) -> Option<()> {
|
||||
None
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "openxr"))]
|
||||
fn monado_metrics_set_enabled(&mut self, _: &mut AppState, _enabled: bool) {
|
||||
// not supported in this build
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "openxr"))]
|
||||
fn monado_metrics_dump_session_frames(
|
||||
&mut self,
|
||||
_: &mut AppState,
|
||||
) -> Vec<dash_interface::MonadoDumpSessionFrame> {
|
||||
Vec::new() // not supported in this build
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "openxr")]
|
||||
|
|
|
|||
|
|
@ -13,6 +13,8 @@ pub struct MonadoMetricsFd {
|
|||
records: VecDeque<proto::Record>,
|
||||
}
|
||||
|
||||
const RECORD_QUEUE_SIZE: usize = 500;
|
||||
|
||||
impl MonadoMetricsFd {
|
||||
pub fn new(monado: &mut libmonado::Monado) -> anyhow::Result<Self> {
|
||||
let (stream_reader, stream_writer) = std::os::unix::net::UnixStream::pair()?;
|
||||
|
|
@ -29,15 +31,21 @@ impl MonadoMetricsFd {
|
|||
}
|
||||
|
||||
fn parse_message(&mut self, record: proto::Record) {
|
||||
log::debug!("metrics message: {record:?}");
|
||||
|
||||
if self.records.len() < 500 {
|
||||
self.records.push_back(record);
|
||||
} else {
|
||||
log::warn!("record queue full, discarding");
|
||||
self.records.push_back(record);
|
||||
if self.records.len() >= RECORD_QUEUE_SIZE {
|
||||
self.records.pop_front();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn dump_records(&mut self) -> Vec<proto::Record> {
|
||||
let records = std::mem::take(&mut self.records);
|
||||
records.into_iter().collect()
|
||||
}
|
||||
|
||||
pub fn is_full(&self) -> bool {
|
||||
self.records.len() >= RECORD_QUEUE_SIZE - 1
|
||||
}
|
||||
|
||||
// called every frame
|
||||
pub fn update(&mut self) {
|
||||
let mut buf: [u8; 1024] = [0; 1024];
|
||||
|
|
|
|||
|
|
@ -35,4 +35,3 @@ vulkano.workspace = true
|
|||
vulkano-shaders.workspace = true
|
||||
rust-embed.workspace = true
|
||||
flate2 = "1.1.5"
|
||||
ringbuffer = "0.16.0"
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
use std::{cell::RefCell, rc::Rc};
|
||||
use std::{cell::RefCell, collections::VecDeque, rc::Rc};
|
||||
|
||||
use glam::Vec2;
|
||||
use ringbuffer::{AllocRingBuffer, RingBuffer};
|
||||
use taffy::{
|
||||
FlexDirection, JustifyContent,
|
||||
prelude::{auto, length, percent},
|
||||
|
|
@ -39,7 +38,7 @@ pub struct ValueCell {
|
|||
|
||||
struct State {
|
||||
limits: (f32, f32), /* min - max */
|
||||
values: AllocRingBuffer<ValueCell>,
|
||||
values: VecDeque<ValueCell>,
|
||||
}
|
||||
|
||||
#[allow(clippy::struct_field_names)]
|
||||
|
|
@ -51,6 +50,7 @@ struct Data {
|
|||
id_label_val_max: WidgetID,
|
||||
|
||||
unit: String,
|
||||
capacity: u32,
|
||||
}
|
||||
|
||||
pub struct ComponentBarGraph {
|
||||
|
|
@ -99,7 +99,10 @@ impl ComponentBarGraph {
|
|||
|
||||
pub fn push_value(&self, cell: ValueCell) {
|
||||
let mut state = self.state.borrow_mut();
|
||||
state.values.enqueue(cell);
|
||||
if state.values.len() > self.data.capacity as usize {
|
||||
state.values.pop_front();
|
||||
}
|
||||
state.values.push_back(cell);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -151,7 +154,7 @@ pub fn construct(
|
|||
|
||||
let state = Rc::new(RefCell::new(State {
|
||||
limits: params.limits,
|
||||
values: AllocRingBuffer::new(params.capacity.clamp(1, 1000) as usize),
|
||||
values: VecDeque::new(),
|
||||
}));
|
||||
|
||||
let (_, _) = ess.layout.add_child(
|
||||
|
|
@ -227,6 +230,7 @@ pub fn construct(
|
|||
id_label_val_min: label_val_min.id,
|
||||
id_label_val_max: label_val_max.id,
|
||||
unit: params.unit,
|
||||
capacity: params.capacity,
|
||||
});
|
||||
|
||||
let base = ComponentBase {
|
||||
|
|
|
|||
|
|
@ -16,6 +16,25 @@ pub struct MonadoClient {
|
|||
pub is_io_active: bool,
|
||||
}
|
||||
|
||||
// see `wayvr/src/subsystem/monado_metrics/proto.rs` for documentation
|
||||
#[derive(Debug)]
|
||||
pub struct MonadoDumpSessionFrame {
|
||||
pub session_id: i64,
|
||||
pub frame_id: i64,
|
||||
pub predicted_frame_time_ns: u64,
|
||||
pub predicted_wake_up_time_ns: u64,
|
||||
pub predicted_gpu_done_time_ns: u64,
|
||||
pub predicted_display_time_ns: u64,
|
||||
pub predicted_display_period_ns: u64,
|
||||
pub display_time_ns: u64,
|
||||
pub when_predicted_ns: u64,
|
||||
pub when_wait_woke_ns: u64,
|
||||
pub when_begin_ns: u64,
|
||||
pub when_delivered_ns: u64,
|
||||
pub when_gpu_done_ns: u64,
|
||||
pub discarded: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum RecenterMode {
|
||||
FixFloor,
|
||||
|
|
@ -40,6 +59,8 @@ pub trait DashInterface<T> {
|
|||
fn monado_client_focus(&mut self, data: &mut T, name: &str) -> anyhow::Result<()>;
|
||||
fn monado_brightness_get(&mut self, data: &mut T) -> Option<f32>;
|
||||
fn monado_brightness_set(&mut self, data: &mut T, brightness: f32) -> Option<()>;
|
||||
fn monado_metrics_set_enabled(&mut self, data: &mut T, enabled: bool) -> bool;
|
||||
fn monado_metrics_dump_session_frames(&mut self, data: &mut T) -> Vec<MonadoDumpSessionFrame>;
|
||||
fn recenter_playspace(&mut self, data: &mut T, mode: RecenterMode) -> anyhow::Result<()>;
|
||||
fn desktop_finder<'a>(&'a mut self, data: &'a mut T) -> &'a mut DesktopFinder;
|
||||
fn general_config<'a>(&'a mut self, data: &'a mut T) -> &'a mut GeneralConfig;
|
||||
|
|
|
|||
|
|
@ -63,6 +63,8 @@ pub struct DashInterfaceEmulated {
|
|||
general_config: GeneralConfig,
|
||||
monado_clients: Vec<dash_interface::MonadoClient>,
|
||||
brightness: f32,
|
||||
debug_frame_id: u64,
|
||||
debug_counter: u64,
|
||||
}
|
||||
|
||||
impl DashInterfaceEmulated {
|
||||
|
|
@ -121,6 +123,8 @@ impl DashInterfaceEmulated {
|
|||
general_config,
|
||||
monado_clients,
|
||||
brightness: 1.0,
|
||||
debug_counter: 0,
|
||||
debug_frame_id: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -256,4 +260,32 @@ impl DashInterface<()> for DashInterfaceEmulated {
|
|||
self.brightness = brightness;
|
||||
Some(())
|
||||
}
|
||||
|
||||
fn monado_metrics_set_enabled(&mut self, _: &mut (), _enabled: bool) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn monado_metrics_dump_session_frames(&mut self, _: &mut ()) -> Vec<dash_interface::MonadoDumpSessionFrame> {
|
||||
// simulate """""typical""""" wired hmd timing graphs
|
||||
self.debug_frame_id += 1;
|
||||
self.debug_counter ^= self.debug_frame_id * 383;
|
||||
self.debug_counter ^= 0xdeadbeefbaddcafe;
|
||||
self.debug_counter >>= 1;
|
||||
vec![dash_interface::MonadoDumpSessionFrame {
|
||||
session_id: 123,
|
||||
frame_id: self.debug_frame_id as _,
|
||||
predicted_frame_time_ns: (((self.debug_frame_id) % 15) * 1000 * 1000) as _,
|
||||
predicted_wake_up_time_ns: (((self.debug_frame_id * 2) % 16) * 1000 * 1000) as _,
|
||||
predicted_gpu_done_time_ns: (((self.debug_frame_id * 3) % 17) * 1000 * 1000) as _,
|
||||
predicted_display_time_ns: (((self.debug_frame_id * 4) % 14) * 1000 * 1000) as _,
|
||||
predicted_display_period_ns: (((self.debug_frame_id * 5) % 13) * 1000 * 1000) as _,
|
||||
display_time_ns: (((self.debug_frame_id * 7) % 12) * 1000 * 1000) as _,
|
||||
when_predicted_ns: (((self.debug_frame_id * 53) % 11) * 1000 * 1000) as _,
|
||||
when_wait_woke_ns: (((self.debug_frame_id * 23) % 10) * 1000 * 1000) as _,
|
||||
when_begin_ns: (((self.debug_frame_id * 13) % 9) * 1000 * 1000) as _,
|
||||
when_delivered_ns: (((self.debug_frame_id * 11) % 8) * 1000 * 1000) as _,
|
||||
when_gpu_done_ns: (((self.debug_frame_id * 12) % 7) * 1000 * 1000) as _,
|
||||
discarded: self.debug_frame_id.is_multiple_of(5),
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue