From 2ea8b12c153f9dcde4b0896cb216584805a5575e Mon Sep 17 00:00:00 2001 From: galister <22305755+galister@users.noreply.github.com> Date: Sun, 8 Jun 2025 08:52:49 +0900 Subject: [PATCH 001/212] Revert "separate floor offset from space drag transform (#218)" This reverts commit b0f5e23ffd84f96fbe9ec19b4b46b3a131c01eca. --- src/backend/openvr/playspace.rs | 23 +++++++++-------------- src/backend/openxr/playspace.rs | 28 +++++++++++++--------------- 2 files changed, 22 insertions(+), 29 deletions(-) diff --git a/src/backend/openvr/playspace.rs b/src/backend/openvr/playspace.rs index 36efcc2..50e16b2 100644 --- a/src/backend/openvr/playspace.rs +++ b/src/backend/openvr/playspace.rs @@ -22,7 +22,6 @@ pub(super) struct PlayspaceMover { universe: ETrackingUniverseOrigin, drag: Option>, rotate: Option>, - floor_offset: f32, } impl PlayspaceMover { @@ -31,7 +30,6 @@ impl PlayspaceMover { universe: ETrackingUniverseOrigin::TrackingUniverseRawAndUncalibrated, drag: None, rotate: None, - floor_offset: 0.0, } } @@ -84,7 +82,7 @@ impl PlayspaceMover { if self.universe == ETrackingUniverseOrigin::TrackingUniverseStanding { apply_chaperone_transform(space_transform.inverse(), chaperone_mgr); } - set_working_copy(&universe, chaperone_mgr, &data.pose, self.floor_offset); + set_working_copy(&universe, chaperone_mgr, &data.pose); chaperone_mgr.commit_working_copy(EChaperoneConfigFile::EChaperoneConfigFile_Live); } else { for (i, pointer) in state.input_state.pointers.iter().enumerate() { @@ -140,7 +138,7 @@ impl PlayspaceMover { if self.universe == ETrackingUniverseOrigin::TrackingUniverseStanding { apply_chaperone_offset(overlay_offset, chaperone_mgr); } - set_working_copy(&universe, chaperone_mgr, &data.pose, self.floor_offset); + set_working_copy(&universe, chaperone_mgr, &data.pose); chaperone_mgr.commit_working_copy(EChaperoneConfigFile::EChaperoneConfigFile_Live); } else { for (i, pointer) in state.input_state.pointers.iter().enumerate() { @@ -178,7 +176,7 @@ impl PlayspaceMover { Affine3A::IDENTITY }; - set_working_copy(&self.universe, chaperone_mgr, &xform, self.floor_offset); + set_working_copy(&self.universe, chaperone_mgr, &xform); chaperone_mgr.commit_working_copy(EChaperoneConfigFile::EChaperoneConfigFile_Live); if self.drag.is_some() { @@ -194,14 +192,14 @@ impl PlayspaceMover { pub fn fix_floor(&mut self, chaperone_mgr: &mut ChaperoneSetupManager, input: &InputState) { let y1 = input.pointers[0].pose.translation.y; let y2 = input.pointers[1].pose.translation.y; - let Some(mat) = get_working_copy(&self.universe, chaperone_mgr) else { + let Some(mut mat) = get_working_copy(&self.universe, chaperone_mgr) else { log::warn!("Can't fix floor - failed to get zero pose"); return; }; let offset = y1.min(y2) - 0.03; - self.floor_offset = offset; + mat.translation.y += offset; - set_working_copy(&self.universe, chaperone_mgr, &mat, self.floor_offset); + set_working_copy(&self.universe, chaperone_mgr, &mat); chaperone_mgr.commit_working_copy(EChaperoneConfigFile::EChaperoneConfigFile_Live); if self.drag.is_some() { @@ -270,16 +268,13 @@ fn set_working_copy( universe: &ETrackingUniverseOrigin, chaperone_mgr: &mut ChaperoneSetupManager, mat: &Affine3A, - floor_offset: f32, ) { - let mut mat = *mat; - mat.translation.y += floor_offset; - let ovr_mat = HmdMatrix34_t::from_affine(&mat); + let mat = HmdMatrix34_t::from_affine(mat); match universe { ETrackingUniverseOrigin::TrackingUniverseStanding => { - chaperone_mgr.set_working_standing_zero_pose_to_raw_tracking_pose(&ovr_mat); + chaperone_mgr.set_working_standing_zero_pose_to_raw_tracking_pose(&mat); } - _ => chaperone_mgr.set_working_seated_zero_pose_to_raw_tracking_pose(&ovr_mat), + _ => chaperone_mgr.set_working_seated_zero_pose_to_raw_tracking_pose(&mat), } } diff --git a/src/backend/openxr/playspace.rs b/src/backend/openxr/playspace.rs index e233083..487c929 100644 --- a/src/backend/openxr/playspace.rs +++ b/src/backend/openxr/playspace.rs @@ -16,7 +16,6 @@ struct MoverData { pub(super) struct PlayspaceMover { last_transform: Affine3A, - floor_offset: f32, drag: Option>, rotate: Option>, } @@ -37,7 +36,6 @@ impl PlayspaceMover { Ok(Self { last_transform, - floor_offset: 0.0, drag: None, rotate: None, @@ -91,7 +89,7 @@ impl PlayspaceMover { data.pose *= space_transform; data.hand_pose = new_hand; - self.apply_offset(data.pose, monado); + apply_offset(data.pose, monado); self.rotate = Some(data); } else { for (i, pointer) in state.input_state.pointers.iter().enumerate() { @@ -140,7 +138,7 @@ impl PlayspaceMover { data.pose.translation += relative_pos; data.hand_pose = new_hand; - self.apply_offset(data.pose, monado); + apply_offset(data.pose, monado); self.drag = Some(data); } else { for (i, pointer) in state.input_state.pointers.iter().enumerate() { @@ -171,7 +169,7 @@ impl PlayspaceMover { } self.last_transform = Affine3A::IDENTITY; - self.apply_offset(self.last_transform, monado); + apply_offset(self.last_transform, monado); } pub fn fix_floor(&mut self, input: &InputState, monado: &mut Monado) { @@ -187,15 +185,15 @@ impl PlayspaceMover { let y1 = input.pointers[0].raw_pose.translation.y; let y2 = input.pointers[1].raw_pose.translation.y; let delta = y1.min(y2) - 0.03; - self.floor_offset = delta; - self.apply_offset(self.last_transform, monado); - } - - fn apply_offset(&self, transform: Affine3A, monado: &mut Monado) { - let pose = Pose { - position: (transform.translation + Vec3A::new(0.0, self.floor_offset, 0.0)).into(), - orientation: Quat::from_affine3(&transform).into(), - }; - let _ = monado.set_reference_space_offset(ReferenceSpaceType::Stage, pose); + self.last_transform.translation.y += delta; + apply_offset(self.last_transform, monado); } } + +fn apply_offset(transform: Affine3A, monado: &mut Monado) { + let pose = Pose { + position: transform.translation.into(), + orientation: Quat::from_affine3(&transform).into(), + }; + let _ = monado.set_reference_space_offset(ReferenceSpaceType::Stage, pose); +} From 95f2ae4296a7aadbac2635e296d3f5ae62390dbc Mon Sep 17 00:00:00 2001 From: galister <22305755+galister@users.noreply.github.com> Date: Wed, 18 Jun 2025 01:06:19 +0900 Subject: [PATCH 002/212] wip: wgui backend --- Cargo.lock | 1936 ++++++++++++++++++++++--------- Cargo.toml | 22 +- src/backend/common.rs | 16 +- src/backend/mod.rs | 3 - src/backend/notifications.rs | 10 +- src/backend/openvr/lines.rs | 99 +- src/backend/openvr/mod.rs | 14 +- src/backend/openvr/overlay.rs | 21 +- src/backend/openxr/lines.rs | 53 +- src/backend/openxr/mod.rs | 26 +- src/backend/openxr/overlay.rs | 2 +- src/backend/openxr/skybox.rs | 86 +- src/backend/openxr/swapchain.rs | 11 +- src/backend/overlay.rs | 3 + src/backend/task.rs | 2 +- src/backend/uidev/mod.rs | 289 ----- src/backend/wayvr/mod.rs | 21 + src/config.rs | 10 - src/config_io.rs | 3 +- src/config_wayvr.rs | 3 +- src/graphics/dds.rs | 9 +- src/graphics/dmabuf.rs | 182 ++- src/graphics/mod.rs | 1837 ++++++++--------------------- src/gui/asset.rs | 12 + src/gui/assets/test | 0 src/gui/canvas/builder.rs | 267 ----- src/gui/canvas/control.rs | 387 ------ src/gui/canvas/mod.rs | 371 ------ src/gui/font.rs | 268 ----- src/gui/mod.rs | 64 +- src/gui/modular/button.rs | 867 -------------- src/gui/modular/label.rs | 305 ----- src/gui/modular/mod.rs | 569 --------- src/gui/panel.rs | 161 +++ src/gui/timestep.rs | 70 ++ src/main.rs | 6 - src/overlays/anchor.rs | 55 +- src/overlays/custom.rs | 37 +- src/overlays/keyboard.rs | 276 ++--- src/overlays/screen.rs | 158 +-- src/overlays/toast.rs | 126 +- src/overlays/watch.rs | 64 +- src/overlays/wayvr.rs | 65 +- src/shaders/color.frag | 24 + src/shaders/grid.frag | 19 + src/shaders/mod.rs | 244 +--- src/shaders/quad.vert | 11 + src/shaders/screen.frag | 17 + src/shaders/srgb.frag | 24 + src/state.rs | 60 +- 50 files changed, 3066 insertions(+), 6119 deletions(-) delete mode 100644 src/backend/uidev/mod.rs create mode 100644 src/gui/asset.rs create mode 100644 src/gui/assets/test delete mode 100644 src/gui/canvas/builder.rs delete mode 100644 src/gui/canvas/control.rs delete mode 100644 src/gui/canvas/mod.rs delete mode 100644 src/gui/font.rs delete mode 100644 src/gui/modular/button.rs delete mode 100644 src/gui/modular/label.rs delete mode 100644 src/gui/modular/mod.rs create mode 100644 src/gui/panel.rs create mode 100644 src/gui/timestep.rs create mode 100644 src/shaders/color.frag create mode 100644 src/shaders/grid.frag create mode 100644 src/shaders/quad.vert create mode 100644 src/shaders/screen.frag create mode 100644 src/shaders/srgb.frag diff --git a/Cargo.lock b/Cargo.lock index 1487811..75dcea5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -29,21 +29,21 @@ dependencies = [ [[package]] name = "adler2" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" [[package]] name = "ahash" -version = "0.8.11" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" dependencies = [ "cfg-if", - "getrandom 0.2.15", + "getrandom 0.3.3", "once_cell", "version_check", - "zerocopy 0.7.35", + "zerocopy", ] [[package]] @@ -55,6 +55,21 @@ dependencies = [ "memchr", ] +[[package]] +name = "aligned-vec" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc890384c8602f339876ded803c97ad529f3842aba97f6392b3dba0dd171769b" +dependencies = [ + "equator", +] + +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + [[package]] name = "alsa" version = "0.9.1" @@ -62,7 +77,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed7572b7ba83a31e20d1b48970ee402d2e3e0537dcfe0a3ff4d6eb7508617d43" dependencies = [ "alsa-sys", - "bitflags 2.9.0", + "bitflags 2.9.1", "cfg-if", "libc", ] @@ -84,7 +99,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef6978589202a00cd7e118380c448a08b6ed394c3a8df3a430d0898e3a42d046" dependencies = [ "android-properties", - "bitflags 2.9.0", + "bitflags 2.9.1", "cc", "cesu8", "jni", @@ -131,9 +146,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.18" +version = "0.6.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" +checksum = "301af1932e46185686725e0fad2f8f2aa7da69dd70bf6ecc44d6b703844a3933" dependencies = [ "anstyle", "anstyle-parse", @@ -146,44 +161,44 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.10" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" +checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd" [[package]] name = "anstyle-parse" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" +checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" +checksum = "6c8bdeb6047d8983be085bab0ba1472e6dc604e7041dbf6fcd5e71523014fae9" dependencies = [ "windows-sys 0.59.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.7" +version = "3.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e" +checksum = "403f75924867bb1033c59fbf0797484329750cfbe3c4325cd33127941fabc882" dependencies = [ "anstyle", - "once_cell", + "once_cell_polyfill", "windows-sys 0.59.0", ] [[package]] name = "anyhow" -version = "1.0.97" +version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f" +checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" [[package]] name = "appendlist" @@ -222,6 +237,23 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "arbitrary" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223" + +[[package]] +name = "arg_enum_proc_macro" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ae92a5119aa49cdbcf6b9f893fe4e1d98b04ccbf82ee0584ad948a44a734dea" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.103", +] + [[package]] name = "arraydeque" version = "0.5.1" @@ -266,7 +298,7 @@ dependencies = [ "enumflags2", "futures-channel", "futures-util", - "rand 0.9.0", + "rand 0.9.1", "serde", "serde_repr", "url", @@ -299,14 +331,15 @@ dependencies = [ [[package]] name = "async-executor" -version = "1.13.1" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30ca9a001c1e8ba5149f91a74362376cc6bc5b919d92d988668657bd570bdcec" +checksum = "bb812ffb58524bdd10860d7d974e2f01cc0950c2438a74ee5ec2e2280c6c4ffa" dependencies = [ "async-task", "concurrent-queue", "fastrand", "futures-lite", + "pin-project-lite", "slab", ] @@ -323,9 +356,9 @@ dependencies = [ [[package]] name = "async-io" -version = "2.4.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a2b323ccce0a1d90b449fd71f2a06ca7faa7c54c2751f06c9bd851fc061059" +checksum = "1237c0ae75a0f3765f58910ff9cdd0a12eeb39ab2f4c7de23262f337f0aacbb3" dependencies = [ "async-lock", "cfg-if", @@ -334,7 +367,7 @@ dependencies = [ "futures-lite", "parking", "polling", - "rustix 0.38.44", + "rustix 1.0.7", "slab", "tracing", "windows-sys 0.59.0", @@ -364,9 +397,9 @@ dependencies = [ [[package]] name = "async-process" -version = "2.3.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63255f1dc2381611000436537bbedfe83183faa303a5a0edaf191edef06526bb" +checksum = "cde3f4e40e6021d7acffc90095cbd6dc54cb593903d1de5832f435eb274b85dc" dependencies = [ "async-channel", "async-io", @@ -377,7 +410,7 @@ dependencies = [ "cfg-if", "event-listener", "futures-lite", - "rustix 0.38.44", + "rustix 1.0.7", "tracing", ] @@ -389,14 +422,14 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.103", ] [[package]] name = "async-signal" -version = "0.2.10" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "637e00349800c0bdf8bfc21ebbc0b6524abea702b0da4168ac00d070d0c0b9f3" +checksum = "d7605a4e50d4b06df3898d5a70bf5fde51ed9059b0434b73105193bc27acce0d" dependencies = [ "async-io", "async-lock", @@ -404,7 +437,7 @@ dependencies = [ "cfg-if", "futures-core", "futures-io", - "rustix 0.38.44", + "rustix 1.0.7", "signal-hook-registry", "slab", "windows-sys 0.59.0", @@ -424,7 +457,7 @@ checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.103", ] [[package]] @@ -468,7 +501,7 @@ version = "0.71.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7d41cf081e31a74378456586b47a5bae2b75a98e5f7c248c9d9bf433e3637f4" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "cexpr", "clang-sys", "itertools 0.13.0", @@ -478,7 +511,7 @@ dependencies = [ "regex", "rustc-hash 2.1.1", "shlex", - "syn 2.0.100", + "syn 2.0.103", ] [[package]] @@ -490,7 +523,7 @@ dependencies = [ "autocxx-engine", "env_logger", "indexmap 1.9.3", - "syn 2.0.100", + "syn 2.0.103", ] [[package]] @@ -516,7 +549,7 @@ dependencies = [ "regex", "rustversion", "serde_json", - "syn 2.0.100", + "syn 2.0.103", "tempfile", "thiserror 1.0.69", "version_check", @@ -532,7 +565,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.103", ] [[package]] @@ -549,15 +582,38 @@ dependencies = [ "quote", "serde", "serde_json", - "syn 2.0.100", + "syn 2.0.103", "thiserror 1.0.69", ] [[package]] -name = "backtrace" -version = "0.3.74" +name = "av1-grain" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" +checksum = "4f3efb2ca85bc610acfa917b5aaa36f3fcbebed5b3182d7f877b02531c4b80c8" +dependencies = [ + "anyhow", + "arrayvec", + "log", + "nom", + "num-rational", + "v_frame", +] + +[[package]] +name = "avif-serialize" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98922d6a4cfbcb08820c69d8eeccc05bb1f29bfa06b4f5b1dbfe9a868bd7608e" +dependencies = [ + "arrayvec", +] + +[[package]] +name = "backtrace" +version = "0.3.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" dependencies = [ "addr2line", "cfg-if", @@ -574,6 +630,12 @@ version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + [[package]] name = "bcdec_rs" version = "0.2.0" @@ -587,7 +649,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088" dependencies = [ "annotate-snippets", - "bitflags 2.9.0", + "bitflags 2.9.1", "cexpr", "clang-sys", "itertools 0.12.1", @@ -600,26 +662,26 @@ dependencies = [ "regex", "rustc-hash 1.1.0", "shlex", - "syn 2.0.100", + "syn 2.0.103", "which", ] [[package]] name = "bindgen" -version = "0.70.1" +version = "0.72.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f49d8fed880d473ea71efb9bf597651e77201bdd4893efe54c9e5d65ae04ce6f" +checksum = "4f72209734318d0b619a5e0f5129918b848c416e122a3c4ce054e03cb87b726f" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "cexpr", "clang-sys", "itertools 0.13.0", "proc-macro2", "quote", "regex", - "rustc-hash 1.1.0", + "rustc-hash 2.1.1", "shlex", - "syn 2.0.100", + "syn 2.0.103", ] [[package]] @@ -630,13 +692,19 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.9.0" +version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" +checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" dependencies = [ "serde", ] +[[package]] +name = "bitstream-io" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6099cdc01846bc367c4e7dd630dc5966dccf36b652fae7a74e17b640411a91b2" + [[package]] name = "block-buffer" version = "0.10.4" @@ -669,16 +737,22 @@ dependencies = [ ] [[package]] -name = "bumpalo" -version = "3.17.0" +name = "built" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" +checksum = "56ed6191a7e78c36abdb16ab65341eefd73d64d303fffccdbb00d51e4205967b" + +[[package]] +name = "bumpalo" +version = "3.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db76d6187cd04dff33004d8e6c9cc4e05cd330500379d2394209271b4aeee" [[package]] name = "bytemuck" -version = "1.22.0" +version = "1.23.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6b1fc10dbac614ebc03540c9dbd60e83887fda27794998c6528f1782047d540" +checksum = "5c76a5792e44e4abe34d3abf15636779261d45a7450612059293d1d2cfc63422" dependencies = [ "bytemuck_derive", ] @@ -691,7 +765,7 @@ checksum = "7ecc273b49b3205b83d648f0690daa588925572cc5063745bfe547fe7ec8e1a1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.103", ] [[package]] @@ -700,6 +774,12 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" +[[package]] +name = "byteorder-lite" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" + [[package]] name = "bytes" version = "1.10.1" @@ -712,7 +792,7 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b99da2f8558ca23c71f4fd15dc57c906239752dd27ff3c00a1d56b685b7cbfec" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "log", "polling", "rustix 0.38.44", @@ -726,7 +806,7 @@ version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "10929724661d1c43856fd87c7a127ae944ec55579134fb485e4136fb6a46fdcb" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "polling", "rustix 0.38.44", "slab", @@ -747,9 +827,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.18" +version = "1.2.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "525046617d8376e3db1deffb079e91cef90a89fc3ca5c185bbf8c9ecdd15cd5c" +checksum = "d487aa071b5f64da6f19a3e848e3578944b726ee5a4854b82172f02aa876bfdc" dependencies = [ "jobserver", "libc", @@ -783,9 +863,9 @@ dependencies = [ [[package]] name = "cfg-if" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" [[package]] name = "cfg_aliases" @@ -805,9 +885,9 @@ dependencies = [ [[package]] name = "chrono" -version = "0.4.40" +version = "0.4.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a7964611d71df112cb1730f2ee67324fcf4d0fc6606acbbe9bfe06df124637c" +checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d" dependencies = [ "android-tzdata", "iana-time-zone", @@ -851,9 +931,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.35" +version = "4.5.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8aa86934b44c19c50f87cc2790e19f54f7a67aedb64101c2e1a2e5ecfb73944" +checksum = "40b6887a1d8685cebccf115538db5c0efe625ccac9696ad45c409d96566e910f" dependencies = [ "clap_builder", "clap_derive", @@ -861,9 +941,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.35" +version = "4.5.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2414dbb2dd0695280da6ea9261e327479e9d37b0630f6b53ba2a11c60c679fd9" +checksum = "e0c66c08ce9f0c698cbce5c0279d0bb6ac936d8674174fe48f736533b964f59e" dependencies = [ "anstream", "anstyle", @@ -873,21 +953,21 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.32" +version = "4.5.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09176aae279615badda0765c0c0b3f6ed53f4709118af73cf4655d85d1530cd7" +checksum = "d2c7947ae4cc3d851207c1adb5b5e260ff0cca11446b1d6d1423788e442257ce" dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.103", ] [[package]] name = "clap_lex" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" +checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" [[package]] name = "cmake" @@ -906,14 +986,20 @@ checksum = "fe6d2e5af09e8c8ad56c969f2157a3d4238cebc7c55f0a517728c38f7b200f81" dependencies = [ "serde", "termcolor", - "unicode-width 0.2.0", + "unicode-width 0.2.1", ] [[package]] -name = "colorchoice" -version = "1.0.3" +name = "color_quant" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" +checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" + +[[package]] +name = "colorchoice" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" [[package]] name = "combine" @@ -974,7 +1060,7 @@ version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.16", "once_cell", "tiny-keccak", ] @@ -1056,11 +1142,34 @@ dependencies = [ [[package]] name = "coreaudio-sys" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ce857aa0b77d77287acc1ac3e37a05a8c95a2af3647d23b15f263bdaeb7562b" +checksum = "ceec7a6067e62d6f931a2baf6f3a751f4a892595bcec1461a3c94ef9949864b6" dependencies = [ - "bindgen 0.70.1", + "bindgen 0.72.0", +] + +[[package]] +name = "cosmic-text" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da46a9d5a8905cc538a4a5bceb6a4510de7a51049c5588c0114efce102bcbbe8" +dependencies = [ + "bitflags 2.9.1", + "fontdb", + "log", + "rangemap", + "rustc-hash 1.1.0", + "rustybuzz", + "self_cell", + "smol_str", + "swash", + "sys-locale", + "ttf-parser 0.21.1", + "unicode-bidi", + "unicode-linebreak", + "unicode-script", + "unicode-segmentation", ] [[package]] @@ -1095,6 +1204,34 @@ dependencies = [ "libc", ] +[[package]] +name = "crc32fast" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "crossbeam-queue" version = "0.3.12" @@ -1128,25 +1265,25 @@ dependencies = [ [[package]] name = "ctrlc" -version = "3.4.6" +version = "3.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "697b5419f348fd5ae2478e8018cb016c00a5881c7f46c717de98ffd135a5651c" +checksum = "46f93780a459b7d656ef7f071fe699c4d3d2cb201c4b24d085b6ddc505276e73" dependencies = [ - "nix 0.29.0", + "nix 0.30.1", "windows-sys 0.59.0", ] [[package]] name = "cursor-icon" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96a6ac251f4a2aca6b3f91340350eab87ae57c3f127ffeb585e92bd336717991" +checksum = "f27ae1dd37df86211c42e150270f82743308803d90a6f6e6651cd730d5e1732f" [[package]] name = "cxx" -version = "1.0.156" +version = "1.0.158" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa3a202fc4f3dd6d2ce5a2f87b04fb2becc00f5643ee9c4743ba10777efb314f" +checksum = "a71ea7f29c73f7ffa64c50b83c9fe4d3a6d4be89a86b009eb80d5a6d3429d741" dependencies = [ "cc", "cxxbridge-cmd", @@ -1158,45 +1295,45 @@ dependencies = [ [[package]] name = "cxx-gen" -version = "0.7.156" +version = "0.7.158" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61b9e50968a66aa69ce1ac23bb1b30e1b728adfe3217b0e9267b018a71297a0d" +checksum = "68318fef0ae96135291398a97ef84763d1be248bef10a9140e1a728b44e24627" dependencies = [ "codespan-reporting", "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.103", ] [[package]] name = "cxxbridge-cmd" -version = "1.0.156" +version = "1.0.158" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e8cefbebcb74ed0b4a08b76139e6c29d8884a0bb94d02c6f35de821a14a6e39" +checksum = "4f44296c8693e9ea226a48f6a122727f77aa9e9e338380cb021accaeeb7ee279" dependencies = [ "clap", "codespan-reporting", "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.103", ] [[package]] name = "cxxbridge-flags" -version = "1.0.156" +version = "1.0.158" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "604e3eff62e2f27289d618f621491a068330c3c9f8eb06555dabc292c123596e" +checksum = "c42f69c181c176981ae44ba9876e2ea41ce8e574c296b38d06925ce9214fb8e4" [[package]] name = "cxxbridge-macro" -version = "1.0.156" +version = "1.0.158" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "130c3a05501d9c15dedbf08f2ff9af60f8e78422e3dffac1f43e2d83c5b489a1" +checksum = "8faff5d4467e0709448187df29ccbf3b0982cc426ee444a193f87b11afb565a8" dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.100", + "syn 2.0.103", ] [[package]] @@ -1219,7 +1356,7 @@ dependencies = [ "ident_case", "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.103", ] [[package]] @@ -1230,7 +1367,7 @@ checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" dependencies = [ "darling_core", "quote", - "syn 2.0.100", + "syn 2.0.103", ] [[package]] @@ -1239,6 +1376,12 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c87e182de0887fd5361989c677c4e8f5000cd9491d6d563161a8f3a5519fc7f" +[[package]] +name = "data-url" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c297a1c74b71ae29df00c3e22dd9534821d60eb9af5a0192823fa2acea70c2a" + [[package]] name = "dbus" version = "0.9.7" @@ -1256,7 +1399,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "479dfe1e6737aa9e96c6ac7b69689dc4c32da8383f2c12744739d76afa8b66c4" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "byteorder", "enum-primitive-derive", "num-traits", @@ -1273,15 +1416,15 @@ dependencies = [ [[package]] name = "derive_more" -version = "0.99.19" +version = "0.99.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3da29a38df43d6f156149c9b43ded5e018ddff2a855cf2cfd62e8cd7d079c69f" +checksum = "6edb4b64a43d977b8e99788fe3a04d483834fba1215a7e02caa415b626497f7f" dependencies = [ "convert_case 0.4.0", "proc-macro2", "quote", "rustc_version", - "syn 2.0.100", + "syn 2.0.103", ] [[package]] @@ -1300,6 +1443,16 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" +[[package]] +name = "dispatch2" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec" +dependencies = [ + "bitflags 2.9.1", + "objc2 0.6.1", +] + [[package]] name = "displaydoc" version = "0.2.5" @@ -1308,7 +1461,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.103", ] [[package]] @@ -1334,13 +1487,13 @@ dependencies = [ [[package]] name = "dlopen2_derive" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2b99bf03862d7f545ebc28ddd33a665b50865f4dfd84031a393823879bd4c54" +checksum = "788160fb30de9cdd857af31c6a2675904b16ece8fc2737b2c7127ba368c9d0f4" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.103", ] [[package]] @@ -1366,9 +1519,9 @@ checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" [[package]] name = "dpi" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f25c0e292a7ca6d6498557ff1df68f32c99850012b6ea401cf8daf771f22ff53" +checksum = "d8b14ccef22fc6f5a8f4d7d768562a182c04ce9a3b3157b91390b52ddfdf1a76" [[package]] name = "drm" @@ -1376,7 +1529,7 @@ version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "80bc8c5c6c2941f70a55c15f8d9f00f9710ebda3ffda98075f996a0e6c92756f" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "bytemuck", "drm-ffi", "drm-fourcc", @@ -1444,9 +1597,9 @@ dependencies = [ [[package]] name = "enumflags2" -version = "0.7.11" +version = "0.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba2f4b465f5318854c6f8dd686ede6c0a9dc67d4b1ac241cf0eb51521a309147" +checksum = "1027f7680c853e056ebcec683615fb6fbbc07dbaa13b4d5d9442b146ded4ecef" dependencies = [ "enumflags2_derive", "serde", @@ -1454,34 +1607,34 @@ dependencies = [ [[package]] name = "enumflags2_derive" -version = "0.7.11" +version = "0.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc4caf64a58d7a6d65ab00639b046ff54399a39f5f2554728895ace4b297cd79" +checksum = "67c78a4d8fdf9953a5c9d458f9efe940fd97a0cab0941c075a813ac594733827" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.103", ] [[package]] name = "enumset" -version = "1.1.5" +version = "1.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d07a4b049558765cef5f0c1a273c3fc57084d768b44d2f98127aef4cceb17293" +checksum = "11a6b7c3d347de0a9f7bfd2f853be43fe32fa6fac30c70f6d6d67a1e936b87ee" dependencies = [ "enumset_derive", ] [[package]] name = "enumset_derive" -version = "0.10.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59c3b24c345d8c314966bdc1832f6c2635bfcce8e7cf363bd115987bba2ee242" +checksum = "6da3ea9e1d1a3b1593e15781f930120e72aa7501610b2f82e5b6739c72e8eac5" dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.103", ] [[package]] @@ -1497,6 +1650,26 @@ dependencies = [ "termcolor", ] +[[package]] +name = "equator" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4711b213838dfee0117e3be6ac926007d7f433d7bbe33595975d4190cb07e6fc" +dependencies = [ + "equator-macro", +] + +[[package]] +name = "equator-macro" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44f23cf4b44bfce11a86ace86f8a73ffdec849c9fd00a386a53d278bd9e81fb3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.103", +] + [[package]] name = "equivalent" version = "1.0.2" @@ -1505,14 +1678,33 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "errno" -version = "0.3.11" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e" +checksum = "cea14ef9355e3beab063703aa9dab15afd25f0667c341310c1e5274bb1d0da18" dependencies = [ "libc", "windows-sys 0.59.0", ] +[[package]] +name = "etagere" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc89bf99e5dc15954a60f707c1e09d7540e5cd9af85fa75caa0b510bc08c5342" +dependencies = [ + "euclid", + "svg_fmt", +] + +[[package]] +name = "euclid" +version = "0.22.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad9cdb4b747e485a12abb0e6566612956c7a1bafa3bdb8d682c5b6d403589e48" +dependencies = [ + "num-traits", +] + [[package]] name = "event-listener" version = "5.4.0" @@ -1540,6 +1732,15 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +[[package]] +name = "fdeflate" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c" +dependencies = [ + "simd-adler32", +] + [[package]] name = "fixedbitset" version = "0.4.2" @@ -1552,6 +1753,22 @@ version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7ac824320a75a52197e8f2d787f6a38b6718bb6897a35142d749af3c0e8f4fe" +[[package]] +name = "flate2" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "float-cmp" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4" + [[package]] name = "fnv" version = "1.0.7" @@ -1564,6 +1781,24 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" +[[package]] +name = "font-types" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02a596f5713680923a2080d86de50fe472fb290693cf0f701187a1c8b36996b7" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "fontconfig-parser" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbc773e24e02d4ddd8395fd30dc147524273a83e54e0f312d986ea30de5f5646" +dependencies = [ + "roxmltree 0.20.0", +] + [[package]] name = "fontconfig-rs" version = "0.1.1" @@ -1576,6 +1811,20 @@ dependencies = [ "yeslogic-fontconfig-sys", ] +[[package]] +name = "fontdb" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0299020c3ef3f60f526a4f64ab4a3d4ce116b1acbf24cdd22da0068e5d81dc3" +dependencies = [ + "fontconfig-parser", + "log", + "memmap2 0.9.5", + "slotmap", + "tinyvec", + "ttf-parser 0.20.0", +] + [[package]] name = "foreign-types" version = "0.5.0" @@ -1594,7 +1843,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.103", ] [[package]] @@ -1618,7 +1867,7 @@ version = "0.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5442dee36ca09604133580dc0553780e867936bb3cbef3275859e889026d2b17" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "freetype-sys", "libc", ] @@ -1703,7 +1952,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.103", ] [[package]] @@ -1758,20 +2007,20 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" dependencies = [ "cfg-if", "libc", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi 0.11.1+wasi-snapshot-preview1", ] [[package]] name = "getrandom" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" dependencies = [ "cfg-if", "libc", @@ -1779,6 +2028,16 @@ dependencies = [ "wasi 0.14.2+wasi-0.2.4", ] +[[package]] +name = "gif" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fb2d69b19215e18bb912fa30f7ce15846e301408695e44e0ef719f1da9e19f2" +dependencies = [ + "color_quant", + "weezl", +] + [[package]] name = "gimli" version = "0.31.1" @@ -1798,9 +2057,9 @@ dependencies = [ [[package]] name = "glam" -version = "0.30.1" +version = "0.30.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf3aa70d918d2b234126ff4f850f628f172542bf0603ded26b8ee36e5e22d5f9" +checksum = "50a99dbe56b72736564cfa4b85bf9a33079f16ae8b74983ab06af3b1a3696b11" dependencies = [ "approx 0.5.1", "mint", @@ -1813,6 +2072,12 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" +[[package]] +name = "grid" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71b01d27060ad58be4663b9e4ac9e2d4806918e8876af8912afbddd1a91d5eaa" + [[package]] name = "half" version = "2.6.0" @@ -1838,10 +2103,12 @@ checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" [[package]] name = "hashbrown" -version = "0.15.2" +version = "0.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" dependencies = [ + "allocator-api2", + "equivalent", "foldhash", ] @@ -1851,7 +2118,7 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1" dependencies = [ - "hashbrown 0.15.2", + "hashbrown 0.15.4", ] [[package]] @@ -1877,9 +2144,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.4.0" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" [[package]] name = "hex" @@ -1920,7 +2187,7 @@ dependencies = [ "js-sys", "log", "wasm-bindgen", - "windows-core 0.61.0", + "windows-core 0.61.2", ] [[package]] @@ -1934,21 +2201,22 @@ dependencies = [ [[package]] name = "icu_collections" -version = "1.5.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" dependencies = [ "displaydoc", + "potential_utf", "yoke", "zerofrom", "zerovec", ] [[package]] -name = "icu_locid" -version = "1.5.0" +name = "icu_locale_core" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" dependencies = [ "displaydoc", "litemap", @@ -1957,31 +2225,11 @@ dependencies = [ "zerovec", ] -[[package]] -name = "icu_locid_transform" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" -dependencies = [ - "displaydoc", - "icu_locid", - "icu_locid_transform_data", - "icu_provider", - "tinystr", - "zerovec", -] - -[[package]] -name = "icu_locid_transform_data" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7515e6d781098bf9f7205ab3fc7e9709d34554ae0b21ddbcb5febfa4bc7df11d" - [[package]] name = "icu_normalizer" -version = "1.5.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" dependencies = [ "displaydoc", "icu_collections", @@ -1989,67 +2237,54 @@ dependencies = [ "icu_properties", "icu_provider", "smallvec", - "utf16_iter", - "utf8_iter", - "write16", "zerovec", ] [[package]] name = "icu_normalizer_data" -version = "1.5.1" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5e8338228bdc8ab83303f16b797e177953730f601a96c25d10cb3ab0daa0cb7" +checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" [[package]] name = "icu_properties" -version = "1.5.1" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" dependencies = [ "displaydoc", "icu_collections", - "icu_locid_transform", + "icu_locale_core", "icu_properties_data", "icu_provider", - "tinystr", + "potential_utf", + "zerotrie", "zerovec", ] [[package]] name = "icu_properties_data" -version = "1.5.1" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85fb8799753b75aee8d2a21d7c14d9f38921b54b3dbda10f5a3c7a7b82dba5e2" +checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" [[package]] name = "icu_provider" -version = "1.5.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" dependencies = [ "displaydoc", - "icu_locid", - "icu_provider_macros", + "icu_locale_core", "stable_deref_trait", "tinystr", "writeable", "yoke", "zerofrom", + "zerotrie", "zerovec", ] -[[package]] -name = "icu_provider_macros" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", -] - [[package]] name = "ident_case" version = "1.0.1" @@ -2090,14 +2325,43 @@ dependencies = [ [[package]] name = "idna_adapter" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" dependencies = [ "icu_normalizer", "icu_properties", ] +[[package]] +name = "image" +version = "0.25.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db35664ce6b9810857a38a906215e75a9c879f0696556a39f59c62829710251a" +dependencies = [ + "bytemuck", + "byteorder-lite", + "color_quant", + "gif", + "image-webp", + "num-traits", + "png", + "ravif", + "rayon", + "zune-core", + "zune-jpeg", +] + +[[package]] +name = "image-webp" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14d75c7014ddab93c232bc6bb9f64790d3dfd1d605199acd4b40b6d69e691e9f" +dependencies = [ + "byteorder-lite", + "quick-error", +] + [[package]] name = "image_dds" version = "0.7.2" @@ -2111,6 +2375,18 @@ dependencies = [ "thiserror 1.0.69", ] +[[package]] +name = "imagesize" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edcd27d72f2f071c64249075f42e205ff93c9a4c5f6c6da53e79ed9f9832c285" + +[[package]] +name = "imgref" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0263a3d970d5c054ed9312c0057b4f3bde9c0b33836d3637361d4a9e6e7a408" + [[package]] name = "indexmap" version = "1.9.3" @@ -2129,7 +2405,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" dependencies = [ "equivalent", - "hashbrown 0.15.2", + "hashbrown 0.15.4", ] [[package]] @@ -2158,6 +2434,17 @@ dependencies = [ "nix 0.29.0", ] +[[package]] +name = "interpolate_name" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c34819042dc3d3971c46c2190835914dfbe0c3c13f61449b2997f4e9722dfa60" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.103", +] + [[package]] name = "interprocess" version = "2.2.3" @@ -2247,7 +2534,7 @@ version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a" dependencies = [ - "getrandom 0.3.2", + "getrandom 0.3.3", "libc", ] @@ -2294,6 +2581,16 @@ version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc" +[[package]] +name = "kurbo" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1077d333efea6170d9ccb96d3c3026f300ca0773da4938cc4c811daa6df68b0c" +dependencies = [ + "arrayvec", + "smallvec", +] + [[package]] name = "lazy_static" version = "1.5.0" @@ -2308,9 +2605,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.171" +version = "0.2.173" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6" +checksum = "d8cfeafaffdbc32176b64fb251369d52ea9f0a8fbc6f8759edffef7b525d64bb" [[package]] name = "libdbus-sys" @@ -2322,15 +2619,31 @@ dependencies = [ ] [[package]] -name = "libloading" -version = "0.8.6" +name = "libfuzzer-sys" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" +checksum = "cf78f52d400cf2d84a3a973a78a592b4adc535739e0a5597a0da6f0c357adc75" +dependencies = [ + "arbitrary", + "cc", +] + +[[package]] +name = "libloading" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" dependencies = [ "cfg-if", - "windows-targets 0.52.6", + "windows-targets 0.53.2", ] +[[package]] +name = "libm" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" + [[package]] name = "libmonado" version = "1.3.2" @@ -2347,7 +2660,7 @@ dependencies = [ "semver", "serde", "serde_json", - "xdg", + "xdg 2.5.2", ] [[package]] @@ -2356,9 +2669,9 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "libc", - "redox_syscall 0.5.11", + "redox_syscall 0.5.13", ] [[package]] @@ -2366,7 +2679,7 @@ name = "libspa" version = "0.8.0" source = "git+https://gitlab.freedesktop.org/galister/pipewire-rs.git#ba32202c3c391004c3bb533b58fa75a50e47ff57" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "cc", "convert_case 0.6.0", "cookie-factory", @@ -2416,15 +2729,15 @@ checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" [[package]] name = "litemap" -version = "0.7.5" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856" +checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" [[package]] name = "lock_api" -version = "0.4.12" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" dependencies = [ "autocfg", "scopeguard", @@ -2446,6 +2759,24 @@ dependencies = [ "log", ] +[[package]] +name = "loop9" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fae87c125b03c1d2c0150c90365d7d6bcc53fb73a9acaef207d2d065860f062" +dependencies = [ + "imgref", +] + +[[package]] +name = "lru" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f8cc7106155f10bdf99a6f379688f543ad6596a415375b36a59a054ceda1198" +dependencies = [ + "hashbrown 0.15.4", +] + [[package]] name = "mach2" version = "0.4.2" @@ -2465,10 +2796,20 @@ dependencies = [ ] [[package]] -name = "memchr" -version = "2.7.4" +name = "maybe-rayon" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +checksum = "8ea1f30cedd69f0a2954655f7188c6a834246d2bcf1e315e2ac40c4b24dc9519" +dependencies = [ + "cfg-if", + "rayon", +] + +[[package]] +name = "memchr" +version = "2.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" [[package]] name = "memmap2" @@ -2517,7 +2858,7 @@ checksum = "49e7bc1560b95a3c4a25d03de42fe76ca718ab92d1a22a55b9b4cf67b3ae635c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.103", ] [[package]] @@ -2528,11 +2869,12 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.8.8" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" dependencies = [ "adler2", + "simd-adler32", ] [[package]] @@ -2556,7 +2898,7 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2076a31b7010b17a38c01907c45b945e8f11495ee4dd588309718901b1f7a5b7" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "jni-sys", "log", "ndk-sys 0.5.0+25.2.9519653", @@ -2570,7 +2912,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "jni-sys", "log", "ndk-sys 0.6.0+11769913", @@ -2603,13 +2945,19 @@ dependencies = [ "jni-sys", ] +[[package]] +name = "new_debug_unreachable" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" + [[package]] name = "nix" version = "0.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "cfg-if", "libc", ] @@ -2620,7 +2968,19 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", + "cfg-if", + "cfg_aliases", + "libc", +] + +[[package]] +name = "nix" +version = "0.30.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6" +dependencies = [ + "bitflags 2.9.1", "cfg-if", "cfg_aliases", "libc", @@ -2637,6 +2997,12 @@ dependencies = [ "minimal-lexical", ] +[[package]] +name = "noop_proc_macro" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0676bb32a98c1a483ce53e500a81ad9c3d5b3f7c920c28c24e9cb0980d0b5bc8" + [[package]] name = "normpath" version = "1.3.0" @@ -2665,6 +3031,16 @@ dependencies = [ "winapi", ] +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + [[package]] name = "num-conv" version = "0.1.0" @@ -2679,7 +3055,27 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.103", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", ] [[package]] @@ -2709,7 +3105,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.103", ] [[package]] @@ -2730,9 +3126,9 @@ dependencies = [ [[package]] name = "objc2" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3531f65190d9cff863b77a99857e74c314dd16bf56c538c4b57c7cbc3f3a6e59" +checksum = "88c6597e14493ab2e44ce58f2fdecf095a51f12ca57bec060a11c57332520551" dependencies = [ "objc2-encode", ] @@ -2743,7 +3139,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e4e89ad9e3d7d297152b17d39ed92cd50ca8063a89a9fa569046d41568891eff" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "block2", "libc", "objc2 0.5.2", @@ -2759,7 +3155,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74dd3b56391c7a0596a295029734d3c1c5e7e510a4cb30245f8221ccea96b009" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "block2", "objc2 0.5.2", "objc2-core-location", @@ -2783,7 +3179,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "617fbf49e071c178c0b24c080767db52958f716d9eabdf0890523aeae54773ef" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "block2", "objc2 0.5.2", "objc2-foundation 0.2.2", @@ -2791,12 +3187,13 @@ dependencies = [ [[package]] name = "objc2-core-foundation" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daeaf60f25471d26948a1c2f840e3f7d86f4109e3af4e8e4b5cd70c39690d925" +checksum = "1c10c2894a6fed806ade6027bcd50662746363a9589d3ec9d9bef30a4e4bc166" dependencies = [ - "bitflags 2.9.0", - "objc2 0.6.0", + "bitflags 2.9.1", + "dispatch2", + "objc2 0.6.1", ] [[package]] @@ -2835,7 +3232,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "block2", "dispatch", "libc", @@ -2844,12 +3241,22 @@ dependencies = [ [[package]] name = "objc2-foundation" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a21c6c9014b82c39515db5b396f91645182611c97d24637cf56ac01e5f8d998" +checksum = "900831247d2fe1a09a683278e5384cfb8c80c79fe6b166f9d14bfdde0ea1b03c" dependencies = [ - "bitflags 2.9.0", - "objc2 0.6.0", + "bitflags 2.9.1", + "objc2 0.6.1", + "objc2-core-foundation", +] + +[[package]] +name = "objc2-io-kit" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71c1c64d6120e51cd86033f67176b1cb66780c2efe34dec55176f77befd93c0a" +dependencies = [ + "libc", "objc2-core-foundation", ] @@ -2871,7 +3278,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "block2", "objc2 0.5.2", "objc2-foundation 0.2.2", @@ -2879,13 +3286,13 @@ dependencies = [ [[package]] name = "objc2-metal" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01c41bc8b0e50ea7a5304a56f25e0066f526e99641b46fd7b9ad4421dd35bff6" +checksum = "7f246c183239540aab1782457b35ab2040d4259175bd1d0c58e46ada7b47a874" dependencies = [ - "bitflags 2.9.0", - "objc2 0.6.0", - "objc2-foundation 0.3.0", + "bitflags 2.9.1", + "objc2 0.6.1", + "objc2-foundation 0.3.1", ] [[package]] @@ -2894,7 +3301,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "block2", "objc2 0.5.2", "objc2-foundation 0.2.2", @@ -2903,15 +3310,15 @@ dependencies = [ [[package]] name = "objc2-quartz-core" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fb3794501bb1bee12f08dcad8c61f2a5875791ad1c6f47faa71a0f033f20071" +checksum = "90ffb6a0cd5f182dc964334388560b12a57f7b74b3e2dec5e2722aa2dfb2ccd5" dependencies = [ - "bitflags 2.9.0", - "objc2 0.6.0", + "bitflags 2.9.1", + "objc2 0.6.1", "objc2-core-foundation", - "objc2-foundation 0.3.0", - "objc2-metal 0.3.0", + "objc2-foundation 0.3.1", + "objc2-metal 0.3.1", ] [[package]] @@ -2930,7 +3337,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8bb46798b20cd6b91cbd113524c490f1686f4c4e8f49502431415f3512e2b6f" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "block2", "objc2 0.5.2", "objc2-cloud-kit", @@ -2962,7 +3369,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76cfcbf642358e8689af64cee815d139339f3ed8ad05103ed5eaf73db8d84cb3" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "block2", "objc2 0.5.2", "objc2-core-location", @@ -3007,6 +3414,12 @@ version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +[[package]] +name = "once_cell_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" + [[package]] name = "openxr" version = "0.19.0" @@ -3095,7 +3508,7 @@ version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22ec719bbf3b2a81c109a4e20b1f129b5566b7dce654bc3872f6a05abf82b2c4" dependencies = [ - "ttf-parser", + "ttf-parser 0.25.1", ] [[package]] @@ -3106,9 +3519,9 @@ checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" [[package]] name = "parking_lot" -version = "0.12.3" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" dependencies = [ "lock_api", "parking_lot_core", @@ -3116,13 +3529,13 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.10" +version = "0.9.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.5.11", + "redox_syscall 0.5.13", "smallvec", "windows-targets 0.52.6", ] @@ -3136,6 +3549,12 @@ dependencies = [ "regex", ] +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + [[package]] name = "pathdiff" version = "0.2.3" @@ -3150,9 +3569,9 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pest" -version = "2.8.0" +version = "2.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "198db74531d58c70a361c42201efde7e2591e976d518caf7662a47dc5720e7b6" +checksum = "1db05f56d34358a8b1066f67cbb203ee3e7ed2ba674a6263a1d5ec6db2204323" dependencies = [ "memchr", "thiserror 2.0.12", @@ -3161,9 +3580,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.8.0" +version = "2.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d725d9cfd79e87dccc9341a2ef39d1b6f6353d68c4b33c177febbe1a402c97c5" +checksum = "bb056d9e8ea77922845ec74a1c4e8fb17e7c218cc4fc11a15c5d25e189aa40bc" dependencies = [ "pest", "pest_generator", @@ -3171,24 +3590,23 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.8.0" +version = "2.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db7d01726be8ab66ab32f9df467ae8b1148906685bbe75c82d1e65d7f5b3f841" +checksum = "87e404e638f781eb3202dc82db6760c8ae8a1eeef7fb3fa8264b2ef280504966" dependencies = [ "pest", "pest_meta", "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.103", ] [[package]] name = "pest_meta" -version = "2.8.0" +version = "2.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f9f832470494906d1fca5329f8ab5791cc60beb230c74815dff541cbd2b5ca0" +checksum = "edd1101f170f5903fde0914f899bb503d9ff5271d7ba76bbb70bea63690cc0d5" dependencies = [ - "once_cell", "pest", "sha2", ] @@ -3231,6 +3649,12 @@ dependencies = [ "siphasher", ] +[[package]] +name = "pico-args" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315" + [[package]] name = "pin-project" version = "1.1.10" @@ -3248,7 +3672,7 @@ checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.103", ] [[package]] @@ -3280,7 +3704,7 @@ version = "0.8.0" source = "git+https://gitlab.freedesktop.org/galister/pipewire-rs.git#ba32202c3c391004c3bb533b58fa75a50e47ff57" dependencies = [ "anyhow", - "bitflags 2.9.0", + "bitflags 2.9.1", "libc", "libspa", "libspa-sys", @@ -3307,20 +3731,42 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" [[package]] -name = "polling" -version = "3.7.4" +name = "png" +version = "0.17.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a604568c3202727d1507653cb121dbd627a58684eb09a820fd746bee38b4442f" +checksum = "82151a2fc869e011c153adc57cf2789ccb8d9906ce52c0b39a6b5697749d7526" +dependencies = [ + "bitflags 1.3.2", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide", +] + +[[package]] +name = "polling" +version = "3.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b53a684391ad002dd6a596ceb6c74fd004fdce75f4be2e3f615068abbea5fd50" dependencies = [ "cfg-if", "concurrent-queue", - "hermit-abi 0.4.0", + "hermit-abi 0.5.2", "pin-project-lite", - "rustix 0.38.44", + "rustix 1.0.7", "tracing", "windows-sys 0.59.0", ] +[[package]] +name = "potential_utf" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585" +dependencies = [ + "zerovec", +] + [[package]] name = "powerfmt" version = "0.2.0" @@ -3333,17 +3779,17 @@ version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" dependencies = [ - "zerocopy 0.8.24", + "zerocopy", ] [[package]] name = "prettyplease" -version = "0.2.32" +version = "0.2.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "664ec5419c51e34154eec046ebcba56312d5a2fc3b09a06da188e1ad21afadf6" +checksum = "6837b9e10d61f45f987d50808f83d1ee3d206c66acf650c3e4ae2e1f6ddedf55" dependencies = [ "proc-macro2", - "syn 2.0.100", + "syn 2.0.103", ] [[package]] @@ -3381,9 +3827,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.94" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" dependencies = [ "unicode-ident", ] @@ -3404,9 +3850,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a65f2e60fbf1063868558d69c6beacf412dc755f9fc020f514b7955fc914fe30" dependencies = [ "quote", - "syn 2.0.100", + "syn 2.0.103", ] +[[package]] +name = "quick-error" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" + [[package]] name = "quick-xml" version = "0.30.0" @@ -3418,9 +3870,9 @@ dependencies = [ [[package]] name = "quick-xml" -version = "0.37.4" +version = "0.37.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4ce8c88de324ff838700f36fb6ab86c96df0e3c4ab6ef3a9b2044465cce1369" +checksum = "331e97a1af0bf59823e6eadffe373d7b27f485be8748f71471c662c1f269b7fb" dependencies = [ "memchr", ] @@ -3453,13 +3905,12 @@ dependencies = [ [[package]] name = "rand" -version = "0.9.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94" +checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97" dependencies = [ "rand_chacha 0.9.0", "rand_core 0.9.3", - "zerocopy 0.8.24", ] [[package]] @@ -3488,7 +3939,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.16", ] [[package]] @@ -3497,7 +3948,63 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" dependencies = [ - "getrandom 0.3.2", + "getrandom 0.3.3", +] + +[[package]] +name = "rangemap" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f60fcc7d6849342eff22c4350c8b9a989ee8ceabc4b481253e8946b9fe83d684" + +[[package]] +name = "rav1e" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd87ce80a7665b1cce111f8a16c1f3929f6547ce91ade6addf4ec86a8dda5ce9" +dependencies = [ + "arbitrary", + "arg_enum_proc_macro", + "arrayvec", + "av1-grain", + "bitstream-io", + "built", + "cfg-if", + "interpolate_name", + "itertools 0.12.1", + "libc", + "libfuzzer-sys", + "log", + "maybe-rayon", + "new_debug_unreachable", + "noop_proc_macro", + "num-derive", + "num-traits", + "once_cell", + "paste", + "profiling", + "rand 0.8.5", + "rand_chacha 0.3.1", + "simd_helpers", + "system-deps", + "thiserror 1.0.69", + "v_frame", + "wasm-bindgen", +] + +[[package]] +name = "ravif" +version = "0.11.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6a5f31fcf7500f9401fea858ea4ab5525c99f2322cfcee732c0e6c74208c0c6" +dependencies = [ + "avif-serialize", + "imgref", + "loop9", + "quick-error", + "rav1e", + "rayon", + "rgb", ] [[package]] @@ -3512,10 +4019,40 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "40d213455a5f1dc59214213c7330e074ddf8114c9a42411eb890c767357ce135" dependencies = [ - "objc2 0.6.0", + "objc2 0.6.1", "objc2-core-foundation", - "objc2-foundation 0.3.0", - "objc2-quartz-core 0.3.0", + "objc2-foundation 0.3.1", + "objc2-quartz-core 0.3.1", +] + +[[package]] +name = "rayon" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "read-fonts" +version = "0.29.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04ca636dac446b5664bd16c069c00a9621806895b8bb02c2dc68542b23b8f25d" +dependencies = [ + "bytemuck", + "font-types", ] [[package]] @@ -3535,11 +4072,11 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.11" +version = "0.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2f103c6d277498fbceb16e84d317e2a400f160f46904d5f5410848c829511a3" +checksum = "0d04b7d0ee6b4a0207a0a7adb104d23ecb0b47d6beae7152d0fa34b692b29fd6" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", ] [[package]] @@ -3586,6 +4123,29 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" +[[package]] +name = "resvg" +version = "0.45.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8928798c0a55e03c9ca6c4c6846f76377427d2c1e1f7e6de3c06ae57942df43" +dependencies = [ + "log", + "pico-args", + "rgb", + "svgtypes", + "tiny-skia", + "usvg", +] + +[[package]] +name = "rgb" +version = "0.8.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57397d16646700483b67d2dd6511d79318f9d057fdbd21a4066aeac8b41d310a" +dependencies = [ + "bytemuck", +] + [[package]] name = "rodio" version = "0.20.1" @@ -3602,8 +4162,8 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b91f7eff05f748767f183df4320a63d6936e9c6107d97c9e6bdd9784f4289c94" dependencies = [ - "base64", - "bitflags 2.9.0", + "base64 0.21.7", + "bitflags 2.9.1", "serde", "serde_derive", ] @@ -3628,6 +4188,12 @@ dependencies = [ "xmlparser", ] +[[package]] +name = "roxmltree" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c20b6793b5c2fa6553b250154b78d6d0db37e72700ae35fad9387a46f487c97" + [[package]] name = "rust-ini" version = "0.21.1" @@ -3641,9 +4207,9 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.24" +version = "0.1.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" +checksum = "989e6739f80c4ad5b13e0fd7fe89531180375b18520cc8c82080e4dc4035b84f" [[package]] name = "rustc-hash" @@ -3672,7 +4238,7 @@ version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "errno", "libc", "linux-raw-sys 0.4.15", @@ -3681,11 +4247,11 @@ dependencies = [ [[package]] name = "rustix" -version = "1.0.5" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d97817398dd4bb2e6da002002db259209759911da105da92bec29ccb12cf58bf" +checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "errno", "libc", "linux-raw-sys 0.9.4", @@ -3694,9 +4260,26 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.20" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" +checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" + +[[package]] +name = "rustybuzz" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfb9cf8877777222e4a3bc7eb247e398b56baba500c38c1c46842431adc8b55c" +dependencies = [ + "bitflags 2.9.1", + "bytemuck", + "libm", + "smallvec", + "ttf-parser 0.21.1", + "unicode-bidi-mirroring", + "unicode-ccc", + "unicode-properties", + "unicode-script", +] [[package]] name = "rxscreen" @@ -3747,6 +4330,12 @@ dependencies = [ "tiny-skia", ] +[[package]] +name = "self_cell" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f7d95a54511e0c7be3f51e8867aa8cf35148d7b9445d44de2f943e2b206e749" + [[package]] name = "semver" version = "1.0.26" @@ -3770,7 +4359,7 @@ checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.103", ] [[package]] @@ -3804,14 +4393,14 @@ checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.103", ] [[package]] name = "serde_spanned" -version = "0.6.8" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" dependencies = [ "serde", ] @@ -3831,9 +4420,9 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.8" +version = "0.10.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", "cpufeatures", @@ -3858,7 +4447,7 @@ checksum = "73120d240fe22196300f39ca8547ca2d014960f27b19b47b21288b396272f7f7" dependencies = [ "cmake", "libc", - "roxmltree", + "roxmltree 0.14.1", ] [[package]] @@ -3878,13 +4467,37 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "signal-hook-registry" -version = "1.4.2" +version = "1.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" +checksum = "9203b8055f63a2a00e2f593bb0510367fe707d7ff1e5c872de2f537b339e5410" dependencies = [ "libc", ] +[[package]] +name = "simd-adler32" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" + +[[package]] +name = "simd_helpers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95890f873bec569a0362c235787f3aca6e1e887302ba4840839bcc6459c42da6" +dependencies = [ + "quote", +] + +[[package]] +name = "simplecss" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a9c6883ca9c3c7c90e888de77b7a5c849c779d25d74a1269b0218b14e8b136c" +dependencies = [ + "log", +] + [[package]] name = "siphasher" version = "1.0.1" @@ -3892,14 +4505,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" [[package]] -name = "slab" -version = "0.4.9" +name = "skrifa" +version = "0.31.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +checksum = "dbeb4ca4399663735553a09dd17ce7e49a0a0203f03b706b39628c4d913a8607" dependencies = [ - "autocfg", + "bytemuck", + "read-fonts", ] +[[package]] +name = "slab" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04dc19736151f35336d325007ac991178d504a119863a2fcb3758cdb5e52c50d" + [[package]] name = "slabbin" version = "1.2.0" @@ -3913,10 +4533,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4f120bb98cb4cb0dab21c882968c3cbff79dd23b46f07b1cf5c25044945ce84" [[package]] -name = "smallvec" -version = "1.15.0" +name = "slotmap" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9" +checksum = "dbff4acf519f630b3a3ddcfaea6c06b42174d9a44bc70c620e9ed1649d58b82a" +dependencies = [ + "version_check", +] + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" [[package]] name = "smithay" @@ -3925,7 +4554,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "497aa82b881bf392470c286b213e01f7aa30b2fb08857831f81c87b251ba4d89" dependencies = [ "appendlist", - "bitflags 2.9.0", + "bitflags 2.9.1", "calloop 0.14.2", "cgmath", "cursor-icon", @@ -3961,7 +4590,7 @@ version = "0.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3457dea1f0eb631b4034d61d4d8c32074caa6cd1ab2d59f2327bd8461e2c0016" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "bytemuck", "calloop 0.13.0", "calloop-wayland-source", @@ -4009,6 +4638,9 @@ name = "strict-num" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731" +dependencies = [ + "float-cmp", +] [[package]] name = "strsim" @@ -4035,7 +4667,34 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.100", + "syn 2.0.103", +] + +[[package]] +name = "svg_fmt" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0193cc4331cfd2f3d2011ef287590868599a2f33c3e69bc22c1a3d3acf9e02fb" + +[[package]] +name = "svgtypes" +version = "0.15.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68c7541fff44b35860c1a7a47a7cadf3e4a304c457b58f9870d9706ece028afc" +dependencies = [ + "kurbo", + "siphasher", +] + +[[package]] +name = "swash" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f745de914febc7c9ab4388dfaf94bbc87e69f57bb41133a9b0c84d4be49856f3" +dependencies = [ + "skrifa", + "yazi", + "zeno", ] [[package]] @@ -4051,9 +4710,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.100" +version = "2.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" +checksum = "e4307e30089d6fd6aff212f2da3a1f9e32f3223b1f010fb09b7c95f90f3ca1e8" dependencies = [ "proc-macro2", "quote", @@ -4062,26 +4721,36 @@ dependencies = [ [[package]] name = "synstructure" -version = "0.13.1" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.103", +] + +[[package]] +name = "sys-locale" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eab9a99a024a169fe8a903cf9d4a3b3601109bcc13bd9e3c6fff259138626c4" +dependencies = [ + "libc", ] [[package]] name = "sysinfo" -version = "0.34.2" +version = "0.35.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4b93974b3d3aeaa036504b8eefd4c039dced109171c1ae973f1dc63b2c7e4b2" +checksum = "3c3ffa3e4ff2b324a57f7aeb3c349656c7b127c3c189520251a648102a92496e" dependencies = [ "libc", "memchr", "ntapi", "objc2-core-foundation", - "windows 0.57.0", + "objc2-io-kit", + "windows 0.61.3", ] [[package]] @@ -4097,6 +4766,18 @@ dependencies = [ "version-compare", ] +[[package]] +name = "taffy" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7aaef0ac998e6527d6d0d5582f7e43953bb17221ac75bb8eb2fcc2db3396db1c" +dependencies = [ + "arrayvec", + "grid", + "serde", + "slotmap", +] + [[package]] name = "target-lexicon" version = "0.12.16" @@ -4105,14 +4786,14 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" [[package]] name = "tempfile" -version = "3.19.1" +version = "3.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7437ac7763b9b123ccf33c338a5cc1bac6f69b45a136c19bdd8a65e3916435bf" +checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1" dependencies = [ "fastrand", - "getrandom 0.3.2", + "getrandom 0.3.3", "once_cell", - "rustix 1.0.5", + "rustix 1.0.7", "windows-sys 0.59.0", ] @@ -4151,7 +4832,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.103", ] [[package]] @@ -4162,17 +4843,16 @@ checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.103", ] [[package]] name = "thread_local" -version = "1.1.8" +version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" dependencies = [ "cfg-if", - "once_cell", ] [[package]] @@ -4226,6 +4906,7 @@ dependencies = [ "bytemuck", "cfg-if", "log", + "png", "tiny-skia-path", ] @@ -4242,19 +4923,34 @@ dependencies = [ [[package]] name = "tinystr" -version = "0.7.6" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" dependencies = [ "displaydoc", "zerovec", ] [[package]] -name = "toml" -version = "0.8.20" +name = "tinyvec" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd87a5cdd6ffab733b2f74bc4fd7ee5fff6634124999ac278c35fc78c6120148" +checksum = "09b3661f17e86524eccd4371ab0429194e0d7c008abb45f7a7495b1719463c71" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "toml" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" dependencies = [ "serde", "serde_spanned", @@ -4264,18 +4960,18 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.8" +version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.22.24" +version = "0.22.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474" +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" dependencies = [ "indexmap 2.9.0", "serde", @@ -4298,20 +4994,20 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.28" +version = "0.1.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" +checksum = "1b1ffbcf9c6f6b99d386e7444eb608ba646ae452a36b39737deb9663b610f662" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.103", ] [[package]] name = "tracing-core" -version = "0.1.33" +version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" +checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" dependencies = [ "once_cell", "valuable", @@ -4352,6 +5048,18 @@ version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "343e926fc669bc8cde4fa3129ab681c63671bae288b1f1081ceee6d9d37904fc" +[[package]] +name = "ttf-parser" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17f77d76d837a7830fe1d4f12b7b4ba4192c1888001c7164257e4bc6d21d96b4" + +[[package]] +name = "ttf-parser" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c591d83f69777866b9126b24c6dd9a18351f177e49d625920d19f989fd31cf8" + [[package]] name = "ttf-parser" version = "0.25.1" @@ -4381,12 +5089,48 @@ dependencies = [ "winapi", ] +[[package]] +name = "unicode-bidi" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" + +[[package]] +name = "unicode-bidi-mirroring" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23cb788ffebc92c5948d0e997106233eeb1d8b9512f93f41651f52b6c5f5af86" + +[[package]] +name = "unicode-ccc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1df77b101bcc4ea3d78dafc5ad7e4f58ceffe0b2b16bf446aeb50b6cb4157656" + [[package]] name = "unicode-ident" version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" +[[package]] +name = "unicode-linebreak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" + +[[package]] +name = "unicode-properties" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0" + +[[package]] +name = "unicode-script" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb421b350c9aff471779e262955939f565ec18b86c15364e6bdf0d662ca7c1f" + [[package]] name = "unicode-segmentation" version = "1.12.0" @@ -4401,9 +5145,9 @@ checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" [[package]] name = "unicode-width" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" +checksum = "4a1a07cc7db3810833284e8d372ccdc6da29741639ecc70c9ec107df0fa6154c" [[package]] name = "unsafe-libyaml" @@ -4424,10 +5168,26 @@ dependencies = [ ] [[package]] -name = "utf16_iter" -version = "1.0.5" +name = "usvg" +version = "0.45.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" +checksum = "80be9b06fbae3b8b303400ab20778c80bbaf338f563afe567cf3c9eea17b47ef" +dependencies = [ + "base64 0.22.1", + "data-url", + "flate2", + "imagesize", + "kurbo", + "log", + "pico-args", + "roxmltree 0.20.0", + "simplecss", + "siphasher", + "strict-num", + "svgtypes", + "tiny-skia-path", + "xmlwriter", +] [[package]] name = "utf8_iter" @@ -4443,12 +5203,25 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.16.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "458f7a779bf54acc9f347480ac654f68407d3aab21269a6e3c9f922acd9e2da9" +checksum = "3cf4199d1e5d15ddd86a694e4d0dffa9c323ce759fea589f00fef9d81cc1931d" dependencies = [ - "getrandom 0.3.2", - "rand 0.9.0", + "getrandom 0.3.3", + "js-sys", + "rand 0.9.1", + "wasm-bindgen", +] + +[[package]] +name = "v_frame" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "666b7727c8875d6ab5db9533418d7c764233ac9c0cff1d469aec8fa127597be2" +dependencies = [ + "aligned-vec", + "num-traits", + "wasm-bindgen", ] [[package]] @@ -4506,8 +5279,6 @@ dependencies = [ "thread_local", "vk-parse", "vulkano-macros", - "x11-dl", - "x11rb", ] [[package]] @@ -4519,7 +5290,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.103", ] [[package]] @@ -4533,7 +5304,7 @@ dependencies = [ "proc-macro2", "quote", "shaderc", - "syn 2.0.100", + "syn 2.0.103", "vulkano", ] @@ -4549,9 +5320,9 @@ dependencies = [ [[package]] name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" +version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasi" @@ -4584,7 +5355,7 @@ dependencies = [ "log", "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.103", "wasm-bindgen-shared", ] @@ -4619,7 +5390,7 @@ checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.103", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -4635,9 +5406,9 @@ dependencies = [ [[package]] name = "wayland-backend" -version = "0.3.8" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7208998eaa3870dad37ec8836979581506e0c5c64c20c9e79e9d2a10d6f47bf" +checksum = "fe770181423e5fc79d3e2a7f4410b7799d5aab1de4372853de3c6aa13ca24121" dependencies = [ "cc", "downcast-rs", @@ -4649,11 +5420,11 @@ dependencies = [ [[package]] name = "wayland-client" -version = "0.31.8" +version = "0.31.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2120de3d33638aaef5b9f4472bff75f07c56379cf76ea320bd3a3d65ecaf73f" +checksum = "978fa7c67b0847dbd6a9f350ca2569174974cd4082737054dbb7fbb79d7d9a61" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "rustix 0.38.44", "wayland-backend", "wayland-scanner", @@ -4665,16 +5436,16 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "625c5029dbd43d25e6aa9615e88b829a5cad13b2819c4ae129fdbb7c31ab4c7e" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "cursor-icon", "wayland-backend", ] [[package]] name = "wayland-cursor" -version = "0.31.8" +version = "0.31.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a93029cbb6650748881a00e4922b076092a6a08c11e7fbdb923f064b23968c5d" +checksum = "a65317158dec28d00416cb16705934070aef4f8393353d41126c54264ae0f182" dependencies = [ "rustix 0.38.44", "wayland-client", @@ -4683,9 +5454,9 @@ dependencies = [ [[package]] name = "wayland-egl" -version = "0.32.5" +version = "0.32.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "504838241a10e271f48ffd429ac4033e0ac468b399fe7c2e2840f5c3a82d9902" +checksum = "7dc56cc3ef057a5efb434e58a0712ea30d2823b736ba9faa4669854ac6454395" dependencies = [ "wayland-backend", "wayland-sys", @@ -4693,11 +5464,11 @@ dependencies = [ [[package]] name = "wayland-protocols" -version = "0.32.6" +version = "0.32.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0781cf46869b37e36928f7b432273c0995aa8aed9552c556fb18754420541efc" +checksum = "779075454e1e9a521794fed15886323ea0feda3f8b0fc1390f5398141310422a" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "wayland-backend", "wayland-client", "wayland-scanner", @@ -4706,11 +5477,11 @@ dependencies = [ [[package]] name = "wayland-protocols-misc" -version = "0.3.6" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "feb7ee1810026d1bb15d47086d03a7e5c68651c707e305ba1e8cc796fcbf5a54" +checksum = "635cf2968bd88599445b25a2eeef655d463bb04f9aed04e4bf8c2018f3d4fc41" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "wayland-backend", "wayland-protocols", "wayland-scanner", @@ -4719,11 +5490,11 @@ dependencies = [ [[package]] name = "wayland-protocols-plasma" -version = "0.3.6" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ccaacc76703fefd6763022ac565b590fcade92202492381c95b2edfdf7d46b3" +checksum = "4fd38cdad69b56ace413c6bcc1fbf5acc5e2ef4af9d5f8f1f9570c0c83eae175" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "wayland-backend", "wayland-client", "wayland-protocols", @@ -4732,11 +5503,11 @@ dependencies = [ [[package]] name = "wayland-protocols-wlr" -version = "0.3.6" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "248a02e6f595aad796561fa82d25601bd2c8c3b145b1c7453fc8f94c1a58f8b2" +checksum = "1cb6cdc73399c0e06504c437fe3cf886f25568dd5454473d565085b36d6a8bbf" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "wayland-backend", "wayland-client", "wayland-protocols", @@ -4751,17 +5522,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "896fdafd5d28145fce7958917d69f2fd44469b1d4e861cb5961bcbeebc6d1484" dependencies = [ "proc-macro2", - "quick-xml 0.37.4", + "quick-xml 0.37.5", "quote", ] [[package]] name = "wayland-server" -version = "0.31.7" +version = "0.31.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97fabd7ed68cff8e7657b8a8a1fbe90cb4a3f0c30d90da4bf179a7a23008a4cb" +checksum = "485dfb8ccf0daa0d34625d34e6ac15f99e550a7999b6fd88a0835ccd37655785" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "downcast-rs", "rustix 0.38.44", "wayland-backend", @@ -4813,6 +5584,34 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "weezl" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a751b3277700db47d3e574514de2eced5e54dc8a5436a3bf7a0b248b2cee16f3" + +[[package]] +name = "wgui" +version = "0.1.0" +source = "git+https://github.com/wlx-team/wgui.git?branch=wip#455fabb31931b888f9b976c6a914c6f4f73b7beb" +dependencies = [ + "anyhow", + "cosmic-text", + "etagere", + "glam", + "image", + "log", + "lru", + "resvg", + "roxmltree 0.20.0", + "rustc-hash 2.1.1", + "slotmap", + "smallvec", + "taffy", + "vulkano", + "vulkano-shaders", +] + [[package]] name = "which" version = "4.4.2" @@ -4874,12 +5673,24 @@ dependencies = [ [[package]] name = "windows" -version = "0.57.0" +version = "0.61.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12342cb4d8e3b046f3d80effd474a7a02447231330ef77d71daa6fbc40681143" +checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893" dependencies = [ - "windows-core 0.57.0", - "windows-targets 0.52.6", + "windows-collections", + "windows-core 0.61.2", + "windows-future", + "windows-link", + "windows-numerics", +] + +[[package]] +name = "windows-collections" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8" +dependencies = [ + "windows-core 0.61.2", ] [[package]] @@ -4894,38 +5705,26 @@ dependencies = [ [[package]] name = "windows-core" -version = "0.57.0" +version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2ed2439a290666cd67ecce2b0ffaad89c2a56b976b736e6ece670297897832d" +checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" dependencies = [ - "windows-implement 0.57.0", - "windows-interface 0.57.0", - "windows-result 0.1.2", - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-core" -version = "0.61.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4763c1de310c86d75a878046489e2e5ba02c649d185f21c67d4cf8a56d098980" -dependencies = [ - "windows-implement 0.60.0", - "windows-interface 0.59.1", + "windows-implement", + "windows-interface", "windows-link", - "windows-result 0.3.2", + "windows-result 0.3.4", "windows-strings", ] [[package]] -name = "windows-implement" -version = "0.57.0" +name = "windows-future" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7" +checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e" dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", + "windows-core 0.61.2", + "windows-link", + "windows-threading", ] [[package]] @@ -4936,18 +5735,7 @@ checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", -] - -[[package]] -name = "windows-interface" -version = "0.57.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", + "syn 2.0.103", ] [[package]] @@ -4958,14 +5746,24 @@ checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.103", ] [[package]] name = "windows-link" -version = "0.1.1" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" + +[[package]] +name = "windows-numerics" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" +dependencies = [ + "windows-core 0.61.2", + "windows-link", +] [[package]] name = "windows-result" @@ -4978,18 +5776,18 @@ dependencies = [ [[package]] name = "windows-result" -version = "0.3.2" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252" +checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" dependencies = [ "windows-link", ] [[package]] name = "windows-strings" -version = "0.4.0" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2ba9642430ee452d5a7aa78d72907ebe8cfda358e8cb7918a2050581322f97" +checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" dependencies = [ "windows-link", ] @@ -5060,13 +5858,38 @@ dependencies = [ "windows_aarch64_gnullvm 0.52.6", "windows_aarch64_msvc 0.52.6", "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm", + "windows_i686_gnullvm 0.52.6", "windows_i686_msvc 0.52.6", "windows_x86_64_gnu 0.52.6", "windows_x86_64_gnullvm 0.52.6", "windows_x86_64_msvc 0.52.6", ] +[[package]] +name = "windows-targets" +version = "0.53.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c66f69fcc9ce11da9966ddb31a40968cad001c5bedeb5c2b82ede4253ab48aef" +dependencies = [ + "windows_aarch64_gnullvm 0.53.0", + "windows_aarch64_msvc 0.53.0", + "windows_i686_gnu 0.53.0", + "windows_i686_gnullvm 0.53.0", + "windows_i686_msvc 0.53.0", + "windows_x86_64_gnu 0.53.0", + "windows_x86_64_gnullvm 0.53.0", + "windows_x86_64_msvc 0.53.0", +] + +[[package]] +name = "windows-threading" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6" +dependencies = [ + "windows-link", +] + [[package]] name = "windows_aarch64_gnullvm" version = "0.42.2" @@ -5085,6 +5908,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" + [[package]] name = "windows_aarch64_msvc" version = "0.42.2" @@ -5103,6 +5932,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" + [[package]] name = "windows_i686_gnu" version = "0.42.2" @@ -5121,12 +5956,24 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" +[[package]] +name = "windows_i686_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" + [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" + [[package]] name = "windows_i686_msvc" version = "0.42.2" @@ -5145,6 +5992,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +[[package]] +name = "windows_i686_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" + [[package]] name = "windows_x86_64_gnu" version = "0.42.2" @@ -5163,6 +6016,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" + [[package]] name = "windows_x86_64_gnullvm" version = "0.42.2" @@ -5181,6 +6040,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" + [[package]] name = "windows_x86_64_msvc" version = "0.42.2" @@ -5200,15 +6065,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] -name = "winit" -version = "0.30.9" +name = "windows_x86_64_msvc" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a809eacf18c8eca8b6635091543f02a5a06ddf3dad846398795460e6e0ae3cc0" +checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" + +[[package]] +name = "winit" +version = "0.30.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4409c10174df8779dc29a4788cac85ed84024ccbc1743b776b21a520ee1aaf4" dependencies = [ "ahash", "android-activity", "atomic-waker", - "bitflags 2.9.0", + "bitflags 2.9.1", "block2", "bytemuck", "calloop 0.13.0", @@ -5253,9 +6124,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.7.6" +version = "0.7.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63d3fcd9bba44b03821e7d699eeee959f3126dcc4aa8e4ae18ec617c2a5cea10" +checksum = "74c7b26e3480b707944fc872477815d29a8e429d2f93a1ce000f5fa84a15cbcd" dependencies = [ "memchr", ] @@ -5266,7 +6137,7 @@ version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", ] [[package]] @@ -5333,29 +6204,22 @@ dependencies = [ "tracing", "tracing-subscriber", "uuid", - "vulkano", - "vulkano-shaders", "wayland-client", "wayland-egl", "wayvr_ipc", + "wgui", "winit", "wlx-capture", "xcb", - "xdg", + "xdg 3.0.0", "xkbcommon 0.8.0", ] -[[package]] -name = "write16" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" - [[package]] name = "writeable" -version = "0.5.5" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" +checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" [[package]] name = "x11-dl" @@ -5414,14 +6278,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "213b7324336b53d2414b2db8537e56544d981803139155afa84f76eeebb7a546" [[package]] -name = "xdg-home" -version = "1.3.0" +name = "xdg" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec1cdab258fb55c0da61328dc52c8764709b249011b2cad0454c72f0bf10a1f6" -dependencies = [ - "libc", - "windows-sys 0.59.0", -] +checksum = "2fb433233f2df9344722454bc7e96465c9d03bff9d77c248f9e7523fe79585b5" [[package]] name = "xkbcommon" @@ -5452,7 +6312,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d039de8032a9a8856a6be89cea3e5d12fdd82306ab7c94d74e6deab2460651c5" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "dlib", "log", "once_cell", @@ -5481,10 +6341,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "66fee0b777b0f5ac1c69bb06d361268faafa61cd4682ae064a171c16c433e9e4" [[package]] -name = "yaml-rust2" -version = "0.10.1" +name = "xmlwriter" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "818913695e83ece1f8d2a1c52d54484b7b46d0f9c06beeb2649b9da50d9b512d" +checksum = "ec7a2a501ed189703dba8b08142f057e887dfc4b2cc4db2d343ac6376ba3e0b9" + +[[package]] +name = "yaml-rust2" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ce2a4ff45552406d02501cea6c18d8a7e50228e7736a872951fe2fe75c91be7" dependencies = [ "arraydeque", "encoding_rs", @@ -5500,6 +6366,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "yazi" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e01738255b5a16e78bbb83e7fbba0a1e7dd506905cfc53f4622d89015a03fbb5" + [[package]] name = "yeslogic-fontconfig-sys" version = "3.2.0" @@ -5514,9 +6386,9 @@ dependencies = [ [[package]] name = "yoke" -version = "0.7.5" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" +checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" dependencies = [ "serde", "stable_deref_trait", @@ -5526,25 +6398,24 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.7.5" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" +checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.103", "synstructure", ] [[package]] name = "zbus" -version = "5.5.0" +version = "5.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59c333f648ea1b647bc95dc1d34807c8e25ed7a6feff3394034dc4776054b236" +checksum = "d3a7c7cee313d044fca3f48fa782cb750c79e4ca76ba7bc7718cd4024cdf6f68" dependencies = [ "async-broadcast", "async-executor", - "async-fs", "async-io", "async-lock", "async-process", @@ -5557,16 +6428,14 @@ dependencies = [ "futures-core", "futures-lite", "hex", - "nix 0.29.0", + "nix 0.30.1", "ordered-stream", "serde", "serde_repr", - "static_assertions", "tracing", "uds_windows", "windows-sys 0.59.0", "winnow", - "xdg-home", "zbus_macros", "zbus_names", "zvariant", @@ -5574,14 +6443,14 @@ dependencies = [ [[package]] name = "zbus_macros" -version = "5.5.0" +version = "5.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f325ad10eb0d0a3eb060203494c3b7ec3162a01a59db75d2deee100339709fc0" +checksum = "a17e7e5eec1550f747e71a058df81a9a83813ba0f6a95f39c4e218bdc7ba366a" dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.103", "zbus_names", "zvariant", "zvariant_utils", @@ -5600,43 +6469,29 @@ dependencies = [ ] [[package]] -name = "zerocopy" -version = "0.7.35" +name = "zeno" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" -dependencies = [ - "zerocopy-derive 0.7.35", -] +checksum = "6df3dc4292935e51816d896edcd52aa30bc297907c26167fec31e2b0c6a32524" [[package]] name = "zerocopy" -version = "0.8.24" +version = "0.8.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2586fea28e186957ef732a5f8b3be2da217d65c5969d4b1e17f973ebbe876879" +checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb" dependencies = [ - "zerocopy-derive 0.8.24", + "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.35" +version = "0.8.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", -] - -[[package]] -name = "zerocopy-derive" -version = "0.8.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a996a8f63c5c4448cd959ac1bab0aaa3306ccfd060472f85943ee0750f0169be" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", + "syn 2.0.103", ] [[package]] @@ -5656,15 +6511,26 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.103", "synstructure", ] [[package]] -name = "zerovec" -version = "0.10.4" +name = "zerotrie" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428" dependencies = [ "yoke", "zerofrom", @@ -5673,25 +6539,39 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.10.3" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.103", +] + +[[package]] +name = "zune-core" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f423a2c17029964870cfaabb1f13dfab7d092a62a29a89264f4d36990ca414a" + +[[package]] +name = "zune-jpeg" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f6fe2e33d02a98ee64423802e16df3de99c43e5cf5ff983767e1128b394c8ac" +dependencies = [ + "zune-core", ] [[package]] name = "zvariant" -version = "5.4.0" +version = "5.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2df9ee044893fcffbdc25de30546edef3e32341466811ca18421e3cd6c5a3ac" +checksum = "9d30786f75e393ee63a21de4f9074d4c038d52c5b1bb4471f955db249f9dffb1" dependencies = [ "endi", "enumflags2", "serde", - "static_assertions", "url", "winnow", "zvariant_derive", @@ -5700,14 +6580,14 @@ dependencies = [ [[package]] name = "zvariant_derive" -version = "5.4.0" +version = "5.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74170caa85b8b84cc4935f2d56a57c7a15ea6185ccdd7eadb57e6edd90f94b2f" +checksum = "75fda702cd42d735ccd48117b1630432219c0e9616bf6cb0f8350844ee4d9580" dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.103", "zvariant_utils", ] @@ -5721,6 +6601,6 @@ dependencies = [ "quote", "serde", "static_assertions", - "syn 2.0.100", + "syn 2.0.103", "winnow", ] diff --git a/Cargo.toml b/Cargo.toml index e89f6a1..1a69d3c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,7 @@ categories = ["games"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -anyhow = "1.0.89" +anyhow = { workspace = true } ash = "^0.38.0" # must match vulkano chrono = "0.4.38" chrono-tz = "0.10.0" @@ -24,17 +24,15 @@ clap = { version = "4.5.6", features = ["derive"] } config = "0.15.11" ctrlc = { version = "3.4.4", features = ["termination"] } dbus = { version = "0.9.7" } -fontconfig-rs = "0.1.1" -freetype-rs = "0.36.0" # latest version supported on ubuntu 22.04 futures = "0.3.30" -glam = { version = "0.30.1", features = ["approx", "mint", "serde"] } +glam = { workspace = true, features = ["mint", "serde"] } idmap = { version = "0.2.21", features = ["serde"] } idmap-derive = "0.1.2" input-linux = "0.7.0" json = { version = "0.12.4", optional = true } json5 = "0.4.1" libc = "0.2.155" -log = "0.4.21" +log = { workspace = true } openxr = { git = "https://github.com/Ralith/openxrs", rev = "d0afdd3365bc1e14de28f6a3a21f457e788a702e", features = [ "linked", "mint", @@ -54,14 +52,12 @@ serde_json = "1.0.117" serde_yaml = "0.9.34" smallvec = "1.13.2" strum = { version = "0.27.1", features = ["derive"] } -sysinfo = { version = "0.34.2" } -thiserror = "2.0.3" -vulkano = { version = "0.35.1" } -vulkano-shaders = { version = "0.35.0" } +sysinfo = { version = "0.35" } +thiserror = "2.0" wlx-capture = { git = "https://github.com/galister/wlx-capture", tag = "v0.5.3", default-features = false } libmonado = { version = "1.3.2", optional = true } -winit = { version = "0.30.0", optional = true } -xdg = "2.5.2" +winit = { version = "0.30", optional = true } +xdg = "3.0" log-panics = { version = "2.1.0", features = ["with-backtrace"] } serde_json5 = "0.2.1" xkbcommon = { version = "0.8.0" } @@ -74,6 +70,9 @@ image_dds = { version = "0.7.2", default-features = false, features = [ mint = "0.5.9" tracing-subscriber = { version = "0.3.19", features = ["env-filter"] } tracing = "0.1.41" +vulkano = { workspace = true } +vulkano-shaders = { workspace = true } +wgui = { path = "../wgui" } ################################ #WayVR-only deps @@ -92,6 +91,7 @@ wayland-egl = { version = "0.32.4", optional = true } interprocess = { version = "2.2.2", optional = true } bytes = { version = "1.9.0", optional = true } wayvr_ipc = { git = "https://github.com/olekolek1000/wayvr-ipc.git", rev = "a72587d23f3bb8624d9aeb1f13c0a21e65350f51", default-features = false, optional = true } +rust-embed = "8.7.2" ################################ [build-dependencies] diff --git a/src/backend/common.rs b/src/backend/common.rs index de399d2..962efba 100644 --- a/src/backend/common.rs +++ b/src/backend/common.rs @@ -137,9 +137,8 @@ where #[allow(clippy::too_many_lines, clippy::cognitive_complexity)] #[allow(clippy::all, clippy::pedantic, clippy::nursery, clippy::cargo)] pub fn update(&mut self, app: &mut AppState) -> anyhow::Result>> { - use crate::overlays::{ - screen::{create_screen_interaction, create_screen_renderer_wl, load_pw_token_config}, - watch::create_watch_canvas, + use crate::overlays::screen::{ + create_screen_interaction, create_screen_renderer_wl, load_pw_token_config, }; use glam::vec2; use wlx_capture::wayland::OutputChangeEvent; @@ -256,15 +255,8 @@ where } if watch_dirty { - let watch = self.mut_by_name(WATCH_NAME).unwrap(); // want panic - match create_watch_canvas(None, app) { - Ok(canvas) => { - watch.backend = Box::new(canvas); - } - Err(e) => { - log::error!("Failed to create watch canvas: {}", e); - } - } + let _watch = self.mut_by_name(WATCH_NAME).unwrap(); // want panic + todo!(); } Ok(removed_overlays) diff --git a/src/backend/mod.rs b/src/backend/mod.rs index fa5397a..339a0d8 100644 --- a/src/backend/mod.rs +++ b/src/backend/mod.rs @@ -11,9 +11,6 @@ pub mod openvr; #[cfg(feature = "openxr")] pub mod openxr; -#[cfg(feature = "uidev")] -pub mod uidev; - #[cfg(feature = "osc")] pub mod osc; diff --git a/src/backend/notifications.rs b/src/backend/notifications.rs index 9c34429..203e5f6 100644 --- a/src/backend/notifications.rs +++ b/src/backend/notifications.rs @@ -279,14 +279,14 @@ struct XsoMessage { messageType: i32, index: Option, volume: Option, - audioPath: Option>, + audioPath: Option, timeout: Option, - title: Arc, - content: Option>, - icon: Option>, + title: String, + content: Option, + icon: Option, height: Option, opacity: Option, useBase64Icon: Option, - sourceApp: Option>, + sourceApp: Option, alwaysShow: Option, } diff --git a/src/backend/openvr/lines.rs b/src/backend/openvr/lines.rs index 1c590e6..9c6f450 100644 --- a/src/backend/openvr/lines.rs +++ b/src/backend/openvr/lines.rs @@ -2,20 +2,31 @@ use std::f32::consts::PI; use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::Arc; +use ash::vk::SubmitInfo; use glam::{Affine3A, Vec3, Vec3A, Vec4}; use idmap::IdMap; use ovr_overlay::overlay::OverlayManager; use ovr_overlay::sys::ETrackingUniverseOrigin; -use vulkano::command_buffer::CommandBufferUsage; -use vulkano::format::Format; -use vulkano::image::view::ImageView; -use vulkano::image::ImageLayout; +use vulkano::{ + command_buffer::{ + CommandBufferBeginInfo, CommandBufferLevel, CommandBufferUsage, RecordingCommandBuffer, + }, + format::Format, + image::view::ImageView, + image::{Image, ImageLayout}, + sync::{ + fence::{Fence, FenceCreateInfo}, + AccessFlags, DependencyInfo, ImageMemoryBarrier, PipelineStages, + }, + VulkanObject, +}; +use wgui::gfx::WGfx; use crate::backend::overlay::{ FrameMeta, OverlayData, OverlayRenderer, OverlayState, ShouldRender, SplitOverlayBackend, Z_ORDER_LINES, }; -use crate::graphics::{CommandBuffers, WlxGraphics}; +use crate::graphics::CommandBuffers; use crate::state::AppState; use super::overlay::OpenVrOverlayData; @@ -29,24 +40,22 @@ pub(super) struct LinePool { } impl LinePool { - pub fn new(graphics: Arc) -> anyhow::Result { - let mut command_buffer = graphics.create_uploads_command_buffer( - graphics.transfer_queue.clone(), - CommandBufferUsage::OneTimeSubmit, - )?; + pub fn new(graphics: Arc) -> anyhow::Result { + let mut command_buffer = + graphics.create_xfer_command_buffer(CommandBufferUsage::OneTimeSubmit)?; let buf = vec![255; 16]; - let texture = command_buffer.texture2d_raw(2, 2, Format::R8G8B8A8_UNORM, &buf)?; + let texture = command_buffer.upload_image(2, 2, Format::R8G8B8A8_UNORM, &buf)?; command_buffer.build_and_execute_now()?; - graphics - .transition_layout( - texture.clone(), - ImageLayout::ShaderReadOnlyOptimal, - ImageLayout::TransferSrcOptimal, - )? - .wait(None)?; + transition_layout( + &graphics, + texture.clone(), + ImageLayout::ShaderReadOnlyOptimal, + ImageLayout::TransferSrcOptimal, + )? + .wait(None)?; let view = ImageView::new_default(texture)?; @@ -150,7 +159,7 @@ impl LinePool { data.after_input(overlay, app)?; if data.state.want_visible { if data.state.dirty { - data.upload_texture(overlay, &app.graphics); + data.upload_texture(overlay, &app.gfx); data.state.dirty = false; } @@ -201,3 +210,55 @@ impl OverlayRenderer for StaticRenderer { }) } } + +pub fn transition_layout( + gfx: &WGfx, + image: Arc, + old_layout: ImageLayout, + new_layout: ImageLayout, +) -> anyhow::Result { + let barrier = ImageMemoryBarrier { + src_stages: PipelineStages::ALL_TRANSFER, + src_access: AccessFlags::TRANSFER_WRITE, + dst_stages: PipelineStages::ALL_TRANSFER, + dst_access: AccessFlags::TRANSFER_READ, + old_layout, + new_layout, + subresource_range: image.subresource_range(), + ..ImageMemoryBarrier::image(image) + }; + + let command_buffer = unsafe { + let mut builder = RecordingCommandBuffer::new( + gfx.command_buffer_allocator.clone(), + gfx.queue_gfx.queue_family_index(), + CommandBufferLevel::Primary, + CommandBufferBeginInfo { + usage: CommandBufferUsage::OneTimeSubmit, + inheritance_info: None, + ..Default::default() + }, + )?; + + builder.pipeline_barrier(&DependencyInfo { + image_memory_barriers: smallvec::smallvec![barrier], + ..Default::default() + })?; + builder.end()? + }; + + let fence = Fence::new(gfx.device.clone(), FenceCreateInfo::default())?; + + let fns = gfx.device.fns(); + unsafe { + (fns.v1_0.queue_submit)( + gfx.queue_gfx.handle(), + 1, + [SubmitInfo::default().command_buffers(&[command_buffer.handle()])].as_ptr(), + fence.handle(), + ) + } + .result()?; + + Ok(fence) +} diff --git a/src/backend/openvr/mod.rs b/src/backend/openvr/mod.rs index a610266..9e9779c 100644 --- a/src/backend/openvr/mod.rs +++ b/src/backend/openvr/mod.rs @@ -30,7 +30,7 @@ use crate::{ overlay::{OverlayData, ShouldRender}, task::{SystemTask, TaskType}, }, - graphics::{CommandBuffers, WlxGraphics}, + graphics::{init_openvr_graphics, CommandBuffers}, overlays::{ toast::{Toast, ToastTopic}, watch::{watch_fade, WATCH_NAME}, @@ -39,7 +39,7 @@ use crate::{ }; #[cfg(feature = "wayvr")] -use crate::{gui::modular::button::WayVRAction, overlays::wayvr::wayvr_action}; +use crate::{backend::wayvr::WayVRAction, overlays::wayvr::wayvr_action}; pub mod helpers; pub mod input; @@ -95,8 +95,8 @@ pub fn openvr_run( }; let mut state = { - let graphics = WlxGraphics::new_openvr(instance_extensions, device_extensions_fn)?; - AppState::from_graphics(graphics)? + let (gfx, gfx_extras) = init_openvr_graphics(instance_extensions, device_extensions_fn)?; + AppState::from_graphics(gfx, gfx_extras)? }; if show_by_default { @@ -147,7 +147,7 @@ pub fn openvr_run( let mut next_device_update = Instant::now(); let mut due_tasks = VecDeque::with_capacity(4); - let mut lines = LinePool::new(state.graphics.clone())?; + let mut lines = LinePool::new(state.gfx.clone())?; let pointer_lines = [lines.allocate(), lines.allocate()]; 'main_loop: loop { @@ -361,7 +361,7 @@ pub fn openvr_run( log::trace!("Rendering overlays"); - if let Some(mut future) = buffers.execute_now(state.graphics.graphics_queue.clone())? { + if let Some(mut future) = buffers.execute_now(state.gfx.queue_gfx.clone())? { if let Err(e) = future.flush() { return Err(BackendError::Fatal(e.into())); } @@ -370,7 +370,7 @@ pub fn openvr_run( overlays .iter_mut() - .for_each(|o| o.after_render(universe.clone(), &mut overlay_mgr, &state.graphics)); + .for_each(|o| o.after_render(universe.clone(), &mut overlay_mgr, &state.gfx)); #[cfg(feature = "wayvr")] if let Some(wayvr) = &state.wayvr { diff --git a/src/backend/openvr/overlay.rs b/src/backend/openvr/overlay.rs index a8c192b..8eb4658 100644 --- a/src/backend/openvr/overlay.rs +++ b/src/backend/openvr/overlay.rs @@ -7,9 +7,13 @@ use ovr_overlay::{ pose::Matrix3x4, sys::{ETrackingUniverseOrigin, VRVulkanTextureData_t}, }; -use vulkano::{image::view::ImageView, Handle, VulkanObject}; +use vulkano::{ + image::{view::ImageView, ImageUsage}, + Handle, VulkanObject, +}; +use wgui::gfx::WGfx; -use crate::{backend::overlay::OverlayData, graphics::WlxGraphics, state::AppState}; +use crate::{backend::overlay::OverlayData, state::AppState}; use super::helpers::Affine3AConvert; @@ -65,10 +69,11 @@ impl OverlayData { let Some(meta) = self.backend.frame_meta() else { return Ok(false); }; - let image = app.graphics.render_texture( + let image = app.gfx.new_image( meta.extent[0], meta.extent[1], - app.graphics.native_format, + app.gfx.surface_format, + ImageUsage::TRANSFER_SRC | ImageUsage::COLOR_ATTACHMENT | ImageUsage::SAMPLED, )?; self.data.image_view = Some(ImageView::new_default(image)?); Ok(true) @@ -91,7 +96,7 @@ impl OverlayData { &mut self, universe: ETrackingUniverseOrigin, overlay: &mut OverlayManager, - graphics: &WlxGraphics, + graphics: &WGfx, ) { if self.data.visible { if self.state.dirty { @@ -228,7 +233,7 @@ impl OverlayData { } } - pub(super) fn upload_texture(&mut self, overlay: &mut OverlayManager, graphics: &WlxGraphics) { + pub(super) fn upload_texture(&mut self, overlay: &mut OverlayManager, graphics: &WGfx) { let Some(handle) = self.data.handle else { log::debug!("{}: No overlay handle", self.state.name); return; @@ -267,8 +272,8 @@ impl OverlayData { m_pDevice: graphics.device.handle().as_raw() as *mut _, m_pPhysicalDevice: graphics.device.physical_device().handle().as_raw() as *mut _, m_pInstance: graphics.instance.handle().as_raw() as *mut _, - m_pQueue: graphics.graphics_queue.handle().as_raw() as *mut _, - m_nQueueFamilyIndex: graphics.graphics_queue.queue_family_index(), + m_pQueue: graphics.queue_gfx.handle().as_raw() as *mut _, + m_nQueueFamilyIndex: graphics.queue_gfx.queue_family_index(), }; log::trace!( "{}: UploadTex {:?}, {}x{}, {:?}", diff --git a/src/backend/openxr/lines.rs b/src/backend/openxr/lines.rs index 144fe1e..af8cb7b 100644 --- a/src/backend/openxr/lines.rs +++ b/src/backend/openxr/lines.rs @@ -9,11 +9,15 @@ use std::{ }, }; -use vulkano::command_buffer::CommandBufferUsage; +use wgui::gfx::{pipeline::WGfxPipeline, WGfx}; use crate::{ backend::openxr::helpers, - graphics::{CommandBuffers, WlxGraphics, WlxPipeline}, + graphics::{CommandBuffers, ExtentExt, Vert2Uv}, + state::AppState, +}; +use vulkano::{ + command_buffer::CommandBufferUsage, pipeline::graphics::input_assembly::PrimitiveTopology, }; use super::{ @@ -37,20 +41,18 @@ static COLORS: [[f32; 6]; 5] = { pub(super) struct LinePool { lines: IdMap, - pipeline: Arc, + pipeline: Arc>, } impl LinePool { - pub(super) fn new(graphics: Arc) -> anyhow::Result { - let Ok(shaders) = graphics.shared_shaders.read() else { - anyhow::bail!("Failed to lock shared shaders for reading"); - }; - - let pipeline = graphics.create_pipeline( - shaders.get("vert_common").unwrap().clone(), // want panic - shaders.get("frag_color").unwrap().clone(), // want panic - graphics.native_format, + pub(super) fn new(app: &AppState) -> anyhow::Result { + let pipeline = app.gfx.create_pipeline( + app.gfx_extras.shaders.get("vert_quad").unwrap().clone(), // want panic + app.gfx_extras.shaders.get("frag_color").unwrap().clone(), // want panic + app.gfx.surface_format, None, + PrimitiveTopology::TriangleStrip, + false, )?; Ok(Self { @@ -59,14 +61,10 @@ impl LinePool { }) } - pub(super) fn allocate( - &mut self, - xr: &XrState, - graphics: Arc, - ) -> anyhow::Result { + pub(super) fn allocate(&mut self, xr: &XrState, gfx: Arc) -> anyhow::Result { let id = LINE_AUTO_INCREMENT.fetch_add(1, Ordering::Relaxed); - let srd = create_swapchain(xr, graphics, [1, 1, 1], SwapchainOpts::new())?; + let srd = create_swapchain(xr, gfx, [1, 1, 1], SwapchainOpts::new())?; self.lines.insert( id, LineContainer { @@ -130,7 +128,7 @@ impl LinePool { pub(super) fn render( &mut self, - graphics: Arc, + app: &AppState, buf: &mut CommandBuffers, ) -> anyhow::Result<()> { for line in self.lines.values_mut() { @@ -139,14 +137,19 @@ impl LinePool { let set0 = self .pipeline - .uniform_buffer(0, COLORS[inner.color].to_vec())?; + .uniform_buffer_upload(0, COLORS[inner.color].to_vec())?; - let pass = self - .pipeline - .create_pass_for_target(tgt.clone(), vec![set0])?; + let pass = self.pipeline.create_pass( + tgt.extent_f32(), + app.gfx_extras.quad_verts.clone(), + 0..4, + 0..1, + vec![set0], + )?; - let mut cmd_buffer = - graphics.create_command_buffer(CommandBufferUsage::OneTimeSubmit)?; + let mut cmd_buffer = app + .gfx + .create_gfx_command_buffer(CommandBufferUsage::OneTimeSubmit)?; cmd_buffer.begin_rendering(tgt)?; cmd_buffer.run_ref(&pass)?; cmd_buffer.end_rendering()?; diff --git a/src/backend/openxr/mod.rs b/src/backend/openxr/mod.rs index dcf8c16..2dd8ccd 100644 --- a/src/backend/openxr/mod.rs +++ b/src/backend/openxr/mod.rs @@ -24,7 +24,7 @@ use crate::{ overlay::{OverlayData, ShouldRender}, task::{SystemTask, TaskType}, }, - graphics::{CommandBuffers, WlxGraphics}, + graphics::{init_openxr_graphics, CommandBuffers}, overlays::{ toast::{Toast, ToastTopic}, watch::{watch_fade, WATCH_NAME}, @@ -33,7 +33,7 @@ use crate::{ }; #[cfg(feature = "wayvr")] -use crate::{gui::modular::button::WayVRAction, overlays::wayvr::wayvr_action}; +use crate::{backend::wayvr::WayVRAction, overlays::wayvr::wayvr_action}; mod blocker; mod helpers; @@ -71,8 +71,8 @@ pub fn openxr_run( }; let mut app = { - let graphics = WlxGraphics::new_openxr(xr_instance.clone(), system)?; - AppState::from_graphics(graphics)? + let (gfx, gfx_extras) = init_openxr_graphics(xr_instance.clone(), system)?; + AppState::from_graphics(gfx, gfx_extras)? }; let environment_blend_mode = { @@ -95,7 +95,7 @@ pub fn openxr_run( } let mut overlays = OverlayContainer::::new(&mut app, headless)?; - let mut lines = LinePool::new(app.graphics.clone())?; + let mut lines = LinePool::new(&app)?; let mut notifications = NotificationManager::new(); notifications.run_dbus(); @@ -120,10 +120,10 @@ pub fn openxr_run( &xr_instance, system, &xr::vulkan::SessionCreateInfo { - instance: app.graphics.instance.handle().as_raw() as _, - physical_device: app.graphics.device.physical_device().handle().as_raw() as _, - device: app.graphics.device.handle().as_raw() as _, - queue_family_index: app.graphics.graphics_queue.queue_family_index(), + instance: app.gfx.instance.handle().as_raw() as _, + physical_device: app.gfx.device.physical_device().handle().as_raw() as _, + device: app.gfx.device.handle().as_raw() as _, + queue_family_index: app.gfx.queue_gfx.queue_family_index(), queue_index: 0, }, )?; @@ -151,8 +151,8 @@ pub fn openxr_run( }; let pointer_lines = [ - lines.allocate(&xr_state, app.graphics.clone())?, - lines.allocate(&xr_state, app.graphics.clone())?, + lines.allocate(&xr_state, app.gfx.clone())?, + lines.allocate(&xr_state, app.gfx.clone())?, ]; let watch_id = overlays.get_by_name(WATCH_NAME).unwrap().state.id; // want panic @@ -418,9 +418,9 @@ pub fn openxr_run( o.data.cur_visible = true; } - lines.render(app.graphics.clone(), &mut buffers)?; + lines.render(&app, &mut buffers)?; - let future = buffers.execute_now(app.graphics.graphics_queue.clone())?; + let future = buffers.execute_now(app.gfx.queue_gfx.clone())?; if let Some(mut future) = future { if let Err(e) = future.flush() { return Err(BackendError::Fatal(e.into())); diff --git a/src/backend/openxr/overlay.rs b/src/backend/openxr/overlay.rs index 6135c9d..ff153b0 100644 --- a/src/backend/openxr/overlay.rs +++ b/src/backend/openxr/overlay.rs @@ -42,7 +42,7 @@ impl OverlayData { let extent = meta.extent; self.data.swapchain = Some(create_swapchain( xr, - app.graphics.clone(), + app.gfx.clone(), extent, SwapchainOpts::new(), )?); diff --git a/src/backend/openxr/skybox.rs b/src/backend/openxr/skybox.rs index 24b8164..b5848fe 100644 --- a/src/backend/openxr/skybox.rs +++ b/src/backend/openxr/skybox.rs @@ -5,16 +5,17 @@ use std::{ }; use glam::{Quat, Vec3A}; -use openxr::{self as xr, CompositionLayerFlags}; +use openxr as xr; use vulkano::{ - command_buffer::CommandBufferUsage, image::view::ImageView, - pipeline::graphics::color_blend::AttachmentBlend, + command_buffer::CommandBufferUsage, + image::view::ImageView, + pipeline::graphics::{color_blend::AttachmentBlend, input_assembly::PrimitiveTopology}, }; use crate::{ backend::openxr::{helpers::translation_rotation_to_posef, swapchain::SwapchainOpts}, config_io, - graphics::{dds::WlxCommandBufferDds, CommandBuffers}, + graphics::{dds::WlxCommandBufferDds, CommandBuffers, ExtentExt}, state::AppState, }; @@ -31,10 +32,9 @@ pub(super) struct Skybox { impl Skybox { pub fn new(app: &AppState) -> anyhow::Result { - let mut command_buffer = app.graphics.create_uploads_command_buffer( - app.graphics.transfer_queue.clone(), - CommandBufferUsage::OneTimeSubmit, - )?; + let mut command_buffer = app + .gfx + .create_xfer_command_buffer(CommandBufferUsage::OneTimeSubmit)?; let mut maybe_image = None; @@ -51,7 +51,7 @@ impl Skybox { ); break 'custom_tex; }; - match command_buffer.texture2d_dds(f) { + match command_buffer.upload_image_dds(f) { Ok(image) => { maybe_image = Some(image); } @@ -67,7 +67,7 @@ impl Skybox { if maybe_image.is_none() { let p = include_bytes!("../../res/table_mountain_2.dds"); - maybe_image = Some(command_buffer.texture2d_dds(p.as_slice())?); + maybe_image = Some(command_buffer.upload_image_dds(p.as_slice())?); } command_buffer.build_and_execute_now()?; @@ -92,30 +92,31 @@ impl Skybox { } let opts = SwapchainOpts::new().immutable(); - let Ok(shaders) = app.graphics.shared_shaders.read() else { - anyhow::bail!("Failed to lock shared shaders for reading"); - }; - let extent = self.view.image().extent(); - let mut swapchain = create_swapchain(xr, app.graphics.clone(), extent, opts)?; + let mut swapchain = create_swapchain(xr, app.gfx.clone(), extent, opts)?; let tgt = swapchain.acquire_wait_image()?; - let pipeline = app.graphics.create_pipeline( - shaders.get("vert_common").unwrap().clone(), // want panic - shaders.get("frag_srgb").unwrap().clone(), // want panic - app.graphics.native_format, + let pipeline = app.gfx.create_pipeline( + app.gfx_extras.shaders.get("vert_quad").unwrap().clone(), // want panic + app.gfx_extras.shaders.get("frag_srgb").unwrap().clone(), // want panic + app.gfx.surface_format, None, + PrimitiveTopology::TriangleStrip, + false, )?; - let set0 = - pipeline.uniform_sampler(0, self.view.clone(), app.graphics.texture_filtering)?; - - let set1 = pipeline.uniform_buffer(1, vec![1f32])?; - - let pass = pipeline.create_pass_for_target(tgt.clone(), vec![set0, set1])?; + let set0 = pipeline.uniform_sampler(0, self.view.clone(), app.gfx.texture_filter)?; + let set1 = pipeline.uniform_buffer_upload(1, vec![1f32])?; + let pass = pipeline.create_pass( + tgt.extent_f32(), + app.gfx_extras.quad_verts.clone(), + 0..4, + 0..1, + vec![set0, set1], + )?; let mut cmd_buffer = app - .graphics - .create_command_buffer(CommandBufferUsage::OneTimeSubmit)?; + .gfx + .create_gfx_command_buffer(CommandBufferUsage::OneTimeSubmit)?; cmd_buffer.begin_rendering(tgt)?; cmd_buffer.run_ref(&pass)?; cmd_buffer.end_rendering()?; @@ -135,30 +136,35 @@ impl Skybox { if self.grid.is_some() { return Ok(()); } - let Ok(shaders) = app.graphics.shared_shaders.read() else { - anyhow::bail!("Failed to lock shared shaders for reading"); - }; let extent = [1024, 1024, 1]; let mut swapchain = create_swapchain( xr, - app.graphics.clone(), + app.gfx.clone(), extent, SwapchainOpts::new().immutable(), )?; - let pipeline = app.graphics.create_pipeline( - shaders.get("vert_common").unwrap().clone(), // want panic - shaders.get("frag_grid").unwrap().clone(), // want panic - app.graphics.native_format, + let pipeline = app.gfx.create_pipeline( + app.gfx_extras.shaders.get("vert_quad").unwrap().clone(), // want panic + app.gfx_extras.shaders.get("frag_grid").unwrap().clone(), // want panic + app.gfx.surface_format, Some(AttachmentBlend::alpha()), + PrimitiveTopology::TriangleStrip, + false, )?; let tgt = swapchain.acquire_wait_image()?; - let pass = pipeline.create_pass_for_target(tgt.clone(), vec![])?; + let pass = pipeline.create_pass( + tgt.extent_f32(), + app.gfx_extras.quad_verts.clone(), + 0..4, + 0..1, + vec![], + )?; let mut cmd_buffer = app - .graphics - .create_command_buffer(CommandBufferUsage::OneTimeSubmit)?; + .gfx + .create_gfx_command_buffer(CommandBufferUsage::OneTimeSubmit)?; cmd_buffer.begin_rendering(tgt)?; cmd_buffer.run_ref(&pass)?; cmd_buffer.end_rendering()?; @@ -206,7 +212,7 @@ impl Skybox { self.sky.as_mut().unwrap().ensure_image_released()?; let sky = xr::CompositionLayerEquirect2KHR::new() - .layer_flags(CompositionLayerFlags::BLEND_TEXTURE_SOURCE_ALPHA) + .layer_flags(xr::CompositionLayerFlags::BLEND_TEXTURE_SOURCE_ALPHA) .pose(pose) .radius(10.0) .sub_image(self.sky.as_ref().unwrap().get_subimage()) @@ -218,7 +224,7 @@ impl Skybox { self.grid.as_mut().unwrap().ensure_image_released()?; let grid = xr::CompositionLayerQuad::new() - .layer_flags(CompositionLayerFlags::BLEND_TEXTURE_SOURCE_ALPHA) + .layer_flags(xr::CompositionLayerFlags::BLEND_TEXTURE_SOURCE_ALPHA) .pose(*GRID_POSE) .size(xr::Extent2Df { width: 10.0, diff --git a/src/backend/openxr/swapchain.rs b/src/backend/openxr/swapchain.rs index f0c3e5a..0b59819 100644 --- a/src/backend/openxr/swapchain.rs +++ b/src/backend/openxr/swapchain.rs @@ -8,8 +8,7 @@ use vulkano::{ image::{sys::RawImage, view::ImageView, ImageCreateInfo, ImageUsage}, Handle, }; - -use crate::graphics::WlxGraphics; +use wgui::gfx::WGfx; use super::XrState; @@ -30,7 +29,7 @@ impl SwapchainOpts { pub(super) fn create_swapchain( xr: &XrState, - graphics: Arc, + gfx: Arc, extent: [u32; 3], opts: SwapchainOpts, ) -> anyhow::Result { @@ -43,7 +42,7 @@ pub(super) fn create_swapchain( let swapchain = xr.session.create_swapchain(&xr::SwapchainCreateInfo { create_flags, usage_flags: xr::SwapchainUsageFlags::COLOR_ATTACHMENT | xr::SwapchainUsageFlags::SAMPLED, - format: graphics.native_format as _, + format: gfx.surface_format as _, sample_count: 1, width: extent[0], height: extent[1], @@ -60,10 +59,10 @@ pub(super) fn create_swapchain( // thanks @yshui let raw_image = unsafe { RawImage::from_handle_borrowed( - graphics.device.clone(), + gfx.device.clone(), vk_image, ImageCreateInfo { - format: graphics.native_format as _, + format: gfx.surface_format as _, extent, usage: ImageUsage::COLOR_ATTACHMENT, ..Default::default() diff --git a/src/backend/overlay.rs b/src/backend/overlay.rs index d96614e..5cde4f0 100644 --- a/src/backend/overlay.rs +++ b/src/backend/overlay.rs @@ -301,8 +301,11 @@ pub struct FrameMeta { } pub enum ShouldRender { + /// The overlay is dirty and needs to be rendered. Should, + /// The overlay is not dirty but is ready to be rendered. Can, + /// The overlay is not ready to be rendered. Unable, } diff --git a/src/backend/task.rs b/src/backend/task.rs index 2f3c60f..62c082a 100644 --- a/src/backend/task.rs +++ b/src/backend/task.rs @@ -10,7 +10,7 @@ use serde::Deserialize; use crate::state::AppState; #[cfg(feature = "wayvr")] -use crate::gui::modular::button::WayVRAction; +use crate::backend::wayvr::WayVRAction; use super::{ common::OverlaySelector, diff --git a/src/backend/uidev/mod.rs b/src/backend/uidev/mod.rs deleted file mode 100644 index 5b62804..0000000 --- a/src/backend/uidev/mod.rs +++ /dev/null @@ -1,289 +0,0 @@ -use std::sync::Arc; - -use vulkano::{ - image::{view::ImageView, ImageUsage}, - swapchain::{ - acquire_next_image, Surface, SurfaceInfo, Swapchain, SwapchainCreateInfo, - SwapchainPresentInfo, - }, - sync::GpuFuture, - Validated, VulkanError, -}; -use winit::{ - dpi::LogicalSize, - event::{Event, WindowEvent}, - event_loop::ControlFlow, - window::Window, -}; - -use crate::{ - config::load_custom_ui, - config_io, - graphics::{CommandBuffers, WlxGraphics}, - gui::{ - canvas::Canvas, - modular::{modular_canvas, ModularData}, - }, - hid::USE_UINPUT, - state::{AppState, ScreenMeta}, -}; - -use super::{ - input::{TrackedDevice, TrackedDeviceRole}, - overlay::{OverlayID, OverlayRenderer}, -}; - -static LAST_SIZE: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0); - -struct PreviewState { - canvas: Canvas<(), ModularData>, - swapchain: Arc, - images: Vec>, -} - -impl PreviewState { - fn new( - state: &mut AppState, - surface: Arc, - window: Arc, - panel_name: &str, - ) -> anyhow::Result { - let config = load_custom_ui(panel_name)?; - - let last_size = { - let size_u64 = LAST_SIZE.load(std::sync::atomic::Ordering::Relaxed); - [size_u64 as u32, (size_u64 >> 32) as u32] - }; - - if last_size != config.size { - let logical_size = LogicalSize::new(config.size[0], config.size[1]); - let _ = window.request_inner_size(logical_size); - window.set_min_inner_size(Some(logical_size)); - window.set_max_inner_size(Some(logical_size)); - LAST_SIZE.store( - ((config.size[1] as u64) << 32) | config.size[0] as u64, - std::sync::atomic::Ordering::Relaxed, - ); - } - - let inner_size = window.inner_size(); - let swapchain_size = [inner_size.width, inner_size.height]; - let (swapchain, images) = create_swapchain(&state.graphics, surface, swapchain_size)?; - - let mut canvas = modular_canvas(config.size, &config.elements, state)?; - canvas.init(state)?; - - Ok(Self { - canvas, - swapchain, - images, - }) - } -} - -#[allow(clippy::too_many_lines)] -pub fn uidev_run(panel_name: &str) -> anyhow::Result<()> { - let (graphics, event_loop, window, surface) = WlxGraphics::new_window()?; - window.set_resizable(false); - window.set_title("WlxOverlay UI Preview"); - - USE_UINPUT.store(false, std::sync::atomic::Ordering::Relaxed); - - let mut state = AppState::from_graphics(graphics.clone())?; - add_dummy_devices(&mut state); - add_dummy_screens(&mut state); - - let mut preview = Some(PreviewState::new( - &mut state, - surface.clone(), - window.clone(), - panel_name, - )?); - - let watch_path = config_io::get_config_root().join(format!("{panel_name}.yaml")); - let mut path_last_modified = watch_path.metadata()?.modified()?; - let mut recreate = false; - let mut last_draw = std::time::Instant::now(); - - #[allow(deprecated)] - event_loop.run(move |event, elwt| { - elwt.set_control_flow(ControlFlow::Poll); - - match event { - Event::WindowEvent { - event: WindowEvent::CloseRequested, - .. - } => { - elwt.exit(); - } - Event::WindowEvent { - event: WindowEvent::Resized(_), - .. - } => { - recreate = true; - } - Event::WindowEvent { - event: WindowEvent::RedrawRequested, - .. - } => { - let new_modified = watch_path.metadata().unwrap().modified().unwrap(); - if new_modified > path_last_modified { - recreate = true; - path_last_modified = new_modified; - } - - if recreate { - drop(preview.take()); - preview = Some( - PreviewState::new(&mut state, surface.clone(), window.clone(), panel_name) - .unwrap(), - ); - recreate = false; - window.request_redraw(); - } - - { - let preview = preview.as_mut().unwrap(); - let (image_index, _, acquire_future) = - match acquire_next_image(preview.swapchain.clone(), None) - .map_err(Validated::unwrap) - { - Ok(r) => r, - Err(VulkanError::OutOfDate) => { - recreate = true; - return; - } - Err(e) => panic!("failed to acquire next image: {e}"), - }; - - let mut canvas_cmd_buf = CommandBuffers::default(); - let tgt = preview.images[image_index as usize].clone(); - - if let Err(e) = preview - .canvas - .render(&mut state, tgt, &mut canvas_cmd_buf, 1.0) - { - log::error!("failed to render canvas: {e}"); - window.request_redraw(); - } - - last_draw = std::time::Instant::now(); - - canvas_cmd_buf - .execute_after( - state.graphics.graphics_queue.clone(), - Box::new(acquire_future), - ) - .unwrap() - .then_swapchain_present( - graphics.graphics_queue.clone(), - SwapchainPresentInfo::swapchain_image_index( - preview.swapchain.clone(), - image_index, - ), - ) - .then_signal_fence_and_flush() - .unwrap() - .wait(None) - .unwrap(); - } - } - Event::AboutToWait => { - if last_draw.elapsed().as_millis() > 100 { - window.request_redraw(); - } - } - _ => (), - } - })?; - - Ok(()) -} - -fn create_swapchain( - graphics: &WlxGraphics, - surface: Arc, - extent: [u32; 2], -) -> anyhow::Result<(Arc, Vec>)> { - let surface_capabilities = graphics - .device - .physical_device() - .surface_capabilities(&surface, SurfaceInfo::default()) - .unwrap(); // want panic - - let (swapchain, images) = Swapchain::new( - graphics.device.clone(), - surface, - SwapchainCreateInfo { - min_image_count: surface_capabilities.min_image_count.max(2), - image_format: graphics.native_format, - image_extent: extent, - image_usage: ImageUsage::COLOR_ATTACHMENT, - composite_alpha: surface_capabilities - .supported_composite_alpha - .into_iter() - .next() - .unwrap(), // want panic - ..Default::default() - }, - )?; - - let image_views = images - .into_iter() - // want panic - .map(|image| ImageView::new_default(image).unwrap()) - .collect::>(); - - Ok((swapchain, image_views)) -} - -fn add_dummy_devices(app: &mut AppState) { - app.input_state.devices.push(TrackedDevice { - role: TrackedDeviceRole::Hmd, - soc: Some(0.42), - charging: true, - }); - app.input_state.devices.push(TrackedDevice { - role: TrackedDeviceRole::LeftHand, - soc: Some(0.72), - charging: false, - }); - app.input_state.devices.push(TrackedDevice { - role: TrackedDeviceRole::RightHand, - soc: Some(0.73), - charging: false, - }); - app.input_state.devices.push(TrackedDevice { - role: TrackedDeviceRole::Tracker, - soc: Some(0.65), - charging: false, - }); - app.input_state.devices.push(TrackedDevice { - role: TrackedDeviceRole::Tracker, - soc: Some(0.67), - charging: false, - }); - app.input_state.devices.push(TrackedDevice { - role: TrackedDeviceRole::Tracker, - soc: Some(0.69), - charging: false, - }); -} - -fn add_dummy_screens(app: &mut AppState) { - app.screens.push(ScreenMeta { - name: "HDMI-A-1".into(), - id: OverlayID(0), - native_handle: 0, - }); - app.screens.push(ScreenMeta { - name: "DP-2".into(), - id: OverlayID(0), - native_handle: 0, - }); - app.screens.push(ScreenMeta { - name: "DP-3".into(), - id: OverlayID(0), - native_handle: 0, - }); -} diff --git a/src/backend/wayvr/mod.rs b/src/backend/wayvr/mod.rs index 4522c7a..bf87ef5 100644 --- a/src/backend/wayvr/mod.rs +++ b/src/backend/wayvr/mod.rs @@ -14,6 +14,7 @@ use comp::Application; use display::{Display, DisplayInitParams, DisplayVec}; use event_queue::SyncEventQueue; use process::ProcessVec; +use serde::Deserialize; use server_ipc::WayVRServer; use smallvec::SmallVec; use smithay::{ @@ -36,6 +37,7 @@ use std::{ cell::RefCell, collections::{HashMap, HashSet}, rc::Rc, + sync::Arc, }; use time::get_millis; use wayvr_ipc::{packet_client, packet_server}; @@ -717,3 +719,22 @@ impl WayVRState { Ok(handle) } } + +#[derive(Deserialize, Clone)] +pub enum WayVRDisplayClickAction { + ToggleVisibility, + Reset, +} + +#[derive(Deserialize, Clone)] +pub enum WayVRAction { + AppClick { + catalog_name: Arc, + app_name: Arc, + }, + DisplayClick { + display_name: Arc, + action: WayVRDisplayClickAction, + }, + ToggleDashboard, +} diff --git a/src/config.rs b/src/config.rs index b1d5de2..d45bbf5 100644 --- a/src/config.rs +++ b/src/config.rs @@ -2,11 +2,9 @@ use std::path::PathBuf; use std::sync::Arc; use crate::config_io; -use crate::gui::modular::ModularUiConfig; use crate::overlays::toast::DisplayMethod; use crate::overlays::toast::ToastTopic; use crate::state::LeftRight; -use anyhow::bail; use chrono::Offset; use config::Config; use config::File; @@ -384,14 +382,6 @@ where panic!("No usable config found."); } -pub fn load_custom_ui(name: &str) -> anyhow::Result { - let filename = format!("{name}.yaml"); - let Some(yaml_data) = config_io::load(&filename) else { - bail!("Could not read file at {}", &filename); - }; - Ok(serde_yaml::from_str(&yaml_data)?) -} - pub fn load_config_with_conf_d( root_config_filename: &str, ctype: config_io::ConfigRoot, diff --git a/src/config_io.rs b/src/config_io.rs index b976411..9ee03f4 100644 --- a/src/config_io.rs +++ b/src/config_io.rs @@ -10,8 +10,7 @@ pub enum ConfigRoot { const FALLBACK_CONFIG_PATH: &str = "/tmp/wlxoverlay"; static CONFIG_ROOT_PATH: LazyLock = LazyLock::new(|| { - if let Ok(xdg_dirs) = xdg::BaseDirectories::new() { - let mut dir = xdg_dirs.get_config_home(); + if let Some(mut dir) = xdg::BaseDirectories::new().get_config_home() { dir.push("wlxoverlay"); return dir; } diff --git a/src/config_wayvr.rs b/src/config_wayvr.rs index ae038ae..a113375 100644 --- a/src/config_wayvr.rs +++ b/src/config_wayvr.rs @@ -14,11 +14,10 @@ use crate::{ backend::{ overlay::Positioning, task::{TaskContainer, TaskType}, - wayvr, + wayvr::{self, WayVRAction}, }, config::load_config_with_conf_d, config_io, - gui::modular::button::WayVRAction, overlays::wayvr::{executable_exists_in_path, WayVRData}, }; diff --git a/src/graphics/dds.rs b/src/graphics/dds.rs index 6494424..963104f 100644 --- a/src/graphics/dds.rs +++ b/src/graphics/dds.rs @@ -8,17 +8,16 @@ use vulkano::{ memory::allocator::{AllocationCreateInfo, MemoryTypeFilter}, DeviceSize, }; - -use super::WlxUploadsBuffer; +use wgui::gfx::cmd::XferCommandBuffer; pub trait WlxCommandBufferDds { - fn texture2d_dds(&mut self, r: R) -> anyhow::Result> + fn upload_image_dds(&mut self, r: R) -> anyhow::Result> where R: Read; } -impl WlxCommandBufferDds for WlxUploadsBuffer { - fn texture2d_dds(&mut self, r: R) -> anyhow::Result> +impl WlxCommandBufferDds for XferCommandBuffer { + fn upload_image_dds(&mut self, r: R) -> anyhow::Result> where R: Read, { diff --git a/src/graphics/dmabuf.rs b/src/graphics/dmabuf.rs index 52df1ee..458f0f5 100644 --- a/src/graphics/dmabuf.rs +++ b/src/graphics/dmabuf.rs @@ -1,12 +1,142 @@ -use std::{mem::MaybeUninit, sync::Arc}; +use std::{ + mem::MaybeUninit, + os::fd::{FromRawFd, IntoRawFd}, + sync::Arc, +}; use smallvec::SmallVec; use vulkano::{ device::Device, - image::{sys::RawImage, ImageCreateInfo, SubresourceLayout}, + format::Format, + image::{sys::RawImage, Image, ImageCreateInfo, ImageTiling, ImageUsage, SubresourceLayout}, + memory::{ + allocator::{MemoryAllocator, MemoryTypeFilter}, + DedicatedAllocation, DeviceMemory, ExternalMemoryHandleType, ExternalMemoryHandleTypes, + MemoryAllocateInfo, MemoryImportInfo, MemoryPropertyFlags, ResourceMemory, + }, sync::Sharing, VulkanError, VulkanObject, }; +use wgui::gfx::WGfx; +use wlx_capture::frame::{ + DmabufFrame, DrmFormat, FourCC, DRM_FORMAT_ABGR2101010, DRM_FORMAT_ABGR8888, + DRM_FORMAT_ARGB8888, DRM_FORMAT_XBGR2101010, DRM_FORMAT_XBGR8888, DRM_FORMAT_XRGB8888, +}; + +pub const DRM_FORMAT_MOD_INVALID: u64 = 0xff_ffff_ffff_ffff; + +pub trait WGfxDmabuf { + fn dmabuf_texture_ex( + &self, + frame: DmabufFrame, + tiling: ImageTiling, + layouts: Vec, + modifiers: &[u64], + ) -> anyhow::Result>; + + fn dmabuf_texture(&self, frame: DmabufFrame) -> anyhow::Result>; +} + +impl WGfxDmabuf for WGfx { + fn dmabuf_texture_ex( + &self, + frame: DmabufFrame, + tiling: ImageTiling, + layouts: Vec, + modifiers: &[u64], + ) -> anyhow::Result> { + let extent = [frame.format.width, frame.format.height, 1]; + let format = fourcc_to_vk(frame.format.fourcc)?; + + let image = unsafe { + create_dmabuf_image( + self.device.clone(), + ImageCreateInfo { + format, + extent, + usage: ImageUsage::SAMPLED, + external_memory_handle_types: ExternalMemoryHandleTypes::DMA_BUF, + tiling, + drm_format_modifiers: modifiers.to_owned(), + drm_format_modifier_plane_layouts: layouts, + ..Default::default() + }, + )? + }; + + let requirements = image.memory_requirements()[0]; + let memory_type_index = self + .memory_allocator + .find_memory_type_index( + requirements.memory_type_bits, + MemoryTypeFilter { + required_flags: MemoryPropertyFlags::DEVICE_LOCAL, + ..Default::default() + }, + ) + .ok_or_else(|| anyhow::anyhow!("failed to get memory type index"))?; + + debug_assert!(self.device.enabled_extensions().khr_external_memory_fd); + debug_assert!(self.device.enabled_extensions().khr_external_memory); + debug_assert!(self.device.enabled_extensions().ext_external_memory_dma_buf); + + // only do the 1st + unsafe { + let Some(fd) = frame.planes[0].fd else { + anyhow::bail!("DMA-buf plane has no FD"); + }; + + let file = std::fs::File::from_raw_fd(fd); + let new_file = file.try_clone()?; + let _ = file.into_raw_fd(); + + let memory = DeviceMemory::allocate_unchecked( + self.device.clone(), + MemoryAllocateInfo { + allocation_size: requirements.layout.size(), + memory_type_index, + dedicated_allocation: Some(DedicatedAllocation::Image(&image)), + ..Default::default() + }, + Some(MemoryImportInfo::Fd { + file: new_file, + handle_type: ExternalMemoryHandleType::DmaBuf, + }), + )?; + + let mem_alloc = ResourceMemory::new_dedicated(memory); + match image.bind_memory_unchecked([mem_alloc]) { + Ok(image) => Ok(Arc::new(image)), + Err(e) => { + anyhow::bail!("Failed to bind memory to image: {}", e.0); + } + } + } + } + + fn dmabuf_texture(&self, frame: DmabufFrame) -> anyhow::Result> { + let mut modifiers: Vec = vec![]; + let mut tiling: ImageTiling = ImageTiling::Optimal; + let mut layouts: Vec = vec![]; + + if frame.format.modifier != DRM_FORMAT_MOD_INVALID { + (0..frame.num_planes).for_each(|i| { + let plane = &frame.planes[i]; + layouts.push(SubresourceLayout { + offset: plane.offset.into(), + size: 0, + row_pitch: plane.stride as _, + array_pitch: None, + depth_pitch: None, + }); + modifiers.push(frame.format.modifier); + }); + tiling = ImageTiling::DrmFormatModifier; + } + + self.dmabuf_texture_ex(frame, tiling, layouts, &modifiers) + } +} #[allow(clippy::all, clippy::pedantic)] pub(super) unsafe fn create_dmabuf_image( @@ -170,3 +300,51 @@ pub(super) unsafe fn create_dmabuf_image( RawImage::from_handle(device, handle, create_info) } + +pub fn get_drm_formats(device: Arc) -> Vec { + let possible_formats = [ + DRM_FORMAT_ABGR8888.into(), + DRM_FORMAT_XBGR8888.into(), + DRM_FORMAT_ARGB8888.into(), + DRM_FORMAT_XRGB8888.into(), + DRM_FORMAT_ABGR2101010.into(), + DRM_FORMAT_XBGR2101010.into(), + ]; + + let mut final_formats = vec![]; + + for &f in &possible_formats { + let Ok(vk_fmt) = fourcc_to_vk(f) else { + continue; + }; + let Ok(props) = device.physical_device().format_properties(vk_fmt) else { + continue; + }; + let mut fmt = DrmFormat { + fourcc: f, + modifiers: props + .drm_format_modifier_properties + .iter() + // important bit: only allow single-plane + .filter(|m| m.drm_format_modifier_plane_count == 1) + .map(|m| m.drm_format_modifier) + .collect(), + }; + fmt.modifiers.push(DRM_FORMAT_MOD_INVALID); // implicit modifiers support + final_formats.push(fmt); + } + log::debug!("Supported DRM formats:"); + for f in &final_formats { + log::debug!(" {} {:?}", f.fourcc, f.modifiers); + } + final_formats +} + +pub fn fourcc_to_vk(fourcc: FourCC) -> anyhow::Result { + match fourcc.value { + DRM_FORMAT_ABGR8888 | DRM_FORMAT_XBGR8888 => Ok(Format::R8G8B8A8_UNORM), + DRM_FORMAT_ARGB8888 | DRM_FORMAT_XRGB8888 => Ok(Format::B8G8R8A8_UNORM), + DRM_FORMAT_ABGR2101010 | DRM_FORMAT_XBGR2101010 => Ok(Format::A2B10G10R10_UNORM_PACK32), + _ => anyhow::bail!("Unsupported format {}", fourcc), + } +} diff --git a/src/graphics/mod.rs b/src/graphics/mod.rs index f6c85ea..1d5125c 100644 --- a/src/graphics/mod.rs +++ b/src/graphics/mod.rs @@ -3,94 +3,51 @@ pub mod dmabuf; use std::{ collections::HashMap, - os::fd::{FromRawFd, IntoRawFd}, - slice::Iter, - sync::{Arc, OnceLock, RwLock}, + sync::{Arc, OnceLock}, }; -use anyhow::{anyhow, bail}; -use ash::vk::SubmitInfo; -use dmabuf::create_dmabuf_image; -use smallvec::smallvec; +use glam::{vec2, Vec2}; +use vulkano::{ + buffer::{BufferCreateInfo, BufferUsage}, + command_buffer::{PrimaryAutoCommandBuffer, PrimaryCommandBufferAbstract}, + image::view::ImageView, + memory::allocator::{AllocationCreateInfo, MemoryTypeFilter}, + sync::GpuFuture, +}; +use wgui::gfx::WGfx; #[cfg(feature = "openvr")] use vulkano::instance::InstanceCreateFlags; +use wlx_capture::frame::DrmFormat; + +use crate::shaders::{frag_color, frag_grid, frag_screen, frag_srgb, vert_quad}; #[cfg(feature = "openxr")] use {ash::vk, std::os::raw::c_void}; use vulkano::{ - buffer::{ - allocator::{SubbufferAllocator, SubbufferAllocatorCreateInfo}, - Buffer, BufferContents, BufferCreateInfo, BufferUsage, IndexBuffer, Subbuffer, - }, - command_buffer::{ - allocator::{StandardCommandBufferAllocator, StandardCommandBufferAllocatorCreateInfo}, - AutoCommandBufferBuilder, CommandBufferBeginInfo, CommandBufferExecFuture, - CommandBufferInheritanceInfo, CommandBufferInheritanceRenderPassType, - CommandBufferInheritanceRenderingInfo, CommandBufferLevel, CommandBufferUsage, - CopyBufferToImageInfo, PrimaryAutoCommandBuffer, PrimaryCommandBufferAbstract, - RecordingCommandBuffer, RenderingAttachmentInfo, RenderingInfo, SecondaryAutoCommandBuffer, - SubpassContents, - }, - descriptor_set::{ - allocator::StandardDescriptorSetAllocator, DescriptorSet, WriteDescriptorSet, - }, + self, + buffer::{Buffer, BufferContents, IndexBuffer, Subbuffer}, device::{ physical::{PhysicalDevice, PhysicalDeviceType}, Device, DeviceCreateInfo, DeviceExtensions, DeviceFeatures, Queue, QueueCreateInfo, QueueFlags, }, format::Format, - image::{ - sampler::{Filter, Sampler, SamplerAddressMode, SamplerCreateInfo}, - view::ImageView, - Image, ImageCreateInfo, ImageLayout, ImageTiling, ImageType, ImageUsage, SubresourceLayout, - }, instance::{Instance, InstanceCreateInfo, InstanceExtensions}, - memory::{ - allocator::{ - AllocationCreateInfo, GenericMemoryAllocatorCreateInfo, MemoryAllocator, - MemoryTypeFilter, StandardMemoryAllocator, - }, - DedicatedAllocation, DeviceMemory, ExternalMemoryHandleType, ExternalMemoryHandleTypes, - MemoryAllocateInfo, MemoryImportInfo, MemoryPropertyFlags, ResourceMemory, + pipeline::graphics::{ + color_blend::{AttachmentBlend, BlendFactor, BlendOp}, + vertex_input::Vertex, }, - pipeline::{ - graphics::{ - color_blend::{ - AttachmentBlend, BlendFactor, BlendOp, ColorBlendAttachmentState, ColorBlendState, - }, - input_assembly::InputAssemblyState, - multisample::MultisampleState, - rasterization::RasterizationState, - subpass::PipelineRenderingCreateInfo, - vertex_input::{Vertex, VertexDefinition}, - viewport::{Viewport, ViewportState}, - GraphicsPipelineCreateInfo, - }, - layout::PipelineDescriptorSetLayoutCreateInfo, - DynamicState, GraphicsPipeline, Pipeline, PipelineBindPoint, PipelineLayout, - }, - render_pass::{AttachmentLoadOp, AttachmentStoreOp}, shader::ShaderModule, - sync::{ - fence::Fence, future::NowFuture, AccessFlags, DependencyInfo, GpuFuture, - ImageMemoryBarrier, PipelineStages, - }, - DeviceSize, VulkanObject, + VulkanObject, }; -use wlx_capture::frame::{ - DmabufFrame, DrmFormat, FourCC, DRM_FORMAT_ABGR2101010, DRM_FORMAT_ABGR8888, - DRM_FORMAT_ARGB8888, DRM_FORMAT_XBGR2101010, DRM_FORMAT_XBGR8888, DRM_FORMAT_XRGB8888, -}; +use dmabuf::get_drm_formats; pub type Vert2Buf = Subbuffer<[Vert2Uv]>; pub type IndexBuf = IndexBuffer; -pub const DRM_FORMAT_MOD_INVALID: u64 = 0xff_ffff_ffff_ffff; - #[repr(C)] #[derive(BufferContents, Vertex, Copy, Clone, Debug)] pub struct Vert2Uv { @@ -111,25 +68,73 @@ pub const BLEND_ALPHA: AttachmentBlend = AttachmentBlend { alpha_blend_op: BlendOp::Max, }; -pub struct WlxGraphics { - pub instance: Arc, - pub device: Arc, - pub graphics_queue: Arc, - pub transfer_queue: Arc, - pub capture_queue: Option>, - - pub native_format: Format, - pub texture_filtering: Filter, - - pub memory_allocator: Arc, - pub command_buffer_allocator: Arc, - pub descriptor_set_allocator: Arc, - - pub quad_verts: Vert2Buf, - pub quad_indices: IndexBuf, - - pub shared_shaders: RwLock>>, +pub struct WGfxExtras { + pub shaders: HashMap<&'static str, Arc>, pub drm_formats: Vec, + pub queue_capture: Option>, + pub quad_verts: Vert2Buf, +} + +impl WGfxExtras { + pub fn new(gfx: &WGfx, queue_capture: Option>) -> anyhow::Result { + let mut shaders = HashMap::new(); + + let shader = vert_quad::load(gfx.device.clone())?; + shaders.insert("vert_quad", shader); + + let shader = frag_color::load(gfx.device.clone())?; + shaders.insert("frag_color", shader); + + let shader = frag_srgb::load(gfx.device.clone())?; + shaders.insert("frag_srgb", shader); + + let shader = frag_grid::load(gfx.device.clone())?; + shaders.insert("frag_grid", shader); + + let shader = frag_screen::load(gfx.device.clone())?; + shaders.insert("frag_screen", shader); + + let drm_formats = get_drm_formats(gfx.device.clone()); + + let vertices = [ + Vert2Uv { + in_pos: [0., 0.], + in_uv: [0., 0.], + }, + Vert2Uv { + in_pos: [1., 0.], + in_uv: [1., 0.], + }, + Vert2Uv { + in_pos: [0., 1.], + in_uv: [0., 1.], + }, + Vert2Uv { + in_pos: [1., 1.], + in_uv: [1., 1.], + }, + ]; + let quad_verts = Buffer::from_iter( + gfx.memory_allocator.clone(), + BufferCreateInfo { + usage: BufferUsage::VERTEX_BUFFER, + ..Default::default() + }, + AllocationCreateInfo { + memory_type_filter: MemoryTypeFilter::PREFER_DEVICE + | MemoryTypeFilter::HOST_SEQUENTIAL_WRITE, + ..Default::default() + }, + vertices.into_iter(), + )?; + + Ok(Self { + shaders, + drm_formats, + queue_capture, + quad_verts, + }) + } } const fn get_dmabuf_extensions() -> DeviceExtensions { @@ -157,1325 +162,360 @@ unsafe extern "system" fn get_instance_proc_addr( library.get_instance_proc_addr(instance, name) } -impl WlxGraphics { - #[cfg(feature = "openxr")] - #[allow(clippy::too_many_lines)] - pub fn new_openxr( - xr_instance: openxr::Instance, - system: openxr::SystemId, - ) -> anyhow::Result> { - use std::ffi::{self, CString}; - - use vulkano::{ - descriptor_set::allocator::StandardDescriptorSetAllocatorCreateInfo, Handle, Version, - }; - - let instance_extensions = InstanceExtensions { - khr_get_physical_device_properties2: true, - ..InstanceExtensions::empty() - }; - - let instance_extensions_raw = instance_extensions - .into_iter() - .filter_map(|(name, enabled)| { - if enabled { - Some(ffi::CString::new(name).unwrap().into_raw().cast_const()) - // want panic - } else { - None - } - }) - .collect::>(); - - let vk_target_version = vk::make_api_version(0, 1, 3, 0); - let target_version = vulkano::Version::V1_3; - let library = get_vulkan_library(); - - let vk_app_info_raw = vk::ApplicationInfo::default() - .application_version(0) - .engine_version(0) - .api_version(vk_target_version); - - let instance = unsafe { - let vk_instance = xr_instance - .create_vulkan_instance( - system, - get_instance_proc_addr, - std::ptr::from_ref( - &vk::InstanceCreateInfo::default() - .application_info(&vk_app_info_raw) - .enabled_extension_names(&instance_extensions_raw), - ) - .cast(), - ) - .expect("XR error creating Vulkan instance") - .map_err(vk::Result::from_raw) - .expect("Vulkan error creating Vulkan instance"); - - Instance::from_handle( - library.clone(), - ash::vk::Instance::from_raw(vk_instance as _), - InstanceCreateInfo { - application_version: Version::major_minor(0, 0), - engine_version: Version::major_minor(0, 0), - max_api_version: Some(Version::V1_3), - enabled_extensions: instance_extensions, - ..Default::default() - }, - ) - }; - - let physical_device = unsafe { - PhysicalDevice::from_handle( - instance.clone(), - vk::PhysicalDevice::from_raw( - xr_instance.vulkan_graphics_device(system, instance.handle().as_raw() as _)? - as _, - ), - ) - }?; - - let vk_device_properties = physical_device.properties(); - assert!( - (vk_device_properties.api_version >= target_version), - "Vulkan physical device doesn't support Vulkan {target_version}" - ); - - log::info!( - "Using vkPhysicalDevice: {}", - physical_device.properties().device_name, - ); - - let queue_families = try_all_queue_families(physical_device.as_ref()) - .expect("vkPhysicalDevice does not have a GRAPHICS / TRANSFER queue."); - - let mut device_extensions = DeviceExtensions::empty(); - let dmabuf_extensions = get_dmabuf_extensions(); - - if physical_device - .supported_extensions() - .contains(&dmabuf_extensions) - { - device_extensions = device_extensions.union(&dmabuf_extensions); - device_extensions.ext_image_drm_format_modifier = physical_device - .supported_extensions() - .ext_image_drm_format_modifier; - } - - let texture_filtering = if physical_device.supported_extensions().ext_filter_cubic { - device_extensions.ext_filter_cubic = true; - Filter::Cubic - } else { - Filter::Linear - }; - - let device_extensions_raw = device_extensions - .into_iter() - .filter_map(|(name, enabled)| { - if enabled { - Some(ffi::CString::new(name).unwrap().into_raw().cast_const()) - // want panic - } else { - None - } - }) - .collect::>(); - - let features = DeviceFeatures { - dynamic_rendering: true, - ..Default::default() - }; - - let queue_create_infos = queue_families - .iter() - .map(|fam| { - vk::DeviceQueueCreateInfo::default() - .queue_family_index(fam.queue_family_index) - .queue_priorities(&fam.priorities) - }) - .collect::>(); - - let mut device_create_info = vk::DeviceCreateInfo::default() - .queue_create_infos(&queue_create_infos) - .enabled_extension_names(&device_extensions_raw); - - let mut dynamic_rendering = - vk::PhysicalDeviceDynamicRenderingFeatures::default().dynamic_rendering(true); - - dynamic_rendering.p_next = device_create_info.p_next.cast_mut(); - device_create_info.p_next = &raw mut dynamic_rendering as *const c_void; - - let (device, queues) = unsafe { - let vk_device = xr_instance - .create_vulkan_device( - system, - get_instance_proc_addr, - physical_device.handle().as_raw() as _, - (&raw const device_create_info).cast(), - ) - .expect("XR error creating Vulkan device") - .map_err(vk::Result::from_raw) - .expect("Vulkan error creating Vulkan device"); - - vulkano::device::Device::from_handle( - physical_device, - vk::Device::from_raw(vk_device as _), - DeviceCreateInfo { - queue_create_infos: queue_families - .iter() - .map(|fam| QueueCreateInfo { - queue_family_index: fam.queue_family_index, - queues: fam.priorities.clone(), - ..Default::default() - }) - .collect::>(), - enabled_extensions: device_extensions, - enabled_features: features, - ..Default::default() - }, - ) - }; - - log::debug!( - " DMA-buf supported: {}", - device.enabled_extensions().ext_external_memory_dma_buf - ); - log::debug!( - " DRM format modifiers supported: {}", - device.enabled_extensions().ext_image_drm_format_modifier - ); - - // Drop the CStrings - device_extensions_raw - .into_iter() - .for_each(|c_string| unsafe { - let _ = CString::from_raw(c_string.cast_mut()); - }); - - let (graphics_queue, transfer_queue, capture_queue) = unwrap_queues(queues.collect()); - - let memory_allocator = memory_allocator(device.clone()); - let command_buffer_allocator = Arc::new(StandardCommandBufferAllocator::new( - device.clone(), - StandardCommandBufferAllocatorCreateInfo { - secondary_buffer_count: 32, - ..Default::default() - }, - )); - let descriptor_set_allocator = Arc::new(StandardDescriptorSetAllocator::new( - device.clone(), - StandardDescriptorSetAllocatorCreateInfo::default(), - )); - - let (quad_verts, quad_indices) = Self::default_quad(memory_allocator.clone())?; - let drm_formats = Self::get_drm_formats(device.clone()); - - let me = Self { - instance, - device, - graphics_queue, - transfer_queue, - capture_queue, - native_format: Format::R8G8B8A8_SRGB, - texture_filtering, - memory_allocator, - command_buffer_allocator, - descriptor_set_allocator, - quad_indices, - quad_verts, - shared_shaders: RwLock::new(HashMap::new()), - drm_formats, - }; - - Ok(Arc::new(me)) - } - - #[allow(clippy::too_many_lines)] - #[cfg(feature = "openvr")] - pub fn new_openvr( - mut vk_instance_extensions: InstanceExtensions, - mut vk_device_extensions_fn: impl FnMut(&PhysicalDevice) -> DeviceExtensions, - ) -> anyhow::Result> { - //#[cfg(debug_assertions)] - //let layers = vec!["VK_LAYER_KHRONOS_validation".to_owned()]; - //#[cfg(not(debug_assertions))] - - use vulkano::descriptor_set::allocator::StandardDescriptorSetAllocatorCreateInfo; - - let layers = vec![]; - - log::debug!("Instance exts for runtime: {:?}", &vk_instance_extensions); - - vk_instance_extensions.khr_get_physical_device_properties2 = true; - - let instance = Instance::new( - get_vulkan_library().clone(), - InstanceCreateInfo { - flags: InstanceCreateFlags::ENUMERATE_PORTABILITY, - enabled_extensions: vk_instance_extensions, - enabled_layers: layers, - ..Default::default() - }, - )?; - - let dmabuf_extensions = get_dmabuf_extensions(); - - let (physical_device, my_extensions, queue_families) = instance - .enumerate_physical_devices()? - .filter_map(|p| { - let mut my_extensions = vk_device_extensions_fn(&p); - - if !p.supported_extensions().contains(&my_extensions) { - log::debug!( - "Not using {} due to missing extensions:", - p.properties().device_name, - ); - for (ext, missing) in p.supported_extensions().difference(&my_extensions) { - if missing { - log::debug!(" {ext}"); - } - } - return None; - } - - if p.supported_extensions().contains(&dmabuf_extensions) { - my_extensions = my_extensions.union(&dmabuf_extensions); - my_extensions.ext_image_drm_format_modifier = - p.supported_extensions().ext_image_drm_format_modifier; - } - - if p.supported_extensions().ext_filter_cubic { - my_extensions.ext_filter_cubic = true; - } - - log::debug!( - "Device exts for {}: {:?}", - p.properties().device_name, - &my_extensions - ); - Some((p, my_extensions)) - }) - .filter_map(|(p, my_extensions)| { - try_all_queue_families(p.as_ref()).map(|families| (p, my_extensions, families)) - }) - .min_by_key(|(p, _, families)| { - prio_from_device_type(p) * 10 + prio_from_families(families) - }) - .expect("no suitable physical device found"); - - log::info!( - "Using vkPhysicalDevice: {}", - physical_device.properties().device_name, - ); - - let texture_filtering = if physical_device.supported_extensions().ext_filter_cubic { - Filter::Cubic - } else { - Filter::Linear - }; - - let (device, queues) = Device::new( - physical_device, - DeviceCreateInfo { - enabled_extensions: my_extensions, - enabled_features: DeviceFeatures { - dynamic_rendering: true, - ..DeviceFeatures::empty() - }, - queue_create_infos: queue_families - .iter() - .map(|fam| QueueCreateInfo { - queue_family_index: fam.queue_family_index, - queues: fam.priorities.clone(), - ..Default::default() - }) - .collect::>(), - ..Default::default() - }, - )?; - - log::debug!( - " DMA-buf supported: {}", - device.enabled_extensions().ext_external_memory_dma_buf - ); - log::debug!( - " DRM format modifiers supported: {}", - device.enabled_extensions().ext_image_drm_format_modifier - ); - - let (graphics_queue, transfer_queue, capture_queue) = unwrap_queues(queues.collect()); - - let memory_allocator = memory_allocator(device.clone()); - let command_buffer_allocator = Arc::new(StandardCommandBufferAllocator::new( - device.clone(), - StandardCommandBufferAllocatorCreateInfo { - secondary_buffer_count: 32, - ..Default::default() - }, - )); - let descriptor_set_allocator = Arc::new(StandardDescriptorSetAllocator::new( - device.clone(), - StandardDescriptorSetAllocatorCreateInfo::default(), - )); - - let (quad_verts, quad_indices) = Self::default_quad(memory_allocator.clone())?; - let drm_formats = Self::get_drm_formats(device.clone()); - - let me = Self { - instance, - device, - graphics_queue, - transfer_queue, - capture_queue, - memory_allocator, - native_format: Format::R8G8B8A8_SRGB, - texture_filtering, - command_buffer_allocator, - descriptor_set_allocator, - quad_indices, - quad_verts, - shared_shaders: RwLock::new(HashMap::new()), - drm_formats, - }; - - Ok(Arc::new(me)) - } - - #[cfg(feature = "uidev")] - #[allow(clippy::type_complexity, clippy::too_many_lines)] - pub fn new_window() -> anyhow::Result<( - Arc, - winit::event_loop::EventLoop<()>, - Arc, - Arc, - )> { - use vulkano::{ - descriptor_set::allocator::StandardDescriptorSetAllocatorCreateInfo, - instance::InstanceCreateFlags, - swapchain::{Surface, SurfaceInfo}, - }; - use winit::{event_loop::EventLoop, window::Window}; - - let event_loop = EventLoop::new().unwrap(); // want panic - let mut vk_instance_extensions = Surface::required_extensions(&event_loop).unwrap(); - vk_instance_extensions.khr_get_physical_device_properties2 = true; - log::debug!("Instance exts for runtime: {:?}", &vk_instance_extensions); - - let instance = Instance::new( - get_vulkan_library().clone(), - InstanceCreateInfo { - flags: InstanceCreateFlags::ENUMERATE_PORTABILITY, - enabled_extensions: vk_instance_extensions, - ..Default::default() - }, - )?; - - #[allow(deprecated)] - let window = Arc::new( - event_loop - .create_window(Window::default_attributes()) - .unwrap(), // want panic - ); - let surface = Surface::from_window(instance.clone(), window.clone())?; - - let mut device_extensions = DeviceExtensions::empty(); - device_extensions.khr_swapchain = true; - - log::debug!("Device exts for app: {:?}", &device_extensions); - - let (physical_device, my_extensions, queue_families) = instance - .enumerate_physical_devices()? - .filter_map(|p| { - if p.supported_extensions().contains(&device_extensions) { - Some((p, device_extensions)) - } else { - log::debug!( - "Not using {} because it does not implement the following device extensions:", - p.properties().device_name, - ); - for (ext, missing) in p.supported_extensions().difference(&device_extensions) { - if missing { - log::debug!(" {ext}"); - } - } - None - } - }) - .filter_map(|(p, my_extensions)| - try_all_queue_families(p.as_ref()).map(|families| (p, my_extensions, families)) - ) - .min_by_key(|(p, _, _)| prio_from_device_type(p) - ) - .expect("no suitable physical device found"); - - log::info!( - "Using vkPhysicalDevice: {}", - physical_device.properties().device_name, - ); - - let (device, queues) = Device::new( - physical_device, - DeviceCreateInfo { - enabled_extensions: my_extensions, - enabled_features: DeviceFeatures { - dynamic_rendering: true, - ..DeviceFeatures::empty() - }, - queue_create_infos: queue_families - .iter() - .map(|fam| QueueCreateInfo { - queue_family_index: fam.queue_family_index, - queues: fam.priorities.clone(), - ..Default::default() - }) - .collect::>(), - ..Default::default() - }, - )?; - - let (graphics_queue, transfer_queue, capture_queue) = unwrap_queues(queues.collect()); - - let native_format = device - .physical_device() - .surface_formats(&surface, SurfaceInfo::default()) - .unwrap()[0] // want panic - .0; - log::info!("Using surface format: {native_format:?}"); - - let memory_allocator = memory_allocator(device.clone()); - let command_buffer_allocator = Arc::new(StandardCommandBufferAllocator::new( - device.clone(), - StandardCommandBufferAllocatorCreateInfo { - secondary_buffer_count: 32, - ..Default::default() - }, - )); - let descriptor_set_allocator = Arc::new(StandardDescriptorSetAllocator::new( - device.clone(), - StandardDescriptorSetAllocatorCreateInfo::default(), - )); - - let (quad_verts, quad_indices) = Self::default_quad(memory_allocator.clone())?; - let drm_formats = Self::get_drm_formats(device.clone()); - - let me = Self { - instance, - device, - graphics_queue, - transfer_queue, - capture_queue, - memory_allocator, - native_format, - texture_filtering: Filter::Linear, - command_buffer_allocator, - descriptor_set_allocator, - quad_indices, - quad_verts, - shared_shaders: RwLock::new(HashMap::new()), - drm_formats, - }; - - Ok((Arc::new(me), event_loop, window, surface)) - } - fn default_quad( - memory_allocator: Arc, - ) -> anyhow::Result<(Vert2Buf, IndexBuf)> { - let vertices = [ - Vert2Uv { - in_pos: [0., 0.], - in_uv: [0., 0.], - }, - Vert2Uv { - in_pos: [0., 1.], - in_uv: [0., 1.], - }, - Vert2Uv { - in_pos: [1., 0.], - in_uv: [1., 0.], - }, - Vert2Uv { - in_pos: [1., 1.], - in_uv: [1., 1.], - }, - ]; - let quad_verts = Buffer::from_iter( - memory_allocator.clone(), - BufferCreateInfo { - usage: BufferUsage::VERTEX_BUFFER, - ..Default::default() - }, - AllocationCreateInfo { - memory_type_filter: MemoryTypeFilter::PREFER_DEVICE - | MemoryTypeFilter::HOST_SEQUENTIAL_WRITE, - ..Default::default() - }, - vertices.into_iter(), - )?; - - let quad_indices = Buffer::from_iter( - memory_allocator, - BufferCreateInfo { - usage: BufferUsage::INDEX_BUFFER, - ..Default::default() - }, - AllocationCreateInfo { - memory_type_filter: MemoryTypeFilter::PREFER_DEVICE - | MemoryTypeFilter::HOST_SEQUENTIAL_WRITE, - ..Default::default() - }, - INDICES.iter().copied(), - )?; - - Ok((quad_verts, IndexBuffer::U16(quad_indices))) - } - - pub fn upload_verts( - &self, - width: f32, - height: f32, - x: f32, - y: f32, - w: f32, - h: f32, - ) -> anyhow::Result { - let rw = width; - let rh = height; - - let x0 = x / rw; - let y0 = y / rh; - - let x1 = w / rw + x0; - let y1 = h / rh + y0; - - let vertices = [ - Vert2Uv { - in_pos: [x0, y0], - in_uv: [0.0, 0.0], - }, - Vert2Uv { - in_pos: [x0, y1], - in_uv: [0.0, 1.0], - }, - Vert2Uv { - in_pos: [x1, y0], - in_uv: [1.0, 0.0], - }, - Vert2Uv { - in_pos: [x1, y1], - in_uv: [1.0, 1.0], - }, - ]; - self.upload_buffer(BufferUsage::VERTEX_BUFFER, vertices.iter()) - } - - pub fn upload_buffer( - &self, - usage: BufferUsage, - contents: Iter<'_, T>, - ) -> anyhow::Result> - where - T: BufferContents + Clone, - { - Ok(Buffer::from_iter( - self.memory_allocator.clone(), - BufferCreateInfo { - usage, - ..Default::default() - }, - AllocationCreateInfo { - memory_type_filter: MemoryTypeFilter::PREFER_HOST - | MemoryTypeFilter::HOST_SEQUENTIAL_WRITE, - ..Default::default() - }, - contents.cloned(), - )?) - } - - fn get_drm_formats(device: Arc) -> Vec { - let possible_formats = [ - DRM_FORMAT_ABGR8888.into(), - DRM_FORMAT_XBGR8888.into(), - DRM_FORMAT_ARGB8888.into(), - DRM_FORMAT_XRGB8888.into(), - DRM_FORMAT_ABGR2101010.into(), - DRM_FORMAT_XBGR2101010.into(), - ]; - - let mut final_formats = vec![]; - - for &f in &possible_formats { - let Ok(vk_fmt) = fourcc_to_vk(f) else { - continue; - }; - let Ok(props) = device.physical_device().format_properties(vk_fmt) else { - continue; - }; - let mut fmt = DrmFormat { - fourcc: f, - modifiers: props - .drm_format_modifier_properties - .iter() - // important bit: only allow single-plane - .filter(|m| m.drm_format_modifier_plane_count == 1) - .map(|m| m.drm_format_modifier) - .collect(), - }; - fmt.modifiers.push(DRM_FORMAT_MOD_INVALID); // implicit modifiers support - final_formats.push(fmt); - } - log::debug!("Supported DRM formats:"); - for f in &final_formats { - log::debug!(" {} {:?}", f.fourcc, f.modifiers); - } - final_formats - } - - pub fn dmabuf_texture_ex( - &self, - frame: DmabufFrame, - tiling: ImageTiling, - layouts: Vec, - modifiers: &[u64], - ) -> anyhow::Result> { - let extent = [frame.format.width, frame.format.height, 1]; - let format = fourcc_to_vk(frame.format.fourcc)?; - - let image = unsafe { - create_dmabuf_image( - self.device.clone(), - ImageCreateInfo { - format, - extent, - usage: ImageUsage::SAMPLED, - external_memory_handle_types: ExternalMemoryHandleTypes::DMA_BUF, - tiling, - drm_format_modifiers: modifiers.to_owned(), - drm_format_modifier_plane_layouts: layouts, - ..Default::default() - }, - )? - }; - - let requirements = image.memory_requirements()[0]; - let memory_type_index = self - .memory_allocator - .find_memory_type_index( - requirements.memory_type_bits, - MemoryTypeFilter { - required_flags: MemoryPropertyFlags::DEVICE_LOCAL, - ..Default::default() - }, - ) - .ok_or_else(|| anyhow!("failed to get memory type index"))?; - - debug_assert!(self.device.enabled_extensions().khr_external_memory_fd); - debug_assert!(self.device.enabled_extensions().khr_external_memory); - debug_assert!(self.device.enabled_extensions().ext_external_memory_dma_buf); - - // only do the 1st - unsafe { - let Some(fd) = frame.planes[0].fd else { - bail!("DMA-buf plane has no FD"); - }; - - let file = std::fs::File::from_raw_fd(fd); - let new_file = file.try_clone()?; - let _ = file.into_raw_fd(); - - let memory = DeviceMemory::allocate_unchecked( - self.device.clone(), - MemoryAllocateInfo { - allocation_size: requirements.layout.size(), - memory_type_index, - dedicated_allocation: Some(DedicatedAllocation::Image(&image)), - ..Default::default() - }, - Some(MemoryImportInfo::Fd { - file: new_file, - handle_type: ExternalMemoryHandleType::DmaBuf, - }), - )?; - - let mem_alloc = ResourceMemory::new_dedicated(memory); - match image.bind_memory_unchecked([mem_alloc]) { - Ok(image) => Ok(Arc::new(image)), - Err(e) => { - bail!("Failed to bind memory to image: {}", e.0); - } +#[cfg(feature = "openxr")] +#[allow(clippy::too_many_lines)] +pub fn init_openxr_graphics( + xr_instance: openxr::Instance, + system: openxr::SystemId, +) -> anyhow::Result<(Arc, WGfxExtras)> { + use std::ffi::{self, CString}; + + use vulkano::{Handle, Version}; + + let instance_extensions = InstanceExtensions { + khr_get_physical_device_properties2: true, + ..InstanceExtensions::empty() + }; + + let instance_extensions_raw = instance_extensions + .into_iter() + .filter_map(|(name, enabled)| { + if enabled { + Some(ffi::CString::new(name).unwrap().into_raw().cast_const()) + // want panic + } else { + None } - } - } - - pub fn dmabuf_texture(&self, frame: DmabufFrame) -> anyhow::Result> { - let mut modifiers: Vec = vec![]; - let mut tiling: ImageTiling = ImageTiling::Optimal; - let mut layouts: Vec = vec![]; - - if frame.format.modifier != DRM_FORMAT_MOD_INVALID { - (0..frame.num_planes).for_each(|i| { - let plane = &frame.planes[i]; - layouts.push(SubresourceLayout { - offset: plane.offset.into(), - size: 0, - row_pitch: plane.stride as _, - array_pitch: None, - depth_pitch: None, - }); - modifiers.push(frame.format.modifier); - }); - tiling = ImageTiling::DrmFormatModifier; - } - - self.dmabuf_texture_ex(frame, tiling, layouts, &modifiers) - } - - pub fn render_texture( - &self, - width: u32, - height: u32, - format: Format, - ) -> anyhow::Result> { - log::debug!( - "Render texture: {}x{} {}MB", - width, - height, - (width * height * 4) / (1024 * 1024) - ); - Ok(Image::new( - self.memory_allocator.clone(), - ImageCreateInfo { - image_type: ImageType::Dim2d, - format, - extent: [width, height, 1], - usage: ImageUsage::TRANSFER_SRC - | ImageUsage::SAMPLED - | ImageUsage::COLOR_ATTACHMENT, - ..Default::default() - }, - AllocationCreateInfo::default(), - )?) - } - - pub fn create_pipeline( - self: &Arc, - vert: Arc, - frag: Arc, - format: Format, - blend: Option, - ) -> anyhow::Result> { - Ok(Arc::new(WlxPipeline::new( - self.clone(), - vert, - frag, - format, - blend, - )?)) - } - - /// Creates a CommandBuffer to be used for graphics workloads on the main thread. - pub fn create_command_buffer( - self: &Arc, - usage: CommandBufferUsage, - ) -> anyhow::Result { - let command_buffer = AutoCommandBufferBuilder::primary( - self.command_buffer_allocator.clone(), - self.graphics_queue.queue_family_index(), - usage, - )?; - Ok(WlxCommandBuffer { - graphics: self.clone(), - queue: self.graphics_queue.clone(), - command_buffer, - dummy: None, }) - } + .collect::>(); - /// Creates a CommandBuffer to be used for texture uploads on the main thread. - pub fn create_uploads_command_buffer( - self: &Arc, - queue: Arc, - usage: CommandBufferUsage, - ) -> anyhow::Result { - let command_buffer = AutoCommandBufferBuilder::primary( - self.command_buffer_allocator.clone(), - queue.queue_family_index(), - usage, - )?; - Ok(WlxUploadsBuffer { - graphics: self.clone(), - queue, - command_buffer, - dummy: None, - }) - } + let vk_target_version = vk::make_api_version(0, 1, 3, 0); + let target_version = vulkano::Version::V1_3; + let library = get_vulkan_library(); - pub fn transition_layout( - &self, - image: Arc, - old_layout: ImageLayout, - new_layout: ImageLayout, - ) -> anyhow::Result { - let barrier = ImageMemoryBarrier { - src_stages: PipelineStages::ALL_TRANSFER, - src_access: AccessFlags::TRANSFER_WRITE, - dst_stages: PipelineStages::ALL_TRANSFER, - dst_access: AccessFlags::TRANSFER_READ, - old_layout, - new_layout, - subresource_range: image.subresource_range(), - ..ImageMemoryBarrier::image(image) - }; + let vk_app_info_raw = vk::ApplicationInfo::default() + .application_version(0) + .engine_version(0) + .api_version(vk_target_version); - let command_buffer = unsafe { - let mut builder = RecordingCommandBuffer::new( - self.command_buffer_allocator.clone(), - self.graphics_queue.queue_family_index(), - CommandBufferLevel::Primary, - CommandBufferBeginInfo { - usage: CommandBufferUsage::OneTimeSubmit, - inheritance_info: None, - ..Default::default() - }, - )?; - - builder.pipeline_barrier(&DependencyInfo { - image_memory_barriers: smallvec![barrier], - ..Default::default() - })?; - builder.end()? - }; - - let fence = vulkano::sync::fence::Fence::new( - self.device.clone(), - vulkano::sync::fence::FenceCreateInfo::default(), - )?; - - let fns = self.device.fns(); - unsafe { - (fns.v1_0.queue_submit)( - self.graphics_queue.handle(), - 1, - [SubmitInfo::default().command_buffers(&[command_buffer.handle()])].as_ptr(), - fence.handle(), + let instance = unsafe { + let vk_instance = xr_instance + .create_vulkan_instance( + system, + get_instance_proc_addr, + std::ptr::from_ref( + &vk::InstanceCreateInfo::default() + .application_info(&vk_app_info_raw) + .enabled_extension_names(&instance_extensions_raw), + ) + .cast(), ) - } - .result()?; + .expect("XR error creating Vulkan instance") + .map_err(vk::Result::from_raw) + .expect("Vulkan error creating Vulkan instance"); - Ok(fence) - } -} - -pub type WlxCommandBuffer = AnyCommandBuffer; -pub type WlxUploadsBuffer = AnyCommandBuffer; - -pub struct GraphicsBuffer; -pub struct UploadBuffer; - -pub struct AnyCommandBuffer { - pub graphics: Arc, - pub command_buffer: AutoCommandBufferBuilder, - pub queue: Arc, - dummy: Option, -} - -impl AnyCommandBuffer { - pub fn build_and_execute(self) -> anyhow::Result> { - let queue = self.queue.clone(); - Ok(self.command_buffer.build()?.execute(queue)?) - } - - pub fn build_and_execute_now(self) -> anyhow::Result<()> { - let mut exec = self.build_and_execute()?; - exec.flush()?; - exec.cleanup_finished(); - Ok(()) - } -} - -impl AnyCommandBuffer { - pub fn begin_rendering(&mut self, render_target: Arc) -> anyhow::Result<()> { - self.command_buffer.begin_rendering(RenderingInfo { - contents: SubpassContents::SecondaryCommandBuffers, - color_attachments: vec![Some(RenderingAttachmentInfo { - load_op: AttachmentLoadOp::Clear, - store_op: AttachmentStoreOp::Store, - clear_value: Some([0.0, 0.0, 0.0, 0.0].into()), - ..RenderingAttachmentInfo::image_view(render_target) - })], - ..Default::default() - })?; - Ok(()) - } - - pub fn build(self) -> anyhow::Result> { - Ok(self.command_buffer.build()?) - } - - pub fn run_ref(&mut self, pass: &WlxPass) -> anyhow::Result<()> { - self.command_buffer - .execute_commands(pass.command_buffer.clone())?; - Ok(()) - } - - pub fn end_rendering(&mut self) -> anyhow::Result<()> { - self.command_buffer.end_rendering()?; - Ok(()) - } -} - -impl AnyCommandBuffer { - pub fn texture2d_raw( - &mut self, - width: u32, - height: u32, - format: Format, - data: &[u8], - ) -> anyhow::Result> { - log::debug!( - "Texture2D: {}x{} {}MB", - width, - height, - data.len() / (1024 * 1024) - ); - let image = Image::new( - self.graphics.memory_allocator.clone(), - ImageCreateInfo { - image_type: ImageType::Dim2d, - format, - extent: [width, height, 1], - usage: ImageUsage::TRANSFER_DST | ImageUsage::TRANSFER_SRC | ImageUsage::SAMPLED, + Instance::from_handle( + library.clone(), + ash::vk::Instance::from_raw(vk_instance as _), + InstanceCreateInfo { + application_version: Version::major_minor(0, 0), + engine_version: Version::major_minor(0, 0), + max_api_version: Some(Version::V1_3), + enabled_extensions: instance_extensions, ..Default::default() }, - AllocationCreateInfo::default(), - )?; - - let buffer: Subbuffer<[u8]> = Buffer::new_slice( - self.graphics.memory_allocator.clone(), - BufferCreateInfo { - usage: BufferUsage::TRANSFER_SRC, - ..Default::default() - }, - AllocationCreateInfo { - memory_type_filter: MemoryTypeFilter::PREFER_HOST - | MemoryTypeFilter::HOST_SEQUENTIAL_WRITE, - ..Default::default() - }, - data.len() as DeviceSize, - )?; - - buffer.write()?.copy_from_slice(data); - - self.command_buffer - .copy_buffer_to_image(CopyBufferToImageInfo::buffer_image(buffer, image.clone()))?; - - Ok(image) - } -} - -pub struct WlxPipeline { - pub graphics: Arc, - pub pipeline: Arc, - pub format: Format, -} - -impl WlxPipeline { - fn new( - graphics: Arc, - vert: Arc, - frag: Arc, - format: Format, - blend: Option, - ) -> anyhow::Result { - let vep = vert.entry_point("main").unwrap(); // want panic - let fep = frag.entry_point("main").unwrap(); // want panic - - let vertex_input_state = Vert2Uv::per_vertex().definition(&vep)?; - - let stages = smallvec![ - vulkano::pipeline::PipelineShaderStageCreateInfo::new(vep), - vulkano::pipeline::PipelineShaderStageCreateInfo::new(fep), - ]; - - let layout = PipelineLayout::new( - graphics.device.clone(), - PipelineDescriptorSetLayoutCreateInfo::from_stages(&stages) - .into_pipeline_layout_create_info(graphics.device.clone())?, - )?; - - let subpass = PipelineRenderingCreateInfo { - color_attachment_formats: vec![Some(format)], - ..Default::default() - }; - - let pipeline = GraphicsPipeline::new( - graphics.device.clone(), - None, - GraphicsPipelineCreateInfo { - stages, - vertex_input_state: Some(vertex_input_state), - input_assembly_state: Some(InputAssemblyState::default()), - viewport_state: Some(ViewportState::default()), - rasterization_state: Some(RasterizationState::default()), - multisample_state: Some(MultisampleState::default()), - color_blend_state: Some(ColorBlendState { - attachments: vec![ColorBlendAttachmentState { - blend, - ..Default::default() - }], - ..Default::default() - }), - dynamic_state: std::iter::once(DynamicState::Viewport).collect(), - subpass: Some(subpass.into()), - ..GraphicsPipelineCreateInfo::layout(layout) - }, - )?; - - Ok(Self { - graphics, - pipeline, - format, - }) - } - pub fn create_pass( - self: &Arc, - dimensions: [f32; 2], - vertex_buffer: Vert2Buf, - index_buffer: IndexBuf, - descriptor_sets: Vec>, - ) -> anyhow::Result { - WlxPass::new( - self.clone(), - dimensions, - vertex_buffer, - index_buffer, - descriptor_sets, ) - } + }; - pub fn create_pass_for_target( - self: &Arc, - tgt: Arc, - descriptor_sets: Vec>, - ) -> anyhow::Result { - let extent = tgt.image().extent(); - WlxPass::new( - self.clone(), - [extent[0] as _, extent[1] as _], - self.graphics.quad_verts.clone(), - self.graphics.quad_indices.clone(), - descriptor_sets, + let physical_device = unsafe { + PhysicalDevice::from_handle( + instance.clone(), + vk::PhysicalDevice::from_raw( + xr_instance.vulkan_graphics_device(system, instance.handle().as_raw() as _)? as _, + ), ) - } -} + }?; -impl WlxPipeline { - pub fn inner(&self) -> Arc { - self.pipeline.clone() - } + let vk_device_properties = physical_device.properties(); + assert!( + (vk_device_properties.api_version >= target_version), + "Vulkan physical device doesn't support Vulkan {target_version}" + ); - pub fn uniform_sampler( - &self, - set: usize, - texture: Arc, - filter: Filter, - ) -> anyhow::Result> { - let sampler = Sampler::new( - self.graphics.device.clone(), - SamplerCreateInfo { - mag_filter: filter, - min_filter: filter, - address_mode: [SamplerAddressMode::Repeat; 3], - ..Default::default() - }, - )?; + log::info!( + "Using vkPhysicalDevice: {}", + physical_device.properties().device_name, + ); - let layout = self.pipeline.layout().set_layouts().get(set).unwrap(); // want panic + let queue_families = try_all_queue_families(physical_device.as_ref()) + .expect("vkPhysicalDevice does not have a GRAPHICS / TRANSFER queue."); - Ok(DescriptorSet::new( - self.graphics.descriptor_set_allocator.clone(), - layout.clone(), - [WriteDescriptorSet::image_view_sampler(0, texture, sampler)], - [], - )?) - } + let mut device_extensions = DeviceExtensions::empty(); + let dmabuf_extensions = get_dmabuf_extensions(); - pub fn uniform_buffer(&self, set: usize, data: Vec) -> anyhow::Result> - where - T: BufferContents + Copy, + if physical_device + .supported_extensions() + .contains(&dmabuf_extensions) { - let uniform_buffer = SubbufferAllocator::new( - self.graphics.memory_allocator.clone(), - SubbufferAllocatorCreateInfo { - buffer_usage: BufferUsage::UNIFORM_BUFFER, - memory_type_filter: MemoryTypeFilter::PREFER_DEVICE - | MemoryTypeFilter::HOST_SEQUENTIAL_WRITE, - ..Default::default() - }, - ); - - let uniform_buffer_subbuffer = { - let subbuffer = uniform_buffer.allocate_slice(data.len() as _)?; - subbuffer.write()?.copy_from_slice(data.as_slice()); - subbuffer - }; - - let layout = self.pipeline.layout().set_layouts().get(set).unwrap(); // want panic - Ok(DescriptorSet::new( - self.graphics.descriptor_set_allocator.clone(), - layout.clone(), - [WriteDescriptorSet::buffer(0, uniform_buffer_subbuffer)], - [], - )?) + device_extensions = device_extensions.union(&dmabuf_extensions); + device_extensions.ext_image_drm_format_modifier = physical_device + .supported_extensions() + .ext_image_drm_format_modifier; } -} -pub struct WlxPass { - pub command_buffer: Arc, -} - -impl WlxPass { - fn new( - pipeline: Arc, - dimensions: [f32; 2], - vertex_buffer: Vert2Buf, - index_buffer: IndexBuf, - descriptor_sets: Vec>, - ) -> anyhow::Result { - let viewport = Viewport { - offset: [0.0, 0.0], - extent: dimensions, - depth_range: 0.0..=1.0, - }; - let pipeline_inner = pipeline.inner(); - let mut command_buffer = AutoCommandBufferBuilder::secondary( - pipeline.graphics.command_buffer_allocator.clone(), - pipeline.graphics.graphics_queue.queue_family_index(), - CommandBufferUsage::MultipleSubmit, - CommandBufferInheritanceInfo { - render_pass: Some(CommandBufferInheritanceRenderPassType::BeginRendering( - CommandBufferInheritanceRenderingInfo { - color_attachment_formats: vec![Some(pipeline.format)], - - ..Default::default() - }, - )), - ..Default::default() - }, - )?; - - unsafe { - command_buffer - .set_viewport(0, smallvec![viewport])? - .bind_pipeline_graphics(pipeline_inner)? - .bind_descriptor_sets( - PipelineBindPoint::Graphics, - pipeline.inner().layout().clone(), - 0, - descriptor_sets, - )? - .bind_vertex_buffers(0, vertex_buffer)? - .bind_index_buffer(index_buffer.clone())? - .draw_indexed(index_buffer.len() as u32, 1, 0, 0, 0)? - }; - - Ok(Self { - command_buffer: command_buffer.build()?, + let device_extensions_raw = device_extensions + .into_iter() + .filter_map(|(name, enabled)| { + if enabled { + Some(ffi::CString::new(name).unwrap().into_raw().cast_const()) + // want panic + } else { + None + } }) - } -} + .collect::>(); -#[derive(Default)] -pub struct CommandBuffers { - inner: Vec>, -} - -impl CommandBuffers { - pub fn push(&mut self, buffer: Arc) { - self.inner.push(buffer); - } - pub fn execute_now(self, queue: Arc) -> anyhow::Result>> { - let mut buffers = self.inner.into_iter(); - let Some(first) = buffers.next() else { - return Ok(None); - }; - - let future = first.execute(queue)?; - let mut future: Box = Box::new(future); - - for buf in buffers { - future = Box::new(future.then_execute_same_queue(buf)?); - } - - Ok(Some(future)) - } - #[cfg(feature = "uidev")] - pub fn execute_after( - self, - queue: Arc, - future: Box, - ) -> anyhow::Result> { - let mut buffers = self.inner.into_iter(); - let Some(first) = buffers.next() else { - return Ok(future); - }; - - let future = future.then_execute(queue, first)?; - let mut future: Box = Box::new(future); - - for buf in buffers { - future = Box::new(future.then_execute_same_queue(buf)?); - } - - Ok(future) - } -} - -pub fn fourcc_to_vk(fourcc: FourCC) -> anyhow::Result { - match fourcc.value { - DRM_FORMAT_ABGR8888 | DRM_FORMAT_XBGR8888 => Ok(Format::R8G8B8A8_UNORM), - DRM_FORMAT_ARGB8888 | DRM_FORMAT_XRGB8888 => Ok(Format::B8G8R8A8_UNORM), - DRM_FORMAT_ABGR2101010 | DRM_FORMAT_XBGR2101010 => Ok(Format::A2B10G10R10_UNORM_PACK32), - _ => bail!("Unsupported format {}", fourcc), - } -} - -fn memory_allocator(device: Arc) -> Arc { - let props = device.physical_device().memory_properties(); - - let mut block_sizes = vec![0; props.memory_types.len()]; - let mut memory_type_bits = u32::MAX; - - for (index, memory_type) in props.memory_types.iter().enumerate() { - const LARGE_HEAP_THRESHOLD: DeviceSize = 1024 * 1024 * 1024; - - let heap_size = props.memory_heaps[memory_type.heap_index as usize].size; - - block_sizes[index] = if heap_size >= LARGE_HEAP_THRESHOLD { - 48 * 1024 * 1024 - } else { - 24 * 1024 * 1024 - }; - - if memory_type.property_flags.intersects( - MemoryPropertyFlags::LAZILY_ALLOCATED - | MemoryPropertyFlags::PROTECTED - | MemoryPropertyFlags::DEVICE_COHERENT - | MemoryPropertyFlags::RDMA_CAPABLE, - ) { - // VUID-VkMemoryAllocateInfo-memoryTypeIndex-01872 - // VUID-vkAllocateMemory-deviceCoherentMemory-02790 - // Lazily allocated memory would just cause problems for suballocation in general. - memory_type_bits &= !(1 << index); - } - } - - let create_info = GenericMemoryAllocatorCreateInfo { - block_sizes: &block_sizes, - memory_type_bits, + let features = DeviceFeatures { + dynamic_rendering: true, ..Default::default() }; - Arc::new(StandardMemoryAllocator::new(device, create_info)) + let queue_create_infos = queue_families + .iter() + .map(|fam| { + vk::DeviceQueueCreateInfo::default() + .queue_family_index(fam.queue_family_index) + .queue_priorities(&fam.priorities) + }) + .collect::>(); + + let mut device_create_info = vk::DeviceCreateInfo::default() + .queue_create_infos(&queue_create_infos) + .enabled_extension_names(&device_extensions_raw); + + let mut dynamic_rendering = + vk::PhysicalDeviceDynamicRenderingFeatures::default().dynamic_rendering(true); + + dynamic_rendering.p_next = device_create_info.p_next.cast_mut(); + device_create_info.p_next = &raw mut dynamic_rendering as *const c_void; + + let (device, queues) = unsafe { + let vk_device = xr_instance + .create_vulkan_device( + system, + get_instance_proc_addr, + physical_device.handle().as_raw() as _, + (&raw const device_create_info).cast(), + ) + .expect("XR error creating Vulkan device") + .map_err(vk::Result::from_raw) + .expect("Vulkan error creating Vulkan device"); + + vulkano::device::Device::from_handle( + physical_device, + vk::Device::from_raw(vk_device as _), + DeviceCreateInfo { + queue_create_infos: queue_families + .iter() + .map(|fam| QueueCreateInfo { + queue_family_index: fam.queue_family_index, + queues: fam.priorities.clone(), + ..Default::default() + }) + .collect::>(), + enabled_extensions: device_extensions, + enabled_features: features, + ..Default::default() + }, + ) + }; + + log::debug!( + " DMA-buf supported: {}", + device.enabled_extensions().ext_external_memory_dma_buf + ); + log::debug!( + " DRM format modifiers supported: {}", + device.enabled_extensions().ext_image_drm_format_modifier + ); + + // Drop the CStrings + device_extensions_raw + .into_iter() + .for_each(|c_string| unsafe { + let _ = CString::from_raw(c_string.cast_mut()); + }); + + let (queue_gfx, queue_xfer, queue_capture) = unwrap_queues(queues.collect()); + + let gfx = WGfx::new_from_raw( + instance, + device, + queue_gfx, + queue_xfer, + Format::R8G8B8A8_SRGB, + ); + let extras = WGfxExtras::new(&gfx, queue_capture)?; + + Ok((gfx, extras)) +} + +#[allow(clippy::too_many_lines)] +#[cfg(feature = "openvr")] +pub fn init_openvr_graphics( + mut vk_instance_extensions: InstanceExtensions, + mut vk_device_extensions_fn: impl FnMut(&PhysicalDevice) -> DeviceExtensions, +) -> anyhow::Result<(Arc, WGfxExtras)> { + //#[cfg(debug_assertions)] + //let layers = vec!["VK_LAYER_KHRONOS_validation".to_owned()]; + //#[cfg(not(debug_assertions))] + + let layers = vec![]; + + log::debug!("Instance exts for runtime: {:?}", &vk_instance_extensions); + + vk_instance_extensions.khr_get_physical_device_properties2 = true; + + let instance = Instance::new( + get_vulkan_library().clone(), + InstanceCreateInfo { + flags: InstanceCreateFlags::ENUMERATE_PORTABILITY, + enabled_extensions: vk_instance_extensions, + enabled_layers: layers, + ..Default::default() + }, + )?; + + let dmabuf_extensions = get_dmabuf_extensions(); + + let (physical_device, my_extensions, queue_families) = instance + .enumerate_physical_devices()? + .filter_map(|p| { + let mut my_extensions = vk_device_extensions_fn(&p); + + if !p.supported_extensions().contains(&my_extensions) { + log::debug!( + "Not using {} due to missing extensions:", + p.properties().device_name, + ); + for (ext, missing) in p.supported_extensions().difference(&my_extensions) { + if missing { + log::debug!(" {ext}"); + } + } + return None; + } + + if p.supported_extensions().contains(&dmabuf_extensions) { + my_extensions = my_extensions.union(&dmabuf_extensions); + my_extensions.ext_image_drm_format_modifier = + p.supported_extensions().ext_image_drm_format_modifier; + } + + if p.supported_extensions().ext_filter_cubic { + my_extensions.ext_filter_cubic = true; + } + + log::debug!( + "Device exts for {}: {:?}", + p.properties().device_name, + &my_extensions + ); + Some((p, my_extensions)) + }) + .filter_map(|(p, my_extensions)| { + try_all_queue_families(p.as_ref()).map(|families| (p, my_extensions, families)) + }) + .min_by_key(|(p, _, families)| prio_from_device_type(p) * 10 + prio_from_families(families)) + .expect("no suitable physical device found"); + + log::info!( + "Using vkPhysicalDevice: {}", + physical_device.properties().device_name, + ); + + let (device, queues) = Device::new( + physical_device, + DeviceCreateInfo { + enabled_extensions: my_extensions, + enabled_features: DeviceFeatures { + dynamic_rendering: true, + ..DeviceFeatures::empty() + }, + queue_create_infos: queue_families + .iter() + .map(|fam| QueueCreateInfo { + queue_family_index: fam.queue_family_index, + queues: fam.priorities.clone(), + ..Default::default() + }) + .collect::>(), + ..Default::default() + }, + )?; + + log::debug!( + " DMA-buf supported: {}", + device.enabled_extensions().ext_external_memory_dma_buf + ); + log::debug!( + " DRM format modifiers supported: {}", + device.enabled_extensions().ext_image_drm_format_modifier + ); + + let (queue_gfx, queue_xfer, queue_capture) = unwrap_queues(queues.collect()); + + let gfx = WGfx::new_from_raw( + instance, + device, + queue_gfx, + queue_xfer, + Format::R8G8B8A8_SRGB, + ); + let extras = WGfxExtras::new(&gfx, queue_capture)?; + + Ok((gfx, extras)) +} + +pub fn upload_quad_vertices( + buf: &mut Subbuffer<[Vert2Uv]>, + width: f32, + height: f32, + x: f32, + y: f32, + w: f32, + h: f32, +) -> anyhow::Result<()> { + let rw = width; + let rh = height; + + let x0 = x / rw; + let y0 = y / rh; + + let x1 = w / rw + x0; + let y1 = h / rh + y0; + + let data = [ + Vert2Uv { + in_pos: [x0, y0], + in_uv: [0.0, 0.0], + }, + Vert2Uv { + in_pos: [x0, y1], + in_uv: [0.0, 1.0], + }, + Vert2Uv { + in_pos: [x1, y0], + in_uv: [1.0, 0.0], + }, + Vert2Uv { + in_pos: [x1, y1], + in_uv: [1.0, 1.0], + }, + ]; + + buf.write()?[0..4].copy_from_slice(&data); + Ok(()) } #[derive(Debug)] @@ -1577,3 +617,50 @@ fn queue_families_priorities( None } } + +#[derive(Default)] +pub struct CommandBuffers { + inner: Vec>, +} + +impl CommandBuffers { + pub fn push(&mut self, buffer: Arc) { + self.inner.push(buffer); + } + pub fn execute_now(self, queue: Arc) -> anyhow::Result>> { + let mut buffers = self.inner.into_iter(); + let Some(first) = buffers.next() else { + return Ok(None); + }; + + let future = first.execute(queue)?; + let mut future: Box = Box::new(future); + + for buf in buffers { + future = Box::new(future.then_execute_same_queue(buf)?); + } + + Ok(Some(future)) + } +} + +pub trait ExtentExt { + fn extent_f32(&self) -> [f32; 2]; + fn extent_vec2(&self) -> Vec2; + fn extent_u32arr(&self) -> [u32; 2]; +} + +impl ExtentExt for Arc { + fn extent_f32(&self) -> [f32; 2] { + let [w, h, _] = self.image().extent(); + [w as _, h as _] + } + fn extent_vec2(&self) -> Vec2 { + let [w, h, _] = self.image().extent(); + vec2(w as _, h as _) + } + fn extent_u32arr(&self) -> [u32; 2] { + let [w, h, _] = self.image().extent(); + [w, h] + } +} diff --git a/src/gui/asset.rs b/src/gui/asset.rs new file mode 100644 index 0000000..a18e762 --- /dev/null +++ b/src/gui/asset.rs @@ -0,0 +1,12 @@ +#[derive(rust_embed::Embed)] +#[folder = "src/gui/assets/"] +pub struct GuiAsset; + +impl wgui::assets::AssetProvider for GuiAsset { + fn load_from_path(&mut self, path: &str) -> anyhow::Result> { + match GuiAsset::get(path) { + Some(data) => Ok(data.data.to_vec()), + None => anyhow::bail!("embedded file {} not found", path), + } + } +} diff --git a/src/gui/assets/test b/src/gui/assets/test new file mode 100644 index 0000000..e69de29 diff --git a/src/gui/canvas/builder.rs b/src/gui/canvas/builder.rs deleted file mode 100644 index 40f1838..0000000 --- a/src/gui/canvas/builder.rs +++ /dev/null @@ -1,267 +0,0 @@ -use glam::Vec4; -use std::sync::Arc; - -use vulkano::format::Format; - -use crate::{ - graphics::WlxGraphics, - gui::{canvas::control::ControlRenderer, GuiColor, KeyCapType}, -}; - -use super::{control::Control, Canvas, Rect}; - -pub struct CanvasBuilder { - canvas: Canvas, - - pub fg_color: GuiColor, - pub bg_color: GuiColor, - pub font_size: isize, -} - -impl CanvasBuilder { - pub fn new( - width: usize, - height: usize, - graphics: Arc, - format: Format, - data: D, - ) -> anyhow::Result { - Ok(Self { - canvas: Canvas::new(width, height, graphics, format, data)?, - bg_color: Vec4::ZERO, - fg_color: Vec4::ONE, - font_size: 16, - }) - } - - pub fn build(self) -> Canvas { - self.canvas - } - - // Creates a panel with bg_color inherited from the canvas - pub fn panel(&mut self, x: f32, y: f32, w: f32, h: f32, radius: f32) -> &mut Control { - let idx = self.canvas.controls.len(); - self.canvas.controls.push(Control { - rect: Rect { x, y, w, h }, - corner_radius: radius, - bg_color: self.bg_color, - on_render_bg: Some(Control::render_rounded_rect), - ..Control::new() - }); - &mut self.canvas.controls[idx] - } - - // Creates a label with fg_color, font_size inherited from the canvas - pub fn label( - &mut self, - x: f32, - y: f32, - w: f32, - h: f32, - radius: f32, - text: Arc, - ) -> &mut Control { - let idx = self.canvas.controls.len(); - self.canvas.controls.push(Control { - rect: Rect { x, y, w, h }, - corner_radius: radius, - text, - fg_color: self.fg_color, - size: self.font_size, - on_render_fg: Some(Control::render_text), - ..Control::new() - }); - &mut self.canvas.controls[idx] - } - - // Creates a label with fg_color, font_size inherited from the canvas - #[allow(dead_code)] - pub fn label_centered( - &mut self, - x: f32, - y: f32, - w: f32, - h: f32, - radius: f32, - text: Arc, - ) -> &mut Control { - let idx = self.canvas.controls.len(); - self.canvas.controls.push(Control { - rect: Rect { x, y, w, h }, - corner_radius: radius, - text, - fg_color: self.fg_color, - size: self.font_size, - on_render_fg: Some(Control::render_text_centered), - ..Control::new() - }); - &mut self.canvas.controls[idx] - } - - // Creates a sprite. Will not draw anything until set_sprite is called. - pub fn sprite(&mut self, x: f32, y: f32, w: f32, h: f32) -> &mut Control { - let idx = self.canvas.controls.len(); - self.canvas.controls.push(Control { - rect: Rect { x, y, w, h }, - corner_radius: 0., - on_render_bg: Some(Control::render_sprite_bg), - ..Control::new() - }); - &mut self.canvas.controls[idx] - } - - // Creates a sprite that highlights on pointer hover. Will not draw anything until set_sprite is called. - #[allow(dead_code)] - pub fn sprite_interactive(&mut self, x: f32, y: f32, w: f32, h: f32) -> &mut Control { - let idx = self.canvas.controls.len(); - self.canvas.controls.push(Control { - rect: Rect { x, y, w, h }, - corner_radius: 0., - on_render_bg: Some(Control::render_sprite_bg), - on_render_hl: Some(Control::render_sprite_hl), - ..Control::new() - }); - &mut self.canvas.controls[idx] - } - - // Creates a button with fg_color, bg_color, font_size inherited from the canvas - pub fn button( - &mut self, - x: f32, - y: f32, - w: f32, - h: f32, - radius: f32, - text: Arc, - ) -> &mut Control { - let idx = self.canvas.controls.len(); - - self.canvas.interactive_set_idx(x, y, w, h, idx); - self.canvas.controls.push(Control { - rect: Rect { x, y, w, h }, - corner_radius: radius, - text, - fg_color: self.fg_color, - bg_color: self.bg_color, - size: self.font_size, - on_render_bg: Some(Control::render_rounded_rect), - on_render_fg: Some(Control::render_text_centered), - on_render_hl: Some(Control::render_highlight), - ..Control::new() - }); - - &mut self.canvas.controls[idx] - } - - #[allow(clippy::too_many_arguments)] - pub fn key_button( - &mut self, - x: f32, - y: f32, - w: f32, - h: f32, - radius: f32, - cap_type: KeyCapType, - label: &[String], - ) -> &mut Control { - let idx = self.canvas.controls.len(); - self.canvas.interactive_set_idx(x, y, w, h, idx); - - self.canvas.controls.push(Control { - rect: Rect { x, y, w, h }, - corner_radius: radius, - bg_color: self.bg_color, - on_render_bg: Some(Control::render_rounded_rect), - on_render_hl: Some(Control::render_highlight), - ..Control::new() - }); - - let renders = match cap_type { - KeyCapType::Regular => { - let render: ControlRenderer = Control::render_text_centered; - let rect = Rect { - x, - y, - w, - h: h - self.font_size as f32, - }; - vec![(render, rect, 1f32)] - } - KeyCapType::RegularAltGr => { - let render: ControlRenderer = Control::render_text; - let rect0 = Rect { - x: x + 12., - y: y + (self.font_size as f32) + 12., - w, - h, - }; - let rect1 = Rect { - x: w.mul_add(0.5, x) + 12., - y: y + h - (self.font_size as f32) + 8., - w, - h, - }; - vec![(render, rect0, 1.0), (render, rect1, 0.8)] - } - KeyCapType::Reversed => { - let render: ControlRenderer = Control::render_text_centered; - let rect0 = Rect { - x, - y: y + 2.0, - w, - h: h * 0.5, - }; - let rect1 = Rect { - x, - y: h.mul_add(0.5, y) + 2.0, - w, - h: h * 0.5, - }; - vec![(render, rect1, 1.0), (render, rect0, 0.8)] - } - KeyCapType::ReversedAltGr => { - let render: ControlRenderer = Control::render_text; - let rect0 = Rect { - x: x + 12., - y: y + (self.font_size as f32) + 8., - w, - h, - }; - let rect1 = Rect { - x: x + 12., - y: y + h - (self.font_size as f32) + 4., - w, - h, - }; - let rect2 = Rect { - x: w.mul_add(0.5, x) + 8., - y: y + h - (self.font_size as f32) + 4., - w, - h, - }; - vec![ - (render, rect1, 1.0), - (render, rect0, 0.8), - (render, rect2, 0.8), - ] - } - }; - - for (idx, (render, rect, alpha)) in renders.into_iter().enumerate() { - if idx >= label.len() { - break; - } - - self.canvas.controls.push(Control { - rect, - text: Arc::from(label[idx].as_str()), - fg_color: self.fg_color * alpha, - size: self.font_size, - on_render_fg: Some(render), - ..Control::new() - }); - } - - &mut self.canvas.controls[idx] - } -} diff --git a/src/gui/canvas/control.rs b/src/gui/canvas/control.rs deleted file mode 100644 index a122de7..0000000 --- a/src/gui/canvas/control.rs +++ /dev/null @@ -1,387 +0,0 @@ -use glam::Vec4; -use std::sync::Arc; -use vulkano::image::view::ImageView; - -use crate::{ - backend::input::PointerMode, graphics::WlxCommandBuffer, gui::GuiColor, state::AppState, -}; - -use super::{CanvasData, Rect}; - -pub type ControlRenderer = - fn(&Control, &CanvasData, &mut AppState, &mut WlxCommandBuffer) -> anyhow::Result<()>; - -pub type ControlRendererHl = fn( - &Control, - &CanvasData, - &mut AppState, - &mut WlxCommandBuffer, - Vec4, -) -> anyhow::Result<()>; - -#[allow(clippy::type_complexity)] -pub struct Control { - pub state: Option, - pub rect: Rect, - pub corner_radius: f32, - pub fg_color: GuiColor, - pub bg_color: GuiColor, - pub text: Arc, - pub size: isize, - pub sprite: Option>, - pub sprite_st: Vec4, - pub(super) bg_dirty: bool, - pub(super) fg_dirty: bool, - - pub on_update: Option, - pub on_press: Option, - pub on_release: Option, - pub on_scroll: Option, - pub test_highlight: Option Option>, - - pub(super) on_render_bg: Option>, - pub(super) on_render_hl: Option>, - pub(super) on_render_fg: Option>, -} - -impl Control { - pub(super) fn new() -> Self { - Self { - rect: Rect { - x: 0., - y: 0., - w: 0., - h: 0., - }, - corner_radius: 0., - fg_color: Vec4::ONE, - bg_color: Vec4::ZERO, - text: Arc::from(""), - sprite: None, - sprite_st: Vec4::new(1., 1., 0., 0.), - bg_dirty: true, - fg_dirty: true, - size: 24, - state: None, - on_update: None, - on_render_bg: None, - on_render_hl: None, - on_render_fg: None, - test_highlight: None, - on_press: None, - on_release: None, - on_scroll: None, - } - } - - pub fn set_text(&mut self, text: &str) { - if *self.text == *text { - return; - } - self.text = text.into(); - self.fg_dirty = true; - } - - pub fn set_sprite(&mut self, sprite: Arc) { - self.sprite.replace(sprite); - self.bg_dirty = true; - } - - pub fn set_sprite_st(&mut self, sprite_st: Vec4) { - if self.sprite_st == sprite_st { - return; - } - self.sprite_st = sprite_st; - self.bg_dirty = true; - } - - pub fn set_fg_color(&mut self, color: GuiColor) { - if self.fg_color == color { - return; - } - self.fg_color = color; - self.fg_dirty = true; - } - - pub fn render_rounded_rect( - &self, - canvas: &CanvasData, - _: &mut AppState, - cmd_buffer: &mut WlxCommandBuffer, - ) -> anyhow::Result<()> { - let pass = { - let vertex_buffer = canvas.graphics.upload_verts( - canvas.width as _, - canvas.height as _, - self.rect.x, - self.rect.y, - self.rect.w, - self.rect.h, - )?; - - let clamped_radius = self - .corner_radius - .min(self.rect.w / 2.0) - .min(self.rect.h / 2.0); - - let skew_radius = [clamped_radius / self.rect.w, clamped_radius / self.rect.h]; - - let set0 = canvas.pipeline_bg_color.uniform_buffer( - 0, - vec![ - self.bg_color.x, - self.bg_color.y, - self.bg_color.z, - self.bg_color.w, - skew_radius[0], - skew_radius[1], - ], - )?; - - canvas.pipeline_bg_color.create_pass( - [canvas.width as _, canvas.height as _], - vertex_buffer, - canvas.graphics.quad_indices.clone(), - vec![set0], - )? - }; - - cmd_buffer.run_ref(&pass) - } - - pub(super) fn render_highlight( - &self, - canvas: &CanvasData, - _: &mut AppState, - cmd_buffer: &mut WlxCommandBuffer, - color: GuiColor, - ) -> anyhow::Result<()> { - let vertex_buffer = canvas.graphics.upload_verts( - canvas.width as _, - canvas.height as _, - self.rect.x, - self.rect.y, - self.rect.w, - self.rect.h, - )?; - - let clamped_radius = self - .corner_radius - .min(self.rect.w / 2.0) - .min(self.rect.h / 2.0); - - let skew_radius = [clamped_radius / self.rect.w, clamped_radius / self.rect.h]; - - let set0 = canvas.pipeline_hl_color.uniform_buffer( - 0, - vec![ - color.x, - color.y, - color.z, - color.w, - skew_radius[0], - skew_radius[1], - ], - )?; - - let pass = canvas.pipeline_hl_color.create_pass( - [canvas.width as _, canvas.height as _], - vertex_buffer, - canvas.graphics.quad_indices.clone(), - vec![set0], - )?; - - cmd_buffer.run_ref(&pass) - } - - pub(super) fn render_text( - &self, - canvas: &CanvasData, - app: &mut AppState, - cmd_buffer: &mut WlxCommandBuffer, - ) -> anyhow::Result<()> { - let mut cur_y = self.rect.y; - for line in self.text.lines() { - let mut cur_x = self.rect.x; - for glyph in app - .fc - .get_glyphs(line, self.size, canvas.graphics.clone())? - { - if let Some(tex) = glyph.tex.clone() { - let vertex_buffer = canvas.graphics.upload_verts( - canvas.width as _, - canvas.height as _, - cur_x + glyph.left, - cur_y - glyph.top, - glyph.width, - glyph.height, - )?; - let set0 = canvas.pipeline_fg_glyph.uniform_sampler( - 0, - ImageView::new_default(tex)?, - app.graphics.texture_filtering, - )?; - let set1 = canvas - .pipeline_fg_glyph - .uniform_buffer(1, self.fg_color.to_array().to_vec())?; - let pass = canvas.pipeline_fg_glyph.create_pass( - [canvas.width as _, canvas.height as _], - vertex_buffer, - canvas.graphics.quad_indices.clone(), - vec![set0, set1], - )?; - cmd_buffer.run_ref(&pass)?; - } - cur_x += glyph.advance; - } - cur_y += (self.size as f32) * 1.5; - } - Ok(()) - } - - pub(super) fn render_text_centered( - &self, - canvas: &CanvasData, - app: &mut AppState, - cmd_buffer: &mut WlxCommandBuffer, - ) -> anyhow::Result<()> { - let (w, h) = app - .fc - .get_text_size(&self.text, self.size, canvas.graphics.clone())?; - - let mut cur_y = - (self.size as f32).mul_add(-0.25, h.mul_add(-0.5, self.rect.y + (self.rect.h))); - for line in self.text.lines() { - let mut cur_x = w.mul_add(-0.5, self.rect.w.mul_add(0.5, self.rect.x)); - for glyph in app - .fc - .get_glyphs(line, self.size, canvas.graphics.clone())? - { - if let Some(tex) = glyph.tex.clone() { - let vertex_buffer = canvas.graphics.upload_verts( - canvas.width as _, - canvas.height as _, - cur_x + glyph.left, - cur_y - glyph.top, - glyph.width, - glyph.height, - )?; - let set0 = canvas.pipeline_fg_glyph.uniform_sampler( - 0, - ImageView::new_default(tex)?, - app.graphics.texture_filtering, - )?; - let set1 = canvas - .pipeline_fg_glyph - .uniform_buffer(1, self.fg_color.to_array().to_vec())?; - let pass = canvas.pipeline_fg_glyph.create_pass( - [canvas.width as _, canvas.height as _], - vertex_buffer, - canvas.graphics.quad_indices.clone(), - vec![set0, set1], - )?; - cmd_buffer.run_ref(&pass)?; - } - cur_x += glyph.advance; - } - cur_y += (self.size as f32) * 1.5; - } - Ok(()) - } - - pub(super) fn render_sprite_bg( - &self, - canvas: &CanvasData, - app: &mut AppState, - cmd_buffer: &mut WlxCommandBuffer, - ) -> anyhow::Result<()> { - let Some(view) = self.sprite.as_ref() else { - return Ok(()); - }; - - let vertex_buffer = canvas.graphics.upload_verts( - canvas.width as _, - canvas.height as _, - self.rect.x, - self.rect.y, - self.rect.w, - self.rect.h, - )?; - let set0 = canvas.pipeline_bg_sprite.uniform_sampler( - 0, - view.clone(), - app.graphics.texture_filtering, - )?; - - let uniform = vec![ - self.sprite_st.x, - self.sprite_st.y, - self.sprite_st.z, - self.sprite_st.w, - self.fg_color.x, - self.fg_color.y, - self.fg_color.z, - self.fg_color.w, - ]; - - let set1 = canvas.pipeline_bg_sprite.uniform_buffer(1, uniform)?; - - let pass = canvas.pipeline_bg_sprite.create_pass( - [canvas.width as _, canvas.height as _], - vertex_buffer, - canvas.graphics.quad_indices.clone(), - vec![set0, set1], - )?; - cmd_buffer.run_ref(&pass)?; - Ok(()) - } - - #[allow(dead_code)] - pub(super) fn render_sprite_hl( - &self, - canvas: &CanvasData, - app: &mut AppState, - cmd_buffer: &mut WlxCommandBuffer, - color: GuiColor, - ) -> anyhow::Result<()> { - let Some(view) = self.sprite.as_ref() else { - return Ok(()); - }; - - let vertex_buffer = canvas.graphics.upload_verts( - canvas.width as _, - canvas.height as _, - self.rect.x, - self.rect.y, - self.rect.w, - self.rect.h, - )?; - let set0 = canvas.pipeline_hl_sprite.uniform_sampler( - 0, - view.clone(), - app.graphics.texture_filtering, - )?; - - let uniform = vec![ - self.sprite_st.x, - self.sprite_st.y, - self.sprite_st.z, - self.sprite_st.w, - color.x, - color.y, - color.z, - color.w, - ]; - - let set1 = canvas.pipeline_hl_sprite.uniform_buffer(1, uniform)?; - - let pass = canvas.pipeline_hl_sprite.create_pass( - [canvas.width as _, canvas.height as _], - vertex_buffer, - canvas.graphics.quad_indices.clone(), - vec![set0, set1], - )?; - cmd_buffer.run_ref(&pass)?; - Ok(()) - } -} diff --git a/src/gui/canvas/mod.rs b/src/gui/canvas/mod.rs deleted file mode 100644 index ae5e837..0000000 --- a/src/gui/canvas/mod.rs +++ /dev/null @@ -1,371 +0,0 @@ -pub mod builder; -pub mod control; - -use std::sync::Arc; - -use glam::{Vec2, Vec4}; -use vulkano::{command_buffer::CommandBufferUsage, format::Format, image::view::ImageView}; - -use crate::{ - backend::{ - input::{Haptics, InteractionHandler, PointerHit}, - overlay::{FrameMeta, OverlayBackend, OverlayRenderer, ShouldRender}, - }, - graphics::{CommandBuffers, WlxGraphics, WlxPipeline, BLEND_ALPHA}, - state::AppState, -}; - -const RES_DIVIDER: usize = 4; - -pub struct Rect { - x: f32, - y: f32, - w: f32, - h: f32, -} - -pub struct CanvasData { - pub data: D, - pub width: usize, - pub height: usize, - - graphics: Arc, - - pipeline_bg_color: Arc, - pipeline_bg_sprite: Arc, - pipeline_fg_glyph: Arc, - pipeline_hl_color: Arc, - pipeline_hl_sprite: Arc, -} - -pub struct Canvas { - controls: Vec>, - data: CanvasData, - - hover_controls: [Option; 2], - pressed_controls: [Option; 2], - - interact_map: Vec>, - interact_stride: usize, - interact_rows: usize, - - pipeline_final: Arc, - - view_fore: Arc, - view_back: Arc, - - format: Format, - - back_dirty: bool, - high_dirty: bool, - fore_dirty: bool, -} - -impl Canvas { - fn new( - width: usize, - height: usize, - graphics: Arc, - format: Format, - data: D, - ) -> anyhow::Result { - let tex_fore = graphics.render_texture(width as _, height as _, format)?; - let tex_back = graphics.render_texture(width as _, height as _, format)?; - - let view_fore = ImageView::new_default(tex_fore)?; - let view_back = ImageView::new_default(tex_back)?; - - let Ok(shaders) = graphics.shared_shaders.read() else { - anyhow::bail!("Failed to lock shared shaders for reading"); - }; - - let vert = shaders.get("vert_common").unwrap().clone(); // want panic - - let pipeline_bg_color = graphics.create_pipeline( - vert.clone(), - shaders.get("frag_color").unwrap().clone(), // want panic - format, - Some(BLEND_ALPHA), - )?; - - let pipeline_fg_glyph = graphics.create_pipeline( - vert.clone(), - shaders.get("frag_glyph").unwrap().clone(), // want panic - format, - Some(BLEND_ALPHA), - )?; - - let pipeline_bg_sprite = graphics.create_pipeline( - vert.clone(), - shaders.get("frag_sprite2").unwrap().clone(), // want panic - format, - Some(BLEND_ALPHA), - )?; - - let pipeline_hl_color = graphics.create_pipeline( - vert.clone(), - shaders.get("frag_color").unwrap().clone(), // want panic - graphics.native_format, - Some(BLEND_ALPHA), - )?; - - let pipeline_hl_sprite = graphics.create_pipeline( - vert.clone(), - shaders.get("frag_sprite2_hl").unwrap().clone(), // want panic - graphics.native_format, - Some(BLEND_ALPHA), - )?; - - let pipeline_final = graphics.create_pipeline( - vert, - shaders.get("frag_srgb").unwrap().clone(), // want panic - graphics.native_format, - Some(BLEND_ALPHA), - )?; - - let stride = width / RES_DIVIDER; - let rows = height / RES_DIVIDER; - - Ok(Self { - data: CanvasData { - data, - width, - height, - graphics: graphics.clone(), - pipeline_bg_color, - pipeline_bg_sprite, - pipeline_fg_glyph, - pipeline_hl_color, - pipeline_hl_sprite, - }, - controls: Vec::new(), - hover_controls: [None, None], - pressed_controls: [None, None], - interact_map: vec![None; stride * rows], - interact_stride: stride, - interact_rows: rows, - pipeline_final, - view_fore, - view_back, - format, - back_dirty: false, - high_dirty: false, - fore_dirty: false, - }) - } - - fn interactive_set_idx(&mut self, x: f32, y: f32, w: f32, h: f32, idx: usize) { - let (x, y, w, h) = (x as usize, y as usize, w as usize, h as usize); - - let x_min = (x / RES_DIVIDER).max(0); - let y_min = (y / RES_DIVIDER).max(0); - let x_max = (x_min + (w / RES_DIVIDER)).min(self.interact_stride - 1); - let y_max = (y_min + (h / RES_DIVIDER)).min(self.interact_rows - 1); - - for y in y_min..y_max { - for x in x_min..x_max { - self.interact_map[y * self.interact_stride + x] = Some(idx as u16); - } - } - } - - fn interactive_get_idx(&self, uv: Vec2) -> Option { - let x = (uv.x * self.data.width as f32) as usize; - let y = (uv.y * self.data.height as f32) as usize; - let x = (x / RES_DIVIDER).max(0).min(self.interact_stride - 1); - let y = (y / RES_DIVIDER).max(0).min(self.interact_rows - 1); - self.interact_map[y * self.interact_stride + x].map(|x| x as usize) - } - - pub const fn data_mut(&mut self) -> &mut D { - &mut self.data.data - } -} - -impl InteractionHandler for Canvas { - fn on_left(&mut self, _app: &mut AppState, pointer: usize) { - self.high_dirty = true; - - self.hover_controls[pointer] = None; - } - fn on_hover(&mut self, _app: &mut AppState, hit: &PointerHit) -> Option { - // render on every frame if we are being hovered - self.high_dirty = true; - - let old = self.hover_controls[hit.pointer]; - if let Some(i) = self.interactive_get_idx(hit.uv) { - self.hover_controls[hit.pointer] = Some(i); - } else { - self.hover_controls[hit.pointer] = None; - } - if old == self.hover_controls[hit.pointer] { - None - } else { - Some(Haptics { - intensity: 0.1, - duration: 0.01, - frequency: 5.0, - }) - } - } - fn on_pointer(&mut self, app: &mut AppState, hit: &PointerHit, pressed: bool) { - let idx = if pressed { - self.interactive_get_idx(hit.uv) - } else { - self.pressed_controls[hit.pointer] - }; - - if let Some(idx) = idx { - let c = &mut self.controls[idx]; - if pressed { - if let Some(ref mut f) = c.on_press { - self.pressed_controls[hit.pointer] = Some(idx); - f(c, &mut self.data.data, app, hit.mode); - } - } else if let Some(ref mut f) = c.on_release { - self.pressed_controls[hit.pointer] = None; - f(c, &mut self.data.data, app); - } - } - } - fn on_scroll(&mut self, app: &mut AppState, hit: &PointerHit, delta_y: f32, delta_x: f32) { - let idx = self.hover_controls[hit.pointer]; - - if let Some(idx) = idx { - let c = &mut self.controls[idx]; - if let Some(ref mut f) = c.on_scroll { - f(c, &mut self.data.data, app, delta_y, delta_x); - } - } - } -} - -impl OverlayRenderer for Canvas { - fn init(&mut self, _app: &mut AppState) -> anyhow::Result<()> { - Ok(()) - } - fn pause(&mut self, _app: &mut AppState) -> anyhow::Result<()> { - Ok(()) - } - fn resume(&mut self, _app: &mut AppState) -> anyhow::Result<()> { - Ok(()) - } - fn should_render(&mut self, app: &mut AppState) -> anyhow::Result { - for c in &mut self.controls { - if let Some(fun) = c.on_update { - fun(c, &mut self.data.data, app); - } - if c.fg_dirty { - self.fore_dirty = true; - c.fg_dirty = false; - } - if c.bg_dirty { - self.back_dirty = true; - c.bg_dirty = false; - } - } - - if self.back_dirty || self.fore_dirty || self.high_dirty { - Ok(ShouldRender::Should) - } else { - Ok(ShouldRender::Can) - } - } - fn render( - &mut self, - app: &mut AppState, - tgt: Arc, - buf: &mut CommandBuffers, - alpha: f32, - ) -> anyhow::Result { - self.high_dirty = false; - - let mut cmd_buffer = self - .data - .graphics - .create_command_buffer(CommandBufferUsage::OneTimeSubmit)?; - - if self.back_dirty { - cmd_buffer.begin_rendering(self.view_back.clone())?; - for c in &mut self.controls { - if let Some(fun) = c.on_render_bg { - fun(c, &self.data, app, &mut cmd_buffer)?; - } - } - cmd_buffer.end_rendering()?; - self.back_dirty = false; - } - if self.fore_dirty { - cmd_buffer.begin_rendering(self.view_fore.clone())?; - for c in &mut self.controls { - if let Some(fun) = c.on_render_fg { - fun(c, &self.data, app, &mut cmd_buffer)?; - } - } - cmd_buffer.end_rendering()?; - self.fore_dirty = false; - } - - let set0_fg = self.pipeline_final.uniform_sampler( - 0, - self.view_fore.clone(), - app.graphics.texture_filtering, - )?; - let set0_bg = self.pipeline_final.uniform_sampler( - 0, - self.view_back.clone(), - app.graphics.texture_filtering, - )?; - let set1 = self.pipeline_final.uniform_buffer(1, vec![alpha])?; - - let pass_fore = self - .pipeline_final - .create_pass_for_target(tgt.clone(), vec![set0_fg, set1.clone()])?; - - let pass_back = self - .pipeline_final - .create_pass_for_target(tgt.clone(), vec![set0_bg, set1])?; - - cmd_buffer.begin_rendering(tgt)?; - cmd_buffer.run_ref(&pass_back)?; - - for (i, c) in self.controls.iter_mut().enumerate() { - if let Some(render) = c.on_render_hl { - if let Some(test) = c.test_highlight { - if let Some(hl_color) = test(c, &mut self.data.data, app) { - render(c, &self.data, app, &mut cmd_buffer, hl_color)?; - } - } - if self.hover_controls.contains(&Some(i)) { - render( - c, - &self.data, - app, - &mut cmd_buffer, - Vec4::new(1., 1., 1., 0.3), - )?; - } - } - } - - // mostly static text - cmd_buffer.run_ref(&pass_fore)?; - - cmd_buffer.end_rendering()?; - buf.push(cmd_buffer.build()?); - Ok(true) - } - - fn frame_meta(&mut self) -> Option { - Some(FrameMeta { - extent: [self.data.width as _, self.data.height as _, 1], - format: self.format, - ..Default::default() - }) - } -} - -impl OverlayBackend for Canvas { - fn set_renderer(&mut self, _renderer: Box) {} - fn set_interaction(&mut self, _interaction: Box) {} -} diff --git a/src/gui/font.rs b/src/gui/font.rs deleted file mode 100644 index 3bb24d9..0000000 --- a/src/gui/font.rs +++ /dev/null @@ -1,268 +0,0 @@ -use std::{rc::Rc, str::FromStr, sync::Arc}; - -use fontconfig::{FontConfig, OwnedPattern}; -use freetype::{bitmap::PixelMode, face::LoadFlag, Face, Library}; -use idmap::IdMap; -use vulkano::{command_buffer::CommandBufferUsage, format::Format, image::Image}; - -use crate::graphics::{WlxGraphics, WlxUploadsBuffer}; - -pub struct FontCache { - primary_font: Arc, - fc: FontConfig, - ft: Library, - collections: IdMap, -} - -struct FontCollection { - fonts: Vec, - cp_map: IdMap, - zero_glyph: Rc, -} - -struct Font { - face: Face, - glyphs: IdMap>, -} - -pub struct Glyph { - pub tex: Option>, - pub top: f32, - pub left: f32, - pub width: f32, - pub height: f32, - pub advance: f32, -} - -impl FontCache { - pub fn new(primary_font: Arc) -> anyhow::Result { - let ft = Library::init()?; - let fc = FontConfig::default(); - - Ok(Self { - primary_font, - fc, - ft, - collections: IdMap::new(), - }) - } - - pub fn get_text_size( - &mut self, - text: &str, - size: isize, - graphics: Arc, - ) -> anyhow::Result<(f32, f32)> { - let sizef = size as f32; - - let height = ((text.lines().count() as f32) - 1f32).mul_add(sizef * 1.5, sizef); - let mut cmd_buffer = None; - - let mut max_w = sizef * 0.33; - for line in text.lines() { - let w: f32 = line - .chars() - .filter_map(|c| { - self.get_glyph_for_cp(c as usize, size, graphics.clone(), &mut cmd_buffer) - .map(|glyph| glyph.advance) - .ok() - }) - .sum(); - - if w > max_w { - max_w = w; - } - } - - if let Some(cmd_buffer) = cmd_buffer { - cmd_buffer.build_and_execute_now()?; - } - - Ok((max_w, height)) - } - - pub fn get_glyphs( - &mut self, - text: &str, - size: isize, - graphics: Arc, - ) -> anyhow::Result>> { - let mut glyphs = Vec::new(); - let mut cmd_buffer = None; - - for line in text.lines() { - for c in line.chars() { - glyphs.push(self.get_glyph_for_cp( - c as usize, - size, - graphics.clone(), - &mut cmd_buffer, - )?); - } - } - - if let Some(cmd_buffer) = cmd_buffer { - cmd_buffer.build_and_execute_now()?; - } - - Ok(glyphs) - } - - fn get_font_for_cp(&mut self, cp: usize, size: isize) -> usize { - if !self.collections.contains_key(size) { - self.collections.insert( - size, - FontCollection { - fonts: Vec::new(), - cp_map: IdMap::new(), - zero_glyph: Rc::new(Glyph { - tex: None, - top: 0., - left: 0., - width: 0., - height: 0., - advance: size as f32 / 3., - }), - }, - ); - } - let coll = self.collections.get_mut(size).unwrap(); // safe because of the insert above - - if let Some(font) = coll.cp_map.get(cp) { - return *font; - } - - let primary_font = self.primary_font.clone(); - let pattern_str = format!("{primary_font}:size={size}:charset={cp:04x}"); - let mut pattern = OwnedPattern::from_str(&pattern_str).unwrap(); // safe because PRIMARY_FONT is const - self.fc - .substitute(&mut pattern, fontconfig::MatchKind::Pattern); - pattern.default_substitute(); - - let pattern = pattern.font_match(&mut self.fc); - - if let Some(path) = pattern.filename() { - let name = pattern.name().unwrap_or(path); - log::debug!("Loading font: {name} {size}pt"); - - let font_idx = pattern.face_index().unwrap_or(0); - - let face = match self.ft.new_face(path, font_idx as _) { - Ok(face) => face, - Err(e) => { - log::warn!("Failed to load font at {path}: {e:?}"); - coll.cp_map.insert(cp, 0); - return 0; - } - }; - match face.set_char_size(size << 6, size << 6, 96, 96) { - Ok(()) => {} - Err(e) => { - log::warn!("Failed to set font size: {e:?}"); - coll.cp_map.insert(cp, 0); - return 0; - } - } - - let idx = coll.fonts.len(); - for (cp, _) in face.chars() { - if coll.cp_map.contains_key(cp) { - continue; - } - coll.cp_map.insert(cp, idx); - } - - if !coll.cp_map.contains_key(cp) { - log::warn!("Got font '{name}' for CP 0x{cp:x}, but CP is not present in font!",); - coll.cp_map.insert(cp, 0); - } - - let zero_glyph = Rc::new(Glyph { - tex: None, - top: 0., - left: 0., - width: 0., - height: 0., - advance: size as f32 / 3., - }); - let mut glyphs = IdMap::new(); - glyphs.insert(0, zero_glyph); - - let font = Font { face, glyphs }; - coll.fonts.push(font); - - return idx; - } - coll.cp_map.insert(cp, 0); - 0 - } - - fn get_glyph_for_cp( - &mut self, - cp: usize, - size: isize, - graphics: Arc, - cmd_buffer: &mut Option, - ) -> anyhow::Result> { - let key = self.get_font_for_cp(cp, size); - - let Some(font) = &mut self.collections[size].fonts.get_mut(key) else { - log::warn!("No font found for codepoint: 0x{cp:x}"); - return Ok(self.collections[size].zero_glyph.clone()); - }; - - if let Some(glyph) = font.glyphs.get(cp) { - return Ok(glyph.clone()); - } - - if font.face.load_char(cp, LoadFlag::DEFAULT).is_err() { - return Ok(self.collections[size].zero_glyph.clone()); - } - - let glyph = font.face.glyph(); - if glyph.render_glyph(freetype::RenderMode::Normal).is_err() { - return Ok(self.collections[size].zero_glyph.clone()); - } - - let bmp = glyph.bitmap(); - let buf = bmp.buffer().to_vec(); - if buf.is_empty() { - return Ok(self.collections[size].zero_glyph.clone()); - } - - let metrics = glyph.metrics(); - - let format = match bmp.pixel_mode() { - Ok(PixelMode::Gray) => Format::R8_UNORM, - Ok(PixelMode::Gray2) => Format::R16_SFLOAT, - Ok(PixelMode::Gray4) => Format::R32_SFLOAT, - _ => return Ok(self.collections[size].zero_glyph.clone()), - }; - - if cmd_buffer.is_none() { - *cmd_buffer = Some(graphics.create_uploads_command_buffer( - graphics.transfer_queue.clone(), - CommandBufferUsage::OneTimeSubmit, - )?); - } - - let texture = cmd_buffer.as_mut().unwrap().texture2d_raw( - bmp.width() as _, - bmp.rows() as _, - format, - &buf, - )?; - - let g = Glyph { - tex: Some(texture), - top: (metrics.horiBearingY >> 6i64) as _, - left: (metrics.horiBearingX >> 6i64) as _, - advance: (metrics.horiAdvance >> 6i64) as _, - width: bmp.width() as _, - height: bmp.rows() as _, - }; - - font.glyphs.insert(cp, Rc::new(g)); - Ok(font.glyphs[cp].clone()) - } -} diff --git a/src/gui/mod.rs b/src/gui/mod.rs index 939f28f..8ccb048 100644 --- a/src/gui/mod.rs +++ b/src/gui/mod.rs @@ -1,61 +1,3 @@ -use std::sync::LazyLock; - -use glam::Vec4; - -pub mod canvas; -pub mod font; -pub mod modular; - -pub type GuiColor = Vec4; -pub static FALLBACK_COLOR: LazyLock = LazyLock::new(|| Vec4::new(1., 0., 1., 1.)); - -// Parses a color from a HTML hex string -pub fn color_parse(html_hex: &str) -> anyhow::Result { - if html_hex.len() == 7 { - if let (Ok(r), Ok(g), Ok(b)) = ( - u8::from_str_radix(&html_hex[1..3], 16), - u8::from_str_radix(&html_hex[3..5], 16), - u8::from_str_radix(&html_hex[5..7], 16), - ) { - return Ok(Vec4::new( - f32::from(r) / 255., - f32::from(g) / 255., - f32::from(b) / 255., - 1., - )); - } - } else if html_hex.len() == 9 { - if let (Ok(r), Ok(g), Ok(b), Ok(a)) = ( - u8::from_str_radix(&html_hex[1..3], 16), - u8::from_str_radix(&html_hex[3..5], 16), - u8::from_str_radix(&html_hex[5..7], 16), - u8::from_str_radix(&html_hex[7..9], 16), - ) { - return Ok(Vec4::new( - f32::from(r) / 255., - f32::from(g) / 255., - f32::from(b) / 255., - f32::from(a) / 255., - )); - } - } - anyhow::bail!( - "Invalid color string: '{}', must be 7 characters long (e.g. #FF00FF)", - &html_hex - ) -} - -pub enum KeyCapType { - /// Label is in center of keycap - Regular, - /// Label on the top - /// AltGr symbol on bottom - RegularAltGr, - /// Primary symbol on bottom - /// Shift symbol on top - Reversed, - /// Primary symbol on bottom-left - /// Shift symbol on top-left - /// AltGr symbol on bottom-right - ReversedAltGr, -} +mod asset; +pub mod panel; +mod timestep; diff --git a/src/gui/modular/button.rs b/src/gui/modular/button.rs deleted file mode 100644 index 44bd062..0000000 --- a/src/gui/modular/button.rs +++ /dev/null @@ -1,867 +0,0 @@ -use std::{ - f32::consts::PI, - ops::Add, - process::{self, Child}, - sync::Arc, - time::{Duration, Instant}, -}; - -use glam::{Quat, Vec4}; -use serde::Deserialize; - -use crate::{ - backend::{ - common::OverlaySelector, - input::PointerMode, - overlay::Positioning, - task::{ColorChannel, SystemTask, TaskType}, - }, - config::{save_layout, save_settings, AStrSetExt}, - hid::VirtualKey, - overlays::{ - toast::{error_toast, Toast, ToastTopic}, - watch::WATCH_NAME, - }, - state::AppState, -}; - -#[cfg(any(not(feature = "wayvr"), not(feature = "osc")))] -use crate::overlays::toast::error_toast_str; - -#[cfg(feature = "osc")] -use rosc::OscType; - -use super::{ExecArgs, ModularControl, ModularData}; - -#[derive(Deserialize, Clone)] -pub enum PressRelease { - Release, - Press, -} - -#[derive(Deserialize, Clone, Copy)] -pub enum ViewAngleKind { - /// The cosine of the angle at which the watch becomes fully transparent - MinOpacity, - /// The cosine of the angle at which the watch becomes fully opaque - MaxOpacity, -} - -#[derive(Deserialize, Clone, Copy)] -pub enum Axis { - X, - Y, - Z, -} - -#[derive(Deserialize, Clone)] -pub enum HighlightTest { - AllowSliding, - AutoRealign, - NotificationSounds, - Notifications, - RorateLock, -} - -#[derive(Deserialize, Clone)] -pub enum SystemAction { - ToggleAllowSliding, - ToggleAutoRealign, - ToggleNotificationSounds, - ToggleNotifications, - ToggleRotateLock, - PlayspaceResetOffset, - PlayspaceFixFloor, - RecalculateExtent, - PersistConfig, - PersistLayout, -} - -#[derive(Deserialize, Clone)] -pub enum WatchAction { - /// Hide the watch until Show/Hide binding is used - Hide, - /// Switch the watch to the opposite controller - SwitchHands, - /// Change the fade behavior of the watch - ViewAngle { - kind: ViewAngleKind, - delta: f32, - }, - Rotation { - axis: Axis, - delta: f32, - }, - Position { - axis: Axis, - delta: f32, - }, -} - -#[derive(Deserialize, Clone)] -pub enum OverlayAction { - /// Reset the overlay to be in front of the HMD with its original scale - Reset, - /// Toggle the visibility of the overlay - ToggleVisible, - /// Toggle the ability to grab and recenter the overlay - ToggleImmovable, - /// Toggle the ability of the overlay to reacto to laser pointer - ToggleInteraction, - /// Change the opacity of the overlay - Opacity { delta: f32 }, -} - -#[derive(Deserialize, Clone)] -pub enum WindowAction { - /// Create a new mirror window, or show/hide an existing one - ShowMirror, - /// Create a new UI window, or show/hide an existing one - ShowUi, - /// Destroy a previously created window, if it exists - Destroy, -} - -#[derive(Deserialize, Clone)] -pub enum WayVRDisplayClickAction { - ToggleVisibility, - Reset, -} - -#[derive(Deserialize, Clone)] -#[allow(dead_code)] // in case if WayVR feature is disabled -pub enum WayVRAction { - AppClick { - catalog_name: Arc, - app_name: Arc, - }, - DisplayClick { - display_name: Arc, - action: WayVRDisplayClickAction, - }, - ToggleDashboard, -} - -#[derive(Deserialize, Clone)] -#[serde(tag = "type")] -pub enum ButtonAction { - Exec { - command: ExecArgs, - toast: Option>, - }, - VirtualKey { - keycode: VirtualKey, - action: PressRelease, - }, - Watch { - action: WatchAction, - }, - Overlay { - target: OverlaySelector, - action: OverlayAction, - }, - // Ignored if "wayvr" feature is not enabled - WayVR { - action: WayVRAction, - }, - Window { - target: Arc, - action: WindowAction, - }, - Toast { - message: Arc, - body: Option>, - seconds: Option, - }, - ColorAdjust { - channel: ColorChannel, - delta: f32, - }, - DragMultiplier { - delta: f32, - }, - System { - action: SystemAction, - }, - SendOscValue { - parameter: Arc, - values: Option>, - }, -} - -#[derive(Deserialize, Clone)] -#[serde(tag = "type")] -#[cfg(feature = "osc")] -pub enum OscValue { - Int { value: i32 }, - Float { value: f32 }, - String { value: String }, - Bool { value: bool }, -} -#[derive(Deserialize, Clone)] -#[serde(tag = "type")] -#[cfg(not(feature = "osc"))] -pub enum OscValue { - None, -} - -pub(super) struct PressData { - last_down: Instant, - last_mode: PointerMode, - child: Option, -} -impl Clone for PressData { - fn clone(&self) -> Self { - Self { - last_down: self.last_down, - last_mode: self.last_mode, - child: None, - } - } -} -impl Default for PressData { - fn default() -> Self { - Self { - last_down: Instant::now(), - last_mode: PointerMode::Left, - child: None, - } - } -} - -#[derive(Deserialize, Default, Clone)] -pub struct ButtonData { - #[serde(skip)] - pub(super) press: PressData, - - pub(super) click_down: Option>, - pub(super) click_up: Option>, - pub(super) long_click_up: Option>, - pub(super) right_down: Option>, - pub(super) right_up: Option>, - pub(super) long_right_up: Option>, - pub(super) middle_down: Option>, - pub(super) middle_up: Option>, - pub(super) long_middle_up: Option>, - pub(super) scroll_down: Option>, - pub(super) scroll_up: Option>, - pub(super) highlight: Option, -} - -pub fn modular_button_init(button: &mut ModularControl, data: &ButtonData) { - button.state = Some(ModularData::Button(Box::new(data.clone()))); - button.on_press = Some(modular_button_dn); - button.on_release = Some(modular_button_up); - button.on_scroll = Some(modular_button_scroll); - button.test_highlight = Some(modular_button_highlight); -} - -fn modular_button_dn( - button: &mut ModularControl, - _: &mut (), - app: &mut AppState, - mode: PointerMode, -) { - // want panic - let ModularData::Button(data) = button.state.as_mut().unwrap() else { - panic!("modular_button_dn: button state is not Button"); - }; - - data.press.last_down = Instant::now(); - data.press.last_mode = mode; - - let actions = match mode { - PointerMode::Left => data.click_down.as_ref(), - PointerMode::Right => data.right_down.as_ref(), - PointerMode::Middle => data.middle_down.as_ref(), - _ => None, - }; - - if let Some(actions) = actions { - for action in actions { - handle_action(action, &mut data.press, app); - } - } -} - -fn modular_button_up(button: &mut ModularControl, _: &mut (), app: &mut AppState) { - // want panic - let ModularData::Button(data) = button.state.as_mut().unwrap() else { - panic!("modular_button_up: button state is not Button"); - }; - - let now = Instant::now(); - let duration = now - data.press.last_down; - let long_press = duration.as_secs_f32() > app.session.config.long_press_duration; - - let actions = match data.press.last_mode { - PointerMode::Left => { - if long_press { - data.long_click_up.as_ref() - } else { - data.click_up.as_ref() - } - } - PointerMode::Right => { - if long_press { - data.long_right_up.as_ref() - } else { - data.right_up.as_ref() - } - } - PointerMode::Middle => { - if long_press { - data.long_middle_up.as_ref() - } else { - data.middle_up.as_ref() - } - } - _ => None, - }; - - if let Some(actions) = actions { - for action in actions { - handle_action(action, &mut data.press, app); - } - } -} - -fn modular_button_scroll( - button: &mut ModularControl, - _: &mut (), - app: &mut AppState, - delta_y: f32, - _delta_x: f32, -) { - // want panic - let ModularData::Button(data) = button.state.as_mut().unwrap() else { - panic!("modular_button_scroll: button state is not Button"); - }; - - let actions = if delta_y < 0.0 { - data.scroll_down.as_ref() - } else { - data.scroll_up.as_ref() - }; - - if let Some(actions) = actions { - for action in actions { - handle_action(action, &mut data.press, app); - } - } -} - -fn modular_button_highlight( - button: &ModularControl, - _: &mut (), - app: &mut AppState, -) -> Option { - // want panic - let ModularData::Button(data) = button.state.as_ref().unwrap() else { - panic!("modular_button_highlight: button state is not Button"); - }; - - if let Some(test) = &data.highlight { - let lit = match test { - HighlightTest::AllowSliding => app.session.config.allow_sliding, - HighlightTest::AutoRealign => app.session.config.realign_on_showhide, - HighlightTest::NotificationSounds => app.session.config.notifications_sound_enabled, - HighlightTest::Notifications => app.session.config.notifications_enabled, - HighlightTest::RorateLock => !app.session.config.space_rotate_unlocked, - }; - - if lit { - return Some(Vec4::new(1.0, 1.0, 1.0, 0.5)); - } - } - None -} - -fn handle_action(action: &ButtonAction, press: &mut PressData, app: &mut AppState) { - match action { - ButtonAction::Exec { command, toast } => run_exec(command, toast.clone(), press, app), - ButtonAction::Watch { action } => run_watch(action, app), - ButtonAction::Overlay { target, action } => run_overlay(target, action, app), - ButtonAction::Window { target, action } => run_window(target, action, app), - ButtonAction::WayVR { action } => { - #[cfg(feature = "wayvr")] - { - app.tasks.enqueue(TaskType::WayVR(action.clone())); - } - #[cfg(not(feature = "wayvr"))] - { - let _ = &action; - error_toast_str(app, "WayVR feature is not enabled"); - } - } - ButtonAction::VirtualKey { keycode, action } => app - .hid_provider - .send_key(*keycode, matches!(*action, PressRelease::Press)), - ButtonAction::Toast { - message, - body, - seconds, - } => { - Toast::new( - ToastTopic::System, - message.clone(), - body.clone().unwrap_or_else(|| "".into()), - ) - .with_timeout(seconds.unwrap_or(5.)) - .submit(app); - } - ButtonAction::ColorAdjust { channel, delta } => { - let channel = *channel; - let delta = *delta; - app.tasks - .enqueue(TaskType::System(SystemTask::ColorGain(channel, delta))); - } - ButtonAction::System { action } => run_system(action, app), - ButtonAction::DragMultiplier { delta } => { - app.session.config.space_drag_multiplier += delta; - } - ButtonAction::SendOscValue { parameter, values } => { - #[cfg(feature = "osc")] - if let Some(ref mut sender) = app.osc_sender { - // convert OscValue to OscType - let mut converted: Vec = Vec::new(); - - for value in values.as_ref().unwrap() { - let converted_value = match value { - OscValue::Bool { value } => OscType::Bool(*value), - OscValue::Int { value } => OscType::Int(*value), - OscValue::Float { value } => OscType::Float(*value), - OscValue::String { value } => OscType::String(value.to_string()), - }; - - converted.push(converted_value); - } - - let _ = sender.send_single_param(parameter.to_string(), converted); - audio_thump(app); // play sound for feedback - } - - #[cfg(not(feature = "osc"))] - { - let _ = ¶meter; - let _ = &values; - error_toast_str(app, "OSC feature is not enabled"); - } - } - } -} - -const ENABLED_DISABLED: [&str; 2] = ["enabled", "disabled"]; - -#[allow(clippy::too_many_lines)] -fn run_system(action: &SystemAction, app: &mut AppState) { - match action { - SystemAction::ToggleAllowSliding => { - app.session.config.allow_sliding = !app.session.config.allow_sliding; - Toast::new( - ToastTopic::System, - format!( - "Sliding is {}.", - ENABLED_DISABLED[usize::from(app.session.config.allow_sliding)] - ) - .into(), - "".into(), - ) - .submit(app); - } - SystemAction::ToggleAutoRealign => { - app.session.config.realign_on_showhide = !app.session.config.realign_on_showhide; - Toast::new( - ToastTopic::System, - format!( - "Auto realign is {}.", - ENABLED_DISABLED[usize::from(app.session.config.realign_on_showhide)] - ) - .into(), - "".into(), - ) - .submit(app); - } - SystemAction::ToggleRotateLock => { - app.session.config.space_rotate_unlocked = !app.session.config.space_rotate_unlocked; - Toast::new( - ToastTopic::System, - format!( - "Space rotate axis lock now {}.", - ENABLED_DISABLED[usize::from(!app.session.config.space_rotate_unlocked)] - ) - .into(), - "".into(), - ) - .submit(app); - } - SystemAction::PlayspaceResetOffset => { - app.tasks - .enqueue(TaskType::System(SystemTask::ResetPlayspace)); - } - SystemAction::PlayspaceFixFloor => { - let now = Instant::now(); - let sec = Duration::from_secs(1); - for i in 0..5 { - let at = now.add(i * sec); - let display = 5 - i; - Toast::new( - ToastTopic::System, - format!("Fixing floor in {display}").into(), - "Place either controller on the floor.".into(), - ) - .with_timeout(1.0) - .submit_at(app, at); - } - app.tasks - .enqueue_at(TaskType::System(SystemTask::FixFloor), now.add(5 * sec)); - } - SystemAction::RecalculateExtent => { - todo!() - } - SystemAction::ToggleNotifications => { - app.session.config.notifications_enabled = !app.session.config.notifications_enabled; - Toast::new( - ToastTopic::System, - format!( - "Notifications are {}.", - ENABLED_DISABLED[usize::from(app.session.config.notifications_enabled)] - ) - .into(), - "".into(), - ) - .submit(app); - } - SystemAction::ToggleNotificationSounds => { - app.session.config.notifications_sound_enabled = - !app.session.config.notifications_sound_enabled; - Toast::new( - ToastTopic::System, - format!( - "Notification sounds are {}.", - ENABLED_DISABLED[usize::from(app.session.config.notifications_sound_enabled)] - ) - .into(), - "".into(), - ) - .submit(app); - } - SystemAction::PersistConfig => { - if let Err(e) = save_settings(&app.session.config) { - error_toast(app, "Failed to save config", e); - } - } - SystemAction::PersistLayout => { - if let Err(e) = save_layout(&app.session.config) { - error_toast(app, "Failed to save layout", e); - } - } - } -} - -fn run_exec(args: &ExecArgs, toast: Option>, press: &mut PressData, app: &mut AppState) { - if let Some(proc) = press.child.as_mut() { - match proc.try_wait() { - Ok(Some(code)) => { - if !code.success() { - error_toast(app, "Child process exited with code", code); - } - press.child = None; - } - Ok(None) => { - log::warn!("Unable to launch child process: previous child not exited yet"); - return; - } - Err(e) => { - press.child = None; - error_toast(app, "Error checking child process", e); - } - } - } - let args = args - .iter() - .map(std::convert::AsRef::as_ref) - .collect::>(); - match process::Command::new(args[0]).args(&args[1..]).spawn() { - Ok(proc) => { - press.child = Some(proc); - if let Some(toast) = toast.as_ref() { - Toast::new(ToastTopic::System, toast.clone(), "".into()).submit(app); - } - } - Err(e) => { - error_toast(app, &format!("Failed to spawn process {args:?}"), e); - } - } -} - -#[allow(clippy::too_many_lines)] -fn run_watch(data: &WatchAction, app: &mut AppState) { - match data { - WatchAction::Hide => { - app.tasks.enqueue(TaskType::Overlay( - OverlaySelector::Name(WATCH_NAME.into()), - Box::new(|app, o| { - if o.saved_transform.is_none() { - o.want_visible = false; - o.saved_transform = Some(o.transform); - Toast::new( - ToastTopic::System, - "Watch hidden".into(), - "Use show/hide binding to restore.".into(), - ) - .with_timeout(3.) - .submit(app); - } else { - o.want_visible = true; - o.saved_transform = None; - Toast::new(ToastTopic::System, "Watch restored".into(), "".into()) - .submit(app); - } - }), - )); - audio_thump(app); - } - WatchAction::SwitchHands => { - app.tasks.enqueue(TaskType::Overlay( - OverlaySelector::Name(WATCH_NAME.into()), - Box::new(|app, o| { - if matches!(o.positioning, Positioning::FollowHand { hand: 0, .. }) { - o.positioning = Positioning::FollowHand { hand: 1, lerp: 1.0 }; - o.spawn_rotation = app.session.config.watch_rot - * Quat::from_rotation_x(PI) - * Quat::from_rotation_z(PI); - o.spawn_point = app.session.config.watch_pos; - o.spawn_point.x *= -1.; - } else { - o.positioning = Positioning::FollowHand { hand: 0, lerp: 1.0 }; - o.spawn_rotation = app.session.config.watch_rot; - o.spawn_point = app.session.config.watch_pos; - } - o.dirty = true; - Toast::new( - ToastTopic::System, - "Watch switched".into(), - "Check your other hand".into(), - ) - .with_timeout(3.) - .submit(app); - }), - )); - audio_thump(app); - } - WatchAction::ViewAngle { kind, delta } => match kind { - ViewAngleKind::MinOpacity => { - let diff = (app.session.config.watch_view_angle_max - - app.session.config.watch_view_angle_min) - + delta; - - app.session.config.watch_view_angle_min = (app.session.config.watch_view_angle_max - - diff) - .clamp(0.0, app.session.config.watch_view_angle_max - 0.05); - } - ViewAngleKind::MaxOpacity => { - let diff = app.session.config.watch_view_angle_max - - app.session.config.watch_view_angle_min; - - app.session.config.watch_view_angle_max = - (app.session.config.watch_view_angle_max + delta).clamp(0.05, 1.0); - - app.session.config.watch_view_angle_min = (app.session.config.watch_view_angle_max - - diff) - .clamp(0.0, app.session.config.watch_view_angle_max - 0.05); - } - }, - WatchAction::Rotation { axis, delta } => { - let rot = match axis { - Axis::X => Quat::from_rotation_x(delta.to_radians()), - Axis::Y => Quat::from_rotation_y(delta.to_radians()), - Axis::Z => Quat::from_rotation_z(delta.to_radians()), - }; - app.tasks.enqueue(TaskType::Overlay( - OverlaySelector::Name(WATCH_NAME.into()), - Box::new(move |app, o| { - o.spawn_rotation *= rot; - app.session.config.watch_rot = o.spawn_rotation; - o.dirty = true; - }), - )); - } - WatchAction::Position { axis, delta } => { - let delta = *delta; - let axis = match axis { - Axis::X => 0, - Axis::Y => 1, - Axis::Z => 2, - }; - app.tasks.enqueue(TaskType::Overlay( - OverlaySelector::Name(WATCH_NAME.into()), - Box::new(move |app, o| { - o.spawn_point[axis] += delta; - app.session.config.watch_pos = o.spawn_point; - o.dirty = true; - }), - )); - } - } -} - -#[allow(clippy::too_many_lines)] -fn run_overlay(overlay: &OverlaySelector, action: &OverlayAction, app: &mut AppState) { - match action { - OverlayAction::Reset => { - app.tasks.enqueue(TaskType::Overlay( - overlay.clone(), - Box::new(|app, o| { - o.reset(app, true); - Toast::new( - ToastTopic::System, - format!("{} has been reset!", o.name).into(), - "".into(), - ) - .submit(app); - }), - )); - } - OverlayAction::ToggleVisible => { - app.tasks.enqueue(TaskType::Overlay( - overlay.clone(), - Box::new(|app, o| { - o.want_visible = !o.want_visible; - if o.recenter { - o.show_hide = o.want_visible; - o.reset(app, false); - } - - let mut state_dirty = false; - if !o.want_visible { - state_dirty |= app.session.config.show_screens.arc_rm(o.name.as_ref()); - } else if o.want_visible { - state_dirty |= app.session.config.show_screens.arc_set(o.name.clone()); - } - - if state_dirty { - match save_layout(&app.session.config) { - Ok(()) => log::debug!("Saved state"), - Err(e) => { - error_toast(app, "Failed to save state", e); - } - } - } - }), - )); - } - OverlayAction::ToggleImmovable => { - app.tasks.enqueue(TaskType::Overlay( - overlay.clone(), - Box::new(|app, o| { - o.recenter = !o.recenter; - o.grabbable = o.recenter; - o.show_hide = o.recenter; - if o.recenter { - Toast::new( - ToastTopic::System, - format!("{} is now unlocked!", o.name).into(), - "".into(), - ) - .submit(app); - } else { - Toast::new( - ToastTopic::System, - format!("{} is now locked in place!", o.name).into(), - "".into(), - ) - .submit(app); - } - }), - )); - audio_thump(app); - } - OverlayAction::ToggleInteraction => { - app.tasks.enqueue(TaskType::Overlay( - overlay.clone(), - Box::new(|app, o| { - o.interactable = !o.interactable; - if o.interactable { - Toast::new( - ToastTopic::System, - format!("{} is now interactable!", o.name).into(), - "".into(), - ) - .submit(app); - } else { - Toast::new( - ToastTopic::System, - format!("{} is now non-interactable!", o.name).into(), - "".into(), - ) - .submit(app); - } - }), - )); - audio_thump(app); - } - OverlayAction::Opacity { delta } => { - let delta = *delta; - app.tasks.enqueue(TaskType::Overlay( - overlay.clone(), - Box::new(move |_, o| { - o.alpha = (o.alpha + delta).clamp(0.1, 1.0); - o.dirty = true; - log::debug!("{}: alpha {}", o.name, o.alpha); - }), - )); - } - } -} - -fn run_window(window: &Arc, action: &WindowAction, app: &mut AppState) { - use crate::overlays::custom; - - match action { - WindowAction::ShowMirror => { - #[cfg(feature = "wayland")] - app.tasks.enqueue(TaskType::CreateOverlay( - OverlaySelector::Name(window.clone()), - Box::new({ - let name = window.clone(); - move |app| { - Toast::new( - ToastTopic::System, - "Check your desktop for popup.".into(), - "".into(), - ) - .with_sound(true) - .submit(app); - Some(crate::overlays::mirror::new_mirror( - name, - false, - &app.session, - )) - } - }), - )); - #[cfg(not(feature = "wayland"))] - log::warn!("Mirror not available without Wayland feature."); - } - WindowAction::ShowUi => { - app.tasks.enqueue(TaskType::CreateOverlay( - OverlaySelector::Name(window.clone()), - Box::new({ - let name = window.clone(); - move |app| custom::create_custom(app, name) - }), - )); - } - WindowAction::Destroy => { - app.tasks - .enqueue(TaskType::DropOverlay(OverlaySelector::Name(window.clone()))); - } - } -} - -const THUMP_AUDIO_WAV: &[u8] = include_bytes!("../../res/380885.wav"); - -fn audio_thump(app: &mut AppState) { - app.audio.play(THUMP_AUDIO_WAV); -} diff --git a/src/gui/modular/label.rs b/src/gui/modular/label.rs deleted file mode 100644 index 98626ea..0000000 --- a/src/gui/modular/label.rs +++ /dev/null @@ -1,305 +0,0 @@ -use chrono::Local; -use chrono_tz::Tz; -use glam::Vec4; -use smallvec::SmallVec; -use std::{ - io::Read, - process::{self, Stdio}, - sync::Arc, - time::Instant, -}; - -use crate::{ - gui::modular::FALLBACK_COLOR, - overlays::toast::{error_toast, error_toast_str}, - state::AppState, -}; - -use serde::Deserialize; - -use super::{color_parse_or_default, ExecArgs, GuiColor, ModularControl, ModularData}; - -#[derive(Deserialize)] -#[serde(untagged)] -pub enum TimezoneDef { - Idx(usize), - Str(Arc), -} - -#[derive(Deserialize)] -#[serde(tag = "source")] -pub enum LabelContent { - Static { - text: Arc, - }, - Exec { - command: ExecArgs, - interval: f32, - }, - Clock { - format: Arc, - timezone: Option, - }, - Timezone { - timezone: usize, - }, - Timer { - format: Arc, - }, - Battery { - device: usize, - low_threshold: f32, - low_color: Arc, - charging_color: Arc, - }, - DragMultiplier, - Ipd, -} - -pub enum LabelData { - Battery { - device: usize, - low_threshold: f32, - normal_color: GuiColor, - low_color: GuiColor, - charging_color: GuiColor, - }, - Clock { - format: Arc, - timezone: Option, - }, - Timer { - format: Arc, - start: Instant, - }, - Exec { - last_exec: Instant, - interval: f32, - command: Vec>, - child: Option, - }, - Ipd { - last_ipd: f32, - }, - DragMultiplier, -} - -pub fn modular_label_init(label: &mut ModularControl, content: &LabelContent, app: &AppState) { - let state = match content { - LabelContent::Battery { - device, - low_threshold, - low_color, - charging_color, - } => Some(LabelData::Battery { - device: *device, - low_threshold: *low_threshold, - normal_color: label.fg_color, - low_color: color_parse_or_default(low_color), - charging_color: color_parse_or_default(charging_color), - }), - LabelContent::Clock { format, timezone } => { - let tz_str = match timezone { - Some(TimezoneDef::Idx(idx)) => app.session.config.timezones.get(*idx).map_or_else( - || { - log::error!("Timezone index out of range '{idx}'"); - label.set_fg_color(*FALLBACK_COLOR); - None - }, - |tz| Some(tz.as_str()), - ), - Some(TimezoneDef::Str(tz_str)) => Some(tz_str.as_ref()), - None => None, - }; - - Some(LabelData::Clock { - format: format.clone(), - timezone: tz_str.and_then(|tz| { - tz.parse() - .map_err(|_| { - log::error!("Failed to parse timezone '{}'", &tz); - label.set_fg_color(*FALLBACK_COLOR); - }) - .ok() - }), - }) - } - LabelContent::Timezone { timezone } => { - if let Some(tz) = app.session.config.timezones.get(*timezone) { - let pretty_tz = tz.split('/').next_back().map(|x| x.replace('_', " ")); - - if let Some(pretty_tz) = pretty_tz { - label.set_text(&pretty_tz); - return; - } - log::error!("Timezone name not valid '{}'", &tz); - } else { - log::error!("Timezone index out of range '{}'", &timezone); - } - label.set_fg_color(*FALLBACK_COLOR); - label.set_text("Error"); - None - } - LabelContent::Timer { format } => Some(LabelData::Timer { - format: format.clone(), - start: Instant::now(), - }), - LabelContent::Exec { command, interval } => Some(LabelData::Exec { - last_exec: Instant::now(), - interval: *interval, - command: command.clone(), - child: None, - }), - LabelContent::Static { text } => { - label.set_text(text); - None - } - LabelContent::Ipd => Some(LabelData::Ipd { last_ipd: -1. }), - LabelContent::DragMultiplier => Some(LabelData::DragMultiplier), - }; - - if let Some(state) = state { - label.state = Some(ModularData::Label(Box::new(state))); - label.on_update = Some(label_update); - } -} - -#[allow(clippy::too_many_lines)] -pub(super) fn label_update(control: &mut ModularControl, _: &mut (), app: &mut AppState) { - // want panic - let ModularData::Label(data) = control.state.as_mut().unwrap() else { - panic!("Label control has no state"); - }; - match data.as_mut() { - LabelData::Battery { - device, - low_threshold, - normal_color, - low_color, - charging_color, - } => { - let device = app.input_state.devices.get(*device); - - let tags = ["", "H", "L", "R", "T"]; - - if let Some(device) = device { - let (text, color) = device.soc.map_or_else( - || (String::new(), Vec4::ZERO), - |soc| { - let text = format!( - "{}{}", - tags[device.role as usize], - (soc * 100.).min(99.) as u32 - ); - let color = if device.charging { - *charging_color - } else if soc < *low_threshold { - *low_color - } else { - *normal_color - }; - (text, color) - }, - ); - - control.set_text(&text); - control.set_fg_color(color); - } else { - control.set_text(""); - } - } - LabelData::Clock { format, timezone } => { - let format = format.clone(); - if let Some(tz) = timezone { - let date_time = Local::now().with_timezone(tz); - control.set_text(&format!("{}", &date_time.format(&format))); - } else { - let date_time = Local::now(); - control.set_text(&format!("{}", &date_time.format(&format))); - } - } - LabelData::Timer { format, start } => { - let mut format = format.clone().to_lowercase(); - let duration = start.elapsed().as_secs(); - format = format.replace("%s", &format!("{:02}", (duration % 60))); - format = format.replace("%m", &format!("{:02}", ((duration / 60) % 60))); - format = format.replace("%h", &format!("{:02}", ((duration / 60) / 60))); - control.set_text(&format); - } - LabelData::Exec { - last_exec, - interval, - command, - child, - } => { - if let Some(mut proc) = child.take() { - match proc.try_wait() { - Ok(Some(code)) => { - if code.success() { - if let Some(mut stdout) = proc.stdout.take() { - let mut buf = String::new(); - if stdout.read_to_string(&mut buf).is_ok() { - control.set_text(&buf); - } else { - error_toast_str( - app, - "LabelData::Exec: Failed to read stdout for child process", - ); - return; - } - return; - } - log::error!("No stdout for child process"); - return; - } - error_toast(app, "LabelData::Exec: Child process exited with code", code); - } - Ok(None) => { - *child = Some(proc); - // not exited yet - return; - } - Err(e) => { - *child = None; - error_toast(app, "Error checking child process", e); - return; - } - } - } - - if Instant::now() - .saturating_duration_since(*last_exec) - .as_secs_f32() - > *interval - { - *last_exec = Instant::now(); - let args = command - .iter() - .map(std::convert::AsRef::as_ref) - .collect::>(); - - match process::Command::new(args[0]) - .args(&args[1..]) - .stdout(Stdio::piped()) - .spawn() - { - Ok(proc) => { - *child = Some(proc); - } - Err(e) => { - error_toast(app, &format!("Failed to spawn process {args:?}"), e); - } - } - } - } - LabelData::Ipd { last_ipd } => { - if (app.input_state.ipd - *last_ipd).abs() > 0.05 { - *last_ipd = app.input_state.ipd; - control.set_text(&format!("{:.1}", app.input_state.ipd)); - } - } - LabelData::DragMultiplier => { - control.set_text(&format!("{:.1}", app.session.config.space_drag_multiplier)); - } - } -} diff --git a/src/gui/modular/mod.rs b/src/gui/modular/mod.rs deleted file mode 100644 index 3763580..0000000 --- a/src/gui/modular/mod.rs +++ /dev/null @@ -1,569 +0,0 @@ -pub mod button; -pub mod label; - -use std::{fs::File, sync::Arc}; - -#[cfg(feature = "wayvr")] -use button::{WayVRAction, WayVRDisplayClickAction}; - -use glam::Vec4; -use serde::Deserialize; -use vulkano::{command_buffer::CommandBufferUsage, image::view::ImageView}; - -use crate::{ - backend::common::OverlaySelector, config::AStrMapExt, config_io, - graphics::dds::WlxCommandBufferDds, state::AppState, -}; - -use self::{ - button::{modular_button_init, ButtonAction, ButtonData, OverlayAction}, - label::{modular_label_init, LabelContent, LabelData}, -}; - -use super::{ - canvas::{builder::CanvasBuilder, control::Control, Canvas}, - color_parse, GuiColor, FALLBACK_COLOR, -}; - -type ModularControl = Control<(), ModularData>; -type ExecArgs = Vec>; - -#[derive(Deserialize)] -pub struct ModularUiConfig { - pub width: f32, - pub size: [u32; 2], - pub spawn_pos: Option<[f32; 3]>, - pub elements: Vec, -} - -#[derive(Deserialize)] -pub struct OverlayListTemplate { - click_down: Option, - click_up: Option, - long_click_up: Option, - right_down: Option, - right_up: Option, - long_right_up: Option, - middle_down: Option, - middle_up: Option, - long_middle_up: Option, - scroll_down: Option, - scroll_up: Option, -} - -#[allow(dead_code)] -#[derive(Deserialize)] -#[serde(tag = "type")] -pub enum ModularElement { - Panel { - rect: [f32; 4], - corner_radius: Option, - bg_color: Arc, - }, - Label { - rect: [f32; 4], - corner_radius: Option, - font_size: isize, - fg_color: Arc, - #[serde(flatten)] - data: LabelContent, - }, - CenteredLabel { - rect: [f32; 4], - corner_radius: Option, - font_size: isize, - fg_color: Arc, - #[serde(flatten)] - data: LabelContent, - }, - Sprite { - rect: [f32; 4], - sprite: Arc, - sprite_st: Option<[f32; 4]>, - }, - Button { - rect: [f32; 4], - corner_radius: Option, - font_size: isize, - fg_color: Arc, - bg_color: Arc, - text: Arc, - #[serde(flatten)] - data: Box, - }, - /// Convenience type to save you from having to create a bunch of labels - BatteryList { - rect: [f32; 4], - corner_radius: Option, - font_size: isize, - fg_color: Arc, - fg_color_low: Arc, - fg_color_charging: Arc, - low_threshold: f32, - num_devices: usize, - layout: ListLayout, - }, - OverlayList { - rect: [f32; 4], - corner_radius: Option, - font_size: isize, - fg_color: Arc, - bg_color: Arc, - layout: ListLayout, - #[serde(flatten)] - template: Box, - }, - // Ignored if "wayvr" feature is not enabled - WayVRLauncher { - rect: [f32; 4], - corner_radius: Option, - font_size: isize, - fg_color: Arc, - bg_color: Arc, - catalog_name: Arc, - }, - // Ignored if "wayvr" feature is not enabled - WayVRDisplayList { - rect: [f32; 4], - corner_radius: Option, - font_size: isize, - fg_color: Arc, - bg_color: Arc, - }, -} - -#[derive(Deserialize, Clone)] -pub enum ButtonFunc { - HideWatch, - SwitchWatchHand, -} - -#[derive(Deserialize)] -pub enum ListLayout { - Horizontal, - Vertical, -} - -pub enum ModularData { - Label(Box), - Button(Box), -} - -#[allow(clippy::too_many_lines, clippy::many_single_char_names)] -pub fn modular_canvas( - size: [u32; 2], - elements: &[ModularElement], - state: &mut AppState, -) -> anyhow::Result> { - let mut canvas = CanvasBuilder::new( - size[0] as _, - size[1] as _, - state.graphics.clone(), - state.graphics.native_format, - (), - )?; - let empty_str: Arc = Arc::from(""); - for elem in elements { - match elem { - ModularElement::Panel { - rect: [x, y, w, h], - corner_radius, - bg_color, - } => { - canvas.bg_color = color_parse(bg_color).unwrap_or(*FALLBACK_COLOR); - canvas.panel(*x, *y, *w, *h, corner_radius.unwrap_or_default()); - } - ModularElement::Label { - rect: [x, y, w, h], - corner_radius, - font_size, - fg_color, - data, - } => { - canvas.font_size = *font_size; - canvas.fg_color = color_parse(fg_color).unwrap_or(*FALLBACK_COLOR); - let label = canvas.label( - *x, - *y, - *w, - *h, - corner_radius.unwrap_or_default(), - empty_str.clone(), - ); - modular_label_init(label, data, state); - } - ModularElement::CenteredLabel { - rect: [x, y, w, h], - corner_radius, - font_size, - fg_color, - data, - } => { - canvas.font_size = *font_size; - canvas.fg_color = color_parse(fg_color).unwrap_or(*FALLBACK_COLOR); - let label = canvas.label_centered( - *x, - *y, - *w, - *h, - corner_radius.unwrap_or_default(), - empty_str.clone(), - ); - modular_label_init(label, data, state); - } - ModularElement::Sprite { - rect: [x, y, w, h], - sprite, - sprite_st, - } => match sprite_from_path(sprite.clone(), state) { - Ok(view) => { - let sprite = canvas.sprite(*x, *y, *w, *h); - sprite.fg_color = Vec4::ONE; - sprite.set_sprite(view); - - let st = sprite_st - .map(|st| Vec4::from_slice(&st)) - .unwrap_or_else(|| Vec4::new(1., 1., 0., 0.)); - sprite.set_sprite_st(st); - } - Err(e) => { - log::warn!("Could not load custom UI sprite: {e:?}"); - } - }, - ModularElement::Button { - rect: [x, y, w, h], - corner_radius, - font_size, - bg_color, - fg_color, - text, - data, - } => { - canvas.bg_color = color_parse(bg_color).unwrap_or(*FALLBACK_COLOR); - canvas.fg_color = color_parse(fg_color).unwrap_or(*FALLBACK_COLOR); - canvas.font_size = *font_size; - let button = canvas.button( - *x, - *y, - *w, - *h, - corner_radius.unwrap_or_default(), - text.clone(), - ); - modular_button_init(button, data); - } - ModularElement::BatteryList { - rect: [x, y, w, h], - corner_radius, - font_size, - fg_color, - fg_color_low, - fg_color_charging, - low_threshold, - num_devices, - layout, - } => { - let num_buttons = *num_devices as f32; - let mut button_x = *x; - let mut button_y = *y; - let low_threshold = low_threshold * 0.01; - let (button_w, button_h) = match layout { - ListLayout::Horizontal => (*w / num_buttons, *h), - ListLayout::Vertical => (*w, *h / num_buttons), - }; - - let fg_color = color_parse(fg_color).unwrap_or(*FALLBACK_COLOR); - canvas.font_size = *font_size; - canvas.fg_color = fg_color; - - for i in 0..*num_devices { - let label = canvas.label_centered( - button_x + 2., - button_y + 2., - button_w - 4., - button_h - 4., - corner_radius.unwrap_or_default(), - empty_str.clone(), - ); - modular_label_init( - label, - &LabelContent::Battery { - device: i, - low_threshold, - low_color: fg_color_low.clone(), - charging_color: fg_color_charging.clone(), - }, - state, - ); - - button_x += match layout { - ListLayout::Horizontal => button_w, - ListLayout::Vertical => 0., - }; - button_y += match layout { - ListLayout::Horizontal => 0., - ListLayout::Vertical => button_h, - }; - } - } - ModularElement::OverlayList { - rect: [x, y, w, h], - corner_radius, - font_size, - fg_color, - bg_color, - layout, - template, - } => { - let num_buttons = state.screens.len() as f32; - let mut button_x = *x; - let mut button_y = *y; - let (button_w, button_h) = match layout { - ListLayout::Horizontal => (*w / num_buttons, *h), - ListLayout::Vertical => (*w, *h / num_buttons), - }; - - canvas.bg_color = color_parse(bg_color).unwrap_or(*FALLBACK_COLOR); - canvas.fg_color = color_parse(fg_color).unwrap_or(*FALLBACK_COLOR); - canvas.font_size = *font_size; - - for screen in &state.screens { - let button = canvas.button( - button_x + 2., - button_y + 2., - button_w - 4., - button_h - 4., - corner_radius.unwrap_or_default(), - screen.name.clone(), - ); - - // cursed - let data = ButtonData { - click_down: template.click_down.as_ref().map(|f| { - vec![ButtonAction::Overlay { - target: OverlaySelector::Id(screen.id), - action: f.clone(), - }] - }), - click_up: template.click_up.as_ref().map(|f| { - vec![ButtonAction::Overlay { - target: OverlaySelector::Id(screen.id), - action: f.clone(), - }] - }), - long_click_up: template.long_click_up.as_ref().map(|f| { - vec![ButtonAction::Overlay { - target: OverlaySelector::Id(screen.id), - action: f.clone(), - }] - }), - right_down: template.right_down.as_ref().map(|f| { - vec![ButtonAction::Overlay { - target: OverlaySelector::Id(screen.id), - action: f.clone(), - }] - }), - right_up: template.right_up.as_ref().map(|f| { - vec![ButtonAction::Overlay { - target: OverlaySelector::Id(screen.id), - action: f.clone(), - }] - }), - long_right_up: template.long_right_up.as_ref().map(|f| { - vec![ButtonAction::Overlay { - target: OverlaySelector::Id(screen.id), - action: f.clone(), - }] - }), - middle_down: template.middle_down.as_ref().map(|f| { - vec![ButtonAction::Overlay { - target: OverlaySelector::Id(screen.id), - action: f.clone(), - }] - }), - middle_up: template.middle_up.as_ref().map(|f| { - vec![ButtonAction::Overlay { - target: OverlaySelector::Id(screen.id), - action: f.clone(), - }] - }), - long_middle_up: template.long_middle_up.as_ref().map(|f| { - vec![ButtonAction::Overlay { - target: OverlaySelector::Id(screen.id), - action: f.clone(), - }] - }), - scroll_down: template.scroll_down.as_ref().map(|f| { - vec![ButtonAction::Overlay { - target: OverlaySelector::Id(screen.id), - action: f.clone(), - }] - }), - scroll_up: template.scroll_up.as_ref().map(|f| { - vec![ButtonAction::Overlay { - target: OverlaySelector::Id(screen.id), - action: f.clone(), - }] - }), - ..Default::default() - }; - - modular_button_init(button, &data); - - button_x += match layout { - ListLayout::Horizontal => button_w, - ListLayout::Vertical => 0., - }; - button_y += match layout { - ListLayout::Horizontal => 0., - ListLayout::Vertical => button_h, - }; - } - } - #[allow(unused_variables)] // needed in case if wayvr feature is not enabled - ModularElement::WayVRLauncher { - rect: [x, y, w, h], - corner_radius, - font_size, - fg_color, - bg_color, - catalog_name, - } => { - #[cfg(feature = "wayvr")] - { - if let Some(catalog) = state.session.wayvr_config.get_catalog(catalog_name) { - let mut button_x = *x; - let button_y = *y; - - for app in &catalog.apps { - let button_w: f32 = *w / catalog.apps.len() as f32; - let button_h: f32 = *h; - - canvas.bg_color = color_parse(bg_color).unwrap_or(*FALLBACK_COLOR); - canvas.fg_color = color_parse(fg_color).unwrap_or(*FALLBACK_COLOR); - canvas.font_size = *font_size; - - let button = canvas.button( - button_x + 2., - button_y + 2., - button_w - 4., - button_h - 4., - corner_radius.unwrap_or_default(), - Arc::from(app.name.as_str()), - ); - - let data = ButtonData { - click_up: Some(vec![ButtonAction::WayVR { - action: WayVRAction::AppClick { - catalog_name: catalog_name.clone(), - app_name: Arc::from(app.name.as_str()), - }, - }]), - ..Default::default() - }; - - modular_button_init(button, &data); - button_x += button_w; - } - } else { - log::error!("WayVR catalog \"{catalog_name}\" not found"); - } - } - #[cfg(not(feature = "wayvr"))] - { - log::error!("WayVR feature is not enabled, ignoring"); - } - } - #[allow(unused_variables)] - ModularElement::WayVRDisplayList { - rect: [x, y, w, h], - corner_radius, - font_size, - fg_color, - bg_color, - } => { - #[cfg(feature = "wayvr")] - { - let mut button_x = *x; - let button_y = *y; - let displays = &state.session.wayvr_config.displays; - for (display_name, display) in displays { - let button_w: f32 = (*w / displays.len() as f32).min(80.0); - let button_h: f32 = *h; - - canvas.bg_color = color_parse(bg_color).unwrap_or(*FALLBACK_COLOR); - canvas.fg_color = color_parse(fg_color).unwrap_or(*FALLBACK_COLOR); - canvas.font_size = *font_size; - - let button = canvas.button( - button_x + 2., - button_y + 2., - button_w - 4., - button_h - 4., - corner_radius.unwrap_or_default(), - Arc::from(display_name.as_str()), - ); - - let data = ButtonData { - click_up: Some(vec![ButtonAction::WayVR { - action: WayVRAction::DisplayClick { - display_name: Arc::from(display_name.as_str()), - action: WayVRDisplayClickAction::ToggleVisibility, - }, - }]), - long_click_up: Some(vec![ButtonAction::WayVR { - action: WayVRAction::DisplayClick { - display_name: Arc::from(display_name.as_str()), - action: WayVRDisplayClickAction::Reset, - }, - }]), - ..Default::default() - }; - - modular_button_init(button, &data); - button_x += button_w; - } - } - #[cfg(not(feature = "wayvr"))] - { - log::error!("WayVR feature is not enabled, ignoring") - } - } - } - } - Ok(canvas.build()) -} - -pub fn color_parse_or_default(color: &str) -> GuiColor { - color_parse(color).unwrap_or_else(|e| { - log::error!("Failed to parse color '{color}': {e}"); - *FALLBACK_COLOR - }) -} - -fn sprite_from_path(path: Arc, app: &mut AppState) -> anyhow::Result> { - if let Some(view) = app.sprites.arc_get(&path) { - return Ok(view.clone()); - } - - let real_path = config_io::get_config_root().join(&*path); - - let Ok(f) = File::open(real_path) else { - anyhow::bail!("Could not open custom sprite at: {}", path); - }; - - let mut command_buffer = app.graphics.create_uploads_command_buffer( - app.graphics.transfer_queue.clone(), - CommandBufferUsage::OneTimeSubmit, - )?; - - match command_buffer.texture2d_dds(f) { - Ok(image) => { - command_buffer.build_and_execute_now()?; - Ok(ImageView::new_default(image)?) - } - Err(e) => { - anyhow::bail!("Could not use custom sprite at: {}\n{:?}", path, e); - } - } -} diff --git a/src/gui/panel.rs b/src/gui/panel.rs new file mode 100644 index 0000000..2f9fe93 --- /dev/null +++ b/src/gui/panel.rs @@ -0,0 +1,161 @@ +use std::sync::Arc; + +use glam::vec2; +use vulkano::{command_buffer::CommandBufferUsage, image::view::ImageView}; +use wgui::{ + event::{Event as WguiEvent, MouseDownEvent, MouseMotionEvent, MouseUpEvent, MouseWheelEvent}, + layout::Layout, + renderer_vk::context::Context as WguiContext, +}; + +use crate::{ + backend::{ + input::{Haptics, InteractionHandler, PointerHit}, + overlay::{FrameMeta, OverlayBackend, OverlayRenderer, ShouldRender}, + }, + graphics::{CommandBuffers, ExtentExt}, + state::AppState, +}; + +use super::{asset::GuiAsset, timestep::Timestep}; + +pub struct GuiPanel { + pub layout: Layout, + context: WguiContext, + timestep: Timestep, + pub width: u32, + pub height: u32, +} + +impl GuiPanel { + pub fn new_from_template( + app: &AppState, + width: u32, + height: u32, + path: &str, + ) -> anyhow::Result { + let mut me = Self::new_blank(app, width, height)?; + + let parent = me.layout.root_widget; + let _res = wgui::parser::parse_from_assets(&mut me.layout, parent, path)?; + + Ok(me) + } + + pub fn new_blank(app: &AppState, width: u32, height: u32) -> anyhow::Result { + let layout = Layout::new(Box::new(GuiAsset {}))?; + let context = WguiContext::new(app.gfx.clone(), app.gfx.surface_format, 1.0)?; + let mut timestep = Timestep::new(); + timestep.set_tps(60.0); + + Ok(Self { + layout, + context, + timestep, + width, + height, + }) + } +} + +impl OverlayBackend for GuiPanel { + fn set_renderer(&mut self, _: Box) { + log::debug!("Attempted to replace renderer on GuiPanel!"); + } + fn set_interaction(&mut self, _: Box) { + log::debug!("Attempted to replace interaction layer on GuiPanel!"); + } +} + +impl InteractionHandler for GuiPanel { + fn on_scroll(&mut self, _app: &mut AppState, hit: &PointerHit, delta_y: f32, delta_x: f32) { + self.layout + .push_event(&WguiEvent::MouseWheel(MouseWheelEvent { + shift: vec2(delta_x, delta_y), + pos: hit.uv, + })) + .unwrap() + } + + fn on_hover(&mut self, _app: &mut AppState, hit: &PointerHit) -> Option { + self.layout + .push_event(&WguiEvent::MouseMotion(MouseMotionEvent { pos: hit.uv })) + .unwrap(); + + None + } + + fn on_left(&mut self, _app: &mut AppState, _pointer: usize) { + //TODO: is this needed? + } + + fn on_pointer(&mut self, _app: &mut AppState, hit: &PointerHit, pressed: bool) { + if pressed { + self.layout + .push_event(&WguiEvent::MouseDown(MouseDownEvent { pos: hit.uv })) + .unwrap(); + } else { + self.layout + .push_event(&WguiEvent::MouseUp(MouseUpEvent { pos: hit.uv })) + .unwrap(); + } + } +} + +impl OverlayRenderer for GuiPanel { + fn init(&mut self, _app: &mut AppState) -> anyhow::Result<()> { + Ok(()) + } + + fn pause(&mut self, _app: &mut AppState) -> anyhow::Result<()> { + Ok(()) + } + + fn resume(&mut self, _app: &mut AppState) -> anyhow::Result<()> { + self.timestep.reset(); + Ok(()) + } + + fn should_render(&mut self, _app: &mut AppState) -> anyhow::Result { + while self.timestep.on_tick() { + self.layout.tick()?; + } + + Ok(if self.layout.check_toggle_needs_redraw() { + ShouldRender::Should + } else { + ShouldRender::Can + }) + } + + fn render( + &mut self, + app: &mut AppState, + tgt: Arc, + buf: &mut CommandBuffers, + _alpha: f32, + ) -> anyhow::Result { + self.context.update_viewport(tgt.extent_u32arr(), 1.0)?; + self.layout.update(tgt.extent_vec2(), self.timestep.alpha); + + let mut cmd_buf = app + .gfx + .create_gfx_command_buffer(CommandBufferUsage::OneTimeSubmit) + .unwrap(); + + cmd_buf.begin_rendering(tgt)?; + let primitives = wgui::drawing::draw(&self.layout)?; + self.context.draw(&app.gfx, &mut cmd_buf, &primitives)?; + cmd_buf.end_rendering()?; + buf.push(cmd_buf.build()?); + + Ok(true) + } + + fn frame_meta(&mut self) -> Option { + Some(FrameMeta { + extent: [self.width, self.height, 1], + ..Default::default() + }) + } +} diff --git a/src/gui/timestep.rs b/src/gui/timestep.rs new file mode 100644 index 0000000..0be34f6 --- /dev/null +++ b/src/gui/timestep.rs @@ -0,0 +1,70 @@ +use std::{sync::LazyLock, time::Instant}; +static TIME_START: LazyLock = LazyLock::new(Instant::now); + +pub fn get_micros() -> u64 { + TIME_START.elapsed().as_micros() as u64 +} + +#[derive(Default)] +pub struct Timestep { + current_time_us: u64, + accumulator: f32, + time_micros: u64, + ticks: u32, + speed: f32, + pub alpha: f32, + delta: f32, + loopnum: u8, +} + +impl Timestep { + pub fn new() -> Timestep { + let mut timestep = Timestep { + speed: 1.0, + ..Default::default() + }; + + timestep.reset(); + timestep + } + + fn calculate_alpha(&mut self) { + self.alpha = (self.accumulator / self.delta).clamp(0.0, 1.0); + } + + pub fn set_tps(&mut self, tps: f32) { + self.delta = 1000.0 / tps; + } + + pub fn reset(&mut self) { + self.current_time_us = get_micros(); + self.accumulator = 0.0; + } + + pub fn on_tick(&mut self) -> bool { + let newtime = get_micros(); + let frametime = newtime - self.current_time_us; + self.time_micros += frametime; + self.current_time_us = newtime; + self.accumulator += frametime as f32 * self.speed / 1000.0; + self.calculate_alpha(); + + if self.accumulator >= self.delta { + self.accumulator -= self.delta; + self.loopnum += 1; + self.ticks += 1; + + if self.loopnum > 5 { + // cannot keep up! + self.loopnum = 0; + self.accumulator = 0.0; + return false; + } + + true + } else { + self.loopnum = 0; + false + } + } +} diff --git a/src/main.rs b/src/main.rs index cfd7b7c..041ac52 100644 --- a/src/main.rs +++ b/src/main.rs @@ -113,12 +113,6 @@ fn main() -> Result<(), Box> { return Ok(()); } - #[cfg(feature = "uidev")] - if let Some(panel_name) = args.uidev.as_ref() { - crate::backend::uidev::uidev_run(panel_name.as_str())?; - return Ok(()); - } - let running = Arc::new(AtomicBool::new(true)); let _ = ctrlc::set_handler({ let running = running.clone(); diff --git a/src/overlays/anchor.rs b/src/overlays/anchor.rs index a473763..47cdd77 100644 --- a/src/overlays/anchor.rs +++ b/src/overlays/anchor.rs @@ -1,18 +1,61 @@ use glam::Vec3A; use std::sync::{Arc, LazyLock}; +use wgui::parser::parse_color_hex; +use wgui::renderer_vk::text::{FontWeight, TextStyle}; +use wgui::taffy; +use wgui::taffy::prelude::{length, percent}; +use wgui::widget::rectangle::{Rectangle, RectangleParams}; +use wgui::widget::text::{TextLabel, TextParams}; +use wgui::widget::util::WLength; use crate::backend::overlay::{OverlayData, OverlayState, Positioning, Z_ORDER_ANCHOR}; -use crate::config::{load_known_yaml, ConfigType}; -use crate::gui::modular::{modular_canvas, ModularUiConfig}; +use crate::gui::panel::GuiPanel; use crate::state::AppState; pub static ANCHOR_NAME: LazyLock> = LazyLock::new(|| Arc::from("anchor")); -pub fn create_anchor(state: &mut AppState) -> anyhow::Result> +pub fn create_anchor(app: &mut AppState) -> anyhow::Result> where O: Default, { - let config = load_known_yaml::(ConfigType::Anchor); + let mut panel = GuiPanel::new_blank(app, 200, 200)?; + + let (rect, _) = panel.layout.add_child( + panel.layout.root_widget, + Rectangle::create(RectangleParams { + color: wgui::drawing::Color::new(0., 0., 0., 0.), + border_color: parse_color_hex("#ffff00").unwrap(), + border: 2.0, + round: WLength::Percent(1.0), + ..Default::default() + }) + .unwrap(), + taffy::Style { + size: taffy::Size { + width: percent(1.0), + height: percent(1.0), + }, + align_items: Some(taffy::AlignItems::Center), + justify_content: Some(taffy::JustifyContent::Center), + padding: length(4.0), + ..Default::default() + }, + )?; + + let _ = panel.layout.add_child( + rect, + TextLabel::create(TextParams { + content: "Center".into(), + style: TextStyle { + weight: Some(FontWeight::Bold), + size: Some(36.0), + color: parse_color_hex("#ffff00"), + ..Default::default() + }, + }) + .unwrap(), + taffy::style::Style::DEFAULT, + ); Ok(OverlayData { state: OverlayState { @@ -21,12 +64,12 @@ where interactable: false, grabbable: false, z_order: Z_ORDER_ANCHOR, - spawn_scale: config.width, + spawn_scale: 0.1, spawn_point: Vec3A::NEG_Z * 0.5, positioning: Positioning::Static, ..Default::default() }, - backend: Box::new(modular_canvas(config.size, &config.elements, state)?), + backend: Box::new(panel), ..Default::default() }) } diff --git a/src/overlays/custom.rs b/src/overlays/custom.rs index 5bf8a54..d0d31c3 100644 --- a/src/overlays/custom.rs +++ b/src/overlays/custom.rs @@ -3,49 +3,34 @@ use std::sync::Arc; use glam::Vec3A; use crate::{ - backend::overlay::{ui_transform, OverlayBackend, OverlayState}, - config::{load_custom_ui, load_known_yaml, ConfigType}, - gui::modular::{modular_canvas, ModularUiConfig}, + backend::overlay::{OverlayBackend, OverlayState}, + gui::panel::GuiPanel, state::AppState, }; const SETTINGS_NAME: &str = "settings"; pub fn create_custom( - state: &mut AppState, + app: &mut AppState, name: Arc, ) -> Option<(OverlayState, Box)> { - let config = if &*name == SETTINGS_NAME { - load_known_yaml::(ConfigType::Settings) - } else { - match load_custom_ui(&name) { - Ok(config) => config, - Err(e) => { - log::error!("Failed to load custom UI config for {name}: {e:?}"); - return None; - } - } - }; + return None; - let canvas = match modular_canvas(config.size, &config.elements, state) { - Ok(canvas) => canvas, - Err(e) => { - log::error!("Failed to create canvas for {name}: {e:?}"); - return None; - } - }; + unreachable!(); + + let panel = GuiPanel::new_blank(&app, 200, 200).ok()?; let state = OverlayState { name, want_visible: true, interactable: true, grabbable: true, - spawn_scale: config.width, - spawn_point: Vec3A::from_array(config.spawn_pos.unwrap_or([0., 0., -0.5])), - interaction_transform: ui_transform(config.size), + spawn_scale: 0.1, //TODO: this + spawn_point: Vec3A::from_array([0., 0., -0.5]), + //interaction_transform: ui_transform(config.size), ..Default::default() }; - let backend = Box::new(canvas); + let backend = Box::new(panel); Some((state, backend)) } diff --git a/src/overlays/keyboard.rs b/src/overlays/keyboard.rs index aa32415..c64f771 100644 --- a/src/overlays/keyboard.rs +++ b/src/overlays/keyboard.rs @@ -15,20 +15,26 @@ use crate::{ }, config::{self, ConfigType}, graphics::CommandBuffers, - gui::{ - canvas::{builder::CanvasBuilder, control::Control, Canvas}, - color_parse, KeyCapType, - }, + gui::panel::GuiPanel, hid::{ get_key_type, KeyModifier, KeyType, VirtualKey, XkbKeymap, ALT, CTRL, KEYS_TO_MODS, META, NUM_LOCK, SHIFT, SUPER, }, state::{AppState, KeyboardFocus}, }; -use glam::{vec2, vec3a, Affine2, Vec4}; +use glam::{vec2, vec3a, Affine2, Vec2Swizzles, Vec4}; use regex::Regex; use serde::{Deserialize, Serialize}; use vulkano::image::view::ImageView; +use wgui::{ + parser::parse_color_hex, + taffy::{self, prelude::length}, + widget::{ + div::Div, + rectangle::{Rectangle, RectangleParams}, + util::WLength, + }, +}; const PIXELS_PER_UNIT: f32 = 80.; const BUTTON_PADDING: f32 = 4.; @@ -92,20 +98,28 @@ where processes: vec![], }; - let mut canvas = CanvasBuilder::new( - size.x as _, - size.y as _, - app.graphics.clone(), - app.graphics.native_format, - data, + let padding = 4f32; + + let mut panel = GuiPanel::new_blank( + app, + padding.mul_add(2.0, size.x) as u32, + padding.mul_add(2.0, size.y) as u32, )?; - canvas.bg_color = color_parse("#181926").unwrap(); //safe - canvas.panel(0., 0., size.x, size.y, 12.); - - canvas.font_size = 18; - canvas.fg_color = color_parse("#cad3f5").unwrap(); //safe - canvas.bg_color = color_parse("#1e2030").unwrap(); //safe + let (background, _) = panel.layout.add_child( + panel.layout.root_widget, + Rectangle::create(RectangleParams { + color: wgui::drawing::Color::new(0., 0., 0., 0.6), + round: WLength::Units(4.0), + ..Default::default() + }) + .unwrap(), + taffy::Style { + flex_direction: taffy::FlexDirection::Column, + padding: length(padding), + ..Default::default() + }, + )?; let has_altgr = keymap .as_ref() @@ -115,17 +129,22 @@ where keymap = None; } - let unit_size = size.x / LAYOUT.row_size; - let h = 2.0f32.mul_add(-BUTTON_PADDING, unit_size); - for row in 0..LAYOUT.key_sizes.len() { - let y = unit_size.mul_add(row as f32, BUTTON_PADDING); - let mut sum_size = 0f32; + let (div, _) = panel.layout.add_child( + background, + Div::create().unwrap(), + taffy::Style { + flex_direction: taffy::FlexDirection::Row, + ..Default::default() + }, + )?; for col in 0..LAYOUT.key_sizes[row].len() { let my_size = LAYOUT.key_sizes[row][col]; - let x = unit_size.mul_add(sum_size, BUTTON_PADDING); - let w = unit_size.mul_add(my_size, -(2. * BUTTON_PADDING)); + let my_size = taffy::Size { + width: length(PIXELS_PER_UNIT * my_size), + height: length(PIXELS_PER_UNIT), + }; if let Some(key) = LAYOUT.main_layout[row][col].as_ref() { let mut label = Vec::with_capacity(2); @@ -180,16 +199,16 @@ where } else if let Some(exec_args) = LAYOUT.exec_commands.get(key) { if exec_args.is_empty() { log::error!("Keyboard: EXEC args empty for {key}"); - continue; - } - let mut iter = exec_args.iter().cloned(); - if let Some(program) = iter.next() { - maybe_state = Some(KeyButtonData::Exec { - program, - args: iter.by_ref().take_while(|arg| arg[..] != *"null").collect(), - release_program: iter.next(), - release_args: iter.collect(), - }); + } else { + let mut iter = exec_args.iter().cloned(); + if let Some(program) = iter.next() { + maybe_state = Some(KeyButtonData::Exec { + program, + args: iter.by_ref().take_while(|arg| arg[..] != *"null").collect(), + release_program: iter.next(), + release_args: iter.collect(), + }); + } } } else { log::error!("Unknown key: {key}"); @@ -199,20 +218,38 @@ where if label.is_empty() { label = LAYOUT.label_for_key(key); } - let button = canvas.key_button(x, y, w, h, 12., cap_type, &label); - button.state = Some(state); - button.on_press = Some(key_press); - button.on_release = Some(key_release); - button.test_highlight = Some(test_highlight); + let _ = panel.layout.add_child( + div, + Rectangle::create(RectangleParams { + border_color: parse_color_hex("#dddddd").unwrap(), + border: 2.0, + round: WLength::Units(4.0), + ..Default::default() + }) + .unwrap(), + taffy::Style { + size: my_size, + min_size: my_size, + max_size: my_size, + ..Default::default() + }, + )?; + } else { + let _ = panel.layout.add_child( + div, + Div::create().unwrap(), + taffy::Style { + size: my_size, + min_size: my_size, + max_size: my_size, + ..Default::default() + }, + )?; } } - - sum_size += my_size; } } - let canvas = canvas.build(); - let interaction_transform = Affine2::from_translation(vec2(0.5, 0.5)) * Affine2::from_scale(vec2(1., -size.x as f32 / size.y as f32)); @@ -230,120 +267,11 @@ where interaction_transform, ..Default::default() }, - backend: Box::new(KeyboardBackend { canvas }), + backend: Box::new(KeyboardBackend { panel }), ..Default::default() }) } -fn key_press( - control: &mut Control, - data: &mut KeyboardData, - app: &mut AppState, - mode: PointerMode, -) { - match control.state.as_mut() { - Some(KeyButtonData::Key { vk, pressed }) => { - key_click(app); - - data.modifiers |= match mode { - PointerMode::Right => SHIFT, - PointerMode::Middle => data.alt_modifier, - _ => 0, - }; - - set_modifiers(app, data.modifiers); - - send_key(app, *vk, true); - *pressed = true; - } - Some(KeyButtonData::Modifier { modifier, sticky }) => { - *sticky = data.modifiers & *modifier == 0; - data.modifiers |= *modifier; - key_click(app); - set_modifiers(app, data.modifiers); - } - Some(KeyButtonData::Macro { verbs }) => { - key_click(app); - for (vk, press) in verbs { - send_key(app, *vk, *press); - } - } - Some(KeyButtonData::Exec { program, args, .. }) => { - // Reap previous processes - data.processes - .retain_mut(|child| !matches!(child.try_wait(), Ok(Some(_)))); - - key_click(app); - if let Ok(child) = Command::new(program).args(args).spawn() { - data.processes.push(child); - } - } - None => {} - } -} - -fn key_release( - control: &mut Control, - data: &mut KeyboardData, - app: &mut AppState, -) { - match control.state.as_mut() { - Some(KeyButtonData::Key { vk, pressed }) => { - send_key(app, *vk, false); - *pressed = false; - - for m in &AUTO_RELEASE_MODS { - if data.modifiers & *m != 0 { - data.modifiers &= !*m; - set_modifiers(app, data.modifiers); - } - } - } - Some(KeyButtonData::Modifier { modifier, sticky }) => { - if !*sticky { - data.modifiers &= !*modifier; - set_modifiers(app, data.modifiers); - } - } - Some(KeyButtonData::Exec { - release_program, - release_args, - .. - }) => { - // Reap previous processes - data.processes - .retain_mut(|child| !matches!(child.try_wait(), Ok(Some(_)))); - - if let Some(program) = release_program { - if let Ok(child) = Command::new(program).args(release_args).spawn() { - data.processes.push(child); - } - } - } - _ => {} - } -} - -static PRESS_COLOR: Vec4 = Vec4::new(198. / 255., 160. / 255., 246. / 255., 0.5); - -fn test_highlight( - control: &Control, - data: &mut KeyboardData, - _app: &mut AppState, -) -> Option { - let pressed = match control.state.as_ref() { - Some(KeyButtonData::Key { pressed, .. }) => *pressed, - Some(KeyButtonData::Modifier { modifier, .. }) => data.modifiers & *modifier != 0, - _ => false, - }; - - if pressed { - Some(PRESS_COLOR) - } else { - None - } -} - struct KeyboardData { modifiers: KeyModifier, alt_modifier: KeyModifier, @@ -501,15 +429,15 @@ fn key_events_for_macro(macro_verbs: &Vec) -> Vec<(VirtualKey, bool)> { } struct KeyboardBackend { - canvas: Canvas, + panel: GuiPanel, } impl OverlayBackend for KeyboardBackend { fn set_interaction(&mut self, interaction: Box) { - self.canvas.set_interaction(interaction); + self.panel.set_interaction(interaction); } fn set_renderer(&mut self, renderer: Box) { - self.canvas.set_renderer(renderer); + self.panel.set_renderer(renderer); } } @@ -520,7 +448,7 @@ impl InteractionHandler for KeyboardBackend { hit: &crate::backend::input::PointerHit, pressed: bool, ) { - self.canvas.on_pointer(app, hit, pressed); + self.panel.on_pointer(app, hit, pressed); } fn on_scroll( &mut self, @@ -529,26 +457,26 @@ impl InteractionHandler for KeyboardBackend { delta_y: f32, delta_x: f32, ) { - self.canvas.on_scroll(app, hit, delta_y, delta_x); + self.panel.on_scroll(app, hit, delta_y, delta_x); } fn on_left(&mut self, app: &mut AppState, pointer: usize) { - self.canvas.on_left(app, pointer); + self.panel.on_left(app, pointer); } fn on_hover( &mut self, app: &mut AppState, hit: &crate::backend::input::PointerHit, ) -> Option { - self.canvas.on_hover(app, hit) + self.panel.on_hover(app, hit) } } impl OverlayRenderer for KeyboardBackend { fn init(&mut self, app: &mut AppState) -> anyhow::Result<()> { - self.canvas.init(app) + self.panel.init(app) } fn should_render(&mut self, app: &mut AppState) -> anyhow::Result { - self.canvas.should_render(app) + self.panel.should_render(app) } fn render( &mut self, @@ -557,17 +485,31 @@ impl OverlayRenderer for KeyboardBackend { buf: &mut CommandBuffers, alpha: f32, ) -> anyhow::Result { - self.canvas.render(app, tgt, buf, alpha) + self.panel.render(app, tgt, buf, alpha) } fn frame_meta(&mut self) -> Option { - self.canvas.frame_meta() + self.panel.frame_meta() } fn pause(&mut self, app: &mut AppState) -> anyhow::Result<()> { - self.canvas.data_mut().modifiers = 0; set_modifiers(app, 0); - self.canvas.pause(app) + self.panel.pause(app) } fn resume(&mut self, app: &mut AppState) -> anyhow::Result<()> { - self.canvas.resume(app) + self.panel.resume(app) } } + +pub enum KeyCapType { + /// Label is in center of keycap + Regular, + /// Label on the top + /// AltGr symbol on bottom + RegularAltGr, + /// Primary symbol on bottom + /// Shift symbol on top + Reversed, + /// Primary symbol on bottom-left + /// Shift symbol on top-left + /// AltGr symbol on bottom-right + ReversedAltGr, +} diff --git a/src/overlays/screen.rs b/src/overlays/screen.rs index f9e209a..ae0966a 100644 --- a/src/overlays/screen.rs +++ b/src/overlays/screen.rs @@ -7,12 +7,14 @@ use std::{ time::Instant, }; use vulkano::{ + buffer::{BufferUsage, Subbuffer}, command_buffer::CommandBufferUsage, device::Queue, format::Format, image::{sampler::Filter, view::ImageView, Image}, - pipeline::graphics::color_blend::AttachmentBlend, + pipeline::graphics::{color_blend::AttachmentBlend, input_assembly::PrimitiveTopology}, }; +use wgui::gfx::{cmd::XferCommandBuffer, pass::WGfxPass, pipeline::WGfxPipeline, WGfx}; use wlx_capture::frame as wlx_frame; use wlx_capture::{ @@ -56,7 +58,10 @@ use crate::{ }, }, config::{def_pw_tokens, GeneralConfig, PwTokenMap}, - graphics::{fourcc_to_vk, CommandBuffers, WlxGraphics, WlxPipeline, WlxUploadsBuffer}, + graphics::{ + dmabuf::{fourcc_to_vk, WGfxDmabuf}, + upload_quad_vertices, CommandBuffers, ExtentExt, Vert2Uv, + }, hid::{MOUSE_LEFT, MOUSE_MIDDLE, MOUSE_RIGHT}, state::{AppSession, AppState, KeyboardFocus, ScreenMeta}, }; @@ -153,36 +158,44 @@ impl InteractionHandler for ScreenInteractionHandler { fn on_left(&mut self, _app: &mut AppState, _hand: usize) {} } -#[derive(Clone)] +struct MousePass { + pass: WGfxPass, + buf_vert: Subbuffer<[Vert2Uv]>, +} + struct ScreenPipeline { - mouse: Option>, - pipeline: Arc, + mouse: Option, + pipeline: Arc>, + buf_alpha: Subbuffer<[f32]>, extentf: [f32; 2], } impl ScreenPipeline { fn new(extent: &[u32; 3], app: &mut AppState) -> anyhow::Result { - let Ok(shaders) = app.graphics.shared_shaders.read() else { - return Err(anyhow::anyhow!("Could not lock shared shaders for reading")); - }; - - let pipeline = app.graphics.create_pipeline( - shaders.get("vert_common").unwrap().clone(), // want panic - shaders.get("frag_screen").unwrap().clone(), // want panic - app.graphics.native_format, + let pipeline = app.gfx.create_pipeline( + app.gfx_extras.shaders.get("vert_quad").unwrap().clone(), // want panic + app.gfx_extras.shaders.get("frag_screen").unwrap().clone(), // want panic + app.gfx.surface_format, Some(AttachmentBlend::default()), + PrimitiveTopology::TriangleStrip, + false, )?; + let buf_alpha = app + .gfx + .empty_buffer(BufferUsage::TRANSFER_DST | BufferUsage::UNIFORM_BUFFER, 1)?; + let extentf = [extent[0] as f32, extent[1] as f32]; Ok(Self { mouse: None, pipeline, + buf_alpha, extentf, }) } - fn ensure_mouse_initialized(&mut self, uploads: &mut WlxUploadsBuffer) -> anyhow::Result<()> { + fn ensure_mouse_initialized(&mut self, cmd_xfer: &mut XferCommandBuffer) -> anyhow::Result<()> { if self.mouse.is_some() { return Ok(()); } @@ -195,9 +208,28 @@ impl ScreenPipeline { 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, ]; - let mouse_tex = - uploads.texture2d_raw(4, 4, vulkano::format::Format::R8G8B8A8_UNORM, &mouse_bytes)?; - self.mouse = Some(ImageView::new_default(mouse_tex)?); + let image = + cmd_xfer.upload_image(4, 4, vulkano::format::Format::R8G8B8A8_UNORM, &mouse_bytes)?; + + let view = ImageView::new_default(image)?; + + let buf_vert = cmd_xfer + .graphics + .empty_buffer(BufferUsage::TRANSFER_DST | BufferUsage::VERTEX_BUFFER, 4)?; + + let set0 = self.pipeline.uniform_sampler(0, view, Filter::Nearest)?; + + let set1 = self.pipeline.buffer(1, self.buf_alpha.clone())?; + + let pass = self.pipeline.create_pass( + self.extentf, + buf_vert.clone(), + 0..4, + 0..1, + vec![set0, set1], + )?; + + self.mouse = Some(MousePass { pass, buf_vert }); Ok(()) } @@ -213,23 +245,31 @@ impl ScreenPipeline { let view = ImageView::new_default(image)?; let set0 = self .pipeline - .uniform_sampler(0, view, app.graphics.texture_filtering)?; - let set1 = self.pipeline.uniform_buffer(1, vec![alpha])?; - let pass = self - .pipeline - .create_pass_for_target(tgt.clone(), vec![set0, set1])?; + .uniform_sampler(0, view, app.gfx.texture_filter)?; + + self.buf_alpha.write()?[0] = alpha; + + let set1 = self.pipeline.buffer(1, self.buf_alpha.clone())?; + let pass = self.pipeline.create_pass( + tgt.extent_f32(), + app.gfx_extras.quad_verts.clone(), + 0..4, + 0..1, + vec![set0, set1], + )?; let mut cmd = app - .graphics - .create_command_buffer(CommandBufferUsage::OneTimeSubmit)?; + .gfx + .create_gfx_command_buffer(CommandBufferUsage::OneTimeSubmit)?; cmd.begin_rendering(tgt)?; cmd.run_ref(&pass)?; - if let (Some(mouse), Some(mouse_view)) = (mouse, self.mouse.clone()) { + if let (Some(mouse), Some(pass)) = (mouse, self.mouse.as_mut()) { let size = CURSOR_SIZE * self.extentf[1]; let half_size = size * 0.5; - let vertex_buffer = app.graphics.upload_verts( + upload_quad_vertices( + &mut pass.buf_vert, self.extentf[0], self.extentf[1], mouse.x.mul_add(self.extentf[0], -half_size), @@ -238,20 +278,7 @@ impl ScreenPipeline { size, )?; - let set0 = self - .pipeline - .uniform_sampler(0, mouse_view, Filter::Nearest)?; - - let set1 = self.pipeline.uniform_buffer(1, vec![alpha])?; - - let pass = self.pipeline.create_pass( - self.extentf, - vertex_buffer, - app.graphics.quad_indices.clone(), - vec![set0, set1], - )?; - - cmd.run_ref(&pass)?; + cmd.run_ref(&pass.pass)?; } cmd.end_rendering()?; @@ -296,7 +323,7 @@ impl ScreenRenderer { pub fn new_wlr_dmabuf(output: &WlxOutput, app: &AppState) -> Option { let client = WlxClient::new()?; let capture = new_wlx_capture!( - app.graphics.capture_queue, + app.gfx_extras.queue_capture, WlrDmabufCapture::new(client, output.id) ); Some(Self::new_raw(output.name.clone(), capture)) @@ -306,7 +333,7 @@ impl ScreenRenderer { pub fn new_wlr_screencopy(output: &WlxOutput, app: &AppState) -> Option { let client = WlxClient::new()?; let capture = new_wlx_capture!( - app.graphics.capture_queue, + app.gfx_extras.queue_capture, WlrScreencopyCapture::new(client, output.id) ); Some(Self::new_raw(output.name.clone(), capture)) @@ -340,7 +367,7 @@ impl ScreenRenderer { let node_id = select_screen_result.streams.first().unwrap().node_id; // streams guaranteed to have at least one element let capture = new_wlx_capture!( - app.graphics.capture_queue, + app.gfx_extras.queue_capture, PipewireCapture::new(name, node_id) ); Ok(( @@ -351,8 +378,10 @@ impl ScreenRenderer { #[cfg(feature = "x11")] pub fn new_xshm(screen: Arc, app: &AppState) -> Self { - let capture = - new_wlx_capture!(app.graphics.capture_queue, XshmCapture::new(screen.clone())); + let capture = new_wlx_capture!( + app.gfx_extras.queue_capture, + XshmCapture::new(screen.clone()) + ); Self::new_raw(screen.name.clone(), capture) } } @@ -360,7 +389,7 @@ impl ScreenRenderer { #[derive(Clone)] pub struct WlxCaptureIn { name: Arc, - graphics: Arc, + gfx: Arc, queue: Arc, } @@ -378,9 +407,9 @@ fn upload_image( format: Format, data: &[u8], ) -> Option> { - let mut upload = match me - .graphics - .create_uploads_command_buffer(me.queue.clone(), CommandBufferUsage::OneTimeSubmit) + let mut cmd_xfer = match me + .gfx + .create_xfer_command_buffer_with_queue(me.queue.clone(), CommandBufferUsage::OneTimeSubmit) { Ok(x) => x, Err(e) => { @@ -388,7 +417,7 @@ fn upload_image( return None; } }; - let image = match upload.texture2d_raw(width, height, format, data) { + let image = match cmd_xfer.upload_image(width, height, format, data) { Ok(x) => x, Err(e) => { log::error!("{}: Could not create vkImage: {:?}", me.name, e); @@ -396,7 +425,7 @@ fn upload_image( } }; - if let Err(e) = upload.build_and_execute_now() { + if let Err(e) = cmd_xfer.build_and_execute_now() { log::error!("{}: Could not execute upload: {:?}", me.name, e); return None; } @@ -413,7 +442,7 @@ fn receive_callback(me: &WlxCaptureIn, frame: wlx_frame::WlxFrame) -> Option Some(WlxCaptureOut { image, format, @@ -499,7 +528,7 @@ impl OverlayRenderer for ScreenRenderer { fn should_render(&mut self, app: &mut AppState) -> anyhow::Result { if !self.capture.is_ready() { let supports_dmabuf = app - .graphics + .gfx .device .enabled_extensions() .ext_external_memory_dma_buf @@ -512,13 +541,13 @@ impl OverlayRenderer for ScreenRenderer { let dmabuf_formats = if !supports_dmabuf { log::info!("Capture method does not support DMA-buf"); - if app.graphics.capture_queue.is_none() { + if app.gfx_extras.queue_capture.is_none() { log::warn!("Current GPU does not support multiple queues. Software capture will take place on the main thread. Expect degraded performance."); } &Vec::new() } else if !allow_dmabuf { log::info!("Not using DMA-buf capture due to {capture_method}"); - if app.graphics.capture_queue.is_none() { + if app.gfx_extras.queue_capture.is_none() { log::warn!("Current GPU does not support multiple queues. Software capture will take place on the main thread. Expect degraded performance."); } &Vec::new() @@ -528,17 +557,17 @@ impl OverlayRenderer for ScreenRenderer { ); log::warn!("echo 'capture_method: pw_fallback' > ~/.config/wlxoverlay/conf.d/pw_fallback.yaml"); - &app.graphics.drm_formats + &app.gfx_extras.drm_formats }; let user_data = WlxCaptureIn { name: self.name.clone(), - graphics: app.graphics.clone(), + gfx: app.gfx.clone(), queue: app - .graphics - .capture_queue + .gfx_extras + .queue_capture .as_ref() - .unwrap_or_else(|| &app.graphics.transfer_queue) + .unwrap_or_else(|| &app.gfx.queue_xfer) .clone(), }; @@ -560,10 +589,9 @@ impl OverlayRenderer for ScreenRenderer { if let (Some(capture), None) = (self.cur_frame.as_ref(), self.pipeline.as_ref()) { self.pipeline = Some({ let mut pipeline = ScreenPipeline::new(&capture.image.extent(), app)?; - let mut upload = app.graphics.create_uploads_command_buffer( - app.graphics.transfer_queue.clone(), - CommandBufferUsage::OneTimeSubmit, - )?; + let mut upload = app + .gfx + .create_xfer_command_buffer(CommandBufferUsage::OneTimeSubmit)?; pipeline.ensure_mouse_initialized(&mut upload)?; upload.build_and_execute_now()?; pipeline @@ -931,7 +959,7 @@ pub fn create_screens_x11pw(app: &mut AppState) -> anyhow::Result, - pub body: Arc, + pub title: String, + pub body: String, pub opacity: f32, pub timeout: f32, pub sound: bool, @@ -50,7 +63,7 @@ pub struct Toast { #[allow(dead_code)] impl Toast { - pub const fn new(topic: ToastTopic, title: Arc, body: Arc) -> Self { + pub const fn new(topic: ToastTopic, title: String, body: String) -> Self { Self { title, body, @@ -117,6 +130,7 @@ impl Toast { } } +#[allow(clippy::too_many_lines)] fn new_toast(toast: Toast, app: &mut AppState) -> Option<(OverlayState, Box)> { let current_method = app .session @@ -153,63 +167,79 @@ fn new_toast(toast: Toast, app: &mut AppState) -> Option<(OverlayState, Box::new( - size.0 as _, - size.1 as _, - app.graphics.clone(), - app.graphics.native_format, - (), - ) - .ok()?; + let _ = panel.layout.add_child( + rect, + TextLabel::create(TextParams { + content: title, + style: TextStyle { + color: parse_color_hex("#ffffff"), + ..Default::default() + }, + }) + .unwrap(), + taffy::Style { + size: taffy::Size { + width: percent(1.0), + height: auto(), + }, + ..Default::default() + }, + ); - canvas.font_size = FONT_SIZE; - canvas.fg_color = color_parse("#cad3f5").unwrap(); // want panic - canvas.bg_color = color_parse("#1e2030").unwrap(); // want panic - canvas.panel(0., 0., size.0, size.1, 16.); - - if toast.body.is_empty() { - canvas.label_centered(PADDING.0, 0., og_width, size.1, 16., title); - } else { - canvas.label(PADDING.0, 54., og_width, size.1 - 54., 3., toast.body); - - canvas.fg_color = color_parse("#b8c0e0").unwrap(); // want panic - canvas.bg_color = color_parse("#24273a").unwrap(); // want panic - canvas.panel(0., 0., size.0, 30., 16.); - canvas.label_centered(PADDING.0, 16., og_width, FONT_SIZE as f32 + 2., 16., title); - } + let _ = panel.layout.add_child( + rect, + TextLabel::create(TextParams { + content: toast.body, + style: TextStyle { + weight: Some(FontWeight::Bold), + color: parse_color_hex("#eeeeee"), + ..Default::default() + }, + }) + .unwrap(), + taffy::Style { + size: taffy::Size { + width: percent(1.0), + height: auto(), + }, + ..Default::default() + }, + ); let state = OverlayState { name: TOAST_NAME.clone(), want_visible: true, - spawn_scale: size.0 * PIXELS_TO_METERS, + spawn_scale: (panel.width as f32) * PIXELS_TO_METERS, spawn_rotation, spawn_point, z_order: Z_ORDER_TOAST, positioning, ..Default::default() }; - let backend = Box::new(canvas.build()); + let backend = Box::new(panel); Some((state, backend)) } diff --git a/src/overlays/watch.rs b/src/overlays/watch.rs index cf29fb8..7902ad3 100644 --- a/src/overlays/watch.rs +++ b/src/overlays/watch.rs @@ -1,25 +1,54 @@ use glam::Vec3A; +use wgui::{ + parser::parse_color_hex, + taffy::{ + self, + prelude::{length, percent}, + }, + widget::{ + rectangle::{Rectangle, RectangleParams}, + util::WLength, + }, +}; use crate::{ backend::overlay::{ui_transform, OverlayData, OverlayState, Positioning, Z_ORDER_WATCH}, - config::{load_known_yaml, ConfigType}, - gui::{ - canvas::Canvas, - modular::{modular_canvas, ModularData, ModularUiConfig}, - }, + gui::panel::GuiPanel, state::AppState, }; pub const WATCH_NAME: &str = "watch"; -pub fn create_watch(state: &mut AppState) -> anyhow::Result> +pub fn create_watch(app: &mut AppState) -> anyhow::Result> where O: Default, { - let config = load_known_yaml::(ConfigType::Watch); + let mut panel = GuiPanel::new_blank(app, 400, 200)?; + + let (_, _) = panel.layout.add_child( + panel.layout.root_widget, + Rectangle::create(RectangleParams { + color: wgui::drawing::Color::new(0., 0., 0., 0.5), + border_color: parse_color_hex("#00ffff").unwrap(), + border: 2.0, + round: WLength::Units(4.0), + ..Default::default() + }) + .unwrap(), + taffy::Style { + size: taffy::Size { + width: percent(1.0), + height: percent(1.0), + }, + align_items: Some(taffy::AlignItems::Center), + justify_content: Some(taffy::JustifyContent::Center), + padding: length(4.0), + ..Default::default() + }, + )?; let positioning = Positioning::FollowHand { - hand: state.session.config.watch_hand as _, + hand: app.session.config.watch_hand as _, lerp: 1.0, }; @@ -29,27 +58,18 @@ where want_visible: true, interactable: true, z_order: Z_ORDER_WATCH, - spawn_scale: config.width, - spawn_point: state.session.config.watch_pos, - spawn_rotation: state.session.config.watch_rot, - interaction_transform: ui_transform(config.size), + spawn_scale: 0.115, //TODO:configurable + spawn_point: app.session.config.watch_pos, + spawn_rotation: app.session.config.watch_rot, + interaction_transform: ui_transform([400, 200]), positioning, ..Default::default() }, - backend: Box::new(create_watch_canvas(Some(config), state)?), + backend: Box::new(panel), ..Default::default() }) } -pub fn create_watch_canvas( - config: Option, - state: &mut AppState, -) -> anyhow::Result> { - let config = config.unwrap_or_else(|| load_known_yaml::(ConfigType::Watch)); - - modular_canvas(config.size, &config.elements, state) -} - pub fn watch_fade(app: &mut AppState, watch: &mut OverlayData) where D: Default, diff --git a/src/overlays/wayvr.rs b/src/overlays/wayvr.rs index f06cfcf..1e85422 100644 --- a/src/overlays/wayvr.rs +++ b/src/overlays/wayvr.rs @@ -2,9 +2,12 @@ use glam::{vec3a, Affine2, Vec3, Vec3A}; use std::{cell::RefCell, collections::HashMap, rc::Rc, sync::Arc}; use vulkano::{ command_buffer::CommandBufferUsage, - image::{view::ImageView, SubresourceLayout}, + format::Format, + image::{view::ImageView, Image, ImageTiling, SubresourceLayout}, + pipeline::graphics::input_assembly::PrimitiveTopology, }; use wayvr_ipc::packet_server::{self, PacketServer, WvrStateChanged}; +use wgui::gfx::{pipeline::WGfxPipeline, WGfx}; use wlx_capture::frame::{DmabufFrame, FourCC, FrameFormat, FramePlane}; use crate::{ @@ -19,12 +22,11 @@ use crate::{ wayvr::{ self, display, server_ipc::{gen_args_vec, gen_env_vec}, - WayVR, + WayVR, WayVRAction, WayVRDisplayClickAction, }, }, config_wayvr, - graphics::{CommandBuffers, WlxGraphics, WlxPipeline}, - gui::modular::button::{WayVRAction, WayVRDisplayClickAction}, + graphics::{dmabuf::WGfxDmabuf, CommandBuffers, ExtentExt, Vert2Uv}, state::{self, AppState, KeyboardFocus}, }; @@ -175,15 +177,15 @@ impl InteractionHandler for WayVRInteractionHandler { } struct ImageData { - vk_image: Arc, - vk_image_view: Arc, + vk_image: Arc, + vk_image_view: Arc, } pub struct WayVRRenderer { - pipeline: Arc, + pipeline: Arc>, image: Option, context: Rc>, - graphics: Arc, + graphics: Arc, resolution: [u16; 2], } @@ -194,21 +196,19 @@ impl WayVRRenderer { display: wayvr::display::DisplayHandle, resolution: [u16; 2], ) -> anyhow::Result { - let Ok(shaders) = app.graphics.shared_shaders.read() else { - anyhow::bail!("Failed to lock shared shaders for reading"); - }; - - let pipeline = app.graphics.create_pipeline( - shaders.get("vert_common").unwrap().clone(), // want panic - shaders.get("frag_srgb").unwrap().clone(), // want panic - app.graphics.native_format, + let pipeline = app.gfx.create_pipeline( + app.gfx_extras.shaders.get("vert_quad").unwrap().clone(), // want panic + app.gfx_extras.shaders.get("frag_srgb").unwrap().clone(), // want panic + app.gfx.surface_format, None, + PrimitiveTopology::TriangleStrip, + false, )?; Ok(Self { pipeline, context: Rc::new(RefCell::new(WayVRContext::new(wvr, display))), - graphics: app.graphics.clone(), + graphics: app.gfx.clone(), image: None, resolution, }) @@ -574,15 +574,14 @@ impl WayVRRenderer { &mut self, data: &wayvr::egl_data::RenderSoftwarePixelsData, ) -> anyhow::Result<()> { - let mut upload = self.graphics.create_uploads_command_buffer( - self.graphics.transfer_queue.clone(), - CommandBufferUsage::OneTimeSubmit, - )?; + let mut upload = self + .graphics + .create_xfer_command_buffer(CommandBufferUsage::OneTimeSubmit)?; - let tex = upload.texture2d_raw( + let tex = upload.upload_image( u32::from(data.width), u32::from(data.height), - vulkano::format::Format::R8G8B8A8_UNORM, + Format::R8G8B8A8_UNORM, &data.data, )?; @@ -644,7 +643,7 @@ impl WayVRRenderer { let tex = self.graphics.dmabuf_texture_ex( frame, - vulkano::image::ImageTiling::DrmFormatModifier, + ImageTiling::DrmFormatModifier, layouts, &data.mod_info.modifiers, )?; @@ -732,18 +731,22 @@ impl OverlayRenderer for WayVRRenderer { let set0 = self.pipeline.uniform_sampler( 0, image.vk_image_view.clone(), - app.graphics.texture_filtering, + app.gfx.texture_filter, )?; - let set1 = self.pipeline.uniform_buffer(1, vec![alpha])?; + let set1 = self.pipeline.uniform_buffer_upload(1, vec![alpha])?; - let pass = self - .pipeline - .create_pass_for_target(tgt.clone(), vec![set0, set1])?; + let pass = self.pipeline.create_pass( + tgt.extent_f32(), + app.gfx_extras.quad_verts.clone(), + 0..4, + 0..1, + vec![set0, set1], + )?; let mut cmd_buffer = app - .graphics - .create_command_buffer(CommandBufferUsage::OneTimeSubmit)?; + .gfx + .create_gfx_command_buffer(CommandBufferUsage::OneTimeSubmit)?; cmd_buffer.begin_rendering(tgt)?; cmd_buffer.run_ref(&pass)?; cmd_buffer.end_rendering()?; diff --git a/src/shaders/color.frag b/src/shaders/color.frag new file mode 100644 index 0000000..ec0e86f --- /dev/null +++ b/src/shaders/color.frag @@ -0,0 +1,24 @@ +#version 310 es +precision highp float; + +layout (location = 0) in vec2 in_uv; +layout (location = 0) out vec4 out_color; + +layout (set = 0, binding = 0) uniform ColorBlock { + uniform vec4 in_color; + uniform vec2 corner_radius; +}; + +void main() +{ + out_color.r = corner_radius.r; + out_color = in_color; + + vec2 uv_circ = ((1. - corner_radius) - (abs(in_uv + vec2(-0.5)) * 2.))/corner_radius; + float dist = length(uv_circ); + + out_color.a = mix(out_color.a, 0., + float(dist > 1.) + * float(uv_circ.x < 0.) + * float(uv_circ.y < 0.)); +} diff --git a/src/shaders/grid.frag b/src/shaders/grid.frag new file mode 100644 index 0000000..f225064 --- /dev/null +++ b/src/shaders/grid.frag @@ -0,0 +1,19 @@ +#version 310 es +precision highp float; + +layout (location = 0) in vec2 in_uv; +layout (location = 0) out vec4 out_color; + +void main() +{ + float fade = max(1.0 - 2.0 * length(in_uv.xy + vec2(-0.5, -0.5)), 0.0); + float grid; + + if (fract(in_uv.x / 0.0005) < 0.01 || fract(in_uv.y / 0.0005) < 0.01) { + grid = 1.0; + } else { + grid = 0.0; + } + out_color = vec4(1.0, 1.0, 1.0, grid * fade); +} + diff --git a/src/shaders/mod.rs b/src/shaders/mod.rs index 4de46d1..86e9f5c 100644 --- a/src/shaders/mod.rs +++ b/src/shaders/mod.rs @@ -1,266 +1,34 @@ -pub mod vert_common { +pub mod vert_quad { vulkano_shaders::shader! { ty: "vertex", - src: r"#version 310 es - precision highp float; - - layout (location = 0) in vec2 in_pos; - layout (location = 1) in vec2 in_uv; - layout (location = 0) out vec2 out_uv; - - void main() { - out_uv = in_uv; - gl_Position = vec4(in_pos * 2. - 1., 0., 1.); - } - ", + path: "src/shaders/quad.vert" } } pub mod frag_color { vulkano_shaders::shader! { ty: "fragment", - src: r"#version 310 es - precision highp float; - - layout (location = 0) in vec2 in_uv; - layout (location = 0) out vec4 out_color; - - layout (set = 0, binding = 0) uniform ColorBlock { - uniform vec4 in_color; - uniform vec2 corner_radius; - }; - - void main() - { - out_color.r = corner_radius.r; - out_color = in_color; - - vec2 uv_circ = ((1. - corner_radius) - (abs(in_uv + vec2(-0.5)) * 2.))/corner_radius; - float dist = length(uv_circ); - - out_color.a = mix(out_color.a, 0., - float(dist > 1.) - * float(uv_circ.x < 0.) - * float(uv_circ.y < 0.)); - } - ", - } -} - -//layout (location = 1) in float corner_radius; -//out_color = in_color; -// Some equation that determines whether to keep the pixel -// Use Lerp not if -//out_color.a = 0; - -pub mod frag_glyph { - vulkano_shaders::shader! { - ty: "fragment", - src: r"#version 310 es - precision highp float; - - layout (location = 0) in vec2 in_uv; - layout (location = 0) out vec4 out_color; - - layout (set = 0, binding = 0) uniform sampler2D in_texture; - - layout (set = 1, binding = 0) uniform ColorBlock { - uniform vec4 in_color; - }; - - void main() - { - float r = texture(in_texture, in_uv).r; - out_color = vec4(r,r,r,r) * in_color; - } - ", - } -} - -pub mod frag_sprite2 { - vulkano_shaders::shader! { - ty: "fragment", - src: r"#version 310 es - precision highp float; - - layout (location = 0) in vec2 in_uv; - layout (location = 0) out vec4 out_color; - - layout (set = 0, binding = 0) uniform sampler2D in_texture; - layout (set = 1, binding = 0) uniform UniBlock { - uniform vec4 st; - uniform vec4 mul; - }; - - void main() - { - out_color = texture(in_texture, (in_uv * st.xy) + st.zw) * mul; - } - ", - } -} - -pub mod frag_sprite2_hl { - vulkano_shaders::shader! { - ty: "fragment", - src: r"#version 310 es - precision highp float; - - layout (location = 0) in vec2 in_uv; - layout (location = 0) out vec4 out_color; - - layout (set = 0, binding = 0) uniform sampler2D in_texture; - layout (set = 1, binding = 0) uniform UniBlock { - uniform vec4 st; - uniform vec4 mul; - }; - - void main() - { - out_color = texture(in_texture, (in_uv * st.xy) + st.zw).a * mul; - } - ", - } -} - -pub mod frag_sprite { - vulkano_shaders::shader! { - ty: "fragment", - src: r"#version 310 es - precision highp float; - - layout (location = 0) in vec2 in_uv; - layout (location = 0) out vec4 out_color; - - layout (set = 0, binding = 0) uniform sampler2D in_texture; - - void main() - { - out_color = texture(in_texture, in_uv); - } - ", + path: "src/shaders/color.frag", } } pub mod frag_grid { vulkano_shaders::shader! { ty: "fragment", - src: r"#version 310 es - precision highp float; - - layout (location = 0) in vec2 in_uv; - layout (location = 0) out vec4 out_color; - - void main() - { - float fade = max(1.0 - 2.0 * length(in_uv.xy + vec2(-0.5, -0.5)), 0.0); - float grid; - - if (fract(in_uv.x / 0.0005) < 0.01 || fract(in_uv.y / 0.0005) < 0.01) { - grid = 1.0; - } else { - grid = 0.0; - } - out_color = vec4(1.0, 1.0, 1.0, grid * fade); - } - ", + path: "src/shaders/grid.frag", } } pub mod frag_screen { vulkano_shaders::shader! { ty: "fragment", - src: r"#version 310 es - precision highp float; - - layout (location = 0) in vec2 in_uv; - layout (location = 0) out vec4 out_color; - - layout (set = 0, binding = 0) uniform sampler2D in_texture; - layout (set = 1, binding = 0) uniform AlphaBlock { - uniform float alpha; - }; - - void main() - { - out_color = texture(in_texture, in_uv); - out_color.a = alpha; - } - ", + path: "src/shaders/screen.frag", } } pub mod frag_srgb { vulkano_shaders::shader! { ty: "fragment", - src: r"#version 310 es - precision highp float; - - layout (location = 0) in vec2 in_uv; - layout (location = 0) out vec4 out_color; - - layout (set = 0, binding = 0) uniform sampler2D in_texture; - layout (set = 1, binding = 0) uniform AlphaBlock { - uniform float alpha; - }; - - - void main() - { - out_color = texture(in_texture, in_uv); - - bvec4 cutoff = lessThan(out_color, vec4(0.04045)); - vec4 higher = pow((out_color + vec4(0.055))/vec4(1.055), vec4(2.4)); - vec4 lower = out_color/vec4(12.92); - - out_color = mix(higher, lower, cutoff); - out_color.a *= alpha; - } - ", - } -} - -pub mod frag_swapchain { - vulkano_shaders::shader! { - ty: "fragment", - src: r"#version 310 es - precision highp float; - - layout (location = 0) in vec2 in_uv; - layout (location = 0) out vec4 out_color; - - layout (set = 0, binding = 0) uniform sampler2D in_texture; - layout (set = 1, binding = 0) uniform AlphaBlock { - uniform float alpha; - }; - - void main() - { - out_color = texture(in_texture, in_uv); - out_color.a *= alpha; - } - ", - } -} - -pub mod frag_line { - vulkano_shaders::shader! { - ty: "fragment", - src: r"#version 310 es - precision highp float; - - layout (location = 0) in vec2 in_uv; - layout (location = 0) out vec4 out_color; - - layout (set = 0, binding = 0) uniform ColorBlock { - uniform vec4 in_color; - uniform vec2 unused; - }; - - void main() - { - out_color = in_color; - } - ", + path: "src/shaders/srgb.frag", } } diff --git a/src/shaders/quad.vert b/src/shaders/quad.vert new file mode 100644 index 0000000..58b93d3 --- /dev/null +++ b/src/shaders/quad.vert @@ -0,0 +1,11 @@ +#version 310 es +precision highp float; + +layout (location = 0) in vec2 in_pos; +layout (location = 1) in vec2 in_uv; +layout (location = 0) out vec2 out_uv; + +void main() { + out_uv = in_uv; + gl_Position = vec4(in_pos * 2. - 1., 0., 1.); +} diff --git a/src/shaders/screen.frag b/src/shaders/screen.frag new file mode 100644 index 0000000..8c4d7a9 --- /dev/null +++ b/src/shaders/screen.frag @@ -0,0 +1,17 @@ +#version 310 es +precision highp float; + +layout (location = 0) in vec2 in_uv; +layout (location = 0) out vec4 out_color; + +layout (set = 0, binding = 0) uniform sampler2D in_texture; +layout (set = 1, binding = 0) uniform AlphaBlock { + uniform float alpha; +}; + +void main() +{ + out_color = texture(in_texture, in_uv); + out_color.a = alpha; +} + diff --git a/src/shaders/srgb.frag b/src/shaders/srgb.frag new file mode 100644 index 0000000..3703468 --- /dev/null +++ b/src/shaders/srgb.frag @@ -0,0 +1,24 @@ +#version 310 es +precision highp float; + +layout (location = 0) in vec2 in_uv; +layout (location = 0) out vec4 out_color; + +layout (set = 0, binding = 0) uniform sampler2D in_texture; +layout (set = 1, binding = 0) uniform AlphaBlock { + uniform float alpha; +}; + + +void main() +{ + out_color = texture(in_texture, in_uv); + + bvec4 cutoff = lessThan(out_color, vec4(0.04045)); + vec4 higher = pow((out_color + vec4(0.055))/vec4(1.055), vec4(2.4)); + vec4 lower = out_color/vec4(12.92); + + out_color = mix(higher, lower, cutoff); + out_color.a *= alpha; +} + diff --git a/src/state.rs b/src/state.rs index b593af2..542de9e 100644 --- a/src/state.rs +++ b/src/state.rs @@ -1,4 +1,3 @@ -use anyhow::bail; use glam::Affine3A; use idmap::IdMap; use rodio::{Decoder, OutputStream, OutputStreamHandle, Source}; @@ -6,6 +5,7 @@ use serde::{Deserialize, Serialize}; use smallvec::{smallvec, SmallVec}; use std::{io::Cursor, sync::Arc}; use vulkano::image::view::ImageView; +use wgui::gfx::WGfx; #[cfg(feature = "wayvr")] use { @@ -21,14 +21,9 @@ use crate::{ backend::{input::InputState, overlay::OverlayID, task::TaskContainer}, config::{AStrMap, GeneralConfig}, config_io, - graphics::WlxGraphics, - gui::font::FontCache, + graphics::WGfxExtras, hid::HidProvider, overlays::toast::{DisplayMethod, ToastTopic}, - shaders::{ - frag_color, frag_glyph, frag_grid, frag_line, frag_screen, frag_sprite, frag_sprite2, - frag_sprite2_hl, frag_srgb, frag_swapchain, vert_common, - }, }; #[derive(Debug, Copy, Clone, PartialEq, Eq)] @@ -40,10 +35,12 @@ pub enum KeyboardFocus { } pub struct AppState { - pub fc: FontCache, pub session: AppSession, pub tasks: TaskContainer, - pub graphics: Arc, + + pub gfx: Arc, + pub gfx_extras: WGfxExtras, + pub input_state: InputState, pub hid_provider: Box, pub audio: AudioOutput, @@ -61,47 +58,8 @@ pub struct AppState { } impl AppState { - pub fn from_graphics(graphics: Arc) -> anyhow::Result { + pub fn from_graphics(gfx: Arc, gfx_extras: WGfxExtras) -> anyhow::Result { // insert shared resources - { - let Ok(mut shaders) = graphics.shared_shaders.write() else { - bail!("Failed to lock shared shaders"); - }; - - let shader = vert_common::load(graphics.device.clone())?; - shaders.insert("vert_common", shader); - - let shader = frag_color::load(graphics.device.clone())?; - shaders.insert("frag_color", shader); - - let shader = frag_line::load(graphics.device.clone())?; - shaders.insert("frag_line", shader); - - let shader = frag_srgb::load(graphics.device.clone())?; - shaders.insert("frag_srgb", shader); - - let shader = frag_glyph::load(graphics.device.clone())?; - shaders.insert("frag_glyph", shader); - - let shader = frag_grid::load(graphics.device.clone())?; - shaders.insert("frag_grid", shader); - - let shader = frag_sprite::load(graphics.device.clone())?; - shaders.insert("frag_sprite", shader); - - let shader = frag_sprite2::load(graphics.device.clone())?; - shaders.insert("frag_sprite2", shader); - - let shader = frag_sprite2_hl::load(graphics.device.clone())?; - shaders.insert("frag_sprite2_hl", shader); - - let shader = frag_screen::load(graphics.device.clone())?; - shaders.insert("frag_screen", shader); - - let shader = frag_swapchain::load(graphics.device.clone())?; - shaders.insert("frag_swapchain", shader); - } - #[cfg(feature = "wayvr")] let mut tasks = TaskContainer::new(); @@ -124,10 +82,10 @@ impl AppState { ); Ok(Self { - fc: FontCache::new(session.config.primary_font.clone())?, session, tasks, - graphics, + gfx, + gfx_extras, input_state: InputState::new(), hid_provider: crate::hid::initialize(), audio: AudioOutput::new(), From f05d3a82517598f7ac090bf107f6b3fbb2277700 Mon Sep 17 00:00:00 2001 From: galister <22305755+galister@users.noreply.github.com> Date: Wed, 18 Jun 2025 01:14:04 +0900 Subject: [PATCH 003/212] new workspace --- Cargo.lock | 137 +- Cargo.toml | 126 +- wgui/.editorconfig | 8 + wgui/.gitignore | 2 + wgui/Cargo.lock | 1966 +++++ wgui/Cargo.toml | 34 + wgui/README.md | 9 + wgui/contrib/logo.png | Bin 0 -> 6644 bytes wgui/doc/widgets.md | 105 + wgui/rustfmt.toml | 2 + wgui/src/animation.rs | 216 + wgui/src/any.rs | 16 + wgui/src/assets.rs | 3 + wgui/src/components/button.rs | 168 + wgui/src/components/mod.rs | 1 + wgui/src/drawing.rs | 200 + wgui/src/event.rs | 108 + wgui/src/gfx/cmd.rs | 176 + wgui/src/gfx/mod.rs | 311 + wgui/src/gfx/pass.rs | 187 + wgui/src/gfx/pipeline.rs | 286 + wgui/src/layout.rs | 319 + wgui/src/lib.rs | 16 + wgui/src/parser.rs | 816 ++ wgui/src/renderer_vk/context.rs | 221 + wgui/src/renderer_vk/mod.rs | 6 + wgui/src/renderer_vk/model_buffer.rs | 124 + wgui/src/renderer_vk/rect.rs | 171 + .../src/renderer_vk/shaders/model_buffer.glsl | 5 + wgui/src/renderer_vk/shaders/rect.frag | 54 + wgui/src/renderer_vk/shaders/rect.vert | 93 + .../renderer_vk/shaders/styles_buffer.glsl | 22 + wgui/src/renderer_vk/shaders/text.frag | 22 + wgui/src/renderer_vk/shaders/text.vert | 61 + wgui/src/renderer_vk/shaders/uniform.glsl | 8 + wgui/src/renderer_vk/text/custom_glyph.rs | 259 + wgui/src/renderer_vk/text/mod.rs | 225 + wgui/src/renderer_vk/text/shaders.rs | 13 + wgui/src/renderer_vk/text/text_atlas.rs | 335 + wgui/src/renderer_vk/text/text_renderer.rs | 484 ++ wgui/src/renderer_vk/util.rs | 18 + wgui/src/renderer_vk/viewport.rs | 103 + wgui/src/transform_stack.rs | 51 + wgui/src/widget/div.rs | 15 + wgui/src/widget/mod.rs | 342 + wgui/src/widget/rectangle.rs | 55 + wgui/src/widget/sprite.rs | 82 + wgui/src/widget/text.rs | 117 + wgui/src/widget/util.rs | 11 + wgui/uidev-vk/.gitignore | 1 + wgui/uidev-vk/Cargo.lock | 3389 +++++++++ wgui/uidev-vk/Cargo.toml | 22 + wgui/uidev-vk/assets/dashboard/add.svg | 3 + .../assets/dashboard/alphabetical.svg | 3 + wgui/uidev-vk/assets/dashboard/apps.svg | 3 + wgui/uidev-vk/assets/dashboard/back.svg | 3 + wgui/uidev-vk/assets/dashboard/bat_10.svg | 3 + wgui/uidev-vk/assets/dashboard/bat_100.svg | 3 + wgui/uidev-vk/assets/dashboard/bat_20.svg | 3 + wgui/uidev-vk/assets/dashboard/bat_30.svg | 3 + wgui/uidev-vk/assets/dashboard/bat_40.svg | 3 + wgui/uidev-vk/assets/dashboard/bat_50.svg | 3 + wgui/uidev-vk/assets/dashboard/bat_60.svg | 3 + wgui/uidev-vk/assets/dashboard/bat_70.svg | 3 + wgui/uidev-vk/assets/dashboard/bat_80.svg | 3 + wgui/uidev-vk/assets/dashboard/bat_90.svg | 3 + wgui/uidev-vk/assets/dashboard/bat_chr_10.svg | 3 + .../uidev-vk/assets/dashboard/bat_chr_100.svg | 3 + wgui/uidev-vk/assets/dashboard/bat_chr_20.svg | 3 + wgui/uidev-vk/assets/dashboard/bat_chr_30.svg | 3 + wgui/uidev-vk/assets/dashboard/bat_chr_40.svg | 3 + wgui/uidev-vk/assets/dashboard/bat_chr_50.svg | 3 + wgui/uidev-vk/assets/dashboard/bat_chr_60.svg | 3 + wgui/uidev-vk/assets/dashboard/bat_chr_70.svg | 3 + wgui/uidev-vk/assets/dashboard/bat_chr_80.svg | 3 + wgui/uidev-vk/assets/dashboard/bat_chr_90.svg | 3 + wgui/uidev-vk/assets/dashboard/binary.svg | 7 + wgui/uidev-vk/assets/dashboard/burger.svg | 3 + .../assets/dashboard/category_search.svg | 3 + wgui/uidev-vk/assets/dashboard/circle.svg | 3 + wgui/uidev-vk/assets/dashboard/close.svg | 3 + wgui/uidev-vk/assets/dashboard/cpu.svg | 4 + wgui/uidev-vk/assets/dashboard/display.svg | 3 + .../uidev-vk/assets/dashboard/displayport.svg | 6 + wgui/uidev-vk/assets/dashboard/eye.svg | 6 + wgui/uidev-vk/assets/dashboard/fix_floor.svg | 3 + wgui/uidev-vk/assets/dashboard/games.svg | 3 + wgui/uidev-vk/assets/dashboard/github.svg | 3 + wgui/uidev-vk/assets/dashboard/globe.svg | 3 + wgui/uidev-vk/assets/dashboard/home.svg | 3 + wgui/uidev-vk/assets/dashboard/knife.svg | 3 + wgui/uidev-vk/assets/dashboard/magic_wand.svg | 3 + wgui/uidev-vk/assets/dashboard/microphone.svg | 3 + wgui/uidev-vk/assets/dashboard/minijack.svg | 3 + wgui/uidev-vk/assets/dashboard/monado.svg | 44 + wgui/uidev-vk/assets/dashboard/panorama.svg | 3 + wgui/uidev-vk/assets/dashboard/play.svg | 3 + wgui/uidev-vk/assets/dashboard/power.svg | 3 + wgui/uidev-vk/assets/dashboard/recenter.svg | 3 + wgui/uidev-vk/assets/dashboard/refresh.svg | 3 + .../assets/dashboard/remove_circle.svg | 3 + wgui/uidev-vk/assets/dashboard/search.svg | 3 + wgui/uidev-vk/assets/dashboard/settings.svg | 3 + wgui/uidev-vk/assets/dashboard/sleep.svg | 3 + wgui/uidev-vk/assets/dashboard/terminal.svg | 3 + wgui/uidev-vk/assets/dashboard/usage.svg | 3 + wgui/uidev-vk/assets/dashboard/volume.svg | 3 + wgui/uidev-vk/assets/dashboard/volume_off.svg | 3 + wgui/uidev-vk/assets/dashboard/vr.svg | 3 + .../assets/dashboard/wayvr_dashboard.svg | 110 + .../assets/dashboard/wayvr_dashboard_mono.svg | 77 + wgui/uidev-vk/assets/dashboard/window.svg | 4 + wgui/uidev-vk/assets/gui/anchor.xml | 123 + wgui/uidev-vk/assets/gui/dashboard.xml | 123 + wgui/uidev-vk/assets/gui/testbed.xml | 87 + wgui/uidev-vk/assets/gui/testbed/icons.xml | 12 + wgui/uidev-vk/assets/gui/theme.xml | 8 + wgui/uidev-vk/assets/raster.png | Bin 0 -> 422 bytes .../test => wgui/uidev-vk/res/watch.xml | 0 wgui/uidev-vk/src/assets.rs | 12 + wgui/uidev-vk/src/main.rs | 332 + wgui/uidev-vk/src/profiler.rs | 49 + wgui/uidev-vk/src/testbed/mod.rs | 9 + .../uidev-vk/src/testbed/testbed_dashboard.rs | 34 + wgui/uidev-vk/src/testbed/testbed_generic.rs | 104 + wgui/uidev-vk/src/timestep.rs | 70 + wgui/uidev-vk/src/vulkan.rs | 211 + wlx-capture/.gitignore | 1 + wlx-capture/Cargo.lock | 2011 +++++ wlx-capture/Cargo.toml | 51 + LICENSE => wlx-capture/LICENSE | 0 wlx-capture/README.md | 78 + wlx-capture/src/frame.rs | 184 + wlx-capture/src/lib.rs | 35 + wlx-capture/src/pipewire.rs | 699 ++ wlx-capture/src/wayland.rs | 428 ++ wlx-capture/src/wlr_dmabuf.rs | 243 + wlx-capture/src/wlr_screencopy.rs | 383 + wlx-capture/src/xshm.rs | 178 + .../.github}/ISSUE_TEMPLATE/bug-report.md | 0 .../.github}/workflows/build-all-features.yml | 0 .../.github}/workflows/build-appimage.yml | 0 .../.github}/workflows/build-default.yml | 0 .../workflows/build-full-appimage.yml | 0 .../workflows/build-wayland-openvr.yml | 0 .../build-wayland-openxr-openvr-wayvr.yml | 0 .../workflows/build-wayland-openxr.yml | 0 .../.github}/workflows/build-x11-openvr.yml | 0 .../.github}/workflows/build-x11-openxr.yml | 0 .../.github}/workflows/make-release.yml | 0 .../scripts/appimage_build_wayvr_dashboard.sh | 0 .../workflows/scripts/appimage_build_wlx.sh | 0 .../workflows/scripts/appimage_package.sh | 0 .../scripts/appimage_package_full.sh | 0 .../workflows/scripts/appimage_prepare_env.sh | 0 wlx-overlay-s/.gitignore | 2 + wlx-overlay-s/Cargo.lock | 6606 +++++++++++++++++ wlx-overlay-s/Cargo.toml | 120 + wlx-overlay-s/LICENSE | 674 ++ README.md => wlx-overlay-s/README.md | 0 build.rs => wlx-overlay-s/build.rs | 0 .../contrib}/wayvr/README.md | 0 .../contrib}/wayvr/watch_wayvr_example.yaml | 0 .../contrib}/wlx-overlay-s.service | 0 .../com.github.galister.wlx-overlay-s.yml | 0 .../flatpak}/sources-wlx-overlay-s.json | 0 {src => wlx-overlay-s/src}/backend/common.rs | 0 {src => wlx-overlay-s/src}/backend/input.rs | 0 {src => wlx-overlay-s/src}/backend/mod.rs | 0 .../src}/backend/notifications.rs | 0 .../src}/backend/notifications_dbus.rs | 0 .../src}/backend/openvr/helpers.rs | 0 .../src}/backend/openvr/input.rs | 0 .../src}/backend/openvr/lines.rs | 0 .../src}/backend/openvr/manifest.rs | 0 .../src}/backend/openvr/mod.rs | 0 .../src}/backend/openvr/overlay.rs | 0 .../src}/backend/openvr/playspace.rs | 0 .../src}/backend/openxr/blocker.rs | 0 .../src}/backend/openxr/helpers.rs | 0 .../src}/backend/openxr/input.rs | 0 .../src}/backend/openxr/lines.rs | 0 .../src}/backend/openxr/mod.rs | 0 .../src}/backend/openxr/openxr_actions.json5 | 0 .../src}/backend/openxr/overlay.rs | 0 .../src}/backend/openxr/playspace.rs | 0 .../src}/backend/openxr/skybox.rs | 0 .../src}/backend/openxr/swapchain.rs | 0 {src => wlx-overlay-s/src}/backend/osc.rs | 0 {src => wlx-overlay-s/src}/backend/overlay.rs | 0 {src => wlx-overlay-s/src}/backend/task.rs | 0 .../src}/backend/wayvr/client.rs | 0 .../src}/backend/wayvr/comp.rs | 0 .../src}/backend/wayvr/display.rs | 0 .../src}/backend/wayvr/egl_data.rs | 0 .../src}/backend/wayvr/egl_ex.rs | 0 .../src}/backend/wayvr/event_queue.rs | 0 .../src}/backend/wayvr/handle.rs | 0 .../src}/backend/wayvr/mod.rs | 0 .../src}/backend/wayvr/process.rs | 0 .../src}/backend/wayvr/server_ipc.rs | 0 .../src}/backend/wayvr/smithay_wrapper.rs | 0 .../src}/backend/wayvr/time.rs | 0 .../src}/backend/wayvr/window.rs | 0 {src => wlx-overlay-s/src}/config.rs | 0 {src => wlx-overlay-s/src}/config_io.rs | 0 {src => wlx-overlay-s/src}/config_wayvr.rs | 0 {src => wlx-overlay-s/src}/graphics/dds.rs | 0 {src => wlx-overlay-s/src}/graphics/dmabuf.rs | 0 {src => wlx-overlay-s/src}/graphics/mod.rs | 0 {src => wlx-overlay-s/src}/gui/asset.rs | 0 {src => wlx-overlay-s/src}/gui/mod.rs | 0 {src => wlx-overlay-s/src}/gui/panel.rs | 0 {src => wlx-overlay-s/src}/gui/timestep.rs | 0 {src => wlx-overlay-s/src}/hid/mod.rs | 0 {src => wlx-overlay-s/src}/hid/wayland.rs | 0 {src => wlx-overlay-s/src}/hid/x11.rs | 0 {src => wlx-overlay-s/src}/main.rs | 0 {src => wlx-overlay-s/src}/overlays/anchor.rs | 0 {src => wlx-overlay-s/src}/overlays/custom.rs | 0 .../src}/overlays/keyboard.rs | 0 {src => wlx-overlay-s/src}/overlays/mirror.rs | 0 {src => wlx-overlay-s/src}/overlays/mod.rs | 0 {src => wlx-overlay-s/src}/overlays/screen.rs | 0 {src => wlx-overlay-s/src}/overlays/toast.rs | 0 {src => wlx-overlay-s/src}/overlays/watch.rs | 0 {src => wlx-overlay-s/src}/overlays/wayvr.rs | 0 {src => wlx-overlay-s/src}/res/380885.wav | Bin {src => wlx-overlay-s/src}/res/421581.wav | Bin {src => wlx-overlay-s/src}/res/557297.wav | Bin {src => wlx-overlay-s/src}/res/660533.wav | Bin {src => wlx-overlay-s/src}/res/actions.json | 0 .../src}/res/actions_binding_knuckles.json | 0 .../src}/res/actions_binding_oculus.json | 0 .../src}/res/actions_binding_vive.json | 0 {src => wlx-overlay-s/src}/res/anchor.yaml | 0 {src => wlx-overlay-s/src}/res/config.yaml | 0 {src => wlx-overlay-s/src}/res/keyboard.yaml | 0 {src => wlx-overlay-s/src}/res/settings.yaml | 0 .../src}/res/table_mountain_2.dds | Bin {src => wlx-overlay-s/src}/res/watch.yaml | 0 {src => wlx-overlay-s/src}/res/wayvr.yaml | 0 {src => wlx-overlay-s/src}/shaders/color.frag | 0 {src => wlx-overlay-s/src}/shaders/grid.frag | 0 {src => wlx-overlay-s/src}/shaders/mod.rs | 0 {src => wlx-overlay-s/src}/shaders/quad.vert | 0 .../src}/shaders/screen.frag | 0 {src => wlx-overlay-s/src}/shaders/srgb.frag | 0 {src => wlx-overlay-s/src}/state.rs | 0 .../wlx-overlay-s.desktop | 0 .../wlx-overlay-s.png | Bin .../wlx-overlay-s.svg | 0 252 files changed, 24618 insertions(+), 184 deletions(-) create mode 100644 wgui/.editorconfig create mode 100644 wgui/.gitignore create mode 100644 wgui/Cargo.lock create mode 100644 wgui/Cargo.toml create mode 100644 wgui/README.md create mode 100644 wgui/contrib/logo.png create mode 100644 wgui/doc/widgets.md create mode 100644 wgui/rustfmt.toml create mode 100644 wgui/src/animation.rs create mode 100644 wgui/src/any.rs create mode 100644 wgui/src/assets.rs create mode 100644 wgui/src/components/button.rs create mode 100644 wgui/src/components/mod.rs create mode 100644 wgui/src/drawing.rs create mode 100644 wgui/src/event.rs create mode 100644 wgui/src/gfx/cmd.rs create mode 100644 wgui/src/gfx/mod.rs create mode 100644 wgui/src/gfx/pass.rs create mode 100644 wgui/src/gfx/pipeline.rs create mode 100644 wgui/src/layout.rs create mode 100644 wgui/src/lib.rs create mode 100644 wgui/src/parser.rs create mode 100644 wgui/src/renderer_vk/context.rs create mode 100644 wgui/src/renderer_vk/mod.rs create mode 100644 wgui/src/renderer_vk/model_buffer.rs create mode 100644 wgui/src/renderer_vk/rect.rs create mode 100644 wgui/src/renderer_vk/shaders/model_buffer.glsl create mode 100644 wgui/src/renderer_vk/shaders/rect.frag create mode 100644 wgui/src/renderer_vk/shaders/rect.vert create mode 100644 wgui/src/renderer_vk/shaders/styles_buffer.glsl create mode 100644 wgui/src/renderer_vk/shaders/text.frag create mode 100644 wgui/src/renderer_vk/shaders/text.vert create mode 100644 wgui/src/renderer_vk/shaders/uniform.glsl create mode 100644 wgui/src/renderer_vk/text/custom_glyph.rs create mode 100644 wgui/src/renderer_vk/text/mod.rs create mode 100644 wgui/src/renderer_vk/text/shaders.rs create mode 100644 wgui/src/renderer_vk/text/text_atlas.rs create mode 100644 wgui/src/renderer_vk/text/text_renderer.rs create mode 100644 wgui/src/renderer_vk/util.rs create mode 100644 wgui/src/renderer_vk/viewport.rs create mode 100644 wgui/src/transform_stack.rs create mode 100644 wgui/src/widget/div.rs create mode 100644 wgui/src/widget/mod.rs create mode 100644 wgui/src/widget/rectangle.rs create mode 100644 wgui/src/widget/sprite.rs create mode 100644 wgui/src/widget/text.rs create mode 100644 wgui/src/widget/util.rs create mode 100644 wgui/uidev-vk/.gitignore create mode 100644 wgui/uidev-vk/Cargo.lock create mode 100644 wgui/uidev-vk/Cargo.toml create mode 100644 wgui/uidev-vk/assets/dashboard/add.svg create mode 100644 wgui/uidev-vk/assets/dashboard/alphabetical.svg create mode 100644 wgui/uidev-vk/assets/dashboard/apps.svg create mode 100644 wgui/uidev-vk/assets/dashboard/back.svg create mode 100644 wgui/uidev-vk/assets/dashboard/bat_10.svg create mode 100644 wgui/uidev-vk/assets/dashboard/bat_100.svg create mode 100644 wgui/uidev-vk/assets/dashboard/bat_20.svg create mode 100644 wgui/uidev-vk/assets/dashboard/bat_30.svg create mode 100644 wgui/uidev-vk/assets/dashboard/bat_40.svg create mode 100644 wgui/uidev-vk/assets/dashboard/bat_50.svg create mode 100644 wgui/uidev-vk/assets/dashboard/bat_60.svg create mode 100644 wgui/uidev-vk/assets/dashboard/bat_70.svg create mode 100644 wgui/uidev-vk/assets/dashboard/bat_80.svg create mode 100644 wgui/uidev-vk/assets/dashboard/bat_90.svg create mode 100644 wgui/uidev-vk/assets/dashboard/bat_chr_10.svg create mode 100644 wgui/uidev-vk/assets/dashboard/bat_chr_100.svg create mode 100644 wgui/uidev-vk/assets/dashboard/bat_chr_20.svg create mode 100644 wgui/uidev-vk/assets/dashboard/bat_chr_30.svg create mode 100644 wgui/uidev-vk/assets/dashboard/bat_chr_40.svg create mode 100644 wgui/uidev-vk/assets/dashboard/bat_chr_50.svg create mode 100644 wgui/uidev-vk/assets/dashboard/bat_chr_60.svg create mode 100644 wgui/uidev-vk/assets/dashboard/bat_chr_70.svg create mode 100644 wgui/uidev-vk/assets/dashboard/bat_chr_80.svg create mode 100644 wgui/uidev-vk/assets/dashboard/bat_chr_90.svg create mode 100644 wgui/uidev-vk/assets/dashboard/binary.svg create mode 100644 wgui/uidev-vk/assets/dashboard/burger.svg create mode 100644 wgui/uidev-vk/assets/dashboard/category_search.svg create mode 100644 wgui/uidev-vk/assets/dashboard/circle.svg create mode 100644 wgui/uidev-vk/assets/dashboard/close.svg create mode 100644 wgui/uidev-vk/assets/dashboard/cpu.svg create mode 100644 wgui/uidev-vk/assets/dashboard/display.svg create mode 100644 wgui/uidev-vk/assets/dashboard/displayport.svg create mode 100644 wgui/uidev-vk/assets/dashboard/eye.svg create mode 100644 wgui/uidev-vk/assets/dashboard/fix_floor.svg create mode 100644 wgui/uidev-vk/assets/dashboard/games.svg create mode 100644 wgui/uidev-vk/assets/dashboard/github.svg create mode 100644 wgui/uidev-vk/assets/dashboard/globe.svg create mode 100644 wgui/uidev-vk/assets/dashboard/home.svg create mode 100644 wgui/uidev-vk/assets/dashboard/knife.svg create mode 100644 wgui/uidev-vk/assets/dashboard/magic_wand.svg create mode 100644 wgui/uidev-vk/assets/dashboard/microphone.svg create mode 100644 wgui/uidev-vk/assets/dashboard/minijack.svg create mode 100644 wgui/uidev-vk/assets/dashboard/monado.svg create mode 100644 wgui/uidev-vk/assets/dashboard/panorama.svg create mode 100644 wgui/uidev-vk/assets/dashboard/play.svg create mode 100644 wgui/uidev-vk/assets/dashboard/power.svg create mode 100644 wgui/uidev-vk/assets/dashboard/recenter.svg create mode 100644 wgui/uidev-vk/assets/dashboard/refresh.svg create mode 100644 wgui/uidev-vk/assets/dashboard/remove_circle.svg create mode 100644 wgui/uidev-vk/assets/dashboard/search.svg create mode 100644 wgui/uidev-vk/assets/dashboard/settings.svg create mode 100644 wgui/uidev-vk/assets/dashboard/sleep.svg create mode 100644 wgui/uidev-vk/assets/dashboard/terminal.svg create mode 100644 wgui/uidev-vk/assets/dashboard/usage.svg create mode 100644 wgui/uidev-vk/assets/dashboard/volume.svg create mode 100644 wgui/uidev-vk/assets/dashboard/volume_off.svg create mode 100644 wgui/uidev-vk/assets/dashboard/vr.svg create mode 100644 wgui/uidev-vk/assets/dashboard/wayvr_dashboard.svg create mode 100644 wgui/uidev-vk/assets/dashboard/wayvr_dashboard_mono.svg create mode 100644 wgui/uidev-vk/assets/dashboard/window.svg create mode 100644 wgui/uidev-vk/assets/gui/anchor.xml create mode 100644 wgui/uidev-vk/assets/gui/dashboard.xml create mode 100644 wgui/uidev-vk/assets/gui/testbed.xml create mode 100644 wgui/uidev-vk/assets/gui/testbed/icons.xml create mode 100644 wgui/uidev-vk/assets/gui/theme.xml create mode 100644 wgui/uidev-vk/assets/raster.png rename src/gui/assets/test => wgui/uidev-vk/res/watch.xml (100%) create mode 100644 wgui/uidev-vk/src/assets.rs create mode 100644 wgui/uidev-vk/src/main.rs create mode 100644 wgui/uidev-vk/src/profiler.rs create mode 100644 wgui/uidev-vk/src/testbed/mod.rs create mode 100644 wgui/uidev-vk/src/testbed/testbed_dashboard.rs create mode 100644 wgui/uidev-vk/src/testbed/testbed_generic.rs create mode 100644 wgui/uidev-vk/src/timestep.rs create mode 100644 wgui/uidev-vk/src/vulkan.rs create mode 100644 wlx-capture/.gitignore create mode 100644 wlx-capture/Cargo.lock create mode 100644 wlx-capture/Cargo.toml rename LICENSE => wlx-capture/LICENSE (100%) create mode 100644 wlx-capture/README.md create mode 100644 wlx-capture/src/frame.rs create mode 100644 wlx-capture/src/lib.rs create mode 100644 wlx-capture/src/pipewire.rs create mode 100644 wlx-capture/src/wayland.rs create mode 100644 wlx-capture/src/wlr_dmabuf.rs create mode 100644 wlx-capture/src/wlr_screencopy.rs create mode 100644 wlx-capture/src/xshm.rs rename {.github => wlx-overlay-s/.github}/ISSUE_TEMPLATE/bug-report.md (100%) rename {.github => wlx-overlay-s/.github}/workflows/build-all-features.yml (100%) rename {.github => wlx-overlay-s/.github}/workflows/build-appimage.yml (100%) rename {.github => wlx-overlay-s/.github}/workflows/build-default.yml (100%) rename {.github => wlx-overlay-s/.github}/workflows/build-full-appimage.yml (100%) rename {.github => wlx-overlay-s/.github}/workflows/build-wayland-openvr.yml (100%) rename {.github => wlx-overlay-s/.github}/workflows/build-wayland-openxr-openvr-wayvr.yml (100%) rename {.github => wlx-overlay-s/.github}/workflows/build-wayland-openxr.yml (100%) rename {.github => wlx-overlay-s/.github}/workflows/build-x11-openvr.yml (100%) rename {.github => wlx-overlay-s/.github}/workflows/build-x11-openxr.yml (100%) rename {.github => wlx-overlay-s/.github}/workflows/make-release.yml (100%) rename {.github => wlx-overlay-s/.github}/workflows/scripts/appimage_build_wayvr_dashboard.sh (100%) rename {.github => wlx-overlay-s/.github}/workflows/scripts/appimage_build_wlx.sh (100%) rename {.github => wlx-overlay-s/.github}/workflows/scripts/appimage_package.sh (100%) rename {.github => wlx-overlay-s/.github}/workflows/scripts/appimage_package_full.sh (100%) rename {.github => wlx-overlay-s/.github}/workflows/scripts/appimage_prepare_env.sh (100%) create mode 100644 wlx-overlay-s/.gitignore create mode 100644 wlx-overlay-s/Cargo.lock create mode 100644 wlx-overlay-s/Cargo.toml create mode 100644 wlx-overlay-s/LICENSE rename README.md => wlx-overlay-s/README.md (100%) rename build.rs => wlx-overlay-s/build.rs (100%) rename {contrib => wlx-overlay-s/contrib}/wayvr/README.md (100%) rename {contrib => wlx-overlay-s/contrib}/wayvr/watch_wayvr_example.yaml (100%) rename {contrib => wlx-overlay-s/contrib}/wlx-overlay-s.service (100%) rename {flatpak => wlx-overlay-s/flatpak}/com.github.galister.wlx-overlay-s.yml (100%) rename {flatpak => wlx-overlay-s/flatpak}/sources-wlx-overlay-s.json (100%) rename {src => wlx-overlay-s/src}/backend/common.rs (100%) rename {src => wlx-overlay-s/src}/backend/input.rs (100%) rename {src => wlx-overlay-s/src}/backend/mod.rs (100%) rename {src => wlx-overlay-s/src}/backend/notifications.rs (100%) rename {src => wlx-overlay-s/src}/backend/notifications_dbus.rs (100%) rename {src => wlx-overlay-s/src}/backend/openvr/helpers.rs (100%) rename {src => wlx-overlay-s/src}/backend/openvr/input.rs (100%) rename {src => wlx-overlay-s/src}/backend/openvr/lines.rs (100%) rename {src => wlx-overlay-s/src}/backend/openvr/manifest.rs (100%) rename {src => wlx-overlay-s/src}/backend/openvr/mod.rs (100%) rename {src => wlx-overlay-s/src}/backend/openvr/overlay.rs (100%) rename {src => wlx-overlay-s/src}/backend/openvr/playspace.rs (100%) rename {src => wlx-overlay-s/src}/backend/openxr/blocker.rs (100%) rename {src => wlx-overlay-s/src}/backend/openxr/helpers.rs (100%) rename {src => wlx-overlay-s/src}/backend/openxr/input.rs (100%) rename {src => wlx-overlay-s/src}/backend/openxr/lines.rs (100%) rename {src => wlx-overlay-s/src}/backend/openxr/mod.rs (100%) rename {src => wlx-overlay-s/src}/backend/openxr/openxr_actions.json5 (100%) rename {src => wlx-overlay-s/src}/backend/openxr/overlay.rs (100%) rename {src => wlx-overlay-s/src}/backend/openxr/playspace.rs (100%) rename {src => wlx-overlay-s/src}/backend/openxr/skybox.rs (100%) rename {src => wlx-overlay-s/src}/backend/openxr/swapchain.rs (100%) rename {src => wlx-overlay-s/src}/backend/osc.rs (100%) rename {src => wlx-overlay-s/src}/backend/overlay.rs (100%) rename {src => wlx-overlay-s/src}/backend/task.rs (100%) rename {src => wlx-overlay-s/src}/backend/wayvr/client.rs (100%) rename {src => wlx-overlay-s/src}/backend/wayvr/comp.rs (100%) rename {src => wlx-overlay-s/src}/backend/wayvr/display.rs (100%) rename {src => wlx-overlay-s/src}/backend/wayvr/egl_data.rs (100%) rename {src => wlx-overlay-s/src}/backend/wayvr/egl_ex.rs (100%) rename {src => wlx-overlay-s/src}/backend/wayvr/event_queue.rs (100%) rename {src => wlx-overlay-s/src}/backend/wayvr/handle.rs (100%) rename {src => wlx-overlay-s/src}/backend/wayvr/mod.rs (100%) rename {src => wlx-overlay-s/src}/backend/wayvr/process.rs (100%) rename {src => wlx-overlay-s/src}/backend/wayvr/server_ipc.rs (100%) rename {src => wlx-overlay-s/src}/backend/wayvr/smithay_wrapper.rs (100%) rename {src => wlx-overlay-s/src}/backend/wayvr/time.rs (100%) rename {src => wlx-overlay-s/src}/backend/wayvr/window.rs (100%) rename {src => wlx-overlay-s/src}/config.rs (100%) rename {src => wlx-overlay-s/src}/config_io.rs (100%) rename {src => wlx-overlay-s/src}/config_wayvr.rs (100%) rename {src => wlx-overlay-s/src}/graphics/dds.rs (100%) rename {src => wlx-overlay-s/src}/graphics/dmabuf.rs (100%) rename {src => wlx-overlay-s/src}/graphics/mod.rs (100%) rename {src => wlx-overlay-s/src}/gui/asset.rs (100%) rename {src => wlx-overlay-s/src}/gui/mod.rs (100%) rename {src => wlx-overlay-s/src}/gui/panel.rs (100%) rename {src => wlx-overlay-s/src}/gui/timestep.rs (100%) rename {src => wlx-overlay-s/src}/hid/mod.rs (100%) rename {src => wlx-overlay-s/src}/hid/wayland.rs (100%) rename {src => wlx-overlay-s/src}/hid/x11.rs (100%) rename {src => wlx-overlay-s/src}/main.rs (100%) rename {src => wlx-overlay-s/src}/overlays/anchor.rs (100%) rename {src => wlx-overlay-s/src}/overlays/custom.rs (100%) rename {src => wlx-overlay-s/src}/overlays/keyboard.rs (100%) rename {src => wlx-overlay-s/src}/overlays/mirror.rs (100%) rename {src => wlx-overlay-s/src}/overlays/mod.rs (100%) rename {src => wlx-overlay-s/src}/overlays/screen.rs (100%) rename {src => wlx-overlay-s/src}/overlays/toast.rs (100%) rename {src => wlx-overlay-s/src}/overlays/watch.rs (100%) rename {src => wlx-overlay-s/src}/overlays/wayvr.rs (100%) rename {src => wlx-overlay-s/src}/res/380885.wav (100%) rename {src => wlx-overlay-s/src}/res/421581.wav (100%) rename {src => wlx-overlay-s/src}/res/557297.wav (100%) rename {src => wlx-overlay-s/src}/res/660533.wav (100%) rename {src => wlx-overlay-s/src}/res/actions.json (100%) rename {src => wlx-overlay-s/src}/res/actions_binding_knuckles.json (100%) rename {src => wlx-overlay-s/src}/res/actions_binding_oculus.json (100%) rename {src => wlx-overlay-s/src}/res/actions_binding_vive.json (100%) rename {src => wlx-overlay-s/src}/res/anchor.yaml (100%) rename {src => wlx-overlay-s/src}/res/config.yaml (100%) rename {src => wlx-overlay-s/src}/res/keyboard.yaml (100%) rename {src => wlx-overlay-s/src}/res/settings.yaml (100%) rename {src => wlx-overlay-s/src}/res/table_mountain_2.dds (100%) rename {src => wlx-overlay-s/src}/res/watch.yaml (100%) rename {src => wlx-overlay-s/src}/res/wayvr.yaml (100%) rename {src => wlx-overlay-s/src}/shaders/color.frag (100%) rename {src => wlx-overlay-s/src}/shaders/grid.frag (100%) rename {src => wlx-overlay-s/src}/shaders/mod.rs (100%) rename {src => wlx-overlay-s/src}/shaders/quad.vert (100%) rename {src => wlx-overlay-s/src}/shaders/screen.frag (100%) rename {src => wlx-overlay-s/src}/shaders/srgb.frag (100%) rename {src => wlx-overlay-s/src}/state.rs (100%) rename wlx-overlay-s.desktop => wlx-overlay-s/wlx-overlay-s.desktop (100%) rename wlx-overlay-s.png => wlx-overlay-s/wlx-overlay-s.png (100%) rename wlx-overlay-s.svg => wlx-overlay-s/wlx-overlay-s.svg (100%) diff --git a/Cargo.lock b/Cargo.lock index 75dcea5..f0660a6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -215,15 +215,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "approx" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6" -dependencies = [ - "num-traits", -] - [[package]] name = "aquamarine" version = "0.1.12" @@ -879,7 +870,7 @@ version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a98d30140e3296250832bbaaff83b27dcd6fa3cc70fb6f1f3e5c9c0023b5317" dependencies = [ - "approx 0.4.0", + "approx", "num-traits", ] @@ -1039,12 +1030,6 @@ dependencies = [ "yaml-rust2", ] -[[package]] -name = "const-cstr" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed3d0b5ff30645a68f35ece8cea4556ca14ef8a1651455f789a099a0513532a6" - [[package]] name = "const-random" version = "0.1.18" @@ -1799,18 +1784,6 @@ dependencies = [ "roxmltree 0.20.0", ] -[[package]] -name = "fontconfig-rs" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb4baadad5111c6820e97fc8bde5077258e6f272b5b38538db4b42e1812f29f3" -dependencies = [ - "const-cstr", - "once_cell", - "thiserror 1.0.69", - "yeslogic-fontconfig-sys", -] - [[package]] name = "fontdb" version = "0.16.2" @@ -1861,28 +1834,6 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "freetype-rs" -version = "0.36.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5442dee36ca09604133580dc0553780e867936bb3cbef3275859e889026d2b17" -dependencies = [ - "bitflags 2.9.1", - "freetype-sys", - "libc", -] - -[[package]] -name = "freetype-sys" -version = "0.20.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e7edc5b9669349acfda99533e9e0bcf26a51862ab43b08ee7745c55d28eb134" -dependencies = [ - "cc", - "libc", - "pkg-config", -] - [[package]] name = "futures" version = "0.3.31" @@ -2061,7 +2012,6 @@ version = "0.30.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "50a99dbe56b72736564cfa4b85bf9a33079f16ae8b74983ab06af3b1a3696b11" dependencies = [ - "approx 0.5.1", "mint", "serde", ] @@ -4194,6 +4144,40 @@ version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c20b6793b5c2fa6553b250154b78d6d0db37e72700ae35fad9387a46f487c97" +[[package]] +name = "rust-embed" +version = "8.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "025908b8682a26ba8d12f6f2d66b987584a4a87bc024abc5bbc12553a8cd178a" +dependencies = [ + "rust-embed-impl", + "rust-embed-utils", + "walkdir", +] + +[[package]] +name = "rust-embed-impl" +version = "8.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6065f1a4392b71819ec1ea1df1120673418bf386f50de1d6f54204d836d4349c" +dependencies = [ + "proc-macro2", + "quote", + "rust-embed-utils", + "syn 2.0.103", + "walkdir", +] + +[[package]] +name = "rust-embed-utils" +version = "8.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6cc0c81648b20b70c491ff8cce00c1c3b223bb8ed2b5d41f0e54c6c4c0a3594" +dependencies = [ + "sha2", + "walkdir", +] + [[package]] name = "rust-ini" version = "0.21.1" @@ -5089,6 +5073,21 @@ dependencies = [ "winapi", ] +[[package]] +name = "uidev-vk" +version = "0.1.0" +dependencies = [ + "anyhow", + "glam", + "log", + "rust-embed", + "tracing-subscriber", + "vulkano", + "vulkano-shaders", + "wgui", + "winit", +] + [[package]] name = "unicode-bidi" version = "0.3.18" @@ -5593,7 +5592,6 @@ checksum = "a751b3277700db47d3e574514de2eced5e54dc8a5436a3bf7a0b248b2cee16f3" [[package]] name = "wgui" version = "0.1.0" -source = "git+https://github.com/wlx-team/wgui.git?branch=wip#455fabb31931b888f9b976c6a914c6f4f73b7beb" dependencies = [ "anyhow", "cosmic-text", @@ -6140,6 +6138,22 @@ dependencies = [ "bitflags 2.9.1", ] +[[package]] +name = "wlx-capture" +version = "0.5.3" +dependencies = [ + "ashpd", + "drm-fourcc", + "idmap", + "libc", + "log", + "pipewire", + "rxscreen", + "smithay-client-toolkit", + "wayland-client", + "wayland-protocols", +] + [[package]] name = "wlx-capture" version = "0.5.3" @@ -6170,8 +6184,6 @@ dependencies = [ "config", "ctrlc", "dbus", - "fontconfig-rs", - "freetype-rs", "futures", "glam", "idmap", @@ -6192,6 +6204,7 @@ dependencies = [ "regex", "rodio", "rosc", + "rust-embed", "serde", "serde_json", "serde_json5", @@ -6204,12 +6217,14 @@ dependencies = [ "tracing", "tracing-subscriber", "uuid", + "vulkano", + "vulkano-shaders", "wayland-client", "wayland-egl", "wayvr_ipc", "wgui", "winit", - "wlx-capture", + "wlx-capture 0.5.3 (git+https://github.com/galister/wlx-capture?tag=v0.5.3)", "xcb", "xdg 3.0.0", "xkbcommon 0.8.0", @@ -6372,18 +6387,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e01738255b5a16e78bbb83e7fbba0a1e7dd506905cfc53f4622d89015a03fbb5" -[[package]] -name = "yeslogic-fontconfig-sys" -version = "3.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2bbd69036d397ebbff671b1b8e4d918610c181c5a16073b96f984a38d08c386" -dependencies = [ - "const-cstr", - "dlib", - "once_cell", - "pkg-config", -] - [[package]] name = "yoke" version = "0.8.0" diff --git a/Cargo.toml b/Cargo.toml index 1a69d3c..95788cd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,120 +1,12 @@ -[profile.release-with-debug] -inherits = "release" -debug = true +[workspace] +members = ["wgui", "wgui/uidev-vk", "wlx-overlay-s", "wlx-capture"] -[package] -name = "wlx-overlay-s" -version = "25.4.2" -edition = "2021" -license = "GPL-3.0-only" -authors = ["galister"] -description = "Access your Wayland/X11 desktop from Monado/WiVRn/SteamVR. Now with Vulkan!" -repository = "https://github.com/galister/wlx-overlay-s" -keywords = ["linux", "openvr", "openxr", "x11", "wayland", "openvr-overlay", "openxr-overlay"] -categories = ["games"] - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -anyhow = { workspace = true } -ash = "^0.38.0" # must match vulkano -chrono = "0.4.38" -chrono-tz = "0.10.0" -clap = { version = "4.5.6", features = ["derive"] } -config = "0.15.11" -ctrlc = { version = "3.4.4", features = ["termination"] } -dbus = { version = "0.9.7" } -futures = "0.3.30" -glam = { workspace = true, features = ["mint", "serde"] } -idmap = { version = "0.2.21", features = ["serde"] } -idmap-derive = "0.1.2" -input-linux = "0.7.0" -json = { version = "0.12.4", optional = true } -json5 = "0.4.1" -libc = "0.2.155" -log = { workspace = true } -openxr = { git = "https://github.com/Ralith/openxrs", rev = "d0afdd3365bc1e14de28f6a3a21f457e788a702e", features = [ - "linked", - "mint", -], optional = true } -ovr_overlay = { features = [ - "ovr_input", - "ovr_system", -], git = "https://github.com/galister/ovr_overlay_oyasumi", optional = true } -regex = "1.11.1" -rodio = { version = "0.20.1", default-features = false, features = [ - "wav", - "hound", +[workspace.dependencies] +anyhow = "1.0.98" +glam = "0.30.3" +log = "0.4.27" +vulkano = { version = "0.35.1", default-features = false, features = [ + "macros", ] } -rosc = { version = "0.11.4", optional = true } -serde = { version = "1.0.203", features = ["derive", "rc"] } -serde_json = "1.0.117" -serde_yaml = "0.9.34" -smallvec = "1.13.2" -strum = { version = "0.27.1", features = ["derive"] } -sysinfo = { version = "0.35" } -thiserror = "2.0" -wlx-capture = { git = "https://github.com/galister/wlx-capture", tag = "v0.5.3", default-features = false } -libmonado = { version = "1.3.2", optional = true } -winit = { version = "0.30", optional = true } -xdg = "3.0" -log-panics = { version = "2.1.0", features = ["with-backtrace"] } -serde_json5 = "0.2.1" -xkbcommon = { version = "0.8.0" } -xcb = { version = "1.4.0", optional = true, features = [ - "as-raw-xcb-connection", -] } -image_dds = { version = "0.7.2", default-features = false, features = [ - "ddsfile", -] } -mint = "0.5.9" -tracing-subscriber = { version = "0.3.19", features = ["env-filter"] } -tracing = "0.1.41" -vulkano = { workspace = true } -vulkano-shaders = { workspace = true } -wgui = { path = "../wgui" } +vulkano-shaders = "0.35.0" -################################ -#WayVR-only deps -################################ -khronos-egl = { version = "6.0.0", features = ["static"], optional = true } -smithay = { version = "0.5.1", default-features = false, features = [ - "renderer_gl", - "backend_egl", - "backend_drm", - "xwayland", - "wayland_frontend", -], optional = true } -uuid = { version = "1.10.0", features = ["v4", "fast-rng"], optional = true } -wayland-client = { version = "0.31.6", optional = true } -wayland-egl = { version = "0.32.4", optional = true } -interprocess = { version = "2.2.2", optional = true } -bytes = { version = "1.9.0", optional = true } -wayvr_ipc = { git = "https://github.com/olekolek1000/wayvr-ipc.git", rev = "a72587d23f3bb8624d9aeb1f13c0a21e65350f51", default-features = false, optional = true } -rust-embed = "8.7.2" -################################ - -[build-dependencies] -regex = { version = "1.11.1" } - -[features] -default = ["openvr", "openxr", "osc", "x11", "wayland", "wayvr"] -openvr = ["dep:ovr_overlay", "dep:json"] -openxr = ["dep:openxr", "dep:libmonado"] -osc = ["dep:rosc"] -x11 = ["dep:xcb", "wlx-capture/xshm", "xkbcommon/x11"] -wayland = ["pipewire", "wlx-capture/wlr", "xkbcommon/wayland"] -pipewire = ["wlx-capture/pipewire"] -uidev = ["dep:winit"] -xcb = ["dep:xcb"] -wayvr = [ - "dep:khronos-egl", - "dep:smithay", - "dep:uuid", - "dep:wayland-client", - "dep:wayland-egl", - "dep:interprocess", - "dep:bytes", - "dep:wayvr_ipc", -] -as-raw-xcb-connection = [] diff --git a/wgui/.editorconfig b/wgui/.editorconfig new file mode 100644 index 0000000..f5834b7 --- /dev/null +++ b/wgui/.editorconfig @@ -0,0 +1,8 @@ +root = true + +[*.rs] +indent_style = tab +indent_size = 2 +charset = utf-8 +trim_trailing_whitespace = false +insert_final_newline = false \ No newline at end of file diff --git a/wgui/.gitignore b/wgui/.gitignore new file mode 100644 index 0000000..7be846b --- /dev/null +++ b/wgui/.gitignore @@ -0,0 +1,2 @@ +target +.vscode \ No newline at end of file diff --git a/wgui/Cargo.lock b/wgui/Cargo.lock new file mode 100644 index 0000000..c8d3a40 --- /dev/null +++ b/wgui/Cargo.lock @@ -0,0 +1,1966 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "adler2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" + +[[package]] +name = "aligned-vec" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4aa90d7ce82d4be67b64039a3d588d38dbcc6736577de4a847025ce5b0c468d1" + +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + +[[package]] +name = "anyhow" +version = "1.0.98" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" + +[[package]] +name = "arbitrary" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223" + +[[package]] +name = "arg_enum_proc_macro" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ae92a5119aa49cdbcf6b9f893fe4e1d98b04ccbf82ee0584ad948a44a734dea" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "arrayref" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[package]] +name = "ash" +version = "0.38.0+1.3.281" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bb44936d800fea8f016d7f2311c6a4f97aebd5dc86f09906139ec848cf3a46f" +dependencies = [ + "libloading", +] + +[[package]] +name = "autocfg" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" + +[[package]] +name = "av1-grain" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f3efb2ca85bc610acfa917b5aaa36f3fcbebed5b3182d7f877b02531c4b80c8" +dependencies = [ + "anyhow", + "arrayvec", + "log", + "nom", + "num-rational", + "v_frame", +] + +[[package]] +name = "avif-serialize" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98922d6a4cfbcb08820c69d8eeccc05bb1f29bfa06b4f5b1dbfe9a868bd7608e" +dependencies = [ + "arrayvec", +] + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" + +[[package]] +name = "bitstream-io" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6099cdc01846bc367c4e7dd630dc5966dccf36b652fae7a74e17b640411a91b2" + +[[package]] +name = "built" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56ed6191a7e78c36abdb16ab65341eefd73d64d303fffccdbb00d51e4205967b" + +[[package]] +name = "bumpalo" +version = "3.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" + +[[package]] +name = "bytemuck" +version = "1.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9134a6ef01ce4b366b50689c94f82c14bc72bc5d0386829828a2e2752ef7958c" +dependencies = [ + "bytemuck_derive", +] + +[[package]] +name = "bytemuck_derive" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ecc273b49b3205b83d648f0690daa588925572cc5063745bfe547fe7ec8e1a1" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "byteorder-lite" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" + +[[package]] +name = "cc" +version = "1.2.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f4ac86a9e5bc1e2b3449ab9d7d3a6a405e3d1bb28d7b9be8614f55846ae3766" +dependencies = [ + "jobserver", + "libc", + "shlex", +] + +[[package]] +name = "cfg-expr" +version = "0.15.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d067ad48b8650848b989a59a86c6c36a995d02d2bf778d45c3c5d57bc2718f02" +dependencies = [ + "smallvec", + "target-lexicon", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cmake" +version = "0.1.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7caa3f9de89ddbe2c607f4101924c5abec803763ae9534e4f4d7d8f84aa81f0" +dependencies = [ + "cc", +] + +[[package]] +name = "color_quant" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" + +[[package]] +name = "cosmic-text" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da46a9d5a8905cc538a4a5bceb6a4510de7a51049c5588c0114efce102bcbbe8" +dependencies = [ + "bitflags 2.9.1", + "fontdb", + "log", + "rangemap", + "rustc-hash 1.1.0", + "rustybuzz", + "self_cell", + "smol_str", + "swash", + "sys-locale", + "ttf-parser 0.21.1", + "unicode-bidi", + "unicode-linebreak", + "unicode-script", + "unicode-segmentation", +] + +[[package]] +name = "crc32fast" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-queue" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "crunchy" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929" + +[[package]] +name = "data-url" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c297a1c74b71ae29df00c3e22dd9534821d60eb9af5a0192823fa2acea70c2a" + +[[package]] +name = "dispatch2" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec" +dependencies = [ + "bitflags 2.9.1", + "objc2", +] + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "etagere" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc89bf99e5dc15954a60f707c1e09d7540e5cd9af85fa75caa0b510bc08c5342" +dependencies = [ + "euclid", + "svg_fmt", +] + +[[package]] +name = "euclid" +version = "0.22.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad9cdb4b747e485a12abb0e6566612956c7a1bafa3bdb8d682c5b6d403589e48" +dependencies = [ + "num-traits", +] + +[[package]] +name = "fdeflate" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c" +dependencies = [ + "simd-adler32", +] + +[[package]] +name = "flate2" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "float-cmp" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4" + +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "font-types" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02a596f5713680923a2080d86de50fe472fb290693cf0f701187a1c8b36996b7" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "fontconfig-parser" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbc773e24e02d4ddd8395fd30dc147524273a83e54e0f312d986ea30de5f5646" +dependencies = [ + "roxmltree 0.20.0", +] + +[[package]] +name = "fontdb" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0299020c3ef3f60f526a4f64ab4a3d4ce116b1acbf24cdd22da0068e5d81dc3" +dependencies = [ + "fontconfig-parser", + "log", + "memmap2", + "slotmap", + "tinyvec", + "ttf-parser 0.20.0", +] + +[[package]] +name = "getrandom" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasi 0.14.2+wasi-0.2.4", +] + +[[package]] +name = "gif" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fb2d69b19215e18bb912fa30f7ce15846e301408695e44e0ef719f1da9e19f2" +dependencies = [ + "color_quant", + "weezl", +] + +[[package]] +name = "glam" +version = "0.30.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b46b9ca4690308844c644e7c634d68792467260e051c8543e0c7871662b3ba7" + +[[package]] +name = "grid" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "969d090eea77fac1be33f853ffc4b6b60cc6f312ddf4fd28b311a730e1dd8ebe" + +[[package]] +name = "half" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "459196ed295495a68f7d7fe1d84f6c4b7ff0e21fe3017b2f283c6fac3ad803c9" +dependencies = [ + "bytemuck", + "cfg-if", + "crunchy", +] + +[[package]] +name = "hashbrown" +version = "0.15.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash", +] + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "image" +version = "0.25.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db35664ce6b9810857a38a906215e75a9c879f0696556a39f59c62829710251a" +dependencies = [ + "bytemuck", + "byteorder-lite", + "color_quant", + "gif", + "image-webp", + "num-traits", + "png", + "ravif", + "rayon", + "zune-core", + "zune-jpeg", +] + +[[package]] +name = "image-webp" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b77d01e822461baa8409e156015a1d91735549f0f2c17691bd2d996bef238f7f" +dependencies = [ + "byteorder-lite", + "quick-error", +] + +[[package]] +name = "imagesize" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edcd27d72f2f071c64249075f42e205ff93c9a4c5f6c6da53e79ed9f9832c285" + +[[package]] +name = "imgref" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0263a3d970d5c054ed9312c0057b4f3bde9c0b33836d3637361d4a9e6e7a408" + +[[package]] +name = "indexmap" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "interpolate_name" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c34819042dc3d3971c46c2190835914dfbe0c3c13f61449b2997f4e9722dfa60" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + +[[package]] +name = "jobserver" +version = "0.1.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a" +dependencies = [ + "getrandom 0.3.3", + "libc", +] + +[[package]] +name = "kurbo" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1077d333efea6170d9ccb96d3c3026f300ca0773da4938cc4c811daa6df68b0c" +dependencies = [ + "arrayvec", + "smallvec", +] + +[[package]] +name = "libc" +version = "0.2.172" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" + +[[package]] +name = "libfuzzer-sys" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf78f52d400cf2d84a3a973a78a592b4adc535739e0a5597a0da6f0c357adc75" +dependencies = [ + "arbitrary", + "cc", +] + +[[package]] +name = "libloading" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a793df0d7afeac54f95b471d3af7f0d4fb975699f972341a4b76988d49cdf0c" +dependencies = [ + "cfg-if", + "windows-targets 0.53.0", +] + +[[package]] +name = "libm" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" + +[[package]] +name = "lock_api" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" + +[[package]] +name = "loop9" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fae87c125b03c1d2c0150c90365d7d6bcc53fb73a9acaef207d2d065860f062" +dependencies = [ + "imgref", +] + +[[package]] +name = "lru" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f8cc7106155f10bdf99a6f379688f543ad6596a415375b36a59a054ceda1198" +dependencies = [ + "hashbrown", +] + +[[package]] +name = "maybe-rayon" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea1f30cedd69f0a2954655f7188c6a834246d2bcf1e315e2ac40c4b24dc9519" +dependencies = [ + "cfg-if", + "rayon", +] + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "memmap2" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd3f7eed9d3848f8b98834af67102b720745c4ec028fcd0aa0239277e7de374f" +dependencies = [ + "libc", +] + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "miniz_oxide" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a" +dependencies = [ + "adler2", + "simd-adler32", +] + +[[package]] +name = "new_debug_unreachable" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "noop_proc_macro" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0676bb32a98c1a483ce53e500a81ad9c3d5b3f7c920c28c24e9cb0980d0b5bc8" + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "objc2" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88c6597e14493ab2e44ce58f2fdecf095a51f12ca57bec060a11c57332520551" +dependencies = [ + "objc2-encode", +] + +[[package]] +name = "objc2-core-foundation" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c10c2894a6fed806ade6027bcd50662746363a9589d3ec9d9bef30a4e4bc166" +dependencies = [ + "bitflags 2.9.1", + "dispatch2", + "objc2", +] + +[[package]] +name = "objc2-encode" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" + +[[package]] +name = "objc2-foundation" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "900831247d2fe1a09a683278e5384cfb8c80c79fe6b166f9d14bfdde0ea1b03c" +dependencies = [ + "bitflags 2.9.1", + "objc2", + "objc2-core-foundation", +] + +[[package]] +name = "objc2-metal" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f246c183239540aab1782457b35ab2040d4259175bd1d0c58e46ada7b47a874" +dependencies = [ + "bitflags 2.9.1", + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-quartz-core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90ffb6a0cd5f182dc964334388560b12a57f7b74b3e2dec5e2722aa2dfb2ccd5" +dependencies = [ + "bitflags 2.9.1", + "objc2", + "objc2-core-foundation", + "objc2-foundation", + "objc2-metal", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "parking_lot" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets 0.52.6", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "pico-args" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315" + +[[package]] +name = "pkg-config" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" + +[[package]] +name = "png" +version = "0.17.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82151a2fc869e011c153adc57cf2789ccb8d9906ce52c0b39a6b5697749d7526" +dependencies = [ + "bitflags 1.3.2", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "proc-macro-crate" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edce586971a4dfaa28950c6f18ed55e0406c1ab88bbce2c6f6293a7aaba73d35" +dependencies = [ + "toml_edit", +] + +[[package]] +name = "proc-macro2" +version = "1.0.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "profiling" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afbdc74edc00b6f6a218ca6a5364d6226a259d4b8ea1af4a0ea063f27e179f4d" +dependencies = [ + "profiling-procmacros", +] + +[[package]] +name = "profiling-procmacros" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a65f2e60fbf1063868558d69c6beacf412dc755f9fc020f514b7955fc914fe30" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "quick-error" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" + +[[package]] +name = "quote" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.16", +] + +[[package]] +name = "rangemap" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f60fcc7d6849342eff22c4350c8b9a989ee8ceabc4b481253e8946b9fe83d684" + +[[package]] +name = "rav1e" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd87ce80a7665b1cce111f8a16c1f3929f6547ce91ade6addf4ec86a8dda5ce9" +dependencies = [ + "arbitrary", + "arg_enum_proc_macro", + "arrayvec", + "av1-grain", + "bitstream-io", + "built", + "cfg-if", + "interpolate_name", + "itertools", + "libc", + "libfuzzer-sys", + "log", + "maybe-rayon", + "new_debug_unreachable", + "noop_proc_macro", + "num-derive", + "num-traits", + "once_cell", + "paste", + "profiling", + "rand", + "rand_chacha", + "simd_helpers", + "system-deps", + "thiserror", + "v_frame", + "wasm-bindgen", +] + +[[package]] +name = "ravif" +version = "0.11.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6a5f31fcf7500f9401fea858ea4ab5525c99f2322cfcee732c0e6c74208c0c6" +dependencies = [ + "avif-serialize", + "imgref", + "loop9", + "quick-error", + "rav1e", + "rayon", + "rgb", +] + +[[package]] +name = "raw-window-handle" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" + +[[package]] +name = "raw-window-metal" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40d213455a5f1dc59214213c7330e074ddf8114c9a42411eb890c767357ce135" +dependencies = [ + "objc2", + "objc2-core-foundation", + "objc2-foundation", + "objc2-quartz-core", +] + +[[package]] +name = "rayon" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "read-fonts" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ce8e2ca6b24313587a03ca61bb74c384e2a815bd90cf2866cfc9f5fb7a11fa0" +dependencies = [ + "bytemuck", + "font-types", +] + +[[package]] +name = "redox_syscall" +version = "0.5.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "928fca9cf2aa042393a8325b9ead81d2f0df4cb12e1e24cef072922ccd99c5af" +dependencies = [ + "bitflags 2.9.1", +] + +[[package]] +name = "resvg" +version = "0.45.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8928798c0a55e03c9ca6c4c6846f76377427d2c1e1f7e6de3c06ae57942df43" +dependencies = [ + "log", + "pico-args", + "rgb", + "svgtypes", + "tiny-skia", + "usvg", +] + +[[package]] +name = "rgb" +version = "0.8.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57397d16646700483b67d2dd6511d79318f9d057fdbd21a4066aeac8b41d310a" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "roxmltree" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "921904a62e410e37e215c40381b7117f830d9d89ba60ab5236170541dd25646b" +dependencies = [ + "xmlparser", +] + +[[package]] +name = "roxmltree" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c20b6793b5c2fa6553b250154b78d6d0db37e72700ae35fad9387a46f487c97" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustc-hash" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" + +[[package]] +name = "rustversion" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" + +[[package]] +name = "rustybuzz" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfb9cf8877777222e4a3bc7eb247e398b56baba500c38c1c46842431adc8b55c" +dependencies = [ + "bitflags 2.9.1", + "bytemuck", + "libm", + "smallvec", + "ttf-parser 0.21.1", + "unicode-bidi-mirroring", + "unicode-ccc", + "unicode-properties", + "unicode-script", +] + +[[package]] +name = "ryu" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "self_cell" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f7d95a54511e0c7be3f51e8867aa8cf35148d7b9445d44de2f943e2b206e749" + +[[package]] +name = "serde" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.140" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + +[[package]] +name = "serde_spanned" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" +dependencies = [ + "serde", +] + +[[package]] +name = "shaderc" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27e07913ada18607bb60d12431cbe3358d3bbebbe95948e1618851dc01e63b7b" +dependencies = [ + "libc", + "shaderc-sys", +] + +[[package]] +name = "shaderc-sys" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73120d240fe22196300f39ca8547ca2d014960f27b19b47b21288b396272f7f7" +dependencies = [ + "cmake", + "libc", + "roxmltree 0.14.1", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "simd-adler32" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" + +[[package]] +name = "simd_helpers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95890f873bec569a0362c235787f3aca6e1e887302ba4840839bcc6459c42da6" +dependencies = [ + "quote", +] + +[[package]] +name = "simplecss" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a9c6883ca9c3c7c90e888de77b7a5c849c779d25d74a1269b0218b14e8b136c" +dependencies = [ + "log", +] + +[[package]] +name = "siphasher" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" + +[[package]] +name = "skrifa" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbe6666ab11018ab91ff7b03f1a3b9fdbecfb610848436fefa5ce50343d3d913" +dependencies = [ + "bytemuck", + "read-fonts", +] + +[[package]] +name = "slabbin" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9db491c0d4152a069911a0fbdaca959691bf0b9d7110d98a7ed1c8e59b79ab30" + +[[package]] +name = "slotmap" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbff4acf519f630b3a3ddcfaea6c06b42174d9a44bc70c620e9ed1649d58b82a" +dependencies = [ + "version_check", +] + +[[package]] +name = "smallvec" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9" + +[[package]] +name = "smol_str" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd538fb6910ac1099850255cf94a94df6551fbdd602454387d0adb2d1ca6dead" + +[[package]] +name = "strict-num" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731" +dependencies = [ + "float-cmp", +] + +[[package]] +name = "svg_fmt" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0193cc4331cfd2f3d2011ef287590868599a2f33c3e69bc22c1a3d3acf9e02fb" + +[[package]] +name = "svgtypes" +version = "0.15.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68c7541fff44b35860c1a7a47a7cadf3e4a304c457b58f9870d9706ece028afc" +dependencies = [ + "kurbo", + "siphasher", +] + +[[package]] +name = "swash" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dce3f0af95643c855cdc449fbaa17d8c2cd08e0b00a49a6babcbe6e71667f3d" +dependencies = [ + "skrifa", + "yazi", + "zeno", +] + +[[package]] +name = "syn" +version = "2.0.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sys-locale" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eab9a99a024a169fe8a903cf9d4a3b3601109bcc13bd9e3c6fff259138626c4" +dependencies = [ + "libc", +] + +[[package]] +name = "system-deps" +version = "6.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e535eb8dded36d55ec13eddacd30dec501792ff23a0b1682c38601b8cf2349" +dependencies = [ + "cfg-expr", + "heck 0.5.0", + "pkg-config", + "toml", + "version-compare", +] + +[[package]] +name = "taffy" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "592835b1f82a500b55aa6242e5e2d1fb90c50e701fa9c33b5962d4aeaa4e88d6" +dependencies = [ + "arrayvec", + "grid", + "serde", + "slotmap", +] + +[[package]] +name = "target-lexicon" +version = "0.12.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "thread_local" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +dependencies = [ + "cfg-if", + "once_cell", +] + +[[package]] +name = "tiny-skia" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83d13394d44dae3207b52a326c0c85a8bf87f1541f23b0d143811088497b09ab" +dependencies = [ + "arrayref", + "arrayvec", + "bytemuck", + "cfg-if", + "log", + "png", + "tiny-skia-path", +] + +[[package]] +name = "tiny-skia-path" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c9e7fc0c2e86a30b117d0462aa261b72b7a99b7ebd7deb3a14ceda95c5bdc93" +dependencies = [ + "arrayref", + "bytemuck", + "strict-num", +] + +[[package]] +name = "tinyvec" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09b3661f17e86524eccd4371ab0429194e0d7c008abb45f7a7495b1719463c71" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "toml" +version = "0.8.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05ae329d1f08c4d17a59bed7ff5b5a769d062e64a62d34a3261b219e62cd5aae" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3da5db5a963e24bc68be8b17b6fa82814bb22ee8660f192bb182771d498f09a3" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.22.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "310068873db2c5b3e7659d2cc35d21855dbafa50d1ce336397c666e3cb08137e" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + +[[package]] +name = "ttf-parser" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17f77d76d837a7830fe1d4f12b7b4ba4192c1888001c7164257e4bc6d21d96b4" + +[[package]] +name = "ttf-parser" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c591d83f69777866b9126b24c6dd9a18351f177e49d625920d19f989fd31cf8" + +[[package]] +name = "unicode-bidi" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" + +[[package]] +name = "unicode-bidi-mirroring" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23cb788ffebc92c5948d0e997106233eeb1d8b9512f93f41651f52b6c5f5af86" + +[[package]] +name = "unicode-ccc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1df77b101bcc4ea3d78dafc5ad7e4f58ceffe0b2b16bf446aeb50b6cb4157656" + +[[package]] +name = "unicode-ident" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" + +[[package]] +name = "unicode-linebreak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" + +[[package]] +name = "unicode-properties" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0" + +[[package]] +name = "unicode-script" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb421b350c9aff471779e262955939f565ec18b86c15364e6bdf0d662ca7c1f" + +[[package]] +name = "unicode-segmentation" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" + +[[package]] +name = "usvg" +version = "0.45.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80be9b06fbae3b8b303400ab20778c80bbaf338f563afe567cf3c9eea17b47ef" +dependencies = [ + "base64", + "data-url", + "flate2", + "imagesize", + "kurbo", + "log", + "pico-args", + "roxmltree 0.20.0", + "simplecss", + "siphasher", + "strict-num", + "svgtypes", + "tiny-skia-path", + "xmlwriter", +] + +[[package]] +name = "v_frame" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6f32aaa24bacd11e488aa9ba66369c7cd514885742c9fe08cfe85884db3e92b" +dependencies = [ + "aligned-vec", + "num-traits", + "wasm-bindgen", +] + +[[package]] +name = "version-compare" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "852e951cb7832cb45cb1169900d19760cfa39b82bc0ea9c0e5a14ae88411c98b" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "vk-parse" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3859da4d7b98bec73e68fb65815d47a263819c415c90eed42b80440a02cbce8c" +dependencies = [ + "xml-rs", +] + +[[package]] +name = "vulkano" +version = "0.35.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08840c2b51759a6f88f26f5ea378bc8b5c199a5b4760ddda292304be087249c4" +dependencies = [ + "ash", + "bytemuck", + "crossbeam-queue", + "foldhash", + "half", + "heck 0.4.1", + "indexmap", + "libloading", + "nom", + "once_cell", + "parking_lot", + "proc-macro2", + "quote", + "raw-window-handle", + "raw-window-metal", + "serde", + "serde_json", + "slabbin", + "smallvec", + "thread_local", + "vk-parse", + "vulkano-macros", +] + +[[package]] +name = "vulkano-macros" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dc929c42c9336fd082079ac3ea30126e4a0dfe36fd2e2b3581303f7d140d20f" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "vulkano-shaders" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3bf501461be7cef2893c0e62c50945add9763cc482051d29053f6157089d5ea9" +dependencies = [ + "foldhash", + "heck 0.4.1", + "proc-macro2", + "quote", + "shaderc", + "syn", + "vulkano", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasi" +version = "0.14.2+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +dependencies = [ + "wit-bindgen-rt", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" +dependencies = [ + "bumpalo", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "weezl" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a751b3277700db47d3e574514de2eced5e54dc8a5436a3bf7a0b248b2cee16f3" + +[[package]] +name = "wgui" +version = "0.1.0" +dependencies = [ + "anyhow", + "cosmic-text", + "etagere", + "glam", + "image", + "log", + "lru", + "resvg", + "roxmltree 0.20.0", + "rustc-hash 2.1.1", + "slotmap", + "smallvec", + "taffy", + "vulkano", + "vulkano-shaders", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm 0.52.6", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1e4c7e8ceaaf9cb7d7507c974735728ab453b67ef8f18febdd7c11fe59dca8b" +dependencies = [ + "windows_aarch64_gnullvm 0.53.0", + "windows_aarch64_msvc 0.53.0", + "windows_i686_gnu 0.53.0", + "windows_i686_gnullvm 0.53.0", + "windows_i686_msvc 0.53.0", + "windows_x86_64_gnu 0.53.0", + "windows_x86_64_gnullvm 0.53.0", + "windows_x86_64_msvc 0.53.0", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_i686_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" + +[[package]] +name = "winnow" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06928c8748d81b05c9be96aad92e1b6ff01833332f281e8cfca3be4b35fc9ec" +dependencies = [ + "memchr", +] + +[[package]] +name = "wit-bindgen-rt" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" +dependencies = [ + "bitflags 2.9.1", +] + +[[package]] +name = "xml-rs" +version = "0.8.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a62ce76d9b56901b19a74f19431b0d8b3bc7ca4ad685a746dfd78ca8f4fc6bda" + +[[package]] +name = "xmlparser" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66fee0b777b0f5ac1c69bb06d361268faafa61cd4682ae064a171c16c433e9e4" + +[[package]] +name = "xmlwriter" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec7a2a501ed189703dba8b08142f057e887dfc4b2cc4db2d343ac6376ba3e0b9" + +[[package]] +name = "yazi" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e01738255b5a16e78bbb83e7fbba0a1e7dd506905cfc53f4622d89015a03fbb5" + +[[package]] +name = "zeno" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6df3dc4292935e51816d896edcd52aa30bc297907c26167fec31e2b0c6a32524" + +[[package]] +name = "zerocopy" +version = "0.8.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zune-core" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f423a2c17029964870cfaabb1f13dfab7d092a62a29a89264f4d36990ca414a" + +[[package]] +name = "zune-jpeg" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99a5bab8d7dedf81405c4bb1f2b83ea057643d9cb28778cea9eecddeedd2e028" +dependencies = [ + "zune-core", +] diff --git a/wgui/Cargo.toml b/wgui/Cargo.toml new file mode 100644 index 0000000..4d5d3a7 --- /dev/null +++ b/wgui/Cargo.toml @@ -0,0 +1,34 @@ +[package] +name = "wgui" +version = "0.1.0" +edition = "2024" + +[dependencies] +anyhow = { workspace = true } +cosmic-text = "0.14.2" +etagere = "0.2.15" +glam = { workspace = true } +image = { version = "0.25.6", default-features = false, features = [ + "gif", + "jpeg", + "png", + "rayon", + "webp", +] } +log = { workspace = true } +lru = "0.14.0" +resvg = { version = "0.45.1", default-features = false } +roxmltree = "0.20.0" +rustc-hash = "2.1.1" +slotmap = "1.0.7" +smallvec = "1.15.0" +taffy = "0.8.1" +vulkano = { workspace = true } +vulkano-shaders = { workspace = true } + +[profile.dev] +opt-level = 0 +debug = true +strip = "none" +debug-assertions = true +incremental = true diff --git a/wgui/README.md b/wgui/README.md new file mode 100644 index 0000000..7c63823 --- /dev/null +++ b/wgui/README.md @@ -0,0 +1,9 @@ +

+  logo +

+ +# wgui + +an experimental gui library for wlx-overlay-s and WayVR Dashboard + +powered via vulkan diff --git a/wgui/contrib/logo.png b/wgui/contrib/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..70f25bbbac54c6a773fb8d9c8cd878e27cba6087 GIT binary patch literal 6644 zcmX9@cR1VM_fO2AMo@c)Qbkc)gxYGh)ZU}9_XrYVCu-N;I+SY78m&D_siHMX?cigV z*sJ`~@9&TEzVGL`=XuV(uk*V1yq3+atiq!PiC1#~)ts2g*k9 ziPBMjXo4u*wFzyx{iR50G9;ABXE_Q4Y5_m=Bh>=?Ee8Z9>5_D}d>@d*UI=WdzmUkt z)xo9dBv~9k$UAf6kS>+zmuo4b=hTj-Pl~=nuOcNvPr5u9zPHdk_u*1DaxVNb*vu@% zEa=yo68#pfxAKKa&}8L!C(OoX@;e5k@N+8eechW_W0qy9XRO8|F?Z7A>Hzsz@wPA) zJ~ROBKC7P9SvC9A+MJ6w<&*D-f6P#fp^dZO$Y+e7NUaxaEr_9v_LicCpkw9KYE_ZLU*WVlBWp`A|DJ+Yml(S3Iehoh(y3Q`#)*0>Q4jZdc27)b$$xZ zOT$TnbVD2kDk8v|oqVit_M$$NoBEH1^wTE+boSz4c0#2=bn+42_yIg|6bBKF53EO(dP+PVl8as9qblg#T*_fV1>uMLzVGX(GEBFo**Hf1 zrDrlfUb;>U@%e_c&dTh|YIe%+5DMk@UGpdZa-{Py84Uh@ne+6G0Mag;fRw&WdY&gW zX!m8mb~=kdsuVub7=p6wW1gc8{BfDXAc8}|G z&U{t3b&#LVc%3dtt|W^W^Jw)AQIsjpc0?y4&R#l>Rv2;Bc))GdyE1=#0$XMRisN@jS>Gjm?uU>haNOg?l) zW-F{EEhVUI^(6<=mHeLfL53HE>Q(P;?rP_mhP&2yJze!m!`EX@7e{_i=d;6vni^20 zfnNoGJ?;je34|8fLe}6=!UVK=Qvb0))tA4Em*jsxFSU7R&woH3A=W(-g`C3j>DPfO z^Z=IWt6HK=44guWQ;}SMz&7cqrBeH2N|f|iTu(~ShFvq`%&$nAsxju55y$XL;lAgf zEQVl|p5047mj03;f&OBD;BT6uXcJv>|M1|_?IKzHuSL;rJG%%r@$YmF;d&+HaPCFN zLm>3aMu6+aroD|x-te+krbyYQnt{fE%PAyiDScn}*`9ac_159n>d=X|ZJqbWWv}1g z^PM|ZR#&?evKx_{m06nHvwl7jROP|ZGIYqzjbHwtTyi&A8+nZ^qk=#op@4*72Oej+1 zp4r_i4L>Z|y$K2GAo3x3osrxxNqom(C76WX(o4h;d68!P!|%&z7ky<{yxce@pfkED zuf&he@&U>l7cHs=QdCUql>vzSiV^GsglDXR{Q)O4@$xGcI`h z@flPoBtnUAXgR=JrM^;t$f;|;x7_}!l38W&NZxlc(Y$n!3@zb@^?{kXA7FjlixhnB z$NPsm+zX|pVg664zlbTdAqM_kG)Dm9Nn_?E2uYI0jIrgMO|(?jvAy6@VilR^Fn}&v z@J8PTD^HiF0{Gdj#w7n>z9NBL7#(9Ls#zjSYNB{ju&^4^aT-|1M%_64MBK41!8;SItQZd{iV@>udUg_tv)tNq)MnT2i=l~SNqT&~6?&9uU9;>5G+xref zdA`Q@uWMn2K;5L^63-MFq76OLC~{0s0r<<2JeFuvGHSP2VdIXi<@C})?0(s!HYVD! zl1YCGsX(EHq2qpUqn>5pmPVWGlZw2KS`43VTeU9wMNCDH%)8{ZkP14Vt$l#LEv@~H zE8l{C=I70r0IN8Jn4y0z4e&@^5(Vw-0omVZ)4Nl_8KYY=A|GC||j{i`~b=+Z5G^u^meNGi=ImIfD;+aX?f3xA;r^eAG~nkMWm6!&fU z>8v>#eI~^Fxy`VK5YUmX#62aF++LX?Fq`x7KPP!yo<6$zhl+)2uV0WP3dyB`YaAwf z2c?+cHHTCHZsU&iDBT(W9IE#vAL9G&4B?a*xudObLt9PnlTdIAp@3ACG+B%f2g$a1% z@{wW|<4#~>b$2PE?|~0jD^RlMzacVctR|#`Nt8gh_oANgS?9Q2EZ~6m^)rGe4MVPL z;P9=cn{78rh`v!agsOB<)^lli@cn`+#tDTmpd&p}LK(EmRw$WR$bL z1$1Vxyml%zB$n2;-Qz!8L6`b*y7(_lnd3!|ukAuE`CAtbo^1p@i_UZ-9^BjBn~JE} zT%jPa*43SX-cG4B4Z+sR)C8D0(C=*nrA8>y zOb$96FAxhq^Yu!_y2EnfKdD@or{32~1z37yRdG$_AgId?Ri~d4DqBQ(>cA!zz$)PI z>&%|3F#C-Ii4yTc?0+Zi9vA(E8p zG`({0#+{0euO|cY%VS6>X8o)cEmhGmdp~P^#|IdEP6lM72Fqnq>3Ts~U#PPQr^6Kw znECy#)ICEQg`9PN5WU0cU!E%1@!HLlPPaUcH_T2NWl%UWqhcu*wMu}TusjQ5HaMw# zs-4mq%>AOUZ(AJgZ1MH<__O@}TCc|i!n*B^LyFfoNr$zSQA&R$x_Syuw(|S81aaT7 zx{VtMIuqEBo;Xn%)RJ$?8wYnntW1!25ET3#M&E=@eMUfD%-`AfYEUIj5@qm@dVjuw z;x?F?Zr)@t2MZ8Y6u`iE0cuV0A9Hs!Dk$+oJxm1klTki8Sdc9NNB}ZYneJvaX_|}+ z_PB-eOiXOa{ps+!=*oHvXB3ABnn&l*0!K~&%Zbb!nY~$ox5#E_V;S|i7cJZlx%*f`xVV`IStU^D$uxo} zlGTtEwHk6TLz3}I;>k12DJQY0Zto6gtj5hW4Lv5;rv;X=meUwt?=8rlQ9;cZ zIgsbUxZc9u%w4Po-j}{!dMcrcJ0D5pG5@3uURESS&SY(s2SGtYQ>LUE5(J35b$gMZ zpf$gxKq%cKsc<_c0p^$Up*_Bj^-BISL?1$I6DWq^;f{H*YkHP8sigb2y8E^fJd8}h zvz2$kw))d}J?_!0;;2#)TrMH5mmAB&RB~-oKC}Vu6@_94;W&-c1H&4w7kd5X#24PR zu;})-$#D`tJozo3+;=FKUc210DS?9eC_E!x6IcX`gjXiDNa^VzD@VYkVb-n15~SO1 z>_7zqqT?<^PIg3`EzTU{>sWw7KQMpRW5AC?R&P+a{Qi%zSb`RNBDz+Sx%$B7>uGTB zF!jXUmzk%VbSh%o2(^lgT93=ZbiU2s-OOYU9e{G2;4W?1Xo2zC#5nW526f8a1kU6X zh=KaRYd4mNKB-&mO2EqOWx{0}Hy}eL&scA>G5d+Li2WDtRr9Zx0lk)iUbeJV=Ic5 z4s}@}T@0TLPPSh>;L1vCC<&5nvr;yi*)N@y~+WK2dsbpK&!^1>Xg&^4bnKrytp!p zcpRx9q<&zPoY^V=dqM~clY#VczhQU;8mv`B-+C4Hx=ye#k?N0aw9WP}$F-17%;~T9 zf#4bsNlbNXrm%sx8%v}S{c0TqUEW>#C{&-EE6J@H8vEc6GW2V3#{*6|7q7_<>h(oxrXyIpv6{j7O0Vhg4xlxdx4&T)tHo zWNR(7*4$4-JX9vhgN3(dd^v56sxOOAWmF)kRmK{3816^A`p#ODfO=Vrd%n(AJ}e*Q zyvy>47~jd$M3{#a_?=SFDLS$j_waN?ASh#+#qA?WD&X%HNc$vESA!qcsvOoLhZ>A^ zQTRQg6G1<=uM;iQ(x{B|p8eTnX4Sry-xI4Z<7d16>J;vj*~93mF7AmuF*$WJXZz3g z%PS|-v1@*V^Q0@qXcxc1mhx0u>B}L3(#&lw*eof))pb{;zAiM)gR$6ua*yP$x@YWC zM$a}mN!&vtmIR1!{o8glX{PmX0##}8^(YBq|=}CwK6Q!6#g9%$NZE-Adxn6Gt z#IP?mZ~Y~zr?0#E^Sw0=FweV922H?^lzlqBYYyE?AJ;k3qd(J$AthExUiY%?M_YYJ zX$t|hl%&X`KMH{z4K(Z}mLz=ktFKqY@jIV#udwH?oQh|!GCnP!Lr4PB&1Ig{npKNy ze~clbqN`aDAhPH8{gW|Qs`PHYVN?HoZfIn>7*pS#jTu&Gi-T>T}6{ z4rP?lZ;kA@8bjB37mJ=0#*`!Z-k9Q%ohRM;}>Z?9^aU4e>L)y-#0p%Y$snma0crVcJ02_b4%Y+8C#Fw(uP{F(HP zb*JFmIfYDhZK!ow4f8jjn-FN&nn<7*>Mf1v2f{j3NV~%z8eZR>_J4|pTkQ&v1ch^{ z#5PABL!gQ`h#llgbFj@S<9+Xf`C^uI+~3B|0ksChp5F<3QO|{v@9rTrpgpA9sR1>i zQULQhy%O}9s*l+Y*#Xcn8xUOs?{%pO#|1!%~U|TWuHzy|)$`eBt ze9CT!Z5SD?Eum-dtG%r9cx|FN+)T=$)wkFT2&V>E$g$ngt&n{(;XA*#<#AOmpxj+k zqs%}+MPaK8+Glq9g<|dCmys+vviQ%gRqe(LI4)Uh?^l2CWn`Gz^UZ*%Jdg!(UoZyq zgm7P!DVix$Rpq8m+DqypcFARz8o3u-b2PHT2IF1lduRkZPKL4_VF~LU{z}Dvf5Ppv z66;#TsYpGMcv5n5BgXe?=b@Y6AfBRe>xBss$4Dk0&9yq$Y@%JHJG&4Ot`24udsQ09H1p6f-Y_emVbkaA+`beA;HfO0=EZWlq-pRTh{551CkQ>|iTFs&)-m~Rz!q4K$|b5B*u0BmScvZ=a4=i7_CVpXO1v{KWohZ^Jv?huw#B9! zKPwF#=B<6C;oR)gli-o}EN*rh)^WTZ2>E5_ulbsFhD#-WSy{*HpJ6aa>>J zdp2w#XOH7&sbu`TI2-R(^Ows9iWh3C2^IC9k<59-2aWK7Mc#$*wMog!Gsg;EVc4v3 zG3*eL`>{ewat}Xd{wWPR*iOz?jbJT6*@>Ng1OmPkeqxL*dQ^7jwQr|K${GOC6wF7v!-+dWEU z3^%SVE3c{7=l<`}d3e=iEvfGh<4n@t58-hL;NwQFdv5Q z^6pU12`7u@X9NJO_urp0h@a?-_EBNpt)%_k%k*@ggW@*C3o%B_1}cn& zvvt_Tb$vT#mVy8~iBnYUYa<|_YiC_o_g3yW2%!;gB#%2SfCVk|=yN-HzHwtQ-ut#z z9Ix&;XY&x0Pf&9PNJ^$ZfL@`jv26+`di6N)9yp3=qN={XuCX_CC~57UNQR uRdMab_Z~iMX~8Dc9(Mn6TV;RN(T%}m(I&S0yC&hq2B4#1pkA$NAN_xr{&=ha literal 0 HcmV?d00001 diff --git a/wgui/doc/widgets.md b/wgui/doc/widgets.md new file mode 100644 index 0000000..289e23c --- /dev/null +++ b/wgui/doc/widgets.md @@ -0,0 +1,105 @@ +# Universal widget attributes + +`display`: flex | block | grid + +`position`: absolute | relative + +`flex_grow`: units (3) + +`flex_shrink`: units (3) + +`gap`: units (42) or percent (42%) + +`flex_basis`: units (42) or percent (42%) + +`justify_self`: center | end | flex_end | flex_start | start | stretch + +`justify_content`: center | end | flex_start | flex_end | space_around | space_between | space_evenly | start | stretch + +`flex_wrap`: wrap | no_wrap | wrap_reverse + +`flex_direction`: row | column | column_reverse | row_reverse, + +`align_items`, `align_self`: baseline | center | end | flex_start | flex_end | start | stretch + +`box_sizing`: border_box | content_box + +`margin`, `margin_left`, `margin_right`, `margin_top`, `margin_bottom`: units (42) or percent (42%) + +`padding`, `padding_left`, `padding_right`, `padding_top`, `padding_bottom`: units (42) or percent (42%) + +`overflow_x`, `overflow_y`: hidden | visible | clip | scroll + +`min_width`, `min_height`: units (42) or percent (42%) + +`max_width`, `max_height`: units (42) or percent (42%) + +`width`, `height`: units (42) or percent (42%) + +# Widgets + +### `div` + +The most simple element + +#### Parameters + +None + +--- + +### `label` + +Text element + +#### Parameters + +`text`: abc + +`color`: #FFAABB | #FFAABBCC + +`align`: left | right | center | justified | end + +`weight`: normal | bold + +`size`: _float_ + +--- + +### `rectangle` + +A styled rectangle + +#### Parameters + +`text`: abc + +`color`: #FFAABB | #FFAABBCC + +_1st gradient color_ + +`color2`: #FFAABB | #FFAABBCC + +_2nd gradient color_ + +`gradient`: horizontal | vertical | radial | none + +`round`: _float (0.0 - 1.0)_ + +`border`: _float_ + +`border_color`: #FFAABB | #FFAABBCC + +--- + +### `sprite` + +Image widget, supports raster and svg vector + +#### Parameters + +`src`: Internal (assets) image path + +`src_ext`: External image path + +--- diff --git a/wgui/rustfmt.toml b/wgui/rustfmt.toml new file mode 100644 index 0000000..39694dc --- /dev/null +++ b/wgui/rustfmt.toml @@ -0,0 +1,2 @@ +tab_spaces = 2 +hard_tabs = true \ No newline at end of file diff --git a/wgui/src/animation.rs b/wgui/src/animation.rs new file mode 100644 index 0000000..7681ed9 --- /dev/null +++ b/wgui/src/animation.rs @@ -0,0 +1,216 @@ +use glam::FloatExt; + +use crate::{ + event::WidgetCallback, + layout::{WidgetID, WidgetMap}, + widget::WidgetObj, +}; + +pub enum AnimationEasing { + Linear, + InQuad, + OutQuad, + OutBack, + InBack, +} + +impl AnimationEasing { + fn interpolate(&self, x: f32) -> f32 { + match self { + AnimationEasing::Linear => x, + AnimationEasing::InQuad => x * x, + AnimationEasing::OutQuad => 1.0 - (1.0 - x) * (1.0 - x), + AnimationEasing::OutBack => { + let a = 1.7; + let b = a + 1.0; + 1.0 + b * (x - 1.0).powf(3.0) + a * (x - 1.0).powf(2.0) + } + AnimationEasing::InBack => { + let a = 1.7; + let b = a + 1.0; + b * x.powf(3.0) - a * x.powf(2.0) + } + } + } +} + +pub struct CallbackData<'a> { + pub obj: &'a mut dyn WidgetObj, + pub widgets: &'a WidgetMap, + pub widget_id: WidgetID, + pub pos: f32, // 0.0 (start of animation) - 1.0 (end of animation) + pub needs_redraw: bool, + pub dirty_nodes: &'a mut Vec, +} + +impl<'a> WidgetCallback<'a> for CallbackData<'a> { + fn get_widgets(&self) -> &'a WidgetMap { + self.widgets + } + + fn mark_redraw(&mut self) { + self.needs_redraw = true; + } + + fn mark_dirty(&mut self, node_id: taffy::NodeId) { + self.dirty_nodes.push(node_id); + } +} + +pub struct Animation { + target_widget: WidgetID, + + animation_id: u32, + ticks_remaining: u32, + ticks_duration: u32, + + easing: AnimationEasing, + + pos: f32, + pos_prev: f32, + last_tick: bool, + + callback: Box, +} + +#[derive(Default)] +struct CallResult { + needs_redraw: bool, +} + +impl Animation { + pub fn new( + target_widget: WidgetID, + ticks: u32, + easing: AnimationEasing, + callback: Box, + ) -> Self { + Animation::new_ex(target_widget, 0, ticks, easing, callback) + } + + pub fn new_ex( + target_widget: WidgetID, + animation_id: u32, + ticks: u32, + easing: AnimationEasing, + callback: Box, + ) -> Self { + Self { + target_widget, + animation_id, + callback, + easing, + ticks_duration: ticks, + ticks_remaining: ticks, + last_tick: false, + pos: 0.0, + pos_prev: 0.0, + } + } + + fn call( + &self, + widgets: &WidgetMap, + dirty_nodes: &mut Vec, + pos: f32, + ) -> CallResult { + let mut res = CallResult::default(); + + if let Some(widget) = widgets.get(self.target_widget).cloned() { + let mut widget = widget.lock().unwrap(); + + let data = &mut CallbackData { + widget_id: self.target_widget, + dirty_nodes, + widgets, + obj: widget.obj.as_mut(), + pos, + needs_redraw: false, + }; + + (self.callback)(data); + + if data.needs_redraw { + res.needs_redraw = true; + } + } + + res + } +} + +#[derive(Default)] +pub struct Animations { + running_animations: Vec, +} + +impl Animations { + pub fn tick( + &mut self, + widgets: &WidgetMap, + dirty_nodes: &mut Vec, + needs_redraw: &mut bool, + ) { + for anim in &mut self.running_animations { + let x = 1.0 - (anim.ticks_remaining as f32 / anim.ticks_duration as f32); + let pos = if anim.ticks_remaining > 0 { + anim.easing.interpolate(x) + } else { + anim.last_tick = true; + 1.0 + }; + + anim.pos_prev = anim.pos; + anim.pos = pos; + + let res = anim.call(widgets, dirty_nodes, 1.0); + + if anim.last_tick || res.needs_redraw { + *needs_redraw = true; + } + + anim.ticks_remaining -= 1; + } + + self + .running_animations + .retain(|anim| anim.ticks_remaining > 0); + } + + pub fn process( + &mut self, + widgets: &WidgetMap, + dirty_nodes: &mut Vec, + alpha: f32, + needs_redraw: &mut bool, + ) { + for anim in &mut self.running_animations { + let pos = anim.pos_prev.lerp(anim.pos, alpha); + let res = anim.call(widgets, dirty_nodes, pos); + + if res.needs_redraw { + *needs_redraw = true; + } + } + } + + pub fn add(&mut self, anim: Animation) { + // prevent running two animations at once + self.stop_by_widget(anim.target_widget, Some(anim.animation_id)); + self.running_animations.push(anim); + } + + pub fn stop_by_widget(&mut self, widget_id: WidgetID, animation_id: Option) { + self.running_animations.retain(|anim| { + if let Some(animation_id) = &animation_id { + if anim.target_widget == widget_id { + anim.animation_id != *animation_id + } else { + true + } + } else { + anim.target_widget != widget_id + } + }); + } +} \ No newline at end of file diff --git a/wgui/src/any.rs b/wgui/src/any.rs new file mode 100644 index 0000000..ff94161 --- /dev/null +++ b/wgui/src/any.rs @@ -0,0 +1,16 @@ +use std::any::Any; + +pub trait AnyTrait: 'static { + fn as_any(&self) -> &dyn Any; + fn as_any_mut(&mut self) -> &mut dyn Any; +} + +impl AnyTrait for T { + fn as_any(&self) -> &dyn Any { + self + } + + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } +} diff --git a/wgui/src/assets.rs b/wgui/src/assets.rs new file mode 100644 index 0000000..8dc80d2 --- /dev/null +++ b/wgui/src/assets.rs @@ -0,0 +1,3 @@ +pub trait AssetProvider { + fn load_from_path(&mut self, path: &str) -> anyhow::Result>; +} diff --git a/wgui/src/components/button.rs b/wgui/src/components/button.rs new file mode 100644 index 0000000..81acac8 --- /dev/null +++ b/wgui/src/components/button.rs @@ -0,0 +1,168 @@ +use std::sync::Arc; + +use glam::Vec2; +use taffy::{AlignItems, JustifyContent, prelude::length}; + +use crate::{ + animation::{Animation, AnimationEasing}, + drawing::{self, Color}, + event::{EventListener, WidgetCallback}, + layout::{Layout, WidgetID}, + renderer_vk::text::{FontWeight, TextStyle}, + widget::{ + rectangle::{Rectangle, RectangleParams}, + text::{TextLabel, TextParams}, + util::WLength, + }, +}; + +pub struct Params<'a> { + pub text: &'a str, + pub color: drawing::Color, + pub size: Vec2, + pub text_style: TextStyle, +} + +impl Default for Params<'_> { + fn default() -> Self { + Self { + text: "Text", + color: drawing::Color::new(1.0, 1.0, 1.0, 1.0), + size: Vec2::new(128.0, 32.0), + text_style: TextStyle::default(), + } + } +} + +pub struct Button { + color: drawing::Color, + pub body: WidgetID, // Rectangle + pub text_id: WidgetID, // Text + text_node: taffy::NodeId, +} + +impl Button { + pub fn set_text<'a, C>(&self, callback_data: &mut C, text: &str) + where + C: WidgetCallback<'a>, + { + callback_data.call_on_widget(self.text_id, |label: &mut TextLabel| { + label.set_text(text); + }); + callback_data.mark_redraw(); + callback_data.mark_dirty(self.text_node); + } +} + +fn anim_hover_in(button: Arc